From 35876eaab991efc7759802f184cdd54663ea8a94 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 1 Jun 2009 22:58:49 +0000 Subject: [PATCH 0001/1180] Import tmux, a terminal multiplexor allowing (among other things) a single terminal to be switched between several different windows and programs displayed on one terminal be detached from one terminal and moved to another. ok deraadt pirofti --- Makefile | 48 ++ arg.c | 194 +++++ array.h | 119 +++ attributes.c | 92 +++ buffer-poll.c | 97 +++ buffer.c | 227 ++++++ cfg.c | 132 ++++ client-fn.c | 92 +++ client-msg.c | 159 ++++ client.c | 226 ++++++ clock.c | 161 ++++ cmd-attach-session.c | 80 ++ cmd-bind-key.c | 157 ++++ cmd-break-pane.c | 92 +++ cmd-choose-session.c | 107 +++ cmd-choose-window.c | 106 +++ cmd-clear-history.c | 68 ++ cmd-clock-mode.c | 54 ++ cmd-command-prompt.c | 178 +++++ cmd-confirm-before.c | 141 ++++ cmd-copy-buffer.c | 222 ++++++ cmd-copy-mode.c | 56 ++ cmd-delete-buffer.c | 61 ++ cmd-detach-client.c | 54 ++ cmd-down-pane.c | 61 ++ cmd-find-window.c | 160 ++++ cmd-generic.c | 694 ++++++++++++++++ cmd-has-session.c | 51 ++ cmd-kill-pane.c | 72 ++ cmd-kill-server.c | 51 ++ cmd-kill-session.c | 68 ++ cmd-kill-window.c | 69 ++ cmd-last-window.c | 60 ++ cmd-link-window.c | 109 +++ cmd-list-buffers.c | 91 +++ cmd-list-clients.c | 67 ++ cmd-list-commands.c | 51 ++ cmd-list-keys.c | 59 ++ cmd-list-sessions.c | 67 ++ cmd-list-windows.c | 88 +++ cmd-list.c | 154 ++++ cmd-load-buffer.c | 106 +++ cmd-lock-server.c | 54 ++ cmd-move-window.c | 123 +++ cmd-new-session.c | 248 ++++++ cmd-new-window.c | 241 ++++++ cmd-next-layout.c | 55 ++ cmd-next-window.c | 78 ++ cmd-paste-buffer.c | 78 ++ cmd-previous-layout.c | 55 ++ cmd-previous-window.c | 78 ++ cmd-refresh-client.c | 54 ++ cmd-rename-session.c | 57 ++ cmd-rename-window.c | 61 ++ cmd-resize-pane.c | 105 +++ cmd-respawn-window.c | 87 ++ cmd-rotate-window.c | 111 +++ cmd-save-buffer.c | 90 +++ cmd-scroll-mode.c | 72 ++ cmd-select-layout.c | 86 ++ cmd-select-pane.c | 69 ++ cmd-select-prompt.c | 93 +++ cmd-select-window.c | 71 ++ cmd-send-keys.c | 184 +++++ cmd-send-prefix.c | 57 ++ cmd-server-info.c | 179 +++++ cmd-set-buffer.c | 64 ++ cmd-set-option.c | 169 ++++ cmd-set-password.c | 169 ++++ cmd-set-window-option.c | 170 ++++ cmd-show-buffer.c | 89 +++ cmd-show-options.c | 110 +++ cmd-show-window-options.c | 110 +++ cmd-source-file.c | 147 ++++ cmd-split-window.c | 235 ++++++ cmd-start-server.c | 46 ++ cmd-string.c | 309 ++++++++ cmd-suspend-client.c | 64 ++ cmd-swap-pane.c | 285 +++++++ cmd-swap-window.c | 75 ++ cmd-switch-client.c | 161 ++++ cmd-unbind-key.c | 120 +++ cmd-unlink-window.c | 74 ++ cmd-up-pane.c | 61 ++ cmd.c | 393 +++++++++ colour.c | 123 +++ grid-view.c | 211 +++++ grid.c | 497 ++++++++++++ input-keys.c | 227 ++++++ input.c | 1276 ++++++++++++++++++++++++++++++ key-bindings.c | 237 ++++++ key-string.c | 198 +++++ layout-manual.c | 183 +++++ layout.c | 373 +++++++++ log.c | 250 ++++++ mode-key.c | 210 +++++ names.c | 110 +++ options-cmd.c | 182 +++++ options.c | 160 ++++ paste.c | 131 +++ procname.c | 130 +++ resize.c | 138 ++++ screen-redraw.c | 171 ++++ screen-write.c | 684 ++++++++++++++++ screen.c | 240 ++++++ server-fn.c | 242 ++++++ server-msg.c | 304 +++++++ server.c | 1105 ++++++++++++++++++++++++++ session.c | 378 +++++++++ status.c | 960 ++++++++++++++++++++++ tmux.1 | 1329 +++++++++++++++++++++++++++++++ tmux.c | 487 ++++++++++++ tmux.cat1 | 813 +++++++++++++++++++ tmux.h | 1576 +++++++++++++++++++++++++++++++++++++ tty-keys.c | 412 ++++++++++ tty-term.c | 393 +++++++++ tty-write.c | 91 +++ tty.c | 1076 +++++++++++++++++++++++++ utf8.c | 317 ++++++++ util.c | 72 ++ window-choose.c | 361 +++++++++ window-clock.c | 124 +++ window-copy.c | 968 +++++++++++++++++++++++ window-more.c | 252 ++++++ window-scroll.c | 296 +++++++ window.c | 625 +++++++++++++++ xmalloc.c | 144 ++++ 127 files changed, 28294 insertions(+) create mode 100644 Makefile create mode 100644 arg.c create mode 100644 array.h create mode 100644 attributes.c create mode 100644 buffer-poll.c create mode 100644 buffer.c create mode 100644 cfg.c create mode 100644 client-fn.c create mode 100644 client-msg.c create mode 100644 client.c create mode 100644 clock.c create mode 100644 cmd-attach-session.c create mode 100644 cmd-bind-key.c create mode 100644 cmd-break-pane.c create mode 100644 cmd-choose-session.c create mode 100644 cmd-choose-window.c create mode 100644 cmd-clear-history.c create mode 100644 cmd-clock-mode.c create mode 100644 cmd-command-prompt.c create mode 100644 cmd-confirm-before.c create mode 100644 cmd-copy-buffer.c create mode 100644 cmd-copy-mode.c create mode 100644 cmd-delete-buffer.c create mode 100644 cmd-detach-client.c create mode 100644 cmd-down-pane.c create mode 100644 cmd-find-window.c create mode 100644 cmd-generic.c create mode 100644 cmd-has-session.c create mode 100644 cmd-kill-pane.c create mode 100644 cmd-kill-server.c create mode 100644 cmd-kill-session.c create mode 100644 cmd-kill-window.c create mode 100644 cmd-last-window.c create mode 100644 cmd-link-window.c create mode 100644 cmd-list-buffers.c create mode 100644 cmd-list-clients.c create mode 100644 cmd-list-commands.c create mode 100644 cmd-list-keys.c create mode 100644 cmd-list-sessions.c create mode 100644 cmd-list-windows.c create mode 100644 cmd-list.c create mode 100644 cmd-load-buffer.c create mode 100644 cmd-lock-server.c create mode 100644 cmd-move-window.c create mode 100644 cmd-new-session.c create mode 100644 cmd-new-window.c create mode 100644 cmd-next-layout.c create mode 100644 cmd-next-window.c create mode 100644 cmd-paste-buffer.c create mode 100644 cmd-previous-layout.c create mode 100644 cmd-previous-window.c create mode 100644 cmd-refresh-client.c create mode 100644 cmd-rename-session.c create mode 100644 cmd-rename-window.c create mode 100644 cmd-resize-pane.c create mode 100644 cmd-respawn-window.c create mode 100644 cmd-rotate-window.c create mode 100644 cmd-save-buffer.c create mode 100644 cmd-scroll-mode.c create mode 100644 cmd-select-layout.c create mode 100644 cmd-select-pane.c create mode 100644 cmd-select-prompt.c create mode 100644 cmd-select-window.c create mode 100644 cmd-send-keys.c create mode 100644 cmd-send-prefix.c create mode 100644 cmd-server-info.c create mode 100644 cmd-set-buffer.c create mode 100644 cmd-set-option.c create mode 100644 cmd-set-password.c create mode 100644 cmd-set-window-option.c create mode 100644 cmd-show-buffer.c create mode 100644 cmd-show-options.c create mode 100644 cmd-show-window-options.c create mode 100644 cmd-source-file.c create mode 100644 cmd-split-window.c create mode 100644 cmd-start-server.c create mode 100644 cmd-string.c create mode 100644 cmd-suspend-client.c create mode 100644 cmd-swap-pane.c create mode 100644 cmd-swap-window.c create mode 100644 cmd-switch-client.c create mode 100644 cmd-unbind-key.c create mode 100644 cmd-unlink-window.c create mode 100644 cmd-up-pane.c create mode 100644 cmd.c create mode 100644 colour.c create mode 100644 grid-view.c create mode 100644 grid.c create mode 100644 input-keys.c create mode 100644 input.c create mode 100644 key-bindings.c create mode 100644 key-string.c create mode 100644 layout-manual.c create mode 100644 layout.c create mode 100644 log.c create mode 100644 mode-key.c create mode 100644 names.c create mode 100644 options-cmd.c create mode 100644 options.c create mode 100644 paste.c create mode 100644 procname.c create mode 100644 resize.c create mode 100644 screen-redraw.c create mode 100644 screen-write.c create mode 100644 screen.c create mode 100644 server-fn.c create mode 100644 server-msg.c create mode 100644 server.c create mode 100644 session.c create mode 100644 status.c create mode 100644 tmux.1 create mode 100644 tmux.c create mode 100644 tmux.cat1 create mode 100644 tmux.h create mode 100644 tty-keys.c create mode 100644 tty-term.c create mode 100644 tty-write.c create mode 100644 tty.c create mode 100644 utf8.c create mode 100644 util.c create mode 100644 window-choose.c create mode 100644 window-clock.c create mode 100644 window-copy.c create mode 100644 window-more.c create mode 100644 window-scroll.c create mode 100644 window.c create mode 100644 xmalloc.c diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..66204957 --- /dev/null +++ b/Makefile @@ -0,0 +1,48 @@ +# $OpenBSD$ + +.PATH: ${.CURDIR}/.. + +PROG= tmux +SRCS= arg.c attributes.c buffer-poll.c buffer.c cfg.c client-fn.c \ + client-msg.c client.c clock.c cmd-attach-session.c cmd-bind-key.c \ + cmd-break-pane.c cmd-choose-session.c cmd-choose-window.c \ + cmd-clear-history.c cmd-clock-mode.c cmd-command-prompt.c \ + cmd-confirm-before.c cmd-copy-buffer.c cmd-copy-mode.c \ + cmd-delete-buffer.c cmd-detach-client.c cmd-down-pane.c \ + cmd-find-window.c cmd-generic.c cmd-has-session.c cmd-kill-pane.c \ + cmd-kill-server.c cmd-kill-session.c cmd-kill-window.c \ + cmd-last-window.c cmd-link-window.c cmd-list-buffers.c \ + cmd-list-clients.c cmd-list-commands.c cmd-list-keys.c \ + cmd-list-sessions.c cmd-list-windows.c cmd-list.c cmd-load-buffer.c \ + cmd-lock-server.c cmd-move-window.c cmd-new-session.c cmd-new-window.c \ + cmd-next-layout.c cmd-next-window.c cmd-paste-buffer.c \ + cmd-previous-layout.c cmd-previous-window.c cmd-refresh-client.c \ + cmd-rename-session.c cmd-rename-window.c cmd-resize-pane.c \ + cmd-respawn-window.c cmd-rotate-window.c cmd-save-buffer.c \ + cmd-scroll-mode.c cmd-select-layout.c cmd-select-pane.c \ + cmd-select-prompt.c cmd-select-window.c cmd-send-keys.c \ + cmd-send-prefix.c cmd-server-info.c cmd-set-buffer.c cmd-set-option.c \ + cmd-set-password.c cmd-set-window-option.c cmd-show-buffer.c \ + cmd-show-options.c cmd-show-window-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 cmd-swap-window.c \ + cmd-switch-client.c cmd-unbind-key.c cmd-unlink-window.c \ + cmd-up-pane.c cmd.c colour.c grid-view.c grid.c input-keys.c \ + input.c key-bindings.c key-string.c layout-manual.c layout.c log.c \ + mode-key.c names.c options-cmd.c options.c paste.c procname.c \ + resize.c screen-redraw.c screen-write.c screen.c server-fn.c \ + server-msg.c server.c session.c status.c tmux.c tty-keys.c tty-term.c \ + tty-write.c tty.c utf8.c util.c window-choose.c window-clock.c \ + window-copy.c window-more.c window-scroll.c window.c xmalloc.c + +CFLAGS+= -Wno-long-long -Wall -W -Wnested-externs -Wformat=2 +CFLAGS+= -Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations +CFLAGS+= -Wwrite-strings -Wshadow -Wpointer-arith -Wsign-compare +CFLAGS+= -Wundef -Wbad-function-cast -Winline -Wcast-align + +LDADD= -lutil -lncurses +DPADD= ${LIBUTIL} + +MAN= tmux.1 + +.include diff --git a/arg.c b/arg.c new file mode 100644 index 00000000..c02b2663 --- /dev/null +++ b/arg.c @@ -0,0 +1,194 @@ +/* $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 "tmux.h" + +struct client *arg_lookup_client(const char *); +struct session *arg_lookup_session(const char *); + +struct client * +arg_lookup_client(const char *name) +{ + struct client *c; + u_int i; + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c != NULL && strcmp(name, c->tty.path) == 0) + return (c); + } + + return (NULL); +} + +struct session * +arg_lookup_session(const char *name) +{ + struct session *s, *newest = NULL; + struct timeval *tv; + u_int i; + + tv = NULL; + for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { + s = ARRAY_ITEM(&sessions, i); + if (s == NULL || fnmatch(name, s->name, 0) != 0) + continue; + + if (tv == NULL || timercmp(&s->tv, tv, >)) { + newest = s; + tv = &s->tv; + } + } + + return (newest); +} + +struct client * +arg_parse_client(const char *arg) +{ + struct client *c; + char *arg2; + size_t n; + + if (arg != NULL && (arg[0] != ':' || arg[1] != '\0')) { + arg2 = xstrdup(arg); + + /* Trim a trailing : if any from the argument. */ + n = strlen(arg2); + if (arg2[n - 1] == ':') + arg2[n - 1] = '\0'; + + /* Try and look up the client name. */ + c = arg_lookup_client(arg2); + xfree(arg2); + return (c); + } + + return (NULL); +} + +struct session * +arg_parse_session(const char *arg) +{ + struct session *s; + struct client *c; + char *arg2; + size_t n; + + if (arg != NULL && (arg[0] != ':' || arg[1] != '\0')) { + arg2 = xstrdup(arg); + + /* Trim a trailing : if any from the argument. */ + n = strlen(arg2); + if (arg2[n - 1] == ':') + arg2[n - 1] = '\0'; + + /* See if the argument matches a session. */ + if ((s = arg_lookup_session(arg2)) != NULL) { + xfree(arg2); + return (s); + } + + /* If not try a client. */ + if ((c = arg_lookup_client(arg2)) != NULL) { + xfree(arg2); + return (c->session); + } + + xfree(arg2); + } + + return (NULL); +} + +int +arg_parse_window(const char *arg, struct session **s, int *idx) +{ + char *arg2, *ptr; + const char *errstr; + + *idx = -1; + + /* Handle no argument or a single :. */ + if (arg == NULL || (arg[0] == ':' && arg[1] == '\0')) { + *s = arg_parse_session(NULL); + return (0); + } + + /* Find the separator if any. */ + arg2 = xstrdup(arg); + ptr = strrchr(arg2, ':'); + + /* + * If it is first, this means no session name, so use current session + * and try to convert the rest as index. + */ + if (ptr == arg2) { + *idx = strtonum(ptr + 1, 0, INT_MAX, &errstr); + if (errstr != NULL) { + xfree(arg2); + return (1); + } + + xfree(arg2); + *s = arg_parse_session(NULL); + return (0); + } + + /* If missing, try as an index, else look up immediately. */ + if (ptr == NULL) { + *idx = strtonum(arg2, 0, INT_MAX, &errstr); + if (errstr == NULL) { + /* This is good as an index; use current session. */ + xfree(arg2); + *s = arg_parse_session(NULL); + return (0); + } + + *idx = -1; + goto lookup; + } + + /* If last, strip it and look up as a session. */ + if (ptr[1] == '\0') { + *ptr = '\0'; + goto lookup; + } + + /* Present but not first and not last. Break and convert both. */ + *ptr = '\0'; + *idx = strtonum(ptr + 1, 0, INT_MAX, &errstr); + if (errstr != NULL) { + xfree(arg2); + return (1); + } + +lookup: + /* Look up as session. */ + *s = arg_parse_session(arg2); + xfree(arg2); + if (*s == NULL) + return (1); + return (0); +} diff --git a/array.h b/array.h new file mode 100644 index 00000000..46855d77 --- /dev/null +++ b/array.h @@ -0,0 +1,119 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2006 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. + */ + +#ifndef ARRAY_H +#define ARRAY_H + +#define ARRAY_DECL(n, c) \ + struct n { \ + c *list; \ + u_int num; \ + size_t space; \ + } + +#define ARRAY_ITEM(a, i) ((a)->list[i]) +#define ARRAY_ITEMSIZE(a) (sizeof *(a)->list) +#define ARRAY_INITIALSPACE(a) (10 * ARRAY_ITEMSIZE(a)) + +#define ARRAY_ENSURE(a, n) do { \ + if (UINT_MAX - (n) < (a)->num) \ + fatalx("number too big"); \ + if (SIZE_MAX / ((a)->num + (n)) < ARRAY_ITEMSIZE(a)) \ + fatalx("size too big"); \ + if ((a)->space == 0) { \ + (a)->space = ARRAY_INITIALSPACE(a); \ + (a)->list = xrealloc((a)->list, 1, (a)->space); \ + } \ + while ((a)->space <= ((a)->num + (n)) * ARRAY_ITEMSIZE(a)) { \ + (a)->list = xrealloc((a)->list, 2, (a)->space); \ + (a)->space *= 2; \ + } \ +} while (0) + +#define ARRAY_EMPTY(a) ((a) == NULL || (a)->num == 0) +#define ARRAY_LENGTH(a) ((a)->num) +#define ARRAY_DATA(a) ((a)->list) + +#define ARRAY_FIRST(a) ARRAY_ITEM(a, 0) +#define ARRAY_LAST(a) ARRAY_ITEM(a, (a)->num - 1) + +#define ARRAY_INIT(a) do { \ + (a)->num = 0; \ + (a)->list = NULL; \ + (a)->space = 0; \ +} while (0) +#define ARRAY_CLEAR(a) do { \ + (a)->num = 0; \ +} while (0) + +#define ARRAY_SET(a, i, s) do { \ + (a)->list[i] = s; \ +} while (0) + +#define ARRAY_ADD(a, s) do { \ + ARRAY_ENSURE(a, 1); \ + (a)->list[(a)->num] = s; \ + (a)->num++; \ +} while (0) +#define ARRAY_INSERT(a, i, s) do { \ + ARRAY_ENSURE(a, 1); \ + if ((i) < (a)->num) { \ + memmove((a)->list + (i) + 1, (a)->list + (i), \ + ARRAY_ITEMSIZE(a) * ((a)->num - (i))); \ + } \ + (a)->list[i] = s; \ + (a)->num++; \ +} while (0) +#define ARRAY_REMOVE(a, i) do { \ + if ((i) < (a)->num - 1) { \ + memmove((a)->list + (i), (a)->list + (i) + 1, \ + ARRAY_ITEMSIZE(a) * ((a)->num - (i) - 1)); \ + } \ + (a)->num--; \ + if ((a)->num == 0) \ + ARRAY_FREE(a); \ +} while (0) + +#define ARRAY_EXPAND(a, n) do { \ + ARRAY_ENSURE(a, n); \ + (a)->num += n; \ +} while (0) +#define ARRAY_TRUNC(a, n) do { \ + if ((a)->num > n) \ + (a)->num -= n; \ + else \ + ARRAY_FREE(a); \ +} while (0) + +#define ARRAY_CONCAT(a, b) do { \ + ARRAY_ENSURE(a, (b)->num); \ + memcpy((a)->list + (a)->num, (b)->list, (b)->num * ARRAY_ITEMSIZE(a)) \ + (a)->num += (b)->num; \ +} while (0) + +#define ARRAY_FREE(a) do { \ + if ((a)->list != NULL) \ + xfree((a)->list); \ + ARRAY_INIT(a); \ +} while (0) +#define ARRAY_FREEALL(a) do { \ + ARRAY_FREE(a); \ + xfree(a); \ +} while (0) + +#endif diff --git a/attributes.c b/attributes.c new file mode 100644 index 00000000..cfe46ecd --- /dev/null +++ b/attributes.c @@ -0,0 +1,92 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2009 Joshua Elsasser + * + * 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 "tmux.h" + +const char * +attributes_tostring(u_char ch) +{ + static char buf[128]; + + if (ch == 0) + return ("default"); + + buf[0] = '\0'; + if (ch & GRID_ATTR_BRIGHT) + strlcat(buf, "bright,", sizeof (buf)); + if (ch & GRID_ATTR_DIM) + strlcat(buf, "dim,", sizeof (buf)); + if (ch & GRID_ATTR_UNDERSCORE) + strlcat(buf, "underscore,", sizeof (buf)); + if (ch & GRID_ATTR_BLINK) + strlcat(buf, "blink,", sizeof (buf)); + if (ch & GRID_ATTR_REVERSE) + strlcat(buf, "reverse,", sizeof (buf)); + if (ch & GRID_ATTR_HIDDEN) + strlcat(buf, "hidden,", sizeof (buf)); + if (ch & GRID_ATTR_ITALICS) + strlcat(buf, "italics,", sizeof (buf)); + *(strrchr(buf, ',')) = '\0'; + + return (buf); +} + +int +attributes_fromstring(const char *str) +{ + const char delimiters[] = " ,|"; + u_char ch; + size_t end; + + if (*str == '\0' || strcspn(str, delimiters) == 0) + return (-1); + if (strchr(delimiters, str[strlen(str) - 1]) != NULL) + return (-1); + + if (strcasecmp(str, "default") == 0) + return (0); + + ch = 0; + do { + end = strcspn(str, delimiters); + if ((end == 6 && strncasecmp(str, "bright", end) == 0) || + (end == 4 && strncasecmp(str, "bold", end) == 0)) + ch |= GRID_ATTR_BRIGHT; + else if (end == 3 && strncasecmp(str, "dim", end) == 0) + ch |= GRID_ATTR_DIM; + else if (end == 10 && strncasecmp(str, "underscore", end) == 0) + ch |= GRID_ATTR_UNDERSCORE; + else if (end == 5 && strncasecmp(str, "blink", end) == 0) + ch |= GRID_ATTR_BLINK; + else if (end == 7 && strncasecmp(str, "reverse", end) == 0) + ch |= GRID_ATTR_REVERSE; + else if (end == 6 && strncasecmp(str, "hidden", end) == 0) + ch |= GRID_ATTR_HIDDEN; + else if (end == 7 && strncasecmp(str, "italics", end) == 0) + ch |= GRID_ATTR_ITALICS; + else + return (-1); + str += end + strspn(str + end, delimiters); + } while (*str != '\0'); + + return (ch); +} diff --git a/buffer-poll.c b/buffer-poll.c new file mode 100644 index 00000000..4dd4d234 --- /dev/null +++ b/buffer-poll.c @@ -0,0 +1,97 @@ +/* $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 +#include + +#include "tmux.h" + +/* Set up pollfd for buffers. */ +void +buffer_set( + struct pollfd *pfd, int fd, unused struct buffer *in, struct buffer *out) +{ + pfd->fd = fd; + pfd->events = POLLIN; + if (BUFFER_USED(out) > 0) + pfd->events |= POLLOUT; +} + +/* Fill buffers from socket based on poll results. */ +int +buffer_poll(struct pollfd *pfd, struct buffer *in, struct buffer *out) +{ + ssize_t n; + +#if 0 + log_debug("buffer_poll (%ld): fd=%d, revents=%d; out=%zu in=%zu", + (long) getpid(), + pfd->fd, pfd->revents, BUFFER_USED(out), BUFFER_USED(in)); +#endif + + if (pfd->revents & (POLLERR|POLLNVAL|POLLHUP)) + return (-1); + if (pfd->revents & POLLIN) { + buffer_ensure(in, BUFSIZ); + n = read(pfd->fd, BUFFER_IN(in), BUFFER_FREE(in)); +#if 0 + log_debug("buffer_poll: fd=%d, read=%zd", pfd->fd, n); +#endif + if (n == 0) + return (-1); + if (n == -1) { + if (errno != EINTR && errno != EAGAIN) + return (-1); + } else + buffer_add(in, n); + } + if (BUFFER_USED(out) > 0 && pfd->revents & POLLOUT) { + n = write(pfd->fd, BUFFER_OUT(out), BUFFER_USED(out)); +#if 0 + log_debug("buffer_poll: fd=%d, write=%zd", pfd->fd, n); +#endif + if (n == -1) { + if (errno != EINTR && errno != EAGAIN) + return (-1); + } else + buffer_remove(out, n); + } + return (0); +} + +/* Flush buffer output to socket. */ +void +buffer_flush(int fd, struct buffer *in, struct buffer *out) +{ + struct pollfd pfd; + + while (BUFFER_USED(out) > 0) { + buffer_set(&pfd, fd, in, out); + + if (poll(&pfd, 1, INFTIM) == -1) { + if (errno == EAGAIN || errno == EINTR) + continue; + fatal("poll failed"); + } + + if (buffer_poll(&pfd, in, out) != 0) + break; + } +} diff --git a/buffer.c b/buffer.c new file mode 100644 index 00000000..eea1fce7 --- /dev/null +++ b/buffer.c @@ -0,0 +1,227 @@ +/* $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 + +#include "tmux.h" + +/* Create a buffer. */ +struct buffer * +buffer_create(size_t size) +{ + struct buffer *b; + + if (size == 0) + fatalx("zero size"); + + b = xcalloc(1, sizeof *b); + + b->base = xmalloc(size); + b->space = size; + + return (b); +} + +/* Destroy a buffer. */ +void +buffer_destroy(struct buffer *b) +{ + xfree(b->base); + xfree(b); +} + +/* Empty a buffer. */ +void +buffer_clear(struct buffer *b) +{ + b->size = 0; + b->off = 0; +} + +/* Ensure free space for size in buffer. */ +void +buffer_ensure(struct buffer *b, size_t size) +{ + if (size == 0) + fatalx("zero size"); + + if (BUFFER_FREE(b) >= size) + return; + + if (b->off > 0) { + if (b->size > 0) + memmove(b->base, b->base + b->off, b->size); + b->off = 0; + } + + if (SIZE_MAX - b->size < size) + fatalx("size too big"); + while (b->space < b->size + size) { + b->base = xrealloc(b->base, 2, b->space); + b->space *= 2; + } +} + +/* Adjust buffer after data appended. */ +void +buffer_add(struct buffer *b, size_t size) +{ + if (size == 0) + fatalx("zero size"); + if (size > b->space - b->size) + fatalx("overflow"); + + b->size += size; +} + +/* Reverse buffer add. */ +void +buffer_reverse_add(struct buffer *b, size_t size) +{ + if (size == 0) + fatalx("zero size"); + if (size > b->size) + fatalx("underflow"); + + b->size -= size; +} + +/* Adjust buffer after data removed. */ +void +buffer_remove(struct buffer *b, size_t size) +{ + if (size == 0) + fatalx("zero size"); + if (size > b->size) + fatalx("underflow"); + + b->size -= size; + b->off += size; +} + +/* Reverse buffer remove. */ +void +buffer_reverse_remove(struct buffer *b, size_t size) +{ + if (size == 0) + fatalx("zero size"); + if (size > b->off) + fatalx("overflow"); + + b->size += size; + b->off -= size; +} + +/* Insert a section into the buffer. */ +void +buffer_insert_range(struct buffer *b, size_t base, size_t size) +{ + if (size == 0) + fatalx("zero size"); + if (base > b->size) + fatalx("range outside buffer"); + + buffer_ensure(b, size); + memmove(b->base + b->off + base + size, + b->base + b->off + base, b->size - base); + b->size += size; +} + +/* Delete a section from the buffer. */ +void +buffer_delete_range(struct buffer *b, size_t base, size_t size) +{ + if (size == 0) + fatalx("zero size"); + if (size > b->size) + fatalx("size too big"); + if (base + size > b->size) + fatalx("range outside buffer"); + + memmove(b->base + b->off + base, + b->base + b->off + base + size, b->size - base - size); + b->size -= size; +} + +/* Copy data into a buffer. */ +void +buffer_write(struct buffer *b, const void *data, size_t size) +{ + if (size == 0) + fatalx("zero size"); + + buffer_ensure(b, size); + memcpy(BUFFER_IN(b), data, size); + buffer_add(b, size); +} + +/* Copy data out of a buffer. */ +void +buffer_read(struct buffer *b, void *data, size_t size) +{ + if (size == 0) + fatalx("zero size"); + if (size > b->size) + fatalx("underflow"); + + memcpy(data, BUFFER_OUT(b), size); + buffer_remove(b, size); +} + +/* Store an 8-bit value. */ +void +buffer_write8(struct buffer *b, uint8_t n) +{ + buffer_ensure(b, 1); + BUFFER_IN(b)[0] = n; + buffer_add(b, 1); +} + +/* Store a 16-bit value. */ +void +buffer_write16(struct buffer *b, uint16_t n) +{ + buffer_ensure(b, 2); + BUFFER_IN(b)[0] = n & 0xff; + BUFFER_IN(b)[1] = n >> 8; + buffer_add(b, 2); +} + +/* Extract an 8-bit value. */ +uint8_t +buffer_read8(struct buffer *b) +{ + uint8_t n; + + n = BUFFER_OUT(b)[0]; + buffer_remove(b, 1); + return (n); +} + +/* Extract a 16-bit value. */ +uint16_t +buffer_read16(struct buffer *b) +{ + uint16_t n; + + n = BUFFER_OUT(b)[0] | (BUFFER_OUT(b)[1] << 8); + buffer_remove(b, 2); + return (n); +} diff --git a/cfg.c b/cfg.c new file mode 100644 index 00000000..e4278e14 --- /dev/null +++ b/cfg.c @@ -0,0 +1,132 @@ +/* $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 "tmux.h" + +/* + * Config file parser. Pretty quick and simple, each line is parsed into a + * argv array and executed as a command. + */ + +char *cfg_string(FILE *, char, int); +void printflike2 cfg_print(struct cmd_ctx *, const char *, ...); +void printflike2 cfg_error(struct cmd_ctx *, const char *, ...); + +char *cfg_cause; + +void printflike2 +cfg_print(unused struct cmd_ctx *ctx, unused const char *fmt, ...) +{ +} + +void printflike2 +cfg_error(unused struct cmd_ctx *ctx, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + xvasprintf(&cfg_cause, fmt, ap); + va_end(ap); +} + +int +load_cfg(const char *path, char **cause) +{ + FILE *f; + u_int n; + struct stat sb; + char *buf, *line, *ptr; + size_t len; + struct cmd_list *cmdlist; + struct cmd_ctx ctx; + + if (stat(path, &sb) != 0) { + xasprintf(cause, "%s: %s", path, strerror(errno)); + return (-1); + } + if (!S_ISREG(sb.st_mode)) { + xasprintf(cause, "%s: not a regular file", path); + return (-1); + } + + if ((f = fopen(path, "rb")) == NULL) { + xasprintf(cause, "%s: %s", path, strerror(errno)); + return (1); + } + n = 0; + + line = NULL; + while ((buf = fgetln(f, &len))) { + if (buf[len - 1] == '\n') + buf[len - 1] = '\0'; + else { + line = xrealloc(line, 1, len + 1); + memcpy(line, buf, len); + line[len] = '\0'; + buf = line; + } + n++; + + if (cmd_string_parse(buf, &cmdlist, cause) != 0) { + if (*cause == NULL) + continue; + goto error; + } + if (cmdlist == NULL) + continue; + cfg_cause = NULL; + + ctx.msgdata = NULL; + ctx.cursession = NULL; + ctx.curclient = NULL; + + ctx.error = cfg_error; + ctx.print = cfg_print; + ctx.info = cfg_print; + + ctx.cmdclient = NULL; + + cfg_cause = NULL; + cmd_list_exec(cmdlist, &ctx); + cmd_list_free(cmdlist); + if (cfg_cause != NULL) { + *cause = cfg_cause; + goto error; + } + } + if (line != NULL) + xfree(line); + fclose(f); + + return (0); + +error: + fclose(f); + + xasprintf(&ptr, "%s: %s at line %u", path, *cause, n); + xfree(*cause); + *cause = ptr; + return (1); +} diff --git a/client-fn.c b/client-fn.c new file mode 100644 index 00000000..3f42a105 --- /dev/null +++ b/client-fn.c @@ -0,0 +1,92 @@ +/* $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 +#include + +#include "tmux.h" + +void +client_fill_session(struct msg_command_data *data) +{ + char *env, *ptr1, *ptr2, buf[256]; + size_t len; + const char *errstr; + long long ll; + + data->pid = -1; + if ((env = getenv("TMUX")) == NULL) + return; + + if ((ptr2 = strrchr(env, ',')) == NULL || ptr2 == env) + return; + for (ptr1 = ptr2 - 1; ptr1 > env && *ptr1 != ','; ptr1--) + ; + if (*ptr1 != ',') + return; + ptr1++; + ptr2++; + + len = ptr2 - ptr1 - 1; + if (len > (sizeof buf) - 1) + return; + memcpy(buf, ptr1, len); + buf[len] = '\0'; + + ll = strtonum(buf, 0, LONG_MAX, &errstr); + if (errstr != NULL) + return; + data->pid = ll; + + ll = strtonum(ptr2, 0, UINT_MAX, &errstr); + if (errstr != NULL) + return; + data->idx = ll; +} + +void +client_write_server( + struct client_ctx *cctx, enum hdrtype type, void *buf, size_t len) +{ + struct hdr hdr; + + hdr.type = type; + hdr.size = len; + buffer_write(cctx->srv_out, &hdr, sizeof hdr); + + if (buf != NULL && len > 0) + buffer_write(cctx->srv_out, buf, len); +} + +void +client_write_server2(struct client_ctx *cctx, + enum hdrtype type, void *buf1, size_t len1, void *buf2, size_t len2) +{ + struct hdr hdr; + + hdr.type = type; + hdr.size = len1 + len2; + buffer_write(cctx->srv_out, &hdr, sizeof hdr); + + if (buf1 != NULL && len1 > 0) + buffer_write(cctx->srv_out, buf1, len1); + if (buf2 != NULL && len2 > 0) + buffer_write(cctx->srv_out, buf2, len2); +} diff --git a/client-msg.c b/client-msg.c new file mode 100644 index 00000000..fd48d403 --- /dev/null +++ b/client-msg.c @@ -0,0 +1,159 @@ +/* $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 +#include +#include +#include + +#include "tmux.h" + +int client_msg_fn_detach(struct hdr *, struct client_ctx *, char **); +int client_msg_fn_error(struct hdr *, struct client_ctx *, char **); +int client_msg_fn_shutdown(struct hdr *, struct client_ctx *, char **); +int client_msg_fn_exit(struct hdr *, struct client_ctx *, char **); +int client_msg_fn_exited(struct hdr *, struct client_ctx *, char **); +int client_msg_fn_suspend(struct hdr *, struct client_ctx *, char **); + +struct client_msg { + enum hdrtype type; + int (*fn)(struct hdr *, struct client_ctx *, char **); +}; +struct client_msg client_msg_table[] = { + { MSG_DETACH, client_msg_fn_detach }, + { MSG_ERROR, client_msg_fn_error }, + { MSG_EXIT, client_msg_fn_exit }, + { MSG_EXITED, client_msg_fn_exited }, + { MSG_SHUTDOWN, client_msg_fn_shutdown }, + { MSG_SUSPEND, client_msg_fn_suspend }, +}; + +int +client_msg_dispatch(struct client_ctx *cctx, char **error) +{ + struct hdr hdr; + struct client_msg *msg; + u_int i; + + if (BUFFER_USED(cctx->srv_in) < sizeof hdr) + return (1); + memcpy(&hdr, BUFFER_OUT(cctx->srv_in), sizeof hdr); + if (BUFFER_USED(cctx->srv_in) < (sizeof hdr) + hdr.size) + return (1); + buffer_remove(cctx->srv_in, sizeof hdr); + + for (i = 0; i < nitems(client_msg_table); i++) { + msg = client_msg_table + i; + if (msg->type == hdr.type) { + if (msg->fn(&hdr, cctx, error) != 0) + return (-1); + return (0); + } + } + fatalx("unexpected message"); +} + +int +client_msg_fn_error(struct hdr *hdr, struct client_ctx *cctx, char **error) +{ + if (hdr->size > SIZE_MAX - 1) + fatalx("bad MSG_ERROR size"); + + *error = xmalloc(hdr->size + 1); + buffer_read(cctx->srv_in, *error, hdr->size); + (*error)[hdr->size] = '\0'; + + return (-1); +} + +int +client_msg_fn_detach( + struct hdr *hdr, unused struct client_ctx *cctx, unused char **error) +{ + if (hdr->size != 0) + fatalx("bad MSG_DETACH size"); + + client_write_server(cctx, MSG_EXITING, NULL, 0); + cctx->flags |= CCTX_DETACH; + + return (0); +} + +int +client_msg_fn_shutdown( + struct hdr *hdr, unused struct client_ctx *cctx, unused char **error) +{ + if (hdr->size != 0) + fatalx("bad MSG_SHUTDOWN size"); + + client_write_server(cctx, MSG_EXITING, NULL, 0); + cctx->flags |= CCTX_SHUTDOWN; + + return (0); +} + +int +client_msg_fn_exit( + struct hdr *hdr, unused struct client_ctx *cctx, unused char **error) +{ + if (hdr->size != 0) + fatalx("bad MSG_EXIT size"); + + client_write_server(cctx, MSG_EXITING, NULL, 0); + cctx->flags |= CCTX_EXIT; + + return (0); +} + +int +client_msg_fn_exited( + struct hdr *hdr, unused struct client_ctx *cctx, unused char **error) +{ + if (hdr->size != 0) + fatalx("bad MSG_EXITED size"); + + return (-1); +} + +int +client_msg_fn_suspend( + struct hdr *hdr, unused struct client_ctx *cctx, unused char **error) +{ + struct sigaction act; + + if (hdr->size != 0) + fatalx("bad MSG_SUSPEND size"); + + memset(&act, 0, sizeof act); + sigemptyset(&act.sa_mask); + act.sa_flags = SA_RESTART; + + act.sa_handler = SIG_DFL; + if (sigaction(SIGTSTP, &act, NULL) != 0) + fatal("sigaction failed"); + + act.sa_handler = sighandler; + if (sigaction(SIGCONT, &act, NULL) != 0) + fatal("sigaction failed"); + + kill(getpid(), SIGTSTP); + + return (0); +} diff --git a/client.c b/client.c new file mode 100644 index 00000000..12041eed --- /dev/null +++ b/client.c @@ -0,0 +1,226 @@ +/* $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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "tmux.h" + +void client_handle_winch(struct client_ctx *); + +int +client_init(char *path, struct client_ctx *cctx, int start_server, int flags) +{ + struct sockaddr_un sa; + struct stat sb; + struct msg_identify_data data; + struct winsize ws; + size_t size; + int mode; + struct buffer *b; + char *name; + + if (lstat(path, &sb) != 0) { + if (start_server && errno == ENOENT) { + if ((cctx->srv_fd = server_start(path)) == -1) + goto start_failed; + goto server_started; + } + goto not_found; + } + if (!S_ISSOCK(sb.st_mode)) { + errno = ENOTSOCK; + goto not_found; + } + + memset(&sa, 0, sizeof sa); + sa.sun_family = AF_UNIX; + size = strlcpy(sa.sun_path, path, sizeof sa.sun_path); + if (size >= sizeof sa.sun_path) { + errno = ENAMETOOLONG; + goto not_found; + } + + if ((cctx->srv_fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) + fatal("socket"); + + if (connect( + cctx->srv_fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1) { + if (errno == ECONNREFUSED) { + if (unlink(path) != 0 || !start_server) + goto not_found; + if ((cctx->srv_fd = server_start(path)) == -1) + goto start_failed; + goto server_started; + } + goto not_found; + } + +server_started: + if ((mode = fcntl(cctx->srv_fd, F_GETFL)) == -1) + fatal("fcntl failed"); + if (fcntl(cctx->srv_fd, F_SETFL, mode|O_NONBLOCK) == -1) + fatal("fcntl failed"); + cctx->srv_in = buffer_create(BUFSIZ); + cctx->srv_out = buffer_create(BUFSIZ); + + if (isatty(STDIN_FILENO)) { + if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1) + fatal("ioctl(TIOCGWINSZ)"); + data.version = PROTOCOL_VERSION; + data.flags = flags; + data.sx = ws.ws_col; + data.sy = ws.ws_row; + *data.tty = '\0'; + if (getcwd(data.cwd, sizeof data.cwd) == NULL) + *data.cwd = '\0'; + + if ((name = ttyname(STDIN_FILENO)) == NULL) + fatal("ttyname failed"); + if (strlcpy(data.tty, name, sizeof data.tty) >= sizeof data.tty) + fatalx("ttyname failed"); + + b = buffer_create(BUFSIZ); + cmd_send_string(b, getenv("TERM")); + client_write_server2(cctx, MSG_IDENTIFY, + &data, sizeof data, BUFFER_OUT(b), BUFFER_USED(b)); + buffer_destroy(b); + } + + return (0); + +start_failed: + log_warnx("server failed to start"); + return (1); + +not_found: + log_warn("server not found"); + return (1); +} + +int +client_main(struct client_ctx *cctx) +{ + struct pollfd pfd; + char *error; + int xtimeout; /* Yay for ncurses namespace! */ + + siginit(); + + logfile("client"); + setproctitle("client"); + + error = NULL; + xtimeout = INFTIM; + while (!sigterm) { + if (sigchld) { + waitpid(WAIT_ANY, NULL, WNOHANG); + sigchld = 0; + } + if (sigwinch) + client_handle_winch(cctx); + if (sigcont) { + siginit(); + client_write_server(cctx, MSG_WAKEUP, NULL, 0); + sigcont = 0; + } + + switch (client_msg_dispatch(cctx, &error)) { + case -1: + goto out; + case 0: + /* May be more in buffer, don't let poll block. */ + xtimeout = 0; + break; + default: + /* Out of data, poll may block. */ + xtimeout = INFTIM; + break; + } + + pfd.fd = cctx->srv_fd; + pfd.events = POLLIN; + if (BUFFER_USED(cctx->srv_out) > 0) + pfd.events |= POLLOUT; + + if (poll(&pfd, 1, xtimeout) == -1) { + if (errno == EAGAIN || errno == EINTR) + continue; + fatal("poll failed"); + } + + if (buffer_poll(&pfd, cctx->srv_in, cctx->srv_out) != 0) + goto server_dead; + } + +out: + if (sigterm) { + printf("[terminated]\n"); + return (1); + } + + if (cctx->flags & CCTX_SHUTDOWN) { + printf("[server exited]\n"); + return (0); + } + + if (cctx->flags & CCTX_EXIT) { + printf("[exited]\n"); + return (0); + } + + if (cctx->flags & CCTX_DETACH) { + printf("[detached]\n"); + return (0); + } + + printf("[error: %s]\n", error); + return (1); + +server_dead: + printf("[lost server]\n"); + return (0); +} + +void +client_handle_winch(struct client_ctx *cctx) +{ + struct msg_resize_data data; + struct winsize ws; + + if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1) + fatal("ioctl failed"); + + data.sx = ws.ws_col; + data.sy = ws.ws_row; + client_write_server(cctx, MSG_RESIZE, &data, sizeof data); + + sigwinch = 0; +} diff --git a/clock.c b/clock.c new file mode 100644 index 00000000..60248f47 --- /dev/null +++ b/clock.c @@ -0,0 +1,161 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2009 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 "tmux.h" + +const char clock_table[14][5][5] = { + { { 1,1,1,1,1 }, /* 0 */ + { 1,0,0,0,1 }, + { 1,0,0,0,1 }, + { 1,0,0,0,1 }, + { 1,1,1,1,1 } }, + { { 0,0,0,0,1 }, /* 1 */ + { 0,0,0,0,1 }, + { 0,0,0,0,1 }, + { 0,0,0,0,1 }, + { 0,0,0,0,1 } }, + { { 1,1,1,1,1 }, /* 2 */ + { 0,0,0,0,1 }, + { 1,1,1,1,1 }, + { 1,0,0,0,0 }, + { 1,1,1,1,1 } }, + { { 1,1,1,1,1 }, /* 3 */ + { 0,0,0,0,1 }, + { 1,1,1,1,1 }, + { 0,0,0,0,1 }, + { 1,1,1,1,1 } }, + { { 1,0,0,0,1 }, /* 4 */ + { 1,0,0,0,1 }, + { 1,1,1,1,1 }, + { 0,0,0,0,1 }, + { 0,0,0,0,1 } }, + { { 1,1,1,1,1 }, /* 5 */ + { 1,0,0,0,0 }, + { 1,1,1,1,1 }, + { 0,0,0,0,1 }, + { 1,1,1,1,1 } }, + { { 1,1,1,1,1 }, /* 6 */ + { 1,0,0,0,0 }, + { 1,1,1,1,1 }, + { 1,0,0,0,1 }, + { 1,1,1,1,1 } }, + { { 1,1,1,1,1 }, /* 7 */ + { 0,0,0,0,1 }, + { 0,0,0,0,1 }, + { 0,0,0,0,1 }, + { 0,0,0,0,1 } }, + { { 1,1,1,1,1 }, /* 8 */ + { 1,0,0,0,1 }, + { 1,1,1,1,1 }, + { 1,0,0,0,1 }, + { 1,1,1,1,1 } }, + { { 1,1,1,1,1 }, /* 9 */ + { 1,0,0,0,1 }, + { 1,1,1,1,1 }, + { 0,0,0,0,1 }, + { 1,1,1,1,1 } }, + { { 0,0,0,0,0 }, /* : */ + { 0,0,1,0,0 }, + { 0,0,0,0,0 }, + { 0,0,1,0,0 }, + { 0,0,0,0,0 } }, + { { 1,1,1,1,1 }, /* A */ + { 1,0,0,0,1 }, + { 1,1,1,1,1 }, + { 1,0,0,0,1 }, + { 1,0,0,0,1 } }, + { { 1,1,1,1,1 }, /* P */ + { 1,0,0,0,1 }, + { 1,1,1,1,1 }, + { 1,0,0,0,0 }, + { 1,0,0,0,0 } }, + { { 1,0,0,0,1 }, /* M */ + { 1,1,0,1,1 }, + { 1,0,1,0,1 }, + { 1,0,0,0,1 }, + { 1,0,0,0,1 } }, +}; + +void +clock_draw(struct screen_write_ctx *ctx, u_int colour, int style) +{ + struct screen *s = ctx->s; + struct grid_cell gc; + char tim[64], *ptr; + time_t t; + u_int i, j, x, y, idx; + + t = time(NULL); + if (style == 0) + strftime(tim, sizeof tim, "%l:%M %p", localtime(&t)); + else + strftime(tim, sizeof tim, "%H:%M", localtime(&t)); + + screen_write_clearscreen(ctx); + memcpy(&gc, &grid_default_cell, sizeof gc); + gc.fg = colour; + + if (screen_size_x(s) < 6 * strlen(tim) || screen_size_y(s) < 6) { + if (screen_size_x(s) >= strlen(tim) && screen_size_y(s) != 0) { + x = (screen_size_x(s) / 2) - (strlen(tim) / 2); + y = screen_size_y(s) / 2; + screen_write_cursormove(ctx, x, y); + + gc.fg = colour; + screen_write_puts(ctx, &gc, "%s", tim); + } + return; + } + + x = (screen_size_x(s) / 2) - 3 * strlen(tim); + y = (screen_size_y(s) / 2) - 3; + + for (ptr = tim; *ptr != '\0'; ptr++) { + if (*ptr >= '0' && *ptr <= '9') + idx = *ptr - '0'; + else if (*ptr == ':') + idx = 10; + else if (*ptr == 'A') + idx = 11; + else if (*ptr == 'P') + idx = 12; + else if (*ptr == 'M') + idx = 13; + else { + x += 6; + continue; + } + + for (j = 0; j < 5; j++) { + screen_write_cursormove(ctx, x, y + j); + for (i = 0; i < 5; i++) { + if (clock_table[idx][j][i]) + gc.attr |= GRID_ATTR_REVERSE; + else + gc.attr &= ~GRID_ATTR_REVERSE; + screen_write_putc(ctx, &gc, ' '); + } + } + x += 6; + } +} diff --git a/cmd-attach-session.c b/cmd-attach-session.c new file mode 100644 index 00000000..1de4eba6 --- /dev/null +++ b/cmd-attach-session.c @@ -0,0 +1,80 @@ +/* $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" + +/* + * Attach existing session to the current terminal. + */ + +int cmd_attach_session_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_attach_session_entry = { + "attach-session", "attach", + "[-d] " CMD_TARGET_SESSION_USAGE, + CMD_DFLAG|CMD_CANTNEST|CMD_STARTSERVER, + cmd_target_init, + cmd_target_parse, + cmd_attach_session_exec, + cmd_target_send, + cmd_target_recv, + cmd_target_free, + cmd_target_print +}; + +int +cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_target_data *data = self->data; + struct session *s; + char *cause; + + if (ctx->curclient != NULL) + return (0); + + if (ARRAY_LENGTH(&sessions) == 0) { + ctx->error(ctx, "no sessions"); + return (-1); + } + if ((s = cmd_find_session(ctx, data->target)) == NULL) + return (-1); + + if (!(ctx->cmdclient->flags & CLIENT_TERMINAL)) { + ctx->error(ctx, "not a terminal"); + return (-1); + } + + if (tty_open(&ctx->cmdclient->tty, &cause) != 0) { + ctx->error(ctx, "terminal open failed: %s", cause); + xfree(cause); + return (-1); + } + + if (data->flags & CMD_DFLAG) + server_write_session(s, MSG_DETACH, NULL, 0); + ctx->cmdclient->session = s; + + server_write_client(ctx->cmdclient, MSG_READY, NULL, 0); + recalculate_sizes(); + server_redraw_client(ctx->cmdclient); + + return (1); +} + diff --git a/cmd-bind-key.c b/cmd-bind-key.c new file mode 100644 index 00000000..f0988899 --- /dev/null +++ b/cmd-bind-key.c @@ -0,0 +1,157 @@ +/* $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" + +/* + * Bind a key to a command, this recurses through cmd_*. + */ + +int cmd_bind_key_parse(struct cmd *, int, char **, char **); +int cmd_bind_key_exec(struct cmd *, struct cmd_ctx *); +void cmd_bind_key_send(struct cmd *, struct buffer *); +void cmd_bind_key_recv(struct cmd *, struct buffer *); +void cmd_bind_key_free(struct cmd *); +size_t cmd_bind_key_print(struct cmd *, char *, size_t); + +struct cmd_bind_key_data { + int key; + int can_repeat; + struct cmd_list *cmdlist; +}; + +const struct cmd_entry cmd_bind_key_entry = { + "bind-key", "bind", + "[-r] key command [arguments]", + 0, + NULL, + cmd_bind_key_parse, + cmd_bind_key_exec, + cmd_bind_key_send, + cmd_bind_key_recv, + cmd_bind_key_free, + cmd_bind_key_print +}; + +int +cmd_bind_key_parse(struct cmd *self, int argc, char **argv, char **cause) +{ + struct cmd_bind_key_data *data; + int opt; + + self->data = data = xmalloc(sizeof *data); + data->can_repeat = 0; + data->cmdlist = NULL; + + while ((opt = getopt(argc, argv, "r")) != -1) { + switch (opt) { + case 'r': + data->can_repeat = 1; + break; + default: + goto usage; + } + } + argc -= optind; + argv += optind; + if (argc < 1) + goto usage; + + if ((data->key = key_string_lookup_string(argv[0])) == KEYC_NONE) { + xasprintf(cause, "unknown key: %s", argv[0]); + goto error; + } + + argc--; + argv++; + if ((data->cmdlist = cmd_list_parse(argc, argv, cause)) == NULL) + goto error; + + return (0); + +usage: + xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); + +error: + self->entry->free(self); + return (-1); +} + +int +cmd_bind_key_exec(struct cmd *self, unused struct cmd_ctx *ctx) +{ + struct cmd_bind_key_data *data = self->data; + + if (data == NULL) + return (0); + + key_bindings_add(data->key, data->can_repeat, data->cmdlist); + data->cmdlist = NULL; /* avoid free */ + + return (0); +} + +void +cmd_bind_key_send(struct cmd *self, struct buffer *b) +{ + struct cmd_bind_key_data *data = self->data; + + buffer_write(b, data, sizeof *data); + cmd_list_send(data->cmdlist, b); +} + +void +cmd_bind_key_recv(struct cmd *self, struct buffer *b) +{ + struct cmd_bind_key_data *data; + + self->data = data = xmalloc(sizeof *data); + buffer_read(b, data, sizeof *data); + data->cmdlist = cmd_list_recv(b); +} + +void +cmd_bind_key_free(struct cmd *self) +{ + struct cmd_bind_key_data *data = self->data; + + if (data->cmdlist != NULL) + cmd_list_free(data->cmdlist); + xfree(data); +} + +size_t +cmd_bind_key_print(struct cmd *self, char *buf, size_t len) +{ + struct cmd_bind_key_data *data = self->data; + size_t off = 0; + const char *skey; + + off += xsnprintf(buf, len, "%s", self->entry->name); + if (data == NULL) + return (off); + if (off < len) { + skey = key_string_lookup_key(data->key); + off += xsnprintf(buf + off, len - off, " %s ", skey); + } + if (off < len) + off += cmd_list_print(data->cmdlist, buf + off, len - off); + return (off); +} diff --git a/cmd-break-pane.c b/cmd-break-pane.c new file mode 100644 index 00000000..f2b51edf --- /dev/null +++ b/cmd-break-pane.c @@ -0,0 +1,92 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2009 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 "tmux.h" + +/* + * Break pane off into a window. + */ + +int cmd_break_pane_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_break_pane_entry = { + "break-pane", "breakp", + CMD_PANE_WINDOW_USAGE " [-d]", + CMD_DFLAG, + cmd_pane_init, + cmd_pane_parse, + cmd_break_pane_exec, + cmd_pane_send, + cmd_pane_recv, + cmd_pane_free, + cmd_pane_print +}; + +int +cmd_break_pane_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_pane_data *data = self->data; + struct winlink *wl; + struct session *s; + struct window_pane *wp; + struct window *w; + char *cause; + + if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL) + return (-1); + if (data->pane == -1) + wp = wl->window->active; + else { + wp = window_pane_at_index(wl->window, data->pane); + if (wp == NULL) { + ctx->error(ctx, "no pane: %d", data->pane); + return (-1); + } + } + + if (window_count_panes(wl->window) == 1) { + ctx->error(ctx, "can't break pane: %d", data->pane); + return (-1); + } + + TAILQ_REMOVE(&wl->window->panes, wp, entry); + if (wl->window->active == wp) { + wl->window->active = TAILQ_PREV(wp, window_panes, entry); + if (wl->window->active == NULL) + wl->window->active = TAILQ_NEXT(wp, entry); + } + layout_refresh(wl->window, 0); + + w = wp->window = window_create1(s->sx, s->sy); + TAILQ_INSERT_HEAD(&w->panes, wp, entry); + w->active = wp; + w->name = default_window_name(w); + + wl = session_attach(s, w, -1, &cause); /* can't fail */ + if (!(data->flags & CMD_DFLAG)) + session_select(s, wl->idx); + layout_refresh(w, 0); + + server_redraw_session(s); + + return (0); +} diff --git a/cmd-choose-session.c b/cmd-choose-session.c new file mode 100644 index 00000000..d1f6ba23 --- /dev/null +++ b/cmd-choose-session.c @@ -0,0 +1,107 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2009 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" + +/* + * Enter choice mode to choose a session. + */ + +int cmd_choose_session_exec(struct cmd *, struct cmd_ctx *); + +void cmd_choose_session_callback(void *, int); + +const struct cmd_entry cmd_choose_session_entry = { + "choose-session", NULL, + CMD_TARGET_WINDOW_USAGE, + 0, + cmd_target_init, + cmd_target_parse, + cmd_choose_session_exec, + cmd_target_send, + cmd_target_recv, + cmd_target_free, + cmd_target_print +}; + +struct cmd_choose_session_data { + u_int client; +}; + +int +cmd_choose_session_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_target_data *data = self->data; + struct cmd_choose_session_data *cdata; + struct winlink *wl; + struct session *s; + u_int i, idx, cur; + + if (ctx->curclient == NULL) { + ctx->error(ctx, "must be run interactively"); + return (-1); + } + + if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) + return (-1); + + if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0) + return (0); + + cur = idx = 0; + for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { + s = ARRAY_ITEM(&sessions, i); + if (s == NULL) + continue; + if (s == ctx->curclient->session) + cur = idx; + idx++; + + window_choose_add(wl->window->active, i, + "%s: %u windows [%ux%u]%s", s->name, + winlink_count(&s->windows), s->sx, s->sy, + s->flags & SESSION_UNATTACHED ? "" : " (attached)"); + } + + cdata = xmalloc(sizeof *cdata); + cdata->client = server_client_index(ctx->curclient); + + window_choose_ready( + wl->window->active, cur, cmd_choose_session_callback, cdata); + + return (0); +} + +void +cmd_choose_session_callback(void *data, int idx) +{ + struct cmd_choose_session_data *cdata = data; + struct client *c; + + if (idx != -1 && cdata->client <= ARRAY_LENGTH(&clients) - 1) { + c = ARRAY_ITEM(&clients, cdata->client); + if (c != NULL && (u_int) idx <= ARRAY_LENGTH(&sessions) - 1) { + c->session = ARRAY_ITEM(&sessions, idx); + recalculate_sizes(); + server_redraw_client(c); + } + } + xfree(cdata); +} diff --git a/cmd-choose-window.c b/cmd-choose-window.c new file mode 100644 index 00000000..64eab882 --- /dev/null +++ b/cmd-choose-window.c @@ -0,0 +1,106 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2009 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" + +/* + * Enter choice mode to choose a window. + */ + +int cmd_choose_window_exec(struct cmd *, struct cmd_ctx *); + +void cmd_choose_window_callback(void *, int); + +const struct cmd_entry cmd_choose_window_entry = { + "choose-window", NULL, + CMD_TARGET_WINDOW_USAGE, + 0, + cmd_target_init, + cmd_target_parse, + cmd_choose_window_exec, + cmd_target_send, + cmd_target_recv, + cmd_target_free, + cmd_target_print +}; + +struct cmd_choose_window_data { + u_int session; +}; + +int +cmd_choose_window_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_target_data *data = self->data; + struct cmd_choose_window_data *cdata; + struct session *s; + struct winlink *wl, *wm; + struct window *w; + u_int idx, cur; + + if (ctx->curclient == NULL) { + ctx->error(ctx, "must be run interactively"); + return (-1); + } + s = ctx->curclient->session; + + if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) + return (-1); + + if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0) + return (0); + + cur = idx = 0; + RB_FOREACH(wm, winlinks, &s->windows) { + w = wm->window; + + if (wm == s->curw) + cur = idx; + idx++; + + window_choose_add(wl->window->active, + wm->idx, "%3d: %s [%ux%u %s] (%u panes)", wm->idx, w->name, + w->sx, w->sy, layout_name(w), window_count_panes(w)); + } + + cdata = xmalloc(sizeof *cdata); + if (session_index(s, &cdata->session) != 0) + fatalx("session not found"); + + window_choose_ready( + wl->window->active, cur, cmd_choose_window_callback, cdata); + + return (0); +} + +void +cmd_choose_window_callback(void *data, int idx) +{ + struct cmd_choose_window_data *cdata = data; + struct session *s; + + if (idx != -1 && cdata->session <= ARRAY_LENGTH(&sessions) - 1) { + s = ARRAY_ITEM(&sessions, cdata->session); + if (s != NULL && session_select(s, idx) == 0) + server_redraw_session(s); + recalculate_sizes(); + } + xfree(cdata); +} diff --git a/cmd-clear-history.c b/cmd-clear-history.c new file mode 100644 index 00000000..0c08f9b5 --- /dev/null +++ b/cmd-clear-history.c @@ -0,0 +1,68 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2009 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" + +/* + * Clear pane history. + */ + +void cmd_clear_history_init(struct cmd *, int); +int cmd_clear_history_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_clear_history_entry = { + "clear-history", "clearhist", + CMD_PANE_WINDOW_USAGE, + 0, + cmd_pane_init, + cmd_pane_parse, + cmd_clear_history_exec, + cmd_pane_send, + cmd_pane_recv, + cmd_pane_free, + cmd_pane_print +}; + +int +cmd_clear_history_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_pane_data *data = self->data; + struct winlink *wl; + struct window_pane *wp; + struct grid *gd; + + if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) + return (-1); + if (data->pane == -1) + wp = wl->window->active; + else { + wp = window_pane_at_index(wl->window, data->pane); + if (wp == NULL) { + ctx->error(ctx, "no pane: %d", data->pane); + return (-1); + } + } + gd = wp->base.grid; + + grid_move_lines(gd, 0, gd->hsize, gd->sy); + gd->hsize = 0; + + return (0); +} diff --git a/cmd-clock-mode.c b/cmd-clock-mode.c new file mode 100644 index 00000000..7f3f0d07 --- /dev/null +++ b/cmd-clock-mode.c @@ -0,0 +1,54 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2009 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" + +/* + * Enter clock mode. + */ + +int cmd_clock_mode_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_clock_mode_entry = { + "clock-mode", NULL, + CMD_TARGET_WINDOW_USAGE, + 0, + cmd_target_init, + cmd_target_parse, + cmd_clock_mode_exec, + cmd_target_send, + cmd_target_recv, + cmd_target_free, + cmd_target_print +}; + +int +cmd_clock_mode_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_target_data *data = self->data; + struct winlink *wl; + + if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) + return (-1); + + window_pane_set_mode(wl->window->active, &window_clock_mode); + + return (0); +} diff --git a/cmd-command-prompt.c b/cmd-command-prompt.c new file mode 100644 index 00000000..cf914648 --- /dev/null +++ b/cmd-command-prompt.c @@ -0,0 +1,178 @@ +/* $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 "tmux.h" + +/* + * Prompt for command in client. + */ + +void cmd_command_prompt_init(struct cmd *, int); +int cmd_command_prompt_exec(struct cmd *, struct cmd_ctx *); + +int cmd_command_prompt_callback(void *, const char *); + +const struct cmd_entry cmd_command_prompt_entry = { + "command-prompt", NULL, + CMD_TARGET_CLIENT_USAGE " [template]", + CMD_ARG01, + cmd_command_prompt_init, + cmd_target_parse, + cmd_command_prompt_exec, + cmd_target_send, + cmd_target_recv, + cmd_target_free, + cmd_target_print +}; + +struct cmd_command_prompt_data { + struct client *c; + char *template; +}; + +void +cmd_command_prompt_init(struct cmd *self, int key) +{ + struct cmd_target_data *data; + + cmd_target_init(self, key); + data = self->data; + + switch (key) { + case ',': + data->arg = xstrdup("rename-window '%%'"); + break; + case '.': + data->arg = xstrdup("move-window -t '%%'"); + break; + case 'f': + data->arg = xstrdup("find-window '%%'"); + break; + } +} + +int +cmd_command_prompt_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_target_data *data = self->data; + struct cmd_command_prompt_data *cdata; + struct client *c; + char *hdr, *ptr; + + if ((c = cmd_find_client(ctx, data->target)) == NULL) + return (-1); + + if (c->prompt_string != NULL) + return (0); + + cdata = xmalloc(sizeof *cdata); + cdata->c = c; + if (data->arg != NULL) { + cdata->template = xstrdup(data->arg); + if ((ptr = strchr(data->arg, ' ')) == NULL) + ptr = strchr(data->arg, '\0'); + xasprintf(&hdr, "(%.*s) ", (int) (ptr - data->arg), data->arg); + } else { + cdata->template = NULL; + hdr = xstrdup(":"); + } + status_prompt_set(c, hdr, cmd_command_prompt_callback, cdata, 0); + xfree(hdr); + + return (0); +} + +int +cmd_command_prompt_callback(void *data, const char *s) +{ + struct cmd_command_prompt_data *cdata = data; + struct client *c = cdata->c; + struct cmd_list *cmdlist; + struct cmd_ctx ctx; + char *cause, *ptr, *buf, ch; + size_t len, slen; + + if (s == NULL) { + xfree(cdata); + return (0); + } + slen = strlen(s); + + len = 0; + buf = NULL; + if (cdata->template != NULL) { + ptr = cdata->template; + while (*ptr != '\0') { + switch (ch = *ptr++) { + case '%': + if (*ptr != '%') + break; + ptr++; + + buf = xrealloc(buf, 1, len + slen + 1); + memcpy(buf + len, s, slen); + len += slen; + break; + default: + buf = xrealloc(buf, 1, len + 2); + buf[len++] = ch; + break; + } + } + xfree(cdata->template); + + buf[len] = '\0'; + s = buf; + } + xfree(cdata); + + if (cmd_string_parse(s, &cmdlist, &cause) != 0) { + if (cause == NULL) + return (0); + *cause = toupper((u_char) *cause); + status_message_set(c, cause); + xfree(cause); + cmdlist = NULL; + } + if (buf != NULL) + xfree(buf); + if (cmdlist == NULL) + return (0); + + ctx.msgdata = NULL; + ctx.cursession = c->session; + ctx.curclient = c; + + ctx.error = key_bindings_error; + ctx.print = key_bindings_print; + ctx.info = key_bindings_info; + + ctx.cmdclient = NULL; + + cmd_list_exec(cmdlist, &ctx); + cmd_list_free(cmdlist); + + if (c->prompt_callback != (void *) &cmd_command_prompt_callback) + return (1); + return (0); +} diff --git a/cmd-confirm-before.c b/cmd-confirm-before.c new file mode 100644 index 00000000..f544d810 --- /dev/null +++ b/cmd-confirm-before.c @@ -0,0 +1,141 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2009 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 + +#include "tmux.h" + +/* + * Asks for confirmation before executing a command. + */ + +int cmd_confirm_before_exec(struct cmd *, struct cmd_ctx *); +void cmd_confirm_before_init(struct cmd *, int); + +int cmd_confirm_before_callback(void *, const char *); + +struct cmd_confirm_before_data { + struct client *c; + char *cmd; +}; + +const struct cmd_entry cmd_confirm_before_entry = { + "confirm-before", "confirm", + CMD_TARGET_CLIENT_USAGE " command", + CMD_ARG1, + cmd_confirm_before_init, + cmd_target_parse, + cmd_confirm_before_exec, + cmd_target_send, + cmd_target_recv, + cmd_target_free, + cmd_target_print +}; + +void +cmd_confirm_before_init(struct cmd *self, int key) +{ + struct cmd_target_data *data; + + cmd_target_init(self, key); + data = self->data; + + switch (key) { + case '&': + data->arg = xstrdup("kill-window"); + break; + case 'x': + data->arg = xstrdup("kill-pane"); + break; + } +} + +int +cmd_confirm_before_exec(unused struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_target_data *data = self->data; + struct cmd_confirm_before_data *cdata; + struct client *c; + char *buf, *cmd, *ptr; + + if (ctx->curclient == NULL) { + ctx->error(ctx, "must be run interactively"); + return (-1); + } + + if ((c = cmd_find_client(ctx, data->target)) == NULL) + return (-1); + + ptr = xstrdup(data->arg); + if ((cmd = strtok(ptr, " \t")) == NULL) + cmd = ptr; + xasprintf(&buf, "Confirm '%s'? (y/n) ", cmd); + xfree(ptr); + + cdata = xmalloc(sizeof *cdata); + cdata->cmd = xstrdup(data->arg); + cdata->c = c; + status_prompt_set( + cdata->c, buf, cmd_confirm_before_callback, cdata, PROMPT_SINGLE); + + xfree(buf); + return (1); +} + +int +cmd_confirm_before_callback(void *data, const char *s) +{ + struct cmd_confirm_before_data *cdata = data; + struct client *c = cdata->c; + struct cmd_list *cmdlist; + struct cmd_ctx ctx; + char *cause; + + if (s == NULL || tolower((u_char) s[0]) != 'y' || s[1] != '\0') + goto out; + + if (cmd_string_parse(cdata->cmd, &cmdlist, &cause) != 0) { + if (cause != NULL) { + *cause = toupper((u_char) *cause); + status_message_set(c, cause); + xfree(cause); + } + goto out; + } + + ctx.msgdata = NULL; + ctx.cursession = c->session; + ctx.curclient = c; + + ctx.error = key_bindings_error; + ctx.print = key_bindings_print; + ctx.info = key_bindings_info; + + ctx.cmdclient = NULL; + + cmd_list_exec(cmdlist, &ctx); + cmd_list_free(cmdlist); + +out: + if (cdata->cmd != NULL) + xfree(cdata->cmd); + xfree(cdata); + + return (0); +} diff --git a/cmd-copy-buffer.c b/cmd-copy-buffer.c new file mode 100644 index 00000000..ab6fe14b --- /dev/null +++ b/cmd-copy-buffer.c @@ -0,0 +1,222 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2009 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" + +/* + * Copies a session paste buffer to another session. + */ + +int cmd_copy_buffer_parse(struct cmd *, int, char **, char **); +int cmd_copy_buffer_exec(struct cmd *, struct cmd_ctx *); +void cmd_copy_buffer_send(struct cmd *, struct buffer *); +void cmd_copy_buffer_recv(struct cmd *, struct buffer *); +void cmd_copy_buffer_free(struct cmd *); +void cmd_copy_buffer_init(struct cmd *, int); +size_t cmd_copy_buffer_print(struct cmd *, char *, size_t); + +struct cmd_copy_buffer_data { + char *dst_session; + char *src_session; + int dst_idx; + int src_idx; +}; + +const struct cmd_entry cmd_copy_buffer_entry = { + "copy-buffer", "copyb", + "[-a src-index] [-b dst-index] [-s src-session] [-t dst-session]", + 0, + cmd_copy_buffer_init, + cmd_copy_buffer_parse, + cmd_copy_buffer_exec, + cmd_copy_buffer_send, + cmd_copy_buffer_recv, + cmd_copy_buffer_free, + cmd_copy_buffer_print +}; + +void +cmd_copy_buffer_init(struct cmd *self, unused int arg) +{ + struct cmd_copy_buffer_data *data; + + self->data = data = xmalloc(sizeof *data); + data->dst_session = NULL; + data->src_session = NULL; + data->dst_idx = -1; + data->src_idx = -1; +} + +int +cmd_copy_buffer_parse(struct cmd *self, int argc, char **argv, char **cause) +{ + struct cmd_copy_buffer_data *data; + const char *errstr; + int n, opt; + + self->entry->init(self, 0); + data = self->data; + + while ((opt = getopt(argc, argv, "a:b:s:t:")) != -1) { + switch (opt) { + case 'a': + if (data->src_idx == -1) { + n = strtonum(optarg, 0, INT_MAX, &errstr); + if (errstr != NULL) { + xasprintf(cause, "buffer %s", errstr); + goto error; + } + data->src_idx = n; + } + break; + case 'b': + if (data->dst_idx == -1) { + n = strtonum(optarg, 0, INT_MAX, &errstr); + if (errstr != NULL) { + xasprintf(cause, "buffer %s", errstr); + goto error; + } + data->dst_idx = n; + } + break; + case 's': + if (data->src_session == NULL) + data->src_session = xstrdup(optarg); + break; + case 't': + if (data->dst_session == NULL) + data->dst_session = xstrdup(optarg); + break; + default: + goto usage; + } + } + argc -= optind; + argv += optind; + + return (0); + +usage: + xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); + +error: + self->entry->free(self); + return (-1); +} + +int +cmd_copy_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_copy_buffer_data *data = self->data; + struct paste_buffer *pb; + struct session *dst_session, *src_session; + u_int limit; + + if ((dst_session = cmd_find_session(ctx, data->dst_session)) == NULL || + (src_session = cmd_find_session(ctx, data->src_session)) == NULL) + return (-1); + + if (data->src_idx == -1) { + if ((pb = paste_get_top(&src_session->buffers)) == NULL) { + ctx->error(ctx, "no buffers"); + return (-1); + } + } else { + if ((pb = paste_get_index(&src_session->buffers, + data->src_idx)) == NULL) { + ctx->error(ctx, "no buffer %d", data->src_idx); + return (-1); + } + } + + limit = options_get_number(&dst_session->options, "buffer-limit"); + if (data->dst_idx == -1) { + paste_add(&dst_session->buffers, xstrdup(pb->data), limit); + return (0); + } + if (paste_replace(&dst_session->buffers, data->dst_idx, + xstrdup(pb->data)) != 0) { + ctx->error(ctx, "no buffer %d", data->dst_idx); + return (-1); + } + + return (0); +} + +void +cmd_copy_buffer_send(struct cmd *self, struct buffer *b) +{ + struct cmd_copy_buffer_data *data = self->data; + + buffer_write(b, data, sizeof *data); + cmd_send_string(b, data->dst_session); + cmd_send_string(b, data->src_session); +} + +void +cmd_copy_buffer_recv(struct cmd *self, struct buffer *b) +{ + struct cmd_copy_buffer_data *data; + + self->data = data = xmalloc(sizeof *data); + buffer_read(b, data, sizeof *data); + data->dst_session = cmd_recv_string(b); + data->src_session = cmd_recv_string(b); +} + +void +cmd_copy_buffer_free(struct cmd *self) +{ + struct cmd_copy_buffer_data *data = self->data; + + if (data->dst_session != NULL) + xfree(data->dst_session); + if (data->src_session != NULL) + xfree(data->src_session); + xfree(data); +} + +size_t +cmd_copy_buffer_print(struct cmd *self, char *buf, size_t len) +{ + struct cmd_copy_buffer_data *data = self->data; + size_t off = 0; + + off += xsnprintf(buf, len, "%s", self->entry->name); + if (data == NULL) + return (off); + if (off < len && data->src_idx != -1) { + off += xsnprintf(buf + off, len - off, " -a %d", + data->src_idx); + } + if (off < len && data->dst_idx != -1) { + off += xsnprintf(buf + off, len - off, " -b %d", + data->dst_idx); + } + if (off < len && data->src_session != NULL) { + off += cmd_prarg(buf + off, len - off, " -s ", + data->src_session); + } + if (off < len && data->dst_session != NULL) { + off += cmd_prarg(buf + off, len - off, " -t ", + data->dst_session); + } + return (off); +} diff --git a/cmd-copy-mode.c b/cmd-copy-mode.c new file mode 100644 index 00000000..af83e10c --- /dev/null +++ b/cmd-copy-mode.c @@ -0,0 +1,56 @@ +/* $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" + +/* + * Enter copy mode. + */ + +int cmd_copy_mode_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_copy_mode_entry = { + "copy-mode", NULL, + CMD_TARGET_WINDOW_USAGE, + CMD_UFLAG, + cmd_target_init, + cmd_target_parse, + cmd_copy_mode_exec, + cmd_target_send, + cmd_target_recv, + cmd_target_free, + NULL +}; + +int +cmd_copy_mode_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_target_data *data = self->data; + struct winlink *wl; + + if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) + return (-1); + + window_pane_set_mode(wl->window->active, &window_copy_mode); + if (data->flags & CMD_UFLAG) + window_copy_pageup(wl->window->active); + + return (0); +} diff --git a/cmd-delete-buffer.c b/cmd-delete-buffer.c new file mode 100644 index 00000000..7351cf2c --- /dev/null +++ b/cmd-delete-buffer.c @@ -0,0 +1,61 @@ +/* $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 + +#include "tmux.h" + +/* + * Delete a paste buffer. + */ + +int cmd_delete_buffer_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_delete_buffer_entry = { + "delete-buffer", "deleteb", + CMD_BUFFER_SESSION_USAGE, + 0, + cmd_buffer_init, + cmd_buffer_parse, + cmd_delete_buffer_exec, + cmd_buffer_send, + cmd_buffer_recv, + cmd_buffer_free, + cmd_buffer_print +}; + +int +cmd_delete_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_buffer_data *data = self->data; + struct session *s; + + if ((s = cmd_find_session(ctx, data->target)) == NULL) + return (-1); + + if (data->buffer == -1) + paste_free_top(&s->buffers); + else if (paste_free_index(&s->buffers, data->buffer) != 0) { + ctx->error(ctx, "no buffer %d", data->buffer); + return (-1); + } + + return (0); +} diff --git a/cmd-detach-client.c b/cmd-detach-client.c new file mode 100644 index 00000000..b900d84a --- /dev/null +++ b/cmd-detach-client.c @@ -0,0 +1,54 @@ +/* $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" + +/* + * Detach a client. + */ + +int cmd_detach_client_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_detach_client_entry = { + "detach-client", "detach", + CMD_TARGET_CLIENT_USAGE, + 0, + cmd_target_init, + cmd_target_parse, + cmd_detach_client_exec, + cmd_target_send, + cmd_target_recv, + cmd_target_free, + cmd_target_print +}; + +int +cmd_detach_client_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_target_data *data = self->data; + struct client *c; + + if ((c = cmd_find_client(ctx, data->target)) == NULL) + return (-1); + + server_write_client(c, MSG_DETACH, NULL, 0); + + return (0); +} diff --git a/cmd-down-pane.c b/cmd-down-pane.c new file mode 100644 index 00000000..ddfe412a --- /dev/null +++ b/cmd-down-pane.c @@ -0,0 +1,61 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2009 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" + +/* + * Move down a pane. + */ + +int cmd_down_pane_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_down_pane_entry = { + "down-pane", "downp", + CMD_TARGET_WINDOW_USAGE, + 0, + cmd_target_init, + cmd_target_parse, + cmd_down_pane_exec, + cmd_target_send, + cmd_target_recv, + cmd_target_free, + cmd_target_print +}; + +int +cmd_down_pane_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_target_data *data = self->data; + struct winlink *wl; + struct window *w; + + if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) + return (-1); + w = wl->window; + + do { + w->active = TAILQ_NEXT(w->active, entry); + if (w->active == NULL) + w->active = TAILQ_FIRST(&w->panes); + layout_refresh(w, 1); + } while (w->active->flags & PANE_HIDDEN); + + return (0); +} diff --git a/cmd-find-window.c b/cmd-find-window.c new file mode 100644 index 00000000..42637168 --- /dev/null +++ b/cmd-find-window.c @@ -0,0 +1,160 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2009 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 "tmux.h" + +/* + * Find window containing text. + */ + +int cmd_find_window_exec(struct cmd *, struct cmd_ctx *); + +void cmd_find_window_callback(void *, int); + +const struct cmd_entry cmd_find_window_entry = { + "find-window", "findw", + CMD_TARGET_WINDOW_USAGE " match-string", + CMD_ARG1, + cmd_target_init, + cmd_target_parse, + cmd_find_window_exec, + cmd_target_send, + cmd_target_recv, + cmd_target_free, + cmd_target_print +}; + +struct cmd_find_window_data { + u_int session; +}; + +int +cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_target_data *data = self->data; + struct cmd_find_window_data *cdata; + struct session *s; + struct winlink *wl, *wm; + struct window *w; + struct window_pane *wp; + ARRAY_DECL(, u_int) list_idx; + ARRAY_DECL(, char *) list_ctx; + char *sres, *sctx; + u_int i; + + if (ctx->curclient == NULL) { + ctx->error(ctx, "must be run interactively"); + return (-1); + } + s = ctx->curclient->session; + + if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) + return (-1); + + ARRAY_INIT(&list_idx); + ARRAY_INIT(&list_ctx); + + RB_FOREACH(wm, winlinks, &s->windows) { + i = 0; + TAILQ_FOREACH(wp, &wm->window->panes, entry) { + i++; + + if (strstr(wm->window->name, data->arg) != NULL) + sctx = xstrdup(""); + else { + sres = window_pane_search(wp, data->arg); + if (sres == NULL && + strstr(wp->base.title, data->arg) == NULL) + continue; + + if (sres == NULL) { + xasprintf(&sctx, + "pane %u title: \"%s\"", i - 1, + wp->base.title); + } else { + xasprintf(&sctx, "\"%s\"", sres); + xfree(sres); + } + } + + ARRAY_ADD(&list_idx, wm->idx); + ARRAY_ADD(&list_ctx, sctx); + } + } + + if (ARRAY_LENGTH(&list_idx) == 0) { + ctx->error(ctx, "no windows matching: %s", data->arg); + ARRAY_FREE(&list_idx); + ARRAY_FREE(&list_ctx); + return (-1); + } + + if (ARRAY_LENGTH(&list_idx) == 1) { + if (session_select(s, ARRAY_FIRST(&list_idx)) == 0) + server_redraw_session(s); + recalculate_sizes(); + goto out; + } + + if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0) + goto out; + + for (i = 0; i < ARRAY_LENGTH(&list_idx); i++) { + wm = winlink_find_by_index( + &s->windows, ARRAY_ITEM(&list_idx, i)); + w = wm->window; + + sctx = ARRAY_ITEM(&list_ctx, i); + window_choose_add(wl->window->active, + wm->idx, "%3d: %s [%ux%u] (%u panes) %s", wm->idx, w->name, + w->sx, w->sy, window_count_panes(w), sctx); + xfree(sctx); + } + + cdata = xmalloc(sizeof *cdata); + if (session_index(s, &cdata->session) != 0) + fatalx("session not found"); + + window_choose_ready( + wl->window->active, 0, cmd_find_window_callback, cdata); + +out: + ARRAY_FREE(&list_idx); + ARRAY_FREE(&list_ctx); + + return (0); +} + +void +cmd_find_window_callback(void *data, int idx) +{ + struct cmd_find_window_data *cdata = data; + struct session *s; + + if (idx != -1 && cdata->session <= ARRAY_LENGTH(&sessions) - 1) { + s = ARRAY_ITEM(&sessions, cdata->session); + if (s != NULL && session_select(s, idx) == 0) + server_redraw_session(s); + recalculate_sizes(); + } + xfree(cdata); +} diff --git a/cmd-generic.c b/cmd-generic.c new file mode 100644 index 00000000..01254a06 --- /dev/null +++ b/cmd-generic.c @@ -0,0 +1,694 @@ +/* $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 "tmux.h" + +#define CMD_FLAGS "adDgkuU" +#define CMD_FLAGMASK (CMD_AFLAG|CMD_DFLAG|CMD_BIGDFLAG|CMD_GFLAG|CMD_KFLAG| \ + CMD_UFLAG|CMD_BIGUFLAG) + +int cmd_do_flags(int, int, int *); +size_t cmd_print_flags(char *, size_t, size_t, int); +int cmd_fill_argument(int, char **, int, char **); + +size_t +cmd_prarg(char *buf, size_t len, const char *prefix, char *arg) +{ + if (strchr(arg, ' ') != NULL) + return (xsnprintf(buf, len, "%s\"%s\"", prefix, arg)); + return (xsnprintf(buf, len, "%s%s", prefix, arg)); +} + +int +cmd_do_flags(int opt, int iflags, int *oflags) +{ + switch (opt) { + case 'a': + if (iflags & CMD_AFLAG) { + (*oflags) |= CMD_AFLAG; + return (0); + } + return (-1); + case 'd': + if (iflags & CMD_DFLAG) { + (*oflags) |= CMD_DFLAG; + return (0); + } + return (-1); + case 'D': + if (iflags & CMD_BIGDFLAG) { + (*oflags) |= CMD_BIGDFLAG; + return (0); + } + return (-1); + case 'g': + if (iflags & CMD_GFLAG) { + (*oflags) |= CMD_GFLAG; + return (0); + } + return (-1); + case 'k': + if (iflags & CMD_KFLAG) { + (*oflags) |= CMD_KFLAG; + return (0); + } + return (-1); + case 'u': + if (iflags & CMD_UFLAG) { + (*oflags) |= CMD_UFLAG; + return (0); + } + return (-1); + case 'U': + if (iflags & CMD_BIGUFLAG) { + (*oflags) |= CMD_BIGUFLAG; + return (0); + } + return (-1); + } + return (1); +} + +size_t +cmd_print_flags(char *buf, size_t len, size_t off, int flags) +{ + size_t boff = off; + + if ((flags & CMD_FLAGMASK) == 0) + return (0); + off += xsnprintf(buf + off, len - off, " -"); + if (off < len && flags & CMD_AFLAG) + off += xsnprintf(buf + off, len - off, "a"); + if (off < len && flags & CMD_BIGDFLAG) + off += xsnprintf(buf + off, len - off, "D"); + if (off < len && flags & CMD_DFLAG) + off += xsnprintf(buf + off, len - off, "d"); + if (off < len && flags & CMD_GFLAG) + off += xsnprintf(buf + off, len - off, "g"); + if (off < len && flags & CMD_KFLAG) + off += xsnprintf(buf + off, len - off, "k"); + if (off < len && flags & CMD_UFLAG) + off += xsnprintf(buf + off, len - off, "u"); + if (off < len && flags & CMD_BIGUFLAG) + off += xsnprintf(buf + off, len - off, "U"); + return (off - boff); +} + +int +cmd_fill_argument(int flags, char **arg, int argc, char **argv) +{ + *arg = NULL; + + if (flags & CMD_ARG1) { + if (argc != 1) + return (-1); + *arg = xstrdup(argv[0]); + return (0); + } + + if (flags & CMD_ARG01) { + if (argc != 0 && argc != 1) + return (-1); + if (argc == 1) + *arg = xstrdup(argv[0]); + return (0); + } + + if (argc != 0) + return (-1); + return (0); +} + +void +cmd_target_init(struct cmd *self, unused int key) +{ + struct cmd_target_data *data; + + self->data = data = xmalloc(sizeof *data); + data->flags = 0; + data->target = NULL; + data->arg = NULL; +} + +int +cmd_target_parse(struct cmd *self, int argc, char **argv, char **cause) +{ + struct cmd_target_data *data; + int opt; + + /* Don't use the entry version since it may be dependent on key. */ + cmd_target_init(self, 0); + data = self->data; + + while ((opt = getopt(argc, argv, CMD_FLAGS "t:")) != -1) { + switch (cmd_do_flags(opt, self->entry->flags, &data->flags)) { + case -1: + goto usage; + case 0: + continue; + } + switch (opt) { + case 't': + if (data->target == NULL) + data->target = xstrdup(optarg); + break; + default: + goto usage; + } + } + argc -= optind; + argv += optind; + + if (cmd_fill_argument(self->entry->flags, &data->arg, argc, argv) != 0) + goto usage; + return (0); + +usage: + xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); + + self->entry->free(self); + return (-1); +} + +void +cmd_target_send(struct cmd *self, struct buffer *b) +{ + struct cmd_target_data *data = self->data; + + buffer_write(b, data, sizeof *data); + cmd_send_string(b, data->target); + cmd_send_string(b, data->arg); +} + +void +cmd_target_recv(struct cmd *self, struct buffer *b) +{ + struct cmd_target_data *data; + + self->data = data = xmalloc(sizeof *data); + buffer_read(b, data, sizeof *data); + data->target = cmd_recv_string(b); + data->arg = cmd_recv_string(b); +} + +void +cmd_target_free(struct cmd *self) +{ + struct cmd_target_data *data = self->data; + + if (data->target != NULL) + xfree(data->target); + if (data->arg != NULL) + xfree(data->arg); + xfree(data); +} + +size_t +cmd_target_print(struct cmd *self, char *buf, size_t len) +{ + struct cmd_target_data *data = self->data; + size_t off = 0; + + off += xsnprintf(buf, len, "%s", self->entry->name); + if (data == NULL) + return (off); + off += cmd_print_flags(buf, len, off, data->flags); + if (off < len && data->target != NULL) + off += cmd_prarg(buf + off, len - off, " -t ", data->target); + if (off < len && data->arg != NULL) + off += cmd_prarg(buf + off, len - off, " ", data->arg); + return (off); +} + +void +cmd_srcdst_init(struct cmd *self, unused int key) +{ + struct cmd_srcdst_data *data; + + self->data = data = xmalloc(sizeof *data); + data->flags = 0; + data->src = NULL; + data->dst = NULL; + data->arg = NULL; +} + +int +cmd_srcdst_parse(struct cmd *self, int argc, char **argv, char **cause) +{ + struct cmd_srcdst_data *data; + int opt; + + cmd_srcdst_init(self, 0); + data = self->data; + + while ((opt = getopt(argc, argv, CMD_FLAGS "s:t:")) != -1) { + switch (cmd_do_flags(opt, self->entry->flags, &data->flags)) { + case -1: + goto usage; + case 0: + continue; + } + switch (opt) { + case 's': + if (data->src == NULL) + data->src = xstrdup(optarg); + break; + case 't': + if (data->dst == NULL) + data->dst = xstrdup(optarg); + break; + default: + goto usage; + } + } + argc -= optind; + argv += optind; + + if (cmd_fill_argument(self->entry->flags, &data->arg, argc, argv) != 0) + goto usage; + return (0); + +usage: + xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); + + self->entry->free(self); + return (-1); +} + +void +cmd_srcdst_send(struct cmd *self, struct buffer *b) +{ + struct cmd_srcdst_data *data = self->data; + + buffer_write(b, data, sizeof *data); + cmd_send_string(b, data->src); + cmd_send_string(b, data->dst); + cmd_send_string(b, data->arg); +} + +void +cmd_srcdst_recv(struct cmd *self, struct buffer *b) +{ + struct cmd_srcdst_data *data; + + self->data = data = xmalloc(sizeof *data); + buffer_read(b, data, sizeof *data); + data->src = cmd_recv_string(b); + data->dst = cmd_recv_string(b); + data->arg = cmd_recv_string(b); +} + +void +cmd_srcdst_free(struct cmd *self) +{ + struct cmd_srcdst_data *data = self->data; + + if (data->src != NULL) + xfree(data->src); + if (data->dst != NULL) + xfree(data->dst); + if (data->arg != NULL) + xfree(data->arg); + xfree(data); +} + +size_t +cmd_srcdst_print(struct cmd *self, char *buf, size_t len) +{ + struct cmd_srcdst_data *data = self->data; + size_t off = 0; + + off += xsnprintf(buf, len, "%s", self->entry->name); + if (data == NULL) + return (off); + off += cmd_print_flags(buf, len, off, data->flags); + if (off < len && data->src != NULL) + off += xsnprintf(buf + off, len - off, " -s %s", data->src); + if (off < len && data->dst != NULL) + off += xsnprintf(buf + off, len - off, " -t %s", data->dst); + if (off < len && data->arg != NULL) + off += cmd_prarg(buf + off, len - off, " ", data->arg); + return (off); +} + +void +cmd_buffer_init(struct cmd *self, unused int key) +{ + struct cmd_buffer_data *data; + + self->data = data = xmalloc(sizeof *data); + data->flags = 0; + data->target = NULL; + data->buffer = -1; + data->arg = NULL; +} + +int +cmd_buffer_parse(struct cmd *self, int argc, char **argv, char **cause) +{ + struct cmd_buffer_data *data; + int opt, n; + const char *errstr; + + cmd_buffer_init(self, 0); + data = self->data; + + while ((opt = getopt(argc, argv, CMD_FLAGS "b:t:")) != -1) { + switch (cmd_do_flags(opt, self->entry->flags, &data->flags)) { + case -1: + goto usage; + case 0: + continue; + } + switch (opt) { + case 'b': + if (data->buffer == -1) { + n = strtonum(optarg, 0, INT_MAX, &errstr); + if (errstr != NULL) { + xasprintf(cause, "buffer %s", errstr); + goto error; + } + data->buffer = n; + } + break; + case 't': + if (data->target == NULL) + data->target = xstrdup(optarg); + break; + default: + goto usage; + } + } + argc -= optind; + argv += optind; + + if (cmd_fill_argument(self->entry->flags, &data->arg, argc, argv) != 0) + goto usage; + return (0); + +usage: + xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); + +error: + self->entry->free(self); + return (-1); +} + +void +cmd_buffer_send(struct cmd *self, struct buffer *b) +{ + struct cmd_buffer_data *data = self->data; + + buffer_write(b, data, sizeof *data); + cmd_send_string(b, data->target); + cmd_send_string(b, data->arg); +} + +void +cmd_buffer_recv(struct cmd *self, struct buffer *b) +{ + struct cmd_buffer_data *data; + + self->data = data = xmalloc(sizeof *data); + buffer_read(b, data, sizeof *data); + data->target = cmd_recv_string(b); + data->arg = cmd_recv_string(b); +} + +void +cmd_buffer_free(struct cmd *self) +{ + struct cmd_buffer_data *data = self->data; + + if (data->target != NULL) + xfree(data->target); + if (data->arg != NULL) + xfree(data->arg); + xfree(data); +} + +size_t +cmd_buffer_print(struct cmd *self, char *buf, size_t len) +{ + struct cmd_buffer_data *data = self->data; + size_t off = 0; + + off += xsnprintf(buf, len, "%s", self->entry->name); + if (data == NULL) + return (off); + off += cmd_print_flags(buf, len, off, data->flags); + if (off < len && data->buffer != -1) + off += xsnprintf(buf + off, len - off, " -b %d", data->buffer); + if (off < len && data->target != NULL) + off += cmd_prarg(buf + off, len - off, " -t ", data->target); + if (off < len && data->arg != NULL) + off += cmd_prarg(buf + off, len - off, " ", data->arg); + return (off); +} + +void +cmd_option_init(struct cmd *self, unused int key) +{ + struct cmd_option_data *data; + + self->data = data = xmalloc(sizeof *data); + data->flags = 0; + data->target = NULL; + data->option = NULL; + data->value = NULL; +} + +int +cmd_option_parse(struct cmd *self, int argc, char **argv, char **cause) +{ + struct cmd_option_data *data; + int opt; + + /* Don't use the entry version since it may be dependent on key. */ + cmd_option_init(self, 0); + data = self->data; + + while ((opt = getopt(argc, argv, CMD_FLAGS "t:")) != -1) { + switch (cmd_do_flags(opt, self->entry->flags, &data->flags)) { + case -1: + goto usage; + case 0: + continue; + } + switch (opt) { + case 't': + if (data->target == NULL) + data->target = xstrdup(optarg); + break; + default: + goto usage; + } + } + argc -= optind; + argv += optind; + + if (argc == 2) { + data->option = xstrdup(argv[0]); + data->value = xstrdup(argv[1]); + } else if (argc == 1) + data->option = xstrdup(argv[0]); + else + goto usage; + return (0); + +usage: + xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); + + self->entry->free(self); + return (-1); +} + +void +cmd_option_send(struct cmd *self, struct buffer *b) +{ + struct cmd_option_data *data = self->data; + + buffer_write(b, data, sizeof *data); + cmd_send_string(b, data->target); + cmd_send_string(b, data->option); + cmd_send_string(b, data->value); +} + +void +cmd_option_recv(struct cmd *self, struct buffer *b) +{ + struct cmd_option_data *data; + + self->data = data = xmalloc(sizeof *data); + buffer_read(b, data, sizeof *data); + data->target = cmd_recv_string(b); + data->option = cmd_recv_string(b); + data->value = cmd_recv_string(b); +} + +void +cmd_option_free(struct cmd *self) +{ + struct cmd_option_data *data = self->data; + + if (data->target != NULL) + xfree(data->target); + if (data->option != NULL) + xfree(data->option); + if (data->value != NULL) + xfree(data->value); + xfree(data); +} + +size_t +cmd_option_print(struct cmd *self, char *buf, size_t len) +{ + struct cmd_option_data *data = self->data; + size_t off = 0; + + off += xsnprintf(buf, len, "%s", self->entry->name); + if (data == NULL) + return (off); + off += cmd_print_flags(buf, len, off, data->flags); + if (off < len && data->target != NULL) + off += cmd_prarg(buf + off, len - off, " -t ", data->target); + if (off < len && data->option != NULL) + off += xsnprintf(buf + off, len - off, " %s", data->option); + if (off < len && data->value != NULL) + off += xsnprintf(buf + off, len - off, " %s", data->value); + return (off); +} + +void +cmd_pane_init(struct cmd *self, unused int key) +{ + struct cmd_pane_data *data; + + self->data = data = xmalloc(sizeof *data); + data->flags = 0; + data->target = NULL; + data->arg = NULL; + data->pane = -1; +} + +int +cmd_pane_parse(struct cmd *self, int argc, char **argv, char **cause) +{ + struct cmd_pane_data *data; + int opt, n; + const char *errstr; + + /* Don't use the entry version since it may be dependent on key. */ + cmd_pane_init(self, 0); + data = self->data; + + while ((opt = getopt(argc, argv, CMD_FLAGS "p:t:")) != -1) { + switch (cmd_do_flags(opt, self->entry->flags, &data->flags)) { + case -1: + goto usage; + case 0: + continue; + } + switch (opt) { + case 'p': + if (data->pane == -1) { + n = strtonum(optarg, 0, INT_MAX, &errstr); + if (errstr != NULL) { + xasprintf(cause, "pane %s", errstr); + goto error; + } + data->pane = n; + } + break; + case 't': + if (data->target == NULL) + data->target = xstrdup(optarg); + break; + default: + goto usage; + } + } + argc -= optind; + argv += optind; + + if (cmd_fill_argument(self->entry->flags, &data->arg, argc, argv) != 0) + goto usage; + return (0); + +usage: + xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); + +error: + self->entry->free(self); + return (-1); +} + +void +cmd_pane_send(struct cmd *self, struct buffer *b) +{ + struct cmd_pane_data *data = self->data; + + buffer_write(b, data, sizeof *data); + cmd_send_string(b, data->target); + cmd_send_string(b, data->arg); +} + +void +cmd_pane_recv(struct cmd *self, struct buffer *b) +{ + struct cmd_pane_data *data; + + self->data = data = xmalloc(sizeof *data); + buffer_read(b, data, sizeof *data); + data->target = cmd_recv_string(b); + data->arg = cmd_recv_string(b); +} + +void +cmd_pane_free(struct cmd *self) +{ + struct cmd_pane_data *data = self->data; + + if (data->target != NULL) + xfree(data->target); + if (data->arg != NULL) + xfree(data->arg); + xfree(data); +} + +size_t +cmd_pane_print(struct cmd *self, char *buf, size_t len) +{ + struct cmd_pane_data *data = self->data; + size_t off = 0; + + off += xsnprintf(buf, len, "%s", self->entry->name); + if (data == NULL) + return (off); + off += cmd_print_flags(buf, len, off, data->flags); + if (off < len && data->target != NULL) + off += cmd_prarg(buf + off, len - off, " -t ", data->target); + if (off < len && data->arg != NULL) + off += cmd_prarg(buf + off, len - off, " ", data->arg); + return (off); +} diff --git a/cmd-has-session.c b/cmd-has-session.c new file mode 100644 index 00000000..c0620e58 --- /dev/null +++ b/cmd-has-session.c @@ -0,0 +1,51 @@ +/* $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" + +/* + * Cause client to report an error and exit with 1 if session doesn't exist. + */ + +int cmd_has_session_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_has_session_entry = { + "has-session", "has", + CMD_TARGET_SESSION_USAGE, + 0, + cmd_target_init, + cmd_target_parse, + cmd_has_session_exec, + cmd_target_send, + cmd_target_recv, + cmd_target_free, + cmd_target_print +}; + +int +cmd_has_session_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_target_data *data = self->data; + + if (cmd_find_session(ctx, data->target) == NULL) + return (-1); + + return (0); +} diff --git a/cmd-kill-pane.c b/cmd-kill-pane.c new file mode 100644 index 00000000..b0e1dc7e --- /dev/null +++ b/cmd-kill-pane.c @@ -0,0 +1,72 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2009 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 "tmux.h" + +/* + * Kill pane. + */ + +int cmd_kill_pane_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_kill_pane_entry = { + "kill-pane", "killp", + CMD_PANE_WINDOW_USAGE, + 0, + cmd_pane_init, + cmd_pane_parse, + cmd_kill_pane_exec, + cmd_pane_send, + cmd_pane_recv, + cmd_pane_free, + cmd_pane_print +}; + +int +cmd_kill_pane_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_pane_data *data = self->data; + struct winlink *wl; + struct window_pane *wp; + + if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) + return (-1); + if (data->pane == -1) + wp = wl->window->active; + else { + wp = window_pane_at_index(wl->window, data->pane); + if (wp == NULL) { + ctx->error(ctx, "no pane: %d", data->pane); + return (-1); + } + } + + if (window_count_panes(wl->window) == 1) { + ctx->error(ctx, "can't kill pane: %d", data->pane); + return (-1); + } + + window_remove_pane(wl->window, wp); + server_redraw_window(wl->window); + layout_refresh(wl->window, 0); + return (0); +} diff --git a/cmd-kill-server.c b/cmd-kill-server.c new file mode 100644 index 00000000..b2627a0a --- /dev/null +++ b/cmd-kill-server.c @@ -0,0 +1,51 @@ +/* $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 +#include + +#include "tmux.h" + +/* + * Kill the server and do nothing else. + */ + +int cmd_kill_server_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_kill_server_entry = { + "kill-server", NULL, + "", + 0, + NULL, + NULL, + cmd_kill_server_exec, + NULL, + NULL, + NULL, + NULL +}; + +int +cmd_kill_server_exec(unused struct cmd *self, unused struct cmd_ctx *ctx) +{ + sigterm = 1; + + return (0); +} diff --git a/cmd-kill-session.c b/cmd-kill-session.c new file mode 100644 index 00000000..0ef9e4f1 --- /dev/null +++ b/cmd-kill-session.c @@ -0,0 +1,68 @@ +/* $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" + +/* + * Destroy session, detaching all clients attached to it and destroying any + * windows linked only to this session. + * + * Note this deliberately has no alias to make it hard to hit by accident. + */ + +int cmd_kill_session_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_kill_session_entry = { + "kill-session", NULL, + CMD_TARGET_SESSION_USAGE, + 0, + cmd_target_init, + cmd_target_parse, + cmd_kill_session_exec, + cmd_target_send, + cmd_target_recv, + cmd_target_free, + cmd_target_print +}; + +int +cmd_kill_session_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_target_data *data = self->data; + struct session *s; + struct client *c; + u_int i; + + if ((s = cmd_find_session(ctx, data->target)) == NULL) + return (-1); + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c->session == s) { + c->session = NULL; + server_write_client(c, MSG_EXIT, NULL, 0); + } + } + recalculate_sizes(); + + session_destroy(s); + + return (0); +} diff --git a/cmd-kill-window.c b/cmd-kill-window.c new file mode 100644 index 00000000..155968d0 --- /dev/null +++ b/cmd-kill-window.c @@ -0,0 +1,69 @@ +/* $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" + +/* + * Destroy window. + */ + +int cmd_kill_window_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_kill_window_entry = { + "kill-window", "killw", + CMD_TARGET_WINDOW_USAGE, + 0, + cmd_target_init, + cmd_target_parse, + cmd_kill_window_exec, + cmd_target_send, + cmd_target_recv, + cmd_target_free, + cmd_target_print +}; + +int +cmd_kill_window_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_target_data *data = self->data; + struct winlink *wl; + struct session *s; + struct client *c; + u_int i; + int destroyed; + + if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL) + return (-1); + + destroyed = session_detach(s, wl); + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c == NULL || c->session != s) + continue; + if (destroyed) { + c->session = NULL; + server_write_client(c, MSG_EXIT, NULL, 0); + } else + server_redraw_client(c); + } + recalculate_sizes(); + + return (0); +} diff --git a/cmd-last-window.c b/cmd-last-window.c new file mode 100644 index 00000000..48c7fe0e --- /dev/null +++ b/cmd-last-window.c @@ -0,0 +1,60 @@ +/* $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" + +/* + * Move to last window. + */ + +int cmd_last_window_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_last_window_entry = { + "last-window", "last", + CMD_TARGET_SESSION_USAGE, + 0, + cmd_target_init, + cmd_target_parse, + cmd_last_window_exec, + cmd_target_send, + cmd_target_recv, + cmd_target_free, + cmd_target_print +}; + +int +cmd_last_window_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_target_data *data = self->data; + struct session *s; + + if ((s = cmd_find_session(ctx, data->target)) == NULL) + return (-1); + + if (session_last(s) == 0) + server_redraw_session(s); + else { + ctx->error(ctx, "no last window"); + return (-1); + } + recalculate_sizes(); + + return (0); +} diff --git a/cmd-link-window.c b/cmd-link-window.c new file mode 100644 index 00000000..143e3cf0 --- /dev/null +++ b/cmd-link-window.c @@ -0,0 +1,109 @@ +/* $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 + +#include "tmux.h" + +/* + * Link a window into another session. + */ + +int cmd_link_window_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_link_window_entry = { + "link-window", "linkw", + "[-dk] " CMD_SRCDST_WINDOW_USAGE, + CMD_DFLAG|CMD_KFLAG, + cmd_srcdst_init, + cmd_srcdst_parse, + cmd_link_window_exec, + cmd_srcdst_send, + cmd_srcdst_recv, + cmd_srcdst_free, + cmd_srcdst_print +}; + +int +cmd_link_window_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_srcdst_data *data = self->data; + struct session *dst; + struct winlink *wl_src, *wl_dst; + char *cause; + int idx; + + if ((wl_src = cmd_find_window(ctx, data->src, NULL)) == NULL) + return (-1); + + if (arg_parse_window(data->dst, &dst, &idx) != 0) { + ctx->error(ctx, "bad window: %s", data->dst); + return (-1); + } + if (dst == NULL) + dst = ctx->cursession; + if (dst == NULL) + dst = cmd_current_session(ctx); + if (dst == NULL) { + ctx->error(ctx, "session not found: %s", data->dst); + return (-1); + } + + wl_dst = NULL; + if (idx != -1) + wl_dst = winlink_find_by_index(&dst->windows, idx); + if (wl_dst != NULL) { + if (wl_dst->window == wl_src->window) + return (0); + + if (data->flags & CMD_KFLAG) { + /* + * Can't use session_detach as it will destroy session + * if this makes it empty. + */ + session_alert_cancel(dst, wl_dst); + winlink_stack_remove(&dst->lastw, wl_dst); + winlink_remove(&dst->windows, wl_dst); + + /* Force select/redraw if current. */ + if (wl_dst == dst->curw) { + data->flags &= ~CMD_DFLAG; + dst->curw = NULL; + } + } + } + + wl_dst = session_attach(dst, wl_src->window, idx, &cause); + if (wl_dst == NULL) { + ctx->error(ctx, "create session failed: %s", cause); + xfree(cause); + return (-1); + } + + if (data->flags & CMD_DFLAG) + server_status_session(dst); + else { + session_select(dst, wl_dst->idx); + server_redraw_session(dst); + } + recalculate_sizes(); + + return (0); +} diff --git a/cmd-list-buffers.c b/cmd-list-buffers.c new file mode 100644 index 00000000..4edc38c3 --- /dev/null +++ b/cmd-list-buffers.c @@ -0,0 +1,91 @@ +/* $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 + +#include "tmux.h" + +/* + * List paste buffers. + */ + +int cmd_list_buffers_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_list_buffers_entry = { + "list-buffers", "lsb", + CMD_TARGET_SESSION_USAGE, + 0, + cmd_target_init, + cmd_target_parse, + cmd_list_buffers_exec, + cmd_target_send, + cmd_target_recv, + cmd_target_free, + cmd_target_print +}; + +int +cmd_list_buffers_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_target_data *data = self->data; + struct session *s; + struct paste_buffer *pb; + u_int idx; + char *tmp; + size_t size, in, out; + + if ((s = cmd_find_session(ctx, data->target)) == NULL) + return (-1); + + if (s->sx > 35) { /* leave three for ... */ + size = s->sx - 32; + tmp = xmalloc(size + 1); + } else { + size = 0; + tmp = NULL; + } + + idx = 0; + while ((pb = paste_walk_stack(&s->buffers, &idx)) != NULL) { + if (tmp != NULL) { + in = out = 0; + while (out < size && pb->data[in] != '\0') { + if (pb->data[in] > 31 && pb->data[in] != 127) + tmp[out++] = pb->data[in]; + in++; + } + tmp[out] = '\0'; + if (out == size) { + tmp[out - 1] = '.'; + tmp[out - 2] = '.'; + tmp[out - 3] = '.'; + } + + ctx->print(ctx, "%d: %zu bytes: \"%s\"", + idx - 1, strlen(pb->data), tmp); + } else + ctx->print(ctx, "%d: %zu bytes", idx, strlen(pb->data)); + } + + if (tmp != NULL) + xfree(tmp); + + return (0); +} diff --git a/cmd-list-clients.c b/cmd-list-clients.c new file mode 100644 index 00000000..343afc20 --- /dev/null +++ b/cmd-list-clients.c @@ -0,0 +1,67 @@ +/* $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 +#include + +#include "tmux.h" + +/* + * List all clients. + */ + +int cmd_list_clients_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_list_clients_entry = { + "list-clients", "lsc", + "", + 0, + NULL, + NULL, + cmd_list_clients_exec, + NULL, + NULL, + NULL, + NULL +}; + +int +cmd_list_clients_exec(unused struct cmd *self, struct cmd_ctx *ctx) +{ + struct client *c; + u_int i; + const char *s_utf8; + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c == NULL || c->session == NULL) + continue; + + if (c->tty.flags & TTY_UTF8) + s_utf8 = " (utf8)"; + else + s_utf8 = ""; + ctx->print(ctx, "%s: %s [%ux%u %s]%s", c->tty.path, + c->session->name, c->tty.sx, c->tty.sy, + c->tty.termname, s_utf8); + } + + return (0); +} diff --git a/cmd-list-commands.c b/cmd-list-commands.c new file mode 100644 index 00000000..59938ae2 --- /dev/null +++ b/cmd-list-commands.c @@ -0,0 +1,51 @@ +/* $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" + +/* + * List all commands with usages. + */ + +int cmd_list_commands_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_list_commands_entry = { + "list-commands", "lscm", + "", + 0, + NULL, + NULL, + cmd_list_commands_exec, + NULL, + NULL, + NULL, + NULL +}; + +int +cmd_list_commands_exec(unused struct cmd *self, struct cmd_ctx *ctx) +{ + const struct cmd_entry **entryp; + + for (entryp = cmd_table; *entryp != NULL; entryp++) + ctx->print(ctx, "%s %s", (*entryp)->name, (*entryp)->usage); + + return (0); +} diff --git a/cmd-list-keys.c b/cmd-list-keys.c new file mode 100644 index 00000000..1b22b4ab --- /dev/null +++ b/cmd-list-keys.c @@ -0,0 +1,59 @@ +/* $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" + +/* + * List key bindings. + */ + +int cmd_list_keys_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_list_keys_entry = { + "list-keys", "lsk", + "", + 0, + NULL, + NULL, + cmd_list_keys_exec, + NULL, + NULL, + NULL, + NULL +}; + +int +cmd_list_keys_exec(unused struct cmd *self, struct cmd_ctx *ctx) +{ + struct key_binding *bd; + const char *key; + char tmp[BUFSIZ]; + + SPLAY_FOREACH(bd, key_bindings, &key_bindings) { + if ((key = key_string_lookup_key(bd->key)) == NULL) + continue; + + *tmp = '\0'; + cmd_list_print(bd->cmdlist, tmp, sizeof tmp); + ctx->print(ctx, "%11s: %s", key, tmp); + } + + return (0); +} diff --git a/cmd-list-sessions.c b/cmd-list-sessions.c new file mode 100644 index 00000000..01f86524 --- /dev/null +++ b/cmd-list-sessions.c @@ -0,0 +1,67 @@ +/* $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 +#include + +#include "tmux.h" + +/* + * List all sessions. + */ + +int cmd_list_sessions_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_list_sessions_entry = { + "list-sessions", "ls", "", + 0, + NULL, + NULL, + cmd_list_sessions_exec, + NULL, + NULL, + NULL, + NULL +}; + +int +cmd_list_sessions_exec(unused struct cmd *self, struct cmd_ctx *ctx) +{ + struct session *s; + char *tim; + u_int i; + time_t t; + + for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { + s = ARRAY_ITEM(&sessions, i); + if (s == NULL) + continue; + + t = s->tv.tv_sec; + tim = ctime(&t); + *strchr(tim, '\n') = '\0'; + + ctx->print(ctx, "%s: %u windows (created %s) [%ux%u]%s", + s->name, winlink_count(&s->windows), tim, s->sx, s->sy, + s->flags & SESSION_UNATTACHED ? "" : " (attached)"); + } + + return (0); +} diff --git a/cmd-list-windows.c b/cmd-list-windows.c new file mode 100644 index 00000000..c9c3ad8c --- /dev/null +++ b/cmd-list-windows.c @@ -0,0 +1,88 @@ +/* $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 + +#include "tmux.h" + +/* + * List windows on given session. + */ + +int cmd_list_windows_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_list_windows_entry = { + "list-windows", "lsw", + CMD_TARGET_SESSION_USAGE, + 0, + cmd_target_init, + cmd_target_parse, + cmd_list_windows_exec, + cmd_target_send, + cmd_target_recv, + cmd_target_free, + cmd_target_print +}; + +int +cmd_list_windows_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_target_data *data = self->data; + struct session *s; + struct winlink *wl; + struct window *w; + struct window_pane *wp; + struct grid *gd; + u_int i; + unsigned long long size; + const char *name; + + if ((s = cmd_find_session(ctx, data->target)) == NULL) + return (-1); + + RB_FOREACH(wl, winlinks, &s->windows) { + w = wl->window; + ctx->print(ctx, + "%3d: %s [%ux%u]", wl->idx, w->name, w->sx, w->sy); + + TAILQ_FOREACH(wp, &w->panes, entry) { + gd = wp->base.grid; + + size = 0; + for (i = 0; i < gd->hsize; i++) { + size += gd->size[i] * sizeof **gd->data; + size += gd->usize[i] * sizeof **gd->udata; + } + size += gd->hsize * (sizeof *gd->data); + size += gd->hsize * (sizeof *gd->size); + + if (wp->fd != -1) + name = ttyname(wp->fd); + else + name = "unknown"; + ctx->print(ctx, + " %s [%ux%u %s] [history %u/%u, %llu bytes]", + name, wp->sx, wp->sy, layout_name(w), gd->hsize, + gd->hlimit, size); + } + } + + return (0); +} diff --git a/cmd-list.c b/cmd-list.c new file mode 100644 index 00000000..ffc8f1ee --- /dev/null +++ b/cmd-list.c @@ -0,0 +1,154 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2009 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 "tmux.h" + +struct cmd_list * +cmd_list_parse(int argc, char **argv, char **cause) +{ + struct cmd_list *cmdlist; + struct cmd *cmd; + int i, lastsplit; + size_t arglen, new_argc; + char **new_argv; + + cmdlist = xmalloc(sizeof *cmdlist); + TAILQ_INIT(cmdlist); + + lastsplit = 0; + for (i = 0; i < argc; i++) { + arglen = strlen(argv[i]); + if (arglen == 0 || argv[i][arglen - 1] != ';') + continue; + argv[i][arglen - 1] = '\0'; + + if (arglen > 1 && argv[i][arglen - 2] == '\\') { + argv[i][arglen - 2] = ';'; + continue; + } + + new_argc = i - lastsplit; + new_argv = argv + lastsplit; + if (arglen != 1) + new_argc++; + + cmd = cmd_parse(new_argc, new_argv, cause); + if (cmd == NULL) + goto bad; + TAILQ_INSERT_TAIL(cmdlist, cmd, qentry); + + lastsplit = i + 1; + } + + if (lastsplit != argc) { + cmd = cmd_parse(argc - lastsplit, argv + lastsplit, cause); + if (cmd == NULL) + goto bad; + TAILQ_INSERT_TAIL(cmdlist, cmd, qentry); + } + + return (cmdlist); + +bad: + cmd_list_free(cmdlist); + return (NULL); +} + +int +cmd_list_exec(struct cmd_list *cmdlist, struct cmd_ctx *ctx) +{ + struct cmd *cmd; + int n; + + TAILQ_FOREACH(cmd, cmdlist, qentry) { + if ((n = cmd_exec(cmd, ctx)) != 0) + return (n); + } + return (0); +} + +void +cmd_list_send(struct cmd_list *cmdlist, struct buffer *b) +{ + struct cmd *cmd; + u_int n; + + n = 0; + TAILQ_FOREACH(cmd, cmdlist, qentry) + n++; + + buffer_write(b, &n, sizeof n); + TAILQ_FOREACH(cmd, cmdlist, qentry) + cmd_send(cmd, b); +} + +struct cmd_list * +cmd_list_recv(struct buffer *b) +{ + struct cmd_list *cmdlist; + struct cmd *cmd; + u_int n; + + buffer_read(b, &n, sizeof n); + + cmdlist = xmalloc(sizeof *cmdlist); + TAILQ_INIT(cmdlist); + + while (n-- > 0) { + cmd = cmd_recv(b); + TAILQ_INSERT_TAIL(cmdlist, cmd, qentry); + } + + return (cmdlist); +} + +void +cmd_list_free(struct cmd_list *cmdlist) +{ + struct cmd *cmd; + + while (!TAILQ_EMPTY(cmdlist)) { + cmd = TAILQ_FIRST(cmdlist); + TAILQ_REMOVE(cmdlist, cmd, qentry); + cmd_free(cmd); + } + xfree(cmdlist); +} + +size_t +cmd_list_print(struct cmd_list *cmdlist, char *buf, size_t len) +{ + struct cmd *cmd; + size_t off; + + off = 0; + TAILQ_FOREACH(cmd, cmdlist, qentry) { + if (off >= len) + break; + off += cmd_print(cmd, buf + off, len - off); + if (off >= len) + break; + if (TAILQ_NEXT(cmd, qentry) != NULL) + off += xsnprintf(buf + off, len - off, " ; "); + } + return (off); +} diff --git a/cmd-load-buffer.c b/cmd-load-buffer.c new file mode 100644 index 00000000..23adfec2 --- /dev/null +++ b/cmd-load-buffer.c @@ -0,0 +1,106 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2009 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 + +#include +#include +#include +#include + +#include "tmux.h" + +/* + * Loads a session paste buffer from a file. + */ + +int cmd_load_buffer_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_load_buffer_entry = { + "load-buffer", "loadb", + CMD_BUFFER_SESSION_USAGE " path", + CMD_ARG1, + cmd_buffer_init, + cmd_buffer_parse, + cmd_load_buffer_exec, + cmd_buffer_send, + cmd_buffer_recv, + cmd_buffer_free, + cmd_buffer_print +}; + +int +cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_buffer_data *data = self->data; + struct session *s; + struct stat statbuf; + FILE *f; + char *buf; + u_int limit; + + if ((s = cmd_find_session(ctx, data->target)) == NULL) + return (-1); + + if (stat(data->arg, &statbuf) < 0) { + ctx->error(ctx, "%s: %s", data->arg, strerror(errno)); + return (-1); + } + if (!S_ISREG(statbuf.st_mode)) { + ctx->error(ctx, "%s: not a regular file", data->arg); + return (-1); + } + + if ((f = fopen(data->arg, "rb")) == NULL) { + ctx->error(ctx, "%s: %s", data->arg, strerror(errno)); + return (-1); + } + + /* + * We don't want to die due to memory exhaustion, hence xmalloc can't + * be used here. + */ + if ((buf = malloc(statbuf.st_size + 1)) == NULL) { + ctx->error(ctx, "malloc error: %s", strerror(errno)); + return (-1); + } + + if (fread(buf, 1, statbuf.st_size, f) != (size_t) statbuf.st_size) { + ctx->error(ctx, "%s: fread error", data->arg); + xfree(buf); + fclose(f); + return (-1); + } + + buf[statbuf.st_size] = '\0'; + fclose(f); + + limit = options_get_number(&s->options, "buffer-limit"); + if (data->buffer == -1) { + paste_add(&s->buffers, buf, limit); + return (0); + } + if (paste_replace(&s->buffers, data->buffer, buf) != 0) { + ctx->error(ctx, "no buffer %d", data->buffer); + xfree(buf); + return (-1); + } + + return (0); +} diff --git a/cmd-lock-server.c b/cmd-lock-server.c new file mode 100644 index 00000000..5dac3292 --- /dev/null +++ b/cmd-lock-server.c @@ -0,0 +1,54 @@ +/* $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 "tmux.h" + +/* + * Lock server. + */ + +int cmd_lock_server_exec(struct cmd *, struct cmd_ctx *); + +int cmd_lock_server_callback(void *, const char *); + +const struct cmd_entry cmd_lock_server_entry = { + "lock-server", "lock", + "", + 0, + NULL, + NULL, + cmd_lock_server_exec, + NULL, + NULL, + NULL, + NULL, +}; + +int +cmd_lock_server_exec(unused struct cmd *self, unused struct cmd_ctx *ctx) +{ + server_lock(); + + return (0); +} diff --git a/cmd-move-window.c b/cmd-move-window.c new file mode 100644 index 00000000..9f356a64 --- /dev/null +++ b/cmd-move-window.c @@ -0,0 +1,123 @@ +/* $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 "tmux.h" + +/* + * Move a window. + */ + +int cmd_move_window_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_move_window_entry = { + "move-window", "movew", + "[-dk] " CMD_SRCDST_WINDOW_USAGE, + CMD_DFLAG|CMD_KFLAG, + cmd_srcdst_init, + cmd_srcdst_parse, + cmd_move_window_exec, + cmd_srcdst_send, + cmd_srcdst_recv, + cmd_srcdst_free, + cmd_srcdst_print +}; + +int +cmd_move_window_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_srcdst_data *data = self->data; + struct session *src, *dst; + struct winlink *wl_src, *wl_dst; + struct client *c; + u_int i; + int destroyed, idx; + char *cause; + + if ((wl_src = cmd_find_window(ctx, data->src, &src)) == NULL) + return (-1); + + if (arg_parse_window(data->dst, &dst, &idx) != 0) { + ctx->error(ctx, "bad window: %s", data->dst); + return (-1); + } + if (dst == NULL) + dst = ctx->cursession; + if (dst == NULL) + dst = cmd_current_session(ctx); + if (dst == NULL) { + ctx->error(ctx, "session not found: %s", data->dst); + return (-1); + } + + wl_dst = NULL; + if (idx != -1) + wl_dst = winlink_find_by_index(&dst->windows, idx); + if (wl_dst != NULL) { + if (wl_dst->window == wl_src->window) + return (0); + + if (data->flags & CMD_KFLAG) { + /* + * Can't use session_detach as it will destroy session + * if this makes it empty. + */ + session_alert_cancel(dst, wl_dst); + winlink_stack_remove(&dst->lastw, wl_dst); + winlink_remove(&dst->windows, wl_dst); + + /* Force select/redraw if current. */ + if (wl_dst == dst->curw) { + data->flags &= ~CMD_DFLAG; + dst->curw = NULL; + } + } + } + + wl_dst = session_attach(dst, wl_src->window, idx, &cause); + if (wl_dst == NULL) { + ctx->error(ctx, "attach window failed: %s", cause); + xfree(cause); + return (-1); + } + + destroyed = session_detach(src, wl_src); + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c == NULL || c->session != src) + continue; + if (destroyed) { + c->session = NULL; + server_write_client(c, MSG_EXIT, NULL, 0); + } else + server_redraw_client(c); + } + + if (data->flags & CMD_DFLAG) + server_status_session(dst); + else { + session_select(dst, wl_dst->idx); + server_redraw_session(dst); + } + recalculate_sizes(); + + return (0); +} diff --git a/cmd-new-session.c b/cmd-new-session.c new file mode 100644 index 00000000..7c2c664b --- /dev/null +++ b/cmd-new-session.c @@ -0,0 +1,248 @@ +/* $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" + +/* + * Create a new session and attach to the current terminal unless -d is given. + */ + +int cmd_new_session_parse(struct cmd *, int, char **, char **); +int cmd_new_session_exec(struct cmd *, struct cmd_ctx *); +void cmd_new_session_send(struct cmd *, struct buffer *); +void cmd_new_session_recv(struct cmd *, struct buffer *); +void cmd_new_session_free(struct cmd *); +void cmd_new_session_init(struct cmd *, int); +size_t cmd_new_session_print(struct cmd *, char *, size_t); + +struct cmd_new_session_data { + char *newname; + char *winname; + char *cmd; + int flag_detached; +}; + +const struct cmd_entry cmd_new_session_entry = { + "new-session", "new", + "[-d] [-n window-name] [-s session-name] [command]", + CMD_STARTSERVER|CMD_CANTNEST, + cmd_new_session_init, + cmd_new_session_parse, + cmd_new_session_exec, + cmd_new_session_send, + cmd_new_session_recv, + cmd_new_session_free, + cmd_new_session_print +}; + +void +cmd_new_session_init(struct cmd *self, unused int arg) +{ + struct cmd_new_session_data *data; + + self->data = data = xmalloc(sizeof *data); + data->flag_detached = 0; + data->newname = NULL; + data->winname = NULL; + data->cmd = NULL; +} + +int +cmd_new_session_parse(struct cmd *self, int argc, char **argv, char **cause) +{ + struct cmd_new_session_data *data; + int opt; + + self->entry->init(self, 0); + data = self->data; + + while ((opt = getopt(argc, argv, "ds:n:")) != -1) { + switch (opt) { + case 'd': + data->flag_detached = 1; + break; + case 's': + if (data->newname == NULL) + data->newname = xstrdup(optarg); + break; + case 'n': + if (data->winname == NULL) + data->winname = xstrdup(optarg); + break; + default: + goto usage; + } + } + argc -= optind; + argv += optind; + if (argc != 0 && argc != 1) + goto usage; + + if (argc == 1) + data->cmd = xstrdup(argv[0]); + + return (0); + +usage: + xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); + + self->entry->free(self); + return (-1); +} + +int +cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_new_session_data *data = self->data; + struct client *c = ctx->cmdclient; + struct session *s; + char *cmd, *cwd, *cause; + u_int sx, sy; + + if (ctx->curclient != NULL) + return (0); + + if (!data->flag_detached) { + if (c == NULL) { + ctx->error(ctx, "no client to attach to"); + return (-1); + } + if (!(c->flags & CLIENT_TERMINAL)) { + ctx->error(ctx, "not a terminal"); + return (-1); + } + } + + if (data->newname != NULL && session_find(data->newname) != NULL) { + ctx->error(ctx, "duplicate session: %s", data->newname); + return (-1); + } + + cmd = data->cmd; + if (cmd == NULL) + cmd = options_get_string(&global_options, "default-command"); + if (c == NULL || c->cwd == NULL) + cwd = options_get_string(&global_options, "default-path"); + else + cwd = c->cwd; + + sx = 80; + sy = 25; + if (!data->flag_detached) { + sx = c->tty.sx; + sy = c->tty.sy; + } + + if (options_get_number(&global_options, "status")) { + if (sy == 0) + sy = 1; + else + sy--; + } + + if (!data->flag_detached && tty_open(&c->tty, &cause) != 0) { + ctx->error(ctx, "open terminal failed: %s", cause); + xfree(cause); + return (-1); + } + + + s = session_create(data->newname, cmd, cwd, sx, sy, &cause); + if (s == NULL) { + ctx->error(ctx, "create session failed: %s", cause); + xfree(cause); + return (-1); + } + if (data->winname != NULL) { + xfree(s->curw->window->name); + s->curw->window->name = xstrdup(data->winname); + options_set_number( + &s->curw->window->options, "automatic-rename", 0); + } + + if (data->flag_detached) { + if (c != NULL) + server_write_client(c, MSG_EXIT, NULL, 0); + } else { + c->session = s; + server_write_client(c, MSG_READY, NULL, 0); + server_redraw_client(c); + } + recalculate_sizes(); + + return (1); +} + +void +cmd_new_session_send(struct cmd *self, struct buffer *b) +{ + struct cmd_new_session_data *data = self->data; + + buffer_write(b, data, sizeof *data); + cmd_send_string(b, data->newname); + cmd_send_string(b, data->winname); + cmd_send_string(b, data->cmd); +} + +void +cmd_new_session_recv(struct cmd *self, struct buffer *b) +{ + struct cmd_new_session_data *data; + + self->data = data = xmalloc(sizeof *data); + buffer_read(b, data, sizeof *data); + data->newname = cmd_recv_string(b); + data->winname = cmd_recv_string(b); + data->cmd = cmd_recv_string(b); +} + +void +cmd_new_session_free(struct cmd *self) +{ + struct cmd_new_session_data *data = self->data; + + if (data->newname != NULL) + xfree(data->newname); + if (data->winname != NULL) + xfree(data->winname); + if (data->cmd != NULL) + xfree(data->cmd); + xfree(data); +} + +size_t +cmd_new_session_print(struct cmd *self, char *buf, size_t len) +{ + struct cmd_new_session_data *data = self->data; + size_t off = 0; + + off += xsnprintf(buf, len, "%s", self->entry->name); + if (data == NULL) + return (off); + if (off < len && data->flag_detached) + off += xsnprintf(buf + off, len - off, " -d"); + if (off < len && data->newname != NULL) + off += cmd_prarg(buf + off, len - off, " -s ", data->newname); + if (off < len && data->winname != NULL) + off += cmd_prarg(buf + off, len - off, " -n ", data->winname); + if (off < len && data->cmd != NULL) + off += cmd_prarg(buf + off, len - off, " ", data->cmd); + return (off); +} diff --git a/cmd-new-window.c b/cmd-new-window.c new file mode 100644 index 00000000..7d3eeb45 --- /dev/null +++ b/cmd-new-window.c @@ -0,0 +1,241 @@ +/* $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 + +#include "tmux.h" + +/* + * Create a new window. + */ + +int cmd_new_window_parse(struct cmd *, int, char **, char **); +int cmd_new_window_exec(struct cmd *, struct cmd_ctx *); +void cmd_new_window_send(struct cmd *, struct buffer *); +void cmd_new_window_recv(struct cmd *, struct buffer *); +void cmd_new_window_free(struct cmd *); +void cmd_new_window_init(struct cmd *, int); +size_t cmd_new_window_print(struct cmd *, char *, size_t); + +struct cmd_new_window_data { + char *target; + char *name; + char *cmd; + int flag_detached; + int flag_kill; +}; + +const struct cmd_entry cmd_new_window_entry = { + "new-window", "neww", + "[-dk] [-n window-name] [-t target-window] [command]", + 0, + cmd_new_window_init, + cmd_new_window_parse, + cmd_new_window_exec, + cmd_new_window_send, + cmd_new_window_recv, + cmd_new_window_free, + cmd_new_window_print +}; + +void +cmd_new_window_init(struct cmd *self, unused int arg) +{ + struct cmd_new_window_data *data; + + self->data = data = xmalloc(sizeof *data); + data->target = NULL; + data->name = NULL; + data->cmd = NULL; + data->flag_detached = 0; + data->flag_kill = 0; +} + +int +cmd_new_window_parse(struct cmd *self, int argc, char **argv, char **cause) +{ + struct cmd_new_window_data *data; + int opt; + + self->entry->init(self, 0); + data = self->data; + + while ((opt = getopt(argc, argv, "dkt:n:")) != -1) { + switch (opt) { + case 'd': + data->flag_detached = 1; + break; + case 'k': + data->flag_kill = 1; + break; + case 't': + if (data->target == NULL) + data->target = xstrdup(optarg); + break; + case 'n': + if (data->name == NULL) + data->name = xstrdup(optarg); + break; + default: + goto usage; + } + } + argc -= optind; + argv += optind; + if (argc != 0 && argc != 1) + goto usage; + + if (argc == 1) + data->cmd = xstrdup(argv[0]); + + return (0); + +usage: + xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); + + self->entry->free(self); + return (-1); +} + +int +cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_new_window_data *data = self->data; + struct session *s; + struct winlink *wl; + char *cmd, *cwd, *cause; + int idx; + + if (data == NULL) + return (0); + + if (arg_parse_window(data->target, &s, &idx) != 0) { + ctx->error(ctx, "bad window: %s", data->target); + return (-1); + } + if (s == NULL) + s = ctx->cursession; + if (s == NULL) + s = cmd_current_session(ctx); + if (s == NULL) { + ctx->error(ctx, "session not found: %s", data->target); + return (-1); + } + + wl = NULL; + if (idx != -1) + wl = winlink_find_by_index(&s->windows, idx); + if (wl != NULL) { + if (data->flag_kill) { + /* + * Can't use session_detach as it will destroy session + * if this makes it empty. + */ + session_alert_cancel(s, wl); + winlink_stack_remove(&s->lastw, wl); + winlink_remove(&s->windows, wl); + + /* Force select/redraw if current. */ + if (wl == s->curw) { + data->flag_detached = 0; + s->curw = NULL; + } + } + } + + cmd = data->cmd; + if (cmd == NULL) + cmd = options_get_string(&s->options, "default-command"); + if (ctx->cmdclient == NULL || ctx->cmdclient->cwd == NULL) + cwd = options_get_string(&global_options, "default-path"); + else + cwd = ctx->cmdclient->cwd; + + wl = session_new(s, data->name, cmd, cwd, idx, &cause); + if (wl == NULL) { + ctx->error(ctx, "create window failed: %s", cause); + xfree(cause); + return (-1); + } + if (!data->flag_detached) { + session_select(s, wl->idx); + server_redraw_session(s); + } else + server_status_session(s); + + return (0); +} + +void +cmd_new_window_send(struct cmd *self, struct buffer *b) +{ + struct cmd_new_window_data *data = self->data; + + buffer_write(b, data, sizeof *data); + cmd_send_string(b, data->target); + cmd_send_string(b, data->name); + cmd_send_string(b, data->cmd); +} + +void +cmd_new_window_recv(struct cmd *self, struct buffer *b) +{ + struct cmd_new_window_data *data; + + self->data = data = xmalloc(sizeof *data); + buffer_read(b, data, sizeof *data); + data->target = cmd_recv_string(b); + data->name = cmd_recv_string(b); + data->cmd = cmd_recv_string(b); +} + +void +cmd_new_window_free(struct cmd *self) +{ + struct cmd_new_window_data *data = self->data; + + if (data->target != NULL) + xfree(data->target); + if (data->name != NULL) + xfree(data->name); + if (data->cmd != NULL) + xfree(data->cmd); + xfree(data); +} + +size_t +cmd_new_window_print(struct cmd *self, char *buf, size_t len) +{ + struct cmd_new_window_data *data = self->data; + size_t off = 0; + + off += xsnprintf(buf, len, "%s", self->entry->name); + if (data == NULL) + return (off); + if (off < len && data->flag_detached) + off += xsnprintf(buf + off, len - off, " -d"); + if (off < len && data->target != NULL) + off += cmd_prarg(buf + off, len - off, " -t ", data->target); + if (off < len && data->name != NULL) + off += cmd_prarg(buf + off, len - off, " -n ", data->name); + if (off < len && data->cmd != NULL) + off += cmd_prarg(buf + off, len - off, " ", data->cmd); + return (off); +} diff --git a/cmd-next-layout.c b/cmd-next-layout.c new file mode 100644 index 00000000..85fd8d35 --- /dev/null +++ b/cmd-next-layout.c @@ -0,0 +1,55 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2009 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" + +/* + * Switch window to next layout. + */ + +int cmd_next_layout_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_next_layout_entry = { + "next-layout", "nextl", + CMD_TARGET_WINDOW_USAGE, + 0, + cmd_target_init, + cmd_target_parse, + cmd_next_layout_exec, + cmd_target_send, + cmd_target_recv, + cmd_target_free, + cmd_target_print +}; + +int +cmd_next_layout_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_target_data *data = self->data; + struct winlink *wl; + + if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) + return (-1); + + layout_next(wl->window); + ctx->info(ctx, "layout now: %s", layout_name(wl->window)); + + return (0); +} diff --git a/cmd-next-window.c b/cmd-next-window.c new file mode 100644 index 00000000..71346764 --- /dev/null +++ b/cmd-next-window.c @@ -0,0 +1,78 @@ +/* $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" + +/* + * Move to next window. + */ + +void cmd_next_window_init(struct cmd *, int); +int cmd_next_window_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_next_window_entry = { + "next-window", "next", + CMD_TARGET_SESSION_USAGE, + CMD_AFLAG, + cmd_next_window_init, + cmd_target_parse, + cmd_next_window_exec, + cmd_target_send, + cmd_target_recv, + cmd_target_free, + cmd_target_print +}; + +void +cmd_next_window_init(struct cmd *self, int key) +{ + struct cmd_target_data *data; + + cmd_target_init(self, key); + data = self->data; + + if (key == KEYC_ADDESC('n')) + data->flags |= CMD_AFLAG; +} + +int +cmd_next_window_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_target_data *data = self->data; + struct session *s; + int activity; + + if ((s = cmd_find_session(ctx, data->target)) == NULL) + return (-1); + + activity = 0; + if (data->flags & CMD_AFLAG) + activity = 1; + + if (session_next(s, activity) == 0) + server_redraw_session(s); + else { + ctx->error(ctx, "no next window"); + return (-1); + } + recalculate_sizes(); + + return (0); +} diff --git a/cmd-paste-buffer.c b/cmd-paste-buffer.c new file mode 100644 index 00000000..35472d3d --- /dev/null +++ b/cmd-paste-buffer.c @@ -0,0 +1,78 @@ +/* $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 + +#include "tmux.h" + +/* + * Paste paste buffer if present. + */ + +int cmd_paste_buffer_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_paste_buffer_entry = { + "paste-buffer", "pasteb", + "[-d] " CMD_BUFFER_WINDOW_USAGE, + CMD_DFLAG, + cmd_buffer_init, + cmd_buffer_parse, + cmd_paste_buffer_exec, + cmd_buffer_send, + cmd_buffer_recv, + cmd_buffer_free, + cmd_buffer_print +}; + +int +cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_buffer_data *data = self->data; + struct winlink *wl; + struct window *w; + struct session *s; + struct paste_buffer *pb; + + if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL) + return (-1); + w = wl->window; + + if (data->buffer == -1) + pb = paste_get_top(&s->buffers); + else { + if ((pb = paste_get_index(&s->buffers, data->buffer)) == NULL) { + ctx->error(ctx, "no buffer %d", data->buffer); + return (-1); + } + } + + if (pb != NULL) + buffer_write(w->active->out, pb->data, strlen(pb->data)); + + /* Delete the buffer if -d. */ + if (data->flags & CMD_DFLAG) { + if (data->buffer == -1) + paste_free_top(&s->buffers); + else + paste_free_index(&s->buffers, data->buffer); + } + + return (0); +} diff --git a/cmd-previous-layout.c b/cmd-previous-layout.c new file mode 100644 index 00000000..5b662ede --- /dev/null +++ b/cmd-previous-layout.c @@ -0,0 +1,55 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2009 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" + +/* + * Switch window to previous layout. + */ + +int cmd_previous_layout_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_previous_layout_entry = { + "previous-layout", "prevl", + CMD_TARGET_WINDOW_USAGE, + 0, + cmd_target_init, + cmd_target_parse, + cmd_previous_layout_exec, + cmd_target_send, + cmd_target_recv, + cmd_target_free, + cmd_target_print +}; + +int +cmd_previous_layout_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_target_data *data = self->data; + struct winlink *wl; + + if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) + return (-1); + + layout_previous(wl->window); + ctx->info(ctx, "layout now: %s", layout_name(wl->window)); + + return (0); +} diff --git a/cmd-previous-window.c b/cmd-previous-window.c new file mode 100644 index 00000000..7b880347 --- /dev/null +++ b/cmd-previous-window.c @@ -0,0 +1,78 @@ +/* $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" + +/* + * Move to previous window. + */ + +void cmd_previous_window_init(struct cmd *, int); +int cmd_previous_window_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_previous_window_entry = { + "previous-window", "prev", + CMD_TARGET_SESSION_USAGE, + CMD_AFLAG, + cmd_previous_window_init, + cmd_target_parse, + cmd_previous_window_exec, + cmd_target_send, + cmd_target_recv, + cmd_target_free, + cmd_target_print +}; + +void +cmd_previous_window_init(struct cmd *self, int key) +{ + struct cmd_target_data *data; + + cmd_target_init(self, key); + data = self->data; + + if (key == KEYC_ADDESC('p')) + data->flags |= CMD_AFLAG; +} + +int +cmd_previous_window_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_target_data *data = self->data; + struct session *s; + int activity; + + if ((s = cmd_find_session(ctx, data->target)) == NULL) + return (-1); + + activity = 0; + if (data->flags & CMD_AFLAG) + activity = 1; + + if (session_previous(s, activity) == 0) + server_redraw_session(s); + else { + ctx->error(ctx, "no previous window"); + return (-1); + } + recalculate_sizes(); + + return (0); +} diff --git a/cmd-refresh-client.c b/cmd-refresh-client.c new file mode 100644 index 00000000..9193a953 --- /dev/null +++ b/cmd-refresh-client.c @@ -0,0 +1,54 @@ +/* $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" + +/* + * Refresh client. + */ + +int cmd_refresh_client_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_refresh_client_entry = { + "refresh-client", "refresh", + CMD_TARGET_CLIENT_USAGE, + 0, + cmd_target_init, + cmd_target_parse, + cmd_refresh_client_exec, + cmd_target_send, + cmd_target_recv, + cmd_target_free, + cmd_target_print +}; + +int +cmd_refresh_client_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_target_data *data = self->data; + struct client *c; + + if ((c = cmd_find_client(ctx, data->target)) == NULL) + return (-1); + + server_redraw_client(c); + + return (0); +} diff --git a/cmd-rename-session.c b/cmd-rename-session.c new file mode 100644 index 00000000..b05835f1 --- /dev/null +++ b/cmd-rename-session.c @@ -0,0 +1,57 @@ +/* $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 + +#include "tmux.h" + +/* + * Change session name. + */ + +int cmd_rename_session_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_rename_session_entry = { + "rename-session", "rename", + CMD_TARGET_SESSION_USAGE " new-name", + CMD_ARG1, + cmd_target_init, + cmd_target_parse, + cmd_rename_session_exec, + cmd_target_send, + cmd_target_recv, + cmd_target_free, + cmd_target_print +}; + +int +cmd_rename_session_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_target_data *data = self->data; + struct session *s; + + if ((s = cmd_find_session(ctx, data->target)) == NULL) + return (-1); + + xfree(s->name); + s->name = xstrdup(data->arg); + + return (0); +} diff --git a/cmd-rename-window.c b/cmd-rename-window.c new file mode 100644 index 00000000..985a7b58 --- /dev/null +++ b/cmd-rename-window.c @@ -0,0 +1,61 @@ +/* $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 + +#include "tmux.h" + +/* + * Rename a window. + */ + +int cmd_rename_window_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_rename_window_entry = { + "rename-window", "renamew", + CMD_TARGET_WINDOW_USAGE " new-name", + CMD_ARG1, + cmd_target_init, + cmd_target_parse, + cmd_rename_window_exec, + cmd_target_send, + cmd_target_recv, + cmd_target_free, + cmd_target_print +}; + +int +cmd_rename_window_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_target_data *data = self->data; + struct session *s; + struct winlink *wl; + + if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL) + return (-1); + + xfree(wl->window->name); + wl->window->name = xstrdup(data->arg); + options_set_number(&wl->window->options, "automatic-rename", 0); + + server_status_session(s); + + return (0); +} diff --git a/cmd-resize-pane.c b/cmd-resize-pane.c new file mode 100644 index 00000000..2f1c3ad7 --- /dev/null +++ b/cmd-resize-pane.c @@ -0,0 +1,105 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2009 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 "tmux.h" + +/* + * Increase or decrease pane size. + */ + +void cmd_resize_pane_init(struct cmd *, int); +int cmd_resize_pane_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_resize_pane_entry = { + "resize-pane", "resizep", + CMD_PANE_WINDOW_USAGE "[-DU] [adjustment]", + CMD_ARG01|CMD_BIGUFLAG|CMD_BIGDFLAG, + cmd_resize_pane_init, + cmd_pane_parse, + cmd_resize_pane_exec, + cmd_pane_send, + cmd_pane_recv, + cmd_pane_free, + cmd_pane_print +}; + +void +cmd_resize_pane_init(struct cmd *self, int key) +{ + struct cmd_pane_data *data; + + cmd_pane_init(self, key); + data = self->data; + + if (key == KEYC_ADDCTL(KEYC_DOWN)) + data->flags |= CMD_BIGDFLAG; + + if (key == KEYC_ADDESC(KEYC_UP)) + data->arg = xstrdup("5"); + if (key == KEYC_ADDESC(KEYC_DOWN)) { + data->flags |= CMD_BIGDFLAG; + data->arg = xstrdup("5"); + } +} + +int +cmd_resize_pane_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_pane_data *data = self->data; + struct winlink *wl; + const char *errstr; + struct window_pane *wp; + u_int adjust; + + if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) + return (-1); + if (data->pane == -1) + wp = wl->window->active; + else { + wp = window_pane_at_index(wl->window, data->pane); + if (wp == NULL) { + ctx->error(ctx, "no pane: %d", data->pane); + return (-1); + } + } + + if (data->arg == NULL) + adjust = 1; + else { + adjust = strtonum(data->arg, 1, INT_MAX, &errstr); + if (errstr != NULL) { + ctx->error(ctx, "adjustment %s: %s", errstr, data->arg); + return (-1); + } + } + + if (!(data->flags & CMD_BIGDFLAG)) + adjust = -adjust; + if (layout_resize(wp, adjust) != 0) { + ctx->error(ctx, "layout %s " + "does not support resizing", layout_name(wp->window)); + return (-1); + } + server_redraw_window(wl->window); + + return (0); +} diff --git a/cmd-respawn-window.c b/cmd-respawn-window.c new file mode 100644 index 00000000..7c5b2fd5 --- /dev/null +++ b/cmd-respawn-window.c @@ -0,0 +1,87 @@ +/* $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 "tmux.h" + +/* + * Respawn a window (restart the command). Kill existing if -k given. + */ + +int cmd_respawn_window_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_respawn_window_entry = { + "respawn-window", "respawnw", + "[-k] " CMD_TARGET_WINDOW_USAGE " [command]", + CMD_ARG01|CMD_KFLAG, + cmd_target_init, + cmd_target_parse, + cmd_respawn_window_exec, + cmd_target_send, + cmd_target_recv, + cmd_target_free, + cmd_target_print +}; + +int +cmd_respawn_window_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_target_data *data = self->data; + struct winlink *wl; + struct window *w; + struct window_pane *wp; + struct session *s; + const char **env; + char *cause; + + if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL) + return (-1); + w = wl->window; + + if (!(data->flags & CMD_KFLAG)) { + TAILQ_FOREACH(wp, &w->panes, entry) { + if (wp->fd == -1) + continue; + ctx->error(ctx, + "window still active: %s:%d", s->name, wl->idx); + return (-1); + } + } + + env = server_fill_environ(s); + + wp = TAILQ_FIRST(&w->panes); + TAILQ_REMOVE(&w->panes, wp, entry); + window_destroy_panes(w); + TAILQ_INSERT_HEAD(&w->panes, wp, entry); + window_pane_resize(wp, w->sx, w->sy); + if (window_pane_spawn(wp, data->arg, NULL, env, &cause) != 0) { + ctx->error(ctx, "respawn window failed: %s", cause); + xfree(cause); + return (-1); + } + screen_reinit(&wp->base); + + recalculate_sizes(); + server_redraw_window(w); + + return (0); +} diff --git a/cmd-rotate-window.c b/cmd-rotate-window.c new file mode 100644 index 00000000..354e6942 --- /dev/null +++ b/cmd-rotate-window.c @@ -0,0 +1,111 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2009 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" + +/* + * Rotate the panes in a window. + */ + +void cmd_rotate_window_init(struct cmd *, int); +int cmd_rotate_window_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_rotate_window_entry = { + "rotate-window", "rotatew", + "[-DU] " CMD_TARGET_WINDOW_USAGE, + CMD_BIGUFLAG|CMD_BIGDFLAG, + cmd_rotate_window_init, + cmd_target_parse, + cmd_rotate_window_exec, + cmd_target_send, + cmd_target_recv, + cmd_target_free, + cmd_target_print +}; + +void +cmd_rotate_window_init(struct cmd *self, int key) +{ + struct cmd_target_data *data; + + cmd_target_init(self, key); + data = self->data; + + if (key == KEYC_ADDESC('o')) + data->flags |= CMD_BIGDFLAG; +} + +int +cmd_rotate_window_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_target_data *data = self->data; + struct winlink *wl; + struct window *w; + struct window_pane *wp, *wp2; + u_int sx, sy, xoff, yoff; + + if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) + return (-1); + w = wl->window; + + if (data->flags & CMD_BIGDFLAG) { + wp = TAILQ_LAST(&w->panes, window_panes); + TAILQ_REMOVE(&w->panes, wp, entry); + TAILQ_INSERT_HEAD(&w->panes, wp, entry); + + xoff = wp->xoff; yoff = wp->yoff; + sx = wp->sx; sy = wp->sy; + TAILQ_FOREACH(wp, &w->panes, entry) { + if ((wp2 = TAILQ_NEXT(wp, entry)) == NULL) + break; + wp->xoff = wp2->xoff; wp->yoff = wp2->yoff; + window_pane_resize(wp, wp2->sx, wp2->sy); + } + wp->xoff = xoff; wp->yoff = yoff; + window_pane_resize(wp, sx, sy); + + if ((wp = TAILQ_PREV(w->active, window_panes, entry)) == NULL) + wp = TAILQ_LAST(&w->panes, window_panes); + window_set_active_pane(w, wp); + } else { + wp = TAILQ_FIRST(&w->panes); + TAILQ_REMOVE(&w->panes, wp, entry); + TAILQ_INSERT_TAIL(&w->panes, wp, entry); + + xoff = wp->xoff; yoff = wp->yoff; + sx = wp->sx; sy = wp->sy; + TAILQ_FOREACH_REVERSE(wp, &w->panes, window_panes, entry) { + if ((wp2 = TAILQ_PREV(wp, window_panes, entry)) == NULL) + break; + wp->xoff = wp2->xoff; wp->yoff = wp2->yoff; + window_pane_resize(wp, wp2->sx, wp2->sy); + } + wp->xoff = xoff; wp->yoff = yoff; + window_pane_resize(wp, sx, sy); + + if ((wp = TAILQ_NEXT(w->active, entry)) == NULL) + wp = TAILQ_FIRST(&w->panes); + window_set_active_pane(w, wp); + } + + layout_refresh(w, 0); + + return (0); +} diff --git a/cmd-save-buffer.c b/cmd-save-buffer.c new file mode 100644 index 00000000..7c5af7a4 --- /dev/null +++ b/cmd-save-buffer.c @@ -0,0 +1,90 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2009 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 + +#include +#include + +#include "tmux.h" + +/* + * Saves a session paste buffer to a file. + */ + +int cmd_save_buffer_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_save_buffer_entry = { + "save-buffer", "saveb", + "[-a] " CMD_BUFFER_SESSION_USAGE " path", + CMD_AFLAG|CMD_ARG1, + cmd_buffer_init, + cmd_buffer_parse, + cmd_save_buffer_exec, + cmd_buffer_send, + cmd_buffer_recv, + cmd_buffer_free, + cmd_buffer_print +}; + +int +cmd_save_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_buffer_data *data = self->data; + struct session *s; + struct paste_buffer *pb; + mode_t mask; + FILE *f; + + if ((s = cmd_find_session(ctx, data->target)) == NULL) + return (-1); + + if (data->buffer == -1) { + if ((pb = paste_get_top(&s->buffers)) == NULL) { + ctx->error(ctx, "no buffers"); + return (-1); + } + } else { + if ((pb = paste_get_index(&s->buffers, data->buffer)) == NULL) { + ctx->error(ctx, "no buffer %d", data->buffer); + return (-1); + } + } + + mask = umask(S_IRWXG | S_IRWXO); + if (data->flags & CMD_AFLAG) + f = fopen(data->arg, "ab"); + else + f = fopen(data->arg, "wb"); + if (f == NULL) { + ctx->error(ctx, "%s: %s", data->arg, strerror(errno)); + return (-1); + } + + if (fwrite(pb->data, 1, strlen(pb->data), f) != strlen(pb->data)) { + ctx->error(ctx, "%s: fwrite error", data->arg); + fclose(f); + return (-1); + } + + fclose(f); + umask(mask); + + return (0); +} diff --git a/cmd-scroll-mode.c b/cmd-scroll-mode.c new file mode 100644 index 00000000..c34f9bd6 --- /dev/null +++ b/cmd-scroll-mode.c @@ -0,0 +1,72 @@ +/* $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" + +/* + * Enter scroll mode. + */ + +void cmd_scroll_mode_init(struct cmd *, int); +int cmd_scroll_mode_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_scroll_mode_entry = { + "scroll-mode", NULL, + CMD_TARGET_WINDOW_USAGE, + CMD_UFLAG, + cmd_scroll_mode_init, + cmd_target_parse, + cmd_scroll_mode_exec, + cmd_target_send, + cmd_target_recv, + cmd_target_free, + cmd_target_print +}; + +void +cmd_scroll_mode_init(struct cmd *self, int key) +{ + struct cmd_target_data *data; + + cmd_target_init(self, key); + data = self->data; + + switch (key) { + case KEYC_PPAGE: + data->flags |= CMD_UFLAG; + break; + } +} + +int +cmd_scroll_mode_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_target_data *data = self->data; + struct winlink *wl; + + if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) + return (-1); + + window_pane_set_mode(wl->window->active, &window_scroll_mode); + if (data->flags & CMD_UFLAG) + window_scroll_pageup(wl->window->active); + + return (0); +} diff --git a/cmd-select-layout.c b/cmd-select-layout.c new file mode 100644 index 00000000..ef921660 --- /dev/null +++ b/cmd-select-layout.c @@ -0,0 +1,86 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2009 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" + +/* + * Switch window to selected layout. + */ + +void cmd_select_layout_init(struct cmd *, int); +int cmd_select_layout_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_select_layout_entry = { + "select-layout", "selectl", + CMD_TARGET_WINDOW_USAGE " layout-name", + CMD_ARG1, + cmd_select_layout_init, + cmd_target_parse, + cmd_select_layout_exec, + cmd_target_send, + cmd_target_recv, + cmd_target_free, + cmd_target_print +}; + +void +cmd_select_layout_init(struct cmd *self, int key) +{ + struct cmd_target_data *data; + + cmd_target_init(self, key); + data = self->data; + + switch (key) { + case KEYC_ADDESC('0'): + data->arg = xstrdup("manual-vertical"); + break; + case KEYC_ADDESC('1'): + data->arg = xstrdup("even-horizontal"); + break; + case KEYC_ADDESC('2'): + data->arg = xstrdup("even-vertical"); + break; + case KEYC_ADDESC('9'): + data->arg = xstrdup("active-only"); + break; + } +} + +int +cmd_select_layout_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_target_data *data = self->data; + struct winlink *wl; + int layout; + + if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) + return (-1); + + if ((layout = layout_lookup(data->arg)) == -1) { + ctx->error(ctx, "unknown or ambiguous layout: %s", data->arg); + return (-1); + } + + if (layout_select(wl->window, layout) == 0) + ctx->info(ctx, "layout now: %s", layout_name(wl->window)); + + return (0); +} diff --git a/cmd-select-pane.c b/cmd-select-pane.c new file mode 100644 index 00000000..33c94a33 --- /dev/null +++ b/cmd-select-pane.c @@ -0,0 +1,69 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2009 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" + +/* + * Select pane. + */ + +int cmd_select_pane_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_select_pane_entry = { + "select-pane", "selectp", + CMD_PANE_WINDOW_USAGE, + 0, + cmd_pane_init, + cmd_pane_parse, + cmd_select_pane_exec, + cmd_pane_send, + cmd_pane_recv, + cmd_pane_free, + cmd_pane_print +}; + +int +cmd_select_pane_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_pane_data *data = self->data; + struct winlink *wl; + struct window_pane *wp; + + if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) + return (-1); + if (data->pane == -1) + wp = wl->window->active; + else { + wp = window_pane_at_index(wl->window, data->pane); + if (wp == NULL) { + ctx->error(ctx, "no pane: %d", data->pane); + return (-1); + } + } + + if (wp->flags & PANE_HIDDEN) { + ctx->error(ctx, "pane %d is hidden", data->pane); + return (-1); + } + window_set_active_pane(wl->window, wp); + layout_refresh(wl->window, 1); + + return (0); +} diff --git a/cmd-select-prompt.c b/cmd-select-prompt.c new file mode 100644 index 00000000..81da9dbb --- /dev/null +++ b/cmd-select-prompt.c @@ -0,0 +1,93 @@ +/* $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 "tmux.h" + +/* + * Prompt for window index and select it. + */ + +int cmd_select_prompt_exec(struct cmd *, struct cmd_ctx *); + +int cmd_select_prompt_callback(void *, const char *); + +const struct cmd_entry cmd_select_prompt_entry = { + "select-prompt", NULL, + CMD_TARGET_CLIENT_USAGE, + 0, + cmd_target_init, + cmd_target_parse, + cmd_select_prompt_exec, + cmd_target_send, + cmd_target_recv, + cmd_target_free, + cmd_target_print +}; + +int +cmd_select_prompt_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_target_data *data = self->data; + struct client *c; + + if ((c = cmd_find_client(ctx, data->target)) == NULL) + return (-1); + + if (c->prompt_string != NULL) + return (0); + + status_prompt_set(c, "index ", cmd_select_prompt_callback, c, 0); + + return (0); +} + +int +cmd_select_prompt_callback(void *data, const char *s) +{ + struct client *c = data; + const char *errstr; + char msg[128]; + u_int idx; + + if (s == NULL) + return (0); + + idx = strtonum(s, 0, UINT_MAX, &errstr); + if (errstr != NULL) { + xsnprintf(msg, sizeof msg, "Index %s: %s", errstr, s); + status_message_set(c, msg); + return (0); + } + + if (winlink_find_by_index(&c->session->windows, idx) == NULL) { + xsnprintf(msg, sizeof msg, + "Window not found: %s:%d", c->session->name, idx); + status_message_set(c, msg); + return (0); + } + + if (session_select(c->session, idx) == 0) + server_redraw_session(c->session); + recalculate_sizes(); + + return (0); +} diff --git a/cmd-select-window.c b/cmd-select-window.c new file mode 100644 index 00000000..55f8318c --- /dev/null +++ b/cmd-select-window.c @@ -0,0 +1,71 @@ +/* $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 + +#include "tmux.h" + +/* + * Select window by index. + */ + +void cmd_select_window_init(struct cmd *, int); +int cmd_select_window_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_select_window_entry = { + "select-window", "selectw", + CMD_TARGET_WINDOW_USAGE, + 0, + cmd_select_window_init, + cmd_target_parse, + cmd_select_window_exec, + cmd_target_send, + cmd_target_recv, + cmd_target_free, + cmd_target_print +}; + +void +cmd_select_window_init(struct cmd *self, int key) +{ + struct cmd_target_data *data; + + cmd_target_init(self, key); + data = self->data; + + xasprintf(&data->target, ":%d", key - '0'); +} + +int +cmd_select_window_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_target_data *data = self->data; + struct winlink *wl; + struct session *s; + + if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL) + return (-1); + + if (session_select(s, wl->idx) == 0) + server_redraw_session(s); + recalculate_sizes(); + + return (0); +} diff --git a/cmd-send-keys.c b/cmd-send-keys.c new file mode 100644 index 00000000..849fe7be --- /dev/null +++ b/cmd-send-keys.c @@ -0,0 +1,184 @@ +/* $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 "tmux.h" + +/* + * Send keys to client. + */ + +int cmd_send_keys_parse(struct cmd *, int, char **, char **); +int cmd_send_keys_exec(struct cmd *, struct cmd_ctx *); +void cmd_send_keys_send(struct cmd *, struct buffer *); +void cmd_send_keys_recv(struct cmd *, struct buffer *); +void cmd_send_keys_free(struct cmd *); +size_t cmd_send_keys_print(struct cmd *, char *, size_t); + +struct cmd_send_keys_data { + char *target; + int idx; + u_int nkeys; + int *keys; +}; + +const struct cmd_entry cmd_send_keys_entry = { + "send-keys", "send", + "[-t target-window] key ...", + 0, + NULL, + cmd_send_keys_parse, + cmd_send_keys_exec, + cmd_send_keys_send, + cmd_send_keys_recv, + cmd_send_keys_free, + cmd_send_keys_print +}; + +int +cmd_send_keys_parse(struct cmd *self, int argc, char **argv, char **cause) +{ + struct cmd_send_keys_data *data; + int opt, key; + char *s; + + self->data = data = xmalloc(sizeof *data); + data->target = NULL; + data->idx = -1; + data->nkeys = 0; + data->keys = NULL; + + while ((opt = getopt(argc, argv, "t:")) != -1) { + switch (opt) { + case 't': + if (data->target == NULL) + data->target = xstrdup(optarg); + break; + default: + goto usage; + } + } + argc -= optind; + argv += optind; + if (argc == 0) + goto usage; + + while (argc-- != 0) { + if ((key = key_string_lookup_string(*argv)) != KEYC_NONE) { + data->keys = xrealloc( + data->keys, data->nkeys + 1, sizeof *data->keys); + data->keys[data->nkeys++] = key; + } else { + for (s = *argv; *s != '\0'; s++) { + data->keys = xrealloc(data->keys, + data->nkeys + 1, sizeof *data->keys); + data->keys[data->nkeys++] = *s; + } + } + + argv++; + } + + return (0); + +usage: + xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); + + self->entry->free(self); + return (-1); +} + +int +cmd_send_keys_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_send_keys_data *data = self->data; + struct winlink *wl; + u_int i; + + if (data == NULL) + return (-1); + + if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) + return (-1); + + for (i = 0; i < data->nkeys; i++) { + window_pane_key( + wl->window->active, ctx->curclient, data->keys[i]); + } + + return (0); +} + +void +cmd_send_keys_send(struct cmd *self, struct buffer *b) +{ + struct cmd_send_keys_data *data = self->data; + + buffer_write(b, data, sizeof *data); + cmd_send_string(b, data->target); + buffer_write(b, data->keys, data->nkeys * sizeof *data->keys); +} + +void +cmd_send_keys_recv(struct cmd *self, struct buffer *b) +{ + struct cmd_send_keys_data *data; + + self->data = data = xmalloc(sizeof *data); + buffer_read(b, data, sizeof *data); + data->target = cmd_recv_string(b); + data->keys = xcalloc(data->nkeys, sizeof *data->keys); + buffer_read(b, data->keys, data->nkeys * sizeof *data->keys); +} + +void +cmd_send_keys_free(struct cmd *self) +{ + struct cmd_send_keys_data *data = self->data; + + if (data->target != NULL) + xfree(data->target); + xfree(data); +} + +size_t +cmd_send_keys_print(struct cmd *self, char *buf, size_t len) +{ + struct cmd_send_keys_data *data = self->data; + size_t off = 0; + u_int i; + + off += xsnprintf(buf, len, "%s", self->entry->name); + if (data == NULL) + return (off); + if (off < len && data->target != NULL) + off += cmd_prarg(buf + off, len - off, " -t ", data->target); + if (off < len && data->idx != -1) + off += xsnprintf(buf + off, len - off, " -i %d", data->idx); + + for (i = 0; i < data->nkeys; i++) { + if (off >= len) + break; + off += xsnprintf(buf + off, + len - off, " %s", key_string_lookup_key(data->keys[i])); + } + return (off); +} diff --git a/cmd-send-prefix.c b/cmd-send-prefix.c new file mode 100644 index 00000000..d45ca0c1 --- /dev/null +++ b/cmd-send-prefix.c @@ -0,0 +1,57 @@ +/* $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" + +/* + * Send prefix key as a key. + */ + +int cmd_send_prefix_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_send_prefix_entry = { + "send-prefix", NULL, + CMD_TARGET_WINDOW_USAGE, + 0, + cmd_target_init, + cmd_target_parse, + cmd_send_prefix_exec, + cmd_target_send, + cmd_target_recv, + cmd_target_free, + cmd_target_print +}; + +int +cmd_send_prefix_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_target_data *data = self->data; + struct session *s; + struct winlink *wl; + int key; + + if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL) + return (-1); + + key = options_get_number(&s->options, "prefix"); + window_pane_key(wl->window->active, ctx->curclient, key); + + return (0); +} diff --git a/cmd-server-info.c b/cmd-server-info.c new file mode 100644 index 00000000..94373f01 --- /dev/null +++ b/cmd-server-info.c @@ -0,0 +1,179 @@ +/* $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 "tmux.h" + +/* + * Show various information about server. + */ + +int cmd_server_info_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_server_info_entry = { + "server-info", "info", + "", + 0, + NULL, + NULL, + cmd_server_info_exec, + NULL, + NULL, + NULL, + NULL +}; + +int +cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx) +{ + struct tty_term *term; + struct client *c; + struct session *s; + struct winlink *wl; + struct window *w; + struct window_pane *wp; + struct tty_code *code; + struct tty_term_code_entry *ent; + struct utsname un; + struct grid *gd; + u_int i, j, k; + char out[80]; + char *tim; + time_t t; + u_int lines, ulines; + size_t size, usize; + + tim = ctime(&start_time); + *strchr(tim, '\n') = '\0'; + ctx->print(ctx, "pid %ld, started %s", (long) getpid(), tim); + ctx->print(ctx, "socket path %s, debug level %d%s", + socket_path, debug_level, be_quiet ? ", quiet" : ""); + if (uname(&un) == 0) { + ctx->print(ctx, "system is %s %s %s %s", + un.sysname, un.release, un.version, un.machine); + } + if (cfg_file != NULL) + ctx->print(ctx, "configuration file is %s", cfg_file); + else + ctx->print(ctx, "configuration file not specified"); + ctx->print(ctx, "protocol version is %d", PROTOCOL_VERSION); + ctx->print(ctx, "%u clients, %u sessions", + ARRAY_LENGTH(&clients), ARRAY_LENGTH(&sessions)); + ctx->print(ctx, ""); + + ctx->print(ctx, "Clients:"); + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c == NULL || c->session == NULL) + continue; + + ctx->print(ctx, "%2d: %s (%d, %d): %s [%ux%u %s] " + "[flags=0x%x/0x%x]", i, c->tty.path, c->fd, c->tty.fd, + c->session->name, c->tty.sx, c->tty.sy, c->tty.termname, + c->flags, c->tty.flags); + } + ctx->print(ctx, ""); + + ctx->print(ctx, "Sessions: [%zu/%zu]", + sizeof (struct grid_cell), sizeof (struct grid_utf8)); + for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { + s = ARRAY_ITEM(&sessions, i); + if (s == NULL) + continue; + + t = s->tv.tv_sec; + tim = ctime(&t); + *strchr(tim, '\n') = '\0'; + + ctx->print(ctx, "%2u: %s: %u windows (created %s) [%ux%u] " + "[flags=0x%x]", i, s->name, winlink_count(&s->windows), + tim, s->sx, s->sy, s->flags); + RB_FOREACH(wl, winlinks, &s->windows) { + w = wl->window; + ctx->print(ctx, "%4u: %s [%ux%u] [flags=0x%x, " + "references=%u, layout=%u]", wl->idx, w->name, + w->sx, w->sy, w->flags, w->references, + w->layout); + j = 0; + TAILQ_FOREACH(wp, &w->panes, entry) { + lines = ulines = size = usize = 0; + gd = wp->base.grid; + for (k = 0; k < gd->hsize + gd->sy; k++) { + if (gd->data[k] != NULL) { + lines++; + size += gd->size[k] * + sizeof (**gd->data); + } + if (gd->udata[k] != NULL) { + ulines++; + usize += gd->usize[k] * + sizeof (**gd->udata); + } + } + ctx->print(ctx, "%6u: %s %lu %d %u/%u, %zu " + "bytes; UTF-8 %u/%u, %zu bytes", j, + wp->tty, (u_long) wp->pid, wp->fd, lines, + gd->hsize + gd->sy, size, ulines, + gd->hsize + gd->sy, usize); + j++; + } + } + } + ctx->print(ctx, ""); + + ctx->print(ctx, "Terminals:"); + SLIST_FOREACH(term, &tty_terms, entry) { + ctx->print(ctx, "%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: + ctx->print(ctx, "%2u: %s: [missing]", + ent->code, ent->name); + break; + case TTYCODE_STRING: + clean_string( + code->value.string, out, sizeof out); + ctx->print(ctx, "%2u: %s: (string) %s", + ent->code, ent->name, out); + break; + case TTYCODE_NUMBER: + ctx->print(ctx, "%2u: %s: (number) %d", + ent->code, ent->name, code->value.number); + break; + case TTYCODE_FLAG: + ctx->print(ctx, "%2u: %s: (flag) %s", + ent->code, ent->name, + code->value.flag ? "true" : "false"); + break; + } + } + } + ctx->print(ctx, ""); + + return (0); +} diff --git a/cmd-set-buffer.c b/cmd-set-buffer.c new file mode 100644 index 00000000..3e1aa0a5 --- /dev/null +++ b/cmd-set-buffer.c @@ -0,0 +1,64 @@ +/* $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 + +#include "tmux.h" + +/* + * Add or set a session paste buffer. + */ + +int cmd_set_buffer_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_set_buffer_entry = { + "set-buffer", "setb", + CMD_BUFFER_SESSION_USAGE " data", + CMD_ARG1, + cmd_buffer_init, + cmd_buffer_parse, + cmd_set_buffer_exec, + cmd_buffer_send, + cmd_buffer_recv, + cmd_buffer_free, + cmd_buffer_print +}; + +int +cmd_set_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_buffer_data *data = self->data; + struct session *s; + u_int limit; + + if ((s = cmd_find_session(ctx, data->target)) == NULL) + return (-1); + + limit = options_get_number(&s->options, "buffer-limit"); + if (data->buffer == -1) { + paste_add(&s->buffers, xstrdup(data->arg), limit); + return (0); + } + if (paste_replace(&s->buffers, data->buffer, xstrdup(data->arg)) != 0) { + ctx->error(ctx, "no buffer %d", data->buffer); + return (-1); + } + return (0); +} diff --git a/cmd-set-option.c b/cmd-set-option.c new file mode 100644 index 00000000..d4e90957 --- /dev/null +++ b/cmd-set-option.c @@ -0,0 +1,169 @@ +/* $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 +#include + +#include "tmux.h" + +/* + * Set an option. + */ + +int cmd_set_option_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_set_option_entry = { + "set-option", "set", + CMD_OPTION_SESSION_USAGE, + CMD_GFLAG|CMD_UFLAG, + NULL, + cmd_option_parse, + cmd_set_option_exec, + cmd_option_send, + cmd_option_recv, + cmd_option_free, + cmd_option_print +}; + +const char *set_option_status_keys_list[] = { + "emacs", "vi", NULL +}; +const char *set_option_bell_action_list[] = { + "none", "any", "current", NULL +}; +const struct set_option_entry set_option_table[NSETOPTION] = { + { "bell-action", SET_OPTION_CHOICE, 0, 0, set_option_bell_action_list }, + { "buffer-limit", SET_OPTION_NUMBER, 1, INT_MAX, NULL }, + { "default-command", SET_OPTION_STRING, 0, 0, NULL }, + { "default-path", SET_OPTION_STRING, 0, 0, NULL }, + { "display-time", SET_OPTION_NUMBER, 1, INT_MAX, NULL }, + { "history-limit", SET_OPTION_NUMBER, 0, INT_MAX, NULL }, + { "lock-after-time", SET_OPTION_NUMBER, 0, INT_MAX, NULL }, + { "message-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL }, + { "message-bg", SET_OPTION_COLOUR, 0, 0, NULL }, + { "message-fg", SET_OPTION_COLOUR, 0, 0, NULL }, + { "prefix", SET_OPTION_KEY, 0, 0, NULL }, + { "repeat-time", SET_OPTION_NUMBER, 0, SHRT_MAX, NULL }, + { "set-remain-on-exit", SET_OPTION_FLAG, 0, 0, NULL }, + { "set-titles", SET_OPTION_FLAG, 0, 0, NULL }, + { "status", SET_OPTION_FLAG, 0, 0, NULL }, + { "status-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL }, + { "status-bg", SET_OPTION_COLOUR, 0, 0, NULL }, + { "status-fg", SET_OPTION_COLOUR, 0, 0, NULL }, + { "status-interval", SET_OPTION_NUMBER, 0, INT_MAX, NULL }, + { "status-keys", SET_OPTION_CHOICE, 0, 0, set_option_status_keys_list }, + { "status-left", SET_OPTION_STRING, 0, 0, NULL }, + { "status-left-length", SET_OPTION_NUMBER, 0, SHRT_MAX, NULL }, + { "status-right", SET_OPTION_STRING, 0, 0, NULL }, + { "status-right-length", SET_OPTION_NUMBER, 0, SHRT_MAX, NULL }, +}; + +int +cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_option_data *data = self->data; + struct session *s; + struct client *c; + struct options *oo; + const struct set_option_entry *entry; + u_int i; + + if (data->flags & CMD_GFLAG) + oo = &global_options; + else { + if ((s = cmd_find_session(ctx, data->target)) == NULL) + return (-1); + oo = &s->options; + } + + if (*data->option == '\0') { + ctx->error(ctx, "invalid option"); + return (-1); + } + + entry = NULL; + for (i = 0; i < NSETOPTION; i++) { + if (strncmp(set_option_table[i].name, + data->option, strlen(data->option)) != 0) + continue; + if (entry != NULL) { + ctx->error(ctx, "ambiguous option: %s", data->option); + return (-1); + } + entry = &set_option_table[i]; + + /* Bail now if an exact match. */ + if (strcmp(entry->name, data->option) == 0) + break; + } + if (entry == NULL) { + ctx->error(ctx, "unknown option: %s", data->option); + return (-1); + } + + if (data->flags & CMD_UFLAG) { + if (data->flags & CMD_GFLAG) { + ctx->error(ctx, + "can't unset global option: %s", entry->name); + return (-1); + } + if (data->value != NULL) { + ctx->error(ctx, + "value passed to unset option: %s", entry->name); + return (-1); + } + + options_remove(oo, entry->name); + ctx->info(ctx, "unset option: %s", entry->name); + } else { + switch (entry->type) { + case SET_OPTION_STRING: + set_option_string(ctx, oo, entry, data->value); + break; + case SET_OPTION_NUMBER: + set_option_number(ctx, oo, entry, data->value); + break; + case SET_OPTION_KEY: + set_option_key(ctx, oo, entry, data->value); + break; + case SET_OPTION_COLOUR: + set_option_colour(ctx, oo, entry, data->value); + break; + case SET_OPTION_ATTRIBUTES: + set_option_attributes(ctx, oo, entry, data->value); + break; + case SET_OPTION_FLAG: + set_option_flag(ctx, oo, entry, data->value); + break; + case SET_OPTION_CHOICE: + set_option_choice(ctx, oo, entry, data->value); + break; + } + } + + recalculate_sizes(); + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c != NULL && c->session != NULL) + server_redraw_client(c); + } + + return (0); +} diff --git a/cmd-set-password.c b/cmd-set-password.c new file mode 100644 index 00000000..93705cab --- /dev/null +++ b/cmd-set-password.c @@ -0,0 +1,169 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2009 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 "tmux.h" + +/* + * Set server password. + */ + +int cmd_set_password_parse(struct cmd *, int, char **, char **); +int cmd_set_password_exec(struct cmd *, struct cmd_ctx *); +void cmd_set_password_send(struct cmd *, struct buffer *); +void cmd_set_password_recv(struct cmd *, struct buffer *); +void cmd_set_password_free(struct cmd *); +void cmd_set_password_init(struct cmd *, int); +size_t cmd_set_password_print(struct cmd *, char *, size_t); + +struct cmd_set_password_data { + char *password; + int flag_encrypted; +}; + +const struct cmd_entry cmd_set_password_entry = { + "set-password", "pass", + "[-c] password", + 0, + cmd_set_password_init, + cmd_set_password_parse, + cmd_set_password_exec, + cmd_set_password_send, + cmd_set_password_recv, + cmd_set_password_free, + cmd_set_password_print +}; + +void +cmd_set_password_init(struct cmd *self, unused int arg) +{ + struct cmd_set_password_data *data; + + self->data = data = xmalloc(sizeof *data); + data->password = NULL; + data->flag_encrypted = 0; +} + +int +cmd_set_password_parse(struct cmd *self, int argc, char **argv, char **cause) +{ + struct cmd_set_password_data *data; + int opt; + char *out; + + self->entry->init(self, 0); + data = self->data; + + while ((opt = getopt(argc, argv, "c")) != -1) { + switch (opt) { + case 'c': + data->flag_encrypted = 1; + break; + default: + goto usage; + } + } + argc -= optind; + argv += optind; + if (argc != 1) + goto usage; + + if (!data->flag_encrypted) { + if ((out = crypt(argv[0], "$1")) != NULL) + data->password = xstrdup(out); + } else + data->password = xstrdup(argv[0]); + + return (0); + +usage: + xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); + + self->entry->free(self); + return (-1); +} + +int +cmd_set_password_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_set_password_data *data = self->data; + + if (data->password == NULL) { + ctx->error(ctx, "failed to encrypt password"); + return (-1); + } + + if (server_password != NULL) + xfree(server_password); + if (*data->password == '\0') + server_password = NULL; + else + server_password = xstrdup(data->password); + log_debug("pw now %s", server_password); + + return (0); +} + +void +cmd_set_password_send(struct cmd *self, struct buffer *b) +{ + struct cmd_set_password_data *data = self->data; + + buffer_write(b, data, sizeof *data); + cmd_send_string(b, data->password); +} + +void +cmd_set_password_recv(struct cmd *self, struct buffer *b) +{ + struct cmd_set_password_data *data; + + self->data = data = xmalloc(sizeof *data); + buffer_read(b, data, sizeof *data); + data->password = cmd_recv_string(b); +} + +void +cmd_set_password_free(struct cmd *self) +{ + struct cmd_set_password_data *data = self->data; + + if (data->password != NULL) + xfree(data->password); + xfree(data); +} + +size_t +cmd_set_password_print(struct cmd *self, char *buf, size_t len) +{ + struct cmd_set_password_data *data = self->data; + size_t off = 0; + + off += xsnprintf(buf, len, "%s", self->entry->name); + if (data == NULL) + return (off); + if (off < len && data->flag_encrypted) + off += xsnprintf(buf + off, len - off, " -c"); + if (off < len && data->password != NULL) + off += xsnprintf(buf + off, len - off, " password"); + return (off); +} diff --git a/cmd-set-window-option.c b/cmd-set-window-option.c new file mode 100644 index 00000000..8d17498e --- /dev/null +++ b/cmd-set-window-option.c @@ -0,0 +1,170 @@ +/* $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 "tmux.h" + +/* + * Set a window option. + */ + +int cmd_set_window_option_parse(struct cmd *, int, char **, char **); +int cmd_set_window_option_exec(struct cmd *, struct cmd_ctx *); +void cmd_set_window_option_send(struct cmd *, struct buffer *); +void cmd_set_window_option_recv(struct cmd *, struct buffer *); +void cmd_set_window_option_free(struct cmd *); +size_t cmd_set_window_option_print(struct cmd *, char *, size_t); + +const struct cmd_entry cmd_set_window_option_entry = { + "set-window-option", "setw", + CMD_OPTION_WINDOW_USAGE, + CMD_GFLAG|CMD_UFLAG, + NULL, + cmd_option_parse, + cmd_set_window_option_exec, + cmd_option_send, + cmd_option_recv, + cmd_option_free, + cmd_option_print +}; + +const char *set_option_mode_keys_list[] = { + "emacs", "vi", NULL +}; +const char *set_option_clock_mode_style_list[] = { + "12", "24", NULL +}; +const struct set_option_entry set_window_option_table[NSETWINDOWOPTION] = { + { "aggressive-resize", SET_OPTION_FLAG, 0, 0, NULL }, + { "automatic-rename", SET_OPTION_FLAG, 0, 0, NULL }, + { "clock-mode-colour", SET_OPTION_COLOUR, 0, 0, NULL }, + { "clock-mode-style", + SET_OPTION_CHOICE, 0, 0, set_option_clock_mode_style_list }, + { "force-height", SET_OPTION_NUMBER, 0, INT_MAX, NULL }, + { "force-width", SET_OPTION_NUMBER, 0, INT_MAX, NULL }, + { "main-pane-width", SET_OPTION_NUMBER, 1, INT_MAX, NULL }, + { "mode-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL }, + { "mode-bg", SET_OPTION_COLOUR, 0, 0, NULL }, + { "mode-fg", SET_OPTION_COLOUR, 0, 0, NULL }, + { "mode-keys", SET_OPTION_CHOICE, 0, 0, set_option_mode_keys_list }, + { "monitor-activity", SET_OPTION_FLAG, 0, 0, NULL }, + { "monitor-content", SET_OPTION_STRING, 0, 0, NULL }, + { "remain-on-exit", SET_OPTION_FLAG, 0, 0, NULL }, + { "utf8", SET_OPTION_FLAG, 0, 0, NULL }, + { "window-status-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL }, + { "window-status-bg", SET_OPTION_COLOUR, 0, 0, NULL }, + { "window-status-fg", SET_OPTION_COLOUR, 0, 0, NULL }, + { "xterm-keys", SET_OPTION_FLAG, 0, 0, NULL }, +}; + +int +cmd_set_window_option_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_option_data *data = self->data; + struct winlink *wl; + struct client *c; + struct options *oo; + const struct set_option_entry *entry; + u_int i; + + if (data->flags & CMD_GFLAG) + oo = &global_window_options; + else { + if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) + return (-1); + oo = &wl->window->options; + } + + if (*data->option == '\0') { + ctx->error(ctx, "invalid option"); + return (-1); + } + + entry = NULL; + for (i = 0; i < NSETWINDOWOPTION; i++) { + if (strncmp(set_window_option_table[i].name, + data->option, strlen(data->option)) != 0) + continue; + if (entry != NULL) { + ctx->error(ctx, "ambiguous option: %s", data->option); + return (-1); + } + entry = &set_window_option_table[i]; + + /* Bail now if an exact match. */ + if (strcmp(entry->name, data->option) == 0) + break; + } + if (entry == NULL) { + ctx->error(ctx, "unknown option: %s", data->option); + return (-1); + } + + if (data->flags & CMD_UFLAG) { + if (data->flags & CMD_GFLAG) { + ctx->error(ctx, + "can't unset global option: %s", entry->name); + return (-1); + } + if (data->value != NULL) { + ctx->error(ctx, + "value passed to unset option: %s", entry->name); + return (-1); + } + + options_remove(oo, entry->name); + ctx->info(ctx, "unset option: %s", entry->name); + } else { + switch (entry->type) { + case SET_OPTION_STRING: + set_option_string(ctx, oo, entry, data->value); + break; + case SET_OPTION_NUMBER: + set_option_number(ctx, oo, entry, data->value); + break; + case SET_OPTION_KEY: + set_option_key(ctx, oo, entry, data->value); + break; + case SET_OPTION_COLOUR: + set_option_colour(ctx, oo, entry, data->value); + break; + case SET_OPTION_ATTRIBUTES: + set_option_attributes(ctx, oo, entry, data->value); + break; + case SET_OPTION_FLAG: + set_option_flag(ctx, oo, entry, data->value); + break; + case SET_OPTION_CHOICE: + set_option_choice(ctx, oo, entry, data->value); + break; + } + } + + recalculate_sizes(); + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c != NULL && c->session != NULL) + server_redraw_client(c); + } + + return (0); +} diff --git a/cmd-show-buffer.c b/cmd-show-buffer.c new file mode 100644 index 00000000..3e779f31 --- /dev/null +++ b/cmd-show-buffer.c @@ -0,0 +1,89 @@ +/* $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 + +#include "tmux.h" + +/* + * Show a session paste buffer. + */ + +int cmd_show_buffer_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_show_buffer_entry = { + "show-buffer", "showb", + CMD_BUFFER_SESSION_USAGE, + 0, + cmd_buffer_init, + cmd_buffer_parse, + cmd_show_buffer_exec, + cmd_buffer_send, + cmd_buffer_recv, + cmd_buffer_free, + cmd_buffer_print +}; + +int +cmd_show_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_buffer_data *data = self->data; + struct session *s; + struct paste_buffer *pb; + u_int size; + char *buf, *ptr; + size_t len; + + if ((s = cmd_find_session(ctx, data->target)) == NULL) + return (-1); + + if (data->buffer == -1) { + if ((pb = paste_get_top(&s->buffers)) == NULL) { + ctx->error(ctx, "no buffers"); + return (-1); + } + } else if ((pb = paste_get_index(&s->buffers, data->buffer)) == NULL) { + ctx->error(ctx, "no buffer %d", data->buffer); + return (-1); + } + + if (pb != NULL) { + size = s->sx; + + buf = xmalloc(size + 1); + len = 0; + + ptr = pb->data; + do { + buf[len++] = *ptr++; + + if (len == size) { + buf[len] = '\0'; + ctx->print(ctx, buf); + + len = 0; + } + } while (*ptr != '\0'); + buf[len] = '\0'; + ctx->print(ctx, buf); + } + + return (0); +} diff --git a/cmd-show-options.c b/cmd-show-options.c new file mode 100644 index 00000000..13482525 --- /dev/null +++ b/cmd-show-options.c @@ -0,0 +1,110 @@ +/* $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 +#include + +#include "tmux.h" + +/* + * Show options. + */ + +int cmd_show_options_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_show_options_entry = { + "show-options", "show", + "[-g] " CMD_TARGET_SESSION_USAGE, + CMD_GFLAG, + cmd_target_init, + cmd_target_parse, + cmd_show_options_exec, + cmd_target_send, + cmd_target_recv, + cmd_target_free, + cmd_target_print +}; + +int +cmd_show_options_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_target_data *data = self->data; + struct session *s; + struct options *oo; + const struct set_option_entry *entry; + u_int i; + char *vs; + long long vn; + + if (data->flags & CMD_GFLAG) + oo = &global_options; + else { + if ((s = cmd_find_session(ctx, data->target)) == NULL) + return (-1); + oo = &s->options; + } + + for (i = 0; i < NSETOPTION; i++) { + entry = &set_option_table[i]; + + if (options_find1(oo, entry->name) == NULL) + continue; + + switch (entry->type) { + case SET_OPTION_STRING: + vs = options_get_string(oo, entry->name); + ctx->print(ctx, "%s \"%s\"", entry->name, vs); + break; + case SET_OPTION_NUMBER: + vn = options_get_number(oo, entry->name); + ctx->print(ctx, "%s %lld", entry->name, vn); + break; + case SET_OPTION_KEY: + vn = options_get_number(oo, entry->name); + ctx->print(ctx, "%s %s", + entry->name, key_string_lookup_key(vn)); + break; + case SET_OPTION_COLOUR: + vn = options_get_number(oo, entry->name); + ctx->print(ctx, "%s %s", + entry->name, colour_tostring(vn)); + break; + case SET_OPTION_ATTRIBUTES: + vn = options_get_number(oo, entry->name); + ctx->print(ctx, "%s %s", + entry->name, attributes_tostring(vn)); + break; + case SET_OPTION_FLAG: + vn = options_get_number(oo, entry->name); + if (vn) + ctx->print(ctx, "%s on", entry->name); + else + ctx->print(ctx, "%s off", entry->name); + break; + case SET_OPTION_CHOICE: + vn = options_get_number(oo, entry->name); + ctx->print(ctx, "%s %s", + entry->name, entry->choices[vn]); + break; + } + } + + return (0); +} diff --git a/cmd-show-window-options.c b/cmd-show-window-options.c new file mode 100644 index 00000000..dd8914a1 --- /dev/null +++ b/cmd-show-window-options.c @@ -0,0 +1,110 @@ +/* $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 "tmux.h" + +/* + * Show window options. + */ + +int cmd_show_window_options_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_show_window_options_entry = { + "show-window-options", "showw", + "[-g] " CMD_TARGET_WINDOW_USAGE, + CMD_GFLAG, + cmd_target_init, + cmd_target_parse, + cmd_show_window_options_exec, + cmd_target_send, + cmd_target_recv, + cmd_target_free, + cmd_target_print +}; + +int +cmd_show_window_options_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_target_data *data = self->data; + struct winlink *wl; + struct options *oo; + const struct set_option_entry *entry; + u_int i; + char *vs; + long long vn; + + if (data->flags & CMD_GFLAG) + oo = &global_window_options; + else { + if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) + return (-1); + oo = &wl->window->options; + } + + for (i = 0; i < NSETWINDOWOPTION; i++) { + entry = &set_window_option_table[i]; + + if (options_find1(oo, entry->name) == NULL) + continue; + + switch (entry->type) { + case SET_OPTION_STRING: + vs = options_get_string(oo, entry->name); + ctx->print(ctx, "%s \"%s\"", entry->name, vs); + break; + case SET_OPTION_NUMBER: + vn = options_get_number(oo, entry->name); + ctx->print(ctx, "%s %lld", entry->name, vn); + break; + case SET_OPTION_KEY: + vn = options_get_number(oo, entry->name); + ctx->print(ctx, "%s %s", + entry->name, key_string_lookup_key(vn)); + break; + case SET_OPTION_COLOUR: + vn = options_get_number(oo, entry->name); + ctx->print(ctx, "%s %s", + entry->name, colour_tostring(vn)); + break; + case SET_OPTION_ATTRIBUTES: + vn = options_get_number(oo, entry->name); + ctx->print(ctx, "%s %s", + entry->name, attributes_tostring(vn)); + break; + case SET_OPTION_FLAG: + vn = options_get_number(oo, entry->name); + if (vn) + ctx->print(ctx, "%s on", entry->name); + else + ctx->print(ctx, "%s off", entry->name); + break; + case SET_OPTION_CHOICE: + vn = options_get_number(oo, entry->name); + ctx->print(ctx, "%s %s", + entry->name, entry->choices[vn]); + break; + } + } + + return (0); +} diff --git a/cmd-source-file.c b/cmd-source-file.c new file mode 100644 index 00000000..f22322ee --- /dev/null +++ b/cmd-source-file.c @@ -0,0 +1,147 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2008 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" + +/* + * Sources a configuration file. + */ + +int cmd_source_file_parse(struct cmd *, int, char **, char **); +int cmd_source_file_exec(struct cmd *, struct cmd_ctx *); +void cmd_source_file_send(struct cmd *, struct buffer *); +void cmd_source_file_recv(struct cmd *, struct buffer *); +void cmd_source_file_free(struct cmd *); +void cmd_source_file_init(struct cmd *, int); +size_t cmd_source_file_print(struct cmd *, char *, size_t); + +struct cmd_source_file_data { + char *path; +}; + +const struct cmd_entry cmd_source_file_entry = { + "source-file", "source", + "path", + 0, + cmd_source_file_init, + cmd_source_file_parse, + cmd_source_file_exec, + cmd_source_file_send, + cmd_source_file_recv, + cmd_source_file_free, + cmd_source_file_print +}; + +void +cmd_source_file_init(struct cmd *self, unused int arg) +{ + struct cmd_source_file_data *data; + + self->data = data = xmalloc(sizeof *data); + data->path = NULL; +} + +int +cmd_source_file_parse(struct cmd *self, int argc, char **argv, char **cause) +{ + struct cmd_source_file_data *data; + int opt; + + self->entry->init(self, 0); + data = self->data; + + while ((opt = getopt(argc, argv, "")) != -1) { + switch (opt) { + default: + goto usage; + } + } + argc -= optind; + argv += optind; + if (argc != 1) + goto usage; + + data->path = xstrdup(argv[0]); + return (0); + +usage: + xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); + + self->entry->free(self); + return (-1); +} + +int +cmd_source_file_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_source_file_data *data = self->data; + char *cause; + + if (load_cfg(data->path, &cause) != 0) { + ctx->error(ctx, "%s", cause); + xfree(cause); + return (-1); + } + + return (0); +} + +void +cmd_source_file_send(struct cmd *self, struct buffer *b) +{ + struct cmd_source_file_data *data = self->data; + + buffer_write(b, data, sizeof *data); + cmd_send_string(b, data->path); +} + +void +cmd_source_file_recv(struct cmd *self, struct buffer *b) +{ + struct cmd_source_file_data *data; + + self->data = data = xmalloc(sizeof *data); + buffer_read(b, data, sizeof *data); + data->path = cmd_recv_string(b); +} + +void +cmd_source_file_free(struct cmd *self) +{ + struct cmd_source_file_data *data = self->data; + + if (data->path != NULL) + xfree(data->path); + xfree(data); +} + +size_t +cmd_source_file_print(struct cmd *self, char *buf, size_t len) +{ + struct cmd_source_file_data *data = self->data; + size_t off = 0; + + off += xsnprintf(buf, len, "%s", self->entry->name); + if (data == NULL) + return (off); + if (off < len && data->path != NULL) + off += cmd_prarg(buf + off, len - off, " ", data->path); + return (off); +} diff --git a/cmd-split-window.c b/cmd-split-window.c new file mode 100644 index 00000000..70822f7d --- /dev/null +++ b/cmd-split-window.c @@ -0,0 +1,235 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2009 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 "tmux.h" + +/* + * Split a window (add a new pane). + */ + +int cmd_split_window_parse(struct cmd *, int, char **, char **); +int cmd_split_window_exec(struct cmd *, struct cmd_ctx *); +void cmd_split_window_send(struct cmd *, struct buffer *); +void cmd_split_window_recv(struct cmd *, struct buffer *); +void cmd_split_window_free(struct cmd *); +void cmd_split_window_init(struct cmd *, int); +size_t cmd_split_window_print(struct cmd *, char *, size_t); + +struct cmd_split_window_data { + char *target; + char *cmd; + int flag_detached; + int percentage; + int lines; +}; + +const struct cmd_entry cmd_split_window_entry = { + "split-window", "splitw", + "[-d] [-p percentage|-l lines] [-t target-window] [command]", + 0, + cmd_split_window_init, + cmd_split_window_parse, + cmd_split_window_exec, + cmd_split_window_send, + cmd_split_window_recv, + cmd_split_window_free, + cmd_split_window_print +}; + +void +cmd_split_window_init(struct cmd *self, unused int arg) +{ + struct cmd_split_window_data *data; + + self->data = data = xmalloc(sizeof *data); + data->target = NULL; + data->cmd = NULL; + data->flag_detached = 0; + data->percentage = -1; + data->lines = -1; +} + +int +cmd_split_window_parse(struct cmd *self, int argc, char **argv, char **cause) +{ + struct cmd_split_window_data *data; + int opt, n; + const char *errstr; + + self->entry->init(self, 0); + data = self->data; + + while ((opt = getopt(argc, argv, "dl:p:t:")) != -1) { + switch (opt) { + case 'd': + data->flag_detached = 1; + break; + case 't': + if (data->target == NULL) + data->target = xstrdup(optarg); + break; + case 'l': + if (data->percentage == -1 && data->lines == -1) { + n = strtonum(optarg, 1, INT_MAX, &errstr); + if (errstr != NULL) { + xasprintf(cause, "lines %s", errstr); + goto error; + } + data->lines = n; + } + break; + case 'p': + if (data->lines == -1 && data->percentage == -1) { + n = strtonum(optarg, 1, 100, &errstr); + if (errstr != NULL) { + xasprintf( + cause, "percentage %s", errstr); + goto error; + } + data->percentage = n; + } + break; + default: + goto usage; + } + } + argc -= optind; + argv += optind; + if (argc != 0 && argc != 1) + goto usage; + + if (argc == 1) + data->cmd = xstrdup(argv[0]); + + return (0); + +usage: + xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); + +error: + self->entry->free(self); + return (-1); +} + +int +cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_split_window_data *data = self->data; + struct session *s; + struct winlink *wl; + struct window *w; + struct window_pane *wp; + const char **env; + char *cmd, *cwd, *cause; + u_int hlimit, lines; + + if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL) + return (-1); + w = wl->window; + + env = server_fill_environ(s); + + cmd = data->cmd; + if (cmd == NULL) + cmd = options_get_string(&s->options, "default-command"); + if (ctx->cmdclient == NULL || ctx->cmdclient->cwd == NULL) + cwd = options_get_string(&global_options, "default-path"); + else + cwd = ctx->cmdclient->cwd; + + lines = -1; + if (data->lines != -1) + lines = data->lines; + else if (data->percentage != -1) + lines = (w->active->sy * data->percentage) / 100; + + hlimit = options_get_number(&s->options, "history-limit"); + wp = window_add_pane(w, lines, cmd, cwd, env, hlimit, &cause); + if (wp == NULL) { + ctx->error(ctx, "create pane failed: %s", cause); + xfree(cause); + return (-1); + } + server_redraw_window(w); + + if (!data->flag_detached) { + window_set_active_pane(w, wp); + session_select(s, wl->idx); + server_redraw_session(s); + } else + server_status_session(s); + layout_refresh(w, 0); + + return (0); +} + +void +cmd_split_window_send(struct cmd *self, struct buffer *b) +{ + struct cmd_split_window_data *data = self->data; + + buffer_write(b, data, sizeof *data); + cmd_send_string(b, data->target); + cmd_send_string(b, data->cmd); +} + +void +cmd_split_window_recv(struct cmd *self, struct buffer *b) +{ + struct cmd_split_window_data *data; + + self->data = data = xmalloc(sizeof *data); + buffer_read(b, data, sizeof *data); + data->target = cmd_recv_string(b); + data->cmd = cmd_recv_string(b); +} + +void +cmd_split_window_free(struct cmd *self) +{ + struct cmd_split_window_data *data = self->data; + + if (data->target != NULL) + xfree(data->target); + if (data->cmd != NULL) + xfree(data->cmd); + xfree(data); +} + +size_t +cmd_split_window_print(struct cmd *self, char *buf, size_t len) +{ + struct cmd_split_window_data *data = self->data; + size_t off = 0; + + off += xsnprintf(buf, len, "%s", self->entry->name); + if (data == NULL) + return (off); + if (off < len && data->flag_detached) + off += xsnprintf(buf + off, len - off, " -d"); + if (off < len && data->target != NULL) + off += cmd_prarg(buf + off, len - off, " -t ", data->target); + if (off < len && data->cmd != NULL) + off += cmd_prarg(buf + off, len - off, " ", data->cmd); + return (off); +} diff --git a/cmd-start-server.c b/cmd-start-server.c new file mode 100644 index 00000000..21bc2395 --- /dev/null +++ b/cmd-start-server.c @@ -0,0 +1,46 @@ +/* $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. + */ + +int cmd_start_server_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_start_server_entry = { + "start-server", "start", + "", + CMD_STARTSERVER, + NULL, + NULL, + cmd_start_server_exec, + NULL, + NULL, + NULL, + NULL +}; + +int +cmd_start_server_exec(unused struct cmd *self, unused struct cmd_ctx *ctx) +{ + return (0); +} diff --git a/cmd-string.c b/cmd-string.c new file mode 100644 index 00000000..1e471081 --- /dev/null +++ b/cmd-string.c @@ -0,0 +1,309 @@ +/* $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 "tmux.h" + +/* + * Parse a command from a string. + */ + +int cmd_string_getc(const char *, size_t *); +void cmd_string_ungetc(const char *, size_t *); +char *cmd_string_string(const char *, size_t *, char, int); +char *cmd_string_variable(const char *, size_t *); + +int +cmd_string_getc(const char *s, size_t *p) +{ + if (s[*p] == '\0') + return (EOF); + return (s[(*p)++]); +} + +void +cmd_string_ungetc(unused const char *s, size_t *p) +{ + (*p)--; +} + +/* + * Parse command string. Returns -1 on error. If returning -1, cause is error + * string, or NULL for empty command. + */ +int +cmd_string_parse(const char *s, struct cmd_list **cmdlist, char **cause) +{ + size_t p; + int ch, argc, rval, have_arg; + char **argv, *buf, *t, *u; + size_t len; + + if ((t = strchr(s, ' ')) == NULL && (t = strchr(s, '\t')) == NULL) + t = strchr(s, '\0'); + if ((u = strchr(s, '=')) != NULL && u < t) { + if (putenv((char *) s) != 0) { + xasprintf(cause, "assignment failed: %s", s); + return (-1); + } + *cmdlist = NULL; + return (0); + } + + argv = NULL; + argc = 0; + + buf = NULL; + len = 0; + + have_arg = 0; + + *cause = NULL; + + *cmdlist = NULL; + rval = -1; + + p = 0; + for (;;) { + ch = cmd_string_getc(s, &p); + switch (ch) { + case '\'': + if ((t = cmd_string_string(s, &p, '\'', 0)) == NULL) + goto error; + buf = xrealloc(buf, 1, len + strlen(t) + 1); + strlcpy(buf + len, t, strlen(t) + 1); + len += strlen(t); + xfree(t); + + have_arg = 1; + break; + case '"': + if ((t = cmd_string_string(s, &p, '"', 1)) == NULL) + goto error; + buf = xrealloc(buf, 1, len + strlen(t) + 1); + strlcpy(buf + len, t, strlen(t) + 1); + len += strlen(t); + xfree(t); + + have_arg = 1; + break; + case '$': + if ((t = cmd_string_variable(s, &p)) == NULL) + goto error; + buf = xrealloc(buf, 1, len + strlen(t) + 1); + strlcpy(buf + len, t, strlen(t) + 1); + len += strlen(t); + + have_arg = 1; + break; + case '#': + /* Comment: discard rest of line. */ + while ((ch = cmd_string_getc(s, &p)) != EOF) + ; + /* FALLTHROUGH */ + case EOF: + case ' ': + case '\t': + if (have_arg) { + buf = xrealloc(buf, 1, len + 1); + buf[len] = '\0'; + + argv = xrealloc(argv, argc + 1, sizeof *argv); + argv[argc++] = buf; + + buf = NULL; + len = 0; + + have_arg = 0; + } + + if (ch != EOF) + break; + if (argc == 0) + goto out; + + *cmdlist = cmd_list_parse(argc, argv, cause); + if (*cmdlist == NULL) + goto out; + + do + xfree(argv[argc - 1]); + while (--argc > 0); + + rval = 0; + goto out; + default: + if (len >= SIZE_MAX - 2) + goto error; + + buf = xrealloc(buf, 1, len + 1); + buf[len++] = ch; + + have_arg = 1; + break; + } + } + +error: + xasprintf(cause, "invalid or unknown command: %s", s); + +out: + if (buf != NULL) + xfree(buf); + + while (--argc >= 0) + xfree(argv[argc]); + if (argv != NULL) + xfree(argv); + + return (rval); +} + +char * +cmd_string_string(const char *s, size_t *p, char endch, int esc) +{ + int ch; + char *buf, *t; + size_t len; + + buf = NULL; + len = 0; + + while ((ch = cmd_string_getc(s, p)) != endch) { + switch (ch) { + case EOF: + goto error; + case '\\': + if (!esc) + break; + switch (ch = cmd_string_getc(s, p)) { + case EOF: + goto error; + case 'r': + ch = '\r'; + break; + case 'n': + ch = '\n'; + break; + case 't': + ch = '\t'; + break; + } + break; + case '$': + if (!esc) + break; + if ((t = cmd_string_variable(s, p)) == NULL) + goto error; + buf = xrealloc(buf, 1, len + strlen(t) + 1); + strlcpy(buf + len, t, strlen(t) + 1); + len += strlen(t); + continue; + } + + if (len >= SIZE_MAX - 2) + goto error; + buf = xrealloc(buf, 1, len + 1); + buf[len++] = ch; + } + + buf = xrealloc(buf, 1, len + 1); + buf[len] = '\0'; + return (buf); + +error: + if (buf != NULL) + xfree(buf); + return (NULL); +} + +char * +cmd_string_variable(const char *s, size_t *p) +{ + int ch, fch; + char *buf, *t; + size_t len; + +#define cmd_string_first(ch) ((ch) == '_' || \ + ((ch) >= 'a' && (ch) <= 'z') || ((ch) >= 'A' && (ch) <= 'Z')) +#define cmd_string_other(ch) ((ch) == '_' || \ + ((ch) >= 'a' && (ch) <= 'z') || ((ch) >= 'A' && (ch) <= 'Z') || \ + ((ch) >= '0' && (ch) <= '9')) + + buf = NULL; + len = 0; + + fch = EOF; + switch (ch = cmd_string_getc(s, p)) { + case EOF: + goto error; + case '{': + fch = '{'; + + ch = cmd_string_getc(s, p); + if (!cmd_string_first(ch)) + goto error; + /* FALLTHROUGH */ + default: + if (!cmd_string_first(ch)) { + xasprintf(&t, "$%c", ch); + return (t); + } + + buf = xrealloc(buf, 1, len + 1); + buf[len++] = ch; + + for (;;) { + ch = cmd_string_getc(s, p); + if (ch == EOF || !cmd_string_other(ch)) + break; + else { + if (len >= SIZE_MAX - 3) + goto error; + buf = xrealloc(buf, 1, len + 1); + buf[len++] = ch; + } + } + } + + if (fch == '{' && ch != '}') + goto error; + if (ch != EOF && fch != '{') + cmd_string_ungetc(s, p); /* ch */ + + buf = xrealloc(buf, 1, len + 1); + buf[len] = '\0'; + + if ((t = getenv(buf)) == NULL) { + xfree(buf); + return (xstrdup("")); + } + xfree(buf); + return (xstrdup(t)); + +error: + if (buf != NULL) + xfree(buf); + return (NULL); +} diff --git a/cmd-suspend-client.c b/cmd-suspend-client.c new file mode 100644 index 00000000..00941f61 --- /dev/null +++ b/cmd-suspend-client.c @@ -0,0 +1,64 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2009 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 "tmux.h" + +/* + * Suspend client with SIGTSTP. + */ + +int cmd_suspend_client_exec(struct cmd *, struct cmd_ctx *); + +struct cmd_suspend_client_data { + char *name; + char *target; +}; + +const struct cmd_entry cmd_suspend_client_entry = { + "suspend-client", "suspendc", + "[-c target-client]", + 0, + cmd_target_init, + cmd_target_parse, + cmd_suspend_client_exec, + cmd_target_send, + cmd_target_recv, + cmd_target_free, + cmd_target_print +}; + +int +cmd_suspend_client_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_target_data *data = self->data; + struct client *c; + + if ((c = cmd_find_client(ctx, data->target)) == NULL) + return (-1); + + tty_stop_tty(&c->tty); + c->flags |= CLIENT_SUSPENDED; + server_write_client(c, MSG_SUSPEND, NULL, 0); + + return (0); +} diff --git a/cmd-swap-pane.c b/cmd-swap-pane.c new file mode 100644 index 00000000..0a34d14d --- /dev/null +++ b/cmd-swap-pane.c @@ -0,0 +1,285 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2009 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 "tmux.h" + +/* + * Swap two panes. + */ + +int cmd_swap_pane_parse(struct cmd *, int, char **, char **); +int cmd_swap_pane_exec(struct cmd *, struct cmd_ctx *); +void cmd_swap_pane_send(struct cmd *, struct buffer *); +void cmd_swap_pane_recv(struct cmd *, struct buffer *); +void cmd_swap_pane_free(struct cmd *); +void cmd_swap_pane_init(struct cmd *, int); +size_t cmd_swap_pane_print(struct cmd *, char *, size_t); + +struct cmd_swap_pane_data { + char *target; + int src; + int dst; + int flag_detached; + int flag_up; + int flag_down; +}; + +const struct cmd_entry cmd_swap_pane_entry = { + "swap-pane", "swapp", + "[-dDU] [-t target-window] [-p src-index] [-q dst-index]", + 0, + cmd_swap_pane_init, + cmd_swap_pane_parse, + cmd_swap_pane_exec, + cmd_swap_pane_send, + cmd_swap_pane_recv, + cmd_swap_pane_free, + cmd_swap_pane_print +}; + +void +cmd_swap_pane_init(struct cmd *self, int key) +{ + struct cmd_swap_pane_data *data; + + self->data = data = xmalloc(sizeof *data); + data->target = NULL; + data->src = -1; + data->dst = -1; + data->flag_detached = 0; + data->flag_up = 0; + data->flag_down = 0; + + switch (key) { + case '{': + data->flag_up = 1; + break; + case '}': + data->flag_down = 1; + break; + } +} + +int +cmd_swap_pane_parse(struct cmd *self, int argc, char **argv, char **cause) +{ + struct cmd_swap_pane_data *data; + int opt, n; + const char *errstr; + + self->entry->init(self, 0); + data = self->data; + + while ((opt = getopt(argc, argv, "dDt:p:q:U")) != -1) { + switch (opt) { + case 'd': + data->flag_detached = 1; + break; + case 'D': + data->flag_up = 0; + data->flag_down = 1; + data->dst = -1; + break; + case 't': + if (data->target == NULL) + data->target = xstrdup(optarg); + break; + case 'p': + if (data->src == -1) { + n = strtonum(optarg, 0, INT_MAX, &errstr); + if (errstr != NULL) { + xasprintf(cause, "src %s", errstr); + goto error; + } + data->src = n; + } + break; + case 'q': + if (data->dst == -1) { + n = strtonum(optarg, 0, INT_MAX, &errstr); + if (errstr != NULL) { + xasprintf(cause, "dst %s", errstr); + goto error; + } + data->dst = n; + } + data->flag_up = 0; + data->flag_down = 0; + break; + case 'U': + data->flag_up = 1; + data->flag_down = 0; + data->dst = -1; + break; + + default: + goto usage; + } + } + argc -= optind; + argv += optind; + if (argc != 0) + goto usage; + + return (0); + +usage: + xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); + +error: + self->entry->free(self); + return (-1); +} + +int +cmd_swap_pane_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_swap_pane_data *data = self->data; + struct winlink *wl; + struct window *w; + struct window_pane *tmp_wp, *src_wp, *dst_wp; + u_int xx, yy; + + if (data == NULL) + return (0); + + if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) + return (-1); + w = wl->window; + + if (data->src == -1) + src_wp = w->active; + else { + src_wp = window_pane_at_index(w, data->src); + if (src_wp == NULL) { + ctx->error(ctx, "no pane: %d", data->src); + return (-1); + } + } + if (data->dst == -1) + dst_wp = w->active; + else { + dst_wp = window_pane_at_index(w, data->dst); + if (dst_wp == NULL) { + ctx->error(ctx, "no pane: %d", data->dst); + return (-1); + } + } + + if (data->dst == -1 && data->flag_up) { + if ((dst_wp = TAILQ_PREV(src_wp, window_panes, entry)) == NULL) + dst_wp = TAILQ_LAST(&w->panes, window_panes); + } + if (data->dst == -1 && data->flag_down) { + if ((dst_wp = TAILQ_NEXT(src_wp, entry)) == NULL) + dst_wp = TAILQ_FIRST(&w->panes); + } + + if (src_wp == dst_wp) + return (0); + + tmp_wp = TAILQ_PREV(dst_wp, window_panes, entry); + TAILQ_REMOVE(&w->panes, dst_wp, entry); + TAILQ_REPLACE(&w->panes, src_wp, dst_wp, entry); + if (tmp_wp == src_wp) + tmp_wp = dst_wp; + if (tmp_wp == NULL) + TAILQ_INSERT_HEAD(&w->panes, src_wp, entry); + else + TAILQ_INSERT_AFTER(&w->panes, tmp_wp, src_wp, entry); + + xx = src_wp->xoff; + yy = src_wp->yoff; + src_wp->xoff = dst_wp->xoff; + src_wp->yoff = dst_wp->yoff; + dst_wp->xoff = xx; + dst_wp->yoff = yy; + + xx = src_wp->sx; + yy = src_wp->sy; + window_pane_resize(src_wp, dst_wp->sx, dst_wp->sy); + window_pane_resize(dst_wp, xx, yy); + + if (!data->flag_detached) { + window_set_active_pane(w, dst_wp); + layout_refresh(w, 0); + } + + return (0); +} + +void +cmd_swap_pane_send(struct cmd *self, struct buffer *b) +{ + struct cmd_swap_pane_data *data = self->data; + + buffer_write(b, data, sizeof *data); + cmd_send_string(b, data->target); +} + +void +cmd_swap_pane_recv(struct cmd *self, struct buffer *b) +{ + struct cmd_swap_pane_data *data; + + self->data = data = xmalloc(sizeof *data); + buffer_read(b, data, sizeof *data); + data->target = cmd_recv_string(b); +} + +void +cmd_swap_pane_free(struct cmd *self) +{ + struct cmd_swap_pane_data *data = self->data; + + if (data->target != NULL) + xfree(data->target); + xfree(data); +} + +size_t +cmd_swap_pane_print(struct cmd *self, char *buf, size_t len) +{ + struct cmd_swap_pane_data *data = self->data; + size_t off = 0; + + off += xsnprintf(buf, len, "%s", self->entry->name); + if (data == NULL) + return (off); + if (off < len && + (data->flag_down || data->flag_up || data->flag_detached)) { + off += xsnprintf(buf + off, len - off, " -"); + if (off < len && data->flag_detached) + off += xsnprintf(buf + off, len - off, "d"); + if (off < len && data->flag_up) + off += xsnprintf(buf + off, len - off, "D"); + if (off < len && data->flag_down) + off += xsnprintf(buf + off, len - off, "U"); + } + if (off < len && data->target != NULL) + off += cmd_prarg(buf + off, len - off, " -t ", data->target); + if (off < len && data->src != -1) + off += xsnprintf(buf + off, len - off, " -p %d", data->src); + if (off < len && data->dst != -1) + off += xsnprintf(buf + off, len - off, " -q %d", data->dst); + return (off); +} diff --git a/cmd-swap-window.c b/cmd-swap-window.c new file mode 100644 index 00000000..4a72a3e5 --- /dev/null +++ b/cmd-swap-window.c @@ -0,0 +1,75 @@ +/* $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 + +#include "tmux.h" + +/* + * Swap one window with another. + */ + +int cmd_swap_window_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_swap_window_entry = { + "swap-window", "swapw", + "[-d] " CMD_SRCDST_WINDOW_USAGE, + CMD_DFLAG, + cmd_srcdst_init, + cmd_srcdst_parse, + cmd_swap_window_exec, + cmd_srcdst_send, + cmd_srcdst_recv, + cmd_srcdst_free, + cmd_srcdst_print +}; + +int +cmd_swap_window_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_srcdst_data *data = self->data; + struct session *src, *dst; + struct winlink *wl_src, *wl_dst; + struct window *w; + + if ((wl_src = cmd_find_window(ctx, data->src, &src)) == NULL) + return (-1); + if ((wl_dst = cmd_find_window(ctx, data->dst, &dst)) == NULL) + return (-1); + + if (wl_dst->window == wl_src->window) + return (0); + + w = wl_dst->window; + wl_dst->window = wl_src->window; + wl_src->window = w; + + if (!(data->flags & CMD_DFLAG)) { + session_select(dst, wl_dst->idx); + if (src != dst) + session_select(src, wl_src->idx); + } + server_redraw_session(src); + if (src != dst) + server_redraw_session(dst); + recalculate_sizes(); + + return (0); +} diff --git a/cmd-switch-client.c b/cmd-switch-client.c new file mode 100644 index 00000000..9df443db --- /dev/null +++ b/cmd-switch-client.c @@ -0,0 +1,161 @@ +/* $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 +#include + +#include "tmux.h" + +/* + * Switch client to a different session. + */ + +int cmd_switch_client_parse(struct cmd *, int, char **, char **); +int cmd_switch_client_exec(struct cmd *, struct cmd_ctx *); +void cmd_switch_client_send(struct cmd *, struct buffer *); +void cmd_switch_client_recv(struct cmd *, struct buffer *); +void cmd_switch_client_free(struct cmd *); +size_t cmd_switch_client_print(struct cmd *, char *, size_t); + +struct cmd_switch_client_data { + char *name; + char *target; +}; + +const struct cmd_entry cmd_switch_client_entry = { + "switch-client", "switchc", + "[-c target-client] [-t target-session]", + 0, + NULL, + cmd_switch_client_parse, + cmd_switch_client_exec, + cmd_switch_client_send, + cmd_switch_client_recv, + cmd_switch_client_free, + cmd_switch_client_print +}; + +int +cmd_switch_client_parse(struct cmd *self, int argc, char **argv, char **cause) +{ + struct cmd_switch_client_data *data; + int opt; + + self->data = data = xmalloc(sizeof *data); + data->name = NULL; + data->target = NULL; + + while ((opt = getopt(argc, argv, "c:t:")) != -1) { + switch (opt) { + case 'c': + data->name = xstrdup(optarg); + break; + case 't': + data->target = xstrdup(optarg); + break; + default: + goto usage; + } + } + argc -= optind; + argv += optind; + if (argc != 0) + goto usage; + + return (0); + +usage: + xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); + + self->entry->free(self); + return (-1); +} + +int +cmd_switch_client_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_switch_client_data *data = self->data; + struct client *c; + struct session *s; + + if (data == NULL) + return (0); + + if ((c = cmd_find_client(ctx, data->name)) == NULL) + return (-1); + if ((s = cmd_find_session(ctx, data->target)) == NULL) + return (-1); + + c->session = s; + + recalculate_sizes(); + server_redraw_client(c); + + return (0); +} + +void +cmd_switch_client_send(struct cmd *self, struct buffer *b) +{ + struct cmd_switch_client_data *data = self->data; + + buffer_write(b, data, sizeof *data); + cmd_send_string(b, data->name); + cmd_send_string(b, data->target); +} + +void +cmd_switch_client_recv(struct cmd *self, struct buffer *b) +{ + struct cmd_switch_client_data *data; + + self->data = data = xmalloc(sizeof *data); + buffer_read(b, data, sizeof *data); + data->name = cmd_recv_string(b); + data->target = cmd_recv_string(b); +} + +void +cmd_switch_client_free(struct cmd *self) +{ + struct cmd_switch_client_data *data = self->data; + + if (data->name != NULL) + xfree(data->name); + if (data->target != NULL) + xfree(data->target); + xfree(data); +} + +size_t +cmd_switch_client_print(struct cmd *self, char *buf, size_t len) +{ + struct cmd_switch_client_data *data = self->data; + size_t off = 0; + + off += xsnprintf(buf, len, "%s", self->entry->name); + if (data == NULL) + return (off); + if (off < len && data->name != NULL) + off += cmd_prarg(buf + off, len - off, " -c ", data->name); + if (off < len && data->target != NULL) + off += cmd_prarg(buf + off, len - off, " -t ", data->target); + return (off); +} diff --git a/cmd-unbind-key.c b/cmd-unbind-key.c new file mode 100644 index 00000000..d9389752 --- /dev/null +++ b/cmd-unbind-key.c @@ -0,0 +1,120 @@ +/* $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" + +/* + * Unbind key from command. + */ + +int cmd_unbind_key_parse(struct cmd *, int, char **, char **); +int cmd_unbind_key_exec(struct cmd *, struct cmd_ctx *); +void cmd_unbind_key_send(struct cmd *, struct buffer *); +void cmd_unbind_key_recv(struct cmd *, struct buffer *); +void cmd_unbind_key_free(struct cmd *); + +struct cmd_unbind_key_data { + int key; +}; + +const struct cmd_entry cmd_unbind_key_entry = { + "unbind-key", "unbind", + "key", + 0, + NULL, + cmd_unbind_key_parse, + cmd_unbind_key_exec, + cmd_unbind_key_send, + cmd_unbind_key_recv, + cmd_unbind_key_free, + NULL +}; + +int +cmd_unbind_key_parse(struct cmd *self, int argc, char **argv, char **cause) +{ + struct cmd_unbind_key_data *data; + int opt; + + self->data = data = xmalloc(sizeof *data); + + while ((opt = getopt(argc, argv, "")) != -1) { + switch (opt) { + default: + goto usage; + } + } + argc -= optind; + argv += optind; + if (argc != 1) + goto usage; + + if ((data->key = key_string_lookup_string(argv[0])) == KEYC_NONE) { + xasprintf(cause, "unknown key: %s", argv[0]); + goto error; + } + + return (0); + +usage: + xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); + +error: + xfree(data); + return (-1); +} + +int +cmd_unbind_key_exec(struct cmd *self, unused struct cmd_ctx *ctx) +{ + struct cmd_unbind_key_data *data = self->data; + + if (data == NULL) + return (0); + + key_bindings_remove(data->key); + + return (0); +} + +void +cmd_unbind_key_send(struct cmd *self, struct buffer *b) +{ + struct cmd_unbind_key_data *data = self->data; + + buffer_write(b, data, sizeof *data); +} + +void +cmd_unbind_key_recv(struct cmd *self, struct buffer *b) +{ + struct cmd_unbind_key_data *data; + + self->data = data = xmalloc(sizeof *data); + buffer_read(b, data, sizeof *data); +} + +void +cmd_unbind_key_free(struct cmd *self) +{ + struct cmd_unbind_key_data *data = self->data; + + xfree(data); +} diff --git a/cmd-unlink-window.c b/cmd-unlink-window.c new file mode 100644 index 00000000..5d9734b6 --- /dev/null +++ b/cmd-unlink-window.c @@ -0,0 +1,74 @@ +/* $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" + +/* + * Unlink a window, unless it would be destroyed by doing so (only one link). + */ + +int cmd_unlink_window_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_unlink_window_entry = { + "unlink-window", "unlinkw", + CMD_TARGET_WINDOW_USAGE, + 0, + cmd_target_init, + cmd_target_parse, + cmd_unlink_window_exec, + cmd_target_send, + cmd_target_recv, + cmd_target_free, + cmd_target_print +}; + +int +cmd_unlink_window_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_target_data *data = self->data; + struct winlink *wl; + struct session *s; + struct client *c; + u_int i; + int destroyed; + + if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL) + return (-1); + + if (wl->window->references == 1) { + ctx->error(ctx, "window is only linked to one session"); + return (-1); + } + + destroyed = session_detach(s, wl); + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c == NULL || c->session != s) + continue; + if (destroyed) { + c->session = NULL; + server_write_client(c, MSG_EXIT, NULL, 0); + } else + server_redraw_client(c); + } + recalculate_sizes(); + + return (0); +} diff --git a/cmd-up-pane.c b/cmd-up-pane.c new file mode 100644 index 00000000..fc62173e --- /dev/null +++ b/cmd-up-pane.c @@ -0,0 +1,61 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2009 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" + +/* + * Move up a pane. + */ + +int cmd_up_pane_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_up_pane_entry = { + "up-pane", "upp", + CMD_TARGET_WINDOW_USAGE, + 0, + cmd_target_init, + cmd_target_parse, + cmd_up_pane_exec, + cmd_target_send, + cmd_target_recv, + cmd_target_free, + cmd_target_print +}; + +int +cmd_up_pane_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_target_data *data = self->data; + struct winlink *wl; + struct window *w; + + if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) + return (-1); + w = wl->window; + + do { + w->active = TAILQ_PREV(w->active, window_panes, entry); + if (w->active == NULL) + w->active = TAILQ_LAST(&w->panes, window_panes); + layout_refresh(w, 1); + } while (w->active->flags & PANE_HIDDEN); + + return (0); +} diff --git a/cmd.c b/cmd.c new file mode 100644 index 00000000..fc87558d --- /dev/null +++ b/cmd.c @@ -0,0 +1,393 @@ +/* $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 + +#include +#include +#include + +#include "tmux.h" + +const struct cmd_entry *cmd_table[] = { + &cmd_attach_session_entry, + &cmd_bind_key_entry, + &cmd_break_pane_entry, + &cmd_choose_session_entry, + &cmd_choose_window_entry, + &cmd_clear_history_entry, + &cmd_clock_mode_entry, + &cmd_command_prompt_entry, + &cmd_confirm_before_entry, + &cmd_copy_buffer_entry, + &cmd_copy_mode_entry, + &cmd_delete_buffer_entry, + &cmd_detach_client_entry, + &cmd_down_pane_entry, + &cmd_find_window_entry, + &cmd_has_session_entry, + &cmd_kill_pane_entry, + &cmd_kill_server_entry, + &cmd_kill_session_entry, + &cmd_kill_window_entry, + &cmd_last_window_entry, + &cmd_link_window_entry, + &cmd_list_buffers_entry, + &cmd_list_clients_entry, + &cmd_list_commands_entry, + &cmd_list_keys_entry, + &cmd_list_sessions_entry, + &cmd_list_windows_entry, + &cmd_load_buffer_entry, + &cmd_lock_server_entry, + &cmd_move_window_entry, + &cmd_new_session_entry, + &cmd_new_window_entry, + &cmd_next_layout_entry, + &cmd_next_window_entry, + &cmd_paste_buffer_entry, + &cmd_previous_layout_entry, + &cmd_previous_window_entry, + &cmd_refresh_client_entry, + &cmd_rename_session_entry, + &cmd_rename_window_entry, + &cmd_resize_pane_entry, + &cmd_respawn_window_entry, + &cmd_rotate_window_entry, + &cmd_save_buffer_entry, + &cmd_scroll_mode_entry, + &cmd_select_layout_entry, + &cmd_select_pane_entry, + &cmd_select_prompt_entry, + &cmd_select_window_entry, + &cmd_send_keys_entry, + &cmd_send_prefix_entry, + &cmd_server_info_entry, + &cmd_set_buffer_entry, + &cmd_set_option_entry, + &cmd_set_password_entry, + &cmd_set_window_option_entry, + &cmd_show_buffer_entry, + &cmd_show_options_entry, + &cmd_show_window_options_entry, + &cmd_source_file_entry, + &cmd_split_window_entry, + &cmd_start_server_entry, + &cmd_suspend_client_entry, + &cmd_swap_pane_entry, + &cmd_swap_window_entry, + &cmd_switch_client_entry, + &cmd_unbind_key_entry, + &cmd_unlink_window_entry, + &cmd_up_pane_entry, + NULL +}; + +struct cmd * +cmd_parse(int argc, char **argv, char **cause) +{ + const struct cmd_entry **entryp, *entry; + struct cmd *cmd; + char s[BUFSIZ]; + int opt; + + *cause = NULL; + if (argc == 0) + return (NULL); + + entry = NULL; + for (entryp = cmd_table; *entryp != NULL; entryp++) { + if ((*entryp)->alias != NULL && + strcmp((*entryp)->alias, argv[0]) == 0) { + entry = *entryp; + break; + } + + if (strncmp((*entryp)->name, argv[0], strlen(argv[0])) != 0) + continue; + if (entry != NULL) + goto ambiguous; + entry = *entryp; + + /* Bail now if an exact match. */ + if (strcmp(entry->name, argv[0]) == 0) + break; + } + if (entry == NULL) { + xasprintf(cause, "unknown command: %s", argv[0]); + return (NULL); + } + + optreset = 1; + optind = 1; + if (entry->parse == NULL) { + while ((opt = getopt(argc, argv, "")) != -1) { + switch (opt) { + default: + goto usage; + } + } + argc -= optind; + argv += optind; + if (argc != 0) + goto usage; + } + + cmd = xmalloc(sizeof *cmd); + cmd->entry = entry; + cmd->data = NULL; + if (entry->parse != NULL) { + if (entry->parse(cmd, argc, argv, cause) != 0) { + xfree(cmd); + return (NULL); + } + } + return (cmd); + +ambiguous: + *s = '\0'; + for (entryp = cmd_table; *entryp != NULL; entryp++) { + if (strncmp((*entryp)->name, argv[0], strlen(argv[0])) != 0) + continue; + if (strlcat(s, (*entryp)->name, sizeof s) >= sizeof s) + break; + if (strlcat(s, ", ", sizeof s) >= sizeof s) + break; + } + s[strlen(s) - 2] = '\0'; + xasprintf(cause, "ambiguous command: %s, could be: %s", argv[0], s); + return (NULL); + +usage: + xasprintf(cause, "usage: %s %s", entry->name, entry->usage); + return (NULL); +} + +int +cmd_exec(struct cmd *cmd, struct cmd_ctx *ctx) +{ + if (server_locked) { + ctx->error(ctx, "server is locked"); + return (-1); + } + return (cmd->entry->exec(cmd, ctx)); +} + +void +cmd_send(struct cmd *cmd, struct buffer *b) +{ + const struct cmd_entry **entryp; + u_int n; + + n = 0; + for (entryp = cmd_table; *entryp != NULL; entryp++) { + if (*entryp == cmd->entry) + break; + n++; + } + if (*entryp == NULL) + fatalx("command not found"); + + buffer_write(b, &n, sizeof n); + + if (cmd->entry->send != NULL) + cmd->entry->send(cmd, b); +} + +struct cmd * +cmd_recv(struct buffer *b) +{ + const struct cmd_entry **entryp; + struct cmd *cmd; + u_int m, n; + + buffer_read(b, &m, sizeof m); + + n = 0; + for (entryp = cmd_table; *entryp != NULL; entryp++) { + if (n == m) + break; + n++; + } + if (*entryp == NULL) + fatalx("command not found"); + + cmd = xmalloc(sizeof *cmd); + cmd->entry = *entryp; + + if (cmd->entry->recv != NULL) + cmd->entry->recv(cmd, b); + return (cmd); +} + +void +cmd_free(struct cmd *cmd) +{ + if (cmd->data != NULL && cmd->entry->free != NULL) + cmd->entry->free(cmd); + xfree(cmd); +} + +size_t +cmd_print(struct cmd *cmd, char *buf, size_t len) +{ + if (cmd->entry->print == NULL) { + return (xsnprintf(buf, len, "%s", cmd->entry->name)); + } + return (cmd->entry->print(cmd, buf, len)); +} + +void +cmd_send_string(struct buffer *b, const char *s) +{ + size_t n; + + if (s == NULL) { + n = 0; + buffer_write(b, &n, sizeof n); + return; + } + + n = strlen(s) + 1; + buffer_write(b, &n, sizeof n); + + buffer_write(b, s, n); +} + +char * +cmd_recv_string(struct buffer *b) +{ + char *s; + size_t n; + + buffer_read(b, &n, sizeof n); + + if (n == 0) + return (NULL); + + s = xmalloc(n); + buffer_read(b, s, n); + s[n - 1] = '\0'; + + return (s); +} + +struct session * +cmd_current_session(struct cmd_ctx *ctx) +{ + struct msg_command_data *data = ctx->msgdata; + struct timeval *tv; + struct session *s, *newest = NULL; + u_int i; + + if (ctx->cursession != NULL) + return (ctx->cursession); + + if (data != NULL && data->pid != -1) { + if (data->pid != getpid()) { + ctx->error(ctx, "wrong server: %ld", (long) data->pid); + return (NULL); + } + if (data->idx > ARRAY_LENGTH(&sessions)) { + ctx->error(ctx, "index out of range: %d", data->idx); + return (NULL); + } + if ((s = ARRAY_ITEM(&sessions, data->idx)) == NULL) { + ctx->error(ctx, "session doesn't exist: %u", data->idx); + return (NULL); + } + return (s); + } + + tv = NULL; + for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { + s = ARRAY_ITEM(&sessions, i); + if (s != NULL && (tv == NULL || timercmp(&s->tv, tv, >))) { + newest = ARRAY_ITEM(&sessions, i); + tv = &s->tv; + } + } + return (newest); +} + +struct client * +cmd_find_client(struct cmd_ctx *ctx, const char *arg) +{ + struct client *c; + + if (arg == NULL) + c = ctx->curclient; + else { + if ((c = arg_parse_client(arg)) == NULL) { + if (arg != NULL) + ctx->error(ctx, "client not found: %s", arg); + else + ctx->error(ctx, "no client found"); + } + } + return (c); +} + +struct session * +cmd_find_session(struct cmd_ctx *ctx, const char *arg) +{ + struct session *s; + + if (arg == NULL) + s = cmd_current_session(ctx); + else { + if ((s = arg_parse_session(arg)) == NULL) { + if (arg != NULL) + ctx->error(ctx, "session not found: %s", arg); + else + ctx->error(ctx, "no session found"); + } + } + return (s); +} + +struct winlink * +cmd_find_window(struct cmd_ctx *ctx, const char *arg, struct session **sp) +{ + struct session *s; + struct winlink *wl; + int idx; + + wl = NULL; + if (arg_parse_window(arg, &s, &idx) != 0) { + ctx->error(ctx, "bad window: %s", arg); + return (NULL); + } + if (s == NULL) + s = ctx->cursession; + if (s == NULL) + s = cmd_current_session(ctx); + if (s == NULL) + return (NULL); + if (sp != NULL) + *sp = s; + + if (idx == -1) + wl = s->curw; + else + wl = winlink_find_by_index(&s->windows, idx); + if (wl == NULL) + ctx->error(ctx, "window not found: %s:%d", s->name, idx); + return (wl); +} diff --git a/colour.c b/colour.c new file mode 100644 index 00000000..2067d0dd --- /dev/null +++ b/colour.c @@ -0,0 +1,123 @@ +/* $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 "tmux.h" + +const char * +colour_tostring(u_char c) +{ + switch (c) { + case 0: + return ("black"); + case 1: + return ("red"); + case 2: + return ("green"); + case 3: + return ("yellow"); + case 4: + return ("blue"); + case 5: + return ("magenta"); + case 6: + return ("cyan"); + case 7: + return ("white"); + case 8: + return ("default"); + } + return (NULL); +} + +int +colour_fromstring(const char *s) +{ + if (strcasecmp(s, "black") == 0 || (s[0] == '0' && s[1] == '\0')) + return (0); + if (strcasecmp(s, "red") == 0 || (s[0] == '1' && s[1] == '\0')) + return (1); + if (strcasecmp(s, "green") == 0 || (s[0] == '2' && s[1] == '\0')) + return (2); + if (strcasecmp(s, "yellow") == 0 || (s[0] == '3' && s[1] == '\0')) + return (3); + if (strcasecmp(s, "blue") == 0 || (s[0] == '4' && s[1] == '\0')) + return (4); + if (strcasecmp(s, "magenta") == 0 || (s[0] == '5' && s[1] == '\0')) + return (5); + if (strcasecmp(s, "cyan") == 0 || (s[0] == '6' && s[1] == '\0')) + return (6); + if (strcasecmp(s, "white") == 0 || (s[0] == '7' && s[1] == '\0')) + return (7); + if (strcasecmp(s, "default") == 0 || (s[0] == '8' && s[1] == '\0')) + return (8); + return (-1); +} + +u_char +colour_256to16(u_char c) +{ + static const u_char table[256] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 4, 4, 4, 12, 12, 2, 6, 4, 4, 12, 12, 2, 2, 6, 4, + 12, 12, 2, 2, 2, 6, 12, 12, 10, 10, 10, 10, 14, 12, 10, 10, + 10, 10, 10, 14, 1, 5, 4, 4, 12, 12, 3, 8, 4, 4, 12, 12, + 2, 2, 6, 4, 12, 12, 2, 2, 2, 6, 12, 12, 10, 10, 10, 10, + 14, 12, 10, 10, 10, 10, 10, 14, 1, 1, 5, 4, 12, 12, 1, 1, + 5, 4, 12, 12, 3, 3, 8, 4, 12, 12, 2, 2, 2, 6, 12, 12, + 10, 10, 10, 10, 14, 12, 10, 10, 10, 10, 10, 14, 1, 1, 1, 5, + 12, 12, 1, 1, 1, 5, 12, 12, 1, 1, 1, 5, 12, 12, 3, 3, + 3, 7, 12, 12, 10, 10, 10, 10, 14, 12, 10, 10, 10, 10, 10, 14, + 9, 9, 9, 9, 13, 12, 9, 9, 9, 9, 13, 12, 9, 9, 9, 9, + 13, 12, 9, 9, 9, 9, 13, 12, 11, 11, 11, 11, 7, 12, 10, 10, + 10, 10, 10, 14, 9, 9, 9, 9, 9, 13, 9, 9, 9, 9, 9, 13, + 9, 9, 9, 9, 9, 13, 9, 9, 9, 9, 9, 13, 9, 9, 9, 9, + 9, 13, 11, 11, 11, 11, 11, 15, 0, 0, 0, 0, 0, 0, 8, 8, + 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 15, 15, 15, 15, 15, 15 + }; + + return (table[c]); +} + +u_char +colour_256to88(u_char c) +{ + static const u_char table[256] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 17, 18, 18, 19, 20, 21, 21, 22, 22, 23, 20, 21, 21, 22, + 22, 23, 24, 25, 25, 26, 26, 27, 24, 25, 25, 26, 26, 27, 28, 29, + 29, 30, 30, 31, 32, 33, 33, 34, 34, 35, 36, 37, 37, 38, 38, 39, + 36, 37, 37, 38, 38, 39, 40, 41, 41, 42, 42, 43, 40, 41, 41, 42, + 42, 43, 44, 45, 45, 46, 46, 47, 32, 33, 33, 34, 34, 35, 36, 37, + 37, 38, 38, 39, 36, 37, 37, 38, 38, 39, 40, 41, 41, 42, 42, 43, + 40, 41, 41, 42, 42, 43, 44, 45, 45, 46, 46, 47, 48, 49, 49, 50, + 50, 51, 52, 53, 53, 54, 54, 55, 52, 53, 53, 54, 54, 55, 56, 57, + 57, 58, 58, 59, 56, 57, 57, 58, 58, 59, 60, 61, 61, 62, 62, 63, + 48, 49, 49, 50, 50, 51, 52, 53, 53, 54, 54, 55, 52, 53, 53, 54, + 54, 55, 56, 57, 57, 58, 58, 59, 56, 57, 57, 58, 58, 59, 60, 61, + 61, 62, 62, 63, 64, 65, 65, 66, 66, 67, 68, 69, 69, 70, 70, 71, + 68, 69, 69, 70, 70, 71, 72, 73, 73, 74, 74, 75, 72, 73, 73, 74, + 74, 75, 76, 77, 77, 78, 78, 79, 0, 0, 80, 80, 80, 81, 81, 81, + 82, 82, 82, 83, 83, 83, 84, 84, 84, 85, 85, 85, 86, 86, 86, 87 + }; + + return (table[c]); +} diff --git a/grid-view.c b/grid-view.c new file mode 100644 index 00000000..f1224bf6 --- /dev/null +++ b/grid-view.c @@ -0,0 +1,211 @@ +/* $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 "tmux.h" + +/* + * Grid view functions. These work using coordinates relative to the visible + * screen area. + */ + +#define grid_view_x(gd, x) (x) +#define grid_view_y(gd, y) ((gd)->hsize + (y)) + +/* Get cell for reading. */ +const struct grid_cell * +grid_view_peek_cell(struct grid *gd, u_int px, u_int py) +{ + return (grid_peek_cell(gd, grid_view_x(gd, px), grid_view_y(gd, py))); +} + +/* Get cell for writing. */ +struct grid_cell * +grid_view_get_cell(struct grid *gd, u_int px, u_int py) +{ + return (grid_get_cell(gd, grid_view_x(gd, px), grid_view_y(gd, py))); +} + +/* Set cell. */ +void +grid_view_set_cell( + struct grid *gd, u_int px, u_int py, const struct grid_cell *gc) +{ + grid_set_cell(gd, grid_view_x(gd, px), grid_view_y(gd, py), gc); +} + +/* Get UTF-8 for reading. */ +const struct grid_utf8 * +grid_view_peek_utf8(struct grid *gd, u_int px, u_int py) +{ + return (grid_peek_utf8(gd, grid_view_x(gd, px), grid_view_y(gd, py))); +} + +/* Get UTF-8 for writing. */ +struct grid_utf8 * +grid_view_get_utf8(struct grid *gd, u_int px, u_int py) +{ + return (grid_get_utf8(gd, grid_view_x(gd, px), grid_view_y(gd, py))); +} + +/* Set UTF-8. */ +void +grid_view_set_utf8( + struct grid *gd, u_int px, u_int py, const struct grid_utf8 *gu) +{ + grid_set_utf8(gd, grid_view_x(gd, px), grid_view_y(gd, py), gu); +} + +/* Clear area. */ +void +grid_view_clear(struct grid *gd, u_int px, u_int py, u_int nx, u_int ny) +{ + GRID_DEBUG(gd, "px=%u, py=%u, nx=%u, ny=%u", px, py, nx, ny); + + px = grid_view_x(gd, px); + py = grid_view_y(gd, py); + + grid_clear(gd, px, py, nx, ny); +} + +/* Scroll region up. */ +void +grid_view_scroll_region_up(struct grid *gd, u_int rupper, u_int rlower) +{ + GRID_DEBUG(gd, "rupper=%u, rlower=%u", rupper, rlower); + + if (rupper == 0 && rlower == gd->sy - 1) { + grid_scroll_line(gd); + return; + } + + rupper = grid_view_y(gd, rupper); + rlower = grid_view_y(gd, rlower); + + grid_move_lines(gd, rupper, rupper + 1, rlower - rupper); +} + +/* Scroll region down. */ +void +grid_view_scroll_region_down(struct grid *gd, u_int rupper, u_int rlower) +{ + GRID_DEBUG(gd, "rupper=%u, rlower=%u", rupper, rlower); + + rupper = grid_view_y(gd, rupper); + rlower = grid_view_y(gd, rlower); + + grid_move_lines(gd, rupper + 1, rupper, rlower - rupper); +} + +/* Insert lines. */ +void +grid_view_insert_lines(struct grid *gd, u_int py, u_int ny) +{ + u_int sy; + + GRID_DEBUG(gd, "py=%u, ny=%u", py, ny); + + py = grid_view_y(gd, py); + + sy = grid_view_y(gd, gd->sy); + + grid_move_lines(gd, py + ny, py, sy - py - ny); +} + +/* Insert lines in region. */ +void +grid_view_insert_lines_region( + struct grid *gd, unused u_int rupper, u_int rlower, u_int py, u_int ny) +{ + GRID_DEBUG( + gd, "rupper=%u, rlower=%u, py=%u, ny=%u", rupper, rlower, py, ny); + + rlower = grid_view_y(gd, rlower); + + py = grid_view_y(gd, py); + + grid_move_lines(gd, py + ny, py, (rlower + 1) - py - ny); +} + +/* Delete lines. */ +void +grid_view_delete_lines(struct grid *gd, u_int py, u_int ny) +{ + u_int sy; + + GRID_DEBUG(gd, "py=%u, ny=%u", py, ny); + + py = grid_view_y(gd, py); + + sy = grid_view_y(gd, gd->sy); + + grid_move_lines(gd, py, py + ny, sy - py - ny); +} + +/* Delete lines inside scroll region. */ +void +grid_view_delete_lines_region( + struct grid *gd, unused u_int rupper, u_int rlower, u_int py, u_int ny) +{ + GRID_DEBUG( + gd, "rupper=%u, rlower=%u, py=%u, ny=%u", rupper, rlower, py, ny); + + rlower = grid_view_y(gd, rlower); + + py = grid_view_y(gd, py); + + grid_move_lines(gd, py, py + ny, (rlower + 1) - py - ny); +} + +/* Insert characters. */ +void +grid_view_insert_cells(struct grid *gd, u_int px, u_int py, u_int nx) +{ + u_int sx; + + GRID_DEBUG(gd, "px=%u, py=%u, nx=%u", px, py, nx); + + px = grid_view_x(gd, px); + py = grid_view_y(gd, py); + + sx = grid_view_x(gd, gd->sx); + + if (px == sx - 1) + grid_clear(gd, px, py, 1, 1); + else + grid_move_cells(gd, px + nx, px, py, (sx - 1) - (px + nx)); +} + +/* Delete characters. */ +void +grid_view_delete_cells(struct grid *gd, u_int px, u_int py, u_int nx) +{ + u_int sx; + + GRID_DEBUG(gd, "px=%u, py=%u, nx=%u", px, py, nx); + + px = grid_view_x(gd, px); + py = grid_view_y(gd, py); + + sx = grid_view_x(gd, gd->sx); + + grid_move_cells(gd, px, px + nx, py, (sx - 1) - (px + nx)); +} diff --git a/grid.c b/grid.c new file mode 100644 index 00000000..461d92ea --- /dev/null +++ b/grid.c @@ -0,0 +1,497 @@ +/* $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 "tmux.h" + +/* + * Grid data. This is the basic data structure that represents what is shown on + * screen. + * + * A grid is a grid of cells (struct grid_cell). Lines are not allocated until + * cells in that line are written to. The grid is split into history and + * viewable data with the history starting at row (line) 0 and extending to + * (hsize - 1); from hsize to hsize + (sy - 1) is the viewable data. All + * functions in this file work on absolute coordinates, grid-view.c has + * functions which work on the screen data. + */ + +/* Default grid cell data. */ +const struct grid_cell grid_default_cell = { 0, 0, 8, 8, ' ' }; + +#define grid_put_cell(gd, px, py, gc) do { \ + memcpy(&gd->data[py][px], gc, sizeof gd->data[py][px]); \ +} while (0) +#define grid_put_utf8(gd, px, py, gc) do { \ + memcpy(&gd->udata[py][px], gc, sizeof gd->udata[py][px]); \ +} while (0) + +int grid_check_x(struct grid *, u_int); +int grid_check_y(struct grid *, u_int); + +#ifdef DEBUG +int +grid_check_x(struct grid *gd, u_int px) +{ + if ((px) >= (gd)->sx) + log_fatalx("x out of range: %u", px); + return (0); +} + +int +grid_check_y(struct grid *gd, u_int py) +{ + if ((py) >= (gd)->hsize + (gd)->sy) + log_fatalx("y out of range: %u", py); + return (0); +} +#else +int +grid_check_x(struct grid *gd, u_int px) +{ + if ((px) >= (gd)->sx) { + log_debug("x out of range: %u", px); + return (-1); + } + return (0); +} + +int +grid_check_y(struct grid *gd, u_int py) +{ + if ((py) >= (gd)->hsize + (gd)->sy) { + log_debug("y out of range: %u", py); + return (-1); + } + return (0); +} +#endif + +/* Create a new grid. */ +struct grid * +grid_create(u_int sx, u_int sy, u_int hlimit) +{ + struct grid *gd; + + gd = xmalloc(sizeof *gd); + gd->sx = sx; + gd->sy = sy; + + gd->hsize = 0; + gd->hlimit = hlimit; + + gd->size = xcalloc(gd->sy, sizeof *gd->size); + gd->data = xcalloc(gd->sy, sizeof *gd->data); + + gd->usize = xcalloc(gd->sy, sizeof *gd->usize); + gd->udata = xcalloc(gd->sy, sizeof *gd->udata); + + return (gd); +} + +/* Destroy grid. */ +void +grid_destroy(struct grid *gd) +{ + u_int yy; + + for (yy = 0; yy < gd->hsize + gd->sy; yy++) { + if (gd->udata[yy] != NULL) + xfree(gd->udata[yy]); + if (gd->data[yy] != NULL) + xfree(gd->data[yy]); + } + + if (gd->udata != NULL) + xfree(gd->udata); + if (gd->usize != NULL) + xfree(gd->usize); + + if (gd->data != NULL) + xfree(gd->data); + if (gd->size != NULL) + xfree(gd->size); + + xfree(gd); +} + +/* Compare grids. */ +int +grid_compare(struct grid *ga, struct grid *gb) +{ + struct grid_cell *gca, *gcb; + struct grid_utf8 *gua, *gub; + u_int xx, yy; + + if (ga->sx != gb->sx || ga->sy != ga->sy) + return (1); + + for (yy = 0; yy < ga->sy; yy++) { + if (ga->size[yy] != gb->size[yy]) + return (1); + for (xx = 0; xx < ga->sx; xx++) { + gca = &ga->data[yy][xx]; + gcb = &gb->data[yy][xx]; + if (memcmp(gca, gcb, sizeof (struct grid_cell)) != 0) + return (1); + if (!(gca->flags & GRID_FLAG_UTF8)) + continue; + gua = &ga->udata[yy][xx]; + gub = &gb->udata[yy][xx]; + if (memcmp(gua, gub, sizeof (struct grid_utf8)) != 0) + return (1); + } + } + + return (0); +} + +/* Scroll a line into the history. */ +void +grid_scroll_line(struct grid *gd) +{ + u_int yy; + + GRID_DEBUG(gd, ""); + + if (gd->hsize >= gd->hlimit - 1) { + /* If the limit is hit, free the bottom 10% and shift up. */ + yy = gd->hlimit / 10; + if (yy < 1) + yy = 1; + + grid_move_lines(gd, 0, yy, gd->hsize + gd->sy - yy); + gd->hsize -= yy; + } + + yy = gd->hsize + gd->sy; + + gd->size = xrealloc(gd->size, yy + 1, sizeof *gd->size); + gd->size[yy] = 0; + gd->data = xrealloc(gd->data, yy + 1, sizeof *gd->data); + gd->data[yy] = NULL; + + gd->usize = xrealloc(gd->usize, yy + 1, sizeof *gd->usize); + gd->usize[yy] = 0; + gd->udata = xrealloc(gd->udata, yy + 1, sizeof *gd->udata); + gd->udata[yy] = NULL; + + gd->hsize++; +} + +/* Reduce line to fit to cell. */ +void +grid_reduce_line(struct grid *gd, u_int py, u_int sx) +{ + if (sx < gd->size[py]) { + gd->data[py] = xrealloc(gd->data[py], sx, sizeof **gd->data); + gd->size[py] = sx; + } + if (sx < gd->usize[py]) { + gd->udata[py] = xrealloc(gd->udata[py], sx, sizeof **gd->udata); + gd->usize[py] = sx; + } +} + +/* Expand line to fit to cell. */ +void +grid_expand_line(struct grid *gd, u_int py, u_int sx) +{ + u_int xx; + + if (sx <= gd->size[py]) + return; + + gd->data[py] = xrealloc(gd->data[py], sx, sizeof **gd->data); + for (xx = gd->size[py]; xx < sx; xx++) + grid_put_cell(gd, xx, py, &grid_default_cell); + gd->size[py] = sx; +} + +/* Expand line to fit to cell for UTF-8. */ +void +grid_expand_line_utf8(struct grid *gd, u_int py, u_int sx) +{ + if (sx <= gd->usize[py]) + return; + + gd->udata[py] = xrealloc(gd->udata[py], sx, sizeof **gd->udata); + gd->usize[py] = sx; +} + +/* Get cell for reading. */ +const struct grid_cell * +grid_peek_cell(struct grid *gd, u_int px, u_int py) +{ + if (grid_check_x(gd, px) != 0) + return (&grid_default_cell); + if (grid_check_y(gd, py) != 0) + return (&grid_default_cell); + + if (px >= gd->size[py]) + return (&grid_default_cell); + return (&gd->data[py][px]); +} + +/* Get cell at relative position (for writing). */ +struct grid_cell * +grid_get_cell(struct grid *gd, u_int px, u_int py) +{ + if (grid_check_x(gd, px) != 0) + return (NULL); + if (grid_check_y(gd, py) != 0) + return (NULL); + + grid_expand_line(gd, py, px + 1); + return (&gd->data[py][px]); +} + +/* Set cell at relative position. */ +void +grid_set_cell( + struct grid *gd, u_int px, u_int py, const struct grid_cell *gc) +{ + if (grid_check_x(gd, px) != 0) + return; + if (grid_check_y(gd, py) != 0) + return; + + grid_expand_line(gd, py, px + 1); + grid_put_cell(gd, px, py, gc); +} + +/* Get UTF-8 for reading. */ +const struct grid_utf8 * +grid_peek_utf8(struct grid *gd, u_int px, u_int py) +{ + if (grid_check_x(gd, px) != 0) + return (NULL); + if (grid_check_y(gd, py) != 0) + return (NULL); + + if (px >= gd->usize[py]) + return (NULL); + return (&gd->udata[py][px]); +} + +/* Get utf8 at relative position (for writing). */ +struct grid_utf8 * +grid_get_utf8(struct grid *gd, u_int px, u_int py) +{ + if (grid_check_x(gd, px) != 0) + return (NULL); + if (grid_check_y(gd, py) != 0) + return (NULL); + + grid_expand_line_utf8(gd, py, px + 1); + return (&gd->udata[py][px]); +} + +/* Set utf8 at relative position. */ +void +grid_set_utf8( + struct grid *gd, u_int px, u_int py, const struct grid_utf8 *gc) +{ + if (grid_check_x(gd, px) != 0) + return; + if (grid_check_y(gd, py) != 0) + return; + + grid_expand_line_utf8(gd, py, px + 1); + grid_put_utf8(gd, px, py, gc); +} + +/* + * Clear area. Note this is different from a fill as it just omits unallocated + * cells. + */ +void +grid_clear(struct grid *gd, u_int px, u_int py, u_int nx, u_int ny) +{ + u_int xx, yy; + + GRID_DEBUG(gd, "px=%u, py=%u, nx=%u, ny=%u", px, py, nx, ny); + + if (nx == 0 || ny == 0) + return; + + if (px == 0 && nx == gd->sx) { + grid_clear_lines(gd, py, ny); + return; + } + + if (grid_check_x(gd, px) != 0) + return; + if (grid_check_x(gd, px + nx - 1) != 0) + return; + if (grid_check_y(gd, py) != 0) + return; + if (grid_check_y(gd, py + ny - 1) != 0) + return; + + for (yy = py; yy < py + ny; yy++) { + for (xx = px; xx < px + nx; xx++) { + if (xx >= gd->size[yy]) + break; + grid_put_cell(gd, xx, yy, &grid_default_cell); + } + } +} + +/* Clear lines. This just frees and truncates the lines. */ +void +grid_clear_lines(struct grid *gd, u_int py, u_int ny) +{ + u_int yy; + + GRID_DEBUG(gd, "py=%u, ny=%u", py, ny); + + if (ny == 0) + return; + + if (grid_check_y(gd, py) != 0) + return; + if (grid_check_y(gd, py + ny - 1) != 0) + return; + + for (yy = py; yy < py + ny; yy++) { + if (gd->data[yy] != NULL) { + xfree(gd->data[yy]); + gd->data[yy] = NULL; + gd->size[yy] = 0; + } + if (gd->udata[yy] != NULL) { + xfree(gd->udata[yy]); + gd->udata[yy] = NULL; + gd->usize[yy] = 0; + } + } +} + +/* Move a group of lines. */ +void +grid_move_lines(struct grid *gd, u_int dy, u_int py, u_int ny) +{ + u_int yy; + + GRID_DEBUG(gd, "dy=%u, py=%u, ny=%u", dy, py, ny); + + if (ny == 0 || py == dy) + return; + + if (grid_check_y(gd, py) != 0) + return; + if (grid_check_y(gd, py + ny - 1) != 0) + return; + if (grid_check_y(gd, dy) != 0) + return; + if (grid_check_y(gd, dy + ny - 1) != 0) + return; + + /* Free any lines which are being replaced. */ + for (yy = dy; yy < dy + ny; yy++) { + if (yy >= py && yy < py + ny) + continue; + grid_clear_lines(gd, yy, 1); + } + + memmove(&gd->data[dy], &gd->data[py], ny * (sizeof *gd->data)); + memmove(&gd->size[dy], &gd->size[py], ny * (sizeof *gd->size)); + + memmove(&gd->udata[dy], &gd->udata[py], ny * (sizeof *gd->udata)); + memmove(&gd->usize[dy], &gd->usize[py], ny * (sizeof *gd->usize)); + + /* Wipe any lines that have been moved (without freeing them). */ + for (yy = py; yy < py + ny; yy++) { + if (yy >= dy && yy < dy + ny) + continue; + gd->data[yy] = NULL; + gd->size[yy] = 0; + gd->udata[yy] = NULL; + gd->usize[yy] = 0; + } +} + +/* Clear a group of cells. */ +void +grid_clear_cells(struct grid *gd, u_int px, u_int py, u_int nx) +{ + u_int xx; + + GRID_DEBUG(gd, "px=%u, py=%u, nx=%u", px, py, nx); + + if (nx == 0) + return; + + if (grid_check_x(gd, px) != 0) + return; + if (grid_check_x(gd, px + nx - 1) != 0) + return; + if (grid_check_y(gd, py) != 0) + return; + + for (xx = px; xx < px + nx; xx++) { + if (xx >= gd->size[py]) + break; + grid_put_cell(gd, xx, py, &grid_default_cell); + } +} + +/* Move a group of cells. */ +void +grid_move_cells(struct grid *gd, u_int dx, u_int px, u_int py, u_int nx) +{ + u_int xx; + + GRID_DEBUG(gd, "dx=%u, px=%u, py=%u, nx=%u", dx, px, py, nx); + + if (nx == 0 || px == dx) + return; + + if (grid_check_x(gd, px) != 0) + return; + if (grid_check_x(gd, px + nx - 1) != 0) + return; + if (grid_check_x(gd, dx + nx - 1) != 0) + return; + if (grid_check_y(gd, py) != 0) + return; + + grid_expand_line(gd, py, px + nx); + grid_expand_line(gd, py, dx + nx); + memmove(&gd->data[py][dx], &gd->data[py][px], nx * (sizeof **gd->data)); + + if (gd->udata[py] != NULL) { + grid_expand_line_utf8(gd, py, px + nx); + grid_expand_line_utf8(gd, py, dx + nx); + memmove(&gd->udata[py][dx], + &gd->udata[py][px], nx * (sizeof **gd->udata)); + } + + /* Wipe any cells that have been moved. */ + for (xx = px; xx < px + nx; xx++) { + if (xx >= dx && xx < dx + nx) + continue; + grid_put_cell(gd, xx, py, &grid_default_cell); + } +} + + diff --git a/input-keys.c b/input-keys.c new file mode 100644 index 00000000..24c0bbaa --- /dev/null +++ b/input-keys.c @@ -0,0 +1,227 @@ +/* $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 +#include +#include + +#include "tmux.h" + +struct input_key_ent { + int key; + const char *data; + + int flags; +#define INPUTKEY_KEYPAD 0x1 /* keypad key */ +#define INPUTKEY_CURSOR 0x2 /* cursor key */ +#define INPUTKEY_CTRL 0x4 /* may be modified with ctrl */ +#define INPUTKEY_XTERM 0x4 /* may have xterm argument appended */ +}; + +struct input_key_ent input_keys[] = { + /* Function keys. */ + { KEYC_F1, "\033OP", INPUTKEY_CTRL|INPUTKEY_XTERM }, + { KEYC_F2, "\033OQ", INPUTKEY_CTRL|INPUTKEY_XTERM }, + { KEYC_F3, "\033OR", INPUTKEY_CTRL|INPUTKEY_XTERM }, + { KEYC_F4, "\033OS", INPUTKEY_CTRL|INPUTKEY_XTERM }, + { KEYC_F5, "\033[15~", INPUTKEY_CTRL|INPUTKEY_XTERM }, + { KEYC_F6, "\033[17~", INPUTKEY_CTRL|INPUTKEY_XTERM }, + { KEYC_F7, "\033[18~", INPUTKEY_CTRL|INPUTKEY_XTERM }, + { KEYC_F8, "\033[19~", INPUTKEY_CTRL|INPUTKEY_XTERM }, + { KEYC_F9, "\033[20~", INPUTKEY_CTRL|INPUTKEY_XTERM }, + { KEYC_F10, "\033[21~", INPUTKEY_CTRL|INPUTKEY_XTERM }, + { KEYC_F11, "\033[23~", INPUTKEY_CTRL|INPUTKEY_XTERM }, + { KEYC_F12, "\033[24~", INPUTKEY_CTRL|INPUTKEY_XTERM }, + { KEYC_F13, "\033[25~", INPUTKEY_CTRL|INPUTKEY_XTERM }, + { KEYC_F14, "\033[26~", INPUTKEY_CTRL|INPUTKEY_XTERM }, + { KEYC_F15, "\033[28~", INPUTKEY_CTRL|INPUTKEY_XTERM }, + { KEYC_F16, "\033[29~", INPUTKEY_CTRL|INPUTKEY_XTERM }, + { KEYC_F17, "\033[31~", INPUTKEY_CTRL|INPUTKEY_XTERM }, + { KEYC_F18, "\033[32~", INPUTKEY_CTRL|INPUTKEY_XTERM }, + { KEYC_F19, "\033[33~", INPUTKEY_CTRL|INPUTKEY_XTERM }, + { KEYC_F20, "\033[34~", INPUTKEY_CTRL|INPUTKEY_XTERM }, + { KEYC_IC, "\033[2~", INPUTKEY_CTRL|INPUTKEY_XTERM }, + { KEYC_DC, "\033[3~", INPUTKEY_CTRL|INPUTKEY_XTERM }, + { KEYC_HOME, "\033[1~", INPUTKEY_CTRL|INPUTKEY_XTERM }, + { KEYC_END, "\033[4~", INPUTKEY_CTRL|INPUTKEY_XTERM }, + { KEYC_NPAGE, "\033[6~", INPUTKEY_CTRL|INPUTKEY_XTERM }, + { KEYC_PPAGE, "\033[5~", INPUTKEY_CTRL|INPUTKEY_XTERM }, + { KEYC_BTAB, "\033[Z", INPUTKEY_CTRL }, + + /* Arrow keys. Cursor versions must come first. */ + { KEYC_ADDCTL(KEYC_UP), "\033Oa", 0 }, + { KEYC_ADDCTL(KEYC_DOWN), "\033Ob", 0 }, + { KEYC_ADDCTL(KEYC_RIGHT), "\033Oc", 0 }, + { KEYC_ADDCTL(KEYC_LEFT), "\033Od", 0 }, + + { KEYC_ADDSFT(KEYC_UP), "\033[a", 0 }, + { KEYC_ADDSFT(KEYC_DOWN), "\033[b", 0 }, + { KEYC_ADDSFT(KEYC_RIGHT), "\033[c", 0 }, + { KEYC_ADDSFT(KEYC_LEFT), "\033[d", 0 }, + + { KEYC_UP, "\033OA", INPUTKEY_CURSOR }, + { KEYC_DOWN, "\033OB", INPUTKEY_CURSOR }, + { KEYC_RIGHT, "\033OC", INPUTKEY_CURSOR }, + { KEYC_LEFT, "\033OD", INPUTKEY_CURSOR }, + + { KEYC_UP, "\033[A", 0 }, + { KEYC_DOWN, "\033[B", 0 }, + { KEYC_RIGHT, "\033[C", 0 }, + { KEYC_LEFT, "\033[D", 0 }, + + /* Keypad keys. Keypad versions must come first. */ + { KEYC_KP0_1, "/", INPUTKEY_KEYPAD }, + { KEYC_KP0_2, "*", INPUTKEY_KEYPAD }, + { KEYC_KP0_3, "-", INPUTKEY_KEYPAD }, + { KEYC_KP1_0, "7", INPUTKEY_KEYPAD }, + { KEYC_KP1_1, "8", INPUTKEY_KEYPAD }, + { KEYC_KP1_2, "9", INPUTKEY_KEYPAD }, + { KEYC_KP1_3, "+", INPUTKEY_KEYPAD }, + { KEYC_KP2_0, "4", INPUTKEY_KEYPAD }, + { KEYC_KP2_1, "5", INPUTKEY_KEYPAD }, + { KEYC_KP2_2, "6", INPUTKEY_KEYPAD }, + { KEYC_KP3_0, "1", INPUTKEY_KEYPAD }, + { KEYC_KP3_1, "2", INPUTKEY_KEYPAD }, + { KEYC_KP3_2, "3", INPUTKEY_KEYPAD }, + { KEYC_KP3_3, "\n", INPUTKEY_KEYPAD }, /* this can be CRLF too? */ + { KEYC_KP4_0, "0", INPUTKEY_KEYPAD }, + { KEYC_KP4_2, ".", INPUTKEY_KEYPAD }, + { KEYC_KP0_1, "\033Oo", 0 }, + { KEYC_KP0_2, "\033Oj", 0 }, + { KEYC_KP0_3, "\033Om", 0 }, + { KEYC_KP1_0, "\033Ow", 0 }, + { KEYC_KP1_1, "\033Ox", 0 }, + { KEYC_KP1_2, "\033Oy", 0 }, + { KEYC_KP1_3, "\033Ok", 0 }, + { KEYC_KP2_0, "\033Ot", 0 }, + { KEYC_KP2_1, "\033Ou", 0 }, + { KEYC_KP2_2, "\033Ov", 0 }, + { KEYC_KP3_0, "\033Oq", 0 }, + { KEYC_KP3_1, "\033Or", 0 }, + { KEYC_KP3_2, "\033Os", 0 }, + { KEYC_KP3_3, "\033OM", 0 }, + { KEYC_KP4_0, "\033Op", 0 }, + { KEYC_KP4_2, "\033On", 0 }, +}; + +/* Translate a key code from client into an output key sequence. */ +void +input_key(struct window_pane *wp, int key) +{ + struct input_key_ent *ike; + u_int i; + char ch; + size_t dlen; + int xterm_keys; + + log_debug2("writing key 0x%x", key); + + if (key != KEYC_NONE && KEYC_REMOVEESC(key) < KEYC_OFFSET) { + if (KEYC_ISESC(key)) + buffer_write8(wp->out, '\033'); + buffer_write8(wp->out, (uint8_t) KEYC_REMOVEESC(key)); + return; + } + + for (i = 0; i < nitems(input_keys); i++) { + ike = &input_keys[i]; + + if ((ike->flags & INPUTKEY_KEYPAD) && + !(wp->screen->mode & MODE_KKEYPAD)) + continue; + if ((ike->flags & INPUTKEY_CURSOR) && + !(wp->screen->mode & MODE_KCURSOR)) + continue; + + if (KEYC_ISESC(key) && KEYC_ADDESC(ike->key) == key) + break; + if (KEYC_ISSFT(key) && KEYC_ADDSFT(ike->key) == key) + break; + if (KEYC_ISCTL(key) && KEYC_ADDCTL(ike->key) == key) { + if (ike->flags & INPUTKEY_CTRL) + break; + } + if (ike->key == key) + break; + } + if (i == nitems(input_keys)) { + log_debug2("key 0x%x missing", key); + return; + } + dlen = strlen(ike->data); + + log_debug2("found key 0x%x: \"%s\"", key, ike->data); + + /* + * If in xterm keys mode, work out and append the modifier as an + * argument. + */ + xterm_keys = options_get_number(&wp->window->options, "xterm-keys"); + if (xterm_keys && ike->flags & INPUTKEY_XTERM) { + ch = '\0'; + if (KEYC_ISSFT(key) && KEYC_ISESC(key) && KEYC_ISCTL(key)) + ch = '8'; + else if (KEYC_ISESC(key) && KEYC_ISCTL(key)) + ch = '7'; + else if (KEYC_ISSFT(key) && KEYC_ISCTL(key)) + ch = '6'; + else if (KEYC_ISCTL(key)) + ch = '5'; + else if (KEYC_ISSFT(key) && KEYC_ISESC(key)) + ch = '4'; + else if (KEYC_ISESC(key)) + ch = '3'; + else if (KEYC_ISSFT(key)) + ch = '2'; + if (ch != '\0') { + buffer_write(wp->out, ike->data, dlen - 1); + buffer_write8(wp->out, ';'); + buffer_write8(wp->out, ch); + buffer_write8(wp->out, ike->data[dlen - 1]); + } else + buffer_write(wp->out, ike->data, dlen); + return; + } + + /* + * Not in xterm mode. Prefix a \033 for escape, and set bit 5 of the + * last byte for ctrl. + */ + if (KEYC_ISESC(key)) + buffer_write8(wp->out, '\033'); + if (KEYC_ISCTL(key) && ike->flags & INPUTKEY_CTRL) { + buffer_write(wp->out, ike->data, dlen - 1); + buffer_write8(wp->out, ike->data[dlen - 1] ^ 0x20); + return; + } + buffer_write(wp->out, ike->data, dlen); +} + +/* Handle input mouse. */ +void +input_mouse(struct window_pane *wp, u_char b, u_char x, u_char y) +{ + if (wp->screen->mode & MODE_MOUSE) { + buffer_write(wp->out, "\033[M", 3); + buffer_write8(wp->out, b + 32); + buffer_write8(wp->out, x + 33); + buffer_write8(wp->out, y + 33); + } +} diff --git a/input.c b/input.c new file mode 100644 index 00000000..9483bae1 --- /dev/null +++ b/input.c @@ -0,0 +1,1276 @@ +/* $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 +#include +#include + +#include "tmux.h" + +#define INPUT_C0CONTROL(ch) (ch <= 0x1f) +#define INPUT_INTERMEDIATE(ch) (ch == 0xa0 || (ch >= 0x20 && ch <= 0x2f)) +#define INPUT_PARAMETER(ch) (ch >= 0x30 && ch <= 0x3f) +#define INPUT_UPPERCASE(ch) (ch >= 0x40 && ch <= 0x5f) +#define INPUT_LOWERCASE(ch) (ch >= 0x60 && ch <= 0x7e) +#define INPUT_DELETE(ch) (ch == 0x7f) +#define INPUT_C1CONTROL(ch) (ch >= 0x80 && ch <= 0x9f) +#define INPUT_G1DISPLAYABLE(ch) (ch >= 0xa1 && ch <= 0xfe) +#define INPUT_SPECIAL(ch) (ch == 0xff) + +int input_get_argument(struct input_ctx *, u_int, uint16_t *, uint16_t); +int input_new_argument(struct input_ctx *); +int input_add_argument(struct input_ctx *, u_char); + +void input_start_string(struct input_ctx *, int); +void input_abort_string(struct input_ctx *); +int input_add_string(struct input_ctx *, u_char); +char *input_get_string(struct input_ctx *); + +void input_state(struct input_ctx *, void *); + +void input_state_first(u_char, struct input_ctx *); +void input_state_escape(u_char, struct input_ctx *); +void input_state_intermediate(u_char, struct input_ctx *); +void input_state_sequence_first(u_char, struct input_ctx *); +void input_state_sequence_next(u_char, struct input_ctx *); +void input_state_sequence_intermediate(u_char, struct input_ctx *); +void input_state_string_next(u_char, struct input_ctx *); +void input_state_string_escape(u_char, struct input_ctx *); +void input_state_utf8(u_char, struct input_ctx *); + +void input_handle_character(u_char, struct input_ctx *); +void input_handle_c0_control(u_char, struct input_ctx *); +void input_handle_c1_control(u_char, struct input_ctx *); +void input_handle_private_two(u_char, struct input_ctx *); +void input_handle_standard_two(u_char, struct input_ctx *); +void input_handle_sequence(u_char, struct input_ctx *); + +void input_handle_sequence_cuu(struct input_ctx *); +void input_handle_sequence_cud(struct input_ctx *); +void input_handle_sequence_cuf(struct input_ctx *); +void input_handle_sequence_cub(struct input_ctx *); +void input_handle_sequence_dch(struct input_ctx *); +void input_handle_sequence_dl(struct input_ctx *); +void input_handle_sequence_ich(struct input_ctx *); +void input_handle_sequence_il(struct input_ctx *); +void input_handle_sequence_vpa(struct input_ctx *); +void input_handle_sequence_hpa(struct input_ctx *); +void input_handle_sequence_cup(struct input_ctx *); +void input_handle_sequence_cup(struct input_ctx *); +void input_handle_sequence_ed(struct input_ctx *); +void input_handle_sequence_el(struct input_ctx *); +void input_handle_sequence_sm(struct input_ctx *); +void input_handle_sequence_rm(struct input_ctx *); +void input_handle_sequence_decstbm(struct input_ctx *); +void input_handle_sequence_sgr(struct input_ctx *); +void input_handle_sequence_dsr(struct input_ctx *); + +int input_sequence_cmp(const void *, const void *); + +struct input_sequence_entry { + u_char ch; + void (*fn)(struct input_ctx *); +}; +const struct input_sequence_entry input_sequence_table[] = { + { '@', input_handle_sequence_ich }, + { 'A', input_handle_sequence_cuu }, + { 'B', input_handle_sequence_cud }, + { 'C', input_handle_sequence_cuf }, + { 'D', input_handle_sequence_cub }, + { 'G', input_handle_sequence_hpa }, + { 'H', input_handle_sequence_cup }, + { 'J', input_handle_sequence_ed }, + { 'K', input_handle_sequence_el }, + { 'L', input_handle_sequence_il }, + { 'M', input_handle_sequence_dl }, + { 'P', input_handle_sequence_dch }, + { 'd', input_handle_sequence_vpa }, + { 'f', input_handle_sequence_cup }, + { 'h', input_handle_sequence_sm }, + { 'l', input_handle_sequence_rm }, + { 'm', input_handle_sequence_sgr }, + { 'n', input_handle_sequence_dsr }, + { 'r', input_handle_sequence_decstbm }, +}; + +int +input_sequence_cmp(const void *a, const void *b) +{ + int ai = ((const struct input_sequence_entry *) a)->ch; + int bi = ((const struct input_sequence_entry *) b)->ch; + + return (ai - bi); +} + +int +input_new_argument(struct input_ctx *ictx) +{ + struct input_arg *arg; + + ARRAY_EXPAND(&ictx->args, 1); + + arg = &ARRAY_LAST(&ictx->args); + arg->used = 0; + + return (0); +} + +int +input_add_argument(struct input_ctx *ictx, u_char ch) +{ + struct input_arg *arg; + + if (ARRAY_LENGTH(&ictx->args) == 0) + return (0); + + arg = &ARRAY_LAST(&ictx->args); + if (arg->used > (sizeof arg->data) - 1) + return (-1); + arg->data[arg->used++] = ch; + + return (0); +} + +int +input_get_argument(struct input_ctx *ictx, u_int i, uint16_t *n, uint16_t d) +{ + struct input_arg *arg; + const char *errstr; + + *n = d; + if (i >= ARRAY_LENGTH(&ictx->args)) + return (0); + + arg = &ARRAY_ITEM(&ictx->args, i); + if (*arg->data == '\0') + return (0); + + *n = strtonum(arg->data, 0, UINT16_MAX, &errstr); + if (errstr != NULL) + return (-1); + return (0); +} + +void +input_start_string(struct input_ctx *ictx, int type) +{ + ictx->string_type = type; + ictx->string_len = 0; +} + +void +input_abort_string(struct input_ctx *ictx) +{ + if (ictx->string_buf != NULL) + xfree(ictx->string_buf); + ictx->string_buf = NULL; +} + +int +input_add_string(struct input_ctx *ictx, u_char ch) +{ + ictx->string_buf = xrealloc(ictx->string_buf, 1, ictx->string_len + 1); + ictx->string_buf[ictx->string_len++] = ch; + + if (ictx->string_len >= MAXSTRINGLEN) { + input_abort_string(ictx); + return (1); + } + + return (0); +} + +char * +input_get_string(struct input_ctx *ictx) +{ + char *s; + + if (ictx->string_buf == NULL || input_add_string(ictx, '\0') != 0) + return (xstrdup("")); + + s = ictx->string_buf; + ictx->string_buf = NULL; + return (s); +} + +void +input_state(struct input_ctx *ictx, void *state) +{ + ictx->state = state; +} + +void +input_init(struct window_pane *wp) +{ + struct input_ctx *ictx = &wp->ictx; + + ARRAY_INIT(&ictx->args); + + ictx->string_len = 0; + ictx->string_buf = NULL; + + memcpy(&ictx->cell, &grid_default_cell, sizeof ictx->cell); + + memcpy(&ictx->saved_cell, &grid_default_cell, sizeof ictx->saved_cell); + ictx->saved_cx = 0; + ictx->saved_cy = 0; + + input_state(ictx, input_state_first); +} + +void +input_free(struct window_pane *wp) +{ + if (wp->ictx.string_buf != NULL) + xfree(wp->ictx.string_buf); + + ARRAY_FREE(&wp->ictx.args); +} + +void +input_parse(struct window_pane *wp) +{ + struct input_ctx *ictx = &wp->ictx; + u_char ch; + + if (BUFFER_USED(wp->in) == 0) + return; + + ictx->buf = BUFFER_OUT(wp->in); + ictx->len = BUFFER_USED(wp->in); + ictx->off = 0; + + ictx->wp = wp; + + log_debug2("entry; buffer=%zu", ictx->len); + + if (wp->mode == NULL) + screen_write_start(&ictx->ctx, wp, &wp->base); + else + screen_write_start(&ictx->ctx, NULL, &wp->base); + + if (ictx->off != ictx->len) + wp->window->flags |= WINDOW_ACTIVITY; + while (ictx->off < ictx->len) { + ch = ictx->buf[ictx->off++]; + ictx->state(ch, ictx); + } + + screen_write_stop(&ictx->ctx); + + buffer_remove(wp->in, ictx->len); +} + +void +input_state_first(u_char ch, struct input_ctx *ictx) +{ + ictx->intermediate = '\0'; + + if (INPUT_C0CONTROL(ch)) { + if (ch == 0x1b) + input_state(ictx, input_state_escape); + else + input_handle_c0_control(ch, ictx); + return; + } + +#if 0 + if (INPUT_C1CONTROL(ch)) { + ch -= 0x40; + if (ch == '[') + input_state(ictx, input_state_sequence_first); + else if (ch == ']') { + input_start_string(ictx, STRING_SYSTEM); + input_state(ictx, input_state_string_next); + } else if (ch == '_') { + input_start_string(ictx, STRING_APPLICATION); + input_state(ictx, input_state_string_next); + } else + input_handle_c1_control(ch, ictx); + return; + } +#endif + + if (INPUT_DELETE(ch)) + return; + + input_handle_character(ch, ictx); +} + +void +input_state_escape(u_char ch, struct input_ctx *ictx) +{ + /* Treat C1 control and G1 displayable as 7-bit equivalent. */ + if (INPUT_C1CONTROL(ch) || INPUT_G1DISPLAYABLE(ch)) + ch &= 0x7f; + + if (INPUT_C0CONTROL(ch)) { + input_handle_c0_control(ch, ictx); + return; + } + + if (INPUT_INTERMEDIATE(ch)) { + log_debug2(":: in1 %zu: %hhu (%c)", ictx->off, ch, ch); + ictx->intermediate = ch; + input_state(ictx, input_state_intermediate); + return; + } + + if (INPUT_PARAMETER(ch)) { + input_state(ictx, input_state_first); + input_handle_private_two(ch, ictx); + return; + } + + if (INPUT_UPPERCASE(ch)) { + if (ch == '[') + input_state(ictx, input_state_sequence_first); + else if (ch == ']') { + input_start_string(ictx, STRING_SYSTEM); + input_state(ictx, input_state_string_next); + } else if (ch == '_') { + input_start_string(ictx, STRING_APPLICATION); + input_state(ictx, input_state_string_next); + } else { + input_state(ictx, input_state_first); + input_handle_c1_control(ch, ictx); + } + return; + } + + if (INPUT_LOWERCASE(ch)) { + input_state(ictx, input_state_first); + input_handle_standard_two(ch, ictx); + return; + } + + input_state(ictx, input_state_first); +} + +void +input_state_intermediate(u_char ch, struct input_ctx *ictx) +{ + if (INPUT_INTERMEDIATE(ch)) { + /* Multiple intermediates currently ignored. */ + log_debug2(":: in2 %zu: %hhu (%c)", ictx->off, ch, ch); + return; + } + + if (INPUT_PARAMETER(ch)) { + input_state(ictx, input_state_first); + input_handle_private_two(ch, ictx); + return; + } + + if (INPUT_UPPERCASE(ch) || INPUT_LOWERCASE(ch)) { + input_state(ictx, input_state_first); + input_handle_standard_two(ch, ictx); + return; + } + + input_state(ictx, input_state_first); +} + +void +input_state_sequence_first(u_char ch, struct input_ctx *ictx) +{ + ictx->private = '\0'; + ARRAY_CLEAR(&ictx->args); + + input_state(ictx, input_state_sequence_next); + + if (INPUT_PARAMETER(ch)) { + input_new_argument(ictx); + if (ch >= 0x3c && ch <= 0x3f) { + /* Private control sequence. */ + ictx->private = ch; + return; + } + } + + /* Pass character on directly. */ + input_state_sequence_next(ch, ictx); +} + +void +input_state_sequence_next(u_char ch, struct input_ctx *ictx) +{ + if (INPUT_INTERMEDIATE(ch)) { + if (input_add_argument(ictx, '\0') != 0) + input_state(ictx, input_state_first); + else { + log_debug2(":: si1 %zu: %hhu (%c)", ictx->off, ch, ch); + input_state(ictx, input_state_sequence_intermediate); + } + return; + } + + if (INPUT_PARAMETER(ch)) { + if (ch == ';') { + if (input_add_argument(ictx, '\0') != 0) + input_state(ictx, input_state_first); + else + input_new_argument(ictx); + } else if (input_add_argument(ictx, ch) != 0) + input_state(ictx, input_state_first); + return; + } + + if (INPUT_UPPERCASE(ch) || INPUT_LOWERCASE(ch)) { + if (input_add_argument(ictx, '\0') != 0) + input_state(ictx, input_state_first); + else { + input_state(ictx, input_state_first); + input_handle_sequence(ch, ictx); + } + return; + } + + input_state(ictx, input_state_first); +} + +void +input_state_sequence_intermediate(u_char ch, struct input_ctx *ictx) +{ + if (INPUT_INTERMEDIATE(ch)) { + log_debug2(":: si2 %zu: %hhu (%c)", ictx->off, ch, ch); + return; + } + + if (INPUT_UPPERCASE(ch) || INPUT_LOWERCASE(ch)) { + input_state(ictx, input_state_first); + input_handle_sequence(ch, ictx); + return; + } + + input_state(ictx, input_state_first); +} + +void +input_state_string_next(u_char ch, struct input_ctx *ictx) +{ + if (ch == 0x1b) { + input_state(ictx, input_state_string_escape); + return; + } + if (ch == 0x07) { + input_state_string_escape(ch, ictx); + return; + } + + if (ch >= 0x20 && ch != 0x7f) { + if (input_add_string(ictx, ch) != 0) + input_state(ictx, input_state_first); + return; + } +} + +void +input_state_string_escape(u_char ch, struct input_ctx *ictx) +{ + char *s; + + if (ch == '\007' || ch == '\\') { + input_state(ictx, input_state_first); + switch (ictx->string_type) { + case STRING_SYSTEM: + if (ch != '\007') + return; + s = input_get_string(ictx); + if ((s[0] != '0' && s[0] != '2') || s[1] != ';') { + xfree(s); + return; + } + screen_set_title(ictx->ctx.s, s + 2); + server_status_window(ictx->wp->window); + xfree(s); + break; + case STRING_APPLICATION: + if (ch != '\\') + return; + s = input_get_string(ictx); + screen_set_title(ictx->ctx.s, s); + server_status_window(ictx->wp->window); + xfree(s); + break; + case STRING_NAME: + if (ch != '\\') + return; + xfree(ictx->wp->window->name); + ictx->wp->window->name = input_get_string(ictx); + server_status_window(ictx->wp->window); + break; + } + return; + } + + input_state(ictx, input_state_string_next); + input_state_string_next(ch, ictx); +} + +void +input_state_utf8(u_char ch, struct input_ctx *ictx) +{ + log_debug2("-- un %zu: %hhu (%c)", ictx->off, ch, ch); + + ictx->utf8_buf[ictx->utf8_off++] = ch; + if (--ictx->utf8_len != 0) + return; + input_state(ictx, input_state_first); + + ictx->cell.flags |= GRID_FLAG_UTF8; + screen_write_cell(&ictx->ctx, &ictx->cell, ictx->utf8_buf); + ictx->cell.flags &= ~GRID_FLAG_UTF8; +} + +void +input_handle_character(u_char ch, struct input_ctx *ictx) +{ + struct window_pane *wp = ictx->wp; + + if (ch > 0x7f && options_get_number(&wp->window->options, "utf8")) { + /* + * UTF-8 sequence. + * + * 11000010-11011111 C2-DF start of 2-byte sequence + * 11100000-11101111 E0-EF start of 3-byte sequence + * 11110000-11110100 F0-F4 start of 4-byte sequence + */ + memset(ictx->utf8_buf, 0xff, sizeof ictx->utf8_buf); + ictx->utf8_buf[0] = ch; + ictx->utf8_off = 1; + + if (ch >= 0xc2 && ch <= 0xdf) { + log_debug2("-- u2 %zu: %hhu (%c)", ictx->off, ch, ch); + input_state(ictx, input_state_utf8); + ictx->utf8_len = 1; + return; + } + if (ch >= 0xe0 && ch <= 0xef) { + log_debug2("-- u3 %zu: %hhu (%c)", ictx->off, ch, ch); + input_state(ictx, input_state_utf8); + ictx->utf8_len = 2; + return; + } + if (ch >= 0xf0 && ch <= 0xf4) { + log_debug2("-- u4 %zu: %hhu (%c)", ictx->off, ch, ch); + input_state(ictx, input_state_utf8); + ictx->utf8_len = 3; + return; + } + } + log_debug2("-- ch %zu: %hhu (%c)", ictx->off, ch, ch); + + ictx->cell.data = ch; + screen_write_cell(&ictx->ctx, &ictx->cell, ictx->utf8_buf); +} + +void +input_handle_c0_control(u_char ch, struct input_ctx *ictx) +{ + struct screen *s = ictx->ctx.s; + + log_debug2("-- c0 %zu: %hhu", ictx->off, ch); + + switch (ch) { + case '\0': /* NUL */ + break; + case '\n': /* LF */ + screen_write_linefeed(&ictx->ctx); + break; + case '\r': /* CR */ + screen_write_carriagereturn(&ictx->ctx); + break; + case '\007': /* BELL */ + ictx->wp->window->flags |= WINDOW_BELL; + break; + case '\010': /* BS */ + screen_write_cursorleft(&ictx->ctx, 1); + break; + case '\011': /* TAB */ + s->cx = ((s->cx / 8) * 8) + 8; + if (s->cx > screen_size_x(s) - 1) { + s->cx = 0; + screen_write_cursordown(&ictx->ctx, 1); + } + screen_write_cursormove(&ictx->ctx, s->cx, s->cy); + break; + case '\016': /* SO */ + ictx->cell.attr |= GRID_ATTR_CHARSET; + break; + case '\017': /* SI */ + ictx->cell.attr &= ~GRID_ATTR_CHARSET; + break; + default: + log_debug("unknown c0: %hhu", ch); + break; + } +} + +void +input_handle_c1_control(u_char ch, struct input_ctx *ictx) +{ + log_debug2("-- c1 %zu: %hhu (%c)", ictx->off, ch, ch); + + switch (ch) { + case 'E': /* NEL */ + screen_write_carriagereturn(&ictx->ctx); + screen_write_linefeed(&ictx->ctx); + break; + case 'M': /* RI */ + screen_write_reverseindex(&ictx->ctx); + break; + default: + log_debug("unknown c1: %hhu", ch); + break; + } +} + +void +input_handle_private_two(u_char ch, struct input_ctx *ictx) +{ + struct screen *s = ictx->ctx.s; + + log_debug2( + "-- p2 %zu: %hhu (%c) %hhu", ictx->off, ch, ch, ictx->intermediate); + + switch (ch) { + case '0': /* Dscs (graphics) */ + /* + * Not really supported, but fake it up enough for those that + * use it to switch character sets (by redefining G0 to + * graphics set, rather than switching to G1). + */ + switch (ictx->intermediate) { + case '(': /* G0 */ + ictx->cell.attr |= GRID_ATTR_CHARSET; + break; + } + break; + case '=': /* DECKPAM */ + screen_write_kkeypadmode(&ictx->ctx, 1); + log_debug("kkeypad on (application mode)"); + break; + case '>': /* DECKPNM */ + screen_write_kkeypadmode(&ictx->ctx, 0); + log_debug("kkeypad off (number mode)"); + break; + case '7': /* DECSC */ + memcpy(&ictx->saved_cell, &ictx->cell, sizeof ictx->saved_cell); + ictx->saved_cx = s->cx; + ictx->saved_cy = s->cy; + break; + case '8': /* DECRC */ + memcpy(&ictx->cell, &ictx->saved_cell, sizeof ictx->cell); + screen_write_cursormove( + &ictx->ctx, ictx->saved_cx, ictx->saved_cy); + break; + default: + log_debug("unknown p2: %hhu", ch); + break; + } +} + +void +input_handle_standard_two(u_char ch, struct input_ctx *ictx) +{ + log_debug2( + "-- s2 %zu: %hhu (%c) %hhu", ictx->off, ch, ch, ictx->intermediate); + + switch (ch) { + case 'B': /* Dscs (ASCII) */ + /* + * Not really supported, but fake it up enough for those that + * use it to switch character sets (by redefining G0 to + * graphics set, rather than switching to G1). + */ + switch (ictx->intermediate) { + case '(': /* G0 */ + ictx->cell.attr &= ~GRID_ATTR_CHARSET; + break; + } + break; + case 'c': /* RIS */ + memcpy(&ictx->cell, &grid_default_cell, sizeof ictx->cell); + + memcpy(&ictx->saved_cell, &ictx->cell, sizeof ictx->saved_cell); + ictx->saved_cx = 0; + ictx->saved_cy = 0; + + screen_write_scrollregion( + &ictx->ctx, 0, screen_size_y(ictx->ctx.s) - 1); + + screen_write_insertmode(&ictx->ctx, 0); + screen_write_kcursormode(&ictx->ctx, 0); + screen_write_kkeypadmode(&ictx->ctx, 0); + screen_write_mousemode(&ictx->ctx, 0); + + screen_write_clearscreen(&ictx->ctx); + screen_write_cursormove(&ictx->ctx, 0, 0); + break; + case 'k': + input_start_string(ictx, STRING_NAME); + input_state(ictx, input_state_string_next); + break; + default: + log_debug("unknown s2: %hhu", ch); + break; + } +} + +void +input_handle_sequence(u_char ch, struct input_ctx *ictx) +{ + struct input_sequence_entry *entry, find; + struct screen *s = ictx->ctx.s; + u_int i; + struct input_arg *iarg; + + log_debug2("-- sq %zu: %hhu (%c): %u [sx=%u, sy=%u, cx=%u, cy=%u, " + "ru=%u, rl=%u]", ictx->off, ch, ch, ARRAY_LENGTH(&ictx->args), + screen_size_x(s), screen_size_y(s), s->cx, s->cy, s->rupper, + s->rlower); + for (i = 0; i < ARRAY_LENGTH(&ictx->args); i++) { + iarg = &ARRAY_ITEM(&ictx->args, i); + if (*iarg->data != '\0') + log_debug2(" ++ %u: %s", i, iarg->data); + } + + find.ch = ch; + entry = bsearch(&find, + input_sequence_table, nitems(input_sequence_table), + sizeof input_sequence_table[0], input_sequence_cmp); + if (entry != NULL) + entry->fn(ictx); + else + log_debug("unknown sq: %c (%hhu %hhu)", ch, ch, ictx->private); +} + +void +input_handle_sequence_cuu(struct input_ctx *ictx) +{ + uint16_t n; + + if (ictx->private != '\0') + return; + + if (ARRAY_LENGTH(&ictx->args) > 1) + return; + if (input_get_argument(ictx, 0, &n, 1) != 0) + return; + if (n == 0) + n = 1; + + screen_write_cursorup(&ictx->ctx, n); +} + +void +input_handle_sequence_cud(struct input_ctx *ictx) +{ + uint16_t n; + + if (ictx->private != '\0') + return; + + if (ARRAY_LENGTH(&ictx->args) > 1) + return; + if (input_get_argument(ictx, 0, &n, 1) != 0) + return; + if (n == 0) + n = 1; + + screen_write_cursordown(&ictx->ctx, n); +} + +void +input_handle_sequence_cuf(struct input_ctx *ictx) +{ + uint16_t n; + + if (ictx->private != '\0') + return; + + if (ARRAY_LENGTH(&ictx->args) > 1) + return; + if (input_get_argument(ictx, 0, &n, 1) != 0) + return; + if (n == 0) + n = 1; + + screen_write_cursorright(&ictx->ctx, n); +} + +void +input_handle_sequence_cub(struct input_ctx *ictx) +{ + uint16_t n; + + if (ictx->private != '\0') + return; + + if (ARRAY_LENGTH(&ictx->args) > 1) + return; + if (input_get_argument(ictx, 0, &n, 1) != 0) + return; + if (n == 0) + n = 1; + + screen_write_cursorleft(&ictx->ctx, n); +} + +void +input_handle_sequence_dch(struct input_ctx *ictx) +{ + uint16_t n; + + if (ictx->private != '\0') + return; + + if (ARRAY_LENGTH(&ictx->args) > 1) + return; + if (input_get_argument(ictx, 0, &n, 1) != 0) + return; + if (n == 0) + n = 1; + + screen_write_deletecharacter(&ictx->ctx, n); +} + +void +input_handle_sequence_dl(struct input_ctx *ictx) +{ + uint16_t n; + + if (ictx->private != '\0') + return; + + if (ARRAY_LENGTH(&ictx->args) > 1) + return; + if (input_get_argument(ictx, 0, &n, 1) != 0) + return; + if (n == 0) + n = 1; + + screen_write_deleteline(&ictx->ctx, n); +} + +void +input_handle_sequence_ich(struct input_ctx *ictx) +{ + uint16_t n; + + if (ictx->private != '\0') + return; + + if (ARRAY_LENGTH(&ictx->args) > 1) + return; + if (input_get_argument(ictx, 0, &n, 1) != 0) + return; + if (n == 0) + n = 1; + + screen_write_insertcharacter(&ictx->ctx, n); +} + +void +input_handle_sequence_il(struct input_ctx *ictx) +{ + uint16_t n; + + if (ictx->private != '\0') + return; + + if (ARRAY_LENGTH(&ictx->args) > 1) + return; + if (input_get_argument(ictx, 0, &n, 1) != 0) + return; + if (n == 0) + n = 1; + + screen_write_insertline(&ictx->ctx, n); +} + +void +input_handle_sequence_vpa(struct input_ctx *ictx) +{ + struct screen *s = ictx->ctx.s; + uint16_t n; + + if (ictx->private != '\0') + return; + + if (ARRAY_LENGTH(&ictx->args) > 1) + return; + if (input_get_argument(ictx, 0, &n, 1) != 0) + return; + if (n == 0) + n = 1; + + screen_write_cursormove(&ictx->ctx, s->cx, n - 1); +} + +void +input_handle_sequence_hpa(struct input_ctx *ictx) +{ + struct screen *s = ictx->ctx.s; + uint16_t n; + + if (ictx->private != '\0') + return; + + if (ARRAY_LENGTH(&ictx->args) > 1) + return; + if (input_get_argument(ictx, 0, &n, 1) != 0) + return; + if (n == 0) + n = 1; + + screen_write_cursormove(&ictx->ctx, n - 1, s->cy); +} + +void +input_handle_sequence_cup(struct input_ctx *ictx) +{ + uint16_t n, m; + + if (ictx->private != '\0') + return; + + if (ARRAY_LENGTH(&ictx->args) > 2) + return; + if (input_get_argument(ictx, 0, &n, 1) != 0) + return; + if (input_get_argument(ictx, 1, &m, 1) != 0) + return; + if (n == 0) + n = 1; + if (m == 0) + m = 1; + + screen_write_cursormove(&ictx->ctx, m - 1, n - 1); +} + +void +input_handle_sequence_ed(struct input_ctx *ictx) +{ + uint16_t n; + + if (ictx->private != '\0') + return; + + if (ARRAY_LENGTH(&ictx->args) > 1) + return; + if (input_get_argument(ictx, 0, &n, 0) != 0) + return; + if (n > 2) + return; + + switch (n) { + case 0: + screen_write_clearendofscreen(&ictx->ctx); + break; + case 1: + screen_write_clearstartofscreen(&ictx->ctx); + break; + case 2: + screen_write_clearscreen(&ictx->ctx); + break; + } +} + +void +input_handle_sequence_el(struct input_ctx *ictx) +{ + uint16_t n; + + if (ictx->private != '\0') + return; + + if (ARRAY_LENGTH(&ictx->args) > 1) + return; + if (input_get_argument(ictx, 0, &n, 0) != 0) + return; + if (n > 2) + return; + + switch (n) { + case 0: + screen_write_clearendofline(&ictx->ctx); + break; + case 1: + screen_write_clearstartofline(&ictx->ctx); + break; + case 2: + screen_write_clearline(&ictx->ctx); + break; + } +} + +void +input_handle_sequence_sm(struct input_ctx *ictx) +{ + uint16_t n; + + if (ARRAY_LENGTH(&ictx->args) > 1) + return; + if (input_get_argument(ictx, 0, &n, 0) != 0) + return; + + if (ictx->private == '?') { + switch (n) { + case 1: /* GATM */ + screen_write_kcursormode(&ictx->ctx, 1); + log_debug("kcursor on"); + break; + case 25: /* TCEM */ + screen_write_cursormode(&ictx->ctx, 1); + log_debug("cursor on"); + break; + case 1000: + screen_write_mousemode(&ictx->ctx, 1); + log_debug("mouse on"); + break; + default: + log_debug("unknown SM [%hhu]: %u", ictx->private, n); + break; + } + } else { + switch (n) { + case 4: /* IRM */ + screen_write_insertmode(&ictx->ctx, 1); + log_debug("insert on"); + break; + case 34: + /* Cursor high visibility not supported. */ + break; + default: + log_debug("unknown SM [%hhu]: %u", ictx->private, n); + break; + } + } +} + +void +input_handle_sequence_rm(struct input_ctx *ictx) +{ + uint16_t n; + + if (ARRAY_LENGTH(&ictx->args) > 1) + return; + if (input_get_argument(ictx, 0, &n, 0) != 0) + return; + + if (ictx->private == '?') { + switch (n) { + case 1: /* GATM */ + screen_write_kcursormode(&ictx->ctx, 0); + log_debug("kcursor off"); + break; + case 25: /* TCEM */ + screen_write_cursormode(&ictx->ctx, 0); + log_debug("cursor off"); + break; + case 1000: + screen_write_mousemode(&ictx->ctx, 0); + log_debug("mouse off"); + break; + default: + log_debug("unknown RM [%hhu]: %u", ictx->private, n); + break; + } + } else if (ictx->private == '\0') { + switch (n) { + case 4: /* IRM */ + screen_write_insertmode(&ictx->ctx, 0); + log_debug("insert off"); + break; + case 34: + /* Cursor high visibility not supported. */ + break; + default: + log_debug("unknown RM [%hhu]: %u", ictx->private, n); + break; + } + } +} + +void +input_handle_sequence_dsr(struct input_ctx *ictx) +{ + struct screen *s = ictx->ctx.s; + uint16_t n; + char reply[32]; + + if (ARRAY_LENGTH(&ictx->args) > 1) + return; + if (input_get_argument(ictx, 0, &n, 0) != 0) + return; + + if (ictx->private == '\0') { + switch (n) { + case 6: /* cursor position */ + xsnprintf(reply, sizeof reply, + "\033[%u;%uR", s->cy + 1, s->cx + 1); + log_debug("cursor request, reply: %s", reply); + buffer_write(ictx->wp->out, reply, strlen(reply)); + break; + } + } + +} + +void +input_handle_sequence_decstbm(struct input_ctx *ictx) +{ + struct screen *s = ictx->ctx.s; + uint16_t n, m; + + if (ictx->private != '\0') + return; + + if (ARRAY_LENGTH(&ictx->args) > 2) + return; + if (input_get_argument(ictx, 0, &n, 0) != 0) + return; + if (input_get_argument(ictx, 1, &m, 0) != 0) + return; + if (n == 0) + n = 1; + if (m == 0) + m = screen_size_y(s); + + screen_write_scrollregion(&ictx->ctx, n - 1, m - 1); +} + +void +input_handle_sequence_sgr(struct input_ctx *ictx) +{ + struct grid_cell *gc = &ictx->cell; + u_int i; + uint16_t m, o; + u_char attr; + + if (ARRAY_LENGTH(&ictx->args) == 0) { + attr = gc->attr; + memcpy(gc, &grid_default_cell, sizeof *gc); + gc->attr |= (attr & GRID_ATTR_CHARSET); + return; + } + + for (i = 0; i < ARRAY_LENGTH(&ictx->args); i++) { + if (input_get_argument(ictx, i, &m, 0) != 0) + return; + + if (m == 38 || m == 48) { + i++; + if (input_get_argument(ictx, i, &o, 0) != 0) + return; + if (o != 5) + continue; + + i++; + if (input_get_argument(ictx, i, &o, 0) != 0) + return; + if (m == 38) { + gc->flags |= GRID_FLAG_FG256; + gc->fg = o; + } else if (m == 48) { + gc->flags |= GRID_FLAG_BG256; + gc->bg = o; + } + continue; + } + + switch (m) { + case 0: + case 10: + attr = gc->attr; + memcpy(gc, &grid_default_cell, sizeof *gc); + gc->attr |= (attr & GRID_ATTR_CHARSET); + break; + case 1: + gc->attr |= GRID_ATTR_BRIGHT; + break; + case 2: + gc->attr |= GRID_ATTR_DIM; + break; + case 3: + gc->attr |= GRID_ATTR_ITALICS; + break; + case 4: + gc->attr |= GRID_ATTR_UNDERSCORE; + break; + case 5: + gc->attr |= GRID_ATTR_BLINK; + break; + case 7: + gc->attr |= GRID_ATTR_REVERSE; + break; + case 8: + gc->attr |= GRID_ATTR_HIDDEN; + break; + case 22: + gc->attr &= ~(GRID_ATTR_BRIGHT|GRID_ATTR_DIM); + break; + case 23: + gc->attr &= ~GRID_ATTR_ITALICS; + break; + case 24: + gc->attr &= ~GRID_ATTR_UNDERSCORE; + break; + case 25: + gc->attr &= ~GRID_ATTR_BLINK; + break; + case 27: + gc->attr &= ~GRID_ATTR_REVERSE; + break; + case 30: + case 31: + case 32: + case 33: + case 34: + case 35: + case 36: + case 37: + gc->flags &= ~GRID_FLAG_FG256; + gc->fg = m - 30; + break; + case 39: + gc->flags &= ~GRID_FLAG_FG256; + gc->fg = 8; + break; + case 40: + case 41: + case 42: + case 43: + case 44: + case 45: + case 46: + case 47: + gc->flags &= ~GRID_FLAG_BG256; + gc->bg = m - 40; + break; + case 49: + gc->flags &= ~GRID_FLAG_BG256; + gc->bg = 8; + break; + } + } +} diff --git a/key-bindings.c b/key-bindings.c new file mode 100644 index 00000000..fc232928 --- /dev/null +++ b/key-bindings.c @@ -0,0 +1,237 @@ +/* $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 +#include +#include + +#include "tmux.h" + +SPLAY_GENERATE(key_bindings, key_binding, entry, key_bindings_cmp); + +struct key_bindings key_bindings; + +int +key_bindings_cmp(struct key_binding *bd1, struct key_binding *bd2) +{ + return (bd1->key - bd2->key); +} + +struct key_binding * +key_bindings_lookup(int key) +{ + struct key_binding bd; + + bd.key = key; + return (SPLAY_FIND(key_bindings, &key_bindings, &bd)); +} + +void +key_bindings_add(int key, int can_repeat, struct cmd_list *cmdlist) +{ + struct key_binding *bd; + + if ((bd = key_bindings_lookup(key)) == NULL) { + bd = xmalloc(sizeof *bd); + bd->key = key; + SPLAY_INSERT(key_bindings, &key_bindings, bd); + } else + cmd_list_free(bd->cmdlist); + bd->can_repeat = can_repeat; + bd->cmdlist = cmdlist; +} + +void +key_bindings_remove(int key) +{ + struct key_binding *bd; + + if ((bd = key_bindings_lookup(key)) == NULL) + return; + SPLAY_REMOVE(key_bindings, &key_bindings, bd); + + cmd_list_free(bd->cmdlist); + xfree(bd); +} + +void +key_bindings_init(void) +{ + static const struct { + int key; + int can_repeat; + const struct cmd_entry *entry; + } table[] = { + { ' ', 0, &cmd_next_layout_entry }, + { '!', 0, &cmd_break_pane_entry }, + { '"', 0, &cmd_split_window_entry }, + { '#', 0, &cmd_list_buffers_entry }, + { '&', 0, &cmd_confirm_before_entry }, + { ',', 0, &cmd_command_prompt_entry }, + { '-', 0, &cmd_delete_buffer_entry }, + { '.', 0, &cmd_command_prompt_entry }, + { '0', 0, &cmd_select_window_entry }, + { '1', 0, &cmd_select_window_entry }, + { '2', 0, &cmd_select_window_entry }, + { '3', 0, &cmd_select_window_entry }, + { '4', 0, &cmd_select_window_entry }, + { '5', 0, &cmd_select_window_entry }, + { '6', 0, &cmd_select_window_entry }, + { '7', 0, &cmd_select_window_entry }, + { '8', 0, &cmd_select_window_entry }, + { '9', 0, &cmd_select_window_entry }, + { ':', 0, &cmd_command_prompt_entry }, + { '=', 0, &cmd_scroll_mode_entry }, + { '?', 0, &cmd_list_keys_entry }, + { '[', 0, &cmd_copy_mode_entry }, + { '\'', 0, &cmd_select_prompt_entry }, + { '\032', /* C-z */ 0, &cmd_suspend_client_entry }, + { ']', 0, &cmd_paste_buffer_entry }, + { 'c', 0, &cmd_new_window_entry }, + { 'd', 0, &cmd_detach_client_entry }, + { 'f', 0, &cmd_command_prompt_entry }, + { 'l', 0, &cmd_last_window_entry }, + { 'n', 0, &cmd_next_window_entry }, + { 'o', 0, &cmd_down_pane_entry }, + { 'p', 0, &cmd_previous_window_entry }, + { 'r', 0, &cmd_refresh_client_entry }, + { 's', 0, &cmd_choose_session_entry }, + { 't', 0, &cmd_clock_mode_entry }, + { 'w', 0, &cmd_choose_window_entry }, + { 'x', 0, &cmd_confirm_before_entry }, + { '{', 0, &cmd_swap_pane_entry }, + { '}', 0, &cmd_swap_pane_entry }, + { '\002', 0, &cmd_send_prefix_entry }, + { KEYC_ADDESC('0'), 0, &cmd_select_layout_entry }, + { KEYC_ADDESC('1'), 0, &cmd_select_layout_entry }, + { KEYC_ADDESC('2'), 0, &cmd_select_layout_entry }, + { KEYC_ADDESC('9'), 0, &cmd_select_layout_entry }, + { KEYC_ADDCTL(KEYC_DOWN), 1, &cmd_resize_pane_entry }, + { KEYC_PPAGE, 0, &cmd_scroll_mode_entry }, + { KEYC_ADDESC('n'), 0, &cmd_next_window_entry }, + { KEYC_ADDESC('p'), 0, &cmd_previous_window_entry }, + { KEYC_UP, 1, &cmd_up_pane_entry }, + { KEYC_DOWN, 1, &cmd_down_pane_entry }, + { KEYC_ADDESC(KEYC_UP), 1, &cmd_resize_pane_entry }, + { KEYC_ADDESC(KEYC_DOWN), 1, &cmd_resize_pane_entry }, + { KEYC_ADDCTL(KEYC_UP), 1, &cmd_resize_pane_entry }, + { KEYC_ADDCTL(KEYC_DOWN), 1, &cmd_resize_pane_entry }, + { KEYC_ADDESC('o'), 0, &cmd_rotate_window_entry }, + { '\017', 0, &cmd_rotate_window_entry }, + }; + u_int i; + struct cmd *cmd; + struct cmd_list *cmdlist; + + SPLAY_INIT(&key_bindings); + + for (i = 0; i < nitems(table); i++) { + cmdlist = xmalloc(sizeof *cmdlist); + TAILQ_INIT(cmdlist); + + cmd = xmalloc(sizeof *cmd); + cmd->entry = table[i].entry; + cmd->data = NULL; + if (cmd->entry->init != NULL) + cmd->entry->init(cmd, table[i].key); + TAILQ_INSERT_HEAD(cmdlist, cmd, qentry); + + key_bindings_add(table[i].key, table[i].can_repeat, cmdlist); + } +} + +void +key_bindings_free(void) +{ + struct key_binding *bd; + + while (!SPLAY_EMPTY(&key_bindings)) { + bd = SPLAY_ROOT(&key_bindings); + SPLAY_REMOVE(key_bindings, &key_bindings, bd); + cmd_list_free(bd->cmdlist); + xfree(bd); + } +} + +void printflike2 +key_bindings_error(struct cmd_ctx *ctx, const char *fmt, ...) +{ + va_list ap; + char *msg; + + va_start(ap, fmt); + xvasprintf(&msg, fmt, ap); + va_end(ap); + + *msg = toupper((u_char) *msg); + status_message_set(ctx->curclient, msg); + xfree(msg); +} + +void printflike2 +key_bindings_print(struct cmd_ctx *ctx, const char *fmt, ...) +{ + struct winlink *wl = ctx->cursession->curw; + va_list ap; + + if (wl->window->active->mode != &window_more_mode) + window_pane_reset_mode(wl->window->active); + window_pane_set_mode(wl->window->active, &window_more_mode); + + va_start(ap, fmt); + window_more_vadd(wl->window->active, fmt, ap); + va_end(ap); +} + +void printflike2 +key_bindings_info(struct cmd_ctx *ctx, const char *fmt, ...) +{ + va_list ap; + char *msg; + + if (be_quiet) + return; + + va_start(ap, fmt); + xvasprintf(&msg, fmt, ap); + va_end(ap); + + *msg = toupper((u_char) *msg); + status_message_set(ctx->curclient, msg); + xfree(msg); +} + +void +key_bindings_dispatch(struct key_binding *bd, struct client *c) +{ + struct cmd_ctx ctx; + + ctx.msgdata = NULL; + ctx.cursession = c->session; + ctx.curclient = c; + + ctx.error = key_bindings_error; + ctx.print = key_bindings_print; + ctx.info = key_bindings_info; + + ctx.cmdclient = NULL; + + cmd_list_exec(bd->cmdlist, &ctx); +} diff --git a/key-string.c b/key-string.c new file mode 100644 index 00000000..b2f1fad2 --- /dev/null +++ b/key-string.c @@ -0,0 +1,198 @@ +/* $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 + +#include "tmux.h" + +int key_string_search_table(const char *); + +struct { + const char *string; + int key; +} key_string_table[] = { + /* Function keys. */ + { "F1", KEYC_F1 }, + { "F2", KEYC_F2 }, + { "F3", KEYC_F3 }, + { "F4", KEYC_F4 }, + { "F5", KEYC_F5 }, + { "F6", KEYC_F6 }, + { "F7", KEYC_F7 }, + { "F8", KEYC_F8 }, + { "F9", KEYC_F9 }, + { "F10", KEYC_F10 }, + { "F11", KEYC_F11 }, + { "F12", KEYC_F12 }, + { "F13", KEYC_F13 }, + { "F14", KEYC_F14 }, + { "F15", KEYC_F15 }, + { "F16", KEYC_F16 }, + { "F17", KEYC_F17 }, + { "F18", KEYC_F18 }, + { "F19", KEYC_F19 }, + { "F20", KEYC_F20 }, + { "IC", KEYC_IC }, + { "DC", KEYC_DC }, + { "Home", KEYC_HOME }, + { "End", KEYC_END }, + { "NPage", KEYC_NPAGE }, + { "PPage", KEYC_PPAGE }, + { "Tab", '\011' }, + { "BTab", KEYC_BTAB }, + + /* Arrow keys. */ + { "Up", KEYC_UP }, + { "Down", KEYC_DOWN }, + { "Left", KEYC_LEFT }, + { "Right", KEYC_RIGHT }, + + /* Numeric keypad. */ + { "KP/", KEYC_KP0_1 }, + { "KP*", KEYC_KP0_2 }, + { "KP-", KEYC_KP0_3 }, + { "KP7", KEYC_KP1_0 }, + { "KP8", KEYC_KP1_1 }, + { "KP9", KEYC_KP1_2 }, + { "KP+", KEYC_KP1_3 }, + { "KP4", KEYC_KP2_0 }, + { "KP5", KEYC_KP2_1 }, + { "KP6", KEYC_KP2_2 }, + { "KP1", KEYC_KP3_0 }, + { "KP2", KEYC_KP3_1 }, + { "KP3", KEYC_KP3_2 }, + { "KPEnter", KEYC_KP3_3 }, + { "KP0", KEYC_KP4_0 }, + { "KP.", KEYC_KP4_2 }, +}; + +int +key_string_search_table(const char *string) +{ + u_int i; + + for (i = 0; i < nitems(key_string_table); i++) { + if (strcasecmp(string, key_string_table[i].string) == 0) + return (key_string_table[i].key); + } + return (KEYC_NONE); +} + +int +key_string_lookup_string(const char *string) +{ + int key; + const u_char *ptr; + + if (string[0] == '\0') + return (KEYC_NONE); + if (string[1] == '\0') + return (string[0]); + + ptr = NULL; + if (string[0] == 'C' && string[1] == '-') + ptr = string + 2; + else if (string[0] == '^') + ptr = string + 1; + if (ptr != NULL) { + if (ptr[0] == '\0') + return (KEYC_NONE); + if (ptr[1] == '\0') { + if (ptr[0] == 32) + return (0); + if (ptr[0] >= 64 && ptr[0] <= 95) + return (ptr[0] - 64); + if (ptr[0] >= 97 && ptr[0] <= 122) + return (ptr[0] - 96); + return (KEYC_NONE); + } + key = key_string_search_table(ptr); + if (key != KEYC_NONE) + return (KEYC_ADDCTL(key)); + return (KEYC_NONE); + } + + if (string[0] == 'M' && string[1] == '-') { + ptr = string + 2; + if (ptr[0] == '\0') + return (KEYC_NONE); + if (ptr[1] == '\0') { + if (ptr[0] < 32 || ptr[0] > 127) + return (KEYC_NONE); + return (KEYC_ADDESC(ptr[0])); + } + key = key_string_lookup_string(ptr); + if (key != KEYC_NONE) + return (KEYC_ADDESC(key)); + return (KEYC_NONE); + } + + return (key_string_search_table(string)); +} + +const char * +key_string_lookup_key(int key) +{ + static char tmp[24], tmp2[24]; + const char *s; + u_int i; + + if (key == 127) + return (NULL); + + if (KEYC_ISESC(key)) { + if ((s = key_string_lookup_key(KEYC_REMOVEESC(key))) == NULL) + return (NULL); + xsnprintf(tmp2, sizeof tmp2, "M-%s", s); + return (tmp2); + } + if (KEYC_ISCTL(key)) { + if ((s = key_string_lookup_key(KEYC_REMOVECTL(key))) == NULL) + return (NULL); + xsnprintf(tmp2, sizeof tmp2, "C-%s", s); + return (tmp2); + } + if (KEYC_ISSFT(key)) { + if ((s = key_string_lookup_key(KEYC_REMOVESFT(key))) == NULL) + return (NULL); + xsnprintf(tmp2, sizeof tmp2, "S-%s", s); + return (tmp2); + } + + if (key >= 32 && key <= 255) { + tmp[0] = key; + tmp[1] = '\0'; + return (tmp); + } + + if (key >= 0 && key <= 32) { + if (key == 0 || key > 26) + xsnprintf(tmp, sizeof tmp, "C-%c", 64 + key); + else + xsnprintf(tmp, sizeof tmp, "C-%c", 96 + key); + return (tmp); + } + + for (i = 0; i < nitems(key_string_table); i++) { + if (key == key_string_table[i].key) + return (key_string_table[i].string); + } + return (NULL); +} diff --git a/layout-manual.c b/layout-manual.c new file mode 100644 index 00000000..eee21d41 --- /dev/null +++ b/layout-manual.c @@ -0,0 +1,183 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2009 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" + +void layout_manual_v_update_offsets(struct window *); + +void +layout_manual_v_refresh(struct window *w, unused int active_only) +{ + struct window_pane *wp; + u_int npanes, canfit, total; + int left; + + if (active_only) + return; + + if (TAILQ_EMPTY(&w->panes)) + return; + + /* Clear hidden flags. */ + TAILQ_FOREACH(wp, &w->panes, entry) + wp->flags &= ~PANE_HIDDEN; + + /* Check the new size. */ + npanes = window_count_panes(w); + if (w->sy <= PANE_MINIMUM * npanes) { + /* How many can we fit? */ + canfit = w->sy / PANE_MINIMUM; + if (canfit == 0) { + /* None. Just use this size for the first. */ + TAILQ_FOREACH(wp, &w->panes, entry) { + if (wp == TAILQ_FIRST(&w->panes)) + wp->sy = w->sy; + else + wp->flags |= PANE_HIDDEN; + } + } else { + /* >=1, set minimum for them all. */ + TAILQ_FOREACH(wp, &w->panes, entry) { + if (canfit-- > 0) + wp->sy = PANE_MINIMUM - 1; + else + wp->flags |= PANE_HIDDEN; + } + /* And increase the first by the rest. */ + TAILQ_FIRST(&w->panes)->sy += 1 + w->sy % PANE_MINIMUM; + } + } else { + /* In theory they will all fit. Find the current total. */ + total = 0; + TAILQ_FOREACH(wp, &w->panes, entry) + total += wp->sy; + total += npanes - 1; + + /* Growing or shrinking? */ + left = w->sy - total; + if (left > 0) { + /* Growing. Expand evenly. */ + while (left > 0) { + TAILQ_FOREACH(wp, &w->panes, entry) { + wp->sy++; + if (--left == 0) + break; + } + } + } else { + /* Shrinking. Reduce evenly down to minimum. */ + while (left < 0) { + TAILQ_FOREACH(wp, &w->panes, entry) { + if (wp->sy <= PANE_MINIMUM - 1) + continue; + wp->sy--; + if (++left == 0) + break; + } + } + } + } + + /* Now do the resize. */ + TAILQ_FOREACH(wp, &w->panes, entry) { + wp->sy--; + window_pane_resize(wp, w->sx, wp->sy + 1); + } + + /* Fill in the offsets. */ + layout_manual_v_update_offsets(w); + + /* Switch the active window if necessary. */ + window_set_active_pane(w, w->active); +} + +void +layout_manual_v_resize(struct window_pane *wp, int adjust) +{ + struct window *w = wp->window; + struct window_pane *wq; + + if (adjust > 0) { + /* + * If this is not the last pane, keep trying to increase size + * and remove it from the next panes. If it is the last, do + * so on the previous pane. + */ + if (TAILQ_NEXT(wp, entry) == NULL) { + if (wp == TAILQ_FIRST(&w->panes)) { + /* Only one pane. */ + return; + } + wp = TAILQ_PREV(wp, window_panes, entry); + } + while (adjust-- > 0) { + wq = wp; + while ((wq = TAILQ_NEXT(wq, entry)) != NULL) { + if (wq->sy <= PANE_MINIMUM) + continue; + window_pane_resize(wq, wq->sx, wq->sy - 1); + break; + } + if (wq == NULL) + break; + window_pane_resize(wp, wp->sx, wp->sy + 1); + } + } else { + adjust = -adjust; + /* + * If this is not the last pane, keep trying to reduce size + * and add to the following pane. If it is the last, do so on + * the previous pane. + */ + wq = TAILQ_NEXT(wp, entry); + if (wq == NULL) { + if (wp == TAILQ_FIRST(&w->panes)) { + /* Only one pane. */ + return; + } + wq = wp; + wp = TAILQ_PREV(wq, window_panes, entry); + } + while (adjust-- > 0) { + if (wp->sy <= PANE_MINIMUM) + break; + window_pane_resize(wq, wq->sx, wq->sy + 1); + window_pane_resize(wp, wp->sx, wp->sy - 1); + } + } + + layout_manual_v_update_offsets(w); +} + +void +layout_manual_v_update_offsets(struct window *w) +{ + struct window_pane *wp; + u_int yoff; + + yoff = 0; + TAILQ_FOREACH(wp, &w->panes, entry) { + if (wp->flags & PANE_HIDDEN) + continue; + wp->xoff = 0; + wp->yoff = yoff; + yoff += wp->sy + 1; + } +} diff --git a/layout.c b/layout.c new file mode 100644 index 00000000..1ae946e5 --- /dev/null +++ b/layout.c @@ -0,0 +1,373 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2009 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 "tmux.h" + +/* + * Each layout has two functions, _refresh to relayout the panes and _resize to + * resize a single pane. + * + * Second argument (int) to _refresh is 1 if the only change has been that the + * active pane has changed. If 0 then panes, active pane or both may have + * changed. + */ + +void layout_active_only_refresh(struct window *, int); +void layout_even_h_refresh(struct window *, int); +void layout_even_v_refresh(struct window *, int); +void layout_main_h_refresh(struct window *, int); +void layout_main_v_refresh(struct window *, int); + +const struct { + const char *name; + void (*refresh)(struct window *, int); + void (*resize)(struct window_pane *, int); +} layouts[] = { + { "manual-vertical", layout_manual_v_refresh, layout_manual_v_resize }, + { "active-only", layout_active_only_refresh, NULL }, + { "even-horizontal", layout_even_h_refresh, NULL }, + { "even-vertical", layout_even_v_refresh, NULL }, + { "main-horizontal", layout_main_h_refresh, NULL }, + { "main-vertical", layout_main_v_refresh, NULL }, +}; + +const char * +layout_name(struct window *w) +{ + return (layouts[w->layout].name); +} + +int +layout_lookup(const char *name) +{ + u_int i; + int matched = -1; + + for (i = 0; i < nitems(layouts); i++) { + if (strncmp(layouts[i].name, name, strlen(name)) == 0) { + if (matched != -1) /* ambiguous */ + return (-1); + matched = i; + } + } + + return (matched); +} + +int +layout_select(struct window *w, u_int layout) +{ + if (layout > nitems(layouts) - 1 || layout == w->layout) + return (-1); + w->layout = layout; + + layout_refresh(w, 0); + return (0); +} + +void +layout_next(struct window *w) +{ + w->layout++; + if (w->layout > nitems(layouts) - 1) + w->layout = 0; + layout_refresh(w, 0); +} + +void +layout_previous(struct window *w) +{ + if (w->layout == 0) + w->layout = nitems(layouts) - 1; + else + w->layout--; + layout_refresh(w, 0); +} + +void +layout_refresh(struct window *w, int active_only) +{ + layouts[w->layout].refresh(w, active_only); + server_redraw_window(w); +} + +int +layout_resize(struct window_pane *wp, int adjust) +{ + struct window *w = wp->window; + + if (layouts[w->layout].resize == NULL) + return (-1); + layouts[w->layout].resize(wp, adjust); + return (0); +} + +void +layout_active_only_refresh(struct window *w, unused int active_only) +{ + struct window_pane *wp; + + TAILQ_FOREACH(wp, &w->panes, entry) { + if (wp == w->active) { + wp->flags &= ~PANE_HIDDEN; + wp->xoff = wp->yoff = 0; + window_pane_resize(wp, w->sx, w->sy); + } else + wp->flags |= PANE_HIDDEN; + } +} + +void +layout_even_h_refresh(struct window *w, int active_only) +{ + struct window_pane *wp; + u_int i, n, width, xoff; + + if (active_only) + return; + + /* Get number of panes. */ + n = window_count_panes(w); + if (n == 0) + return; + + /* How many can we fit? */ + if (w->sx / n < PANE_MINIMUM) { + width = PANE_MINIMUM; + n = w->sx / PANE_MINIMUM; + } else + width = w->sx / n; + + /* Fit the panes. */ + i = xoff = 0; + TAILQ_FOREACH(wp, &w->panes, entry) { + if (i > n) { + wp->flags |= PANE_HIDDEN; + continue; + } + wp->flags &= ~PANE_HIDDEN; + + wp->xoff = xoff; + wp->yoff = 0; + if (i != n - 1) + window_pane_resize(wp, width - 1, w->sy); + else + window_pane_resize(wp, width, w->sy); + + i++; + xoff += width; + } + + /* Any space left? */ + while (xoff++ < w->sx) { + wp = TAILQ_LAST(&w->panes, window_panes); + window_pane_resize(wp, wp->sx + 1, wp->sy); + } +} + +void +layout_even_v_refresh(struct window *w, int active_only) +{ + struct window_pane *wp; + u_int i, n, height, yoff; + + if (active_only) + return; + + /* Get number of panes. */ + n = window_count_panes(w); + if (n == 0) + return; + + /* How many can we fit? */ + if (w->sy / n < PANE_MINIMUM) { + height = PANE_MINIMUM; + n = w->sy / PANE_MINIMUM; + } else + height = w->sy / n; + + /* Fit the panes. */ + i = yoff = 0; + TAILQ_FOREACH(wp, &w->panes, entry) { + if (i > n) { + wp->flags |= PANE_HIDDEN; + continue; + } + wp->flags &= ~PANE_HIDDEN; + + wp->xoff = 0; + wp->yoff = yoff; + if (i != n - 1) + window_pane_resize(wp, w->sx, height - 1); + else + window_pane_resize(wp, w->sx, height); + + i++; + yoff += height; + } + + /* Any space left? */ + while (yoff++ < w->sy) { + wp = TAILQ_LAST(&w->panes, window_panes); + window_pane_resize(wp, wp->sx, wp->sy + 1); + } +} + +void +layout_main_v_refresh(struct window *w, int active_only) +{ + struct window_pane *wp; + u_int i, n, mainwidth, height, yoff; + + if (active_only) + return; + + /* Get number of panes. */ + n = window_count_panes(w); + if (n == 0) + return; + + /* Get the main pane width and add one for separator line. */ + mainwidth = options_get_number(&w->options, "main-pane-width") + 1; + + /* Need >1 pane and minimum columns; if fewer, display active only. */ + if (n == 1 || w->sx < mainwidth + PANE_MINIMUM) { + layout_active_only_refresh(w, active_only); + return; + } + n--; + + /* How many can we fit, not including first? */ + if (w->sy / n < PANE_MINIMUM) { + height = PANE_MINIMUM; + n = w->sy / PANE_MINIMUM; + } else + height = w->sy / n; + + /* Fit the panes. */ + i = yoff = 0; + TAILQ_FOREACH(wp, &w->panes, entry) { + if (wp == TAILQ_FIRST(&w->panes)) { + wp->xoff = 0; + wp->yoff = 0; + window_pane_resize(wp, mainwidth - 1, w->sy); + wp->flags &= ~PANE_HIDDEN; + continue; + } + + if (i > n) { + wp->flags |= PANE_HIDDEN; + continue; + } + wp->flags &= ~PANE_HIDDEN; + + wp->xoff = mainwidth; + wp->yoff = yoff; + if (i != n - 1) + window_pane_resize(wp, w->sx - mainwidth, height - 1); + else + window_pane_resize(wp, w->sx - mainwidth, height); + + i++; + yoff += height; + } + + /* Any space left? */ + while (yoff++ < w->sy) { + wp = TAILQ_LAST(&w->panes, window_panes); + while (wp != NULL && wp == TAILQ_FIRST(&w->panes)) + wp = TAILQ_PREV(wp, window_panes, entry); + if (wp == NULL) + break; + window_pane_resize(wp, wp->sx, wp->sy + 1); + } +} + +void +layout_main_h_refresh(struct window *w, int active_only) +{ + struct window_pane *wp; + u_int i, n, mainheight, width, xoff; + + if (active_only) + return; + + /* Get number of panes. */ + n = window_count_panes(w); + if (n == 0) + return; + + /* Get the main pane height and add one for separator line. */ + mainheight = options_get_number(&w->options, "main-pane-height") + 1; + + /* Need >1 pane and minimum rows; if fewer, display active only. */ + if (n == 1 || w->sy < mainheight + PANE_MINIMUM) { + layout_active_only_refresh(w, active_only); + return; + } + n--; + + /* How many can we fit, not including first? */ + if (w->sx / n < PANE_MINIMUM) { + width = PANE_MINIMUM; + n = w->sx / PANE_MINIMUM; + } else + width = w->sx / n; + + /* Fit the panes. */ + i = xoff = 0; + TAILQ_FOREACH(wp, &w->panes, entry) { + if (wp == TAILQ_FIRST(&w->panes)) { + wp->xoff = 0; + wp->yoff = 0; + window_pane_resize(wp, w->sx, mainheight - 1); + wp->flags &= ~PANE_HIDDEN; + continue; + } + + if (i > n) { + wp->flags |= PANE_HIDDEN; + continue; + } + wp->flags &= ~PANE_HIDDEN; + + wp->xoff = xoff; + wp->yoff = mainheight; + if (i != n - 1) + window_pane_resize(wp, width - 1, w->sy - mainheight); + else + window_pane_resize(wp, width - 1, w->sy - mainheight); + + i++; + xoff += width; + } + + /* Any space left? */ + while (xoff++ < w->sx + 1) { + wp = TAILQ_LAST(&w->panes, window_panes); + while (wp != NULL && wp == TAILQ_FIRST(&w->panes)) + wp = TAILQ_PREV(wp, window_panes, entry); + if (wp == NULL) + break; + window_pane_resize(wp, wp->sx + 1, wp->sy); + } +} diff --git a/log.c b/log.c new file mode 100644 index 00000000..b4a612d5 --- /dev/null +++ b/log.c @@ -0,0 +1,250 @@ +/* $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 +#include +#include +#include +#include +#include + +#include "tmux.h" + +/* Logging type. */ +#define LOG_TYPE_OFF 0 +#define LOG_TYPE_SYSLOG 1 +#define LOG_TYPE_TTY 2 +#define LOG_TYPE_FILE 3 +int log_type = LOG_TYPE_OFF; + +/* Log file, if needed. */ +FILE *log_file; + +/* Debug level. */ +int log_level; + +/* Open logging to syslog. */ +void +log_open_syslog(int level) +{ + log_type = LOG_TYPE_SYSLOG; + log_level = level; + + openlog(__progname, LOG_PID|LOG_NDELAY, LOG_FACILITY); + + tzset(); +} + +/* Open logging to tty. */ +void +log_open_tty(int level) +{ + log_type = LOG_TYPE_TTY; + log_level = level; + + setlinebuf(stderr); + setlinebuf(stdout); + + tzset(); +} + +/* Open logging to file. */ +void +log_open_file(int level, const char *path) +{ + log_file = fopen(path, "w"); + if (log_file == NULL) + return; + + log_type = LOG_TYPE_FILE; + log_level = level; + + setlinebuf(log_file); + + tzset(); +} + +/* Close logging. */ +void +log_close(void) +{ + if (log_type == LOG_TYPE_FILE) + fclose(log_file); + + log_type = LOG_TYPE_OFF; +} + +/* Write a log message. */ +void +log_write(int pri, const char *msg, ...) +{ + va_list ap; + + va_start(ap, msg); + log_vwrite(pri, msg, ap); + va_end(ap); +} + +/* Write a log message. */ +void +log_vwrite(int pri, const char *msg, va_list ap) +{ + char *fmt; + FILE *f = log_file; + + switch (log_type) { + case LOG_TYPE_SYSLOG: + vsyslog(pri, msg, ap); + break; + case LOG_TYPE_TTY: + if (pri == LOG_INFO) + f = stdout; + else + f = stderr; + /* FALLTHROUGH */ + case LOG_TYPE_FILE: + if (asprintf(&fmt, "%s\n", msg) == -1) + exit(1); + if (vfprintf(f, fmt, ap) == -1) + exit(1); + fflush(f); + free(fmt); + break; + } +} + +/* Log a warning with error string. */ +void printflike1 +log_warn(const char *msg, ...) +{ + va_list ap; + char *fmt; + + va_start(ap, msg); + if (asprintf(&fmt, "%s: %s", msg, strerror(errno)) == -1) + exit(1); + log_vwrite(LOG_CRIT, fmt, ap); + free(fmt); + va_end(ap); +} + +/* Log a warning. */ +void printflike1 +log_warnx(const char *msg, ...) +{ + va_list ap; + + va_start(ap, msg); + log_vwrite(LOG_CRIT, msg, ap); + va_end(ap); +} + +/* Log an informational message. */ +void printflike1 +log_info(const char *msg, ...) +{ + va_list ap; + + if (log_level > -1) { + va_start(ap, msg); + log_vwrite(LOG_INFO, msg, ap); + va_end(ap); + } +} + +/* Log a debug message. */ +void printflike1 +log_debug(const char *msg, ...) +{ + va_list ap; + + if (log_level > 0) { + va_start(ap, msg); + log_vwrite(LOG_DEBUG, msg, ap); + va_end(ap); + } +} + +/* Log a debug message at level 2. */ +void printflike1 +log_debug2(const char *msg, ...) +{ + va_list ap; + + if (log_level > 1) { + va_start(ap, msg); + log_vwrite(LOG_DEBUG, msg, ap); + va_end(ap); + } +} + +/* Log a debug message at level 3. */ +void printflike1 +log_debug3(const char *msg, ...) +{ + va_list ap; + + if (log_level > 2) { + va_start(ap, msg); + log_vwrite(LOG_DEBUG, msg, ap); + va_end(ap); + } +} + +/* Log a critical error, with error string if necessary, and die. */ +__dead void +log_vfatal(const char *msg, va_list ap) +{ + char *fmt; + + if (errno != 0) { + if (asprintf(&fmt, "fatal: %s: %s", msg, strerror(errno)) == -1) + exit(1); + log_vwrite(LOG_CRIT, fmt, ap); + } else { + if (asprintf(&fmt, "fatal: %s", msg) == -1) + exit(1); + log_vwrite(LOG_CRIT, fmt, ap); + } + free(fmt); + + exit(1); +} + +/* Log a critical error, with error string, and die. */ +__dead void printflike1 +log_fatal(const char *msg, ...) +{ + va_list ap; + + va_start(ap, msg); + log_vfatal(msg, ap); +} + +/* Log a critical error and die. */ +__dead void printflike1 +log_fatalx(const char *msg, ...) +{ + va_list ap; + + errno = 0; + va_start(ap, msg); + log_vfatal(msg, ap); +} diff --git a/mode-key.c b/mode-key.c new file mode 100644 index 00000000..ba1d12d1 --- /dev/null +++ b/mode-key.c @@ -0,0 +1,210 @@ +/* $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 "tmux.h" + +enum mode_key_cmd mode_key_lookup_vi(struct mode_key_data *, int); +enum mode_key_cmd mode_key_lookup_emacs(struct mode_key_data *, int); + +void +mode_key_init(struct mode_key_data *mdata, int type, int flags) +{ + mdata->type = type; + + if (flags & MODEKEY_CANEDIT) + flags |= MODEKEY_EDITMODE; + mdata->flags = flags; +} + +void +mode_key_free(unused struct mode_key_data *mdata) +{ +} + +enum mode_key_cmd +mode_key_lookup(struct mode_key_data *mdata, int key) +{ + switch (mdata->type) { + case MODEKEY_VI: + return (mode_key_lookup_vi(mdata, key)); + case MODEKEY_EMACS: + return (mode_key_lookup_emacs(mdata, key)); + default: + fatalx("unknown mode key type"); + } +} + +enum mode_key_cmd +mode_key_lookup_vi(struct mode_key_data *mdata, int key) +{ + if (KEYC_ISESC(key)) { + key = KEYC_REMOVEESC(key); + if (mdata->flags & MODEKEY_CANEDIT) + mdata->flags ^= MODEKEY_EDITMODE; + } + + + if (mdata->flags & MODEKEY_EDITMODE) { + switch (key) { + case '\003': + return (MODEKEYCMD_QUIT); + case '\033': + if (mdata->flags & MODEKEY_CANEDIT) + mdata->flags &= ~MODEKEY_EDITMODE; + return (MODEKEYCMD_NONE); + case '\010': + case '\177': + return (MODEKEYCMD_BACKSPACE); + case '\011': + return (MODEKEYCMD_COMPLETE); + case KEYC_DC: + return (MODEKEYCMD_DELETE); + case '\r': + return (MODEKEYCMD_CHOOSE); + } + return (MODEKEYCMD_OTHERKEY); + } + + switch (key) { + case '\010': + case '\177': + return (MODEKEYCMD_LEFT); + case KEYC_DC: + return (MODEKEYCMD_DELETE); + case '\011': + return (MODEKEYCMD_COMPLETE); + case 'i': + if (mdata->flags & MODEKEY_CANEDIT) + mdata->flags |= MODEKEY_EDITMODE; + break; + case 'a': + if (mdata->flags & MODEKEY_CANEDIT) { + mdata->flags |= MODEKEY_EDITMODE; + return (MODEKEYCMD_RIGHT); + } + break; + case '\r': + if (mdata->flags & (MODEKEY_CANEDIT|MODEKEY_CHOOSEMODE)) + return (MODEKEYCMD_CHOOSE); + return (MODEKEYCMD_COPYSELECTION); + case '0': + case '^': + return (MODEKEYCMD_STARTOFLINE); + case '\033': + return (MODEKEYCMD_CLEARSELECTION); + case 'j': + case KEYC_DOWN: + return (MODEKEYCMD_DOWN); + case '$': + return (MODEKEYCMD_ENDOFLINE); + case 'h': + case KEYC_LEFT: + return (MODEKEYCMD_LEFT); + case '\006': + case KEYC_NPAGE: + return (MODEKEYCMD_NEXTPAGE); + case 'w': + return (MODEKEYCMD_NEXTWORD); + case '\025': + case KEYC_PPAGE: + return (MODEKEYCMD_PREVIOUSPAGE); + case 'b': + return (MODEKEYCMD_PREVIOUSWORD); + case 'q': + case '\003': + return (MODEKEYCMD_QUIT); + case 'l': + case KEYC_RIGHT: + return (MODEKEYCMD_RIGHT); + case ' ': + return (MODEKEYCMD_STARTSELECTION); + case 'k': + case KEYC_UP: + return (MODEKEYCMD_UP); + case 'p': + return (MODEKEYCMD_PASTE); + } + + return (MODEKEYCMD_NONE); +} + +enum mode_key_cmd +mode_key_lookup_emacs(struct mode_key_data *mdata, int key) +{ + switch (key) { + case '\010': + case '\177': + return (MODEKEYCMD_BACKSPACE); + case KEYC_DC: + return (MODEKEYCMD_DELETE); + case '\011': + return (MODEKEYCMD_COMPLETE); + case '\r': + return (MODEKEYCMD_CHOOSE); + case '\001': + return (MODEKEYCMD_STARTOFLINE); + case '\007': + return (MODEKEYCMD_CLEARSELECTION); + case '\027': + case KEYC_ADDESC('w'): + return (MODEKEYCMD_COPYSELECTION); + case '\016': + case KEYC_DOWN: + return (MODEKEYCMD_DOWN); + case '\005': + return (MODEKEYCMD_ENDOFLINE); + case '\002': + case KEYC_LEFT: + return (MODEKEYCMD_LEFT); + case ' ': + if (mdata->flags & MODEKEY_CANEDIT) + break; + /* FALLTHROUGH */ + case '\026': + case KEYC_NPAGE: + return (MODEKEYCMD_NEXTPAGE); + case KEYC_ADDESC('f'): + return (MODEKEYCMD_NEXTWORD); + case '\031': + return (MODEKEYCMD_PASTE); + case KEYC_ADDESC('v'): + case KEYC_PPAGE: + return (MODEKEYCMD_PREVIOUSPAGE); + case KEYC_ADDESC('b'): + return (MODEKEYCMD_PREVIOUSWORD); + case '\006': + case KEYC_RIGHT: + return (MODEKEYCMD_RIGHT); + case '\000': + return (MODEKEYCMD_STARTSELECTION); + case '\020': + case KEYC_UP: + return (MODEKEYCMD_UP); + case 'q': + if (mdata->flags & MODEKEY_CANEDIT) + break; + /* FALLTHROUGH */ + case '\003': + case '\033': + return (MODEKEYCMD_QUIT); + } + + return (MODEKEYCMD_OTHERKEY); +} diff --git a/names.c b/names.c new file mode 100644 index 00000000..d5182d88 --- /dev/null +++ b/names.c @@ -0,0 +1,110 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2009 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 "tmux.h" + +char *parse_window_name(const char *); + +void +set_window_names(void) +{ + struct window *w; + u_int i; + char *name, *wname; + struct timeval tv, tv2; + + if (gettimeofday(&tv, NULL) != 0) + fatal("gettimeofday"); + + for (i = 0; i < ARRAY_LENGTH(&windows); i++) { + w = ARRAY_ITEM(&windows, i); + if (w == NULL || w->active == NULL) + continue; + if (!options_get_number(&w->options, "automatic-rename")) + continue; + + if (timercmp(&tv, &w->name_timer, <)) + continue; + memcpy(&w->name_timer, &tv, sizeof w->name_timer); + tv2.tv_sec = 0; + tv2.tv_usec = NAME_INTERVAL * 1000L; + timeradd(&w->name_timer, &tv2, &w->name_timer); + + if (w->active->screen != &w->active->base) + name = NULL; + else + name = get_proc_name(w->active->fd, w->active->tty); + if (name == NULL) + wname = default_window_name(w); + else { + wname = parse_window_name(name); + xfree(name); + } + + if (strcmp(wname, w->name) == 0) + xfree(wname); + else { + xfree(w->name); + w->name = wname; + server_status_window(w); + } + } +} + +char * +default_window_name(struct window *w) +{ + if (w->active->screen != &w->active->base) + return (xstrdup("[tmux]")); + return (parse_window_name(w->active->cmd)); +} + +char * +parse_window_name(const char *in) +{ + char *copy, *name, *ptr; + + name = copy = xstrdup(in); + if (strncmp(name, "exec ", (sizeof "exec ") - 1) == 0) + name = name + (sizeof "exec ") - 1; + + while (*name == ' ') + name++; + if ((ptr = strchr(name, ' ')) != NULL) + *ptr = '\0'; + + if (*name != '\0') { + ptr = name + strlen(name) - 1; + while (ptr > name && !isalnum(*ptr)) + *ptr-- = '\0'; + } + + if (*name == '/') + name = basename(name); + name = xstrdup(name); + xfree(copy); + return (name); +} + diff --git a/options-cmd.c b/options-cmd.c new file mode 100644 index 00000000..6b7090bd --- /dev/null +++ b/options-cmd.c @@ -0,0 +1,182 @@ +/* $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 "tmux.h" + +void +set_option_string(struct cmd_ctx *ctx, struct options *oo, + const struct set_option_entry *entry, char *value) +{ + if (value == NULL) { + ctx->error(ctx, "empty value"); + return; + } + + options_set_string(oo, entry->name, "%s", value); + ctx->info(ctx, "set option: %s -> %s", entry->name, value); +} + +void +set_option_number(struct cmd_ctx *ctx, struct options *oo, + const struct set_option_entry *entry, char *value) +{ + long long number; + const char *errstr; + + if (value == NULL) { + ctx->error(ctx, "empty value"); + return; + } + + number = strtonum(value, entry->minimum, entry->maximum, &errstr); + if (errstr != NULL) { + ctx->error(ctx, "value is %s: %s", errstr, value); + return; + } + options_set_number(oo, entry->name, number); + ctx->info(ctx, "set option: %s -> %lld", entry->name, number); +} + +void +set_option_key(struct cmd_ctx *ctx, struct options *oo, + const struct set_option_entry *entry, char *value) +{ + int key; + + if (value == NULL) { + ctx->error(ctx, "empty value"); + return; + } + + if ((key = key_string_lookup_string(value)) == KEYC_NONE) { + ctx->error(ctx, "unknown key: %s", value); + return; + } + options_set_number(oo, entry->name, key); + ctx->info(ctx, + "set option: %s -> %s", entry->name, key_string_lookup_key(key)); +} + +void +set_option_colour(struct cmd_ctx *ctx, struct options *oo, + const struct set_option_entry *entry, char *value) +{ + int colour; + + if (value == NULL) { + ctx->error(ctx, "empty value"); + return; + } + + if ((colour = colour_fromstring(value)) == -1) { + ctx->error(ctx, "bad colour: %s", value); + return; + } + + options_set_number(oo, entry->name, colour); + ctx->info(ctx, + "set option: %s -> %s", entry->name, colour_tostring(colour)); +} + +void +set_option_attributes(struct cmd_ctx *ctx, struct options *oo, + const struct set_option_entry *entry, char *value) +{ + int attr; + + if (value == NULL) { + ctx->error(ctx, "empty value"); + return; + } + + if ((attr = attributes_fromstring(value)) == -1) { + ctx->error(ctx, "bad attributes: %s", value); + return; + } + + options_set_number(oo, entry->name, attr); + ctx->info(ctx, + "set option: %s -> %s", entry->name, attributes_tostring(attr)); +} + +void +set_option_flag(struct cmd_ctx *ctx, struct options *oo, + const struct set_option_entry *entry, char *value) +{ + int flag; + + if (value == NULL || *value == '\0') + flag = !options_get_number(oo, entry->name); + else { + if ((value[0] == '1' && value[1] == '\0') || + strcasecmp(value, "on") == 0 || + strcasecmp(value, "yes") == 0) + flag = 1; + else if ((value[0] == '0' && value[1] == '\0') || + strcasecmp(value, "off") == 0 || + strcasecmp(value, "no") == 0) + flag = 0; + else { + ctx->error(ctx, "bad value: %s", value); + return; + } + } + + options_set_number(oo, entry->name, flag); + ctx->info(ctx, + "set option: %s -> %s", entry->name, flag ? "on" : "off"); +} + +void +set_option_choice(struct cmd_ctx *ctx, struct options *oo, + const struct set_option_entry *entry, char *value) +{ + const char **choicep; + int n, choice = -1; + + if (value == NULL) { + ctx->error(ctx, "empty value"); + return; + } + + n = 0; + for (choicep = entry->choices; *choicep != NULL; choicep++) { + n++; + if (strncmp(*choicep, value, strlen(value)) != 0) + continue; + + if (choice != -1) { + ctx->error(ctx, "ambiguous option: %s", value); + return; + } + choice = n - 1; + } + if (choice == -1) { + ctx->error(ctx, "unknown option: %s", value); + return; + } + + options_set_number(oo, entry->name, choice); + ctx->info(ctx, + "set option: %s -> %s", entry->name, entry->choices[choice]); +} diff --git a/options.c b/options.c new file mode 100644 index 00000000..c742e092 --- /dev/null +++ b/options.c @@ -0,0 +1,160 @@ +/* $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 "tmux.h" + +/* + * Option handling; each option has a name, type and value and is stored in + * a splay tree. + */ + +SPLAY_GENERATE(options_tree, options_entry, entry, options_cmp); + +int +options_cmp(struct options_entry *o1, struct options_entry *o2) +{ + return (strcmp(o1->name, o2->name)); +} + +void +options_init(struct options *oo, struct options *parent) +{ + SPLAY_INIT(&oo->tree); + oo->parent = parent; +} + +void +options_free(struct options *oo) +{ + struct options_entry *o; + + while (!SPLAY_EMPTY(&oo->tree)) { + o = SPLAY_ROOT(&oo->tree); + SPLAY_REMOVE(options_tree, &oo->tree, o); + xfree(o->name); + if (o->type == OPTIONS_STRING) + xfree(o->value.string); + xfree(o); + } +} + +struct options_entry * +options_find1(struct options *oo, const char *name) +{ + struct options_entry p; + + p.name = (char *) name; + return (SPLAY_FIND(options_tree, &oo->tree, &p)); +} + +struct options_entry * +options_find(struct options *oo, const char *name) +{ + struct options_entry *o, p; + + p.name = (char *) name; + o = SPLAY_FIND(options_tree, &oo->tree, &p); + while (o == NULL) { + oo = oo->parent; + if (oo == NULL) + break; + o = SPLAY_FIND(options_tree, &oo->tree, &p); + } + return (o); +} + +int +options_remove(struct options *oo, const char *name) +{ + struct options_entry *o; + + if ((o = options_find1(oo, name)) == NULL) + return (-1); + + SPLAY_REMOVE(options_tree, &oo->tree, o); + xfree(o->name); + if (o->type == OPTIONS_STRING) + xfree(o->value.string); + xfree(o); + return (0); +} + +void printflike3 +options_set_string(struct options *oo, const char *name, const char *fmt, ...) +{ + struct options_entry *o; + va_list ap; + + if ((o = options_find1(oo, name)) == NULL) { + o = xmalloc(sizeof *o); + o->name = xstrdup(name); + SPLAY_INSERT(options_tree, &oo->tree, o); + } else if (o->type == OPTIONS_STRING) + xfree(o->value.string); + + va_start(ap, fmt); + o->type = OPTIONS_STRING; + xvasprintf(&o->value.string, fmt, ap); + va_end(ap); +} + +char * +options_get_string(struct options *oo, const char *name) +{ + struct options_entry *o; + + if ((o = options_find(oo, name)) == NULL) + fatalx("missing option"); + if (o->type != OPTIONS_STRING) + fatalx("option not a string"); + return (o->value.string); +} + +void +options_set_number(struct options *oo, const char *name, long long value) +{ + struct options_entry *o; + + if ((o = options_find1(oo, name)) == NULL) { + o = xmalloc(sizeof *o); + o->name = xstrdup(name); + SPLAY_INSERT(options_tree, &oo->tree, o); + } else if (o->type == OPTIONS_STRING) + xfree(o->value.string); + + o->type = OPTIONS_NUMBER; + o->value.number = value; + +} + +long long +options_get_number(struct options *oo, const char *name) +{ + struct options_entry *o; + + if ((o = options_find(oo, name)) == NULL) + fatalx("missing option"); + if (o->type != OPTIONS_NUMBER) + fatalx("option not a number"); + return (o->value.number); +} diff --git a/paste.c b/paste.c new file mode 100644 index 00000000..3644381c --- /dev/null +++ b/paste.c @@ -0,0 +1,131 @@ +/* $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 + +#include + +#include "tmux.h" + +void +paste_init_stack(struct paste_stack *ps) +{ + ARRAY_INIT(ps); +} + +void +paste_free_stack(struct paste_stack *ps) +{ + while (paste_free_top(ps) == 0) + ; +} + +struct paste_buffer * +paste_walk_stack(struct paste_stack *ps, uint *idx) +{ + struct paste_buffer *pb; + + pb = paste_get_index(ps, *idx); + (*idx)++; + return (pb); +} + +struct paste_buffer * +paste_get_top(struct paste_stack *ps) +{ + if (ARRAY_LENGTH(ps) == 0) + return (NULL); + return (ARRAY_FIRST(ps)); +} + +struct paste_buffer * +paste_get_index(struct paste_stack *ps, u_int idx) +{ + if (idx >= ARRAY_LENGTH(ps)) + return (NULL); + return (ARRAY_ITEM(ps, idx)); +} + +int +paste_free_top(struct paste_stack *ps) +{ + struct paste_buffer *pb; + + if (ARRAY_LENGTH(ps) == 0) + return (-1); + + pb = ARRAY_FIRST(ps); + ARRAY_REMOVE(ps, 0); + + xfree(pb->data); + xfree(pb); + + return (0); +} + +int +paste_free_index(struct paste_stack *ps, u_int idx) +{ + struct paste_buffer *pb; + + if (idx >= ARRAY_LENGTH(ps)) + return (-1); + + pb = ARRAY_ITEM(ps, idx); + ARRAY_REMOVE(ps, idx); + + xfree(pb->data); + xfree(pb); + + return (0); +} + +void +paste_add(struct paste_stack *ps, char *data, u_int limit) +{ + struct paste_buffer *pb; + + while (ARRAY_LENGTH(ps) >= limit) + ARRAY_TRUNC(ps, 1); + + pb = xmalloc(sizeof *pb); + ARRAY_INSERT(ps, 0, pb); + + pb->data = data; + if (gettimeofday(&pb->tv, NULL) != 0) + fatal("gettimeofday"); +} + +int +paste_replace(struct paste_stack *ps, u_int idx, char *data) +{ + struct paste_buffer *pb; + + if (idx >= ARRAY_LENGTH(ps)) + return (-1); + + pb = ARRAY_ITEM(ps, idx); + xfree(pb->data); + + pb->data = data; + if (gettimeofday(&pb->tv, NULL) != 0) + fatal("gettimeofday"); + + return (0); +} diff --git a/procname.c b/procname.c new file mode 100644 index 00000000..262d63a4 --- /dev/null +++ b/procname.c @@ -0,0 +1,130 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2009 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 + +#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) + +#define is_runnable(p) \ + ((p)->p_stat == SRUN || (p)->p_stat == SIDL || (p)->p_stat == SONPROC) +#define is_stopped(p) \ + ((p)->p_stat == SSTOP || (p)->p_stat == SZOMB || (p)->p_stat == SDEAD) + +char *get_proc_name(int, char *); + +char * +get_proc_name(int fd, char *tty) +{ + int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PGRP, 0 }; + struct stat sb; + size_t len; + struct kinfo_proc *buf, *newbuf; + struct proc *p, *bestp; + u_int i; + char *name; + + buf = NULL; + + if (stat(tty, &sb) == -1) + return (NULL); + if ((mib[3] = tcgetpgrp(fd)) == -1) + return (NULL); + +retry: + if (sysctl(mib, nitems(mib), NULL, &len, NULL, 0) == -1) + return (NULL); + len = (len * 5) / 4; + + if ((newbuf = realloc(buf, len)) == NULL) { + free(buf); + return (NULL); + } + buf = newbuf; + + if (sysctl(mib, nitems(mib), buf, &len, NULL, 0) == -1) { + if (errno == ENOMEM) + goto retry; + free(buf); + return (NULL); + } + + bestp = NULL; + for (i = 0; i < len / sizeof (struct kinfo_proc); i++) { + if (buf[i].kp_eproc.e_tdev != sb.st_rdev) + continue; + p = &buf[i].kp_proc; + if (bestp == NULL) { + bestp = p; + continue; + } + + if (is_runnable(p) && !is_runnable(bestp)) + bestp = p; + else if (!is_runnable(p) && is_runnable(bestp)) + continue; + + if (!is_stopped(p) && is_stopped(bestp)) + bestp = p; + else if (is_stopped(p) && !is_stopped(bestp)) + continue; + + if (p->p_estcpu > bestp->p_estcpu) + bestp = p; + else if (p->p_estcpu < bestp->p_estcpu) + continue; + + if (p->p_slptime < bestp->p_slptime) + bestp = p; + else if (p->p_slptime > bestp->p_slptime) + continue; + + if (p->p_flag & P_SINTR && !(bestp->p_flag & P_SINTR)) + bestp = p; + else if (!(p->p_flag & P_SINTR) && bestp->p_flag & P_SINTR) + continue; + + if (LIST_FIRST(&p->p_children) == NULL && + LIST_FIRST(&bestp->p_children) != NULL) /* XXX ugh */ + bestp = p; + else if (LIST_FIRST(&p->p_children) != NULL && + LIST_FIRST(&bestp->p_children) == NULL) + continue; + + if (strcmp(p->p_comm, p->p_comm) < 0) + bestp = p; + else if (strcmp(p->p_comm, p->p_comm) > 0) + continue; + + if (p->p_pid > bestp->p_pid) + bestp = p; + } + + name = NULL; + if (bestp != NULL) + name = strdup(bestp->p_comm); + + free(buf); + return (name); +} diff --git a/resize.c b/resize.c new file mode 100644 index 00000000..50e12fb0 --- /dev/null +++ b/resize.c @@ -0,0 +1,138 @@ +/* $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 + +#include "tmux.h" + +/* + * Recalculate window and session sizes. + * + * Every session has the size of the smallest client it is attached to and + * every window the size of the smallest session it is attached to. + * + * So, when a client is resized or a session attached to or detached from a + * client, the window sizes must be recalculated. For each session, find the + * smallest client it is attached to, and resize it to that size. Then for + * every window, find the smallest session it is attached to, resize it to that + * size and clear and redraw every client with it as the current window. + * + * This is quite inefficient - better/additional data structures are needed + * to make it better. + * + * As a side effect, this function updates the SESSION_UNATTACHED flag. This + * flag is necessary to make sure unattached sessions do not limit the size of + * windows that are attached both to them and to other (attached) sessions. + */ + +void +recalculate_sizes(void) +{ + struct session *s; + struct client *c; + struct window *w; + u_int i, j, ssx, ssy, has, limit; + int flag; + + for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { + s = ARRAY_ITEM(&sessions, i); + if (s == NULL) + continue; + + ssx = ssy = UINT_MAX; + for (j = 0; j < ARRAY_LENGTH(&clients); j++) { + c = ARRAY_ITEM(&clients, j); + if (c == NULL) + continue; + if (c->session == s) { + if (c->tty.sx < ssx) + ssx = c->tty.sx; + if (c->tty.sy < ssy) + ssy = c->tty.sy; + } + } + if (ssx == UINT_MAX || ssy == UINT_MAX) { + s->flags |= SESSION_UNATTACHED; + continue; + } + s->flags &= ~SESSION_UNATTACHED; + + if (options_get_number(&s->options, "status")) { + if (ssy == 0) + ssy = 1; + else + ssy--; + } + if (s->sx == ssx && s->sy == ssy) + continue; + + log_debug( + "session size %u,%u (was %u,%u)", ssx, ssy, s->sx, s->sy); + + s->sx = ssx; + s->sy = ssy; + } + + for (i = 0; i < ARRAY_LENGTH(&windows); i++) { + w = ARRAY_ITEM(&windows, i); + if (w == NULL) + continue; + flag = options_get_number(&w->options, "aggressive-resize"); + + ssx = ssy = UINT_MAX; + for (j = 0; j < ARRAY_LENGTH(&sessions); j++) { + s = ARRAY_ITEM(&sessions, j); + if (s == NULL || s->flags & SESSION_UNATTACHED) + continue; + if (flag) + has = s->curw->window == w; + else + has = session_has(s, w); + if (has) { + if (s->sx < ssx) + ssx = s->sx; + if (s->sy < ssy) + ssy = s->sy; + } + } + if (ssx == UINT_MAX || ssy == UINT_MAX) { + w->flags |= WINDOW_HIDDEN; + continue; + } + w->flags &= ~WINDOW_HIDDEN; + + limit = options_get_number(&w->options, "force-width"); + if (limit != 0 && ssx > limit) + ssx = limit; + limit = options_get_number(&w->options, "force-height"); + if (limit != 0 && ssy > limit) + ssy = limit; + + if (w->sx == ssx && w->sy == ssy) + continue; + + log_debug( + "window size %u,%u (was %u,%u)", ssx, ssy, w->sx, w->sy); + + window_resize(w, ssx, ssy); + server_redraw_window(w); + layout_refresh(w, 0); + } +} diff --git a/screen-redraw.c b/screen-redraw.c new file mode 100644 index 00000000..06033436 --- /dev/null +++ b/screen-redraw.c @@ -0,0 +1,171 @@ +/* $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 + +#include "tmux.h" + +int screen_redraw_check_cell(struct client *, u_int, u_int); + +/* Check if cell inside a pane. */ +int +screen_redraw_check_cell(struct client *c, u_int px, u_int py) +{ + struct window *w = c->session->curw->window; + struct window_pane *wp; + + if (px > w->sx || py > w->sy) + return (0); + + TAILQ_FOREACH(wp, &w->panes, entry) { + /* Inside pane. */ + if (px >= wp->xoff && px < wp->xoff + wp->sx && + py >= wp->yoff && py < wp->yoff + wp->sy) + return (1); + + /* Left/right borders. */ + if (py >= wp->yoff && py < wp->yoff + wp->sy) { + if (wp->xoff != 0 && px == wp->xoff - 1) + return (1); + if (px == wp->xoff + wp->sx) + return (1); + } + + /* Top/bottom borders. */ + if (px >= wp->xoff && px < wp->xoff + wp->sx) { + if (wp->yoff != 0 && py == wp->yoff - 1) + return (1); + if (py == wp->yoff + wp->sy) + return (1); + } + } + + return (0); +} + +/* Redraw entire screen.. */ +void +screen_redraw_screen(struct client *c) +{ + struct window *w = c->session->curw->window; + struct tty *tty = &c->tty; + struct window_pane *wp; + struct screen *s; + u_int i, j, sx, sy; + int status, has_acs; + u_char choriz, cvert, cbackg; + + /* Get status line, er, status. */ + status = options_get_number(&c->session->options, "status"); + + /* Work out ACS characters. */ + if (tty_term_has(tty->term, TTYC_ACSC)) { + has_acs = 1; + choriz = tty_get_acs(tty, 'q'); + cvert = tty_get_acs(tty, 'x'); + cbackg = tty_get_acs(tty, '~'); + } else { + has_acs = 0; + choriz = '-'; + cvert = '|'; + cbackg = '.'; + } + + /* Clear the screen. */ + tty_reset(tty); + if (has_acs) + tty_putcode(tty, TTYC_SMACS); + for (j = 0; j < tty->sy - status; j++) { + for (i = 0; i < tty->sx; i++) { + if (!screen_redraw_check_cell(c, i, j)) { + tty_cursor(tty, i, j, 0, 0); + tty_putc(tty, cbackg); + } + } + } + if (has_acs) + tty_putcode(tty, TTYC_RMACS); + + /* Draw the panes. */ + TAILQ_FOREACH(wp, &w->panes, entry) { + if (wp->flags & PANE_HIDDEN) + continue; + + tty_reset(tty); + + s = wp->screen; + sx = wp->sx; + sy = wp->sy; + + /* Draw left and right borders. */ + if (has_acs) + tty_putcode(tty, TTYC_SMACS); + if (wp->xoff > 0) { + for (i = wp->yoff; i < wp->yoff + sy; i++) { + tty_cursor(tty, wp->xoff - 1, i, 0, 0); + tty_putc(tty, cvert); + } + } + if (wp->xoff + sx < tty->sx) { + for (i = wp->yoff; i < wp->yoff + sy; i++) { + tty_cursor(tty, wp->xoff + sx, i, 0, 0); + tty_putc(&c->tty, cvert); + } + } + + /* Draw top and bottom borders. */ + if (wp->yoff > 0) { + tty_cursor(tty, wp->xoff, wp->yoff - 1, 0, 0); + for (i = 0; i < sx; i++) + tty_putc(tty, choriz); + } + if (wp->yoff + sy < tty->sy - status) { + tty_cursor(tty, wp->xoff, wp->yoff + sy, 0, 0); + for (i = 0; i < sx; i++) + tty_putc(tty, choriz); + } + if (has_acs) + tty_putcode(tty, TTYC_RMACS); + + /* Draw the pane. */ + screen_redraw_pane(c, wp); + } + + /* Draw the status line. */ + screen_redraw_status(c); +} + +/* Draw a single pane. */ +void +screen_redraw_pane(struct client *c, struct window_pane *wp) +{ + u_int i; + + for (i = 0; i < wp->sy; i++) + tty_draw_line(&c->tty, wp->screen, i, wp->xoff, wp->yoff); +} + + +/* Draw the status line. */ +void +screen_redraw_status(struct client *c) +{ + tty_draw_line(&c->tty, &c->status, 0, 0, c->tty.sy - 1); +} diff --git a/screen-write.c b/screen-write.c new file mode 100644 index 00000000..ac31fc6f --- /dev/null +++ b/screen-write.c @@ -0,0 +1,684 @@ +/* $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 + +#include "tmux.h" + +void screen_write_save(struct screen_write_ctx *); +void screen_write_overwrite(struct screen_write_ctx *); + +/* Initialise writing with a window. */ +void +screen_write_start( + struct screen_write_ctx *ctx, struct window_pane *wp, struct screen *s) +{ + ctx->wp = wp; + if (wp != NULL && s == NULL) + ctx->s = wp->screen; + else + ctx->s = s; +} + +/* Finish writing. */ +void +screen_write_stop(unused struct screen_write_ctx *ctx) +{ +} + +/* Write character. */ +void +screen_write_putc( + struct screen_write_ctx *ctx, struct grid_cell *gc, u_char ch) +{ + gc->data = ch; + screen_write_cell(ctx, gc, NULL); +} + +/* Write string. */ +void printflike3 +screen_write_puts( + struct screen_write_ctx *ctx, struct grid_cell *gc, const char *fmt, ...) +{ + va_list ap; + char *msg, *ptr; + + va_start(ap, fmt); + xvasprintf(&msg, fmt, ap); + va_end(ap); + + for (ptr = msg; *ptr != '\0'; ptr++) + screen_write_putc(ctx, gc, (u_char) *ptr); + + xfree(msg); +} + +/* Copy from another screen. */ +void +screen_write_copy(struct screen_write_ctx *ctx, + struct screen *src, u_int px, u_int py, u_int nx, u_int ny) +{ + struct screen *s = ctx->s; + struct grid *gd = src->grid; + const struct grid_cell *gc; + struct grid_utf8 *gu; + u_char *udata; + u_int xx, yy, cx, cy; + + cx = s->cx; + cy = s->cy; + for (yy = py; yy < py + ny; yy++) { + for (xx = px; xx < px + nx; xx++) { + if (xx >= gd->sx || yy >= gd->hsize + gd->sy) + gc = &grid_default_cell; + else + gc = grid_peek_cell(gd, xx, yy); + + udata = NULL; + if (gc->flags & GRID_FLAG_UTF8) { + gu = grid_get_utf8(gd, xx, yy); + udata = gu->data; + } + + screen_write_cell(ctx, gc, udata); + } + cy++; + screen_write_cursormove(ctx, cx, cy); + } +} + +/* Save cursor and region positions. */ +void +screen_write_save(struct screen_write_ctx *ctx) +{ + struct screen *s = ctx->s; + + s->old_cx = s->cx; + s->old_cy = s->cy; + + s->old_rlower = s->rlower; + s->old_rupper = s->rupper; +} + +/* Cursor up by ny. */ +void +screen_write_cursorup(struct screen_write_ctx *ctx, u_int ny) +{ + struct screen *s = ctx->s; + + if (ny == 0) + ny = 1; + + if (ny > s->cy) + ny = s->cy; + if (ny == 0) + return; + + s->cy -= ny; +} + +/* Cursor down by ny. */ +void +screen_write_cursordown(struct screen_write_ctx *ctx, u_int ny) +{ + struct screen *s = ctx->s; + + if (ny == 0) + ny = 1; + + if (ny > screen_size_y(s) - 1 - s->cy) + ny = screen_size_y(s) - 1 - s->cy; + if (ny == 0) + return; + + s->cy += ny; +} + +/* Cursor right by nx. */ +void +screen_write_cursorright(struct screen_write_ctx *ctx, u_int nx) +{ + struct screen *s = ctx->s; + + if (nx == 0) + nx = 1; + + if (nx > screen_size_x(s) - 1 - s->cx) + nx = screen_size_x(s) - 1 - s->cx; + if (nx == 0) + return; + + s->cx += nx; +} + +/* Cursor left by nx. */ +void +screen_write_cursorleft(struct screen_write_ctx *ctx, u_int nx) +{ + struct screen *s = ctx->s; + + if (nx == 0) + nx = 1; + + if (nx > s->cx) + nx = s->cx; + if (nx == 0) + return; + + s->cx -= nx; +} + +/* Insert nx characters. */ +void +screen_write_insertcharacter(struct screen_write_ctx *ctx, u_int nx) +{ + struct screen *s = ctx->s; + + if (nx == 0) + nx = 1; + + if (nx > screen_size_x(s) - 1 - s->cx) + nx = screen_size_x(s) - 1 - s->cx; + if (nx == 0) + return; + + screen_write_save(ctx); + + if (s->cx <= screen_size_x(s) - 1) + grid_view_insert_cells(s->grid, s->cx, s->cy, nx); + + tty_write_cmd(ctx->wp, TTY_INSERTCHARACTER, nx); +} + +/* Delete nx characters. */ +void +screen_write_deletecharacter(struct screen_write_ctx *ctx, u_int nx) +{ + struct screen *s = ctx->s; + + if (nx == 0) + nx = 1; + + if (nx > screen_size_x(s) - 1 - s->cx) + nx = screen_size_x(s) - 1 - s->cx; + if (nx == 0) + return; + + screen_write_save(ctx); + + if (s->cx <= screen_size_x(s) - 1) + grid_view_delete_cells(s->grid, s->cx, s->cy, nx); + + tty_write_cmd(ctx->wp, TTY_DELETECHARACTER, nx); +} + +/* Insert ny lines. */ +void +screen_write_insertline(struct screen_write_ctx *ctx, u_int ny) +{ + struct screen *s = ctx->s; + + if (ny == 0) + ny = 1; + + if (ny > screen_size_y(s) - 1 - s->cy) + ny = screen_size_y(s) - 1 - s->cy; + if (ny == 0) + return; + + screen_write_save(ctx); + + if (s->cy < s->rupper || s->cy > s->rlower) + grid_view_insert_lines(s->grid, s->cy, ny); + else { + grid_view_insert_lines_region( + s->grid, s->rupper, s->rlower, s->cy, ny); + } + + tty_write_cmd(ctx->wp, TTY_INSERTLINE, ny); +} + +/* Delete ny lines. */ +void +screen_write_deleteline(struct screen_write_ctx *ctx, u_int ny) +{ + struct screen *s = ctx->s; + + if (ny == 0) + ny = 1; + + if (ny > screen_size_y(s) - 1 - s->cy) + ny = screen_size_y(s) - 1 - s->cy; + if (ny == 0) + return; + + screen_write_save(ctx); + + if (s->cy < s->rupper || s->cy > s->rlower) + grid_view_delete_lines(s->grid, s->cy, ny); + else { + grid_view_delete_lines_region( + s->grid, s->rupper, s->rlower, s->cy, ny); + } + + tty_write_cmd(ctx->wp, TTY_DELETELINE, ny); +} + +/* Clear line at cursor. */ +void +screen_write_clearline(struct screen_write_ctx *ctx) +{ + struct screen *s = ctx->s; + + screen_write_save(ctx); + + grid_view_clear(s->grid, 0, s->cy, screen_size_x(s), 1); + + tty_write_cmd(ctx->wp, TTY_CLEARLINE); +} + +/* Clear to end of line from cursor. */ +void +screen_write_clearendofline(struct screen_write_ctx *ctx) +{ + struct screen *s = ctx->s; + u_int sx; + + screen_write_save(ctx); + + sx = screen_size_x(s); + + if (s->cx <= sx - 1) + grid_view_clear(s->grid, s->cx, s->cy, sx - s->cx, 1); + + tty_write_cmd(ctx->wp, TTY_CLEARENDOFLINE); +} + +/* Clear to start of line from cursor. */ +void +screen_write_clearstartofline(struct screen_write_ctx *ctx) +{ + struct screen *s = ctx->s; + u_int sx; + + screen_write_save(ctx); + + sx = screen_size_x(s); + + if (s->cx > sx - 1) + grid_view_clear(s->grid, 0, s->cy, sx, 1); + else + grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1); + + tty_write_cmd(ctx->wp, TTY_CLEARSTARTOFLINE); +} + +/* Move cursor to px,py. */ +void +screen_write_cursormove(struct screen_write_ctx *ctx, u_int px, u_int py) +{ + struct screen *s = ctx->s; + + if (px > screen_size_x(s) - 1) + px = screen_size_x(s) - 1; + if (py > screen_size_y(s) - 1) + py = screen_size_y(s) - 1; + + s->cx = px; + s->cy = py; +} + +/* Set cursor mode. */ +void +screen_write_cursormode(struct screen_write_ctx *ctx, int state) +{ + struct screen *s = ctx->s; + + if (state) + s->mode |= MODE_CURSOR; + else + s->mode &= ~MODE_CURSOR; +} + +/* Reverse index (up with scroll). */ +void +screen_write_reverseindex(struct screen_write_ctx *ctx) +{ + struct screen *s = ctx->s; + + screen_write_save(ctx); + + if (s->cy == s->rupper) + grid_view_scroll_region_down(s->grid, s->rupper, s->rlower); + else if (s->cy > 0) + s->cy--; + + tty_write_cmd(ctx->wp, TTY_REVERSEINDEX); +} + +/* Set scroll region. */ +void +screen_write_scrollregion( + struct screen_write_ctx *ctx, u_int rupper, u_int rlower) +{ + struct screen *s = ctx->s; + + if (rupper > screen_size_y(s) - 1) + rupper = screen_size_y(s) - 1; + if (rlower > screen_size_y(s) - 1) + rlower = screen_size_y(s) - 1; + if (rupper > rlower) + return; + + /* Cursor moves to top-left. */ + s->cx = 0; + s->cy = 0; + + s->rupper = rupper; + s->rlower = rlower; +} + +/* Set insert mode. */ +void +screen_write_insertmode(struct screen_write_ctx *ctx, int state) +{ + struct screen *s = ctx->s; + + if (state) + s->mode |= MODE_INSERT; + else + s->mode &= ~MODE_INSERT; +} + +/* Set mouse mode. */ +void +screen_write_mousemode(struct screen_write_ctx *ctx, int state) +{ + struct screen *s = ctx->s; + + if (state) + s->mode |= MODE_MOUSE; + else + s->mode &= ~MODE_MOUSE; +} + +/* Line feed (down with scroll). */ +void +screen_write_linefeed(struct screen_write_ctx *ctx) +{ + struct screen *s = ctx->s; + + screen_write_save(ctx); + + if (s->cy == s->rlower) + grid_view_scroll_region_up(s->grid, s->rupper, s->rlower); + else if (s->cy < screen_size_y(s) - 1) + s->cy++; + + tty_write_cmd(ctx->wp, TTY_LINEFEED); +} + +/* Carriage return (cursor to start of line). */ +void +screen_write_carriagereturn(struct screen_write_ctx *ctx) +{ + struct screen *s = ctx->s; + + s->cx = 0; +} + +/* Set keypad cursor keys mode. */ +void +screen_write_kcursormode(struct screen_write_ctx *ctx, int state) +{ + struct screen *s = ctx->s; + + if (state) + s->mode |= MODE_KCURSOR; + else + s->mode &= ~MODE_KCURSOR; +} + +/* Set keypad number keys mode. */ +void +screen_write_kkeypadmode(struct screen_write_ctx *ctx, int state) +{ + struct screen *s = ctx->s; + + if (state) + s->mode |= MODE_KKEYPAD; + else + s->mode &= ~MODE_KKEYPAD; +} + +/* Clear to end of screen from cursor. */ +void +screen_write_clearendofscreen(struct screen_write_ctx *ctx) +{ + struct screen *s = ctx->s; + u_int sx, sy; + + screen_write_save(ctx); + + sx = screen_size_x(s); + sy = screen_size_y(s); + + if (s->cx <= sx - 1) + grid_view_clear(s->grid, s->cx, s->cy, sx - s->cx, 1); + grid_view_clear(s->grid, 0, s->cy + 1, sx, sy - (s->cy + 1)); + + tty_write_cmd(ctx->wp, TTY_CLEARENDOFSCREEN); +} + +/* Clear to start of screen. */ +void +screen_write_clearstartofscreen(struct screen_write_ctx *ctx) +{ + struct screen *s = ctx->s; + u_int sx; + + screen_write_save(ctx); + + sx = screen_size_x(s); + + if (s->cy > 0) + grid_view_clear(s->grid, 0, 0, sx, s->cy - 1); + if (s->cx > sx - 1) + grid_view_clear(s->grid, 0, s->cy, sx, 1); + else + grid_view_clear(s->grid, 0, s->cy, s->cx, 1); + + tty_write_cmd(ctx->wp, TTY_CLEARSTARTOFSCREEN); +} + +/* Clear entire screen. */ +void +screen_write_clearscreen(struct screen_write_ctx *ctx) +{ + struct screen *s = ctx->s; + + screen_write_save(ctx); + + grid_view_clear(s->grid, 0, 0, screen_size_x(s), screen_size_y(s)); + + tty_write_cmd(ctx->wp, TTY_CLEARSCREEN); +} + +/* Write cell data. */ +void +screen_write_cell( + struct screen_write_ctx *ctx, const struct grid_cell *gc, u_char *udata) +{ + struct screen *s = ctx->s; + struct grid *gd = s->grid; + struct grid_utf8 gu, *tmp_gu; + u_int width, xx, i; + struct grid_cell tmp_gc, *tmp_gc2; + size_t size; + + /* Ignore padding. */ + if (gc->flags & GRID_FLAG_PADDING) + return; + + /* Find character width. */ + if (gc->flags & GRID_FLAG_UTF8) { + width = utf8_width(udata); + + gu.width = width; + memcpy(&gu.data, udata, sizeof gu.data); + } else + width = 1; + + /* If the width is zero, combine onto the previous character. */ + if (width == 0) { + if (s->cx == 0) + return; + tmp_gc2 = grid_view_get_cell(gd, s->cx - 1, s->cy); + if (!(tmp_gc2->flags & GRID_FLAG_UTF8)) { + tmp_gc2->flags |= GRID_FLAG_UTF8; + memset(&gu.data, 0xff, sizeof gu.data); + *gu.data = tmp_gc2->data; + gu.width = 1; + grid_view_set_utf8(gd, s->cx - 1, s->cy, &gu); + } + tmp_gu = grid_view_get_utf8(gd, s->cx - 1, s->cy); + + for (i = 0; i < UTF8_SIZE; i++) { + if (tmp_gu->data[i] == 0xff) + break; + } + memcpy(tmp_gu->data + i, udata, UTF8_SIZE - i); + + /* Assume the previous character has just been input. */ + for (size = 0; size < UTF8_SIZE; size++) { + if (udata[size] == 0xff) + break; + } + tty_write_cmd(ctx->wp, TTY_RAW, udata, size); + return; + } + + /* If the character is wider than the screen, don't print it. */ + if (width > screen_size_x(s)) { + memcpy(&tmp_gc, gc, sizeof tmp_gc); + tmp_gc.data = '_'; + width = 1; + gc = &tmp_gc; + } + + /* Check this will fit on the current line; scroll if not. */ + if (s->cx > screen_size_x(s) - width) { + screen_write_carriagereturn(ctx); + screen_write_linefeed(ctx); + } + + /* Sanity checks. */ + if (s->cx > screen_size_x(s) - 1 || s->cy > screen_size_y(s) - 1) + return; + + /* Handle overwriting of UTF-8 characters. */ + screen_write_overwrite(ctx); + + /* + * If the new character is UTF-8 wide, fill in padding cells. Have + * already ensured there is enough room. + */ + for (xx = s->cx + 1; xx < s->cx + width; xx++) { + tmp_gc2 = grid_view_get_cell(gd, xx, s->cy); + if (tmp_gc2 != NULL) + tmp_gc2->flags |= GRID_FLAG_PADDING; + } + + /* Set the cell. */ + grid_view_set_cell(gd, s->cx, s->cy, gc); + if (gc->flags & GRID_FLAG_UTF8) + grid_view_set_utf8(gd, s->cx, s->cy, &gu); + + /* Move the cursor. */ + screen_write_save(ctx); + s->cx += width; + + /* Draw to the screen if necessary. */ + if (screen_check_selection(s, s->cx - width, s->cy)) { + s->sel.cell.data = gc->data; + tty_write_cmd(ctx->wp, TTY_CELL, &s->sel.cell, &gu); + } else + tty_write_cmd(ctx->wp, TTY_CELL, gc, &gu); +} + +/* + * UTF-8 wide characters are a bit of an annoyance. They take up more than one + * cell on the screen, so following cells must not be drawn by marking them as + * padding. + * + * So far, so good. The problem is, when overwriting a padding cell, or a UTF-8 + * character, it is necessary to also overwrite any other cells which covered + * by the same character. + */ +void +screen_write_overwrite(struct screen_write_ctx *ctx) +{ + struct screen *s = ctx->s; + struct grid *gd = s->grid; + const struct grid_cell *gc; + const struct grid_utf8 *gu; + u_int xx; + + gc = grid_view_peek_cell(gd, s->cx, s->cy); + gu = grid_view_peek_utf8(gd, s->cx, s->cy); + + if (gc->flags & GRID_FLAG_PADDING) { + /* + * A padding cell, so clear any following and leading padding + * cells back to the character. Don't overwrite the current + * cell as that happens later anyway. + */ + xx = s->cx + 1; + while (--xx > 0) { + gc = grid_view_peek_cell(gd, xx, s->cy); + if (!(gc->flags & GRID_FLAG_PADDING)) + break; + grid_view_set_cell(gd, xx, s->cy, &grid_default_cell); + } + + /* Overwrite the character at the start of this padding. */ + grid_view_set_cell(gd, xx, s->cy, &grid_default_cell); + + /* Overwrite following padding cells. */ + xx = s->cx; + while (++xx < screen_size_x(s)) { + gc = grid_view_peek_cell(gd, xx, s->cy); + if (!(gc->flags & GRID_FLAG_PADDING)) + break; + grid_view_set_cell(gd, xx, s->cy, &grid_default_cell); + } + } else if (gc->flags & GRID_FLAG_UTF8 && gu->width > 1) { + /* + * An UTF-8 wide cell; overwrite following padding cells only. + */ + xx = s->cx; + while (++xx < screen_size_x(s)) { + gc = grid_view_peek_cell(gd, xx, s->cy); + if (!(gc->flags & GRID_FLAG_PADDING)) + break; + grid_view_set_cell(gd, xx, s->cy, &grid_default_cell); + } + } +} diff --git a/screen.c b/screen.c new file mode 100644 index 00000000..4b355115 --- /dev/null +++ b/screen.c @@ -0,0 +1,240 @@ +/* $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 + +#include "tmux.h" + +void screen_resize_x(struct screen *, u_int); +void screen_resize_y(struct screen *, u_int); + +/* Create a new screen. */ +void +screen_init(struct screen *s, u_int sx, u_int sy, u_int hlimit) +{ + s->grid = grid_create(sx, sy, hlimit); + + s->title = xstrdup(""); + + screen_reinit(s); +} + +/* Reinitialise screen. */ +void +screen_reinit(struct screen *s) +{ + s->cx = 0; + s->cy = 0; + + s->rupper = 0; + s->rlower = screen_size_y(s) - 1; + + s->mode = MODE_CURSOR; + + grid_clear_lines(s->grid, s->grid->hsize, s->grid->sy - 1); + + screen_clear_selection(s); +} + +/* Destroy a screen. */ +void +screen_free(struct screen *s) +{ + xfree(s->title); + grid_destroy(s->grid); +} + +/* Set screen title. */ +void +screen_set_title(struct screen *s, const char *title) +{ + xfree(s->title); + s->title = xstrdup(title); +} + +/* Resize screen. */ +void +screen_resize(struct screen *s, u_int sx, u_int sy) +{ + if (sx < 1) + sx = 1; + if (sy < 1) + sy = 1; + + if (sx != screen_size_x(s)) + screen_resize_x(s, sx); + if (sy != screen_size_y(s)) + screen_resize_y(s, sy); +} + +void +screen_resize_x(struct screen *s, u_int sx) +{ + struct grid *gd = s->grid; + const struct grid_cell *gc; + const struct grid_utf8 *gu; + u_int xx, yy; + + if (sx == 0) + fatalx("zero size"); + + /* If getting larger, not much to do. */ + if (sx > screen_size_x(s)) { + gd->sx = sx; + return; + } + + /* If getting smaller, nuke any data in lines over the new size. */ + for (yy = gd->hsize; yy < gd->hsize + screen_size_y(s); yy++) { + /* + * If the character after the last is wide or padding, remove + * it and any leading padding. + */ + gc = &grid_default_cell; + for (xx = sx; xx > 0; xx--) { + gc = grid_peek_cell(gd, xx - 1, yy); + if (!(gc->flags & GRID_FLAG_PADDING)) + break; + grid_set_cell(gd, xx - 1, yy, &grid_default_cell); + } + if (xx > 0 && xx != sx && gc->flags & GRID_FLAG_UTF8) { + gu = grid_peek_utf8(gd, xx - 1, yy); + if (gu->width > 1) { + grid_set_cell( + gd, xx - 1, yy, &grid_default_cell); + } + } + + /* Reduce the line size. */ + grid_reduce_line(gd, yy, sx); + } + + if (s->cx >= sx) + s->cx = sx - 1; + gd->sx = sx; +} + +void +screen_resize_y(struct screen *s, u_int sy) +{ + struct grid *gd = s->grid; + u_int oy, yy, ny; + + if (sy == 0) + fatalx("zero size"); + + /* Size decreasing. */ + if (sy < screen_size_y(s)) { + oy = screen_size_y(s); + + if (s->cy != 0) { + /* + * The cursor is not at the start. Try to remove as + * many lines as possible from the top. (Up to the + * cursor line.) + */ + ny = s->cy; + if (ny > oy - sy) + ny = oy - sy; + + grid_view_delete_lines(gd, 0, ny); + + s->cy -= ny; + oy -= ny; + } + + if (sy < oy) { + /* Remove any remaining lines from the bottom. */ + grid_view_delete_lines(gd, sy, oy - sy); + if (s->cy >= sy) + s->cy = sy - 1; + } + } + + /* Resize line arrays. */ + gd->size = xrealloc(gd->size, gd->hsize + sy, sizeof *gd->size); + gd->data = xrealloc(gd->data, gd->hsize + sy, sizeof *gd->data); + gd->usize = xrealloc(gd->usize, gd->hsize + sy, sizeof *gd->usize); + gd->udata = xrealloc(gd->udata, gd->hsize + sy, sizeof *gd->udata); + + /* Size increasing. */ + if (sy > screen_size_y(s)) { + oy = screen_size_y(s); + for (yy = gd->hsize + oy; yy < gd->hsize + sy; yy++) { + gd->size[yy] = 0; + gd->data[yy] = NULL; + gd->usize[yy] = 0; + gd->udata[yy] = NULL; + } + } + + gd->sy = sy; + + s->rupper = 0; + s->rlower = screen_size_y(s) - 1; +} + +/* Set selection. */ +void +screen_set_selection(struct screen *s, + u_int sx, u_int sy, u_int ex, u_int ey, struct grid_cell *gc) +{ + struct screen_sel *sel = &s->sel; + + memcpy(&sel->cell, gc, sizeof sel->cell); + + sel->flag = 1; + if (ey < sy || (sy == ey && ex < sx)) { + sel->sx = ex; sel->sy = ey; + sel->ex = sx; sel->ey = sy; + } else { + sel->sx = sx; sel->sy = sy; + sel->ex = ex; sel->ey = ey; + } +} + +/* Clear selection. */ +void +screen_clear_selection(struct screen *s) +{ + struct screen_sel *sel = &s->sel; + + sel->flag = 0; +} + +/* Check if cell in selection. */ +int +screen_check_selection(struct screen *s, u_int px, u_int py) +{ + struct screen_sel *sel = &s->sel; + + if (!sel->flag || py < sel->sy || py > sel->ey) + return (0); + + if (py == sel->sy && py == sel->ey) { + if (px < sel->sx || px > sel->ex) + return (0); + return (1); + } + + if ((py == sel->sy && px < sel->sx) || (py == sel->ey && px > sel->ex)) + return (0); + return (1); +} diff --git a/server-fn.c b/server-fn.c new file mode 100644 index 00000000..69926d8e --- /dev/null +++ b/server-fn.c @@ -0,0 +1,242 @@ +/* $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 + +#include +#include + +#include "tmux.h" + +int server_lock_callback(void *, const char *); + +const char ** +server_fill_environ(struct session *s) +{ + static const char *env[] = { NULL /* TMUX= */, "TERM=screen", NULL }; + static char tmuxvar[MAXPATHLEN + 256]; + u_int idx; + + if (session_index(s, &idx) != 0) + fatalx("session not found"); + + xsnprintf(tmuxvar, sizeof tmuxvar, + "TMUX=%s,%ld,%u", socket_path, (long) getpid(), idx); + env[0] = tmuxvar; + + return (env); +} + +void +server_write_client( + struct client *c, enum hdrtype type, const void *buf, size_t len) +{ + struct hdr hdr; + + log_debug("writing %d to client %d", type, c->fd); + + hdr.type = type; + hdr.size = len; + + buffer_write(c->out, &hdr, sizeof hdr); + if (buf != NULL && len > 0) + buffer_write(c->out, buf, len); +} + +void +server_write_session( + struct session *s, enum hdrtype type, const void *buf, size_t len) +{ + struct client *c; + u_int i; + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c == NULL || c->session == NULL) + continue; + if (c->session == s) + server_write_client(c, type, buf, len); + } +} + +void +server_write_window( + struct window *w, enum hdrtype type, const void *buf, size_t len) +{ + struct client *c; + u_int i; + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c == NULL || c->session == NULL) + continue; + if (c->session->curw->window == w) + server_write_client(c, type, buf, len); + } +} + +void +server_redraw_client(struct client *c) +{ + c->flags |= CLIENT_REDRAW; +} + +void +server_status_client(struct client *c) +{ + c->flags |= CLIENT_STATUS; +} + +void +server_redraw_session(struct session *s) +{ + struct client *c; + u_int i; + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c == NULL || c->session == NULL) + continue; + if (c->session == s) + server_redraw_client(c); + } +} + +void +server_status_session(struct session *s) +{ + struct client *c; + u_int i; + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c == NULL || c->session == NULL) + continue; + if (c->session == s) + server_status_client(c); + } +} + +void +server_redraw_window(struct window *w) +{ + struct client *c; + u_int i; + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c == NULL || c->session == NULL) + continue; + if (c->session->curw->window == w) + server_redraw_client(c); + } + w->flags |= WINDOW_REDRAW; +} + +void +server_status_window(struct window *w) +{ + struct session *s; + u_int i; + + /* + * This is slightly different. We want to redraw the status line of any + * clients containing this window rather than any where it is the + * current window. + */ + + for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { + s = ARRAY_ITEM(&sessions, i); + if (s != NULL && session_has(s, w)) + server_status_session(s); + } +} + +void +server_lock(void) +{ + struct client *c; + u_int i; + + if (server_locked) + return; + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c == NULL || c->session == NULL) + continue; + + status_prompt_clear(c); + status_prompt_set( + c, "Password: ", server_lock_callback, c, PROMPT_HIDDEN); + server_redraw_client(c); + } + server_locked = 1; +} + +int +server_lock_callback(unused void *data, const char *s) +{ + return (server_unlock(s)); +} + +int +server_unlock(const char *s) +{ + struct client *c; + u_int i; + char *out; + + if (!server_locked) + return (0); + server_activity = time(NULL); + + if (server_password != NULL) { + if (s == NULL) + return (-1); + out = crypt(s, server_password); + if (strcmp(out, server_password) != 0) + goto wrong; + } + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c == NULL) + continue; + + status_prompt_clear(c); + server_redraw_client(c); + } + + server_locked = 0; + return (0); + +wrong: + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c == NULL) + continue; + + *c->prompt_buffer = '\0'; + c->prompt_index = 0; + server_status_client(c); + } + + return (-1); +} diff --git a/server-msg.c b/server-msg.c new file mode 100644 index 00000000..cff23cd5 --- /dev/null +++ b/server-msg.c @@ -0,0 +1,304 @@ +/* $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 +#include +#include +#include +#include + +#include "tmux.h" + +int server_msg_fn_command(struct hdr *, struct client *); +int server_msg_fn_identify(struct hdr *, struct client *); +int server_msg_fn_resize(struct hdr *, struct client *); +int server_msg_fn_exiting(struct hdr *, struct client *); +int server_msg_fn_unlock(struct hdr *, struct client *); +int server_msg_fn_wakeup(struct hdr *, struct client *); + +void printflike2 server_msg_fn_command_error( + struct cmd_ctx *, const char *, ...); +void printflike2 server_msg_fn_command_print( + struct cmd_ctx *, const char *, ...); +void printflike2 server_msg_fn_command_info( + struct cmd_ctx *, const char *, ...); + +struct server_msg { + enum hdrtype type; + int (*fn)(struct hdr *, struct client *); +}; +const struct server_msg server_msg_table[] = { + { MSG_IDENTIFY, server_msg_fn_identify }, + { MSG_COMMAND, server_msg_fn_command }, + { MSG_RESIZE, server_msg_fn_resize }, + { MSG_EXITING, server_msg_fn_exiting }, + { MSG_UNLOCK, server_msg_fn_unlock }, + { MSG_WAKEUP, server_msg_fn_wakeup }, +}; + +int +server_msg_dispatch(struct client *c) +{ + struct hdr hdr; + const struct server_msg *msg; + u_int i; + int n; + + for (;;) { + if (BUFFER_USED(c->in) < sizeof hdr) + return (0); + memcpy(&hdr, BUFFER_OUT(c->in), sizeof hdr); + if (BUFFER_USED(c->in) < (sizeof hdr) + hdr.size) + return (0); + buffer_remove(c->in, sizeof hdr); + + for (i = 0; i < nitems(server_msg_table); i++) { + msg = server_msg_table + i; + if (msg->type == hdr.type) { + if ((n = msg->fn(&hdr, c)) != 0) + return (n); + break; + } + } + if (i == nitems(server_msg_table)) + fatalx("unexpected message"); + } +} + +void printflike2 +server_msg_fn_command_error(struct cmd_ctx *ctx, const char *fmt, ...) +{ + va_list ap; + char *msg; + + va_start(ap, fmt); + xvasprintf(&msg, fmt, ap); + va_end(ap); + + server_write_client(ctx->cmdclient, MSG_ERROR, msg, strlen(msg)); + xfree(msg); +} + +void printflike2 +server_msg_fn_command_print(struct cmd_ctx *ctx, const char *fmt, ...) +{ + va_list ap; + char *msg; + + va_start(ap, fmt); + xvasprintf(&msg, fmt, ap); + va_end(ap); + + server_write_client(ctx->cmdclient, MSG_PRINT, msg, strlen(msg)); + xfree(msg); +} + +void printflike2 +server_msg_fn_command_info(struct cmd_ctx *ctx, const char *fmt, ...) +{ + va_list ap; + char *msg; + + if (be_quiet) + return; + + va_start(ap, fmt); + xvasprintf(&msg, fmt, ap); + va_end(ap); + + server_write_client(ctx->cmdclient, MSG_PRINT, msg, strlen(msg)); + xfree(msg); +} + +int +server_msg_fn_command(struct hdr *hdr, struct client *c) +{ + struct msg_command_data data; + struct cmd_ctx ctx; + struct cmd_list *cmdlist; + struct cmd *cmd; + + if (hdr->size < sizeof data) + fatalx("bad MSG_COMMAND size"); + buffer_read(c->in, &data, sizeof data); + + cmdlist = cmd_list_recv(c->in); + server_activity = time(NULL); + + ctx.error = server_msg_fn_command_error; + ctx.print = server_msg_fn_command_print; + ctx.info = server_msg_fn_command_info; + + ctx.msgdata = &data; + ctx.curclient = NULL; + ctx.cursession = NULL; + + ctx.cmdclient = c; + + if (data.pid != -1) { + TAILQ_FOREACH(cmd, cmdlist, qentry) { + if (cmd->entry->flags & CMD_CANTNEST) { + server_msg_fn_command_error(&ctx, + "sessions should be nested with care. " + "unset $TMUX to force"); + cmd_list_free(cmdlist); + server_write_client(c, MSG_EXIT, NULL, 0); + return (0); + } + } + } + + if (cmd_list_exec(cmdlist, &ctx) != 1) + server_write_client(c, MSG_EXIT, NULL, 0); + cmd_list_free(cmdlist); + return (0); +} + +int +server_msg_fn_identify(struct hdr *hdr, struct client *c) +{ + struct msg_identify_data data; + char *term; + + if (hdr->size < sizeof data) + fatalx("bad MSG_IDENTIFY size"); + buffer_read(c->in, &data, sizeof data); + term = cmd_recv_string(c->in); + + log_debug("identify msg from client: %u,%u (%d)", + data.sx, data.sy, data.version); + + if (data.version != PROTOCOL_VERSION) { +#define MSG "protocol version mismatch" + server_write_client(c, MSG_ERROR, MSG, (sizeof MSG) - 1); +#undef MSG + return (0); + } + + c->tty.sx = data.sx; + c->tty.sy = data.sy; + + c->cwd = NULL; + if (*data.cwd != '\0') + c->cwd = xstrdup(data.cwd); + + data.tty[(sizeof data.tty) - 1] = '\0'; + tty_init(&c->tty, data.tty, term); + if (data.flags & IDENTIFY_UTF8) + c->tty.flags |= TTY_UTF8; + if (data.flags & IDENTIFY_256COLOURS) + c->tty.term_flags |= TERM_256COLOURS; + else if (data.flags & IDENTIFY_88COLOURS) + c->tty.term_flags |= TERM_88COLOURS; + if (data.flags & IDENTIFY_HASDEFAULTS) + c->tty.term_flags |= TERM_HASDEFAULTS; + xfree(term); + + c->flags |= CLIENT_TERMINAL; + + return (0); +} + +int +server_msg_fn_resize(struct hdr *hdr, struct client *c) +{ + struct msg_resize_data data; + + if (hdr->size != sizeof data) + fatalx("bad MSG_RESIZE size"); + buffer_read(c->in, &data, sizeof data); + + log_debug("resize msg from client: %u,%u", data.sx, data.sy); + + c->tty.sx = data.sx; + if (c->tty.sx == 0) + c->tty.sx = 80; + c->tty.sy = data.sy; + if (c->tty.sy == 0) + c->tty.sy = 25; + + c->tty.cx = UINT_MAX; + c->tty.cy = UINT_MAX; + c->tty.rupper = UINT_MAX; + c->tty.rlower = UINT_MAX; + + recalculate_sizes(); + + /* Always redraw this client. */ + server_redraw_client(c); + + return (0); +} + +int +server_msg_fn_exiting(struct hdr *hdr, struct client *c) +{ + if (hdr->size != 0) + fatalx("bad MSG_EXITING size"); + + log_debug("exiting msg from client"); + + c->session = NULL; + + tty_close(&c->tty, c->flags & CLIENT_SUSPENDED); + + server_write_client(c, MSG_EXITED, NULL, 0); + + return (0); +} + +int +server_msg_fn_unlock(struct hdr *hdr, struct client *c) +{ + char *pass; + + if (hdr->size == 0) + fatalx("bad MSG_UNLOCK size"); + pass = cmd_recv_string(c->in); + + log_debug("unlock msg from client"); + + if (server_unlock(pass) != 0) { +#define MSG "bad password" + server_write_client(c, MSG_ERROR, MSG, (sizeof MSG) - 1); + server_write_client(c, MSG_EXIT, NULL, 0); + return (0); +#undef MSG + } + + server_write_client(c, MSG_EXIT, NULL, 0); + + return (0); +} + +int +server_msg_fn_wakeup(struct hdr *hdr, struct client *c) +{ + if (hdr->size != 0) + fatalx("bad MSG_WAKEUP size"); + + log_debug("wakeup msg from client"); + + c->flags &= ~CLIENT_SUSPENDED; + tty_start_tty(&c->tty); + server_redraw_client(c); + + return (0); +} diff --git a/server.c b/server.c new file mode 100644 index 00000000..67931c99 --- /dev/null +++ b/server.c @@ -0,0 +1,1105 @@ +/* $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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tmux.h" + +/* + * Main server functions. + */ + +/* Client list. */ +struct clients clients; + +int server_create_socket(void); +int server_main(int); +void server_shutdown(void); +void server_child_signal(void); +void server_fill_windows(struct pollfd **); +void server_handle_windows(struct pollfd **); +void server_fill_clients(struct pollfd **); +void server_handle_clients(struct pollfd **); +struct client *server_accept_client(int); +void server_handle_client(struct client *); +void server_handle_window(struct window *, struct window_pane *); +int server_check_window_bell(struct session *, struct window *, + struct window_pane *); +int server_check_window_activity(struct session *, + struct window *); +int server_check_window_content(struct session *, struct window *, + struct window_pane *); +void server_lost_client(struct client *); +void server_check_window(struct window *); +void server_check_redraw(struct client *); +void server_redraw_locked(struct client *); +void server_check_timers(struct client *); +void server_second_timers(void); +int server_update_socket(void); + +/* Create a new client. */ +struct client * +server_create_client(int fd) +{ + struct client *c; + int mode; + u_int i; + + if ((mode = fcntl(fd, F_GETFL)) == -1) + fatal("fcntl failed"); + if (fcntl(fd, F_SETFL, mode|O_NONBLOCK) == -1) + fatal("fcntl failed"); + if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) + fatal("fcntl failed"); + + c = xcalloc(1, sizeof *c); + c->fd = fd; + c->in = buffer_create(BUFSIZ); + c->out = buffer_create(BUFSIZ); + + ARRAY_INIT(&c->prompt_hdata); + + c->tty.fd = -1; + c->title = NULL; + + c->session = NULL; + c->tty.sx = 80; + c->tty.sy = 25; + screen_init(&c->status, c->tty.sx, 1, 0); + + c->message_string = NULL; + + c->prompt_string = NULL; + c->prompt_buffer = NULL; + c->prompt_index = 0; + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + if (ARRAY_ITEM(&clients, i) == NULL) { + ARRAY_SET(&clients, i, c); + return (c); + } + } + ARRAY_ADD(&clients, c); + return (c); +} + +/* Find client index. */ +int +server_client_index(struct client *c) +{ + u_int i; + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + if (c == ARRAY_ITEM(&clients, i)) + return (i); + } + return (-1); +} + +/* Fork new server. */ +int +server_start(char *path) +{ + int pair[2], srv_fd; + char *cause; + char rpathbuf[MAXPATHLEN]; + + /* The first client is special and gets a socketpair; create it. */ + if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) != 0) + fatal("socketpair failed"); + + switch (fork()) { + case -1: + fatal("fork failed"); + case 0: + break; + default: + close(pair[1]); + return (pair[0]); + } + close(pair[0]); + + /* + * Must daemonise before loading configuration as the PID changes so + * $TMUX would be wrong for sessions created in the config file. + */ + if (daemon(1, 1) != 0) + fatal("daemon failed"); + + ARRAY_INIT(&windows); + ARRAY_INIT(&clients); + ARRAY_INIT(&sessions); + key_bindings_init(); + utf8_build(); + + server_locked = 0; + server_password = NULL; + server_activity = time(NULL); + + start_time = time(NULL); + socket_path = path; + + if (cfg_file != NULL && load_cfg(cfg_file, &cause) != 0) { + log_warnx("%s", cause); + exit(1); + } + logfile("server"); + + log_debug("server started, pid %ld", (long) getpid()); + log_debug("socket path %s", socket_path); + + if (realpath(socket_path, rpathbuf) == NULL) + strlcpy(rpathbuf, socket_path, sizeof rpathbuf); + setproctitle("server (%s)", rpathbuf); + + srv_fd = server_create_socket(); + server_create_client(pair[1]); + + exit(server_main(srv_fd)); +} + +/* Create server socket. */ +int +server_create_socket(void) +{ + struct sockaddr_un sa; + size_t size; + mode_t mask; + int fd, mode; + + memset(&sa, 0, sizeof sa); + sa.sun_family = AF_UNIX; + size = strlcpy(sa.sun_path, socket_path, sizeof sa.sun_path); + if (size >= sizeof sa.sun_path) { + errno = ENAMETOOLONG; + fatal("socket failed"); + } + unlink(sa.sun_path); + + if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) + fatal("socket failed"); + + mask = umask(S_IXUSR|S_IRWXG|S_IRWXO); + if (bind(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1) + fatal("bind failed"); + umask(mask); + + if (listen(fd, 16) == -1) + fatal("listen failed"); + + if ((mode = fcntl(fd, F_GETFL)) == -1) + fatal("fcntl failed"); + if (fcntl(fd, F_SETFL, mode|O_NONBLOCK) == -1) + fatal("fcntl failed"); + if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) + fatal("fcntl failed"); + + return (fd); +} + +/* Main server loop. */ +int +server_main(int srv_fd) +{ + struct window *w; + struct pollfd *pfds, *pfd; + int nfds, xtimeout; + u_int i, n; + time_t now, last; + + siginit(); + + last = time(NULL); + + pfds = NULL; + for (;;) { + /* If sigterm, kill all windows and clients. */ + if (sigterm) + server_shutdown(); + + /* Handle child exit. */ + if (sigchld) { + server_child_signal(); + sigchld = 0; + } + + /* Recreate socket on SIGUSR1. */ + if (sigusr1) { + close(srv_fd); + srv_fd = server_create_socket(); + sigusr1 = 0; + } + + /* Initialise pollfd array. */ + nfds = 1; + for (i = 0; i < ARRAY_LENGTH(&windows); i++) { + w = ARRAY_ITEM(&windows, i); + if (w != NULL) + nfds += window_count_panes(w); + } + nfds += ARRAY_LENGTH(&clients) * 2; + pfds = xrealloc(pfds, nfds, sizeof *pfds); + memset(pfds, 0, nfds * sizeof *pfds); + pfd = pfds; + + /* Fill server socket. */ + pfd->fd = srv_fd; + pfd->events = POLLIN; + pfd++; + + /* Fill window and client sockets. */ + server_fill_windows(&pfd); + server_fill_clients(&pfd); + + /* Update socket permissions. */ + xtimeout = INFTIM; + if (sigterm || server_update_socket() != 0) + xtimeout = POLL_TIMEOUT; + + /* Do the poll. */ + if ((nfds = poll(pfds, nfds, xtimeout)) == -1) { + if (errno == EAGAIN || errno == EINTR) + continue; + fatal("poll failed"); + } + pfd = pfds; + + /* Handle server socket. */ + if (pfd->revents & (POLLERR|POLLNVAL|POLLHUP)) + fatalx("lost server socket"); + if (pfd->revents & POLLIN) { + server_accept_client(srv_fd); + continue; + } + pfd++; + + /* Call second-based timers. */ + now = time(NULL); + if (now != last) { + last = now; + server_second_timers(); + } + + /* Set window names. */ + set_window_names(); + + /* + * Handle window and client sockets. Clients can create + * windows, so windows must come first to avoid messing up by + * increasing the array size. + */ + server_handle_windows(&pfd); + server_handle_clients(&pfd); + + /* + * If we have no sessions and clients left, let's get out + * of here... + */ + n = 0; + for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { + if (ARRAY_ITEM(&sessions, i) != NULL) + n++; + } + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + if (ARRAY_ITEM(&clients, i) != NULL) + n++; + } + if (n == 0) + break; + } + if (pfds != NULL) + xfree(pfds); + + for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { + if (ARRAY_ITEM(&sessions, i) != NULL) + session_destroy(ARRAY_ITEM(&sessions, i)); + } + ARRAY_FREE(&sessions); + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + if (ARRAY_ITEM(&clients, i) != NULL) + server_lost_client(ARRAY_ITEM(&clients, i)); + } + ARRAY_FREE(&clients); + + key_bindings_free(); + + close(srv_fd); + + unlink(socket_path); + xfree(socket_path); + + options_free(&global_options); + options_free(&global_window_options); + if (server_password != NULL) + xfree(server_password); + + return (0); +} + +/* Kill all clients. */ +void +server_shutdown(void) +{ + struct session *s; + struct client *c; + u_int i, j; + + for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { + s = ARRAY_ITEM(&sessions, i); + for (j = 0; j < ARRAY_LENGTH(&clients); j++) { + c = ARRAY_ITEM(&clients, j); + if (c != NULL && c->session == s) { + s = NULL; + break; + } + } + if (s != NULL) + session_destroy(s); + } + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c != NULL) + server_write_client(c, MSG_SHUTDOWN, NULL, 0); + } +} + +/* Handle SIGCHLD. */ +void +server_child_signal(void) +{ + struct window *w; + struct window_pane *wp; + int status; + pid_t pid; + u_int i; + + for (;;) { + switch (pid = waitpid(WAIT_ANY, &status, WNOHANG|WUNTRACED)) { + case -1: + if (errno == ECHILD) + return; + fatal("waitpid"); + case 0: + return; + } + if (!WIFSTOPPED(status)) + continue; + if (WSTOPSIG(status) == SIGTTIN || WSTOPSIG(status) == SIGTTOU) + continue; + + for (i = 0; i < ARRAY_LENGTH(&windows); i++) { + w = ARRAY_ITEM(&windows, i); + if (w == NULL) + continue; + TAILQ_FOREACH(wp, &w->panes, entry) { + if (wp->pid == pid) { + if (killpg(pid, SIGCONT) != 0) + kill(pid, SIGCONT); + } + } + } + } +} + +/* Fill window pollfds. */ +void +server_fill_windows(struct pollfd **pfd) +{ + struct window *w; + struct window_pane *wp; + u_int i; + + for (i = 0; i < ARRAY_LENGTH(&windows); i++) { + w = ARRAY_ITEM(&windows, i); + if (w == NULL) + continue; + + TAILQ_FOREACH(wp, &w->panes, entry) { + (*pfd)->fd = wp->fd; + if (wp->fd != -1) { + (*pfd)->events = POLLIN; + if (BUFFER_USED(wp->out) > 0) + (*pfd)->events |= POLLOUT; + } + (*pfd)++; + } + } +} + +/* Handle window pollfds. */ +void +server_handle_windows(struct pollfd **pfd) +{ + struct window *w; + struct window_pane *wp; + u_int i; + + for (i = 0; i < ARRAY_LENGTH(&windows); i++) { + w = ARRAY_ITEM(&windows, i); + if (w == NULL) + continue; + + TAILQ_FOREACH(wp, &w->panes, entry) { + if (wp->fd != -1) { + if (buffer_poll(*pfd, wp->in, wp->out) != 0) { + close(wp->fd); + wp->fd = -1; + } else + server_handle_window(w, wp); + } + (*pfd)++; + } + + server_check_window(w); + } +} + +/* Check for general redraw on client. */ +void +server_check_redraw(struct client *c) +{ + struct session *s; + struct window_pane *wp; + char title[512]; + int flags, redraw; + + if (c == NULL || c->session == NULL) + return; + s = c->session; + + flags = c->tty.flags & TTY_FREEZE; + c->tty.flags &= ~TTY_FREEZE; + + if (options_get_number(&s->options, "set-titles")) { + xsnprintf(title, sizeof title, "%s:%u:%s - \"%s\"", + s->name, s->curw->idx, s->curw->window->name, + s->curw->window->active->screen->title); + if (c->title == NULL || strcmp(title, c->title) != 0) { + if (c->title != NULL) + xfree(c->title); + c->title = xstrdup(title); + tty_set_title(&c->tty, c->title); + } + } + + if (c->flags & (CLIENT_REDRAW|CLIENT_STATUS)) { + if (c->message_string != NULL) + redraw = status_message_redraw(c); + else if (c->prompt_string != NULL) + redraw = status_prompt_redraw(c); + else + redraw = status_redraw(c); + if (!redraw) + c->flags &= ~CLIENT_STATUS; + } + + if (c->flags & CLIENT_REDRAW) { + if (server_locked) + server_redraw_locked(c); + else + screen_redraw_screen(c); + c->flags &= ~CLIENT_STATUS; + } else { + TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry) { + if (wp->flags & PANE_REDRAW) + screen_redraw_pane(c, wp); + } + } + + if (c->flags & CLIENT_STATUS) + screen_redraw_status(c); + + c->tty.flags |= flags; + + c->flags &= ~(CLIENT_REDRAW|CLIENT_STATUS); +} + +/* Redraw client when locked. */ +void +server_redraw_locked(struct client *c) +{ + struct screen_write_ctx ctx; + struct screen screen; + u_int colour, xx, yy, i; + int style; + + xx = c->tty.sx; + yy = c->tty.sy - 1; + if (xx == 0 || yy == 0) + return; + colour = options_get_number( + &global_window_options, "clock-mode-colour"); + style = options_get_number( + &global_window_options, "clock-mode-style"); + + screen_init(&screen, xx, yy, 0); + + screen_write_start(&ctx, NULL, &screen); + clock_draw(&ctx, colour, style); + screen_write_stop(&ctx); + + for (i = 0; i < screen_size_y(&screen); i++) + tty_draw_line(&c->tty, &screen, i, 0, 0); + screen_redraw_status(c); + + screen_free(&screen); +} + +/* Check for timers on client. */ +void +server_check_timers(struct client *c) +{ + struct session *s; + struct timeval tv; + u_int interval; + + if (c == NULL || c->session == NULL) + return; + s = c->session; + + if (gettimeofday(&tv, NULL) != 0) + fatal("gettimeofday"); + + if (c->message_string != NULL && timercmp(&tv, &c->message_timer, >)) + status_message_clear(c); + + if (c->message_string != NULL || c->prompt_string != NULL) { + /* + * Don't need timed redraw for messages/prompts so bail now. + * The status timer isn't reset when they are redrawn anyway. + */ + return; + } + if (!options_get_number(&s->options, "status")) + return; + + /* Check timer; resolution is only a second so don't be too clever. */ + interval = options_get_number(&s->options, "status-interval"); + if (interval == 0) + return; + if (tv.tv_sec < c->status_timer.tv_sec || + ((u_int) tv.tv_sec) - c->status_timer.tv_sec >= interval) + c->flags |= CLIENT_STATUS; +} + +/* Fill client pollfds. */ +void +server_fill_clients(struct pollfd **pfd) +{ + struct client *c; + struct window *w; + struct window_pane *wp; + u_int i; + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + + server_check_timers(c); + server_check_redraw(c); + + if (c == NULL) + (*pfd)->fd = -1; + else { + (*pfd)->fd = c->fd; + (*pfd)->events = POLLIN; + if (BUFFER_USED(c->out) > 0) + (*pfd)->events |= POLLOUT; + } + (*pfd)++; + + if (c == NULL || c->flags & CLIENT_SUSPENDED || + c->tty.fd == -1 || c->session == NULL) + (*pfd)->fd = -1; + else { + (*pfd)->fd = c->tty.fd; + (*pfd)->events = POLLIN; + if (BUFFER_USED(c->tty.out) > 0) + (*pfd)->events |= POLLOUT; + } + (*pfd)++; + } + + /* + * Clear any window redraw flags (will have been redrawn as part of + * client). + */ + for (i = 0; i < ARRAY_LENGTH(&windows); i++) { + w = ARRAY_ITEM(&windows, i); + if (w == NULL) + continue; + + w->flags &= ~WINDOW_REDRAW; + TAILQ_FOREACH(wp, &w->panes, entry) + wp->flags &= ~PANE_REDRAW; + } +} + +/* Handle client pollfds. */ +void +server_handle_clients(struct pollfd **pfd) +{ + struct client *c; + u_int i; + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + + if (c != NULL) { + if (buffer_poll(*pfd, c->in, c->out) != 0) { + server_lost_client(c); + (*pfd) += 2; + continue; + } else + server_msg_dispatch(c); + } + (*pfd)++; + + if (c != NULL && !(c->flags & CLIENT_SUSPENDED) && + c->tty.fd != -1 && c->session != NULL) { + if (buffer_poll(*pfd, c->tty.in, c->tty.out) != 0) + server_lost_client(c); + else + server_handle_client(c); + } + (*pfd)++; + } +} + +/* accept(2) and create new client. */ +struct client * +server_accept_client(int srv_fd) +{ + struct sockaddr_storage sa; + socklen_t slen = sizeof sa; + int fd; + + fd = accept(srv_fd, (struct sockaddr *) &sa, &slen); + if (fd == -1) { + if (errno == EAGAIN || errno == EINTR || errno == ECONNABORTED) + return (NULL); + fatal("accept failed"); + } + if (sigterm) { + close(fd); + return (NULL); + } + return (server_create_client(fd)); +} + +/* Input data from client. */ +void +server_handle_client(struct client *c) +{ + struct window_pane *wp; + struct screen *s; + struct timeval tv; + struct key_binding *bd; + int key, prefix, status, xtimeout; + int mode; + u_char mouse[3]; + + xtimeout = options_get_number(&c->session->options, "repeat-time"); + if (xtimeout != 0 && c->flags & CLIENT_REPEAT) { + if (gettimeofday(&tv, NULL) != 0) + fatal("gettimeofday"); + if (timercmp(&tv, &c->repeat_timer, >)) + c->flags &= ~(CLIENT_PREFIX|CLIENT_REPEAT); + } + + /* Process keys. */ + prefix = options_get_number(&c->session->options, "prefix"); + while (tty_keys_next(&c->tty, &key, mouse) == 0) { + server_activity = time(NULL); + + if (c->session == NULL) + return; + wp = c->session->curw->window->active; /* could die */ + + status_message_clear(c); + if (c->prompt_string != NULL) { + status_prompt_key(c, key); + continue; + } + if (server_locked) + continue; + + /* Check for mouse keys. */ + if (key == KEYC_MOUSE) { + window_pane_mouse(wp, c, mouse[0], mouse[1], mouse[2]); + continue; + } + + /* No previous prefix key. */ + if (!(c->flags & CLIENT_PREFIX)) { + if (key == prefix) + c->flags |= CLIENT_PREFIX; + else + window_pane_key(wp, c, key); + continue; + } + + /* Prefix key already pressed. Reset prefix and lookup key. */ + c->flags &= ~CLIENT_PREFIX; + if ((bd = key_bindings_lookup(key)) == NULL) { + /* If repeating, treat this as a key, else ignore. */ + if (c->flags & CLIENT_REPEAT) { + c->flags &= ~CLIENT_REPEAT; + if (key == prefix) + c->flags |= CLIENT_PREFIX; + else + window_pane_key(wp, c, key); + } + continue; + } + + /* If already repeating, but this key can't repeat, skip it. */ + if (c->flags & CLIENT_REPEAT && !bd->can_repeat) { + c->flags &= ~CLIENT_REPEAT; + if (key == prefix) + c->flags |= CLIENT_PREFIX; + else + window_pane_key(wp, c, key); + continue; + } + + /* If this key can repeat, reset the repeat flags and timer. */ + if (xtimeout != 0 && bd->can_repeat) { + c->flags |= CLIENT_PREFIX|CLIENT_REPEAT; + + tv.tv_sec = xtimeout / 1000; + tv.tv_usec = (xtimeout % 1000) * 1000L; + if (gettimeofday(&c->repeat_timer, NULL) != 0) + fatal("gettimeofday"); + timeradd(&c->repeat_timer, &tv, &c->repeat_timer); + } + + /* Dispatch the command. */ + key_bindings_dispatch(bd, c); + } + if (c->session == NULL) + return; + wp = c->session->curw->window->active; /* could die - do each loop */ + s = wp->screen; + + /* Ensure cursor position and mode settings. */ + status = options_get_number(&c->session->options, "status"); + if (wp->yoff + s->cy < c->tty.sy - status) + tty_cursor(&c->tty, s->cx, s->cy, wp->xoff, wp->yoff); + + mode = s->mode; + if (server_locked) + mode &= ~TTY_NOCURSOR; + tty_update_mode(&c->tty, mode); +} + +/* Lost a client. */ +void +server_lost_client(struct client *c) +{ + u_int i; + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + if (ARRAY_ITEM(&clients, i) == c) + ARRAY_SET(&clients, i, NULL); + } + + tty_free(&c->tty, c->flags & CLIENT_SUSPENDED); + + screen_free(&c->status); + + if (c->title != NULL) + xfree(c->title); + + if (c->message_string != NULL) + xfree(c->message_string); + + if (c->prompt_string != NULL) + xfree(c->prompt_string); + if (c->prompt_buffer != NULL) + xfree(c->prompt_buffer); + for (i = 0; i < ARRAY_LENGTH(&c->prompt_hdata); i++) + xfree(ARRAY_ITEM(&c->prompt_hdata, i)); + ARRAY_FREE(&c->prompt_hdata); + + if (c->cwd != NULL) + xfree(c->cwd); + + close(c->fd); + buffer_destroy(c->in); + buffer_destroy(c->out); + xfree(c); + + recalculate_sizes(); +} + +/* Handle window data. */ +void +server_handle_window(struct window *w, struct window_pane *wp) +{ + struct session *s; + u_int i; + int update; + + window_pane_parse(wp); + + if ((w->flags & (WINDOW_BELL|WINDOW_ACTIVITY|WINDOW_CONTENT)) == 0) + return; + + update = 0; + for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { + s = ARRAY_ITEM(&sessions, i); + if (s == NULL || !session_has(s, w)) + continue; + + update += server_check_window_bell(s, w, wp); + update += server_check_window_activity(s, w); + update += server_check_window_content(s, w, wp); + } + if (update) + server_status_window(w); + + w->flags &= ~(WINDOW_BELL|WINDOW_ACTIVITY|WINDOW_CONTENT); +} + +int +server_check_window_bell( + struct session *s, struct window *w, struct window_pane *wp) +{ + struct client *c; + u_int i; + int action; + + if (!(w->flags & WINDOW_BELL)) + return (0); + if (session_alert_has_window(s, w, WINDOW_BELL)) + return (0); + session_alert_add(s, w, WINDOW_BELL); + + action = options_get_number(&s->options, "bell-action"); + switch (action) { + case BELL_ANY: + if (s->flags & SESSION_UNATTACHED) + break; + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c != NULL && c->session == s) + tty_putcode(&c->tty, TTYC_BEL); + } + break; + case BELL_CURRENT: + if (w->active != wp) + break; + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c != NULL && c->session == s) + tty_putcode(&c->tty, TTYC_BEL); + } + break; + } + return (1); +} + +int +server_check_window_activity(struct session *s, struct window *w) +{ + if (!(w->flags & WINDOW_ACTIVITY)) + return (0); + if (!options_get_number(&w->options, "monitor-activity")) + return (0); + if (session_alert_has_window(s, w, WINDOW_ACTIVITY)) + return (0); + session_alert_add(s, w, WINDOW_ACTIVITY); + return (1); +} + +int +server_check_window_content( + struct session *s, struct window *w, struct window_pane *wp) +{ + char *found, *ptr; + + if (!(w->flags & WINDOW_CONTENT)) + return (0); + if ((ptr = options_get_string(&w->options, "monitor-content")) == NULL) + return (0); + if (*ptr == '\0') + return (0); + if (session_alert_has_window(s, w, WINDOW_CONTENT)) + return (0); + if ((found = window_pane_search(wp, ptr)) == NULL) + return (0); + session_alert_add(s, w, WINDOW_CONTENT); + xfree(found); + return (1); +} + +/* Check if window still exists.. */ +void +server_check_window(struct window *w) +{ + struct window_pane *wp, *wq; + struct client *c; + struct session *s; + struct winlink *wl; + u_int i, j; + int destroyed, flag; + + flag = options_get_number(&w->options, "remain-on-exit"); + + destroyed = 1; + + wp = TAILQ_FIRST(&w->panes); + while (wp != NULL) { + wq = TAILQ_NEXT(wp, entry); + if (wp->fd != -1) + destroyed = 0; + else if (!flag) { + window_remove_pane(w, wp); + server_redraw_window(w); + layout_refresh(w, 0); + } + wp = wq; + } + + if (!destroyed) + return; + + for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { + s = ARRAY_ITEM(&sessions, i); + if (s == NULL) + continue; + if (!session_has(s, w)) + continue; + + restart: + /* Detach window and either redraw or kill clients. */ + RB_FOREACH(wl, winlinks, &s->windows) { + if (wl->window != w) + continue; + destroyed = session_detach(s, wl); + for (j = 0; j < ARRAY_LENGTH(&clients); j++) { + c = ARRAY_ITEM(&clients, j); + if (c == NULL || c->session != s) + continue; + if (!destroyed) { + server_redraw_client(c); + continue; + } + c->session = NULL; + server_write_client(c, MSG_EXIT, NULL, 0); + } + /* If the session was destroyed, bail now. */ + if (destroyed) + break; + goto restart; + } + } + + recalculate_sizes(); +} + +/* Call any once-per-second timers. */ +void +server_second_timers(void) +{ + struct window *w; + struct window_pane *wp; + u_int i; + int xtimeout; + struct tm now, then; + static time_t last_t = 0; + time_t t; + + t = time(NULL); + xtimeout = options_get_number(&global_options, "lock-after-time"); + if (xtimeout > 0 && t > server_activity + xtimeout) + server_lock(); + + for (i = 0; i < ARRAY_LENGTH(&windows); i++) { + w = ARRAY_ITEM(&windows, i); + if (w == NULL) + continue; + + TAILQ_FOREACH(wp, &w->panes, entry) { + if (wp->mode != NULL && wp->mode->timer != NULL) + wp->mode->timer(wp); + } + } + + /* Check for a minute having passed. */ + gmtime_r(&t, &now); + gmtime_r(&last_t, &then); + if (now.tm_min == then.tm_min) + return; + last_t = t; + + /* If locked, redraw all clients. */ + if (server_locked) { + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + if (ARRAY_ITEM(&clients, i) != NULL) + server_redraw_client(ARRAY_ITEM(&clients, i)); + } + } +} + +/* Update socket execute permissions based on whether sessions are attached. */ +int +server_update_socket(void) +{ + struct session *s; + u_int i; + static int last = -1; + int n; + + n = 0; + for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { + s = ARRAY_ITEM(&sessions, i); + if (s != NULL && !(s->flags & SESSION_UNATTACHED)) { + n++; + break; + } + } + + if (n != last) { + last = n; + if (n != 0) + chmod(socket_path, S_IRWXU); + else + chmod(socket_path, S_IRUSR|S_IWUSR); + } + + return (n); +} diff --git a/session.c b/session.c new file mode 100644 index 00000000..3b65127c --- /dev/null +++ b/session.c @@ -0,0 +1,378 @@ +/* $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 + +#include +#include +#include + +#include "tmux.h" + +/* Global session list. */ +struct sessions sessions; + +struct winlink *session_next_activity(struct session *, struct winlink *); +struct winlink *session_previous_activity(struct session *, struct winlink *); + +void +session_alert_cancel(struct session *s, struct winlink *wl) +{ + struct session_alert *sa, *sb; + + sa = SLIST_FIRST(&s->alerts); + while (sa != NULL) { + sb = sa; + sa = SLIST_NEXT(sa, entry); + + if (wl == NULL || sb->wl == wl) { + SLIST_REMOVE(&s->alerts, sb, session_alert, entry); + xfree(sb); + } + } +} + +void +session_alert_add(struct session *s, struct window *w, int type) +{ + struct session_alert *sa; + struct winlink *wl; + + RB_FOREACH(wl, winlinks, &s->windows) { + if (wl == s->curw) + continue; + + if (wl->window == w && + !session_alert_has(s, wl, type)) { + sa = xmalloc(sizeof *sa); + sa->wl = wl; + sa->type = type; + SLIST_INSERT_HEAD(&s->alerts, sa, entry); + } + } +} + +int +session_alert_has(struct session *s, struct winlink *wl, int type) +{ + struct session_alert *sa; + + SLIST_FOREACH(sa, &s->alerts, entry) { + if (sa->wl == wl && sa->type == type) + return (1); + } + + return (0); +} + +int +session_alert_has_window(struct session *s, struct window *w, int type) +{ + struct session_alert *sa; + + SLIST_FOREACH(sa, &s->alerts, entry) { + if (sa->wl->window == w && sa->type == type) + return (1); + } + + return (0); +} + +/* Find session by name. */ +struct session * +session_find(const char *name) +{ + struct session *s; + u_int i; + + for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { + s = ARRAY_ITEM(&sessions, i); + if (s != NULL && strcmp(s->name, name) == 0) + return (s); + } + + return (NULL); +} + +/* Create a new session. */ +struct session * +session_create(const char *name, + const char *cmd, const char *cwd, u_int sx, u_int sy, char **cause) +{ + struct session *s; + u_int i; + + s = xmalloc(sizeof *s); + s->flags = 0; + if (gettimeofday(&s->tv, NULL) != 0) + fatal("gettimeofday"); + s->curw = NULL; + SLIST_INIT(&s->lastw); + RB_INIT(&s->windows); + SLIST_INIT(&s->alerts); + paste_init_stack(&s->buffers); + options_init(&s->options, &global_options); + + s->sx = sx; + s->sy = sy; + + for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { + if (ARRAY_ITEM(&sessions, i) == NULL) { + ARRAY_SET(&sessions, i, s); + break; + } + } + if (i == ARRAY_LENGTH(&sessions)) + ARRAY_ADD(&sessions, s); + + if (name != NULL) + s->name = xstrdup(name); + else + xasprintf(&s->name, "%u", i); + if (session_new(s, NULL, cmd, cwd, -1, cause) == NULL) { + session_destroy(s); + return (NULL); + } + session_select(s, 0); + + log_debug("session %s created", s->name); + + return (s); +} + +/* Destroy a session. */ +void +session_destroy(struct session *s) +{ + u_int i; + + log_debug("session %s destroyed", s->name); + + if (session_index(s, &i) != 0) + fatalx("session not found"); + ARRAY_SET(&sessions, i, NULL); + while (!ARRAY_EMPTY(&sessions) && ARRAY_LAST(&sessions) == NULL) + ARRAY_TRUNC(&sessions, 1); + + session_alert_cancel(s, NULL); + options_free(&s->options); + paste_free_stack(&s->buffers); + + while (!SLIST_EMPTY(&s->lastw)) + winlink_stack_remove(&s->lastw, SLIST_FIRST(&s->lastw)); + while (!RB_EMPTY(&s->windows)) + winlink_remove(&s->windows, RB_ROOT(&s->windows)); + + xfree(s->name); + xfree(s); +} + +/* Find session index. */ +int +session_index(struct session *s, u_int *i) +{ + for (*i = 0; *i < ARRAY_LENGTH(&sessions); (*i)++) { + if (s == ARRAY_ITEM(&sessions, *i)) + return (0); + } + return (-1); +} + +/* Create a new window on a session. */ +struct winlink * +session_new(struct session *s, + const char *name, const char *cmd, const char *cwd, int idx, char **cause) +{ + struct window *w; + const char **env; + u_int hlimit; + + env = server_fill_environ(s); + + hlimit = options_get_number(&s->options, "history-limit"); + w = window_create(name, cmd, cwd, env, s->sx, s->sy, hlimit, cause); + if (w == NULL) + return (NULL); + + if (options_get_number(&s->options, "set-remain-on-exit")) + options_set_number(&w->options, "remain-on-exit", 1); + + return (session_attach(s, w, idx, cause)); +} + +/* Attach a window to a session. */ +struct winlink * +session_attach(struct session *s, struct window *w, int idx, char **cause) +{ + struct winlink *wl; + + if ((wl = winlink_add(&s->windows, w, idx)) == NULL) + xasprintf(cause, "index in use: %d", idx); + return (wl); +} + +/* Detach a window from a session. */ +int +session_detach(struct session *s, struct winlink *wl) +{ + if (s->curw == wl && + session_last(s) != 0 && session_previous(s, 0) != 0) + session_next(s, 0); + + session_alert_cancel(s, wl); + winlink_stack_remove(&s->lastw, wl); + winlink_remove(&s->windows, wl); + if (RB_EMPTY(&s->windows)) { + session_destroy(s); + return (1); + } + return (0); +} + +/* Return if session has window. */ +int +session_has(struct session *s, struct window *w) +{ + struct winlink *wl; + + RB_FOREACH(wl, winlinks, &s->windows) { + if (wl->window == w) + return (1); + } + return (0); +} + +struct winlink * +session_next_activity(struct session *s, struct winlink *wl) +{ + while (wl != NULL) { + if (session_alert_has(s, wl, WINDOW_BELL)) + break; + if (session_alert_has(s, wl, WINDOW_ACTIVITY)) + break; + if (session_alert_has(s, wl, WINDOW_CONTENT)) + break; + wl = winlink_next(&s->windows, wl); + } + return (wl); +} + +/* Move session to next window. */ +int +session_next(struct session *s, int activity) +{ + struct winlink *wl; + + if (s->curw == NULL) + return (-1); + + wl = winlink_next(&s->windows, s->curw); + if (activity) + wl = session_next_activity(s, wl); + if (wl == NULL) { + wl = RB_MIN(winlinks, &s->windows); + if (activity && ((wl = session_next_activity(s, wl)) == NULL)) + return (-1); + } + if (wl == s->curw) + return (1); + winlink_stack_remove(&s->lastw, wl); + winlink_stack_push(&s->lastw, s->curw); + s->curw = wl; + session_alert_cancel(s, wl); + return (0); +} + +struct winlink * +session_previous_activity(struct session *s, struct winlink *wl) +{ + while (wl != NULL) { + if (session_alert_has(s, wl, WINDOW_BELL)) + break; + if (session_alert_has(s, wl, WINDOW_ACTIVITY)) + break; + if (session_alert_has(s, wl, WINDOW_CONTENT)) + break; + wl = winlink_previous(&s->windows, wl); + } + return (wl); +} + +/* Move session to previous window. */ +int +session_previous(struct session *s, int activity) +{ + struct winlink *wl; + + if (s->curw == NULL) + return (-1); + + wl = winlink_previous(&s->windows, s->curw); + if (activity) + wl = session_previous_activity(s, wl); + if (wl == NULL) { + wl = RB_MAX(winlinks, &s->windows); + if (activity && (wl = session_previous_activity(s, wl)) == NULL) + return (-1); + } + if (wl == s->curw) + return (1); + winlink_stack_remove(&s->lastw, wl); + winlink_stack_push(&s->lastw, s->curw); + s->curw = wl; + session_alert_cancel(s, wl); + return (0); +} + +/* Move session to specific window. */ +int +session_select(struct session *s, int idx) +{ + struct winlink *wl; + + wl = winlink_find_by_index(&s->windows, idx); + if (wl == NULL) + return (-1); + if (wl == s->curw) + return (1); + winlink_stack_remove(&s->lastw, wl); + winlink_stack_push(&s->lastw, s->curw); + s->curw = wl; + session_alert_cancel(s, wl); + return (0); +} + +/* Move session to last used window. */ +int +session_last(struct session *s) +{ + struct winlink *wl; + + wl = SLIST_FIRST(&s->lastw); + if (wl == NULL) + return (-1); + if (wl == s->curw) + return (1); + + winlink_stack_remove(&s->lastw, wl); + winlink_stack_push(&s->lastw, s->curw); + s->curw = wl; + session_alert_cancel(s, wl); + return (0); +} diff --git a/status.c b/status.c new file mode 100644 index 00000000..a72e5a26 --- /dev/null +++ b/status.c @@ -0,0 +1,960 @@ +/* $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 + +#include +#include +#include +#include +#include +#include +#include + +#include "tmux.h" + +char *status_replace(struct session *, char *, time_t); +char *status_replace_popen(char **); +size_t status_width(struct winlink *); +char *status_print(struct session *, struct winlink *, struct grid_cell *); + +void status_prompt_add_history(struct client *); +char *status_prompt_complete(const char *); + +/* Draw status for client on the last lines of given context. */ +int +status_redraw(struct client *c) +{ + struct screen_write_ctx ctx; + struct session *s = c->session; + struct winlink *wl; + struct window_pane *wp; + struct screen *sc = NULL, old_status; + char *left, *right, *text, *ptr; + size_t llen, rlen, offset, xx, yy, sy; + size_t size, start, width; + struct grid_cell stdgc, gc; + int larrow, rarrow; + + left = right = NULL; + + /* Create the target screen. */ + memcpy(&old_status, &c->status, sizeof old_status); + screen_init(&c->status, c->tty.sx, 1, 0); + + /* No status line? */ + if (c->tty.sy == 0 || !options_get_number(&s->options, "status")) + goto off; + larrow = rarrow = 0; + + if (gettimeofday(&c->status_timer, NULL) != 0) + fatal("gettimeofday"); + memcpy(&stdgc, &grid_default_cell, sizeof gc); + stdgc.bg = options_get_number(&s->options, "status-fg"); + stdgc.fg = options_get_number(&s->options, "status-bg"); + stdgc.attr |= options_get_number(&s->options, "status-attr"); + + yy = c->tty.sy - 1; + if (yy == 0) + goto blank; + + /* Work out the left and right strings. */ + left = status_replace(s, options_get_string( + &s->options, "status-left"), c->status_timer.tv_sec); + llen = options_get_number(&s->options, "status-left-length"); + if (strlen(left) < llen) + llen = strlen(left); + left[llen] = '\0'; + + right = status_replace(s, options_get_string( + &s->options, "status-right"), c->status_timer.tv_sec); + rlen = options_get_number(&s->options, "status-right-length"); + if (strlen(right) < rlen) + rlen = strlen(right); + right[rlen] = '\0'; + + /* + * Figure out how much space we have for the window list. If there isn't + * enough space, just wimp out. + */ + xx = 0; + if (llen != 0) + xx += llen + 1; + if (rlen != 0) + xx += rlen + 1; + if (c->tty.sx == 0 || c->tty.sx <= xx) + goto blank; + xx = c->tty.sx - xx; + + /* + * Right. We have xx characters to fill. Find out how much is to go in + * them and the offset of the current window (it must be on screen). + */ + width = offset = 0; + RB_FOREACH(wl, winlinks, &s->windows) { + size = status_width(wl) + 1; + if (wl == s->curw) + offset = width; + width += size; + } + start = 0; + + /* If there is enough space for the total width, all is gravy. */ + if (width <= xx) + goto draw; + + /* Find size of current window text. */ + size = status_width(s->curw); + + /* + * If the offset is already on screen, we're good to draw from the + * start and just leave off the end. + */ + if (offset + size < xx) { + if (xx > 0) { + rarrow = 1; + xx--; + } + + width = xx; + goto draw; + } + + /* + * Work out how many characters we need to omit from the start. There + * are xx characters to fill, and offset + size must be the last. So, + * the start character is offset + size - xx. + */ + if (xx > 0) { + larrow = 1; + xx--; + } + + start = offset + size - xx; + if (xx > 0 && width > start + xx + 1) { /* + 1, eh? */ + rarrow = 1; + start++; + xx--; + } + width = xx; + +draw: + /* Bail here if anything is too small too. XXX. */ + if (width == 0 || xx == 0) + goto blank; + + /* Begin drawing and move to the starting position. */ + screen_write_start(&ctx, NULL, &c->status); + if (llen != 0) { + screen_write_cursormove(&ctx, 0, yy); + screen_write_puts(&ctx, &stdgc, "%s ", left); + if (larrow) + screen_write_putc(&ctx, &stdgc, ' '); + } else { + if (larrow) + screen_write_cursormove(&ctx, 1, yy); + else + screen_write_cursormove(&ctx, 0, yy); + } + + /* Draw each character in succession. */ + offset = 0; + RB_FOREACH(wl, winlinks, &s->windows) { + memcpy(&gc, &stdgc, sizeof gc); + text = status_print(s, wl, &gc); + + if (larrow == 1 && offset < start) { + if (session_alert_has(s, wl, WINDOW_ACTIVITY)) + larrow = -1; + else if (session_alert_has(s, wl, WINDOW_BELL)) + larrow = -1; + else if (session_alert_has(s, wl, WINDOW_CONTENT)) + larrow = -1; + } + + for (ptr = text; *ptr != '\0'; ptr++) { + if (offset >= start && offset < start + width) + screen_write_putc(&ctx, &gc, *ptr); + offset++; + } + + if (rarrow == 1 && offset > start + width) { + if (session_alert_has(s, wl, WINDOW_ACTIVITY)) + rarrow = -1; + else if (session_alert_has(s, wl, WINDOW_BELL)) + rarrow = -1; + else if (session_alert_has(s, wl, WINDOW_CONTENT)) + rarrow = -1; + } + + if (offset < start + width) { + if (offset >= start) { + screen_write_putc(&ctx, &stdgc, ' '); + } + offset++; + } + + xfree(text); + } + + /* Fill the remaining space if any. */ + while (offset++ < xx) + screen_write_putc(&ctx, &stdgc, ' '); + + /* Draw the last item. */ + if (rlen != 0) { + screen_write_cursormove(&ctx, c->tty.sx - rlen - 1, yy); + screen_write_puts(&ctx, &stdgc, " %s", right); + } + + /* Draw the arrows. */ + if (larrow != 0) { + memcpy(&gc, &stdgc, sizeof gc); + if (larrow == -1) + gc.attr ^= GRID_ATTR_REVERSE; + if (llen != 0) + screen_write_cursormove(&ctx, llen + 1, yy); + else + screen_write_cursormove(&ctx, 0, yy); + screen_write_putc(&ctx, &gc, '<'); + } + if (rarrow != 0) { + memcpy(&gc, &stdgc, sizeof gc); + if (rarrow == -1) + gc.attr ^= GRID_ATTR_REVERSE; + if (rlen != 0) + screen_write_cursormove(&ctx, c->tty.sx - rlen - 2, yy); + else + screen_write_cursormove(&ctx, c->tty.sx - 1, yy); + screen_write_putc(&ctx, &gc, '>'); + } + + goto out; + +blank: + /* Just draw the whole line as blank. */ + screen_write_start(&ctx, NULL, &c->status); + screen_write_cursormove(&ctx, 0, yy); + for (offset = 0; offset < c->tty.sx; offset++) + screen_write_putc(&ctx, &stdgc, ' '); + + goto out; + +off: + /* + * Draw the real window last line. Necessary to wipe over message if + * status is off. Not sure this is the right place for this. + */ + memcpy(&stdgc, &grid_default_cell, sizeof stdgc); + screen_write_start(&ctx, NULL, &c->status); + + sy = 0; + TAILQ_FOREACH(wp, &s->curw->window->panes, entry) { + sy += wp->sy + 1; + sc = wp->screen; + } + + screen_write_cursormove(&ctx, 0, 0); + if (sy < c->tty.sy) { + /* If the screen is too small, use blank. */ + for (offset = 0; offset < c->tty.sx; offset++) + screen_write_putc(&ctx, &stdgc, ' '); + } else { + screen_write_copy(&ctx, + sc, 0, sc->grid->hsize + screen_size_y(sc) - 1, c->tty.sx, 1); + } + +out: + screen_write_stop(&ctx); + + if (left != NULL) + xfree(left); + if (right != NULL) + xfree(right); + + if (grid_compare(c->status.grid, old_status.grid) == 0) { + screen_free(&old_status); + return (0); + } + screen_free(&old_status); + return (1); +} + +char * +status_replace(struct session *s, char *fmt, time_t t) +{ + struct winlink *wl = s->curw; + static char out[BUFSIZ]; + char in[BUFSIZ], tmp[256], ch, *iptr, *optr, *ptr, *endptr; + char *savedptr; + size_t len; + long n; + + strftime(in, sizeof in, fmt, localtime(&t)); + in[(sizeof in) - 1] = '\0'; + + iptr = in; + optr = out; + savedptr = NULL; + + while (*iptr != '\0') { + if (optr >= out + (sizeof out) - 1) + break; + switch (ch = *iptr++) { + case '#': + errno = 0; + n = strtol(iptr, &endptr, 10); + if ((n == 0 && errno != EINVAL) || + (n == LONG_MIN && errno != ERANGE) || + (n == LONG_MAX && errno != ERANGE) || + n != 0) + iptr = endptr; + if (n <= 0) + n = LONG_MAX; + + ptr = NULL; + switch (*iptr++) { + case '(': + if (ptr == NULL) { + ptr = status_replace_popen(&iptr); + if (ptr == NULL) + break; + savedptr = ptr; + } + /* FALLTHROUGH */ + case 'H': + if (ptr == NULL) { + if (gethostname(tmp, sizeof tmp) != 0) + fatal("gethostname"); + ptr = tmp; + } + /* FALLTHROUGH */ + case 'S': + if (ptr == NULL) + ptr = s->name; + /* FALLTHROUGH */ + case 'T': + if (ptr == NULL) + ptr = wl->window->active->base.title; + len = strlen(ptr); + if ((size_t) n < len) + len = n; + if (optr + len >= out + (sizeof out) - 1) + break; + while (len > 0 && *ptr != '\0') { + *optr++ = *ptr++; + len--; + } + break; + case '#': + *optr++ = '#'; + break; + } + if (savedptr != NULL) { + xfree(savedptr); + savedptr = NULL; + } + break; + default: + *optr++ = ch; + break; + } + } + *optr = '\0'; + + return (xstrdup(out)); +} + +char * +status_replace_popen(char **iptr) +{ + FILE *f; + char *buf, *cmd, *ptr; + int lastesc; + size_t len; + + if (**iptr == '\0') + return (NULL); + if (**iptr == ')') { /* no command given */ + (*iptr)++; + return (NULL); + } + + buf = NULL; + + cmd = xmalloc(strlen(*iptr) + 1); + len = 0; + + lastesc = 0; + for (; **iptr != '\0'; (*iptr)++) { + if (!lastesc && **iptr == ')') + break; /* unescaped ) is the end */ + if (!lastesc && **iptr == '\\') { + lastesc = 1; + continue; /* skip \ if not escaped */ + } + lastesc = 0; + cmd[len++] = **iptr; + } + if (**iptr == '\0') /* no terminating ) */ + goto out; + (*iptr)++; /* skip final ) */ + cmd[len] = '\0'; + + if ((f = popen(cmd, "r")) == NULL) + goto out; + + if ((buf = fgetln(f, &len)) == NULL) { + pclose(f); + goto out; + } + if (buf[len - 1] == '\n') { + buf[len - 1] = '\0'; + buf = xstrdup(buf); + } else { + ptr = xmalloc(len + 1); + memcpy(ptr, buf, len); + ptr[len] = '\0'; + buf = ptr; + } + pclose(f); + +out: + xfree(cmd); + return (buf); +} + +size_t +status_width(struct winlink *wl) +{ + return (xsnprintf(NULL, 0, "%d:%s ", wl->idx, wl->window->name)); +} + +char * +status_print(struct session *s, struct winlink *wl, struct grid_cell *gc) +{ + char *text, flag; + u_char fg, bg, attr; + + fg = options_get_number(&wl->window->options, "window-status-fg"); + if (fg != 8) + gc->fg = fg; + bg = options_get_number(&wl->window->options, "window-status-bg"); + if (bg != 8) + gc->bg = bg; + attr = options_get_number(&wl->window->options, "window-status-attr"); + if (attr != 0) + gc->attr = attr; + + flag = ' '; + if (wl == SLIST_FIRST(&s->lastw)) + flag = '-'; + if (wl == s->curw) + flag = '*'; + + if (session_alert_has(s, wl, WINDOW_ACTIVITY)) { + flag = '#'; + gc->attr ^= GRID_ATTR_REVERSE; + } else if (session_alert_has(s, wl, WINDOW_BELL)) { + flag = '!'; + gc->attr ^= GRID_ATTR_REVERSE; + } else if (session_alert_has(s, wl, WINDOW_CONTENT)) { + flag = '+'; + gc->attr ^= GRID_ATTR_REVERSE; + } + + xasprintf(&text, "%d:%s%c", wl->idx, wl->window->name, flag); + return (text); +} + +void +status_message_set(struct client *c, const char *msg) +{ + struct timeval tv; + int delay; + + delay = options_get_number(&c->session->options, "display-time"); + tv.tv_sec = delay / 1000; + tv.tv_usec = (delay % 1000) * 1000L; + + c->message_string = xstrdup(msg); + if (gettimeofday(&c->message_timer, NULL) != 0) + fatal("gettimeofday"); + timeradd(&c->message_timer, &tv, &c->message_timer); + + c->tty.flags |= (TTY_NOCURSOR|TTY_FREEZE); + c->flags |= CLIENT_STATUS; +} + +void +status_message_clear(struct client *c) +{ + if (c->message_string == NULL) + return; + + xfree(c->message_string); + c->message_string = NULL; + + c->tty.flags &= ~(TTY_NOCURSOR|TTY_FREEZE); + c->flags |= CLIENT_REDRAW; +} + +/* Draw client message on status line of present else on last line. */ +int +status_message_redraw(struct client *c) +{ + struct screen_write_ctx ctx; + struct session *s = c->session; + struct screen old_status; + size_t len; + struct grid_cell gc; + + if (c->tty.sx == 0 || c->tty.sy == 0) + return (0); + memcpy(&old_status, &c->status, sizeof old_status); + screen_init(&c->status, c->tty.sx, 1, 0); + + len = strlen(c->message_string); + if (len > c->tty.sx) + len = c->tty.sx; + + memcpy(&gc, &grid_default_cell, sizeof gc); + gc.bg = options_get_number(&s->options, "message-fg"); + gc.fg = options_get_number(&s->options, "message-bg"); + gc.attr |= options_get_number(&s->options, "message-attr"); + + screen_write_start(&ctx, NULL, &c->status); + + screen_write_cursormove(&ctx, 0, 0); + screen_write_puts(&ctx, &gc, "%.*s", (int) len, c->message_string); + for (; len < c->tty.sx; len++) + screen_write_putc(&ctx, &gc, ' '); + + screen_write_stop(&ctx); + + if (grid_compare(c->status.grid, old_status.grid) == 0) { + screen_free(&old_status); + return (0); + } + screen_free(&old_status); + return (1); +} + +void +status_prompt_set(struct client *c, + const char *msg, int (*fn)(void *, const char *), void *data, int flags) +{ + c->prompt_string = xstrdup(msg); + + c->prompt_buffer = xstrdup(""); + c->prompt_index = 0; + + c->prompt_callback = fn; + c->prompt_data = data; + + c->prompt_hindex = 0; + + c->prompt_flags = flags; + + mode_key_init(&c->prompt_mdata, + options_get_number(&c->session->options, "status-keys"), + MODEKEY_CANEDIT); + + c->tty.flags |= (TTY_NOCURSOR|TTY_FREEZE); + c->flags |= CLIENT_STATUS; +} + +void +status_prompt_clear(struct client *c) +{ + if (c->prompt_string == NULL) + return; + + mode_key_free(&c->prompt_mdata); + + xfree(c->prompt_string); + c->prompt_string = NULL; + + xfree(c->prompt_buffer); + c->prompt_buffer = NULL; + + c->tty.flags &= ~(TTY_NOCURSOR|TTY_FREEZE); + c->flags |= CLIENT_REDRAW; +} + +/* Draw client prompt on status line of present else on last line. */ +int +status_prompt_redraw(struct client *c) +{ + struct screen_write_ctx ctx; + struct session *s = c->session; + struct screen old_status; + size_t i, size, left, len, offset, n; + char ch; + struct grid_cell gc; + + if (c->tty.sx == 0 || c->tty.sy == 0) + return (0); + memcpy(&old_status, &c->status, sizeof old_status); + screen_init(&c->status, c->tty.sx, 1, 0); + offset = 0; + + len = strlen(c->prompt_string); + if (len > c->tty.sx) + len = c->tty.sx; + + memcpy(&gc, &grid_default_cell, sizeof gc); + gc.bg = options_get_number(&s->options, "message-fg"); + gc.fg = options_get_number(&s->options, "message-bg"); + gc.attr |= options_get_number(&s->options, "message-attr"); + + screen_write_start(&ctx, NULL, &c->status); + + screen_write_cursormove(&ctx, 0, 0); + screen_write_puts(&ctx, &gc, "%.*s", (int) len, c->prompt_string); + + left = c->tty.sx - len; + if (left != 0) { + if (c->prompt_index < left) + size = strlen(c->prompt_buffer); + else { + offset = c->prompt_index - left - 1; + if (c->prompt_index == strlen(c->prompt_buffer)) + left--; + size = left; + } + if (c->prompt_flags & PROMPT_HIDDEN) { + n = strlen(c->prompt_buffer); + if (n > left) + n = left; + for (i = 0; i < n; i++) + screen_write_putc(&ctx, &gc, '*'); + } else { + screen_write_puts(&ctx, &gc, + "%.*s", (int) left, c->prompt_buffer + offset); + } + + for (i = len + size; i < c->tty.sx; i++) + screen_write_putc(&ctx, &gc, ' '); + } + + /* Draw a fake cursor. */ + screen_write_cursormove(&ctx, len + c->prompt_index - offset, 0); + if (c->prompt_index == strlen(c->prompt_buffer)) + ch = ' '; + else { + if (c->prompt_flags & PROMPT_HIDDEN) + ch = '*'; + else + ch = c->prompt_buffer[c->prompt_index]; + } + if (ch == '\0') + ch = ' '; + gc.attr ^= GRID_ATTR_REVERSE; + screen_write_putc(&ctx, &gc, ch); + + screen_write_stop(&ctx); + + if (grid_compare(c->status.grid, old_status.grid) == 0) { + screen_free(&old_status); + return (0); + } + screen_free(&old_status); + return (1); +} + +/* Handle keys in prompt. */ +void +status_prompt_key(struct client *c, int key) +{ + struct paste_buffer *pb; + char *s, *first, *last, word[64]; + size_t size, n, off, idx; + + size = strlen(c->prompt_buffer); + switch (mode_key_lookup(&c->prompt_mdata, key)) { + case MODEKEYCMD_LEFT: + if (c->prompt_index > 0) { + c->prompt_index--; + c->flags |= CLIENT_STATUS; + } + break; + case MODEKEYCMD_RIGHT: + if (c->prompt_index < size) { + c->prompt_index++; + c->flags |= CLIENT_STATUS; + } + break; + case MODEKEYCMD_STARTOFLINE: + if (c->prompt_index != 0) { + c->prompt_index = 0; + c->flags |= CLIENT_STATUS; + } + break; + case MODEKEYCMD_ENDOFLINE: + if (c->prompt_index != size) { + c->prompt_index = size; + c->flags |= CLIENT_STATUS; + } + break; + case MODEKEYCMD_COMPLETE: + if (*c->prompt_buffer == '\0') + break; + + idx = c->prompt_index; + if (idx != 0) + idx--; + + /* Find the word we are in. */ + first = c->prompt_buffer + idx; + while (first > c->prompt_buffer && *first != ' ') + first--; + while (*first == ' ') + first++; + last = c->prompt_buffer + idx; + while (*last != '\0' && *last != ' ') + last++; + while (*last == ' ') + last--; + if (*last != '\0') + last++; + if (last <= first || + ((size_t) (last - first)) > (sizeof word) - 1) + break; + memcpy(word, first, last - first); + word[last - first] = '\0'; + + /* And try to complete it. */ + if ((s = status_prompt_complete(word)) == NULL) + break; + + /* Trim out word. */ + n = size - (last - c->prompt_buffer) + 1; /* with \0 */ + memmove(first, last, n); + size -= last - first; + + /* Insert the new word. */ + size += strlen(s); + off = first - c->prompt_buffer; + c->prompt_buffer = xrealloc(c->prompt_buffer, 1, size + 1); + first = c->prompt_buffer + off; + memmove(first + strlen(s), first, n); + memcpy(first, s, strlen(s)); + + c->prompt_index = (first - c->prompt_buffer) + strlen(s); + + c->flags |= CLIENT_STATUS; + break; + case MODEKEYCMD_BACKSPACE: + if (c->prompt_index != 0) { + if (c->prompt_index == size) + c->prompt_buffer[--c->prompt_index] = '\0'; + else { + memmove(c->prompt_buffer + c->prompt_index - 1, + c->prompt_buffer + c->prompt_index, + size + 1 - c->prompt_index); + c->prompt_index--; + } + c->flags |= CLIENT_STATUS; + } + break; + case MODEKEYCMD_DELETE: + if (c->prompt_index != size) { + memmove(c->prompt_buffer + c->prompt_index, + c->prompt_buffer + c->prompt_index + 1, + size + 1 - c->prompt_index); + c->flags |= CLIENT_STATUS; + } + break; + case MODEKEYCMD_UP: + if (server_locked) + break; + + if (ARRAY_LENGTH(&c->prompt_hdata) == 0) + break; + xfree(c->prompt_buffer); + + c->prompt_buffer = xstrdup(ARRAY_ITEM(&c->prompt_hdata, + ARRAY_LENGTH(&c->prompt_hdata) - 1 - c->prompt_hindex)); + if (c->prompt_hindex != ARRAY_LENGTH(&c->prompt_hdata) - 1) + c->prompt_hindex++; + + c->prompt_index = strlen(c->prompt_buffer); + c->flags |= CLIENT_STATUS; + break; + case MODEKEYCMD_DOWN: + if (server_locked) + break; + + xfree(c->prompt_buffer); + + if (c->prompt_hindex != 0) { + c->prompt_hindex--; + c->prompt_buffer = xstrdup(ARRAY_ITEM( + &c->prompt_hdata, ARRAY_LENGTH( + &c->prompt_hdata) - 1 - c->prompt_hindex)); + } else + c->prompt_buffer = xstrdup(""); + + c->prompt_index = strlen(c->prompt_buffer); + c->flags |= CLIENT_STATUS; + break; + case MODEKEYCMD_PASTE: + if ((pb = paste_get_top(&c->session->buffers)) == NULL) + break; + if ((last = strchr(pb->data, '\n')) == NULL) + last = strchr(pb->data, '\0'); + n = last - pb->data; + + c->prompt_buffer = xrealloc(c->prompt_buffer, 1, size + n + 1); + if (c->prompt_index == size) { + memcpy(c->prompt_buffer + c->prompt_index, pb->data, n); + c->prompt_index += n; + c->prompt_buffer[c->prompt_index] = '\0'; + } else { + memmove(c->prompt_buffer + c->prompt_index + n, + c->prompt_buffer + c->prompt_index, + size + 1 - c->prompt_index); + memcpy(c->prompt_buffer + c->prompt_index, pb->data, n); + c->prompt_index += n; + } + + c->flags |= CLIENT_STATUS; + break; + case MODEKEYCMD_CHOOSE: + if (*c->prompt_buffer != '\0') { + status_prompt_add_history(c); + if (c->prompt_callback( + c->prompt_data, c->prompt_buffer) == 0) + status_prompt_clear(c); + break; + } + /* FALLTHROUGH */ + case MODEKEYCMD_QUIT: + if (c->prompt_callback(c->prompt_data, NULL) == 0) + status_prompt_clear(c); + break; + case MODEKEYCMD_OTHERKEY: + if (key < 32 || key > 126) + break; + c->prompt_buffer = xrealloc(c->prompt_buffer, 1, size + 2); + + if (c->prompt_index == size) { + c->prompt_buffer[c->prompt_index++] = key; + c->prompt_buffer[c->prompt_index] = '\0'; + } else { + memmove(c->prompt_buffer + c->prompt_index + 1, + c->prompt_buffer + c->prompt_index, + size + 1 - c->prompt_index); + c->prompt_buffer[c->prompt_index++] = key; + } + + if (c->prompt_flags & PROMPT_SINGLE) { + if (c->prompt_callback( + c->prompt_data, c->prompt_buffer) == 0) + status_prompt_clear(c); + } + + c->flags |= CLIENT_STATUS; + break; + default: + break; + } +} + +/* Add line to the history. */ +void +status_prompt_add_history(struct client *c) +{ + if (server_locked) + return; + + if (ARRAY_LENGTH(&c->prompt_hdata) > 0 && + strcmp(ARRAY_LAST(&c->prompt_hdata), c->prompt_buffer) == 0) + return; + + if (ARRAY_LENGTH(&c->prompt_hdata) == PROMPT_HISTORY) { + xfree(ARRAY_FIRST(&c->prompt_hdata)); + ARRAY_REMOVE(&c->prompt_hdata, 0); + } + + ARRAY_ADD(&c->prompt_hdata, xstrdup(c->prompt_buffer)); +} + +/* Complete word. */ +char * +status_prompt_complete(const char *s) +{ + const struct cmd_entry **cmdent; + const struct set_option_entry *optent; + ARRAY_DECL(, const char *) list; + char *prefix, *s2; + u_int i; + size_t j; + + if (*s == '\0') + return (NULL); + + /* First, build a list of all the possible matches. */ + ARRAY_INIT(&list); + for (cmdent = cmd_table; *cmdent != NULL; cmdent++) { + if (strncmp((*cmdent)->name, s, strlen(s)) == 0) + ARRAY_ADD(&list, (*cmdent)->name); + } + for (i = 0; i < NSETOPTION; i++) { + optent = &set_option_table[i]; + if (strncmp(optent->name, s, strlen(s)) == 0) + ARRAY_ADD(&list, optent->name); + } + for (i = 0; i < NSETWINDOWOPTION; i++) { + optent = &set_window_option_table[i]; + if (strncmp(optent->name, s, strlen(s)) == 0) + ARRAY_ADD(&list, optent->name); + } + + /* If none, bail now. */ + if (ARRAY_LENGTH(&list) == 0) { + ARRAY_FREE(&list); + return (NULL); + } + + /* If an exact match, return it, with a trailing space. */ + if (ARRAY_LENGTH(&list) == 1) { + xasprintf(&s2, "%s ", ARRAY_FIRST(&list)); + ARRAY_FREE(&list); + return (s2); + } + + /* Now loop through the list and find the longest common prefix. */ + prefix = xstrdup(ARRAY_FIRST(&list)); + for (i = 1; i < ARRAY_LENGTH(&list); i++) { + s = ARRAY_ITEM(&list, i); + + j = strlen(s); + if (j > strlen(prefix)) + j = strlen(prefix); + for (; j > 0; j--) { + if (prefix[j - 1] != s[j - 1]) + prefix[j - 1] = '\0'; + } + } + + ARRAY_FREE(&list); + return (prefix); +} diff --git a/tmux.1 b/tmux.1 new file mode 100644 index 00000000..4b96ad47 --- /dev/null +++ b/tmux.1 @@ -0,0 +1,1329 @@ +.\" $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. +.\" +.Dd April 20, 2009 +.Dt TMUX 1 +.Os +.Sh NAME +.Nm tmux +.Nd "terminal multiplexer" +.Sh SYNOPSIS +.Nm tmux +.Bk -words +.Op Fl 28dqUuv +.Op Fl f Ar file +.Op Fl L Ar socket-name +.Op Fl S Ar socket-path +.Op Ar command Op Ar flags +.Ek +.Sh DESCRIPTION +.Nm +is a terminal multiplexer; it enables a number of terminals to be accessed and +controlled from a single terminal. +.Pp +.Nm +runs as a server-client system. +A server is created automatically when necessary and holds a number of +.Em sessions , +each of which may have a number of +.Em windows +linked to it. +A window may be split on screen into one or more +.Em panes , +each of which is a separate terminal. +Any number of +.Em clients +may connect to a session, or the server +may be controlled by issuing commands with +.Nm . +Communication takes place through a socket, by default placed in +.Pa /tmp . +.Pp +The options are as follows: +.Bl -tag -width "XXXXXXXXXXXX" +.It Fl 2 +Force +.Nm +to assume the terminal supports 256 colours. +.It Fl 8 +Like +.Fl 2 , +indicates the terminal supports 88 colours. +.It Fl d +Force +.Nm +to assume the terminal supports default colours. +.It Fl f Ar file +Specify an alternative configuration file. +By default, +.Nm +will look for a config file at +.Pa ~/.tmux.conf . +The configuration file is a set of +.Nm +commands which are executed in sequence when the server is first started. +.It Fl q +Prevent the server sending various information messages, for example when +window flags are altered. +.It Fl L Ar socket-name +.Nm +stores the server socket in a directory under +.Pa /tmp ; +the default socket is named +.Em default . +This option allows a different socket name to be specified, allowing several +independent +.Nm +servers to be run. +Unlike +.Fl S +a full path is not necessary: the sockets are all created in the same +directory. +.It Fl S Ar socket-path +Specify a full alternative path to the server socket. +If +.Fl S +is specified, the default socket directory is not used and any +.Fl L +flag is ignored. +.It Fl U +Unlock the server. +.It Fl u +Instruct +.Nm +that the terminal support UTF-8. +.It Fl v +Request verbose logging. +This option may be specified multiple times for increasing verbosity. +Log messages will be saved into +.Pa tmux-client-PID.log +and +.Pa tmux-server-PID.log +files in the current directory, where +.Em PID +is the pid of the server or client process. +.It Ar command Op Ar flags +This specifies one of a set of commands used to control +.Nm , +and described in the following sections. +If no command and flags is specified, the +.Ic new-session +command is assumed. +.Pp +.El +.Sh QUICK START +To create a new tmux session running +.Xr vi 1 : +.Pp +.Dl $ tmux new-session vi +.Pp +Most commands have a shorter form, known as an alias. +For new-session, this is +.Ic new : +.Pp +.Dl $ tmux new vi +.Pp +Alternatively, the shortest unambiguous form of a command is accepted. +If there are several options, they are listed: +.Bd -literal -offset indent +$ tmux n +ambiguous command: n, could be: new-session, new-window, next-window +$ +.Ed +.Pp +Within an active session, a new window may be created by typing +.Ql C-b +(ctrl-b, known as the prefix key) +followed by the +.Ql c +key. +.Pp +Windows may be navigated with: +.Ql C-b 0 +(to select window 0), +.Ql C-b 1 +(to select window 1), and so on; +.Ql C-b n +to select the next window; and +.Ql C-b p +to select the previous window. +.Pp +A session may be detached using +.Ql C-b d +and reattached with: +.Pp +.Dl $ tmux attach-session +.Pp +Typing +.Ql C-b \&? +lists the current key bindings in the current window; up and down may be used +to navigate the list or +.Ql Q +to exit from it. +.Sh KEY BINDINGS +.Nm +may be controlled from an attached client by using a key combination of a +prefix key, +.Ql C-b +(ctrl-b) by default, followed by a command key. +.Pp +Some of the default key bindings include: +.Pp +.Bl -tag -width Ds -compact +.It Ql d +Detach current client. +.It Ql c +Create new window. +.It Ql n +Change to next window in the current session. +.It Ql p +Change to previous window in the current session. +.It Ql l +Move to last (previously selected) window in the current session. +.It Ql t +Display a large clock. +.It Ql \&? +List current key bindings. +.El +.Pp +A complete list may be obtained with the +.Ic list-keys +command (bound to +.Ql \&? +by default). +Key bindings may be changed with the +.Ic bind-key +and +.Ic unbind-key +commands. +.Sh HISTORY +.Nm +maintains a configurable history buffer for each window. +By default, up to 2000 lines are kept, this can be altered with the +.Ic history-limit +option (see the +.Ic set-option +command below). +.Sh MODES +A +.Nm +window may be in one of several modes. +The default permits direct access to the terminal attached to the window. +The others are: +.Bl -tag -width Ds +.It Em output mode +This is entered when a command which produces output, such as +.Ic list-keys , +is executed from a key binding. +.It Em scroll mode +This is entered with the +.Ic scroll-mode +command (bound to +.Ql = +by default) and permits the window history buffer to be inspected. +.It Em copy mode +This permits a section of a window or its history to be copied to a +.Em paste buffer +for later insertion into another window. +This mode is entered with the +.Ic copy-mode +command, bound to +.Ql [ +by default. +.El +.Pp +The keys available depend on whether +.Xr emacs 1 +or +.Xr vi 1 +mode is selected (see the +.Ic mode-keys +option). +The following keys are supported as appropriate for the mode: +.Bl -column "FunctionXXXXXXXXXXXX" "viXXXXXX" "emacs" -offset indent +.It Sy "Function" Ta Sy "vi" Ta Sy "emacs" +.It Li "Start of line" Ta "0 or ^" Ta "C-a" +.It Li "Clear selection" Ta "Escape" Ta "C-g" +.It Li "Copy selection" Ta "Enter" Ta "M-w" +.It Li "Cursor down" Ta "j" Ta "Down" +.It Li "End of line" Ta "$" Ta "C-e" +.It Li "Cursor left" Ta "h" Ta "Left" +.It Li "Next page" Ta "C-f" Ta "Page down" +.It Li "Next word" Ta "w" Ta "M-f" +.It Li "Previous page" Ta "C-u" Ta "Page up" +.It Li "Previous word" Ta "b" Ta "M-b" +.It Li "Quit mode" Ta "q" Ta "Escape" +.It Li "Cursor right" Ta "l" Ta "Right" +.It Li "Start selection" Ta "Space" Ta "C-Space" +.It Li "Cursor up" Ta "k" Ta "Up" +.El +.Pp +.Sh BUFFERS +.Nm +maintains a stack of +.Em paste buffers +for each session. +Up to the value of the +.Ic buffer-limit +option are kept; when a new buffer is added, the buffer at the bottom of the +stack is removed. +Buffers may be added using +.Ic copy-mode +or the +.Ic set-buffer +command, and pasted into a window using the +.Ic paste-buffer +command. +.Sh PANES AND LAYOUTS +Each window displayed by +.Nm +may be split into one or more +.Em panes ; +each pane takes up a certain area of the display and is a separate terminal. +A window may be split into panes using the +.Ic split-window +command. +.Pp +Panes are numbered beginning from zero; in horizontal layouts zero is the +leftmost pane and in vertical the topmost. +.Pp +Panes may be arranged using several layouts. +The layout may be cycled with the +.Ic next-layout +command (bound to +.Ql C-space +by default), the current pane may be changed with the +.Ic up-pane +and +.Ic down-pane +commands and the +.Ic rotate-window +and +.Ic swap-pane +commands may be used to swap panes without changing the window layout. +.Pp +The following layouts are supported: +.Bl -tag -width Ds +.It Ic manual +Manual layout splits windows vertically (running across); only with this layout +may panes be resized using the +.Ic resize-pane +command. +.It Ic active-only +Only the active pane is shown - all other panes are hidden. +.It Ic even-horizontal +Panes are spread out evenly from left to right across the window. +.It Ic even-vertical +Panes are spread evenly from top to bottom. +.It Ic main-vertical +A large (81 column) pane is shown on the left of the window and the remaining +panes are spread from top to bottom in the leftover space to the right. +.El +.Sh COMMANDS +This section contains a list of the commands supported by +.Nm . +Most commands accept the optional +.Fl t +argument with one of +.Ar target-client , +.Ar target-session +or +.Ar target-window . +These specify the client, session or window which a command should affect. +.Ar target-client +is the name of the +.Xr pty 4 +file to which the client is connected, for example +.Pa /dev/ttyp1 . +Clients may be listed with the +.Ic list-clients +command. +.Pp +.Ar target-session +is either the name of a session (as listed by the +.Ic list-sessions +command); or the name of a client as for +.Ar target-client , +in this case, the session attached to the client is used. +An +.Xr fnmatch 3 +pattern may be used to match the session name. +If a session is omitted when required, +.Nm tmux +attempts to use the current session; if no current session is available, the +most recently created is chosen. +If no client is specified, the current client is chosen, if possible, or an +error is reported. +.Pp +.Ar target-window +specifies a window in the form +.Em session Ns \&: Ns Em index , +for example mysession:1. +The session is in the same form as for +.Ar target-session . +.Em session , +.Em index +or both may be omitted. +If +.Em session +is omitted, the same rules as for +.Ar target-session +are followed; if +.Em index +is not present, the current window for the given session is used. +When the argument does not contain a colon (:), +.Nm +first attempts to parse it as window index; if that fails, an attempt is made +to match a session or client name. +.Pp +Multiple commands may be specified together as part of a +.Em command sequence . +Each command should be separated by spaces and a semicolon +.Eo ( Ql \& \&; \& Ec ) ; +commands are executed sequentially from left to right. +A literal semicolon may be included by escaping it with a backslash (for +example, when specifying a command sequence to +.Ic bind-key ) . +.Pp +Examples include: +.Pp +.Bd -literal -offset indent +refresh-client -t/dev/ttyp2 + +rename-session -tfirst newname + +set-window-option -t:0 monitor-activity on + +new-window ; split-window -d + +bind-key D detach-client \e\; lock-server +.Ed +.Pp +The following commands are available: +.Bl -tag -width Ds +.It Xo Ic attach-session +.Op Fl d +.Op Fl t Ar target-session +.Xc +.D1 (alias: Ic attach ) +Create a new client in the current terminal and attach it to a session. +If +.Fl d +is specified, any other clients attached to the session are detached. +.Pp +If no server is started, +.Ic attach-session +will attempt to start it; this will fail unless sessions are created in the +configuration file. +.It Xo Ic bind-key +.Op Fl r +.Ar key Ar command Op Ar arguments +.Xc +.D1 (alias: Ic bind ) +Bind key +.Ar key +to +.Ar command . +Keys may be specified prefixed with +.Ql C- +or +.Ql ^ +for ctrl keys, or +.Ql M- +for alt (meta) keys. +The +.Fl r +flag indicates this key may repeat, see the +.Ic repeat-time +option. +.It Xo Ic break-pane +.Op Fl d +.Op Fl p Ar pane-index +.Op Fl t Ar target-window +.Xc +.D1 (alias: Ic breakp) +Break the current pane off from its containing window to make it the only pane +in a new window. +If +.Fl d +is given, the new window does not become the current window. +.It Xo Ic choose-session +.Op Fl t Ar target-window +.Xc +Put a window into session choice mode, where the session for the current +client may be selected interactively from a list. +This command works only from inside +.Nm . +.It Xo Ic choose-window +.Op Fl t Ar target-window +.Xc +Put a window into window choice mode, where the window for the session +attached to the current client may be selected interactively from a list. +This command works only from inside +.Nm . +.It Xo Ic clock-mode +.Op Fl t Ar target-window +.Xc +Display a large clock. +.It Xo Ic command-prompt +.Op Fl t Ar target-client +.Op Ar template +.Xc +Open the command prompt in a client. +This may be used from inside +.Nm +to execute commands interactively. +If +.Ar template +is specified, it is used as the command; any %% in the template will be +replaced by what is entered at the prompt. +.It Xo Ic confirm-before +.Op Fl t Ar target-client +.Ar command +.Xc +.D1 (alias: Ic confirm) +Ask for confirmation before executing +.Ar command . +This command works only from inside +.Nm . +.It Xo Ic copy-buffer +.Op Fl a Ar src-index +.Op Fl b Ar dst-index +.Op Fl s Ar src-session +.Op Fl t Ar dst-session +.Xc +.D1 (alias: Ic copyb) +Copy a session paste buffer to another session. +If no sessions are specified, the current one is used instead. +.It Xo Ic copy-mode +.Op Fl u +.Op Fl t Ar target-window +.Xc +Enter copy mode. +The +.Fl u +option scrolls one page up. +.It Xo Ic delete-buffer +.Op Fl b Ar buffer-index +.Op Fl t Ar target-session +.Xc +.D1 (alias: Ic deleteb ) +Delete the buffer at +.Ar buffer-index , +or the top buffer if not specified. +.It Xo Ic detach-client +.Op Fl t Ar target-client +.Xc +.D1 (alias: Ic detach ) +Detach the current client if bound to a key, or the specified client with +.Fl t . +.It Xo Ic down-pane +.Op Fl p Ar pane-index +.Op Fl t Ar target-window +.Xc +.D1 (alias: Ic downp ) +Move down a pane. +.It Xo Ic find-window +.Op Fl t Ar target-window +.Ar match-string +.Xc +.D1 (alias: Ic findw ) +Search for +.Ar match-string +in window names, titles, and visible content (but not history). +If only one window is matched, it'll be automatically selected, otherwise a +choice list is shown. +This command only works from inside +.Nm . +.It Xo Ic has-session +.Op Fl t Ar target-session +.Xc +.D1 (alias: Ic has ) +Report an error and exit with 1 if the specified session does not exist. +If it does exist, exit with 0. +.It Xo Ic kill-pane +.Op Fl p Ar pane-index +.Op Fl t Ar target-window +.Xc +.D1 (alias: Ic killp ) +Destroy the given pane. +.It Xo Ic kill-server +.Xc +Kill the +.Nm +server and clients and destroy all sessions. +.It Xo Ic kill-session +.Op Fl t Ar target-session +.Xc +Destroy the given session, closing any windows linked to it and no other +sessions, and detaching all clients attached to it. +.It Xo Ic kill-window +.Op Fl t Ar target-window +.Xc +.D1 (alias: Ic killw ) +Kill the current window or the window at +.Ar target-window , +removing it from any sessions to which it is linked. +.It Xo Ic last-window +.Op Fl t Ar target-session +.Xc +.D1 (alias: Ic last ) +Select the last (previously selected) window. +If no +.Ar target-session +is specified, select the last window of the current session. +.It Xo Ic link-window +.Op Fl dk +.Op Fl s Ar src-window +.Op Fl t Ar dst-window +.Xc +.D1 (alias: Ic linkw ) +Link the window at +.Ar src-window +to the specified +.Ar dst-window . +If +.Ar dst-window +is specified and no such window exists, the +.Ar src-window +is linked there. +If +.Fl k +is given and +.Ar dst-window +exists, it is killed, otherwise an error is generated. +If +.Fl d +is given, the newly linked window is not selected. +.It Xo Ic list-buffers +.Op Fl t Ar target-session +.Xc +.D1 (alias: Ic lsb ) +List the buffers in the given session. +.It Xo Ic list-clients +.Xc +.D1 (alias: Ic lsc ) +List all clients attached to the server. +.It Xo Ic list-commands +.Xc +.D1 (alias: Ic lscm ) +List the syntax of all commands supported by +.Nm . +.It Xo Ic list-keys +.Xc +.D1 (alias: Ic lsk ) +List all key bindings. +.It Xo Ic list-sessions +.Xc +.D1 (alias: Ic ls ) +List all sessions managed by the server. +.It Xo Ic list-windows +.Op Fl t Ar target-session +.Xc +.D1 (alias: Ic lsw ) +List windows in the current session or in +.Ar target-session . +.It Xo Ic load-buffer +.Op Fl b Ar buffer-index +.Op Fl t Ar target-session +.Ar path +.Xc +.D1 (alias: Ic loadb ) +Load the contents of the specified paste buffer from +.Ar path . +.It Xo Ic lock-server +.Xc +.D1 (alias: Ic lock ) +Lock the server until a password is entered. +.It Xo Ic move-window +.Op Fl d +.Op Fl s Ar src-window +.Op Fl t Ar dst-window +.Xc +.D1 (alias: Ic movew ) +This is similar to +.Ic link-window , +except the window at +.Ar src-window +is moved to +.Ar dst-window . +.It Xo Ic new-session +.Op Fl d +.Op Fl n Ar window-name +.Op Fl s Ar session-name +.Op Ar command +.Xc +.D1 (alias: Ic new ) +Create a new session with name +.Ar session-name . +The new session is attached to the current terminal unless +.Fl d +is given. +.Ar window-name +and +.Ar command +are the name of and command to execute in the initial window. +.It Xo Ic new-window +.Op Fl d +.Op Fl n Ar window-name +.Op Fl t Ar target-window +.Op Ar command +.Xc +.D1 (alias: Ic neww ) +Create a new window. +If +.Fl d +is given, the session does not make the new window the current window. +.Ar target-window +represents the window to be created. +.Ar command +is the command to execute. +If +.Ar command +is not specified, the default command is used. +.Pp +The +.Ev TERM +environment variable must be set to +.Dq screen +for all programs running +.Em inside +.Nm . +New windows will automatically have +.Dq TERM=screen +added to their environment, but care must be taken not to reset this in shell +start-up files. +.It Xo Ic next-layout +.Op Fl t Ar target-window +.Xc +.D1 (alias: Ic nextl ) +Move a window to the next layout and rearrange the panes to fit. +.It Xo Ic next-window +.Op Fl t Ar target-session +.Xc +.D1 (alias: Ic next ) +Move to the next window in the session. +.It Xo Ic paste-buffer +.Op Fl d +.Op Fl b Ar buffer-index +.Op Fl t Ar target-window +.Xc +.D1 (alias: Ic pasteb ) +Insert the contents of a paste buffer into the current window. +.It Xo Ic previous-window +.Op Fl t Ar target-session +.Xc +.D1 (alias: Ic prev ) +Move to the previous window in the session. +.It Xo Ic refresh-client +.Op Fl t Ar target-client +.Xc +.D1 (alias: Ic refresh ) +Refresh the current client if bound to a key, or a single client if one is given +with +.Fl t . +.It Xo Ic rename-session +.Op Fl t Ar target-session +.Ar new-name +.Xc +.D1 (alias: Ic rename ) +Rename the session to +.Ar new-name . +.It Xo Ic rename-window +.Op Fl t Ar target-window +.Ar new-name +.Xc +.D1 (alias: Ic renamew ) +Rename the current window, or the window at +.Ar target-window +if specified, to +.Ar new-name . +.It Xo Ic resize-pane +.Op Fl DU +.Op Fl p Ar pane-index +.Op Fl t Ar target-window +.Op Ar adjustment +.Xc +.D1 (alias: Ic resizep ) +Resize a pane, upward with +.Fl U +(the default) or downward with +.Fl D . +The +.Ar adjustment +is given in lines (the default is 1). +.It Xo Ic respawn-window +.Op Fl k +.Op Fl t Ar target-window +.Op Ar command +.Xc +.D1 (alias: Ic respawnw ) +Reactive a window in which the command has exited (see the +.Ic remain-on-exit +window option). +If +.Ar command +is not given, the command used when the window was created is executed. +The window must be already inactive, unless +.Fl k +is given, in which case any existing command is killed. +.It Xo Ic rotate-window +.Op Fl DU +.Op Fl t Ar target-window +.Xc +.D1 (alias: Ic rotatew ) +Rotate the positions of the panes within a window, either upward (numerically +lower) with +.Fl U +or downward (numerically higher). +.It Xo Ic save-buffer +.Op Fl a +.Op Fl b Ar buffer-index +.Op Fl t Ar target-session +.Ar path +.Xc +.D1 (alias: Ic saveb ) +Save the contents of the specified paste buffer to +.Ar path . +The +.Fl a +option appends to rather than overwriting the file. +.It Xo Ic scroll-mode +.Op Fl u +.Op Fl t Ar target-window +.Xc +Enter scroll mode. +The +.Fl u +has the same meaning as in the +.Ic copy-mode +command. +.It Xo Ic select-pane +.Op Fl p Ar pane-index +.Op Fl t Ar target-window +.Xc +.D1 (alias: Ic selectp ) +Make pane +.Ar pane-index +the active pane in window +.Ar target-window . +.It Xo Ic select-prompt +.Op Fl t Ar target-client +.Xc +Open a prompt inside +.Ar target-client +allowing a window index to be entered interactively. +.It Xo Ic select-window +.Op Fl t Ar target-window +.Xc +.D1 (alias: Ic selectw ) +Select the window at +.Ar target-window . +.It Xo Ic send-keys +.Op Fl t Ar target-window +.Ar key Ar ... +.Xc +.D1 (alias: Ic send ) +Send a key or keys to a window. +Each argument +.Ar key +is the name of the key (such as +.Ql C-a +or +.Ql npage +) to send; if the string is not recognised as a key, it is sent as a series of +characters. +All arguments are sent sequentially from first to last. +.It Xo Ic send-prefix +.Op Fl t Ar target-window +.Xc +Send the prefix key to a window as if it was pressed. +.It Xo Ic server-info +.Xc +.D1 (alias: Ic info ) +Show server information and terminal details. +.It Xo Ic set-buffer +.Op Fl b Ar buffer-index +.Op Fl t Ar target-session +.Ar data +.Xc +.D1 (alias: Ic setb ) +Set the contents of the specified buffer to +.Ar data . +.It Xo Ic set-option +.Op Fl gu +.Op Fl t Ar target-session +.Ar option Ar value +.Xc +.D1 (alias: Ic set ) +Set an option. +If +.Fl g +is specified, the option is set as a global option. +Global options apply to all sessions which don't have the option explicitly +set. +If +.Fl g +is not used, the option applies only to +.Ar target-session . +The +.Fl u +flag unsets an option, so a session inherits the option from the global +options - it is not possible to unset a global option. +.Pp +Possible options are: +.Bl -tag -width Ds +.It Xo Ic bell-action +.Op Ic any | Ic none | Ic current +.Xc +Set action on window bell. +.Ic any +means a bell in any window linked to a session causes a bell in the current +window of that session, +.Ic none +means all bells are ignored and +.Ic current +means only bell in windows other than the current window are ignored. +.It Ic buffer-limit Ar number +Set the number of buffers kept for each session; as new buffers are added to +the top of the stack, old ones are removed from the bottom if necessary to +maintain this maximum length. +.It Ic default-command Ar command +Set the command used for new windows (if not specified when the window is +created) to +.Ar command . +The default is +.Dq exec $SHELL . +.It Ic default-path Ar path +Set the default working directory for processes created from keys, or +interactively from the prompt. +The default is the current working directory when the server is started. +.It Ic history-limit Ar lines +Set the maximum number of lines held in window history. +This setting applies only to new windows - existing window histories are not +resized and retain the limit at the point they were created. +.It Ic lock-after-time Ar number +Lock the server after +.Ar number +seconds of inactivity. +The default is off (set to 0). +This has no effect as a session option; it must be set as a global option using +.Fl g . +.It Ic message-attr Ar attributes +Set status line message attributes, where +.Ar attributes +is either +.Ic default +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: +.Ic black , +.Ic red , +.Ic green , +.Ic yellow , +.Ic blue , +.Ic magenta , +.Ic cyan , +.Ic white +or +.Ic default . +.It Ic message-fg Ar colour +Set status line message foreground colour. +.It Ic prefix Ar key +Set the current prefix key. +.It Ic repeat-time Ar number +Allow multiple commands to be entered without pressing the prefix-key again +in the specified +.Ar number +milliseconds (the default is 500). +Whether a key repeats may be set when it is bound using the +.Fl r +flag to +.Ic bind-key . +Repeat is enabled for the default keys of the +.Ic up-pane , +.Ic down-pane , +.Ic resize-pane-up , +and +.Ic resize-pane-down +commands. +.It Xo Ic set-remain-on-exit +.Op Ic on | Ic off +.Xc +Set the +.Ic remain-on-exit +window option for any windows first created in this session. +.It Xo Ic set-titles +.Op Ic on | Ic off +.Xc +Attempt to set the window title using the \ee]2;...\e007 xterm code and +the terminal appears to be an xterm. +This option is enabled by default. +Note that +.Xr elinks 1 +will only attempt to set the window title if the STY environment +variable is set. +.It Xo Ic status +.Op Ic on | Ic 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 +seconds. +By default, updates will occur every 15 seconds. +A setting of zero disables redrawing at interval. +.It Xo Ic status-keys +.Op Ic vi | Ic emacs +.Xc +Use +.Xr vi 1 - +or +.Xr emacs 1 -style +key bindings in the status line, for example at the command prompt. +Defaults to emacs. +.It Ic status-left Ar string +Display +.Ar string +to the left of the status bar. +.Ar string +will be passed through +.Xr strftime 3 +before being used. +By default, the session name is shown. +.Ar string +may contain any of the following special character pairs: +.Bl -column "Character pair" "Replaced with" -offset indent +.It Sy "Character pair" Ta Sy "Replaced with" +.It Li "#(command)" Ta "First line of command's output" +.It Li "#H" Ta "Hostname of local host" +.It Li "#S" Ta "Session name" +.It Li "#T" Ta "Current window title" +.It Li "##" Ta "A literal" Ql # +.El +.Pp +Where appropriate, these may be prefixed with a number to specify the maximum +length, for example +.Ql #24T . +.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-right Ar string +Display +.Ar string +to the right of the status bar. +By default, the date and time will be shown. +As with +.Ic status-left , +.Ar string +will be passed to +.Xr strftime 3 +and character pairs are replaced. +.It Ic status-right-length Ar length +Set the maximum +.Ar length +of the right component of the status bar. +The default is 40. +.El +.It Xo Ic set-password +.Op Fl c +.Ar password +.Xc +.D1 (alias: Ic pass ) +Set the server password. +If the +.Fl c +option is given, a pre-encrypted password may be specified. +By default, the password is blank, thus any entered password will be accepted +when unlocking the server (see the +.Ic lock-server +command). +To prevent variable expansion when an encrypted password is read from a +configuration file, enclose it in single quotes ('). +.It Xo Ic set-window-option +.Op Fl gu +.Op Fl t Ar target-window +.Ar option Ar value +.Xc +.D1 (alias: Ic setw ) +Set a window-specific option. +The +.Fl g +and +.Fl u +flags work similarly to the +.Ic set-option +command. +.Pp +Supported options are: +.Bl -tag -width Ds +.It Xo Ic aggressive-resize +.Op Ic on | Ic off +.Xc +Aggressively resize the chosen window. +This means that +.Nm +will resize the window to the size of the smallest session for which it is the +current window, rather than the smallest session to which it is attached. +The window may resize when the current window is changed on another sessions; +this option is good for full-screen programs which support SIGWINCH and poor for +interactive programs such as shells. +.It Xo Ic automatic-rename +.Op Ic on | Ic off +.Xc +Control automatic window renaming. +When this setting is enabled, +.Nm +will attempt - on supported platforms - to rename the window to reflect the +command currently running in it. +This flag is automatically disabled for an individual window when a name +is specified at creation with +.Ic new-window or +.Ic new-session , +or later with +.Ic rename-window . +It may be switched off globally with: +.Bd -literal -offset indent +set-window-option -g automatic-rename off +.Ed +.It Ic clock-mode-colour Ar colour +Set clock colour. +.It Xo Ic clock-mode-style +.Op Ic 12 | Ic 24 +.Xc +Set clock hour format. +.It Ic force-height Ar height +.It Ic force-width Ar width +Prevent +.Nm +from resizing a window to greater than +.Ar width +or +.Ar height . +A value of zero restores the default unlimited setting. +.It Ic mode-attr Ar attributes +Set window modes attributes. +.It Ic mode-bg Ar colour +Set window modes background colour. +.It Ic mode-fg Ar colour +Set window modes foreground colour. +.It Xo Ic mode-keys +.Op Ic vi | Ic emacs +.Xc +Use +.Xr vi 1 - +or +.Xr emacs 1 -style +key bindings in scroll and copy modes. +Key bindings default to emacs. +.It Xo Ic monitor-activity +.Op Ic on | Ic off +.Xc +Monitor for activity in the window. +Windows with activity are highlighted in the status line. +.It Xo Ic monitor-content Ar match-string +.Xc +Monitor content in the window. When +.Ar match-string +appears in the window, it is highlighted in the status line. +.It Xo Ic remain-on-exit +.Op Ic on | Ic off +.Xc +A window with this flag set is not destroyed when the program running in it +exits. +The window may be reactivated with the +.Ic respawn-window +command. +.It Xo Ic utf8 +.Op Ic on | Ic off +.Xc +Instructs +.Nm +to expect UTF-8 sequences to appear in this window. +.It Ic window-status-attr Ar attributes +Set status line attributes for a single window. +.It Ic window-status-bg Ar colour +Set status line background colour for a single window. +.It Ic window-status-fg Ar colour +Set status line foreground colour for a single window. +.It Xo Ic xterm-keys +.Op Ic on | Ic off +.Xc +If this option is set, +.Nm +will generate +.Xr xterm 1 -style +function key sequences; these have a number included to indicate modifiers such +as shift, meta or ctrl. +.El +.It Xo Ic show-buffer +.Op Fl b Ar buffer-index +.Op Fl t Ar target-session +.Xc +.D1 (alias: Ic showb ) +Display the contents of the specified buffer. +.It Xo Ic show-options +.Op Fl t Ar target-session +.Ar option Ar value +.Xc +.D1 (alias: Ic show ) +Show the currently set options. +If a +.Ar target-session +is specified, the options for that session are shown; otherwise, the global +options are listed. +.It Xo Ic show-window-options +.Op Fl t Ar target-window +.Ar option Ar value +.Xc +.D1 (alias: Ic showw ) +List the current options for the given window. +.It Xo Ic source-file +.Ar path +.Xc +.D1 (alias: Ic source ) +Execute commands from +.Ar path . +.It Xo Ic split-window +.Op Fl d +.Oo Fl l +.Ar lines | +.Fl p Ar percentage Oc +.Op Fl t Ar target-window +.Op Ar command +.Xc +.D1 (alias: splitw ) +Creates a new window by splitting it vertically. +The +.Fl l +and +.Fl p +options specify the size of the new window in lines, or as a percentage, +respectively. +All other options have the same meaning as in the +.Ic new-window +command. +.Pp +A few notes with regard to panes: +.Bl -enum -compact +.It +If attempting to split a window with less than eight lines, an error will be +shown. +.It +If the window is resized, as many panes are shown as can fit without reducing +them below four lines. +.It +The minimum pane size is four lines (including the separator line). +.It +The panes are indexed from top (0) to bottom, with no numbers skipped. +.El +.It Xo Ic start-server +.Xc +.D1 (alias: Ic start ) +Start the +.Nm +server, if not already running, without creating any sessions. +.It Xo Ic suspend-client +.Op Fl c target-client +.Xc +.D1 (alias: Ic suspendc ) +Suspend a client by sending SIGTSTP (tty stop). +.It Xo Ic swap-pane +.Op Fl dDU +.Op Fl p Ar src-index +.Op Fl t Ar target-window +.Op Fl q Ar dst-index +.Xc +.D1 (alias: Ic swapp ) +Swap two panes within a window. +If +.Fl U +is used, the pane is swapped with the pane above (before it numerically); +.Fl D +swaps with the pane below (the next numerically); or +.Ar dst-index +may be give to swap with a specific pane. +.It Xo Ic swap-window +.Op Fl d +.Op Fl s Ar src-window +.Op Fl t Ar dst-window +.Xc +.D1 (alias: Ic swapw ) +This is similar to +.Ic link-window , +except the source and destination windows are swapped. +It is an error if no window exists at +.Ar src-window . +.It Xo Ic switch-client +.Op Fl c Ar target-client Fl t Ar target-session +.Xc +.D1 (alias: Ic switchc ) +Switch the current session for client +.Ar target-client +to +.Ar target-session . +.It Xo Ic unbind-key +.Ar key +.Xc +.D1 (alias: Ic unbind ) +Unbind the key bound to +.Ar key . +.It Xo Ic unlink-window +.Op Fl t Ar target-window +.Xc +.D1 (alias: Ic unlinkw ) +Unlink +.Ar target-window . +A window may be unlinked only if it is linked to multiple sessions - windows may +not be linked to no sessions. +.It Xo Ic up-pane +.Op Fl p Ar pane-index +.Op Fl t Ar target-window +.Xc +.D1 (alias: Ic upp ) +Move up a pane. +.El +.Sh FILES +.Bl -tag -width Ds -compact +.It Pa ~/.tmux.conf +default +.Nm +configuration file +.El +.Sh SEE ALSO +.Xr pty 4 +.Sh AUTHORS +.An Nicholas Marriott Aq nicm@users.sourceforge.net diff --git a/tmux.c b/tmux.c new file mode 100644 index 00000000..b9d502e3 --- /dev/null +++ b/tmux.c @@ -0,0 +1,487 @@ +/* $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 + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tmux.h" + +#ifdef DEBUG +const char *malloc_options = "AFGJPX"; +#endif + +volatile sig_atomic_t sigwinch; +volatile sig_atomic_t sigterm; +volatile sig_atomic_t sigcont; +volatile sig_atomic_t sigchld; +volatile sig_atomic_t sigusr1; +volatile sig_atomic_t sigusr2; + +char *cfg_file; +struct options global_options; +struct options global_window_options; + +int server_locked; +char *server_password; +time_t server_activity; + +int debug_level; +int be_quiet; +time_t start_time; +char *socket_path; + +__dead void usage(void); +char *makesockpath(const char *); + +__dead void +usage(void) +{ + fprintf(stderr, "usage: %s [-28dqUuVv] [-f file] " + "[-L socket-name] [-S socket-path] [command [flags]]\n", + __progname); + exit(1); +} + +void +logfile(const char *name) +{ + char *path; + + log_close(); + if (debug_level > 0) { + xasprintf( + &path, "%s-%s-%ld.log", __progname, name, (long) getpid()); + log_open_file(debug_level, path); + xfree(path); + } +} + +void +sighandler(int sig) +{ + int saved_errno; + + saved_errno = errno; + switch (sig) { + case SIGWINCH: + sigwinch = 1; + break; + case SIGTERM: + sigterm = 1; + break; + case SIGCHLD: + sigchld = 1; + break; + case SIGCONT: + sigcont = 1; + break; + case SIGUSR1: + sigusr1 = 1; + break; + case SIGUSR2: + sigusr2 = 1; + break; + } + errno = saved_errno; +} + +void +siginit(void) +{ + struct sigaction act; + + memset(&act, 0, sizeof act); + sigemptyset(&act.sa_mask); + act.sa_flags = SA_RESTART; + + act.sa_handler = SIG_IGN; + if (sigaction(SIGPIPE, &act, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGINT, &act, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGTSTP, &act, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGQUIT, &act, NULL) != 0) + fatal("sigaction failed"); + + act.sa_handler = sighandler; + if (sigaction(SIGWINCH, &act, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGTERM, &act, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGCHLD, &act, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGUSR1, &act, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGUSR2, &act, NULL) != 0) + fatal("sigaction failed"); +} + +void +sigreset(void) +{ + struct sigaction act; + + memset(&act, 0, sizeof act); + sigemptyset(&act.sa_mask); + + act.sa_handler = SIG_DFL; + if (sigaction(SIGPIPE, &act, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGUSR1, &act, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGUSR2, &act, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGINT, &act, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGTSTP, &act, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGQUIT, &act, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGWINCH, &act, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGTERM, &act, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGCHLD, &act, NULL) != 0) + fatal("sigaction failed"); +} + +char * +makesockpath(const char *label) +{ + char base[MAXPATHLEN], *path; + struct stat sb; + u_int uid; + + uid = getuid(); + xsnprintf(base, MAXPATHLEN, "%s/%s-%d", _PATH_TMP, __progname, uid); + + if (mkdir(base, S_IRWXU) != 0 && errno != EEXIST) + return (NULL); + + if (lstat(base, &sb) != 0) + return (NULL); + if (!S_ISDIR(sb.st_mode)) { + errno = ENOTDIR; + return (NULL); + } + if (sb.st_uid != uid || (sb.st_mode & (S_IRWXG|S_IRWXO)) != 0) { + errno = EACCES; + return (NULL); + } + + xasprintf(&path, "%s/%s", base, label); + return (path); +} + +int +main(int argc, char **argv) +{ + struct client_ctx cctx; + struct msg_command_data cmddata; + struct buffer *b; + struct cmd_list *cmdlist; + struct cmd *cmd; + struct pollfd pfd; + struct hdr hdr; + const char *shell; + struct passwd *pw; + char *s, *path, *label, *cause, *home, *pass = NULL; + char cwd[MAXPATHLEN]; + int retcode, opt, flags, unlock, start_server; + + unlock = flags = 0; + label = path = NULL; + while ((opt = getopt(argc, argv, "28df:L:qS:uUv")) != -1) { + switch (opt) { + case '2': + flags |= IDENTIFY_256COLOURS; + flags &= ~IDENTIFY_88COLOURS; + break; + case '8': + flags |= IDENTIFY_88COLOURS; + flags &= ~IDENTIFY_256COLOURS; + break; + case 'f': + cfg_file = xstrdup(optarg); + break; + case 'L': + if (path != NULL) { + log_warnx("-L and -S cannot be used together"); + exit(1); + } + if (label != NULL) + xfree(label); + label = xstrdup(optarg); + break; + case 'S': + if (label != NULL) { + log_warnx("-L and -S cannot be used together"); + exit(1); + } + if (path != NULL) + xfree(path); + path = xstrdup(optarg); + break; + case 'q': + be_quiet = 1; + break; + case 'u': + flags |= IDENTIFY_UTF8; + break; + case 'U': + unlock = 1; + break; + case 'd': + flags |= IDENTIFY_HASDEFAULTS; + break; + case 'v': + debug_level++; + break; + default: + usage(); + } + } + argc -= optind; + argv += optind; + + log_open_tty(debug_level); + siginit(); + + options_init(&global_options, NULL); + options_set_number(&global_options, "bell-action", BELL_ANY); + options_set_number(&global_options, "buffer-limit", 9); + options_set_number(&global_options, "display-time", 750); + options_set_number(&global_options, "history-limit", 2000); + options_set_number(&global_options, "lock-after-time", 0); + options_set_number(&global_options, "message-attr", GRID_ATTR_REVERSE); + options_set_number(&global_options, "message-bg", 3); + options_set_number(&global_options, "message-fg", 0); + options_set_number(&global_options, "prefix", '\002'); + options_set_number(&global_options, "repeat-time", 500); + options_set_number(&global_options, "set-remain-on-exit", 0); + options_set_number(&global_options, "set-titles", 1); + options_set_number(&global_options, "status", 1); + options_set_number(&global_options, "status-attr", GRID_ATTR_REVERSE); + options_set_number(&global_options, "status-bg", 2); + options_set_number(&global_options, "status-fg", 0); + options_set_number(&global_options, "status-interval", 15); + options_set_number(&global_options, "status-keys", MODEKEY_EMACS); + options_set_number(&global_options, "status-left-length", 10); + options_set_number(&global_options, "status-right-length", 40); + options_set_string(&global_options, "status-left", "[#S]"); + options_set_string( + &global_options, "status-right", "\"#24T\" %%H:%%M %%d-%%b-%%y"); + + options_init(&global_window_options, NULL); + options_set_number(&global_window_options, "aggressive-resize", 0); + options_set_number(&global_window_options, "automatic-rename", 1); + options_set_number(&global_window_options, "clock-mode-colour", 4); + options_set_number(&global_window_options, "clock-mode-style", 1); + options_set_number(&global_window_options, "force-height", 0); + options_set_number(&global_window_options, "force-width", 0); + options_set_number( + &global_window_options, "mode-attr", GRID_ATTR_REVERSE); + options_set_number(&global_window_options, "main-pane-width", 81); + options_set_number(&global_window_options, "main-pane-height", 24); + options_set_number(&global_window_options, "mode-bg", 3); + options_set_number(&global_window_options, "mode-fg", 0); + options_set_number(&global_window_options, "mode-keys", MODEKEY_EMACS); + options_set_number(&global_window_options, "monitor-activity", 0); + options_set_string(&global_window_options, "monitor-content", "%s", ""); + options_set_number(&global_window_options, "utf8", 0); + options_set_number(&global_window_options, "window-status-attr", 0); + options_set_number(&global_window_options, "window-status-bg", 8); + options_set_number(&global_window_options, "window-status-fg", 8); + options_set_number(&global_window_options, "xterm-keys", 0); + options_set_number(&global_window_options, "remain-on-exit", 0); + + if (!(flags & IDENTIFY_UTF8)) { + /* + * If the user has set LANG to contain UTF-8, it is a safe + * assumption that either they are using a UTF-8 terminal, or + * if not they know that output from UTF-8-capable programs may + * be wrong. + */ + if ((s = getenv("LANG")) != NULL && strstr(s, "UTF-8") != NULL) + flags |= IDENTIFY_UTF8; + } + + if (cfg_file == NULL) { + home = getenv("HOME"); + if (home == NULL || *home == '\0') { + pw = getpwuid(getuid()); + if (pw != NULL) + home = pw->pw_dir; + } + xasprintf(&cfg_file, "%s/%s", home, DEFAULT_CFG); + if (access(cfg_file, R_OK) != 0) { + xfree(cfg_file); + cfg_file = NULL; + } + } else { + if (access(cfg_file, R_OK) != 0) { + log_warn("%s", cfg_file); + exit(1); + } + } + + if (label == NULL) + label = xstrdup("default"); + if (path == NULL && (path = makesockpath(label)) == NULL) { + log_warn("can't create socket"); + exit(1); + } + xfree(label); + + shell = getenv("SHELL"); + if (shell == NULL || *shell == '\0') { + pw = getpwuid(getuid()); + if (pw != NULL) + shell = pw->pw_shell; + if (shell == NULL || *shell == '\0') + shell = _PATH_BSHELL; + } + options_set_string( + &global_options, "default-command", "exec %s", shell); + + if (getcwd(cwd, sizeof cwd) == NULL) { + log_warn("getcwd"); + exit(1); + } + options_set_string(&global_options, "default-path", "%s", cwd); + + if (unlock) { + if (argc != 0) { + log_warnx("can't specify a command when unlocking"); + exit(1); + } + cmdlist = NULL; + if ((pass = getpass("Password: ")) == NULL) + exit(1); + start_server = 0; + } else { + if (argc == 0) { + cmd = xmalloc(sizeof *cmd); + cmd->entry = &cmd_new_session_entry; + cmd->entry->init(cmd, 0); + + cmdlist = xmalloc(sizeof *cmdlist); + TAILQ_INIT(cmdlist); + TAILQ_INSERT_HEAD(cmdlist, cmd, qentry); + } else { + cmdlist = cmd_list_parse(argc, argv, &cause); + if (cmdlist == NULL) { + log_warnx("%s", cause); + exit(1); + } + } + start_server = 0; + TAILQ_FOREACH(cmd, cmdlist, qentry) { + if (cmd->entry->flags & CMD_STARTSERVER) { + start_server = 1; + break; + } + } + } + + memset(&cctx, 0, sizeof cctx); + if (client_init(path, &cctx, start_server, flags) != 0) + exit(1); + xfree(path); + + b = buffer_create(BUFSIZ); + if (unlock) { + cmd_send_string(b, pass); + client_write_server( + &cctx, MSG_UNLOCK, BUFFER_OUT(b), BUFFER_USED(b)); + } else { + cmd_list_send(cmdlist, b); + cmd_list_free(cmdlist); + client_fill_session(&cmddata); + client_write_server2(&cctx, MSG_COMMAND, + &cmddata, sizeof cmddata, BUFFER_OUT(b), BUFFER_USED(b)); + } + buffer_destroy(b); + + retcode = 0; + for (;;) { + pfd.fd = cctx.srv_fd; + pfd.events = POLLIN; + if (BUFFER_USED(cctx.srv_out) > 0) + pfd.events |= POLLOUT; + + if (poll(&pfd, 1, INFTIM) == -1) { + if (errno == EAGAIN || errno == EINTR) + continue; + fatal("poll failed"); + } + + if (buffer_poll(&pfd, cctx.srv_in, cctx.srv_out) != 0) + goto out; + + restart: + if (BUFFER_USED(cctx.srv_in) < sizeof hdr) + continue; + memcpy(&hdr, BUFFER_OUT(cctx.srv_in), sizeof hdr); + if (BUFFER_USED(cctx.srv_in) < (sizeof hdr) + hdr.size) + continue; + buffer_remove(cctx.srv_in, sizeof hdr); + + switch (hdr.type) { + case MSG_EXIT: + case MSG_SHUTDOWN: + goto out; + case MSG_ERROR: + retcode = 1; + /* FALLTHROUGH */ + case MSG_PRINT: + if (hdr.size > INT_MAX - 1) + fatalx("bad MSG_PRINT size"); + log_info("%.*s", + (int) hdr.size, BUFFER_OUT(cctx.srv_in)); + if (hdr.size != 0) + buffer_remove(cctx.srv_in, hdr.size); + goto restart; + case MSG_READY: + retcode = client_main(&cctx); + goto out; + default: + fatalx("unexpected command"); + } + } + +out: + options_free(&global_options); + options_free(&global_window_options); + + close(cctx.srv_fd); + buffer_destroy(cctx.srv_in); + buffer_destroy(cctx.srv_out); + + return (retcode); +} diff --git a/tmux.cat1 b/tmux.cat1 new file mode 100644 index 00000000..fe815603 --- /dev/null +++ b/tmux.cat1 @@ -0,0 +1,813 @@ +TMUX(1) OpenBSD Reference Manual TMUX(1) + +NNAAMMEE + ttmmuuxx - terminal multiplexer + +SSYYNNOOPPSSIISS + ttmmuuxx [--2288ddqqUUuuvv] [--ff _f_i_l_e] [--LL _s_o_c_k_e_t_-_n_a_m_e] [--SS _s_o_c_k_e_t_-_p_a_t_h] + [_c_o_m_m_a_n_d [_f_l_a_g_s]] + +DDEESSCCRRIIPPTTIIOONN + ttmmuuxx is a terminal multiplexer; it enables a number of terminals to be + accessed and controlled from a single terminal. + + ttmmuuxx runs as a server-client system. A server is created automatically + when necessary and holds a number of _s_e_s_s_i_o_n_s, each of which may have a + number of _w_i_n_d_o_w_s linked to it. A window may be split on screen into one + or more _p_a_n_e_s, each of which is a separate terminal. Any number of + _c_l_i_e_n_t_s may connect to a session, or the server may be controlled by is- + suing commands with ttmmuuxx. Communication takes place through a socket, by + default placed in _/_t_m_p. + + The options are as follows: + + --22 Force ttmmuuxx to assume the terminal supports 256 colours. + + --88 Like --22, indicates the terminal supports 88 colours. + + --dd Force ttmmuuxx to assume the terminal supports default colours. + + --ff _f_i_l_e Specify an alternative configuration file. By default, + ttmmuuxx will look for a config file at _~_/_._t_m_u_x_._c_o_n_f. The con- + figuration file is a set of ttmmuuxx commands which are execut- + ed in sequence when the server is first started. + + --qq Prevent the server sending various information messages, + for example when window flags are altered. + + --LL _s_o_c_k_e_t_-_n_a_m_e + ttmmuuxx stores the server socket in a directory under _/_t_m_p; + the default socket is named _d_e_f_a_u_l_t. This option allows a + different socket name to be specified, allowing several in- + dependent ttmmuuxx servers to be run. Unlike --SS a full path is + not necessary: the sockets are all created in the same di- + rectory. + + --SS _s_o_c_k_e_t_-_p_a_t_h + Specify a full alternative path to the server socket. If + --SS is specified, the default socket directory is not used + and any --LL flag is ignored. + + --UU Unlock the server. + + --uu Instruct ttmmuuxx that the terminal support UTF-8. + + --vv Request verbose logging. This option may be specified mul- + tiple times for increasing verbosity. Log messages will be + saved into _t_m_u_x_-_c_l_i_e_n_t_-_P_I_D_._l_o_g and _t_m_u_x_-_s_e_r_v_e_r_-_P_I_D_._l_o_g + files in the current directory, where _P_I_D is the pid of the + server or client process. + + _c_o_m_m_a_n_d [_f_l_a_g_s] + This specifies one of a set of commands used to control + ttmmuuxx, and described in the following sections. If no com- + mand and flags is specified, the nneeww--sseessssiioonn command is as- + sumed. + +QQUUIICCKK SSTTAARRTT + To create a new tmux session running vi(1): + + $ tmux new-session vi + + Most commands have a shorter form, known as an alias. For new-session, + this is nneeww: + + $ tmux new vi + + Alternatively, the shortest unambiguous form of a command is accepted. + If there are several options, they are listed: + + $ tmux n + ambiguous command: n, could be: new-session, new-window, next-window + $ + + Within an active session, a new window may be created by typing `C-b' + (ctrl-b, known as the prefix key) followed by the `c' key. + + Windows may be navigated with: `C-b 0' (to select window 0), `C-b 1' (to + select window 1), and so on; `C-b n' to select the next window; and `C-b + p' to select the previous window. + + A session may be detached using `C-b d' and reattached with: + + $ tmux attach-session + + Typing `C-b ?' lists the current key bindings in the current window; up + and down may be used to navigate the list or `Q' to exit from it. + +KKEEYY BBIINNDDIINNGGSS + ttmmuuxx may be controlled from an attached client by using a key combination + of a prefix key, `C-b' (ctrl-b) by default, followed by a command key. + + Some of the default key bindings include: + + `d' Detach current client. + `c' Create new window. + `n' Change to next window in the current session. + `p' Change to previous window in the current session. + `l' Move to last (previously selected) window in the current session. + `t' Display a large clock. + `?' List current key bindings. + + A complete list may be obtained with the lliisstt--kkeeyyss command (bound to `?' + by default). Key bindings may be changed with the bbiinndd--kkeeyy and uunnbbiinndd-- + kkeeyy commands. + +HHIISSTTOORRYY + ttmmuuxx maintains a configurable history buffer for each window. By de- + fault, up to 2000 lines are kept, this can be altered with the hhiissttoorryy-- + lliimmiitt option (see the sseett--ooppttiioonn command below). + +MMOODDEESS + A ttmmuuxx window may be in one of several modes. The default permits direct + access to the terminal attached to the window. The others are: + + _o_u_t_p_u_t _m_o_d_e + This is entered when a command which produces output, such as + lliisstt--kkeeyyss, is executed from a key binding. + + _s_c_r_o_l_l _m_o_d_e + This is entered with the ssccrroollll--mmooddee command (bound to `=' by de- + fault) and permits the window history buffer to be inspected. + + _c_o_p_y _m_o_d_e + This permits a section of a window or its history to be copied to + a _p_a_s_t_e _b_u_f_f_e_r for later insertion into another window. This + mode is entered with the ccooppyy--mmooddee command, bound to `[' by de- + fault. + + The keys available depend on whether emacs(1) or vi(1) mode is selected + (see the mmooddee--kkeeyyss option). The following keys are supported as appro- + priate for the mode: + + FFuunnccttiioonn vvii eemmaaccss + Start of line 0 or ^ C-a + Clear selection Escape C-g + Copy selection Enter M-w + Cursor down j Down + End of line $ C-e + Cursor left h Left + Next page C-f Page down + Next word w M-f + Previous page C-u Page up + Previous word b M-b + Quit mode q Escape + Cursor right l Right + Start selection Space C-Space + Cursor up k Up + +BBUUFFFFEERRSS + ttmmuuxx maintains a stack of _p_a_s_t_e _b_u_f_f_e_r_s for each session. Up to the val- + ue of the bbuuffffeerr--lliimmiitt option are kept; when a new buffer is added, the + buffer at the bottom of the stack is removed. Buffers may be added using + ccooppyy--mmooddee or the sseett--bbuuffffeerr command, and pasted into a window using the + ppaassttee--bbuuffffeerr command. + +PPAANNEESS AANNDD LLAAYYOOUUTTSS + Each window displayed by ttmmuuxx may be split into one or more _p_a_n_e_s; each + pane takes up a certain area of the display and is a separate terminal. + A window may be split into panes using the sspplliitt--wwiinnddooww command. + + Panes are numbered beginning from zero; in horizontal layouts zero is the + leftmost pane and in vertical the topmost. + + Panes may be arranged using several layouts. The layout may be cycled + with the nneexxtt--llaayyoouutt command (bound to `C-space' by default), the current + pane may be changed with the uupp--ppaannee and ddoowwnn--ppaannee commands and the + rroottaattee--wwiinnddooww and sswwaapp--ppaannee commands may be used to swap panes without + changing the window layout. + + The following layouts are supported: + + mmaannuuaall Manual layout splits windows vertically (running across); only + with this layout may panes be resized using the rreessiizzee--ppaannee com- + mand. + + aaccttiivvee--oonnllyy + Only the active pane is shown - all other panes are hidden. + + eevveenn--hhoorriizzoonnttaall + Panes are spread out evenly from left to right across the window. + + eevveenn--vveerrttiiccaall + Panes are spread evenly from top to bottom. + + mmaaiinn--vveerrttiiccaall + A large (81 column) pane is shown on the left of the window and + the remaining panes are spread from top to bottom in the leftover + space to the right. + +CCOOMMMMAANNDDSS + This section contains a list of the commands supported by ttmmuuxx. Most + commands accept the optional --tt argument with one of _t_a_r_g_e_t_-_c_l_i_e_n_t, + _t_a_r_g_e_t_-_s_e_s_s_i_o_n or _t_a_r_g_e_t_-_w_i_n_d_o_w. These specify the client, session or + window which a command should affect. _t_a_r_g_e_t_-_c_l_i_e_n_t is the name of the + pty(4) file to which the client is connected, for example _/_d_e_v_/_t_t_y_p_1. + Clients may be listed with the lliisstt--cclliieennttss command. + + _t_a_r_g_e_t_-_s_e_s_s_i_o_n is either the name of a session (as listed by the lliisstt-- + sseessssiioonnss command); or the name of a client as for _t_a_r_g_e_t_-_c_l_i_e_n_t, in this + case, the session attached to the client is used. An fnmatch(3) pattern + may be used to match the session name. If a session is omitted when re- + quired, ttmmuuxx attempts to use the current session; if no current session + is available, the most recently created is chosen. If no client is spec- + ified, the current client is chosen, if possible, or an error is report- + ed. + + _t_a_r_g_e_t_-_w_i_n_d_o_w specifies a window in the form _s_e_s_s_i_o_n:_i_n_d_e_x, for example + mysession:1. The session is in the same form as for _t_a_r_g_e_t_-_s_e_s_s_i_o_n. + _s_e_s_s_i_o_n, _i_n_d_e_x or both may be omitted. If _s_e_s_s_i_o_n is omitted, the same + rules as for _t_a_r_g_e_t_-_s_e_s_s_i_o_n are followed; if _i_n_d_e_x is not present, the + current window for the given session is used. When the argument does not + contain a colon (:), ttmmuuxx first attempts to parse it as window index; if + that fails, an attempt is made to match a session or client name. + + Multiple commands may be specified together as part of a _c_o_m_m_a_n_d + _s_e_q_u_e_n_c_e. Each command should be separated by spaces and a semicolon (` + ; '); commands are executed sequentially from left to right. A literal + semicolon may be included by escaping it with a backslash (for example, + when specifying a command sequence to bbiinndd--kkeeyy). + + Examples include: + + refresh-client -t/dev/ttyp2 + + rename-session -tfirst newname + + set-window-option -t:0 monitor-activity on + + new-window ; split-window -d + + bind-key D detach-client \; lock-server + + The following commands are available: + + aattttaacchh--sseessssiioonn [--dd] [--tt _t_a_r_g_e_t_-_s_e_s_s_i_o_n] + (alias: aattttaacchh) + Create a new client in the current terminal and attach it to a + session. If --dd is specified, any other clients attached to the + session are detached. + + If no server is started, aattttaacchh--sseessssiioonn will attempt to start it; + this will fail unless sessions are created in the configuration + file. + + bbiinndd--kkeeyy [--rr] _k_e_y _c_o_m_m_a_n_d [_a_r_g_u_m_e_n_t_s] + (alias: bbiinndd) + Bind key _k_e_y to _c_o_m_m_a_n_d. Keys may be specified prefixed with + `C-' or `^' for ctrl keys, or `M-' for alt (meta) keys. The --rr + flag indicates this key may repeat, see the rreeppeeaatt--ttiimmee option. + + bbrreeaakk--ppaannee [--dd] [--pp _p_a_n_e_-_i_n_d_e_x] [--tt _t_a_r_g_e_t_-_w_i_n_d_o_w] + (alias: bbrreeaakkpp)) + Break the current pane off from its containing window to make it + the only pane in a new window. If --dd is given, the new window + does not become the current window. + + cchhoooossee--sseessssiioonn [--tt _t_a_r_g_e_t_-_w_i_n_d_o_w] + Put a window into session choice mode, where the session for the + current client may be selected interactively from a list. This + command works only from inside ttmmuuxx. + + cchhoooossee--wwiinnddooww [--tt _t_a_r_g_e_t_-_w_i_n_d_o_w] + Put a window into window choice mode, where the window for the + session attached to the current client may be selected interac- + tively from a list. This command works only from inside ttmmuuxx. + + cclloocckk--mmooddee [--tt _t_a_r_g_e_t_-_w_i_n_d_o_w] + Display a large clock. + + ccoommmmaanndd--pprroommpptt [--tt _t_a_r_g_e_t_-_c_l_i_e_n_t] [_t_e_m_p_l_a_t_e] + Open the command prompt in a client. This may be used from in- + side ttmmuuxx to execute commands interactively. If _t_e_m_p_l_a_t_e is + specified, it is used as the command; any %% in the template will + be replaced by what is entered at the prompt. + + ccoonnffiirrmm--bbeeffoorree [--tt _t_a_r_g_e_t_-_c_l_i_e_n_t] _c_o_m_m_a_n_d + (alias: ccoonnffiirrmm)) + Ask for confirmation before executing _c_o_m_m_a_n_d. This command + works only from inside ttmmuuxx. + + ccooppyy--bbuuffffeerr [--aa _s_r_c_-_i_n_d_e_x] [--bb _d_s_t_-_i_n_d_e_x] [--ss _s_r_c_-_s_e_s_s_i_o_n] [--tt + _d_s_t_-_s_e_s_s_i_o_n] + (alias: ccooppyybb)) + Copy a session paste buffer to another session. If no sessions + are specified, the current one is used instead. + + ccooppyy--mmooddee [--uu] [--tt _t_a_r_g_e_t_-_w_i_n_d_o_w] + Enter copy mode. The --uu option scrolls one page up. + + ddeelleettee--bbuuffffeerr [--bb _b_u_f_f_e_r_-_i_n_d_e_x] [--tt _t_a_r_g_e_t_-_s_e_s_s_i_o_n] + (alias: ddeelleetteebb) + Delete the buffer at _b_u_f_f_e_r_-_i_n_d_e_x, or the top buffer if not spec- + ified. + + ddeettaacchh--cclliieenntt [--tt _t_a_r_g_e_t_-_c_l_i_e_n_t] + (alias: ddeettaacchh) + Detach the current client if bound to a key, or the specified + client with --tt. + + ddoowwnn--ppaannee [--pp _p_a_n_e_-_i_n_d_e_x] [--tt _t_a_r_g_e_t_-_w_i_n_d_o_w] + (alias: ddoowwnnpp) + Move down a pane. + + ffiinndd--wwiinnddooww [--tt _t_a_r_g_e_t_-_w_i_n_d_o_w] _m_a_t_c_h_-_s_t_r_i_n_g + (alias: ffiinnddww) + Search for _m_a_t_c_h_-_s_t_r_i_n_g in window names, titles, and visible con- + tent (but not history). If only one window is matched, it'll be + automatically selected, otherwise a choice list is shown. This + command only works from inside ttmmuuxx. + + hhaass--sseessssiioonn [--tt _t_a_r_g_e_t_-_s_e_s_s_i_o_n] + (alias: hhaass) + Report an error and exit with 1 if the specified session does not + exist. If it does exist, exit with 0. + + kkiillll--ppaannee [--pp _p_a_n_e_-_i_n_d_e_x] [--tt _t_a_r_g_e_t_-_w_i_n_d_o_w] + (alias: kkiillllpp) + Destroy the given pane. + + kkiillll--sseerrvveerr + Kill the ttmmuuxx server and clients and destroy all sessions. + + kkiillll--sseessssiioonn [--tt _t_a_r_g_e_t_-_s_e_s_s_i_o_n] + Destroy the given session, closing any windows linked to it and + no other sessions, and detaching all clients attached to it. + + kkiillll--wwiinnddooww [--tt _t_a_r_g_e_t_-_w_i_n_d_o_w] + (alias: kkiillllww) + Kill the current window or the window at _t_a_r_g_e_t_-_w_i_n_d_o_w, removing + it from any sessions to which it is linked. + + llaasstt--wwiinnddooww [--tt _t_a_r_g_e_t_-_s_e_s_s_i_o_n] + (alias: llaasstt) + Select the last (previously selected) window. If no _t_a_r_g_e_t_- + _s_e_s_s_i_o_n is specified, select the last window of the current ses- + sion. + + lliinnkk--wwiinnddooww [--ddkk] [--ss _s_r_c_-_w_i_n_d_o_w] [--tt _d_s_t_-_w_i_n_d_o_w] + (alias: lliinnkkww) + Link the window at _s_r_c_-_w_i_n_d_o_w to the specified _d_s_t_-_w_i_n_d_o_w. If + _d_s_t_-_w_i_n_d_o_w is specified and no such window exists, the _s_r_c_-_w_i_n_d_o_w + is linked there. If --kk is given and _d_s_t_-_w_i_n_d_o_w exists, it is + killed, otherwise an error is generated. If --dd is given, the + newly linked window is not selected. + + lliisstt--bbuuffffeerrss [--tt _t_a_r_g_e_t_-_s_e_s_s_i_o_n] + (alias: llssbb) + List the buffers in the given session. + + lliisstt--cclliieennttss + (alias: llsscc) + List all clients attached to the server. + + lliisstt--ccoommmmaannddss + (alias: llssccmm) + List the syntax of all commands supported by ttmmuuxx. + + lliisstt--kkeeyyss + (alias: llsskk) + List all key bindings. + + lliisstt--sseessssiioonnss + (alias: llss) + List all sessions managed by the server. + + lliisstt--wwiinnddoowwss [--tt _t_a_r_g_e_t_-_s_e_s_s_i_o_n] + (alias: llssww) + List windows in the current session or in _t_a_r_g_e_t_-_s_e_s_s_i_o_n. + + llooaadd--bbuuffffeerr [--bb _b_u_f_f_e_r_-_i_n_d_e_x] [--tt _t_a_r_g_e_t_-_s_e_s_s_i_o_n] _p_a_t_h + (alias: llooaaddbb) + Load the contents of the specified paste buffer from _p_a_t_h. + + lloocckk--sseerrvveerr + (alias: lloocckk) + Lock the server until a password is entered. + + mmoovvee--wwiinnddooww [--dd] [--ss _s_r_c_-_w_i_n_d_o_w] [--tt _d_s_t_-_w_i_n_d_o_w] + (alias: mmoovveeww) + This is similar to lliinnkk--wwiinnddooww, except the window at _s_r_c_-_w_i_n_d_o_w + is moved to _d_s_t_-_w_i_n_d_o_w. + + nneeww--sseessssiioonn [--dd] [--nn _w_i_n_d_o_w_-_n_a_m_e] [--ss _s_e_s_s_i_o_n_-_n_a_m_e] [_c_o_m_m_a_n_d] + (alias: nneeww) + Create a new session with name _s_e_s_s_i_o_n_-_n_a_m_e. The new session is + attached to the current terminal unless --dd is given. _w_i_n_d_o_w_-_n_a_m_e + and _c_o_m_m_a_n_d are the name of and command to execute in the initial + window. + + nneeww--wwiinnddooww [--dd] [--nn _w_i_n_d_o_w_-_n_a_m_e] [--tt _t_a_r_g_e_t_-_w_i_n_d_o_w] [_c_o_m_m_a_n_d] + (alias: nneewwww) + Create a new window. If --dd is given, the session does not make + the new window the current window. _t_a_r_g_e_t_-_w_i_n_d_o_w represents the + window to be created. _c_o_m_m_a_n_d is the command to execute. If + _c_o_m_m_a_n_d is not specified, the default command is used. + + The TERM environment variable must be set to ``screen'' for all + programs running _i_n_s_i_d_e ttmmuuxx. New windows will automatically + have ``TERM=screen'' added to their environment, but care must be + taken not to reset this in shell start-up files. + + nneexxtt--llaayyoouutt [--tt _t_a_r_g_e_t_-_w_i_n_d_o_w] + (alias: nneexxttll) + Move a window to the next layout and rearrange the panes to fit. + + nneexxtt--wwiinnddooww [--tt _t_a_r_g_e_t_-_s_e_s_s_i_o_n] + (alias: nneexxtt) + Move to the next window in the session. + + ppaassttee--bbuuffffeerr [--dd] [--bb _b_u_f_f_e_r_-_i_n_d_e_x] [--tt _t_a_r_g_e_t_-_w_i_n_d_o_w] + (alias: ppaasstteebb) + Insert the contents of a paste buffer into the current window. + + pprreevviioouuss--wwiinnddooww [--tt _t_a_r_g_e_t_-_s_e_s_s_i_o_n] + (alias: pprreevv) + Move to the previous window in the session. + + rreeffrreesshh--cclliieenntt [--tt _t_a_r_g_e_t_-_c_l_i_e_n_t] + (alias: rreeffrreesshh) + Refresh the current client if bound to a key, or a single client + if one is given with --tt. + + rreennaammee--sseessssiioonn [--tt _t_a_r_g_e_t_-_s_e_s_s_i_o_n] _n_e_w_-_n_a_m_e + (alias: rreennaammee) + Rename the session to _n_e_w_-_n_a_m_e. + + rreennaammee--wwiinnddooww [--tt _t_a_r_g_e_t_-_w_i_n_d_o_w] _n_e_w_-_n_a_m_e + (alias: rreennaammeeww) + Rename the current window, or the window at _t_a_r_g_e_t_-_w_i_n_d_o_w if + specified, to _n_e_w_-_n_a_m_e. + + rreessiizzee--ppaannee [--DDUU] [--pp _p_a_n_e_-_i_n_d_e_x] [--tt _t_a_r_g_e_t_-_w_i_n_d_o_w] [_a_d_j_u_s_t_m_e_n_t] + (alias: rreessiizzeepp) + Resize a pane, upward with --UU (the default) or downward with --DD. + The _a_d_j_u_s_t_m_e_n_t is given in lines (the default is 1). + + rreessppaawwnn--wwiinnddooww [--kk] [--tt _t_a_r_g_e_t_-_w_i_n_d_o_w] [_c_o_m_m_a_n_d] + (alias: rreessppaawwnnww) + Reactive a window in which the command has exited (see the + rreemmaaiinn--oonn--eexxiitt window option). If _c_o_m_m_a_n_d is not given, the com- + mand used when the window was created is executed. The window + must be already inactive, unless --kk is given, in which case any + existing command is killed. + + rroottaattee--wwiinnddooww [--DDUU] [--tt _t_a_r_g_e_t_-_w_i_n_d_o_w] + (alias: rroottaatteeww) + Rotate the positions of the panes within a window, either upward + (numerically lower) with --UU or downward (numerically higher). + + ssaavvee--bbuuffffeerr [--aa] [--bb _b_u_f_f_e_r_-_i_n_d_e_x] [--tt _t_a_r_g_e_t_-_s_e_s_s_i_o_n] _p_a_t_h + (alias: ssaavveebb) + Save the contents of the specified paste buffer to _p_a_t_h. The --aa + option appends to rather than overwriting the file. + + ssccrroollll--mmooddee [--uu] [--tt _t_a_r_g_e_t_-_w_i_n_d_o_w] + Enter scroll mode. The --uu has the same meaning as in the ccooppyy-- + mmooddee command. + + sseelleecctt--ppaannee [--pp _p_a_n_e_-_i_n_d_e_x] [--tt _t_a_r_g_e_t_-_w_i_n_d_o_w] + (alias: sseelleeccttpp) + Make pane _p_a_n_e_-_i_n_d_e_x the active pane in window _t_a_r_g_e_t_-_w_i_n_d_o_w. + + sseelleecctt--pprroommpptt [--tt _t_a_r_g_e_t_-_c_l_i_e_n_t] + Open a prompt inside _t_a_r_g_e_t_-_c_l_i_e_n_t allowing a window index to be + entered interactively. + + sseelleecctt--wwiinnddooww [--tt _t_a_r_g_e_t_-_w_i_n_d_o_w] + (alias: sseelleeccttww) + Select the window at _t_a_r_g_e_t_-_w_i_n_d_o_w. + + sseenndd--kkeeyyss [--tt _t_a_r_g_e_t_-_w_i_n_d_o_w] _k_e_y _._._. + (alias: sseenndd) + Send a key or keys to a window. Each argument _k_e_y is the name of + the key (such as `C-a' or `npage' ) to send; if the string is not + recognised as a key, it is sent as a series of characters. All + arguments are sent sequentially from first to last. + + sseenndd--pprreeffiixx [--tt _t_a_r_g_e_t_-_w_i_n_d_o_w] + Send the prefix key to a window as if it was pressed. + + sseerrvveerr--iinnffoo + (alias: iinnffoo) + Show server information and terminal details. + + sseett--bbuuffffeerr [--bb _b_u_f_f_e_r_-_i_n_d_e_x] [--tt _t_a_r_g_e_t_-_s_e_s_s_i_o_n] _d_a_t_a + (alias: sseettbb) + Set the contents of the specified buffer to _d_a_t_a. + + sseett--ooppttiioonn [--gguu] [--tt _t_a_r_g_e_t_-_s_e_s_s_i_o_n] _o_p_t_i_o_n _v_a_l_u_e + (alias: sseett) + Set an option. If --gg is specified, the option is set as a global + option. Global options apply to all sessions which don't have + the option explicitly set. If --gg is not used, the option applies + only to _t_a_r_g_e_t_-_s_e_s_s_i_o_n. The --uu flag unsets an option, so a ses- + sion inherits the option from the global options - it is not pos- + sible to unset a global option. + + Possible options are: + + bbeellll--aaccttiioonn [aannyy | nnoonnee | ccuurrrreenntt] + Set action on window bell. aannyy means a bell in any win- + dow linked to a session causes a bell in the current win- + dow of that session, nnoonnee means all bells are ignored and + ccuurrrreenntt means only bell in windows other than the current + window are ignored. + + bbuuffffeerr--lliimmiitt _n_u_m_b_e_r + Set the number of buffers kept for each session; as new + buffers are added to the top of the stack, old ones are + removed from the bottom if necessary to maintain this + maximum length. + + ddeeffaauulltt--ccoommmmaanndd _c_o_m_m_a_n_d + Set the command used for new windows (if not specified + when the window is created) to _c_o_m_m_a_n_d. The default is + ``exec $SHELL''. + + ddeeffaauulltt--ppaatthh _p_a_t_h + Set the default working directory for processes created + from keys, or interactively from the prompt. The default + is the current working directory when the server is + started. + + hhiissttoorryy--lliimmiitt _l_i_n_e_s + Set the maximum number of lines held in window history. + This setting applies only to new windows - existing win- + dow histories are not resized and retain the limit at the + point they were created. + + lloocckk--aafftteerr--ttiimmee _n_u_m_b_e_r + Lock the server after _n_u_m_b_e_r seconds of inactivity. The + default is off (set to 0). This has no effect as a ses- + sion option; it must be set as a global option using --gg. + + mmeessssaaggee--aattttrr _a_t_t_r_i_b_u_t_e_s + Set status line message attributes, where _a_t_t_r_i_b_u_t_e_s is + either ddeeffaauulltt or a comma-delimited list of one or more + of: bbrriigghhtt (or bboolldd), ddiimm, uunnddeerrssccoorree, bblliinnkk, rreevveerrssee, + hhiiddddeenn, or iittaalliiccss. + + mmeessssaaggee--bbgg _c_o_l_o_u_r + Set status line message background colour, where _c_o_l_o_u_r + is one of: bbllaacckk, rreedd, ggrreeeenn, yyeellllooww, bblluuee, mmaaggeennttaa, + ccyyaann, wwhhiittee or ddeeffaauulltt. + + mmeessssaaggee--ffgg _c_o_l_o_u_r + Set status line message foreground colour. + + pprreeffiixx _k_e_y + Set the current prefix key. + + rreeppeeaatt--ttiimmee _n_u_m_b_e_r + Allow multiple commands to be entered without pressing + the prefix-key again in the specified _n_u_m_b_e_r milliseconds + (the default is 500). Whether a key repeats may be set + when it is bound using the --rr flag to bbiinndd--kkeeyy. Repeat + is enabled for the default keys of the uupp--ppaannee, ddoowwnn-- + ppaannee, rreessiizzee--ppaannee--uupp, and rreessiizzee--ppaannee--ddoowwnn commands. + + sseett--rreemmaaiinn--oonn--eexxiitt [oonn | ooffff] + Set the rreemmaaiinn--oonn--eexxiitt window option for any windows + first created in this session. + + sseett--ttiittlleess [oonn | ooffff] + Attempt to set the window title using the \e]2;...\007 + xterm code and the terminal appears to be an xterm. This + option is enabled by default. Note that elinks(1) will + only attempt to set the window title if the STY environ- + ment variable is set. + + ssttaattuuss [oonn | ooffff] + Show or hide the status line. + + ssttaattuuss--aattttrr _a_t_t_r_i_b_u_t_e_s + Set status line attributes. + + ssttaattuuss--bbgg _c_o_l_o_u_r + Set status line background colour. + + ssttaattuuss--ffgg _c_o_l_o_u_r + Set status line foreground colour. + + ssttaattuuss--iinntteerrvvaall _i_n_t_e_r_v_a_l + Update the status bar every _i_n_t_e_r_v_a_l seconds. By de- + fault, updates will occur every 15 seconds. A setting of + zero disables redrawing at interval. + + ssttaattuuss--kkeeyyss [vvii | eemmaaccss] + Use vi(1)- or emacs(1)-style key bindings in the status + line, for example at the command prompt. Defaults to + emacs. + + ssttaattuuss--lleefftt _s_t_r_i_n_g + Display _s_t_r_i_n_g to the left of the status bar. _s_t_r_i_n_g + will be passed through strftime(3) before being used. By + default, the session name is shown. _s_t_r_i_n_g may contain + any of the following special character pairs: + + CChhaarraacctteerr ppaaiirr RReeppllaacceedd wwiitthh + #(command) First line of command's output + #H Hostname of local host + #S Session name + #T Current window title + ## A literal `#' + + Where appropriate, these may be prefixed with a number to + specify the maximum length, for example `#24T'. + + ssttaattuuss--lleefftt--lleennggtthh _l_e_n_g_t_h + Set the maximum _l_e_n_g_t_h of the left component of the sta- + tus bar. The default is 10. + + ssttaattuuss--rriigghhtt _s_t_r_i_n_g + Display _s_t_r_i_n_g to the right of the status bar. By de- + fault, the date and time will be shown. As with ssttaattuuss-- + lleefftt, _s_t_r_i_n_g will be passed to strftime(3) and character + pairs are replaced. + + ssttaattuuss--rriigghhtt--lleennggtthh _l_e_n_g_t_h + Set the maximum _l_e_n_g_t_h of the right component of the sta- + tus bar. The default is 40. + + sseett--ppaasssswwoorrdd [--cc] _p_a_s_s_w_o_r_d + (alias: ppaassss) + Set the server password. If the --cc option is given, a pre-en- + crypted password may be specified. By default, the password is + blank, thus any entered password will be accepted when unlocking + the server (see the lloocckk--sseerrvveerr command). To prevent variable + expansion when an encrypted password is read from a configuration + file, enclose it in single quotes ('). + + sseett--wwiinnddooww--ooppttiioonn [--gguu] [--tt _t_a_r_g_e_t_-_w_i_n_d_o_w] _o_p_t_i_o_n _v_a_l_u_e + (alias: sseettww) + Set a window-specific option. The --gg and --uu flags work similarly + to the sseett--ooppttiioonn command. + + Supported options are: + + aaggggrreessssiivvee--rreessiizzee [oonn | ooffff] + Aggressively resize the chosen window. This means that + ttmmuuxx will resize the window to the size of the smallest + session for which it is the current window, rather than + the smallest session to which it is attached. The window + may resize when the current window is changed on another + sessions; this option is good for full-screen programs + which support SIGWINCH and poor for interactive programs + such as shells. + + aauuttoommaattiicc--rreennaammee [oonn | ooffff] + Control automatic window renaming. When this setting is + enabled, ttmmuuxx will attempt - on supported platforms - to + rename the window to reflect the command currently run- + ning in it. This flag is automatically disabled for an + individual window when a name is specified at creation + with nneeww--wwiinnddooww oorr nneeww--sseessssiioonn, or later with rreennaammee-- + wwiinnddooww. It may be switched off globally with: + + set-window-option -g automatic-rename off + + cclloocckk--mmooddee--ccoolloouurr _c_o_l_o_u_r + Set clock colour. + + cclloocckk--mmooddee--ssttyyllee [1122 | 2244] + Set clock hour format. + + ffoorrccee--hheeiigghhtt _h_e_i_g_h_t + + ffoorrccee--wwiiddtthh _w_i_d_t_h + Prevent ttmmuuxx from resizing a window to greater than _w_i_d_t_h + or _h_e_i_g_h_t. A value of zero restores the default unlimit- + ed setting. + + mmooddee--aattttrr _a_t_t_r_i_b_u_t_e_s + Set window modes attributes. + + mmooddee--bbgg _c_o_l_o_u_r + Set window modes background colour. + + mmooddee--ffgg _c_o_l_o_u_r + Set window modes foreground colour. + + mmooddee--kkeeyyss [vvii | eemmaaccss] + Use vi(1)- or emacs(1)-style key bindings in scroll and + copy modes. Key bindings default to emacs. + + mmoonniittoorr--aaccttiivviittyy [oonn | ooffff] + Monitor for activity in the window. Windows with activi- + ty are highlighted in the status line. + + mmoonniittoorr--ccoonntteenntt _m_a_t_c_h_-_s_t_r_i_n_g + Monitor content in the window. When _m_a_t_c_h_-_s_t_r_i_n_g appears + in the window, it is highlighted in the status line. + + rreemmaaiinn--oonn--eexxiitt [oonn | ooffff] + A window with this flag set is not destroyed when the + program running in it exits. The window may be reacti- + vated with the rreessppaawwnn--wwiinnddooww command. + + uuttff88 [oonn | ooffff] + Instructs ttmmuuxx to expect UTF-8 sequences to appear in + this window. + + wwiinnddooww--ssttaattuuss--aattttrr _a_t_t_r_i_b_u_t_e_s + Set status line attributes for a single window. + + wwiinnddooww--ssttaattuuss--bbgg _c_o_l_o_u_r + Set status line background colour for a single window. + + wwiinnddooww--ssttaattuuss--ffgg _c_o_l_o_u_r + Set status line foreground colour for a single window. + + xxtteerrmm--kkeeyyss [oonn | ooffff] + If this option is set, ttmmuuxx will generate xterm(1)-style + function key sequences; these have a number included to + indicate modifiers such as shift, meta or ctrl. + + sshhooww--bbuuffffeerr [--bb _b_u_f_f_e_r_-_i_n_d_e_x] [--tt _t_a_r_g_e_t_-_s_e_s_s_i_o_n] + (alias: sshhoowwbb) + Display the contents of the specified buffer. + + sshhooww--ooppttiioonnss [--tt _t_a_r_g_e_t_-_s_e_s_s_i_o_n] _o_p_t_i_o_n _v_a_l_u_e + (alias: sshhooww) + Show the currently set options. If a _t_a_r_g_e_t_-_s_e_s_s_i_o_n is speci- + fied, the options for that session are shown; otherwise, the + global options are listed. + + sshhooww--wwiinnddooww--ooppttiioonnss [--tt _t_a_r_g_e_t_-_w_i_n_d_o_w] _o_p_t_i_o_n _v_a_l_u_e + (alias: sshhoowwww) + List the current options for the given window. + + ssoouurrccee--ffiillee _p_a_t_h + (alias: ssoouurrccee) + Execute commands from _p_a_t_h. + + sspplliitt--wwiinnddooww [--dd] [--ll _l_i_n_e_s | --pp _p_e_r_c_e_n_t_a_g_e] [--tt _t_a_r_g_e_t_-_w_i_n_d_o_w] [_c_o_m_m_a_n_d] + (alias: splitw) + Creates a new window by splitting it vertically. The --ll and --pp + options specify the size of the new window in lines, or as a per- + centage, respectively. All other options have the same meaning + as in the nneeww--wwiinnddooww command. + + A few notes with regard to panes: + 1. If attempting to split a window with less than eight lines, + an error will be shown. + 2. If the window is resized, as many panes are shown as can fit + without reducing them below four lines. + 3. The minimum pane size is four lines (including the separator + line). + 4. The panes are indexed from top (0) to bottom, with no num- + bers skipped. + + ssttaarrtt--sseerrvveerr + (alias: ssttaarrtt) + Start the ttmmuuxx server, if not already running, without creating + any sessions. + + ssuussppeenndd--cclliieenntt [--cc --ttaarrggeett--cclliieenntt] + (alias: ssuussppeennddcc) + Suspend a client by sending SIGTSTP (tty stop). + + sswwaapp--ppaannee [--ddDDUU] [--pp _s_r_c_-_i_n_d_e_x] [--tt _t_a_r_g_e_t_-_w_i_n_d_o_w] [--qq _d_s_t_-_i_n_d_e_x] + (alias: sswwaapppp) + Swap two panes within a window. If --UU is used, the pane is + swapped with the pane above (before it numerically); --DD swaps + with the pane below (the next numerically); or _d_s_t_-_i_n_d_e_x may be + give to swap with a specific pane. + + sswwaapp--wwiinnddooww [--dd] [--ss _s_r_c_-_w_i_n_d_o_w] [--tt _d_s_t_-_w_i_n_d_o_w] + (alias: sswwaappww) + This is similar to lliinnkk--wwiinnddooww, except the source and destination + windows are swapped. It is an error if no window exists at _s_r_c_- + _w_i_n_d_o_w. + + sswwiittcchh--cclliieenntt [--cc _t_a_r_g_e_t_-_c_l_i_e_n_t --tt _t_a_r_g_e_t_-_s_e_s_s_i_o_n] + (alias: sswwiittcchhcc) + Switch the current session for client _t_a_r_g_e_t_-_c_l_i_e_n_t to _t_a_r_g_e_t_- + _s_e_s_s_i_o_n. + + uunnbbiinndd--kkeeyy _k_e_y + (alias: uunnbbiinndd) + Unbind the key bound to _k_e_y. + + uunnlliinnkk--wwiinnddooww [--tt _t_a_r_g_e_t_-_w_i_n_d_o_w] + (alias: uunnlliinnkkww) + Unlink _t_a_r_g_e_t_-_w_i_n_d_o_w. A window may be unlinked only if it is + linked to multiple sessions - windows may not be linked to no + sessions. + + uupp--ppaannee [--pp _p_a_n_e_-_i_n_d_e_x] [--tt _t_a_r_g_e_t_-_w_i_n_d_o_w] + (alias: uupppp) + Move up a pane. + +FFIILLEESS + ~/.tmux.conf + default ttmmuuxx configuration file + +SSEEEE AALLSSOO + pty(4) + +AAUUTTHHOORRSS + Nicholas Marriott + +OpenBSD 4.5 April 20, 2009 13 diff --git a/tmux.h b/tmux.h new file mode 100644 index 00000000..a2d5f0da --- /dev/null +++ b/tmux.h @@ -0,0 +1,1576 @@ +/* $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. + */ + +#ifndef TMUX_H +#define TMUX_H + +#define PROTOCOL_VERSION -13 + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "array.h" + +extern const char *__progname; + +/* Default configuration file. */ +#define DEFAULT_CFG ".tmux.conf" + +/* Default prompt history length. */ +#define PROMPT_HISTORY 100 + +/* Minimum pane size. */ +#define PANE_MINIMUM 4 /* includes separator line */ + +/* Automatic name refresh interval, in milliseconds. */ +#define NAME_INTERVAL 500 + +/* Escape timer period, in milliseconds. */ +#define ESCAPE_PERIOD 250 + +/* Maximum poll timeout (when attached). */ +#define POLL_TIMEOUT 50 + +/* Fatal errors. */ +#define fatal(msg) log_fatal("%s: %s", __func__, msg); +#define fatalx(msg) log_fatalx("%s: %s", __func__, msg); + +/* Definition to shut gcc up about unused arguments. */ +#define unused __attribute__ ((unused)) + +/* Attribute to make gcc check printf-like arguments. */ +#define printflike1 __attribute__ ((format (printf, 1, 2))) +#define printflike2 __attribute__ ((format (printf, 2, 3))) +#define printflike3 __attribute__ ((format (printf, 3, 4))) +#define printflike4 __attribute__ ((format (printf, 4, 5))) + +/* Number of items in array. */ +#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) + +/* Buffer macros. */ +#define BUFFER_USED(b) ((b)->size) +#define BUFFER_FREE(b) ((b)->space - (b)->off - (b)->size) +#define BUFFER_IN(b) ((b)->base + (b)->off + (b)->size) +#define BUFFER_OUT(b) ((b)->base + (b)->off) + +/* Buffer structure. */ +struct buffer { + u_char *base; /* buffer start */ + size_t space; /* total size of buffer */ + + size_t size; /* size of data in buffer */ + size_t off; /* offset of data in buffer */ +}; + +/* Bell option values. */ +#define BELL_NONE 0 +#define BELL_ANY 1 +#define BELL_CURRENT 2 + +/* Key codes. ncurses defines KEY_*. Grrr. */ +#define KEYC_NONE 0x00ffff +#define KEYC_OFFSET 0x010000 +#define KEYC_ESCAPE 0x020000 +#define KEYC_CONTROL 0x080000 +#define KEYC_SHIFT 0x100000 + +#define KEYC_ADDESC(k) ((k) | KEYC_ESCAPE) +#define KEYC_REMOVEESC(k) ((k) & ~KEYC_ESCAPE) +#define KEYC_ISESC(k) ((k) != KEYC_NONE && ((k) & KEYC_ESCAPE)) + +#define KEYC_ADDCTL(k) ((k) | KEYC_CONTROL) +#define KEYC_REMOVECTL(k) ((k) & ~KEYC_CONTROL) +#define KEYC_ISCTL(k) ((k) != KEYC_NONE && ((k) & KEYC_CONTROL)) + +#define KEYC_ADDSFT(k) ((k) | KEYC_SHIFT) +#define KEYC_REMOVESFT(k) ((k) & ~KEYC_SHIFT) +#define KEYC_ISSFT(k) ((k) != KEYC_NONE && ((k) & KEYC_SHIFT)) + +/* Mouse key. */ +#define KEYC_MOUSE (KEYC_OFFSET + 0x00) + +/* Function keys. */ +#define KEYC_F1 (KEYC_OFFSET + 0x01) +#define KEYC_F2 (KEYC_OFFSET + 0x02) +#define KEYC_F3 (KEYC_OFFSET + 0x03) +#define KEYC_F4 (KEYC_OFFSET + 0x04) +#define KEYC_F5 (KEYC_OFFSET + 0x05) +#define KEYC_F6 (KEYC_OFFSET + 0x06) +#define KEYC_F7 (KEYC_OFFSET + 0x07) +#define KEYC_F8 (KEYC_OFFSET + 0x08) +#define KEYC_F9 (KEYC_OFFSET + 0x09) +#define KEYC_F10 (KEYC_OFFSET + 0x10) +#define KEYC_F11 (KEYC_OFFSET + 0x11) +#define KEYC_F12 (KEYC_OFFSET + 0x12) +#define KEYC_F13 (KEYC_OFFSET + 0x13) +#define KEYC_F14 (KEYC_OFFSET + 0x14) +#define KEYC_F15 (KEYC_OFFSET + 0x15) +#define KEYC_F16 (KEYC_OFFSET + 0x16) +#define KEYC_F17 (KEYC_OFFSET + 0x17) +#define KEYC_F18 (KEYC_OFFSET + 0x18) +#define KEYC_F19 (KEYC_OFFSET + 0x19) +#define KEYC_F20 (KEYC_OFFSET + 0x1a) +#define KEYC_IC (KEYC_OFFSET + 0x1b) +#define KEYC_DC (KEYC_OFFSET + 0x1c) +#define KEYC_HOME (KEYC_OFFSET + 0x1d) +#define KEYC_END (KEYC_OFFSET + 0x1e) +#define KEYC_NPAGE (KEYC_OFFSET + 0x1f) +#define KEYC_PPAGE (KEYC_OFFSET + 0x20) +#define KEYC_BTAB (KEYC_OFFSET + 0x21) + +/* Arrow keys. */ +#define KEYC_UP (KEYC_OFFSET + 0x50) +#define KEYC_DOWN (KEYC_OFFSET + 0x51) +#define KEYC_LEFT (KEYC_OFFSET + 0x52) +#define KEYC_RIGHT (KEYC_OFFSET + 0x53) + +/* Numeric keypad. Numbered from top-left, KPY_X. */ +#define KEYC_KP0_1 (KEYC_OFFSET + 0x100) +#define KEYC_KP0_2 (KEYC_OFFSET + 0x101) +#define KEYC_KP0_3 (KEYC_OFFSET + 0x102) +#define KEYC_KP1_0 (KEYC_OFFSET + 0x103) +#define KEYC_KP1_1 (KEYC_OFFSET + 0x104) +#define KEYC_KP1_2 (KEYC_OFFSET + 0x105) +#define KEYC_KP1_3 (KEYC_OFFSET + 0x106) +#define KEYC_KP2_0 (KEYC_OFFSET + 0x107) +#define KEYC_KP2_1 (KEYC_OFFSET + 0x108) +#define KEYC_KP2_2 (KEYC_OFFSET + 0x109) +#define KEYC_KP3_0 (KEYC_OFFSET + 0x10a) +#define KEYC_KP3_1 (KEYC_OFFSET + 0x10b) +#define KEYC_KP3_2 (KEYC_OFFSET + 0x10c) +#define KEYC_KP3_3 (KEYC_OFFSET + 0x10d) +#define KEYC_KP4_0 (KEYC_OFFSET + 0x10e) +#define KEYC_KP4_2 (KEYC_OFFSET + 0x10f) + +/* Termcap codes. */ +enum tty_code_code { + TTYC_AX = 0, + TTYC_ACSC, /* acs_chars, ac */ + TTYC_BEL, /* bell, bl */ + TTYC_BLINK, /* enter_blink_mode, mb */ + TTYC_BOLD, /* enter_bold_mode, md */ + TTYC_CIVIS, /* cursor_invisible, vi */ + TTYC_CLEAR, /* clear_screen, cl */ + TTYC_CNORM, /* cursor_normal, ve */ + TTYC_COLORS, /* max_colors, Co */ + TTYC_CSR, /* change_scroll_region, cs */ + TTYC_CUD, /* parm_down_cursor, DO */ + TTYC_CUD1, /* cursor_down, do */ + TTYC_CUP, /* cursor_address, cm */ + TTYC_DCH, /* parm_dch, DC */ + TTYC_DCH1, /* delete_character, dc */ + TTYC_DIM, /* enter_dim_mode, mh */ + TTYC_DL, /* parm_delete_line, DL */ + TTYC_DL1, /* delete_line, dl */ + TTYC_EL, /* clr_eol, ce */ + TTYC_EL1, /* clr_bol, cb */ + TTYC_ENACS, /* ena_acs, eA */ + TTYC_ICH, /* parm_ich, IC */ + TTYC_ICH1, /* insert_character, ic */ + TTYC_IL, /* parm_insert_line, IL */ + TTYC_IL1, /* insert_line, il */ + TTYC_INVIS, /* enter_secure_mode, mk */ + TTYC_IS1, /* init_1string, i1 */ + TTYC_IS2, /* init_2string, i2 */ + TTYC_IS3, /* init_3string, i3 */ + TTYC_KCBT, /* key_btab, kB */ + TTYC_KCUB1, /* key_left, kl */ + TTYC_KCUD1, /* key_down, kd */ + TTYC_KCUF1, /* key_right, kr */ + TTYC_KCUU1, /* key_up, ku */ + TTYC_KDCH1, /* key_dc, kD */ + TTYC_KEND, /* key_end, ke */ + TTYC_KF1, /* key_f1, k1 */ + TTYC_KF10, /* key_f10, k; */ + TTYC_KF11, /* key_f11, F1 */ + TTYC_KF12, /* key_f12, F2 */ + TTYC_KF13, /* key_f13, F3 */ + TTYC_KF14, /* key_f14, F4 */ + TTYC_KF15, /* key_f15, F5 */ + TTYC_KF16, /* key_f16, F6 */ + TTYC_KF17, /* key_f17, F7 */ + TTYC_KF18, /* key_f18, F8 */ + TTYC_KF19, /* key_f19, F9 */ + TTYC_KF20, /* key_f20, F10 */ + TTYC_KF2, /* key_f2, k2 */ + TTYC_KF3, /* key_f3, k3 */ + TTYC_KF4, /* key_f4, k4 */ + TTYC_KF5, /* key_f5, k5 */ + TTYC_KF6, /* key_f6, k6 */ + TTYC_KF7, /* key_f7, k7 */ + TTYC_KF8, /* key_f8, k8 */ + TTYC_KF9, /* key_f9, k9 */ + TTYC_KHOME, /* key_home, kh */ + TTYC_KICH1, /* key_ic, kI */ + TTYC_KMOUS, /* key_mouse, Km */ + TTYC_KNP, /* key_npage, kN */ + TTYC_KPP, /* key_ppage, kP */ + TTYC_OP, /* orig_pair, op */ + TTYC_REV, /* enter_reverse_mode, mr */ + TTYC_RI, /* scroll_reverse, sr */ + TTYC_RMACS, /* exit_alt_charset_mode */ + TTYC_RMCUP, /* exit_ca_mode, te */ + TTYC_RMIR, /* exit_insert_mode, ei */ + TTYC_RMKX, /* keypad_local, ke */ + TTYC_SETAB, /* set_a_background, AB */ + TTYC_SETAF, /* set_a_foreground, AF */ + TTYC_SGR0, /* exit_attribute_mode, me */ + TTYC_SMACS, /* enter_alt_charset_mode, as */ + TTYC_SMCUP, /* enter_ca_mode, ti */ + TTYC_SMIR, /* enter_insert_mode, im */ + TTYC_SMKX, /* keypad_xmit, ks */ + TTYC_SMSO, /* enter_standout_mode, so */ + TTYC_SMUL, /* enter_underline_mode, us */ + TTYC_XENL, /* eat_newline_glitch, xn */ +}; +#define NTTYCODE (TTYC_XENL + 1) + +/* Termcap types. */ +enum tty_code_type { + TTYCODE_NONE = 0, + TTYCODE_STRING, + TTYCODE_NUMBER, + TTYCODE_FLAG, +}; + +/* Termcap code. */ +struct tty_code { + enum tty_code_type type; + union { + char *string; + int number; + int flag; + } value; +}; + +/* Entry in terminal code table. */ +struct tty_term_code_entry { + enum tty_code_code code; + enum tty_code_type type; + const char *name; +}; + +/* Output commands. */ +enum tty_cmd { + TTY_CELL, + TTY_CLEARENDOFLINE, + TTY_CLEARENDOFSCREEN, + TTY_CLEARLINE, + TTY_CLEARSCREEN, + TTY_CLEARSTARTOFLINE, + TTY_CLEARSTARTOFSCREEN, + TTY_DELETECHARACTER, + TTY_DELETELINE, + TTY_INSERTCHARACTER, + TTY_INSERTLINE, + TTY_LINEFEED, + TTY_RAW, + TTY_REVERSEINDEX, +}; + +/* Message codes. */ +enum hdrtype { + MSG_COMMAND, + MSG_DETACH, + MSG_ERROR, + MSG_EXIT, + MSG_EXITED, + MSG_EXITING, + MSG_IDENTIFY, + MSG_PRINT, + MSG_READY, + MSG_RESIZE, + MSG_SHUTDOWN, + MSG_SUSPEND, + MSG_UNLOCK, + MSG_WAKEUP, +}; + +/* Message header structure. */ +struct hdr { + enum hdrtype type; + size_t size; +}; + +struct msg_command_data { + pid_t pid; /* pid from $TMUX or -1 */ + u_int idx; /* index from $TMUX */ + + size_t namelen; +}; + +struct msg_identify_data { + char tty[TTY_NAME_MAX]; + int version; + + char cwd[MAXPATHLEN]; + +#define IDENTIFY_UTF8 0x1 +#define IDENTIFY_256COLOURS 0x2 +#define IDENTIFY_88COLOURS 0x4 +#define IDENTIFY_HASDEFAULTS 0x8 + int flags; + + u_int sx; + u_int sy; + + size_t termlen; +}; + +struct msg_resize_data { + u_int sx; + u_int sy; +}; + +/* Editing keys. */ +enum mode_key_cmd { + MODEKEYCMD_BACKSPACE = 0x1000, + MODEKEYCMD_CHOOSE, + MODEKEYCMD_CLEARSELECTION, + MODEKEYCMD_COMPLETE, + MODEKEYCMD_COPYSELECTION, + MODEKEYCMD_DELETE, + MODEKEYCMD_DOWN, + MODEKEYCMD_ENDOFLINE, + MODEKEYCMD_LEFT, + MODEKEYCMD_NEXTPAGE, + MODEKEYCMD_NEXTWORD, + MODEKEYCMD_NONE, + MODEKEYCMD_OTHERKEY, + MODEKEYCMD_PASTE, + MODEKEYCMD_PREVIOUSPAGE, + MODEKEYCMD_PREVIOUSWORD, + MODEKEYCMD_QUIT, + MODEKEYCMD_RIGHT, + MODEKEYCMD_STARTOFLINE, + MODEKEYCMD_STARTSELECTION, + MODEKEYCMD_UP, +}; + +struct mode_key_data { + int type; + + int flags; +#define MODEKEY_EDITMODE 0x1 +#define MODEKEY_CANEDIT 0x2 +#define MODEKEY_CHOOSEMODE 0x4 +}; + +#define MODEKEY_EMACS 0 +#define MODEKEY_VI 1 + +/* Modes. */ +#define MODE_CURSOR 0x1 +#define MODE_INSERT 0x2 +#define MODE_KCURSOR 0x4 +#define MODE_KKEYPAD 0x8 +#define MODE_MOUSE 0x10 + +/* Grid output. */ +#if defined(DEBUG) && \ + ((defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || \ + (defined(__GNUC__) && __GNUC__ >= 3)) +#define GRID_DEBUG(gd, fmt, ...) log_debug3("%s: (sx=%u, sy=%u, hsize=%u) " \ + fmt, __func__, (gd)->sx, (gd)->sy, (gd)->hsize, ## __VA_ARGS__) +#else +#define GRID_DEBUG(...) +#endif + +/* Grid attributes. */ +#define GRID_ATTR_BRIGHT 0x1 +#define GRID_ATTR_DIM 0x2 +#define GRID_ATTR_UNDERSCORE 0x4 +#define GRID_ATTR_BLINK 0x8 +#define GRID_ATTR_REVERSE 0x10 +#define GRID_ATTR_HIDDEN 0x20 +#define GRID_ATTR_ITALICS 0x40 +#define GRID_ATTR_CHARSET 0x80 /* alternative character set */ + +/* Grid flags. */ +#define GRID_FLAG_FG256 0x1 +#define GRID_FLAG_BG256 0x2 +#define GRID_FLAG_PADDING 0x4 +#define GRID_FLAG_UTF8 0x8 + +/* Grid cell data. */ +struct grid_cell { + u_char attr; + u_char flags; + u_char fg; + u_char bg; + u_char data; +} __packed; + +/* Grid cell UTF-8 data. Used instead of data in grid_cell for UTF-8 cells. */ +#define UTF8_SIZE 8 +struct grid_utf8 { + u_char width; + u_char data[UTF8_SIZE]; +} __packed; + +/* Entire grid of cells. */ +struct grid { + u_int sx; + u_int sy; + + u_int hsize; + u_int hlimit; + + u_int *size; + struct grid_cell **data; + + u_int *usize; + struct grid_utf8 **udata; +}; + +/* Option data structures. */ +struct options_entry { + char *name; + + enum { + OPTIONS_STRING, + OPTIONS_NUMBER, + OPTIONS_KEY, + } type; + union { + char *string; + long long number; + int key; + } value; + + SPLAY_ENTRY(options_entry) entry; +}; + +struct options { + SPLAY_HEAD(options_tree, options_entry) tree; + struct options *parent; +}; + +/* Screen selection. */ +struct screen_sel { + int flag; + + u_int sx; + u_int sy; + + u_int ex; + u_int ey; + + struct grid_cell cell; +}; + +/* Virtual screen. */ +struct screen { + char *title; + + struct grid *grid; /* grid data */ + + u_int cx; /* cursor x */ + u_int cy; /* cursor y */ + + u_int old_cx; + u_int old_cy; + + u_int rupper; /* scroll region top */ + u_int rlower; /* scroll region bottom */ + + u_int old_rupper; + u_int old_rlower; + + int mode; + + struct screen_sel sel; +}; + +/* Screen write context. */ +struct screen_write_ctx { + struct window_pane *wp; + struct screen *s; +}; + +/* Screen size. */ +#define screen_size_x(s) ((s)->grid->sx) +#define screen_size_y(s) ((s)->grid->sy) +#define screen_hsize(s) ((s)->grid->hsize) +#define screen_hlimit(s) ((s)->grid->hlimit) + +/* Input parser sequence argument. */ +struct input_arg { + u_char data[64]; + size_t used; +}; + +/* Input parser context. */ +struct input_ctx { + struct window_pane *wp; + struct screen_write_ctx ctx; + + u_char *buf; + size_t len; + size_t off; + + struct grid_cell cell; + + + struct grid_cell saved_cell; + u_int saved_cx; + u_int saved_cy; + +#define MAXSTRINGLEN 1024 + u_char *string_buf; + size_t string_len; + int string_type; +#define STRING_SYSTEM 0 +#define STRING_APPLICATION 1 +#define STRING_NAME 2 + + u_char utf8_buf[4]; + u_int utf8_len; + u_int utf8_off; + + u_char intermediate; + void *(*state)(u_char, struct input_ctx *); + + u_char private; + ARRAY_DECL(, struct input_arg) args; +}; + +/* + * Window mode. Windows can be in several modes and this is used to call the + * right function to handle input and output. + */ +struct client; +struct window; +struct window_mode { + struct screen *(*init)(struct window_pane *); + void (*free)(struct window_pane *); + void (*resize)(struct window_pane *, u_int, u_int); + void (*key)(struct window_pane *, struct client *, int); + void (*mouse)(struct window_pane *, + struct client *, u_char, u_char, u_char); + void (*timer)(struct window_pane *); +}; + +/* Child window structure. */ +struct window_pane { + struct window *window; + + u_int sx; + u_int sy; + + u_int xoff; + u_int yoff; + + int flags; +#define PANE_HIDDEN 0x1 +#define PANE_RESTART 0x2 +#define PANE_REDRAW 0x4 + + char *cmd; + char *cwd; + + pid_t pid; + int fd; + char tty[TTY_NAME_MAX]; + struct buffer *in; + struct buffer *out; + + struct input_ctx ictx; + + struct screen *screen; + struct screen base; + + const struct window_mode *mode; + void *modedata; + + TAILQ_ENTRY(window_pane) entry; +}; +TAILQ_HEAD(window_panes, window_pane); + +/* Window structure. */ +struct window { + char *name; + struct timeval name_timer; + + struct window_pane *active; + struct window_panes panes; + u_int layout; + + u_int sx; + u_int sy; + + int flags; +#define WINDOW_BELL 0x1 +#define WINDOW_HIDDEN 0x2 +#define WINDOW_ACTIVITY 0x4 +#define WINDOW_CONTENT 0x6 +#define WINDOW_REDRAW 0x8 + + struct options options; + + u_int references; +}; +ARRAY_DECL(windows, struct window *); + +/* Entry on local window list. */ +struct winlink { + int idx; + struct window *window; + + RB_ENTRY(winlink) entry; + SLIST_ENTRY(winlink) sentry; +}; +RB_HEAD(winlinks, winlink); +SLIST_HEAD(winlink_stack, winlink); + +/* Paste buffer. */ +struct paste_buffer { + char *data; + struct timeval tv; +}; +ARRAY_DECL(paste_stack, struct paste_buffer *); + +/* Client session. */ +struct session_alert { + struct winlink *wl; + int type; + + SLIST_ENTRY(session_alert) entry; +}; + +struct session { + char *name; + struct timeval tv; + + u_int sx; + u_int sy; + + struct winlink *curw; + struct winlink_stack lastw; + struct winlinks windows; + + struct options options; + + struct paste_stack buffers; + + SLIST_HEAD(, session_alert) alerts; + +#define SESSION_UNATTACHED 0x1 /* not attached to any clients */ + int flags; +}; +ARRAY_DECL(sessions, struct session *); + +/* TTY information. */ +struct tty_key { + int key; + char *string; + + int flags; +#define TTYKEY_CTRL 0x1 +#define TTYKEY_RAW 0x2 + + RB_ENTRY(tty_key) entry; +}; + +struct tty_term { + char *name; + u_int references; + + struct tty_code codes[NTTYCODE]; + +#define TERM_HASDEFAULTS 0x1 +#define TERM_256COLOURS 0x2 +#define TERM_88COLOURS 0x4 +#define TERM_EARLYWRAP 0x8 + int flags; + + SLIST_ENTRY(tty_term) entry; +}; +SLIST_HEAD(tty_terms, tty_term); + +struct tty { + char *path; + + u_int sx; + u_int sy; + + u_int cx; + u_int cy; + + int mode; + + u_int rlower; + u_int rupper; + + char *termname; + struct tty_term *term; + + int fd; + struct buffer *in; + struct buffer *out; + + int log_fd; + + struct termios tio; + + struct grid_cell cell; + + u_char acs[UCHAR_MAX + 1]; + +#define TTY_NOCURSOR 0x1 +#define TTY_FREEZE 0x2 +#define TTY_ESCAPE 0x4 +#define TTY_UTF8 0x8 + int flags; + + int term_flags; + + struct timeval key_timer; + + size_t ksize; /* maximum key size */ + RB_HEAD(tty_keys, tty_key) ktree; +}; + +/* Client connection. */ +struct client { + int fd; + struct buffer *in; + struct buffer *out; + + char *title; + char *cwd; + + struct tty tty; + struct timeval status_timer; + struct timeval repeat_timer; + + struct screen status; + +#define CLIENT_TERMINAL 0x1 +#define CLIENT_PREFIX 0x2 +#define CLIENT_MOUSE 0x4 +#define CLIENT_REDRAW 0x8 +#define CLIENT_STATUS 0x10 +#define CLIENT_REPEAT 0x20 /* allow command to repeat within repeat time */ +#define CLIENT_SUSPENDED 0x40 + int flags; + + char *message_string; + struct timeval message_timer; + + char *prompt_string; + char *prompt_buffer; + size_t prompt_index; + int (*prompt_callback)(void *, const char *); + void *prompt_data; + +#define PROMPT_HIDDEN 0x1 +#define PROMPT_SINGLE 0x2 + int prompt_flags; + + u_int prompt_hindex; + ARRAY_DECL(, char *) prompt_hdata; + + struct mode_key_data prompt_mdata; + + struct session *session; +}; +ARRAY_DECL(clients, struct client *); + +/* Client context. */ +struct client_ctx { + int srv_fd; + struct buffer *srv_in; + struct buffer *srv_out; + +#define CCTX_DETACH 0x1 +#define CCTX_EXIT 0x2 +#define CCTX_SHUTDOWN 0x4 + int flags; +}; + +/* Key/command line command. */ +struct cmd_ctx { + struct client *cmdclient; + + struct client *curclient; + struct session *cursession; + struct msg_command_data *msgdata; + + void (*print)(struct cmd_ctx *, const char *, ...); + void (*info)(struct cmd_ctx *, const char *, ...); + void (*error)(struct cmd_ctx *, const char *, ...); +}; + +struct cmd { + const struct cmd_entry *entry; + void *data; + + TAILQ_ENTRY(cmd) qentry; +}; +TAILQ_HEAD(cmd_list, cmd); + +struct cmd_entry { + const char *name; + const char *alias; + const char *usage; + +#define CMD_STARTSERVER 0x1 +#define CMD_CANTNEST 0x2 +#define CMD_ARG1 0x4 +#define CMD_ARG01 0x8 +#define CMD_AFLAG 0x10 +#define CMD_DFLAG 0x20 +#define CMD_GFLAG 0x40 +#define CMD_KFLAG 0x80 +#define CMD_UFLAG 0x100 +#define CMD_BIGDFLAG 0x200 +#define CMD_BIGUFLAG 0x400 + + int flags; + + void (*init)(struct cmd *, int); + int (*parse)(struct cmd *, int, char **, char **); + int (*exec)(struct cmd *, struct cmd_ctx *); + void (*send)(struct cmd *, struct buffer *); + void (*recv)(struct cmd *, struct buffer *); + void (*free)(struct cmd *); + size_t (*print)(struct cmd *, char *, size_t); +}; + +/* Generic command data. */ +struct cmd_target_data { + int flags; + char *target; + char *arg; +}; + +struct cmd_srcdst_data { + int flags; + char *src; + char *dst; + char *arg; +}; + +struct cmd_buffer_data { + int flags; + char *target; + int buffer; + char *arg; +}; + +struct cmd_option_data { + int flags; + char *target; + char *option; + char *value; +}; + +struct cmd_pane_data { + int flags; + char *target; + char *arg; + int pane; +}; + +/* Key binding. */ +struct key_binding { + int key; + struct cmd_list *cmdlist; + int can_repeat; + + SPLAY_ENTRY(key_binding) entry; +}; +SPLAY_HEAD(key_bindings, key_binding); + +/* Set/display option data. */ +struct set_option_entry { + const char *name; + enum { + SET_OPTION_STRING, + SET_OPTION_NUMBER, + SET_OPTION_KEY, + SET_OPTION_COLOUR, + SET_OPTION_ATTRIBUTES, + SET_OPTION_FLAG, + SET_OPTION_CHOICE + } type; + + u_int minimum; + u_int maximum; + + const char **choices; +}; +extern const struct set_option_entry set_option_table[]; +extern const struct set_option_entry set_window_option_table[]; +#define NSETOPTION 24 +#define NSETWINDOWOPTION 19 + +/* tmux.c */ +extern volatile sig_atomic_t sigwinch; +extern volatile sig_atomic_t sigterm; +extern volatile sig_atomic_t sigcont; +extern volatile sig_atomic_t sigchld; +extern volatile sig_atomic_t sigusr1; +extern volatile sig_atomic_t sigusr2; +extern struct options global_options; +extern struct options global_window_options; +extern char *cfg_file; +extern int server_locked; +extern char *server_password; +extern time_t server_activity; +extern int debug_level; +extern int be_quiet; +extern time_t start_time; +extern char *socket_path; +void logfile(const char *); +void siginit(void); +void sigreset(void); +void sighandler(int); + +/* cfg.c */ +int load_cfg(const char *, char **x); + +/* mode-key.c */ +void mode_key_init(struct mode_key_data *, int, int); +void mode_key_free(struct mode_key_data *); +enum mode_key_cmd mode_key_lookup(struct mode_key_data *, int); + +/* options.c */ +int options_cmp(struct options_entry *, struct options_entry *); +SPLAY_PROTOTYPE(options_tree, options_entry, entry, options_cmp); +void options_init(struct options *, struct options *); +void options_free(struct options *); +struct options_entry *options_find1(struct options *, const char *); +struct options_entry *options_find(struct options *, const char *); +int options_remove(struct options *, const char *); +void printflike3 options_set_string( + struct options *, const char *, const char *, ...); +char *options_get_string(struct options *, const char *); +void options_set_number(struct options *, const char *, long long); +long long options_get_number(struct options *, const char *); + +/* tty.c */ +u_char tty_get_acs(struct tty *, u_char); +void tty_emulate_repeat(struct tty *, + enum tty_code_code, enum tty_code_code, u_int); +void tty_reset(struct tty *); +void tty_region(struct tty *, u_int, u_int, u_int); +void tty_cursor(struct tty *, u_int, u_int, u_int, u_int); +void tty_cell(struct tty *, + const struct grid_cell *, const struct grid_utf8 *); +void tty_putcode(struct tty *, enum tty_code_code); +void tty_putcode1(struct tty *, enum tty_code_code, int); +void tty_putcode2(struct tty *, enum tty_code_code, int, int); +void tty_puts(struct tty *, const char *); +void tty_putc(struct tty *, u_char); +void tty_init(struct tty *, char *, char *); +void tty_start_tty(struct tty *); +void tty_stop_tty(struct tty *); +void tty_detect_utf8(struct tty *); +void tty_set_title(struct tty *, const char *); +void tty_update_mode(struct tty *, int); +void tty_draw_line( + struct tty *, struct screen *, u_int, u_int, u_int); +void tty_redraw_region(struct tty *, struct window_pane *); +int tty_open(struct tty *, char **); +void tty_close(struct tty *, int); +void tty_free(struct tty *, int); +void tty_write( + struct tty *, struct window_pane *, enum tty_cmd, ...); +void tty_vwrite( + struct tty *, struct window_pane *, enum tty_cmd, va_list); + +/* tty-term.c */ +extern struct tty_terms tty_terms; +extern struct tty_term_code_entry tty_term_codes[NTTYCODE]; +struct tty_term *tty_term_find(char *, int, char **); +void tty_term_free(struct tty_term *); +int tty_term_has(struct tty_term *, enum tty_code_code); +const char *tty_term_string(struct tty_term *, enum tty_code_code); +const char *tty_term_string1(struct tty_term *, enum tty_code_code, int); +const char *tty_term_string2( + struct tty_term *, enum tty_code_code, int, int); +int tty_term_number(struct tty_term *, enum tty_code_code); +int tty_term_flag(struct tty_term *, enum tty_code_code); + +/* tty-keys.c */ +int tty_keys_cmp(struct tty_key *, struct tty_key *); +RB_PROTOTYPE(tty_keys, tty_key, entry, tty_keys_cmp); +void tty_keys_init(struct tty *); +void tty_keys_free(struct tty *); +int tty_keys_next(struct tty *, int *, u_char *); + +/* tty-write.c */ +void tty_write_cmd(struct window_pane *, enum tty_cmd, ...); +void tty_write_mode(struct window_pane *, int); + +/* options-cmd.c */ +void set_option_string(struct cmd_ctx *, + struct options *, const struct set_option_entry *, char *); +void set_option_number(struct cmd_ctx *, + struct options *, const struct set_option_entry *, char *); +void set_option_key(struct cmd_ctx *, + struct options *, const struct set_option_entry *, char *); +void set_option_colour(struct cmd_ctx *, + struct options *, const struct set_option_entry *, char *); +void set_option_attributes(struct cmd_ctx *, + struct options *, const struct set_option_entry *, char *); +void set_option_flag(struct cmd_ctx *, + struct options *, const struct set_option_entry *, char *); +void set_option_choice(struct cmd_ctx *, + struct options *, const struct set_option_entry *, char *); + +/* paste.c */ +void paste_init_stack(struct paste_stack *); +void paste_free_stack(struct paste_stack *); +struct paste_buffer *paste_walk_stack(struct paste_stack *, uint *); +struct paste_buffer *paste_get_top(struct paste_stack *); +struct paste_buffer *paste_get_index(struct paste_stack *, u_int); +int paste_free_top(struct paste_stack *); +int paste_free_index(struct paste_stack *, u_int); +void paste_add(struct paste_stack *, char *, u_int); +int paste_replace(struct paste_stack *, u_int, char *); + +/* clock.c */ +void clock_draw(struct screen_write_ctx *, u_int, int); + +/* arg.c */ +struct client *arg_parse_client(const char *); +struct session *arg_parse_session(const char *); +int arg_parse_window(const char *, struct session **, int *); + +/* cmd.c */ +struct cmd *cmd_parse(int, char **, char **); +int cmd_exec(struct cmd *, struct cmd_ctx *); +void cmd_send(struct cmd *, struct buffer *); +struct cmd *cmd_recv(struct buffer *); +void cmd_free(struct cmd *); +size_t cmd_print(struct cmd *, char *, size_t); +void cmd_send_string(struct buffer *, const char *); +char *cmd_recv_string(struct buffer *); +struct session *cmd_current_session(struct cmd_ctx *); +struct client *cmd_find_client(struct cmd_ctx *, const char *); +struct session *cmd_find_session(struct cmd_ctx *, const char *); +struct winlink *cmd_find_window( + struct cmd_ctx *, const char *, struct session **); +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; +extern const struct cmd_entry cmd_break_pane_entry; +extern const struct cmd_entry cmd_choose_session_entry; +extern const struct cmd_entry cmd_choose_window_entry; +extern const struct cmd_entry cmd_clear_history_entry; +extern const struct cmd_entry cmd_clock_mode_entry; +extern const struct cmd_entry cmd_command_prompt_entry; +extern const struct cmd_entry cmd_confirm_before_entry; +extern const struct cmd_entry cmd_copy_buffer_entry; +extern const struct cmd_entry cmd_copy_mode_entry; +extern const struct cmd_entry cmd_delete_buffer_entry; +extern const struct cmd_entry cmd_detach_client_entry; +extern const struct cmd_entry cmd_down_pane_entry; +extern const struct cmd_entry cmd_find_window_entry; +extern const struct cmd_entry cmd_has_session_entry; +extern const struct cmd_entry cmd_kill_pane_entry; +extern const struct cmd_entry cmd_kill_server_entry; +extern const struct cmd_entry cmd_kill_session_entry; +extern const struct cmd_entry cmd_kill_window_entry; +extern const struct cmd_entry cmd_last_window_entry; +extern const struct cmd_entry cmd_link_window_entry; +extern const struct cmd_entry cmd_list_buffers_entry; +extern const struct cmd_entry cmd_list_clients_entry; +extern const struct cmd_entry cmd_list_commands_entry; +extern const struct cmd_entry cmd_list_keys_entry; +extern const struct cmd_entry cmd_list_sessions_entry; +extern const struct cmd_entry cmd_list_windows_entry; +extern const struct cmd_entry cmd_load_buffer_entry; +extern const struct cmd_entry cmd_lock_server_entry; +extern const struct cmd_entry cmd_move_window_entry; +extern const struct cmd_entry cmd_new_session_entry; +extern const struct cmd_entry cmd_new_window_entry; +extern const struct cmd_entry cmd_next_layout_entry; +extern const struct cmd_entry cmd_next_window_entry; +extern const struct cmd_entry cmd_paste_buffer_entry; +extern const struct cmd_entry cmd_previous_layout_entry; +extern const struct cmd_entry cmd_previous_window_entry; +extern const struct cmd_entry cmd_refresh_client_entry; +extern const struct cmd_entry cmd_rename_session_entry; +extern const struct cmd_entry cmd_rename_window_entry; +extern const struct cmd_entry cmd_resize_pane_entry; +extern const struct cmd_entry cmd_respawn_window_entry; +extern const struct cmd_entry cmd_rotate_window_entry; +extern const struct cmd_entry cmd_save_buffer_entry; +extern const struct cmd_entry cmd_scroll_mode_entry; +extern const struct cmd_entry cmd_select_layout_entry; +extern const struct cmd_entry cmd_select_pane_entry; +extern const struct cmd_entry cmd_select_prompt_entry; +extern const struct cmd_entry cmd_select_window_entry; +extern const struct cmd_entry cmd_send_keys_entry; +extern const struct cmd_entry cmd_send_prefix_entry; +extern const struct cmd_entry cmd_server_info_entry; +extern const struct cmd_entry cmd_set_buffer_entry; +extern const struct cmd_entry cmd_set_option_entry; +extern const struct cmd_entry cmd_set_password_entry; +extern const struct cmd_entry cmd_set_window_option_entry; +extern const struct cmd_entry cmd_show_buffer_entry; +extern const struct cmd_entry cmd_show_options_entry; +extern const struct cmd_entry cmd_show_window_options_entry; +extern const struct cmd_entry cmd_source_file_entry; +extern const struct cmd_entry cmd_split_window_entry; +extern const struct cmd_entry cmd_start_server_entry; +extern const struct cmd_entry cmd_suspend_client_entry; +extern const struct cmd_entry cmd_swap_pane_entry; +extern const struct cmd_entry cmd_swap_window_entry; +extern const struct cmd_entry cmd_switch_client_entry; +extern const struct cmd_entry cmd_unbind_key_entry; +extern const struct cmd_entry cmd_unlink_window_entry; +extern const struct cmd_entry cmd_up_pane_entry; + +/* cmd-list.c */ +struct cmd_list *cmd_list_parse(int, char **, char **); +int cmd_list_exec(struct cmd_list *, struct cmd_ctx *); +void cmd_list_send(struct cmd_list *, struct buffer *); +struct cmd_list *cmd_list_recv(struct buffer *); +void cmd_list_free(struct cmd_list *); +size_t cmd_list_print(struct cmd_list *, char *, size_t); + +/* cmd-string.c */ +int cmd_string_parse(const char *, struct cmd_list **, char **); + +/* cmd-generic.c */ +size_t cmd_prarg(char *, size_t, const char *, char *); +#define CMD_TARGET_WINDOW_USAGE "[-t target-window]" +#define CMD_TARGET_SESSION_USAGE "[-t target-session]" +#define CMD_TARGET_CLIENT_USAGE "[-t target-client]" +void cmd_target_init(struct cmd *, int); +int cmd_target_parse(struct cmd *, int, char **, char **); +void cmd_target_send(struct cmd *, struct buffer *); +void cmd_target_recv(struct cmd *, struct buffer *); +void cmd_target_free(struct cmd *); +size_t cmd_target_print(struct cmd *, char *, size_t); +#define CMD_SRCDST_WINDOW_USAGE "[-s src-window] [-t dst-window]" +#define CMD_SRCDST_SESSION_USAGE "[-s src-session] [-t dst-session]" +#define CMD_SRCDST_CLIENT_USAGE "[-s src-client] [-t dst-client]" +void cmd_srcdst_init(struct cmd *, int); +int cmd_srcdst_parse(struct cmd *, int, char **, char **); +void cmd_srcdst_send(struct cmd *, struct buffer *); +void cmd_srcdst_recv(struct cmd *, struct buffer *); +void cmd_srcdst_free(struct cmd *); +size_t cmd_srcdst_print(struct cmd *, char *, size_t); +#define CMD_BUFFER_WINDOW_USAGE "[-b buffer-index] [-t target-window]" +#define CMD_BUFFER_SESSION_USAGE "[-b buffer-index] [-t target-session]" +#define CMD_BUFFER_CLIENT_USAGE "[-b buffer-index] [-t target-client]" +void cmd_buffer_init(struct cmd *, int); +int cmd_buffer_parse(struct cmd *, int, char **, char **); +void cmd_buffer_send(struct cmd *, struct buffer *); +void cmd_buffer_recv(struct cmd *, struct buffer *); +void cmd_buffer_free(struct cmd *); +size_t cmd_buffer_print(struct cmd *, char *, size_t); +#define CMD_OPTION_WINDOW_USAGE "[-gu] [-t target-window] option [value]" +#define CMD_OPTION_SESSION_USAGE "[-gu] [-t target-session] option [value]" +#define CMD_OPTION_CLIENT_USAGE "[-gu] [-t target-client] option [value]" +void cmd_option_init(struct cmd *, int); +int cmd_option_parse(struct cmd *, int, char **, char **); +void cmd_option_send(struct cmd *, struct buffer *); +void cmd_option_recv(struct cmd *, struct buffer *); +void cmd_option_free(struct cmd *); +size_t cmd_option_print(struct cmd *, char *, size_t); +#define CMD_PANE_WINDOW_USAGE "[-t target-window] [-p pane-index]" +#define CMD_PANE_SESSION_USAGE "[-t target-session] [-p pane-index]" +#define CMD_PANE_CLIENT_USAGE "[-t target-client] [-p pane-index]" +void cmd_pane_init(struct cmd *, int); +int cmd_pane_parse(struct cmd *, int, char **, char **); +void cmd_pane_send(struct cmd *, struct buffer *); +void cmd_pane_recv(struct cmd *, struct buffer *); +void cmd_pane_free(struct cmd *); +size_t cmd_pane_print(struct cmd *, char *, size_t); + +/* client.c */ +int client_init(char *, struct client_ctx *, int, int); +int client_flush(struct client_ctx *); +int client_main(struct client_ctx *); + +/* client-msg.c */ +int client_msg_dispatch(struct client_ctx *, char **); + +/* client-fn.c */ +void client_write_server(struct client_ctx *, enum hdrtype, void *, size_t); +void client_write_server2( + struct client_ctx *, enum hdrtype, void *, size_t, void *, size_t); +void client_fill_session(struct msg_command_data *); + +/* key-bindings.c */ +extern struct key_bindings key_bindings; +int key_bindings_cmp(struct key_binding *, struct key_binding *); +SPLAY_PROTOTYPE(key_bindings, key_binding, entry, key_bindings_cmp); +struct key_binding *key_bindings_lookup(int); +void key_bindings_add(int, int, struct cmd_list *); +void key_bindings_remove(int); +void key_bindings_init(void); +void key_bindings_free(void); +void key_bindings_dispatch(struct key_binding *, struct client *); +void printflike2 key_bindings_error(struct cmd_ctx *, const char *, ...); +void printflike2 key_bindings_print(struct cmd_ctx *, const char *, ...); +void printflike2 key_bindings_info(struct cmd_ctx *, const char *, ...); + +/* key-string.c */ +int key_string_lookup_string(const char *); +const char *key_string_lookup_key(int); + +/* server.c */ +extern struct clients clients; +struct client *server_create_client(int); +int server_client_index(struct client *); +int server_start(char *); + +/* server-msg.c */ +int server_msg_dispatch(struct client *); + +/* server-fn.c */ +const char **server_fill_environ(struct session *); +void server_write_client( + struct client *, enum hdrtype, const void *, size_t); +void server_write_session( + struct session *, enum hdrtype, const void *, size_t); +void server_write_window( + struct window *, enum hdrtype, const void *, size_t); +void server_redraw_client(struct client *); +void server_status_client(struct client *); +void server_redraw_session(struct session *); +void server_status_session(struct session *); +void server_redraw_window(struct window *); +void server_status_window(struct window *); +void server_lock(void); +int server_unlock(const char *); + +/* status.c */ +int status_redraw(struct client *); +void status_message_set(struct client *, const char *); +void status_message_clear(struct client *); +int status_message_redraw(struct client *); +void status_prompt_set(struct client *, + const char *, int (*)(void *, const char *), void *, int); +void status_prompt_clear(struct client *); +int status_prompt_redraw(struct client *); +void status_prompt_key(struct client *, int); + +/* resize.c */ +void recalculate_sizes(void); + +/* input.c */ +void input_init(struct window_pane *); +void input_free(struct window_pane *); +void input_parse(struct window_pane *); + +/* input-key.c */ +void input_key(struct window_pane *, int); +void input_mouse(struct window_pane *, u_char, u_char, u_char); + +/* colour.c */ +const char *colour_tostring(u_char); +int colour_fromstring(const char *); +u_char colour_256to16(u_char); +u_char colour_256to88(u_char); + +/* attributes.c */ +const char *attributes_tostring(u_char); +int attributes_fromstring(const char *); + +/* grid.c */ +extern const struct grid_cell grid_default_cell; +struct grid *grid_create(u_int, u_int, u_int); +void grid_destroy(struct grid *); +int grid_compare(struct grid *, struct grid *); +void grid_reduce_line(struct grid *, u_int, u_int); +void grid_expand_line(struct grid *, u_int, u_int); +void grid_expand_line_utf8(struct grid *, u_int, u_int); +void grid_scroll_line(struct grid *); +const struct grid_cell *grid_peek_cell(struct grid *, u_int, u_int); +struct grid_cell *grid_get_cell(struct grid *, u_int, u_int); +void grid_set_cell(struct grid *, u_int, u_int, const struct grid_cell *); +const struct grid_utf8 *grid_peek_utf8(struct grid *, u_int, u_int); +struct grid_utf8 *grid_get_utf8(struct grid *, u_int, u_int); +void grid_set_utf8(struct grid *, u_int, u_int, const struct grid_utf8 *); +void grid_clear(struct grid *, u_int, u_int, u_int, u_int); +void grid_clear_lines(struct grid *, u_int, u_int); +void grid_move_lines(struct grid *, u_int, u_int, u_int); +void grid_clear_cells(struct grid *, u_int, u_int, u_int); +void grid_move_cells(struct grid *, u_int, u_int, u_int, u_int); + +/* grid-view.c */ +const struct grid_cell *grid_view_peek_cell(struct grid *, u_int, u_int); +struct grid_cell *grid_view_get_cell(struct grid *, u_int, u_int); +void grid_view_set_cell( + struct grid *, u_int, u_int, const struct grid_cell *); +const struct grid_utf8 *grid_view_peek_utf8(struct grid *, u_int, u_int); +struct grid_utf8 *grid_view_get_utf8(struct grid *, u_int, u_int); +void grid_view_set_utf8( + struct grid *, u_int, u_int, const struct grid_utf8 *); +void grid_view_clear(struct grid *, u_int, u_int, u_int, u_int); +void grid_view_scroll_region_up(struct grid *, u_int, u_int); +void grid_view_scroll_region_down(struct grid *, u_int, u_int); +void grid_view_insert_lines(struct grid *, u_int, u_int); +void grid_view_insert_lines_region( + struct grid *, u_int, u_int, u_int, u_int); +void grid_view_delete_lines(struct grid *, u_int, u_int); +void grid_view_delete_lines_region( + struct grid *, u_int, u_int, u_int, u_int); +void grid_view_insert_cells(struct grid *, u_int, u_int, u_int); +void grid_view_delete_cells(struct grid *, u_int, u_int, u_int); + +/* screen-write.c */ +void screen_write_start( + struct screen_write_ctx *, struct window_pane *, struct screen *); +void screen_write_stop(struct screen_write_ctx *); +void printflike3 screen_write_puts( + struct screen_write_ctx *, 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 *, + struct screen *, u_int, u_int, u_int, u_int); +void screen_write_cursorup(struct screen_write_ctx *, u_int); +void screen_write_cursordown(struct screen_write_ctx *, u_int); +void screen_write_cursorright(struct screen_write_ctx *, u_int); +void screen_write_cursorleft(struct screen_write_ctx *, u_int); +void screen_write_insertcharacter(struct screen_write_ctx *, u_int); +void screen_write_deletecharacter(struct screen_write_ctx *, u_int); +void screen_write_insertline(struct screen_write_ctx *, u_int); +void screen_write_deleteline(struct screen_write_ctx *, u_int); +void screen_write_clearline(struct screen_write_ctx *); +void screen_write_clearendofline(struct screen_write_ctx *); +void screen_write_clearstartofline(struct screen_write_ctx *); +void screen_write_cursormove(struct screen_write_ctx *, u_int, u_int); +void screen_write_cursormode(struct screen_write_ctx *, int); +void screen_write_reverseindex(struct screen_write_ctx *); +void screen_write_scrollregion(struct screen_write_ctx *, u_int, u_int); +void screen_write_insertmode(struct screen_write_ctx *, int); +void screen_write_mousemode(struct screen_write_ctx *, int); +void screen_write_linefeed(struct screen_write_ctx *); +void screen_write_carriagereturn(struct screen_write_ctx *); +void screen_write_kcursormode(struct screen_write_ctx *, int); +void screen_write_kkeypadmode(struct screen_write_ctx *, int); +void screen_write_clearendofscreen(struct screen_write_ctx *); +void screen_write_clearstartofscreen(struct screen_write_ctx *); +void screen_write_clearscreen(struct screen_write_ctx *); +void screen_write_cell( + struct screen_write_ctx *, const struct grid_cell *, u_char *); + +/* screen-redraw.c */ +void screen_redraw_screen(struct client *); +void screen_redraw_pane(struct client *, struct window_pane *); +void screen_redraw_status(struct client *); + +/* screen.c */ +void screen_init(struct screen *, u_int, u_int, u_int); +void screen_reinit(struct screen *); +void screen_free(struct screen *); +void screen_set_title(struct screen *, const char *); +void screen_resize(struct screen *, u_int, u_int); +void screen_set_selection( + struct screen *, u_int, u_int, u_int, u_int, struct grid_cell *); +void screen_clear_selection(struct screen *); +int screen_check_selection(struct screen *, u_int, u_int); +void screen_display_copy_area(struct screen *, struct screen *, + u_int, u_int, u_int, u_int, u_int, u_int); + +/* window.c */ +extern struct windows windows; +int window_cmp(struct window *, struct window *); +int winlink_cmp(struct winlink *, struct winlink *); +RB_PROTOTYPE(windows, window, entry, window_cmp); +RB_PROTOTYPE(winlinks, winlink, entry, winlink_cmp); +struct winlink *winlink_find_by_index(struct winlinks *, int); +struct winlink *winlink_find_by_window(struct winlinks *, struct window *); +int winlink_next_index(struct winlinks *); +u_int winlink_count(struct winlinks *); +struct winlink *winlink_add(struct winlinks *, struct window *, int); +void winlink_remove(struct winlinks *, struct winlink *); +struct winlink *winlink_next(struct winlinks *, struct winlink *); +struct winlink *winlink_previous(struct winlinks *, struct winlink *); +void winlink_stack_push(struct winlink_stack *, struct winlink *); +void winlink_stack_remove(struct winlink_stack *, struct winlink *); +int window_index(struct window *, u_int *); +struct window *window_create1(u_int, u_int); +struct window *window_create(const char *, const char *, + const char *, const char **, u_int, u_int, u_int, char **); +void window_destroy(struct window *); +int window_resize(struct window *, u_int, u_int); +void window_set_active_pane(struct window *, struct window_pane *); +struct window_pane *window_add_pane(struct window *, int, + const char *, const char *, const char **, u_int, char **); +void window_remove_pane(struct window *, struct window_pane *); +u_int window_index_of_pane(struct window *, struct window_pane *); +struct window_pane *window_pane_at_index(struct window *, u_int); +u_int window_count_panes(struct window *); +void window_destroy_panes(struct window *); +struct window_pane *window_pane_create(struct window *, u_int, u_int, u_int); +void window_pane_destroy(struct window_pane *); +int window_pane_spawn(struct window_pane *, + const char *, const char *, const char **, char **); +int window_pane_resize(struct window_pane *, u_int, u_int); +void window_calculate_sizes(struct window *); +int window_pane_set_mode( + struct window_pane *, const struct window_mode *); +void window_pane_reset_mode(struct window_pane *); +void window_pane_parse(struct window_pane *); +void window_pane_key(struct window_pane *, struct client *, int); +void window_pane_mouse(struct window_pane *, + struct client *, u_char, u_char, u_char); +char *window_pane_search(struct window_pane *, const char *); + +/* layout.c */ +const char * layout_name(struct window *); +int layout_lookup(const char *); +void layout_refresh(struct window *, int); +int layout_resize(struct window_pane *, int); +int layout_select(struct window *, u_int); +void layout_next(struct window *); +void layout_previous(struct window *); + +/* layout-manual.c */ +void layout_manual_v_refresh(struct window *, int); +void layout_manual_v_resize(struct window_pane *, int); + +/* window-clock.c */ +extern const struct window_mode window_clock_mode; + +/* window-copy.c */ +extern const struct window_mode window_copy_mode; +void window_copy_pageup(struct window_pane *); + +/* window-scroll.c */ +extern const struct window_mode window_scroll_mode; +void window_scroll_pageup(struct window_pane *); + +/* window-more.c */ +extern const struct window_mode window_more_mode; +void window_more_vadd(struct window_pane *, const char *, va_list); +void printflike2 window_more_add(struct window_pane *, const char *, ...); + +/* window-choose.c */ +extern const struct window_mode window_choose_mode; +void window_choose_vadd( + struct window_pane *, int, const char *, va_list); +void printflike3 window_choose_add( + struct window_pane *, int, const char *, ...); +void window_choose_ready(struct window_pane *, + u_int, void (*)(void *, int), void *); + +/* names.c */ +void set_window_names(void); +char *default_window_name(struct window *); + +/* session.c */ +extern struct sessions sessions; +void session_alert_add(struct session *, struct window *, int); +void session_alert_cancel(struct session *, struct winlink *); +int session_alert_has(struct session *, struct winlink *, int); +int session_alert_has_window(struct session *, struct window *, int); +struct session *session_find(const char *); +struct session *session_create(const char *, const char *, + const char *, u_int, u_int, char **); +void session_destroy(struct session *); +int session_index(struct session *, u_int *); +struct winlink *session_new(struct session *, + const char *, const char *, const char *, int, char **); +struct winlink *session_attach( + struct session *, struct window *, int, char **); +int session_detach(struct session *, struct winlink *); +int session_has(struct session *, struct window *); +int session_next(struct session *, int); +int session_previous(struct session *, int); +int session_select(struct session *, int); +int session_last(struct session *); + +/* utf8.c */ +void utf8_build(void); +int utf8_width(u_char *); + +/* util.c */ +char *section_string(char *, size_t, size_t, size_t); +void clean_string(const char *, char *, size_t); + +/* procname.c */ +char *get_proc_name(int, char *); + +/* buffer.c */ +struct buffer *buffer_create(size_t); +void buffer_destroy(struct buffer *); +void buffer_clear(struct buffer *); +void buffer_ensure(struct buffer *, size_t); +void buffer_add(struct buffer *, size_t); +void buffer_reverse_add(struct buffer *, size_t); +void buffer_remove(struct buffer *, size_t); +void buffer_reverse_remove(struct buffer *, size_t); +void buffer_insert_range(struct buffer *, size_t, size_t); +void buffer_delete_range(struct buffer *, size_t, size_t); +void buffer_write(struct buffer *, const void *, size_t); +void buffer_read(struct buffer *, void *, size_t); +void buffer_write8(struct buffer *, uint8_t); +void buffer_write16(struct buffer *, uint16_t); +uint8_t buffer_read8(struct buffer *); +uint16_t buffer_read16(struct buffer *); + +/* buffer-poll.c */ +void buffer_set( + struct pollfd *, int, struct buffer *, struct buffer *); +int buffer_poll(struct pollfd *, struct buffer *, struct buffer *); +void buffer_flush(int, struct buffer *n, struct buffer *); + +/* log.c */ +#define LOG_FACILITY LOG_DAEMON +void log_open_syslog(int); +void log_open_tty(int); +void log_open_file(int, const char *); +void log_close(void); +void log_vwrite(int, const char *, va_list); +void log_write(int, const char *, ...); +void printflike1 log_warn(const char *, ...); +void printflike1 log_warnx(const char *, ...); +void printflike1 log_info(const char *, ...); +void printflike1 log_debug(const char *, ...); +void printflike1 log_debug2(const char *, ...); +void printflike1 log_debug3(const char *, ...); +__dead void log_vfatal(const char *, va_list); +__dead void log_fatal(const char *, ...); +__dead void log_fatalx(const char *, ...); + +/* xmalloc.c */ +char *xstrdup(const char *); +void *xcalloc(size_t, size_t); +void *xmalloc(size_t); +void *xrealloc(void *, size_t, size_t); +void xfree(void *); +int printflike2 xasprintf(char **, const char *, ...); +int xvasprintf(char **, const char *, va_list); +int printflike3 xsnprintf(char *, size_t, const char *, ...); +int xvsnprintf(char *, size_t, const char *, va_list); +int printflike3 printpath(char *, size_t, const char *, ...); + +#endif /* TMUX_H */ diff --git a/tty-keys.c b/tty-keys.c new file mode 100644 index 00000000..3b8a3b45 --- /dev/null +++ b/tty-keys.c @@ -0,0 +1,412 @@ +/* $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 + +#include + +#include "tmux.h" + +void tty_keys_add(struct tty *, const char *, int, int); +int tty_keys_parse_xterm(struct tty *, char *, size_t, size_t *); +int tty_keys_parse_mouse(struct tty *, char *, size_t, size_t *, u_char *); + +struct tty_key_ent { + enum tty_code_code code; + const char *string; + + int key; + int flags; +}; + +struct tty_key_ent tty_keys[] = { + /* Function keys. */ + { TTYC_KF1, NULL, KEYC_F1, TTYKEY_CTRL }, + { TTYC_KF2, NULL, KEYC_F2, TTYKEY_CTRL }, + { TTYC_KF3, NULL, KEYC_F3, TTYKEY_CTRL }, + { TTYC_KF4, NULL, KEYC_F4, TTYKEY_CTRL }, + { TTYC_KF5, NULL, KEYC_F5, TTYKEY_CTRL }, + { TTYC_KF6, NULL, KEYC_F6, TTYKEY_CTRL }, + { TTYC_KF7, NULL, KEYC_F7, TTYKEY_CTRL }, + { TTYC_KF8, NULL, KEYC_F8, TTYKEY_CTRL }, + { TTYC_KF9, NULL, KEYC_F9, TTYKEY_CTRL }, + { TTYC_KF10, NULL, KEYC_F10, TTYKEY_CTRL }, + { TTYC_KF11, NULL, KEYC_F11, TTYKEY_CTRL }, + { TTYC_KF12, NULL, KEYC_F12, TTYKEY_CTRL }, + { TTYC_KF13, NULL, KEYC_F13, TTYKEY_CTRL }, + { TTYC_KF14, NULL, KEYC_F14, TTYKEY_CTRL }, + { TTYC_KF15, NULL, KEYC_F15, TTYKEY_CTRL }, + { TTYC_KF16, NULL, KEYC_F16, TTYKEY_CTRL }, + { TTYC_KF17, NULL, KEYC_F17, TTYKEY_CTRL }, + { TTYC_KF18, NULL, KEYC_F18, TTYKEY_CTRL }, + { TTYC_KF19, NULL, KEYC_F19, TTYKEY_CTRL }, + { TTYC_KF20, NULL, KEYC_F20, TTYKEY_CTRL }, + { TTYC_KICH1, NULL, KEYC_IC, TTYKEY_CTRL }, + { TTYC_KDCH1, NULL, KEYC_DC, TTYKEY_CTRL }, + { TTYC_KHOME, NULL, KEYC_HOME, TTYKEY_CTRL }, + { TTYC_KEND, NULL, KEYC_END, TTYKEY_CTRL }, + { TTYC_KNP, NULL, KEYC_NPAGE, TTYKEY_CTRL }, + { TTYC_KPP, NULL, KEYC_PPAGE, TTYKEY_CTRL }, + { TTYC_KCBT, NULL, KEYC_BTAB, TTYKEY_CTRL }, + + /* Arrow keys. */ + { 0, "\033OA", KEYC_UP, TTYKEY_RAW }, + { 0, "\033OB", KEYC_DOWN, TTYKEY_RAW }, + { 0, "\033OC", KEYC_RIGHT, TTYKEY_RAW }, + { 0, "\033OD", KEYC_LEFT, TTYKEY_RAW }, + + { 0, "\033[A", KEYC_UP, TTYKEY_RAW }, + { 0, "\033[B", KEYC_DOWN, TTYKEY_RAW }, + { 0, "\033[C", KEYC_RIGHT, TTYKEY_RAW }, + { 0, "\033[D", KEYC_LEFT, TTYKEY_RAW }, + + { 0, "\033Oa", KEYC_ADDCTL(KEYC_UP), TTYKEY_RAW }, + { 0, "\033Ob", KEYC_ADDCTL(KEYC_DOWN), TTYKEY_RAW }, + { 0, "\033Oc", KEYC_ADDCTL(KEYC_RIGHT), TTYKEY_RAW }, + { 0, "\033Od", KEYC_ADDCTL(KEYC_LEFT), TTYKEY_RAW }, + { 0, "\033[a", KEYC_ADDSFT(KEYC_UP), TTYKEY_RAW }, + { 0, "\033[b", KEYC_ADDSFT(KEYC_DOWN), TTYKEY_RAW }, + { 0, "\033[c", KEYC_ADDSFT(KEYC_RIGHT), TTYKEY_RAW }, + { 0, "\033[d", KEYC_ADDSFT(KEYC_LEFT), TTYKEY_RAW }, + + { TTYC_KCUU1, NULL, KEYC_UP, TTYKEY_CTRL }, + { TTYC_KCUD1, NULL, KEYC_DOWN, TTYKEY_CTRL }, + { TTYC_KCUB1, NULL, KEYC_LEFT, TTYKEY_CTRL }, + { TTYC_KCUF1, NULL, KEYC_RIGHT, TTYKEY_CTRL }, + + /* + * Numeric keypad. termcap and terminfo are totally confusing for this. + * There are definitions for some keypad keys and for function keys, + * but these seem to now be used for the real function keys rather than + * for the keypad keys in application mode (which is different from + * what it says in the termcap file). So, we just hardcode the vt100 + * escape sequences here and always put the terminal into keypad_xmit + * mode. Translation of numbers mode/applications mode is done in + * input-keys.c. + */ + { 0, "\033Oo", KEYC_KP0_1, TTYKEY_RAW }, + { 0, "\033Oj", KEYC_KP0_2, TTYKEY_RAW }, + { 0, "\033Om", KEYC_KP0_3, TTYKEY_RAW }, + { 0, "\033Ow", KEYC_KP1_0, TTYKEY_RAW }, + { 0, "\033Ox", KEYC_KP1_1, TTYKEY_RAW }, + { 0, "\033Oy", KEYC_KP1_2, TTYKEY_RAW }, + { 0, "\033Ok", KEYC_KP1_3, TTYKEY_RAW }, + { 0, "\033Ot", KEYC_KP2_0, TTYKEY_RAW }, + { 0, "\033Ou", KEYC_KP2_1, TTYKEY_RAW }, + { 0, "\033Ov", KEYC_KP2_2, TTYKEY_RAW }, + { 0, "\033Oq", KEYC_KP3_0, TTYKEY_RAW }, + { 0, "\033Or", KEYC_KP3_1, TTYKEY_RAW }, + { 0, "\033Os", KEYC_KP3_2, TTYKEY_RAW }, + { 0, "\033OM", KEYC_KP3_3, TTYKEY_RAW }, + { 0, "\033Op", KEYC_KP4_0, TTYKEY_RAW }, + { 0, "\033On", KEYC_KP4_2, TTYKEY_RAW }, +}; + +RB_GENERATE(tty_keys, tty_key, entry, tty_keys_cmp); + +struct tty_key *tty_keys_find(struct tty *, char *, size_t, size_t *); + +int +tty_keys_cmp(struct tty_key *k1, struct tty_key *k2) +{ + return (strcmp(k1->string, k2->string)); +} + +void +tty_keys_add(struct tty *tty, const char *s, int key, int flags) +{ + struct tty_key *tk, *tl; + + tk = xmalloc(sizeof *tk); + tk->string = xstrdup(s); + tk->key = key; + tk->flags = flags; + + if ((tl = RB_INSERT(tty_keys, &tty->ktree, tk)) != NULL) { + xfree(tk->string); + xfree(tk); + log_debug("key exists: %s (old %x, new %x)", s, tl->key, key); + return; + } + + if (strlen(tk->string) > tty->ksize) + tty->ksize = strlen(tk->string); + log_debug("new key %x: size now %zu (%s)", key, tty->ksize, tk->string); +} + +void +tty_keys_init(struct tty *tty) +{ + struct tty_key_ent *tke; + u_int i; + const char *s; + char tmp[64]; + + RB_INIT(&tty->ktree); + + tty->ksize = 0; + for (i = 0; i < nitems(tty_keys); i++) { + tke = &tty_keys[i]; + + if (tke->flags & TTYKEY_RAW) + s = tke->string; + else { + if (!tty_term_has(tty->term, tke->code)) + continue; + s = tty_term_string(tty->term, tke->code); + if (s[0] != '\033' || s[1] == '\0') + continue; + } + + tty_keys_add(tty, s + 1, tke->key, tke->flags); + if (tke->flags & TTYKEY_CTRL) { + if (strlcpy(tmp, s, sizeof tmp) >= sizeof tmp) + continue; + tmp[strlen(tmp) - 1] ^= 0x20; + tty_keys_add(tty, tmp + 1, KEYC_ADDCTL(tke->key), 0); + } + } +} + +void +tty_keys_free(struct tty *tty) +{ + struct tty_key *tk; + + while (!RB_EMPTY(&tty->ktree)) { + tk = RB_ROOT(&tty->ktree); + RB_REMOVE(tty_keys, &tty->ktree, tk); + xfree(tk->string); + xfree(tk); + } +} + +struct tty_key * +tty_keys_find(struct tty *tty, char *buf, size_t len, size_t *size) +{ + struct tty_key *tk, tl; + char *s; + + if (len == 0) + return (NULL); + + s = xmalloc(tty->ksize + 1); + for (*size = tty->ksize; (*size) > 0; (*size)--) { + if ((*size) > len) + continue; + memcpy(s, buf, *size); + s[*size] = '\0'; + + log_debug2("looking for key: %s", s); + + tl.string = s; + tk = RB_FIND(tty_keys, &tty->ktree, &tl); + if (tk != NULL) { + log_debug2("got key: 0x%x", tk->key); + xfree(s); + return (tk); + } + } + xfree(s); + + return (NULL); +} + +int +tty_keys_next(struct tty *tty, int *key, u_char *mouse) +{ + struct tty_key *tk; + struct timeval tv; + char *buf; + size_t len, size; + + buf = BUFFER_OUT(tty->in); + len = BUFFER_USED(tty->in); + if (len == 0) + return (1); + log_debug("keys are %zu (%.*s)", len, (int) len, buf); + + /* If a normal key, return it. */ + if (*buf != '\033') { + *key = buffer_read8(tty->in); + goto found; + } + + /* Look for matching key string and return if found. */ + tk = tty_keys_find(tty, buf + 1, len - 1, &size); + if (tk != NULL) { + buffer_remove(tty->in, size + 1); + *key = tk->key; + goto found; + } + + /* Not found. Is this a mouse key press? */ + *key = tty_keys_parse_mouse(tty, buf, len, &size, mouse); + if (*key != KEYC_NONE) { + buffer_remove(tty->in, size); + goto found; + } + + /* Not found. Try to parse xterm-type arguments. */ + *key = tty_keys_parse_xterm(tty, buf, len, &size); + if (*key != KEYC_NONE) { + buffer_remove(tty->in, size); + goto found; + } + + /* Escape but no key string. If the timer isn't started, start it. */ + if (!(tty->flags & TTY_ESCAPE)) { + tv.tv_sec = 0; + tv.tv_usec = ESCAPE_PERIOD * 1000L; + if (gettimeofday(&tty->key_timer, NULL) != 0) + fatal("gettimeofday"); + timeradd(&tty->key_timer, &tv, &tty->key_timer); + + tty->flags |= TTY_ESCAPE; + return (1); + } + + /* Skip the escape. */ + buf++; + len--; + + /* Is there a normal key following? */ + if (len != 0 && *buf != '\033') { + buffer_remove(tty->in, 1); + *key = KEYC_ADDESC(buffer_read8(tty->in)); + goto found; + } + + /* Or a key string? */ + if (len > 1) { + tk = tty_keys_find(tty, buf + 1, len - 1, &size); + if (tk != NULL) { + buffer_remove(tty->in, size + 2); + *key = KEYC_ADDESC(tk->key); + goto found; + } + } + + /* If the timer hasn't expired, keep waiting. */ + if (gettimeofday(&tv, NULL) != 0) + fatal("gettimeofday"); + if (timercmp(&tty->key_timer, &tv, >)) + return (1); + + /* Give up and return the escape. */ + buffer_remove(tty->in, 1); + *key = '\033'; + +found: + tty->flags &= ~TTY_ESCAPE; + return (0); +} + +int +tty_keys_parse_mouse( + unused struct tty *tty, char *buf, size_t len, size_t *size, u_char *mouse) +{ + /* + * Mouse sequences are \033[M followed by three characters indicating + * buttons, X and Y, all based at 32 with 1,1 top-left. + */ + + log_debug("mouse input is: %.*s", (int) len, buf); + if (len != 6 || memcmp(buf, "\033[M", 3) != 0) + return (KEYC_NONE); + *size = 6; + + if (buf[3] < 32 || buf[4] < 33 || buf[5] < 33) + return (KEYC_NONE); + + mouse[0] = buf[3] - 32; + mouse[1] = buf[4] - 33; + mouse[2] = buf[5] - 33; + return (KEYC_MOUSE); +} + +int +tty_keys_parse_xterm(struct tty *tty, char *buf, size_t len, size_t *size) +{ + struct tty_key *tk; + char tmp[5]; + size_t tmplen; + int key; + + /* + * xterm sequences with modifier keys are of the form: + * + * ^[[1;xD becomes ^[[D + * ^[[5;x~ becomes ^[[5~ + * + * This function is a bit of a hack. Need to figure out what exact + * format and meaning xterm outputs and fix it. XXX + */ + + log_debug("xterm input is: %.*s", (int) len, buf); + if (len != 6 || memcmp(buf, "\033[1;", 4) != 0) + return (KEYC_NONE); + *size = 6; + + tmplen = 0; + tmp[tmplen++] = '['; + if (buf[5] == '~') { + tmp[tmplen++] = buf[2]; + tmp[tmplen++] = '~'; + } else + tmp[tmplen++] = buf[5]; + log_debug("xterm output is: %.*s", (int) tmplen, tmp); + + tk = tty_keys_find(tty, tmp, tmplen, size); + if (tk == NULL) + return (KEYC_NONE); + key = tk->key; + + switch (buf[4]) { + case '8': + key = KEYC_ADDSFT(key); + key = KEYC_ADDESC(key); + key = KEYC_ADDCTL(key); + break; + case '7': + key = KEYC_ADDESC(key); + key = KEYC_ADDCTL(key); + break; + case '6': + key = KEYC_ADDSFT(key); + key = KEYC_ADDCTL(key); + break; + case '5': + key = KEYC_ADDCTL(key); + break; + case '4': + key = KEYC_ADDSFT(key); + key = KEYC_ADDESC(key); + break; + case '3': + key = KEYC_ADDESC(key); + break; + case '2': + key = KEYC_ADDSFT(key); + break; + } + + *size = 6; + return (key); +} diff --git a/tty-term.c b/tty-term.c new file mode 100644 index 00000000..200cc020 --- /dev/null +++ b/tty-term.c @@ -0,0 +1,393 @@ +/* $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 "tmux.h" + +void tty_term_quirks(struct tty_term *); +char *tty_term_strip(const char *); + +struct tty_terms tty_terms = SLIST_HEAD_INITIALIZER(tty_terms); + +struct tty_term_code_entry tty_term_codes[NTTYCODE] = { + { TTYC_AX, TTYCODE_FLAG, "AX" }, + { TTYC_ACSC, TTYCODE_STRING, "acsc" }, + { TTYC_BEL, TTYCODE_STRING, "bel" }, + { TTYC_BLINK, TTYCODE_STRING, "blink" }, + { TTYC_BOLD, TTYCODE_STRING, "bold" }, + { TTYC_CIVIS, TTYCODE_STRING, "civis" }, + { TTYC_CLEAR, TTYCODE_STRING, "clear" }, + { TTYC_CNORM, TTYCODE_STRING, "cnorm" }, + { TTYC_COLORS, TTYCODE_NUMBER, "colors" }, + { TTYC_CSR, TTYCODE_STRING, "csr" }, + { TTYC_CUD, TTYCODE_STRING, "cud" }, + { TTYC_CUD1, TTYCODE_STRING, "cud1" }, + { TTYC_CUP, TTYCODE_STRING, "cup" }, + { TTYC_DCH, TTYCODE_STRING, "dch" }, + { TTYC_DCH1, TTYCODE_STRING, "dch1" }, + { TTYC_DIM, TTYCODE_STRING, "dim" }, + { TTYC_DL, TTYCODE_STRING, "dl" }, + { TTYC_DL1, TTYCODE_STRING, "dl1" }, + { TTYC_EL, TTYCODE_STRING, "el" }, + { TTYC_EL1, TTYCODE_STRING, "el1" }, + { TTYC_ENACS, TTYCODE_STRING, "enacs" }, + { TTYC_ICH, TTYCODE_STRING, "ich" }, + { TTYC_ICH1, TTYCODE_STRING, "ich1" }, + { TTYC_IL, TTYCODE_STRING, "il" }, + { TTYC_IL1, TTYCODE_STRING, "il1" }, + { TTYC_INVIS, TTYCODE_STRING, "invis" }, + { TTYC_IS1, TTYCODE_STRING, "is1" }, + { TTYC_IS2, TTYCODE_STRING, "is2" }, + { TTYC_IS3, TTYCODE_STRING, "is3" }, + { TTYC_KCBT, TTYCODE_STRING, "kcbt" }, + { TTYC_KCUB1, TTYCODE_STRING, "kcub1" }, + { TTYC_KCUD1, TTYCODE_STRING, "kcud1" }, + { TTYC_KCUF1, TTYCODE_STRING, "kcuf1" }, + { TTYC_KCUU1, TTYCODE_STRING, "kcuu1" }, + { TTYC_KDCH1, TTYCODE_STRING, "kdch1" }, + { TTYC_KEND, TTYCODE_STRING, "kend" }, + { TTYC_KF1, TTYCODE_STRING, "kf1" }, + { TTYC_KF10, TTYCODE_STRING, "kf10" }, + { TTYC_KF11, TTYCODE_STRING, "kf11" }, + { TTYC_KF12, TTYCODE_STRING, "kf12" }, + { TTYC_KF13, TTYCODE_STRING, "kf13" }, + { TTYC_KF14, TTYCODE_STRING, "kf14" }, + { TTYC_KF15, TTYCODE_STRING, "kf15" }, + { TTYC_KF16, TTYCODE_STRING, "kf16" }, + { TTYC_KF17, TTYCODE_STRING, "kf17" }, + { TTYC_KF18, TTYCODE_STRING, "kf18" }, + { TTYC_KF19, TTYCODE_STRING, "kf19" }, + { TTYC_KF20, TTYCODE_STRING, "kf20" }, + { TTYC_KF2, TTYCODE_STRING, "kf2" }, + { TTYC_KF3, TTYCODE_STRING, "kf3" }, + { TTYC_KF4, TTYCODE_STRING, "kf4" }, + { TTYC_KF5, TTYCODE_STRING, "kf5" }, + { TTYC_KF6, TTYCODE_STRING, "kf6" }, + { TTYC_KF7, TTYCODE_STRING, "kf7" }, + { TTYC_KF8, TTYCODE_STRING, "kf8" }, + { TTYC_KF9, TTYCODE_STRING, "kf9" }, + { TTYC_KHOME, TTYCODE_STRING, "khome" }, + { TTYC_KICH1, TTYCODE_STRING, "kich1" }, + { TTYC_KMOUS, TTYCODE_STRING, "kmous" }, + { TTYC_KNP, TTYCODE_STRING, "knp" }, + { TTYC_KPP, TTYCODE_STRING, "kpp" }, + { TTYC_OP, TTYCODE_STRING, "op" }, + { TTYC_REV, TTYCODE_STRING, "rev" }, + { TTYC_RI, TTYCODE_STRING, "ri" }, + { TTYC_RMACS, TTYCODE_STRING, "rmacs" }, + { TTYC_RMCUP, TTYCODE_STRING, "rmcup" }, + { TTYC_RMIR, TTYCODE_STRING, "rmir" }, + { TTYC_RMKX, TTYCODE_STRING, "rmkx" }, + { TTYC_SETAB, TTYCODE_STRING, "setab" }, + { TTYC_SETAF, TTYCODE_STRING, "setaf" }, + { TTYC_SGR0, TTYCODE_STRING, "sgr0" }, + { TTYC_SMACS, TTYCODE_STRING, "smacs" }, + { TTYC_SMCUP, TTYCODE_STRING, "smcup" }, + { TTYC_SMIR, TTYCODE_STRING, "smir" }, + { TTYC_SMKX, TTYCODE_STRING, "smkx" }, + { TTYC_SMSO, TTYCODE_STRING, "smso" }, + { TTYC_SMUL, TTYCODE_STRING, "smul" }, + { TTYC_XENL, TTYCODE_FLAG, "xenl" }, +}; + +char * +tty_term_strip(const char *s) +{ + const char *ptr; + static char buf[BUFSIZ]; + size_t len; + + /* Ignore strings with no padding. */ + if (strchr(s, '$') == NULL) + return (xstrdup(s)); + + len = 0; + for (ptr = s; *ptr != '\0'; ptr++) { + if (*ptr == '$' && *(ptr + 1) == '<') { + while (*ptr != '\0' && *ptr != '>') + ptr++; + if (*ptr == '>') + ptr++; + } + + buf[len++] = *ptr; + if (len == (sizeof buf) - 1) + break; + } + buf[len] = '\0'; + + return (xstrdup(buf)); +} + +void +tty_term_quirks(struct tty_term *term) +{ + if (strncmp(term->name, "rxvt", 4) == 0) { + /* rxvt supports dch1 but some termcap files do not have it. */ + if (!tty_term_has(term, TTYC_DCH1)) { + term->codes[TTYC_DCH1].type = TTYCODE_STRING; + term->codes[TTYC_DCH1].value.string = xstrdup("\033[P"); + } + } + + if (strncmp(term->name, "xterm", 5) == 0) { + /* xterm supports ich1 but some termcaps omit it. */ + if (!tty_term_has(term, TTYC_ICH1)) { + term->codes[TTYC_ICH1].type = TTYCODE_STRING; + term->codes[TTYC_ICH1].value.string = xstrdup("\033[@"); + } + } +} + +struct tty_term * +tty_term_find(char *name, int fd, char **cause) +{ + struct tty_term *term; + struct tty_term_code_entry *ent; + struct tty_code *code; + u_int i; + int n, error; + char *s; + + SLIST_FOREACH(term, &tty_terms, entry) { + if (strcmp(term->name, name) == 0) { + term->references++; + return (term); + } + } + + log_debug("new term: %s", name); + term = xmalloc(sizeof *term); + term->name = xstrdup(name); + term->references = 1; + term->flags = 0; + SLIST_INSERT_HEAD(&tty_terms, term, entry); + + /* Set up ncurses terminal. */ + if (setupterm(name, fd, &error) != OK) { + switch (error) { + case 0: + xasprintf(cause, "can't use hardcopy terminal"); + break; + case 1: + xasprintf(cause, "missing or unsuitable terminal"); + break; + case 2: + xasprintf(cause, "can't find terminfo database"); + break; + default: + xasprintf(cause, "unknown error"); + break; + } + goto error; + } + + /* Fill in codes. */ + memset(&term->codes, 0, sizeof term->codes); + for (i = 0; i < NTTYCODE; i++) { + ent = &tty_term_codes[i]; + + code = &term->codes[ent->code]; + code->type = TTYCODE_NONE; + switch (ent->type) { + case TTYCODE_NONE: + break; + case TTYCODE_STRING: + s = tigetstr((char *) ent->name); + if (s == NULL || s == (char *) -1) + break; + code->type = TTYCODE_STRING; + code->value.string = tty_term_strip(s); + break; + case TTYCODE_NUMBER: + n = tigetnum((char *) ent->name); + if (n == -1 || n == -2) + break; + code->type = TTYCODE_NUMBER; + code->value.number = n; + break; + case TTYCODE_FLAG: + n = tigetflag((char *) ent->name); + if (n == -1) + break; + code->type = TTYCODE_FLAG; + code->value.number = n; + break; + } + } + tty_term_quirks(term); + + /* Delete ncurses data. */ + del_curterm(cur_term); + + /* These are always required. */ + if (!tty_term_has(term, TTYC_CLEAR)) { + xasprintf(cause, "terminal does not support clear"); + goto error; + } + if (!tty_term_has(term, TTYC_RI)) { + xasprintf(cause, "terminal does not support ri"); + goto error; + } + if (!tty_term_has(term, TTYC_CUP)) { + xasprintf(cause, "terminal does not support cup"); + goto error; + } + + /* These can be emulated so one of the two is required. */ + if (!tty_term_has(term, TTYC_CUD1) && !tty_term_has(term, TTYC_CUD)) { + xasprintf(cause, "terminal does not support cud1 or cud"); + goto error; + } + if (!tty_term_has(term, TTYC_IL1) && !tty_term_has(term, TTYC_IL)) { + xasprintf(cause, "terminal does not support il1 or il"); + goto error; + } + if (!tty_term_has(term, TTYC_DL1) && !tty_term_has(term, TTYC_DL)) { + xasprintf(cause, "terminal does not support dl1 or dl"); + goto error; + } + if (!tty_term_has(term, TTYC_ICH1) && + !tty_term_has(term, TTYC_ICH) && (!tty_term_has(term, TTYC_SMIR) || + !tty_term_has(term, TTYC_RMIR))) { + xasprintf(cause, + "terminal does not support ich1 or ich or smir and rmir"); + goto error; + } + if (!tty_term_has(term, TTYC_DCH1) && !tty_term_has(term, TTYC_DCH)) { + xasprintf(cause, "terminal does not support dch1 or dch"); + goto error; + } + + /* + * Figure out if terminal support default colours. AX is a screen + * extension which indicates this. Also check if op (orig_pair) uses + * the default colours - if it does, this is a good indication the + * terminal supports them. + */ + if (tty_term_flag(term, TTYC_AX)) + term->flags |= TERM_HASDEFAULTS; + if (strcmp(tty_term_string(term, TTYC_OP), "\033[39;49m") == 0) + term->flags |= TERM_HASDEFAULTS; + + /* + * Try to figure out if we have 256 or 88 colours. The standard xterm + * definitions are broken (well, or the way they are parsed is: in any + * case they end up returning 8). So also do a hack. + */ + if (tty_term_number(term, TTYC_COLORS) == 256) + term->flags |= TERM_256COLOURS; + if (strstr(name, "256col") != NULL) /* XXX HACK */ + term->flags |= TERM_256COLOURS; + if (tty_term_number(term, TTYC_COLORS) == 88) + term->flags |= TERM_88COLOURS; + if (strstr(name, "88col") != NULL) /* XXX HACK */ + term->flags |= TERM_88COLOURS; + + /* + * Terminals without xenl (eat newline glitch) wrap at at $COLUMNS - 1 + * rather than $COLUMNS (the cursor can never be beyond $COLUMNS - 1). + * + * This is irritating, most notably because it is impossible to write + * to the very bottom-right of the screen without scrolling. + * + * Flag the terminal here and apply some workarounds in other places to + * do the best possible. + */ + if (!tty_term_flag(term, TTYC_XENL)) + term->flags |= TERM_EARLYWRAP; + + return (term); + +error: + tty_term_free(term); + return (NULL); +} + +void +tty_term_free(struct tty_term *term) +{ + u_int i; + + if (--term->references != 0) + return; + + SLIST_REMOVE(&tty_terms, term, tty_term, entry); + + for (i = 0; i < NTTYCODE; i++) { + if (term->codes[i].type == TTYCODE_STRING) + xfree(term->codes[i].value.string); + } + xfree(term->name); + xfree(term); +} + +int +tty_term_has(struct tty_term *term, enum tty_code_code code) +{ + return (term->codes[code].type != TTYCODE_NONE); +} + +const char * +tty_term_string(struct tty_term *term, enum tty_code_code code) +{ + if (!tty_term_has(term, code)) + return (""); + if (term->codes[code].type != TTYCODE_STRING) + log_fatalx("not a string: %d", code); + return (term->codes[code].value.string); +} + +/* No vtparm. Fucking ncurses. */ +const char * +tty_term_string1(struct tty_term *term, enum tty_code_code code, int a) +{ + return (tparm((char *) tty_term_string(term, code), a)); +} + +const char * +tty_term_string2(struct tty_term *term, enum tty_code_code code, int a, int b) +{ + return (tparm((char *) tty_term_string(term, code), a, b)); +} + +int +tty_term_number(struct tty_term *term, enum tty_code_code code) +{ + if (!tty_term_has(term, code)) + return (0); + if (term->codes[code].type != TTYCODE_NUMBER) + log_fatalx("not a number: %d", code); + return (term->codes[code].value.number); +} + +int +tty_term_flag(struct tty_term *term, enum tty_code_code code) +{ + if (!tty_term_has(term, code)) + return (0); + if (term->codes[code].type != TTYCODE_FLAG) + log_fatalx("not a flag: %d", code); + return (term->codes[code].value.flag); +} + diff --git a/tty-write.c b/tty-write.c new file mode 100644 index 00000000..46cb8e8c --- /dev/null +++ b/tty-write.c @@ -0,0 +1,91 @@ +/* $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" + +void tty_vwrite_cmd(struct window_pane *, enum tty_cmd, va_list); + +void +tty_write_cmd(struct window_pane *wp, enum tty_cmd cmd, ...) +{ + va_list ap; + + va_start(ap, cmd); + tty_vwrite_cmd(wp, cmd, ap); + va_end(ap); +} + +void +tty_vwrite_cmd(struct window_pane *wp, enum tty_cmd cmd, va_list ap) +{ + struct client *c; + va_list aq; + u_int i; + + if (wp == NULL) + return; + + if (wp->window->flags & WINDOW_REDRAW || wp->flags & PANE_REDRAW) + return; + if (wp->window->flags & WINDOW_HIDDEN || wp->flags & PANE_HIDDEN) + return; + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c == NULL || c->session == NULL) + continue; + if (c->flags & CLIENT_SUSPENDED) + continue; + + if (c->session->curw->window == wp->window) { + tty_update_mode(&c->tty, c->tty.mode & ~MODE_CURSOR); + + va_copy(aq, ap); + tty_vwrite(&c->tty, wp, cmd, aq); + va_end(aq); + } + } +} + +void +tty_write_mode(struct window_pane *wp, int mode) +{ + struct client *c; + u_int i; + + if (wp == NULL) + return; + + if (wp->window->flags & WINDOW_REDRAW || wp->flags & PANE_REDRAW) + return; + if (wp->window->flags & WINDOW_HIDDEN || wp->flags & PANE_HIDDEN) + return; + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c == NULL || c->session == NULL) + continue; + if (c->flags & CLIENT_SUSPENDED) + continue; + + tty_update_mode(&c->tty, mode); + } +} + diff --git a/tty.c b/tty.c new file mode 100644 index 00000000..4d81910d --- /dev/null +++ b/tty.c @@ -0,0 +1,1076 @@ +/* $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 + +#include +#include +#include +#include +#include + +#include "tmux.h" + +void tty_fill_acs(struct tty *); + +void tty_raw(struct tty *, const char *); + +int tty_try_256(struct tty *, u_char, const char *); +int tty_try_88(struct tty *, u_char, const char *); + +void tty_attributes(struct tty *, const struct grid_cell *); +void tty_attributes_fg(struct tty *, const struct grid_cell *); +void tty_attributes_bg(struct tty *, const struct grid_cell *); + +void tty_cmd_cell(struct tty *, struct window_pane *, va_list); +void tty_cmd_clearendofline(struct tty *, struct window_pane *, va_list); +void tty_cmd_clearendofscreen(struct tty *, struct window_pane *, va_list); +void tty_cmd_clearline(struct tty *, struct window_pane *, va_list); +void tty_cmd_clearscreen(struct tty *, struct window_pane *, va_list); +void tty_cmd_clearstartofline(struct tty *, struct window_pane *, va_list); +void tty_cmd_clearstartofscreen(struct tty *, struct window_pane *, va_list); +void tty_cmd_deletecharacter(struct tty *, struct window_pane *, va_list); +void tty_cmd_deleteline(struct tty *, struct window_pane *, va_list); +void tty_cmd_insertcharacter(struct tty *, struct window_pane *, va_list); +void tty_cmd_insertline(struct tty *, struct window_pane *, va_list); +void tty_cmd_linefeed(struct tty *, struct window_pane *, va_list); +void tty_cmd_raw(struct tty *, struct window_pane *, va_list); +void tty_cmd_reverseindex(struct tty *, struct window_pane *, va_list); + +void (*tty_cmds[])(struct tty *, struct window_pane *, va_list) = { + tty_cmd_cell, + tty_cmd_clearendofline, + tty_cmd_clearendofscreen, + tty_cmd_clearline, + tty_cmd_clearscreen, + tty_cmd_clearstartofline, + tty_cmd_clearstartofscreen, + tty_cmd_deletecharacter, + tty_cmd_deleteline, + tty_cmd_insertcharacter, + tty_cmd_insertline, + tty_cmd_linefeed, + tty_cmd_raw, + tty_cmd_reverseindex, +}; + +void +tty_init(struct tty *tty, char *path, char *term) +{ + tty->path = xstrdup(path); + if (term == NULL) + tty->termname = xstrdup("unknown"); + else + tty->termname = xstrdup(term); + tty->flags = 0; + tty->term_flags = 0; +} + +int +tty_open(struct tty *tty, char **cause) +{ + int mode; + + tty->fd = open(tty->path, O_RDWR|O_NONBLOCK); + if (tty->fd == -1) { + xasprintf(cause, "%s: %s", tty->path, strerror(errno)); + return (-1); + } + + if ((mode = fcntl(tty->fd, F_GETFL)) == -1) + fatal("fcntl failed"); + if (fcntl(tty->fd, F_SETFL, mode|O_NONBLOCK) == -1) + fatal("fcntl failedo"); + if (fcntl(tty->fd, F_SETFD, FD_CLOEXEC) == -1) + fatal("fcntl failed"); + + if (debug_level > 3) + tty->log_fd = open("tmux.out", O_WRONLY|O_CREAT|O_TRUNC, 0644); + else + tty->log_fd = -1; + + if ((tty->term = tty_term_find(tty->termname, tty->fd, cause)) == NULL) + goto error; + + tty->in = buffer_create(BUFSIZ); + tty->out = buffer_create(BUFSIZ); + + tty->flags &= TTY_UTF8; + + tty_start_tty(tty); + + tty_keys_init(tty); + + tty_fill_acs(tty); + + return (0); + +error: + close(tty->fd); + tty->fd = -1; + + return (-1); +} + +void +tty_start_tty(struct tty *tty) +{ + struct termios tio; + int what; + + tty_detect_utf8(tty); + + if (tcgetattr(tty->fd, &tty->tio) != 0) + fatal("tcgetattr failed"); + memcpy(&tio, &tty->tio, sizeof tio); + tio.c_iflag &= ~(IXON|IXOFF|ICRNL|INLCR|IGNCR|IMAXBEL|ISTRIP); + tio.c_iflag |= IGNBRK; + tio.c_oflag &= ~(OPOST|ONLCR|OCRNL|ONLRET); + tio.c_lflag &= ~(IEXTEN|ICANON|ECHO|ECHOE|ECHONL|ECHOCTL| + ECHOPRT|ECHOKE|ECHOCTL|ISIG); + tio.c_cc[VMIN] = 1; + tio.c_cc[VTIME] = 0; + if (tcsetattr(tty->fd, TCSANOW, &tio) != 0) + fatal("tcsetattr failed"); + + what = 0; + if (ioctl(tty->fd, TIOCFLUSH, &what) != 0) + fatal("ioctl(TIOCFLUSH)"); + + tty_putcode(tty, TTYC_IS1); + tty_putcode(tty, TTYC_IS2); + tty_putcode(tty, TTYC_IS3); + + tty_putcode(tty, TTYC_SMCUP); + tty_putcode(tty, TTYC_SMKX); + tty_putcode(tty, TTYC_ENACS); + tty_putcode(tty, TTYC_CLEAR); + + tty_putcode(tty, TTYC_CNORM); + if (tty_term_has(tty->term, TTYC_KMOUS)) + tty_puts(tty, "\033[?1000l"); + + memcpy(&tty->cell, &grid_default_cell, sizeof tty->cell); + + tty->cx = UINT_MAX; + tty->cy = UINT_MAX; + + tty->rlower = UINT_MAX; + tty->rupper = UINT_MAX; + + tty->mode = MODE_CURSOR; +} + +void +tty_stop_tty(struct tty *tty) +{ + struct winsize ws; + + /* + * Be flexible about error handling and try not kill the server just + * because the fd is invalid. Things like ssh -t can easily leave us + * with a dead tty. + */ + if (ioctl(tty->fd, TIOCGWINSZ, &ws) == -1) + return; + if (tcsetattr(tty->fd, TCSANOW, &tty->tio) == -1) + return; + + tty_raw(tty, tty_term_string2(tty->term, TTYC_CSR, 0, ws.ws_row - 1)); + tty_raw(tty, tty_term_string(tty->term, TTYC_RMACS)); + tty_raw(tty, tty_term_string(tty->term, TTYC_SGR0)); + tty_raw(tty, tty_term_string(tty->term, TTYC_RMKX)); + tty_raw(tty, tty_term_string(tty->term, TTYC_RMCUP)); + tty_raw(tty, tty_term_string(tty->term, TTYC_CLEAR)); + + tty_raw(tty, tty_term_string(tty->term, TTYC_CNORM)); + if (tty_term_has(tty->term, TTYC_KMOUS)) + tty_raw(tty, "\033[?1000l"); +} + +void +tty_detect_utf8(struct tty *tty) +{ + struct pollfd pfd; + char buf[7]; + size_t len; + ssize_t n; + int nfds; + struct termios tio, old_tio; + int what; + + if (tty->flags & TTY_UTF8) + return; + + /* + * If the terminal looks reasonably likely to support this, try to + * write a three-byte UTF-8 wide character to the terminal, then read + * the cursor position. + * + * XXX This entire function is a hack. + */ + + /* Check if the terminal looks sort of vt100. */ + if (strstr(tty_term_string(tty->term, TTYC_CLEAR), "[2J") == NULL || + strstr(tty_term_string(tty->term, TTYC_CUP), "H") == NULL) + return; + + if (tcgetattr(tty->fd, &old_tio) != 0) + fatal("tcgetattr failed"); + cfmakeraw(&tio); + if (tcsetattr(tty->fd, TCSANOW, &tio) != 0) + fatal("tcsetattr failed"); + + what = 0; + if (ioctl(tty->fd, TIOCFLUSH, &what) != 0) + fatal("ioctl(TIOCFLUSH)"); + +#define UTF8_TEST_DATA "\033[H\357\277\246\033[6n" + if (write(tty->fd, UTF8_TEST_DATA, (sizeof UTF8_TEST_DATA) - 1) == -1) + fatal("write failed"); +#undef UTF8_TEST_DATA + + len = 0; + for (;;) { + pfd.fd = tty->fd; + pfd.events = POLLIN; + + nfds = poll(&pfd, 1, 500); + if (nfds == -1) { + if (errno == EAGAIN || errno == EINTR) + continue; + fatal("poll failed"); + } + if (nfds == 0) + break; + if (pfd.revents & (POLLERR|POLLNVAL|POLLHUP)) + break; + if (!(pfd.revents & POLLIN)) + continue; + + if ((n = read(tty->fd, buf + len, 1)) != 1) + break; + buf[++len] = '\0'; + + if (len == (sizeof buf) - 1) { + if (strcmp(buf, "\033[1;3R") == 0) + tty->flags |= TTY_UTF8; + break; + } + } + + if (tcsetattr(tty->fd, TCSANOW, &old_tio) != 0) + fatal("tcsetattr failed"); +} + +void +tty_fill_acs(struct tty *tty) +{ + const char *ptr; + + memset(tty->acs, 0, sizeof tty->acs); + if (!tty_term_has(tty->term, TTYC_ACSC)) + return; + + ptr = tty_term_string(tty->term, TTYC_ACSC); + if (strlen(ptr) % 2 != 0) + return; + for (; *ptr != '\0'; ptr += 2) + tty->acs[(u_char) ptr[0]] = ptr[1]; +} + +u_char +tty_get_acs(struct tty *tty, u_char ch) +{ + if (tty->acs[ch] != '\0') + return (tty->acs[ch]); + return (ch); +} + +void +tty_close(struct tty *tty, int no_stop) +{ + if (tty->fd == -1) + return; + + if (tty->log_fd != -1) { + close(tty->log_fd); + tty->log_fd = -1; + } + + if (!no_stop) + tty_stop_tty(tty); + + tty_term_free(tty->term); + tty_keys_free(tty); + + close(tty->fd); + tty->fd = -1; + + buffer_destroy(tty->in); + buffer_destroy(tty->out); +} + +void +tty_free(struct tty *tty, int no_stop) +{ + tty_close(tty, no_stop); + + if (tty->path != NULL) + xfree(tty->path); + if (tty->termname != NULL) + xfree(tty->termname); +} + +void +tty_raw(struct tty *tty, const char *s) +{ + write(tty->fd, s, strlen(s)); +} + +void +tty_putcode(struct tty *tty, enum tty_code_code code) +{ + tty_puts(tty, tty_term_string(tty->term, code)); +} + +void +tty_putcode1(struct tty *tty, enum tty_code_code code, int a) +{ + if (a < 0) + return; + tty_puts(tty, tty_term_string1(tty->term, code, a)); +} + +void +tty_putcode2(struct tty *tty, enum tty_code_code code, int a, int b) +{ + if (a < 0 || b < 0) + return; + tty_puts(tty, tty_term_string2(tty->term, code, a, b)); +} + +void +tty_puts(struct tty *tty, const char *s) +{ + if (*s == '\0') + return; + buffer_write(tty->out, s, strlen(s)); + + if (tty->log_fd != -1) + write(tty->log_fd, s, strlen(s)); +} + +void +tty_putc(struct tty *tty, u_char ch) +{ + u_int sx; + + if (tty->cell.attr & GRID_ATTR_CHARSET) + ch = tty_get_acs(tty, ch); + buffer_write8(tty->out, ch); + + if (ch >= 0x20 && ch != 0x7f) { + sx = tty->sx; + if (tty->term->flags & TERM_EARLYWRAP) + sx--; + + if (tty->cx == sx) { + tty->cx = 0; + tty->cy++; + } else + tty->cx++; + } + + if (tty->log_fd != -1) + write(tty->log_fd, &ch, 1); +} + +void +tty_set_title(struct tty *tty, const char *title) +{ + if (strstr(tty->termname, "xterm") == NULL && + strstr(tty->termname, "rxvt") == NULL && + strcmp(tty->termname, "screen") != 0) + return; + + tty_puts(tty, "\033]0;"); + tty_puts(tty, title); + tty_putc(tty, '\007'); +} + +void +tty_update_mode(struct tty *tty, int mode) +{ + int changed; + + if (tty->flags & TTY_NOCURSOR) + mode &= ~MODE_CURSOR; + + changed = mode ^ tty->mode; + if (changed & MODE_CURSOR) { + if (mode & MODE_CURSOR) + tty_putcode(tty, TTYC_CNORM); + else + tty_putcode(tty, TTYC_CIVIS); + } + if (changed & MODE_MOUSE) { + if (mode & MODE_MOUSE) + tty_puts(tty, "\033[?1000h"); + else + tty_puts(tty, "\033[?1000l"); + } + tty->mode = mode; +} + +void +tty_emulate_repeat( + struct tty *tty, enum tty_code_code code, enum tty_code_code code1, u_int n) +{ + if (tty_term_has(tty->term, code)) + tty_putcode1(tty, code, n); + else { + while (n-- > 0) + tty_putcode(tty, code1); + } +} + +/* + * Redraw scroll region using data from screen (already updated). Used when + * CSR not supported, or window is a pane that doesn't take up the full + * width of the terminal. + */ +void +tty_redraw_region(struct tty *tty, struct window_pane *wp) +{ + struct screen *s = wp->screen; + u_int i; + + /* + * If region is >= 50% of the screen, just schedule a window redraw. In + * most cases, this is likely to be followed by some more scrolling - + * without this, the entire pane ends up being redrawn many times which + * can be much more data. + */ + if (s->old_rupper - s->old_rlower >= screen_size_y(s) / 2) { + wp->flags |= PANE_REDRAW; + return; + } + + if (s->old_cy < s->old_rupper || s->old_cy > s->old_rlower) { + for (i = s->old_cy; i < screen_size_y(s); i++) + tty_draw_line(tty, s, i, wp->xoff, wp->yoff); + } else { + for (i = s->old_rupper; i <= s->old_rlower; i++) + tty_draw_line(tty, s, i, wp->xoff, wp->yoff); + } +} + +void +tty_draw_line(struct tty *tty, struct screen *s, u_int py, u_int ox, u_int oy) +{ + const struct grid_cell *gc; + const struct grid_utf8 *gu; + u_int i, sx; + + sx = screen_size_x(s); + if (sx > s->grid->size[s->grid->hsize + py]) + sx = s->grid->size[s->grid->hsize + py]; + if (sx > tty->sx) + sx = tty->sx; + + tty_cursor(tty, 0, py, ox, oy); + for (i = 0; i < sx; i++) { + gc = grid_view_peek_cell(s->grid, i, py); + + gu = NULL; + if (gc->flags & GRID_FLAG_UTF8) + gu = grid_view_peek_utf8(s->grid, i, py); + + if (screen_check_selection(s, i, py)) { + s->sel.cell.data = gc->data; + tty_cell(tty, &s->sel.cell, gu); + } else + tty_cell(tty, gc, gu); + } + + if (sx >= tty->sx) + return; + tty_reset(tty); + + tty_cursor(tty, sx, py, ox, oy); + if (screen_size_x(s) >= tty->sx && tty_term_has(tty->term, TTYC_EL)) + tty_putcode(tty, TTYC_EL); + else { + for (i = sx; i < screen_size_x(s); i++) + tty_putc(tty, ' '); + } +} + +void +tty_write(struct tty *tty, struct window_pane *wp, enum tty_cmd cmd, ...) +{ + va_list ap; + + va_start(ap, cmd); + tty_vwrite(tty, wp, cmd, ap); + va_end(ap); +} + +void +tty_vwrite( + struct tty *tty, struct window_pane *wp, enum tty_cmd cmd, va_list ap) +{ + if (tty->flags & TTY_FREEZE || tty->term == NULL) + return; + if (tty_cmds[cmd] != NULL) + tty_cmds[cmd](tty, wp, ap); +} + +void +tty_cmd_insertcharacter(struct tty *tty, struct window_pane *wp, va_list ap) +{ + struct screen *s = wp->screen; + u_int ua; + + if (wp->xoff != 0 || screen_size_x(s) < tty->sx) { + tty_draw_line(tty, wp->screen, s->old_cy, wp->xoff, wp->yoff); + return; + } + + ua = va_arg(ap, u_int); + + tty_reset(tty); + + tty_cursor(tty, s->old_cx, s->old_cy, wp->xoff, wp->yoff); + if (tty_term_has(tty->term, TTYC_ICH) || + tty_term_has(tty->term, TTYC_ICH1)) + tty_emulate_repeat(tty, TTYC_ICH, TTYC_ICH1, ua); + else { + tty_putcode(tty, TTYC_SMIR); + while (ua-- > 0) + tty_putc(tty, ' '); + tty_putcode(tty, TTYC_RMIR); + } +} + +void +tty_cmd_deletecharacter(struct tty *tty, struct window_pane *wp, va_list ap) +{ + struct screen *s = wp->screen; + u_int ua; + + if (wp->xoff != 0 || screen_size_x(s) < tty->sx) { + tty_draw_line(tty, wp->screen, s->old_cy, wp->xoff, wp->yoff); + return; + } + + ua = va_arg(ap, u_int); + + tty_reset(tty); + + tty_cursor(tty, s->old_cx, s->old_cy, wp->xoff, wp->yoff); + tty_emulate_repeat(tty, TTYC_DCH, TTYC_DCH1, ua); +} + +void +tty_cmd_insertline(struct tty *tty, struct window_pane *wp, va_list ap) +{ + struct screen *s = wp->screen; + u_int ua; + + if (wp->xoff != 0 || screen_size_x(s) < tty->sx || + !tty_term_has(tty->term, TTYC_CSR)) { + tty_redraw_region(tty, wp); + return; + } + + ua = va_arg(ap, u_int); + + tty_reset(tty); + + tty_region(tty, s->old_rupper, s->old_rlower, wp->yoff); + + tty_cursor(tty, s->old_cx, s->old_cy, wp->xoff, wp->yoff); + tty_emulate_repeat(tty, TTYC_IL, TTYC_IL1, ua); +} + +void +tty_cmd_deleteline(struct tty *tty, struct window_pane *wp, va_list ap) +{ + struct screen *s = wp->screen; + u_int ua; + + if (wp->xoff != 0 || screen_size_x(s) < tty->sx || + !tty_term_has(tty->term, TTYC_CSR)) { + tty_redraw_region(tty, wp); + return; + } + + ua = va_arg(ap, u_int); + + tty_reset(tty); + + tty_region(tty, s->old_rupper, s->old_rlower, wp->yoff); + + tty_cursor(tty, s->old_cx, s->old_cy, wp->xoff, wp->yoff); + tty_emulate_repeat(tty, TTYC_DL, TTYC_DL1, ua); +} + +void +tty_cmd_clearline(struct tty *tty, struct window_pane *wp, unused va_list ap) +{ + struct screen *s = wp->screen; + u_int i; + + tty_reset(tty); + + tty_cursor(tty, 0, s->old_cy, wp->xoff, wp->yoff); + if (wp->xoff == 0 && screen_size_x(s) >= tty->sx && + tty_term_has(tty->term, TTYC_EL)) { + tty_putcode(tty, TTYC_EL); + } else { + for (i = 0; i < screen_size_x(s); i++) + tty_putc(tty, ' '); + } +} + +void +tty_cmd_clearendofline( + struct tty *tty, struct window_pane *wp, unused va_list ap) +{ + struct screen *s = wp->screen; + u_int i; + + tty_reset(tty); + + tty_cursor(tty, s->old_cx, s->old_cy, wp->xoff, wp->yoff); + if (wp->xoff == 0 && screen_size_x(s) >= tty->sx && + tty_term_has(tty->term, TTYC_EL)) + tty_putcode(tty, TTYC_EL); + else { + for (i = s->old_cx; i < screen_size_x(s); i++) + tty_putc(tty, ' '); + } +} + +void +tty_cmd_clearstartofline( + struct tty *tty, struct window_pane *wp, unused va_list ap) +{ + struct screen *s = wp->screen; + u_int i; + + tty_reset(tty); + + if (wp->xoff == 0 && tty_term_has(tty->term, TTYC_EL1)) { + tty_cursor(tty, s->old_cx, s->old_cy, wp->xoff, wp->yoff); + tty_putcode(tty, TTYC_EL1); + } else { + tty_cursor(tty, 0, s->old_cy, wp->xoff, wp->yoff); + for (i = 0; i < s->old_cx + 1; i++) + tty_putc(tty, ' '); + } +} + +void +tty_cmd_reverseindex(struct tty *tty, struct window_pane *wp, unused va_list ap) +{ + struct screen *s = wp->screen; + + if (wp->xoff != 0 || screen_size_x(s) < tty->sx || + !tty_term_has(tty->term, TTYC_CSR)) { + tty_redraw_region(tty, wp); + return; + } + + tty_reset(tty); + + tty_region(tty, s->old_rupper, s->old_rlower, wp->yoff); + + if (s->old_cy == s->old_rupper) { + tty_cursor(tty, s->old_cx, s->old_rupper, wp->xoff, wp->yoff); + tty_putcode(tty, TTYC_RI); + } +} + +void +tty_cmd_linefeed(struct tty *tty, struct window_pane *wp, unused va_list ap) +{ + struct screen *s = wp->screen; + + if (wp->xoff != 0 || screen_size_x(s) < tty->sx || + !tty_term_has(tty->term, TTYC_CSR)) { + tty_redraw_region(tty, wp); + return; + } + + tty_reset(tty); + + tty_region(tty, s->old_rupper, s->old_rlower, wp->yoff); + + if (s->old_cy == s->old_rlower) { + tty_cursor(tty, s->old_cx, s->old_cy, wp->xoff, wp->yoff); + tty_putc(tty, '\n'); + } +} + +void +tty_cmd_clearendofscreen( + struct tty *tty, struct window_pane *wp, unused va_list ap) +{ + struct screen *s = wp->screen; + u_int i, j, oy; + + oy = wp->yoff; + + tty_reset(tty); + + tty_region(tty, 0, screen_size_y(s) - 1, wp->yoff); + tty_cursor(tty, s->old_cx, s->old_cy, wp->xoff, wp->yoff); + if (wp->xoff == 0 && screen_size_x(s) >= tty->sx && + tty_term_has(tty->term, TTYC_EL)) { + tty_putcode(tty, TTYC_EL); + if (s->old_cy != screen_size_y(s) - 1) { + tty_cursor(tty, 0, s->old_cy + 1, wp->xoff, wp->yoff); + for (i = s->old_cy + 1; i < screen_size_y(s); i++) { + tty_putcode(tty, TTYC_EL); + if (i == screen_size_y(s) - 1) + continue; + tty_emulate_repeat(tty, TTYC_CUD, TTYC_CUD1, 1); + tty->cy++; + } + } + } else { + for (i = s->old_cx; i < screen_size_x(s); i++) + tty_putc(tty, ' '); + for (j = s->old_cy; j < screen_size_y(s); j++) { + tty_cursor(tty, 0, j, wp->xoff, wp->yoff); + for (i = 0; i < screen_size_x(s); i++) + tty_putc(tty, ' '); + } + } +} + +void +tty_cmd_clearstartofscreen( + struct tty *tty, struct window_pane *wp, unused va_list ap) +{ + struct screen *s = wp->screen; + u_int i, j; + + tty_reset(tty); + + tty_region(tty, 0, screen_size_y(s) - 1, wp->yoff); + tty_cursor(tty, 0, 0, wp->xoff, wp->yoff); + if (wp->xoff == 0 && screen_size_x(s) >= tty->sx && + tty_term_has(tty->term, TTYC_EL)) { + for (i = 0; i < s->old_cy; i++) { + tty_putcode(tty, TTYC_EL); + tty_emulate_repeat(tty, TTYC_CUD, TTYC_CUD1, 1); + tty->cy++; + } + } else { + for (j = 0; j < s->old_cy; j++) { + tty_cursor(tty, 0, j, wp->xoff, wp->yoff); + for (i = 0; i < screen_size_x(s); i++) + tty_putc(tty, ' '); + } + } + for (i = 0; i < s->old_cx; i++) + tty_putc(tty, ' '); +} + +void +tty_cmd_clearscreen( + struct tty *tty, struct window_pane *wp, unused va_list ap) +{ + struct screen *s = wp->screen; + u_int i, j; + + tty_reset(tty); + + tty_region(tty, 0, screen_size_y(s) - 1, wp->yoff); + tty_cursor(tty, 0, 0, wp->xoff, wp->yoff); + if (wp->xoff == 0 && screen_size_x(s) >= tty->sx && + tty_term_has(tty->term, TTYC_EL)) { + for (i = 0; i < screen_size_y(s); i++) { + tty_putcode(tty, TTYC_EL); + if (i != screen_size_y(s) - 1) { + tty_emulate_repeat(tty, TTYC_CUD, TTYC_CUD1, 1); + tty->cy++; + } + } + } else { + for (j = 0; j < screen_size_y(s); j++) { + tty_cursor(tty, 0, j, wp->xoff, wp->yoff); + for (i = 0; i < screen_size_x(s); i++) + tty_putc(tty, ' '); + } + } +} + +void +tty_cmd_cell(struct tty *tty, struct window_pane *wp, va_list ap) +{ + struct screen *s = wp->screen; + struct grid_cell *gc; + struct grid_utf8 *gu; + + gc = va_arg(ap, struct grid_cell *); + gu = va_arg(ap, struct grid_utf8 *); + + tty_cursor(tty, s->old_cx, s->old_cy, wp->xoff, wp->yoff); + + tty_cell(tty, gc, gu); +} + +void +tty_cmd_raw(struct tty *tty, unused struct window_pane *wp, va_list ap) +{ + u_char *buf; + size_t i, len; + + buf = va_arg(ap, u_char *); + len = va_arg(ap, size_t); + + for (i = 0; i < len; i++) + tty_putc(tty, buf[i]); +} + +void +tty_cell( + struct tty *tty, const struct grid_cell *gc, const struct grid_utf8 *gu) +{ + u_int i; + + /* Skip last character if terminal is stupid. */ + if (tty->term->flags & TERM_EARLYWRAP && + tty->cy == tty->sy - 1 && tty->cx == tty->sx - 1) + return; + + /* If this is a padding character, do nothing. */ + if (gc->flags & GRID_FLAG_PADDING) + return; + + /* Set the attributes. */ + tty_attributes(tty, gc); + + /* If not UTF-8, write directly. */ + if (!(gc->flags & GRID_FLAG_UTF8)) { + if (gc->data < 0x20 || gc->data == 0x7f) + return; + tty_putc(tty, gc->data); + return; + } + + /* If the terminal doesn't support UTF-8, write underscores. */ + if (!(tty->flags & TTY_UTF8)) { + for (i = 0; i < gu->width; i++) + tty_putc(tty, '_'); + return; + } + + /* Otherwise, write UTF-8. */ + for (i = 0; i < UTF8_SIZE; i++) { + if (gu->data[i] == 0xff) + break; + tty_putc(tty, gu->data[i]); + } +} + +void +tty_reset(struct tty *tty) +{ + struct grid_cell *gc = &tty->cell; + + if (memcmp(gc, &grid_default_cell, sizeof *gc) == 0) + return; + + if (tty_term_has(tty->term, TTYC_RMACS) && gc->attr & GRID_ATTR_CHARSET) + tty_putcode(tty, TTYC_RMACS); + tty_putcode(tty, TTYC_SGR0); + memcpy(gc, &grid_default_cell, sizeof *gc); +} + +void +tty_region(struct tty *tty, u_int rupper, u_int rlower, u_int oy) +{ + if (!tty_term_has(tty->term, TTYC_CSR)) + return; + if (tty->rlower != oy + rlower || tty->rupper != oy + rupper) { + tty->rlower = oy + rlower; + tty->rupper = oy + rupper; + tty->cx = 0; + tty->cy = 0; + tty_putcode2(tty, TTYC_CSR, tty->rupper, tty->rlower); + } +} + +void +tty_cursor(struct tty *tty, u_int cx, u_int cy, u_int ox, u_int oy) +{ + if (ox + cx == 0 && tty->cx != 0 && tty->cy == oy + cy) { + tty->cx = 0; + tty_putc(tty, '\r'); + } else if (tty->cx != ox + cx || tty->cy != oy + cy) { + tty->cx = ox + cx; + tty->cy = oy + cy; + tty_putcode2(tty, TTYC_CUP, tty->cy, tty->cx); + } +} + +void +tty_attributes(struct tty *tty, const struct grid_cell *gc) +{ + struct grid_cell *tc = &tty->cell; + u_char changed; + u_int fg, bg; + + /* If any bits are being cleared, reset everything. */ + if (tc->attr & ~gc->attr) + tty_reset(tty); + + /* Filter out attribute bits already set. */ + changed = gc->attr & ~tc->attr; + tc->attr = gc->attr; + + /* Set the attributes. */ + fg = gc->fg; + bg = gc->bg; + if (changed & GRID_ATTR_BRIGHT) + tty_putcode(tty, TTYC_BOLD); + if (changed & GRID_ATTR_DIM) + tty_putcode(tty, TTYC_DIM); + if (changed & GRID_ATTR_ITALICS) + tty_putcode(tty, TTYC_SMSO); + if (changed & GRID_ATTR_UNDERSCORE) + tty_putcode(tty, TTYC_SMUL); + if (changed & GRID_ATTR_BLINK) + tty_putcode(tty, TTYC_BLINK); + if (changed & GRID_ATTR_REVERSE) { + if (tty_term_has(tty->term, TTYC_REV)) + tty_putcode(tty, TTYC_REV); + else if (tty_term_has(tty->term, TTYC_SMSO)) + tty_putcode(tty, TTYC_SMSO); + } + if (changed & GRID_ATTR_HIDDEN) + tty_putcode(tty, TTYC_INVIS); + if (changed & GRID_ATTR_CHARSET) + tty_putcode(tty, TTYC_SMACS); + + /* Set foreground colour. */ + if (fg != tc->fg || + (gc->flags & GRID_FLAG_FG256) != (tc->flags & GRID_FLAG_FG256)) { + tty_attributes_fg(tty, gc); + tc->fg = fg; + } + + /* Set background colour. */ + if (bg != tc->bg || + (gc->flags & GRID_FLAG_BG256) != (tc->flags & GRID_FLAG_BG256)) { + tty_attributes_bg(tty, gc); + tc->bg = bg; + } +} + +int +tty_try_256(struct tty *tty, u_char colour, const char *type) +{ + char s[32]; + + if (!(tty->term->flags & TERM_256COLOURS) && + !(tty->term_flags & TERM_256COLOURS)) + return (-1); + + xsnprintf(s, sizeof s, "\033[%s;5;%hhum", type, colour); + tty_puts(tty, s); + return (0); +} + +int +tty_try_88(struct tty *tty, u_char colour, const char *type) +{ + char s[32]; + + if (!(tty->term->flags & TERM_88COLOURS) && + !(tty->term_flags & TERM_88COLOURS)) + return (-1); + colour = colour_256to88(colour); + + xsnprintf(s, sizeof s, "\033[%s;5;%hhum", type, colour); + tty_puts(tty, s); + return (0); +} + +void +tty_attributes_fg(struct tty *tty, const struct grid_cell *gc) +{ + u_char fg; + + fg = gc->fg; + if (gc->flags & GRID_FLAG_FG256) { + if (tty_try_256(tty, fg, "38") == 0) + return; + if (tty_try_88(tty, fg, "38") == 0) + return; + fg = colour_256to16(fg); + if (fg & 8) { + fg &= 7; + tty_putcode(tty, TTYC_BOLD); + tty->cell.attr |= GRID_ATTR_BRIGHT; + } else if (tty->cell.attr & GRID_ATTR_BRIGHT) + tty_reset(tty); + } + + if (fg == 8 && + !(tty->term->flags & TERM_HASDEFAULTS) && + !(tty->term_flags & TERM_HASDEFAULTS)) + fg = 7; + if (fg == 8) + tty_puts(tty, "\033[39m"); + else + tty_putcode1(tty, TTYC_SETAF, fg); +} + +void +tty_attributes_bg(struct tty *tty, const struct grid_cell *gc) +{ + u_char bg; + + bg = gc->bg; + if (gc->flags & GRID_FLAG_BG256) { + if (tty_try_256(tty, bg, "48") == 0) + return; + if (tty_try_88(tty, bg, "48") == 0) + return; + bg = colour_256to16(bg); + if (bg & 8) + bg &= 7; + } + + if (bg == 8 && + !(tty->term->flags & TERM_HASDEFAULTS) && + !(tty->term_flags & TERM_HASDEFAULTS)) + bg = 0; + if (bg == 8) + tty_puts(tty, "\033[49m"); + else + tty_putcode1(tty, TTYC_SETAB, bg); +} diff --git a/utf8.c b/utf8.c new file mode 100644 index 00000000..b0e3c3cb --- /dev/null +++ b/utf8.c @@ -0,0 +1,317 @@ +/* $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 "tmux.h" + +struct utf8_width_entry { + u_int first; + u_int last; + + int width; + + struct utf8_width_entry *left; + struct utf8_width_entry *right; +}; + +/* Random order. Not optimal but it'll do for now... */ +struct utf8_width_entry utf8_width_table[] = { + { 0x00951, 0x00954, 0, NULL, NULL }, + { 0x00ccc, 0x00ccd, 0, NULL, NULL }, + { 0x0fff9, 0x0fffb, 0, NULL, NULL }, + { 0x20000, 0x2fffd, 2, NULL, NULL }, + { 0x00ebb, 0x00ebc, 0, NULL, NULL }, + { 0x01932, 0x01932, 0, NULL, NULL }, + { 0x0070f, 0x0070f, 0, NULL, NULL }, + { 0x00a70, 0x00a71, 0, NULL, NULL }, + { 0x02329, 0x02329, 2, NULL, NULL }, + { 0x00acd, 0x00acd, 0, NULL, NULL }, + { 0x00ac7, 0x00ac8, 0, NULL, NULL }, + { 0x00a3c, 0x00a3c, 0, NULL, NULL }, + { 0x009cd, 0x009cd, 0, NULL, NULL }, + { 0x00591, 0x005bd, 0, NULL, NULL }, + { 0x01058, 0x01059, 0, NULL, NULL }, + { 0x0ffe0, 0x0ffe6, 2, NULL, NULL }, + { 0x01100, 0x0115f, 2, NULL, NULL }, + { 0x0fe20, 0x0fe23, 0, NULL, NULL }, + { 0x0302a, 0x0302f, 0, NULL, NULL }, + { 0x01772, 0x01773, 0, NULL, NULL }, + { 0x005bf, 0x005bf, 0, NULL, NULL }, + { 0x006ea, 0x006ed, 0, NULL, NULL }, + { 0x00bc0, 0x00bc0, 0, NULL, NULL }, + { 0x00962, 0x00963, 0, NULL, NULL }, + { 0x01732, 0x01734, 0, NULL, NULL }, + { 0x00d41, 0x00d43, 0, NULL, NULL }, + { 0x01b42, 0x01b42, 0, NULL, NULL }, + { 0x00a41, 0x00a42, 0, NULL, NULL }, + { 0x00eb4, 0x00eb9, 0, NULL, NULL }, + { 0x00b01, 0x00b01, 0, NULL, NULL }, + { 0x00e34, 0x00e3a, 0, NULL, NULL }, + { 0x03040, 0x03098, 2, NULL, NULL }, + { 0x0093c, 0x0093c, 0, NULL, NULL }, + { 0x00c4a, 0x00c4d, 0, NULL, NULL }, + { 0x01032, 0x01032, 0, NULL, NULL }, + { 0x00f37, 0x00f37, 0, NULL, NULL }, + { 0x00901, 0x00902, 0, NULL, NULL }, + { 0x00cbf, 0x00cbf, 0, NULL, NULL }, + { 0x0a806, 0x0a806, 0, NULL, NULL }, + { 0x00dd2, 0x00dd4, 0, NULL, NULL }, + { 0x00f71, 0x00f7e, 0, NULL, NULL }, + { 0x01752, 0x01753, 0, NULL, NULL }, + { 0x1d242, 0x1d244, 0, NULL, NULL }, + { 0x005c1, 0x005c2, 0, NULL, NULL }, + { 0x0309b, 0x0a4cf, 2, NULL, NULL }, + { 0xe0100, 0xe01ef, 0, NULL, NULL }, + { 0x017dd, 0x017dd, 0, NULL, NULL }, + { 0x00600, 0x00603, 0, NULL, NULL }, + { 0x009e2, 0x009e3, 0, NULL, NULL }, + { 0x00cc6, 0x00cc6, 0, NULL, NULL }, + { 0x0a80b, 0x0a80b, 0, NULL, NULL }, + { 0x01712, 0x01714, 0, NULL, NULL }, + { 0x00b3c, 0x00b3c, 0, NULL, NULL }, + { 0x01b00, 0x01b03, 0, NULL, NULL }, + { 0x007eb, 0x007f3, 0, NULL, NULL }, + { 0xe0001, 0xe0001, 0, NULL, NULL }, + { 0x1d185, 0x1d18b, 0, NULL, NULL }, + { 0x0feff, 0x0feff, 0, NULL, NULL }, + { 0x01b36, 0x01b3a, 0, NULL, NULL }, + { 0x01920, 0x01922, 0, NULL, NULL }, + { 0x00670, 0x00670, 0, NULL, NULL }, + { 0x00f90, 0x00f97, 0, NULL, NULL }, + { 0x01927, 0x01928, 0, NULL, NULL }, + { 0x0200b, 0x0200f, 0, NULL, NULL }, + { 0x0ff00, 0x0ff60, 2, NULL, NULL }, + { 0x0f900, 0x0faff, 2, NULL, NULL }, + { 0x0fb1e, 0x0fb1e, 0, NULL, NULL }, + { 0x00cbc, 0x00cbc, 0, NULL, NULL }, + { 0x00eb1, 0x00eb1, 0, NULL, NULL }, + { 0x10a38, 0x10a3a, 0, NULL, NULL }, + { 0x007a6, 0x007b0, 0, NULL, NULL }, + { 0x00f80, 0x00f84, 0, NULL, NULL }, + { 0x005c4, 0x005c5, 0, NULL, NULL }, + { 0x0ac00, 0x0d7a3, 2, NULL, NULL }, + { 0x017c9, 0x017d3, 0, NULL, NULL }, + { 0x00d4d, 0x00d4d, 0, NULL, NULL }, + { 0x1d167, 0x1d169, 0, NULL, NULL }, + { 0x01036, 0x01037, 0, NULL, NULL }, + { 0xe0020, 0xe007f, 0, NULL, NULL }, + { 0x00f35, 0x00f35, 0, NULL, NULL }, + { 0x017b4, 0x017b5, 0, NULL, NULL }, + { 0x0206a, 0x0206f, 0, NULL, NULL }, + { 0x00c46, 0x00c48, 0, NULL, NULL }, + { 0x01939, 0x0193b, 0, NULL, NULL }, + { 0x01dc0, 0x01dca, 0, NULL, NULL }, + { 0x10a0c, 0x10a0f, 0, NULL, NULL }, + { 0x0102d, 0x01030, 0, NULL, NULL }, + { 0x017c6, 0x017c6, 0, NULL, NULL }, + { 0x00ec8, 0x00ecd, 0, NULL, NULL }, + { 0x00b41, 0x00b43, 0, NULL, NULL }, + { 0x017b7, 0x017bd, 0, NULL, NULL }, + { 0x1d173, 0x1d182, 0, NULL, NULL }, + { 0x00a47, 0x00a48, 0, NULL, NULL }, + { 0x0232a, 0x0232a, 2, NULL, NULL }, + { 0x01b3c, 0x01b3c, 0, NULL, NULL }, + { 0x10a01, 0x10a03, 0, NULL, NULL }, + { 0x00ae2, 0x00ae3, 0, NULL, NULL }, + { 0x00483, 0x00486, 0, NULL, NULL }, + { 0x0135f, 0x0135f, 0, NULL, NULL }, + { 0x01a17, 0x01a18, 0, NULL, NULL }, + { 0x006e7, 0x006e8, 0, NULL, NULL }, + { 0x03099, 0x0309a, 0, NULL, NULL }, + { 0x00b4d, 0x00b4d, 0, NULL, NULL }, + { 0x00ce2, 0x00ce3, 0, NULL, NULL }, + { 0x00bcd, 0x00bcd, 0, NULL, NULL }, + { 0x00610, 0x00615, 0, NULL, NULL }, + { 0x00f99, 0x00fbc, 0, NULL, NULL }, + { 0x009c1, 0x009c4, 0, NULL, NULL }, + { 0x00730, 0x0074a, 0, NULL, NULL }, + { 0x00300, 0x0036f, 0, NULL, NULL }, + { 0x03030, 0x0303e, 2, NULL, NULL }, + { 0x01b34, 0x01b34, 0, NULL, NULL }, + { 0x1d1aa, 0x1d1ad, 0, NULL, NULL }, + { 0x00dca, 0x00dca, 0, NULL, NULL }, + { 0x006d6, 0x006e4, 0, NULL, NULL }, + { 0x00f86, 0x00f87, 0, NULL, NULL }, + { 0x00b3f, 0x00b3f, 0, NULL, NULL }, + { 0x0fe30, 0x0fe6f, 2, NULL, NULL }, + { 0x01039, 0x01039, 0, NULL, NULL }, + { 0x0094d, 0x0094d, 0, NULL, NULL }, + { 0x00c55, 0x00c56, 0, NULL, NULL }, + { 0x00488, 0x00489, 0, NULL, NULL }, + { 0x00e47, 0x00e4e, 0, NULL, NULL }, + { 0x00a81, 0x00a82, 0, NULL, NULL }, + { 0x00ac1, 0x00ac5, 0, NULL, NULL }, + { 0x0202a, 0x0202e, 0, NULL, NULL }, + { 0x00dd6, 0x00dd6, 0, NULL, NULL }, + { 0x018a9, 0x018a9, 0, NULL, NULL }, + { 0x0064b, 0x0065e, 0, NULL, NULL }, + { 0x00abc, 0x00abc, 0, NULL, NULL }, + { 0x00b82, 0x00b82, 0, NULL, NULL }, + { 0x00f39, 0x00f39, 0, NULL, NULL }, + { 0x020d0, 0x020ef, 0, NULL, NULL }, + { 0x01dfe, 0x01dff, 0, NULL, NULL }, + { 0x30000, 0x3fffd, 2, NULL, NULL }, + { 0x00711, 0x00711, 0, NULL, NULL }, + { 0x0fe00, 0x0fe0f, 0, NULL, NULL }, + { 0x01160, 0x011ff, 0, NULL, NULL }, + { 0x0180b, 0x0180d, 0, NULL, NULL }, + { 0x10a3f, 0x10a3f, 0, NULL, NULL }, + { 0x00981, 0x00981, 0, NULL, NULL }, + { 0x0a825, 0x0a826, 0, NULL, NULL }, + { 0x00941, 0x00948, 0, NULL, NULL }, + { 0x01b6b, 0x01b73, 0, NULL, NULL }, + { 0x00e31, 0x00e31, 0, NULL, NULL }, + { 0x0fe10, 0x0fe19, 2, NULL, NULL }, + { 0x00a01, 0x00a02, 0, NULL, NULL }, + { 0x00a4b, 0x00a4d, 0, NULL, NULL }, + { 0x00f18, 0x00f19, 0, NULL, NULL }, + { 0x00fc6, 0x00fc6, 0, NULL, NULL }, + { 0x02e80, 0x03029, 2, NULL, NULL }, + { 0x00b56, 0x00b56, 0, NULL, NULL }, + { 0x009bc, 0x009bc, 0, NULL, NULL }, + { 0x005c7, 0x005c7, 0, NULL, NULL }, + { 0x02060, 0x02063, 0, NULL, NULL }, + { 0x00c3e, 0x00c40, 0, NULL, NULL }, + { 0x10a05, 0x10a06, 0, NULL, NULL }, +}; + +struct utf8_width_entry *utf8_width_root = NULL; + +int utf8_overlap(struct utf8_width_entry *, struct utf8_width_entry *); +void utf8_print(struct utf8_width_entry *, int); +u_int utf8_combine(const u_char *); +void utf8_split(u_int, u_char *); + +int +utf8_overlap( + struct utf8_width_entry *item1, struct utf8_width_entry *item2) +{ + if (item1->first >= item2->first && item1->first <= item2->last) + return (1); + if (item1->last >= item2->first && item1->last <= item2->last) + return (1); + if (item2->first >= item1->first && item2->first <= item1->last) + return (1); + if (item2->last >= item1->first && item2->last <= item1->last) + return (1); + return (0); +} + +void +utf8_build(void) +{ + struct utf8_width_entry **ptr, *item, *node; + u_int i, j; + + for (i = 0; i < nitems(utf8_width_table); i++) { + item = &utf8_width_table[i]; + + for (j = 0; j < nitems(utf8_width_table); j++) { + if (i != j && utf8_overlap(item, &utf8_width_table[j])) + log_fatalx("utf8 overlap: %u %u", i, j); + } + + ptr = &utf8_width_root; + while (*ptr != NULL) { + node = *ptr; + if (item->last < node->first) + ptr = &(node->left); + else if (item->first > node->last) + ptr = &(node->right); + } + *ptr = item; + } +} + +void +utf8_print(struct utf8_width_entry *node, int n) +{ + log_debug("%*s%04x -> %04x", n, " ", node->first, node->last); + if (node->left != NULL) + utf8_print(node->left, n + 1); + if (node->right != NULL) + utf8_print(node->right, n + 1); +} + +u_int +utf8_combine(const u_char *data) +{ + u_int uvalue; + + if (data[1] == 0xff) + uvalue = data[0]; + else if (data[2] == 0xff) { + uvalue = data[1] & 0x3f; + uvalue |= (data[0] & 0x1f) << 6; + } else if (data[3] == 0xff) { + uvalue = data[2] & 0x3f; + uvalue |= (data[1] & 0x3f) << 6; + uvalue |= (data[0] & 0x0f) << 12; + } else { + uvalue = data[3] & 0x3f; + uvalue |= (data[2] & 0x3f) << 6; + uvalue |= (data[1] & 0x3f) << 12; + uvalue |= (data[0] & 0x3f) << 18; + } + return (uvalue); +} + +void +utf8_split(u_int uvalue, u_char *data) +{ + memset(data, 0xff, 4); + + if (uvalue <= 0x7f) + data[0] = uvalue; + else if (uvalue > 0x7f && uvalue <= 0x7ff) { + data[0] = (uvalue >> 6) | 0xc0; + data[1] = (uvalue & 0x3f) | 0x80; + } else if (uvalue > 0x7ff && uvalue <= 0xffff) { + data[0] = (uvalue >> 12) | 0xe0; + data[1] = ((uvalue >> 6) & 0x3f) | 0x80; + data[2] = (uvalue & 0x3f) | 0x80; + } else if (uvalue > 0xffff && uvalue <= 0x10ffff) { + data[0] = (uvalue >> 18) | 0xf0; + data[1] = ((uvalue >> 12) & 0x3f) | 0x80; + data[2] = ((uvalue >> 6) & 0x3f) | 0x80; + data[3] = (uvalue & 0x3f) | 0x80; + } +} + +int +utf8_width(u_char *udata) +{ + struct utf8_width_entry *item; + u_int uvalue; + + uvalue = utf8_combine(udata); + + item = utf8_width_root; + while (item != NULL) { + if (uvalue < item->first) + item = item->left; + else if (uvalue > item->last) + item = item->right; + else + return (item->width); + } + return (1); +} diff --git a/util.c b/util.c new file mode 100644 index 00000000..1455214a --- /dev/null +++ b/util.c @@ -0,0 +1,72 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2009 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" + +/* Return a section of a string around a point. */ +char * +section_string(char *buf, size_t len, size_t sectoff, size_t sectlen) +{ + char *s; + size_t first, last; + + if (len <= sectlen) { + first = 0; + last = len; + } else if (sectoff < sectlen / 2) { + first = 0; + last = sectlen; + } else if (sectoff + sectlen / 2 > len) { + last = len; + first = last - sectlen; + } else { + first = sectoff - sectlen / 2; + last = first + sectlen; + } + + if (last - first > 3 && first != 0) + first += 3; + if (last - first > 3 && last != len) + last -= 3; + + xasprintf(&s, "%s%.*s%s", first == 0 ? "" : "...", + (int) (last - first), buf + first, last == len ? "" : "..."); + return (s); +} + +/* Clean string of invisible characters. */ +void +clean_string(const char *in, char *buf, size_t len) +{ + const u_char *cp; + size_t off; + + off = 0; + for (cp = in; *cp != '\0'; cp++) { + if (off >= len) + break; + if (*cp >= 0x20 && *cp <= 0x7f) + buf[off++] = *cp; + else + off += xsnprintf(buf + off, len - off, "\\%03hho", *cp); + } + if (off < len) + buf[off] = '\0'; +} diff --git a/window-choose.c b/window-choose.c new file mode 100644 index 00000000..5470a7e8 --- /dev/null +++ b/window-choose.c @@ -0,0 +1,361 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2009 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 "tmux.h" + +struct screen *window_choose_init(struct window_pane *); +void window_choose_free(struct window_pane *); +void window_choose_resize(struct window_pane *, u_int, u_int); +void window_choose_key(struct window_pane *, struct client *, int); +void window_choose_mouse( + struct window_pane *, struct client *, u_char, u_char, u_char); + +void window_choose_redraw_screen(struct window_pane *); +void window_choose_write_line( + struct window_pane *, struct screen_write_ctx *, u_int); + +void window_choose_scroll_up(struct window_pane *); +void window_choose_scroll_down(struct window_pane *); + +const struct window_mode window_choose_mode = { + window_choose_init, + window_choose_free, + window_choose_resize, + window_choose_key, + window_choose_mouse, + NULL, +}; + +struct window_choose_mode_item { + char *name; + int idx; +}; + +struct window_choose_mode_data { + struct screen screen; + + struct mode_key_data mdata; + + ARRAY_DECL(, struct window_choose_mode_item) list; + u_int top; + u_int selected; + + void (*callback)(void *, int); + void *data; +}; + +void +window_choose_vadd(struct window_pane *wp, int idx, const char *fmt, va_list ap) +{ + struct window_choose_mode_data *data = wp->modedata; + struct window_choose_mode_item *item; + + ARRAY_EXPAND(&data->list, 1); + item = &ARRAY_LAST(&data->list); + xvasprintf(&item->name, fmt, ap); + item->idx = idx; +} + +void printflike3 +window_choose_add(struct window_pane *wp, int idx, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + window_choose_vadd(wp, idx, fmt, ap); + va_end(ap); +} + +void +window_choose_ready(struct window_pane *wp, + u_int cur, void (*callback)(void *, int), void *cdata) +{ + struct window_choose_mode_data *data = wp->modedata; + struct screen *s = &data->screen; + + data->selected = cur; + if (data->selected > screen_size_y(s) - 1) + data->top = ARRAY_LENGTH(&data->list) - screen_size_y(s); + + data->callback = callback; + data->data = cdata; + + window_choose_redraw_screen(wp); +} + +struct screen * +window_choose_init(struct window_pane *wp) +{ + struct window_choose_mode_data *data; + struct screen *s; + + wp->modedata = data = xmalloc(sizeof *data); + data->callback = NULL; + ARRAY_INIT(&data->list); + data->top = 0; + + s = &data->screen; + screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0); + s->mode &= ~MODE_CURSOR; + s->mode |= MODE_MOUSE; + + mode_key_init(&data->mdata, + options_get_number(&wp->window->options, "mode-keys"), + MODEKEY_CHOOSEMODE); + + return (s); +} + +void +window_choose_free(struct window_pane *wp) +{ + struct window_choose_mode_data *data = wp->modedata; + u_int i; + + mode_key_free(&data->mdata); + + for (i = 0; i < ARRAY_LENGTH(&data->list); i++) + xfree(ARRAY_ITEM(&data->list, i).name); + ARRAY_FREE(&data->list); + + screen_free(&data->screen); + xfree(data); +} + +void +window_choose_resize(struct window_pane *wp, u_int sx, u_int sy) +{ + struct window_choose_mode_data *data = wp->modedata; + struct screen *s = &data->screen; + + data->top = 0; + if (data->selected > sy - 1) + data->top = data->selected - (sy - 1); + + screen_resize(s, sx, sy); + window_choose_redraw_screen(wp); +} + +void +window_choose_key(struct window_pane *wp, unused struct client *c, int key) +{ + struct window_choose_mode_data *data = wp->modedata; + struct screen *s = &data->screen; + struct screen_write_ctx ctx; + struct window_choose_mode_item *item; + u_int items; + + items = ARRAY_LENGTH(&data->list); + + switch (mode_key_lookup(&data->mdata, key)) { + case MODEKEYCMD_QUIT: + data->callback(data->data, -1); + window_pane_reset_mode(wp); + break; + case MODEKEYCMD_CHOOSE: + item = &ARRAY_ITEM(&data->list, data->selected); + data->callback(data->data, item->idx); + window_pane_reset_mode(wp); + break; + case MODEKEYCMD_UP: + if (items == 0) + break; + if (data->selected == 0) { + data->selected = items - 1; + if (data->selected > screen_size_y(s) - 1) + data->top = items - screen_size_y(s); + window_choose_redraw_screen(wp); + break; + } + data->selected--; + if (data->selected < data->top) + window_choose_scroll_up(wp); + else { + screen_write_start(&ctx, wp, NULL); + window_choose_write_line( + wp, &ctx, data->selected - data->top); + window_choose_write_line( + wp, &ctx, data->selected + 1 - data->top); + screen_write_stop(&ctx); + } + break; + case MODEKEYCMD_DOWN: + if (items == 0) + break; + if (data->selected == items - 1) { + data->selected = 0; + data->top = 0; + window_choose_redraw_screen(wp); + break; + } + data->selected++; + if (data->selected >= data->top + screen_size_y(&data->screen)) + window_choose_scroll_down(wp); + else { + screen_write_start(&ctx, wp, NULL); + window_choose_write_line( + wp, &ctx, data->selected - data->top); + window_choose_write_line( + wp, &ctx, data->selected - 1 - data->top); + screen_write_stop(&ctx); + } + break; + case MODEKEYCMD_PREVIOUSPAGE: + if (data->selected < screen_size_y(s)) { + data->selected = 0; + data->top = 0; + } else { + data->selected -= screen_size_y(s); + if (data->top < screen_size_y(s)) + data->top = 0; + else + data->top -= screen_size_y(s); + } + window_choose_redraw_screen(wp); + break; + case MODEKEYCMD_NEXTPAGE: + data->selected += screen_size_y(s); + if (data->selected > items - 1) + data->selected = items - 1; + data->top += screen_size_y(s); + if (screen_size_y(s) < items) { + if (data->top + screen_size_y(s) > items) + data->top = items - screen_size_y(s); + } else + data->top = 0; + if (data->selected < data->top) + data->top = data->selected; + window_choose_redraw_screen(wp); + break; + default: + break; + } +} + +void +window_choose_mouse(struct window_pane *wp, + unused struct client *c, u_char b, u_char x, u_char y) +{ + struct window_choose_mode_data *data = wp->modedata; + struct screen *s = &data->screen; + struct window_choose_mode_item *item; + u_int idx; + + if ((b & 3) == 3) + return; + if (x >= screen_size_x(s)) + return; + if (y >= screen_size_y(s)) + return; + + idx = data->top + y; + if (idx >= ARRAY_LENGTH(&data->list)) + return; + data->selected = idx; + + item = &ARRAY_ITEM(&data->list, data->selected); + data->callback(data->data, item->idx); + window_pane_reset_mode(wp); +} + +void +window_choose_write_line( + struct window_pane *wp, struct screen_write_ctx *ctx, u_int py) +{ + struct window_choose_mode_data *data = wp->modedata; + struct window_choose_mode_item *item; + struct screen *s = &data->screen; + struct grid_cell gc; + + if (data->callback == NULL) + fatalx("called before callback assigned"); + + memcpy(&gc, &grid_default_cell, sizeof gc); + if (data->selected == data->top + py) { + gc.fg = options_get_number(&wp->window->options, "mode-bg"); + gc.bg = options_get_number(&wp->window->options, "mode-fg"); + gc.attr |= options_get_number(&wp->window->options, "mode-attr"); + } + + screen_write_cursormove(ctx, 0, py); + if (data->top + py < ARRAY_LENGTH(&data->list)) { + item = &ARRAY_ITEM(&data->list, data->top + py); + screen_write_puts( + ctx, &gc, "%.*s", (int) screen_size_x(s), item->name); + } + while (s->cx < screen_size_x(s)) + screen_write_putc(ctx, &gc, ' '); + +} + +void +window_choose_redraw_screen(struct window_pane *wp) +{ + struct window_choose_mode_data *data = wp->modedata; + struct screen *s = &data->screen; + struct screen_write_ctx ctx; + u_int i; + + screen_write_start(&ctx, wp, NULL); + for (i = 0; i < screen_size_y(s); i++) + window_choose_write_line(wp, &ctx, i); + screen_write_stop(&ctx); +} + +void +window_choose_scroll_up(struct window_pane *wp) +{ + struct window_choose_mode_data *data = wp->modedata; + struct screen_write_ctx ctx; + + if (data->top == 0) + return; + data->top--; + + screen_write_start(&ctx, wp, NULL); + screen_write_cursormove(&ctx, 0, 0); + screen_write_insertline(&ctx, 1); + window_choose_write_line(wp, &ctx, 0); + if (screen_size_y(&data->screen) > 1) + window_choose_write_line(wp, &ctx, 1); + screen_write_stop(&ctx); +} + +void +window_choose_scroll_down(struct window_pane *wp) +{ + struct window_choose_mode_data *data = wp->modedata; + struct screen *s = &data->screen; + struct screen_write_ctx ctx; + + if (data->top >= ARRAY_LENGTH(&data->list)) + return; + data->top++; + + screen_write_start(&ctx, wp, NULL); + screen_write_cursormove(&ctx, 0, 0); + screen_write_deleteline(&ctx, 1); + window_choose_write_line(wp, &ctx, screen_size_y(s) - 1); + if (screen_size_y(&data->screen) > 1) + window_choose_write_line(wp, &ctx, screen_size_y(s) - 2); + screen_write_stop(&ctx); +} diff --git a/window-clock.c b/window-clock.c new file mode 100644 index 00000000..e84635f6 --- /dev/null +++ b/window-clock.c @@ -0,0 +1,124 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2009 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 "tmux.h" + +struct screen *window_clock_init(struct window_pane *); +void window_clock_free(struct window_pane *); +void window_clock_resize(struct window_pane *, u_int, u_int); +void window_clock_key(struct window_pane *, struct client *, int); +void window_clock_timer(struct window_pane *); + +void window_clock_draw_screen(struct window_pane *); + +const struct window_mode window_clock_mode = { + window_clock_init, + window_clock_free, + window_clock_resize, + window_clock_key, + NULL, + window_clock_timer, +}; + +struct window_clock_mode_data { + struct screen screen; + time_t tim; +}; + +struct screen * +window_clock_init(struct window_pane *wp) +{ + struct window_clock_mode_data *data; + struct screen *s; + + wp->modedata = data = xmalloc(sizeof *data); + data->tim = time(NULL); + + s = &data->screen; + screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0); + s->mode &= ~MODE_CURSOR; + + window_clock_draw_screen(wp); + + return (s); +} + +void +window_clock_free(struct window_pane *wp) +{ + struct window_clock_mode_data *data = wp->modedata; + + screen_free(&data->screen); + xfree(data); +} + +void +window_clock_resize(struct window_pane *wp, u_int sx, u_int sy) +{ + struct window_clock_mode_data *data = wp->modedata; + struct screen *s = &data->screen; + + screen_resize(s, sx, sy); + window_clock_draw_screen(wp); +} + +void +window_clock_key( + struct window_pane *wp, unused struct client *c, unused int key) +{ + window_pane_reset_mode(wp); +} + +void +window_clock_timer(struct window_pane *wp) +{ + struct window_clock_mode_data *data = wp->modedata; + struct tm *now, *then; + time_t t; + + t = time(NULL); + now = gmtime(&t); + then = gmtime(&data->tim); + if (now->tm_min == then->tm_min) + return; + data->tim = t; + + window_clock_draw_screen(wp); + server_redraw_window(wp->window); +} + +void +window_clock_draw_screen(struct window_pane *wp) +{ + struct window_clock_mode_data *data = wp->modedata; + struct screen_write_ctx ctx; + u_int colour; + int style; + + colour = options_get_number(&wp->window->options, "clock-mode-colour"); + style = options_get_number(&wp->window->options, "clock-mode-style"); + + screen_write_start(&ctx, NULL, &data->screen); + clock_draw(&ctx, colour, style); + screen_write_stop(&ctx); +} diff --git a/window-copy.c b/window-copy.c new file mode 100644 index 00000000..dc2a4d45 --- /dev/null +++ b/window-copy.c @@ -0,0 +1,968 @@ +/* $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 + +#include "tmux.h" + +struct screen *window_copy_init(struct window_pane *); +void window_copy_free(struct window_pane *); +void window_copy_resize(struct window_pane *, u_int, u_int); +void window_copy_key(struct window_pane *, struct client *, int); +void window_copy_mouse( + struct window_pane *, struct client *, u_char, u_char, u_char); + +void window_copy_redraw_lines(struct window_pane *, u_int, u_int); +void window_copy_redraw_screen(struct window_pane *); +void window_copy_write_line( + struct window_pane *, struct screen_write_ctx *, u_int); +void window_copy_write_lines( + struct window_pane *, struct screen_write_ctx *, u_int, u_int); +void window_copy_write_column( + struct window_pane *, struct screen_write_ctx *, u_int); +void window_copy_write_columns( + struct window_pane *, struct screen_write_ctx *, u_int, u_int); + +void window_copy_update_cursor(struct window_pane *); +void window_copy_start_selection(struct window_pane *); +int window_copy_update_selection(struct window_pane *); +void window_copy_copy_selection(struct window_pane *, struct client *); +void window_copy_copy_line( + struct window_pane *, char **, size_t *, u_int, u_int, u_int); +int window_copy_is_space(struct window_pane *, u_int, u_int); +u_int window_copy_find_length(struct window_pane *, u_int); +void window_copy_cursor_start_of_line(struct window_pane *); +void window_copy_cursor_end_of_line(struct window_pane *); +void window_copy_cursor_left(struct window_pane *); +void window_copy_cursor_right(struct window_pane *); +void window_copy_cursor_up(struct window_pane *); +void window_copy_cursor_down(struct window_pane *); +void window_copy_cursor_next_word(struct window_pane *); +void window_copy_cursor_previous_word(struct window_pane *); +void window_copy_scroll_left(struct window_pane *, u_int); +void window_copy_scroll_right(struct window_pane *, u_int); +void window_copy_scroll_up(struct window_pane *, u_int); +void window_copy_scroll_down(struct window_pane *, u_int); + +const struct window_mode window_copy_mode = { + window_copy_init, + window_copy_free, + window_copy_resize, + window_copy_key, + window_copy_mouse, + NULL, +}; + +struct window_copy_mode_data { + struct screen screen; + + struct mode_key_data mdata; + + u_int ox; + u_int oy; + + u_int selx; + u_int sely; + + u_int cx; + u_int cy; +}; + +struct screen * +window_copy_init(struct window_pane *wp) +{ + struct window_copy_mode_data *data; + struct screen *s; + struct screen_write_ctx ctx; + u_int i; + + wp->modedata = data = xmalloc(sizeof *data); + data->ox = 0; + data->oy = 0; + data->cx = wp->base.cx; + data->cy = wp->base.cy; + + s = &data->screen; + screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0); + s->mode |= MODE_MOUSE; + + mode_key_init(&data->mdata, + options_get_number(&wp->window->options, "mode-keys"), 0); + + s->cx = data->cx; + s->cy = data->cy; + + screen_write_start(&ctx, NULL, s); + for (i = 0; i < screen_size_y(s); i++) + window_copy_write_line(wp, &ctx, i); + screen_write_cursormove(&ctx, data->cx, data->cy); + screen_write_stop(&ctx); + + return (s); +} + +void +window_copy_free(struct window_pane *wp) +{ + struct window_copy_mode_data *data = wp->modedata; + + mode_key_free(&data->mdata); + + screen_free(&data->screen); + xfree(data); +} + +void +window_copy_pageup(struct window_pane *wp) +{ + struct window_copy_mode_data *data = wp->modedata; + struct screen *s = &data->screen; + + if (data->oy + screen_size_y(s) > screen_hsize(&wp->base)) + data->oy = screen_hsize(&wp->base); + else + data->oy += screen_size_y(s); + window_copy_update_selection(wp); + window_copy_redraw_screen(wp); +} + +void +window_copy_resize(struct window_pane *wp, u_int sx, u_int sy) +{ + struct window_copy_mode_data *data = wp->modedata; + struct screen *s = &data->screen; + struct screen_write_ctx ctx; + + screen_resize(s, sx, sy); + screen_write_start(&ctx, NULL, s); + window_copy_write_lines(wp, &ctx, 0, screen_size_y(s) - 1); + screen_write_stop(&ctx); + window_copy_update_selection(wp); +} + +void +window_copy_key(struct window_pane *wp, struct client *c, int key) +{ + struct window_copy_mode_data *data = wp->modedata; + struct screen *s = &data->screen; + + switch (mode_key_lookup(&data->mdata, key)) { + case MODEKEYCMD_QUIT: + window_pane_reset_mode(wp); + break; + case MODEKEYCMD_LEFT: + window_copy_cursor_left(wp); + return; + case MODEKEYCMD_RIGHT: + window_copy_cursor_right(wp); + return; + case MODEKEYCMD_UP: + window_copy_cursor_up(wp); + return; + case MODEKEYCMD_DOWN: + window_copy_cursor_down(wp); + return; + case MODEKEYCMD_PREVIOUSPAGE: + window_copy_pageup(wp); + break; + case MODEKEYCMD_NEXTPAGE: + if (data->oy < screen_size_y(s)) + data->oy = 0; + else + data->oy -= screen_size_y(s); + window_copy_update_selection(wp); + window_copy_redraw_screen(wp); + break; + case MODEKEYCMD_STARTSELECTION: + window_copy_start_selection(wp); + break; + case MODEKEYCMD_CLEARSELECTION: + screen_clear_selection(&data->screen); + window_copy_redraw_screen(wp); + break; + case MODEKEYCMD_COPYSELECTION: + if (c != NULL && c->session != NULL) { + window_copy_copy_selection(wp, c); + window_pane_reset_mode(wp); + } + break; + case MODEKEYCMD_STARTOFLINE: + window_copy_cursor_start_of_line(wp); + break; + case MODEKEYCMD_ENDOFLINE: + window_copy_cursor_end_of_line(wp); + break; + case MODEKEYCMD_NEXTWORD: + window_copy_cursor_next_word(wp); + break; + case MODEKEYCMD_PREVIOUSWORD: + window_copy_cursor_previous_word(wp); + break; + default: + break; + } +} + +void +window_copy_mouse(struct window_pane *wp, + unused struct client *c, u_char b, u_char x, u_char y) +{ + struct window_copy_mode_data *data = wp->modedata; + struct screen *s = &data->screen; + + if ((b & 3) == 3) + return; + if (x >= screen_size_x(s)) + return; + if (y >= screen_size_y(s)) + return; + + data->cx = x; + data->cy = y; + + if (window_copy_update_selection(wp)) + window_copy_redraw_screen(wp); + window_copy_update_cursor(wp); +} + +void +window_copy_write_line(struct window_pane *wp, struct screen_write_ctx *ctx, u_int py) +{ + struct window_copy_mode_data *data = wp->modedata; + struct screen *s = &data->screen; + struct grid_cell gc; + char hdr[32]; + size_t size; + + if (py == 0) { + memcpy(&gc, &grid_default_cell, sizeof gc); + size = xsnprintf(hdr, sizeof hdr, + "[%u,%u/%u]", data->ox, data->oy, screen_hsize(&wp->base)); + gc.bg = options_get_number(&wp->window->options, "mode-fg"); + gc.fg = options_get_number(&wp->window->options, "mode-bg"); + gc.attr |= options_get_number(&wp->window->options, "mode-attr"); + screen_write_cursormove(ctx, screen_size_x(s) - size, 0); + screen_write_puts(ctx, &gc, "%s", hdr); + } else + size = 0; + + screen_write_cursormove(ctx, 0, py); + screen_write_copy(ctx, &wp->base, data->ox, (screen_hsize(&wp->base) - + data->oy) + py, screen_size_x(s) - size, 1); +} + +void +window_copy_write_lines( + struct window_pane *wp, struct screen_write_ctx *ctx, u_int py, u_int ny) +{ + u_int yy; + + for (yy = py; yy < py + ny; yy++) + window_copy_write_line(wp, ctx, py); +} + +void +window_copy_write_column( + struct window_pane *wp, struct screen_write_ctx *ctx, u_int px) +{ + struct window_copy_mode_data *data = wp->modedata; + struct screen *s = &data->screen; + + screen_write_cursormove(ctx, px, 0); + screen_write_copy(ctx, &wp->base, + data->ox + px, screen_hsize(&wp->base) - data->oy, 1, screen_size_y(s)); +} + +void +window_copy_write_columns( + struct window_pane *wp, struct screen_write_ctx *ctx, u_int px, u_int nx) +{ + u_int xx; + + for (xx = px; xx < px + nx; xx++) + window_copy_write_column(wp, ctx, xx); +} + +void +window_copy_redraw_lines(struct window_pane *wp, u_int py, u_int ny) +{ + struct window_copy_mode_data *data = wp->modedata; + struct screen_write_ctx ctx; + u_int i; + + screen_write_start(&ctx, wp, NULL); + for (i = py; i < py + ny; i++) + window_copy_write_line(wp, &ctx, i); + screen_write_cursormove(&ctx, data->cx, data->cy); + screen_write_stop(&ctx); +} + +void +window_copy_redraw_screen(struct window_pane *wp) +{ + struct window_copy_mode_data *data = wp->modedata; + + window_copy_redraw_lines(wp, 0, screen_size_y(&data->screen)); +} + +void +window_copy_update_cursor(struct window_pane *wp) +{ + struct window_copy_mode_data *data = wp->modedata; + struct screen_write_ctx ctx; + + screen_write_start(&ctx, wp, NULL); + screen_write_cursormove(&ctx, data->cx, data->cy); + screen_write_stop(&ctx); +} + +void +window_copy_start_selection(struct window_pane *wp) +{ + struct window_copy_mode_data *data = wp->modedata; + struct screen *s = &data->screen; + + data->selx = data->cx + data->ox; + data->sely = screen_hsize(&wp->base) + data->cy - data->oy; + + s->sel.flag = 1; + window_copy_update_selection(wp); +} + +int +window_copy_update_selection(struct window_pane *wp) +{ + struct window_copy_mode_data *data = wp->modedata; + struct screen *s = &data->screen; + struct grid_cell gc; + u_int sx, sy, tx, ty; + + if (!s->sel.flag) + return (0); + + /* Set colours. */ + memcpy(&gc, &grid_default_cell, sizeof gc); + gc.bg = options_get_number(&wp->window->options, "mode-fg"); + gc.fg = options_get_number(&wp->window->options, "mode-bg"); + gc.attr |= options_get_number(&wp->window->options, "mode-attr"); + + /* Find top-left of screen. */ + tx = data->ox; + ty = screen_hsize(&wp->base) - data->oy; + + /* Adjust the selection. */ + sx = data->selx; + sy = data->sely; + if (sy < ty) { + /* Above it. */ + sx = 0; + sy = 0; + } else if (sy > ty + screen_size_y(s) - 1) { + /* Below it. */ + sx = screen_size_x(s) - 1; + sy = screen_size_y(s) - 1; + } else if (sx < tx) { + /* To the left. */ + sx = 0; + } else if (sx > tx + screen_size_x(s) - 1) { + /* To the right. */ + sx = 0; + sy++; + if (sy > screen_size_y(s) - 1) + sy = screen_size_y(s) - 1; + } else { + sx -= tx; + sy -= ty; + } + sy = screen_hsize(s) + sy; + + screen_set_selection( + s, sx, sy, data->cx, screen_hsize(s) + data->cy, &gc); + return (1); +} + +void +window_copy_copy_selection(struct window_pane *wp, struct client *c) +{ + struct window_copy_mode_data *data = wp->modedata; + struct screen *s = &data->screen; + char *buf; + size_t off; + u_int i, xx, yy, sx, sy, ex, ey, limit; + + if (!s->sel.flag) + return; + + buf = xmalloc(1); + off = 0; + + *buf = '\0'; + + /* + * The selection extends from selx,sely to (adjusted) cx,cy on + * the base screen. + */ + + /* Find start and end. */ + xx = data->cx + data->ox; + yy = screen_hsize(&wp->base) + data->cy - data->oy; + if (xx < data->selx || (yy == data->sely && xx < data->selx)) { + sx = xx; sy = yy; + ex = data->selx; ey = data->sely; + } else { + sx = data->selx; sy = data->sely; + ex = xx; ey = yy; + } + + /* Trim ex to end of line. */ + xx = window_copy_find_length(wp, ey); + if (ex > xx) + ex = xx; + + /* Copy the lines. */ + if (sy == ey) + window_copy_copy_line(wp, &buf, &off, sy, sx, ex); + else { + xx = window_copy_find_length(wp, sy); + window_copy_copy_line(wp, &buf, &off, sy, sx, xx); + if (ey - sy > 1) { + for (i = sy + 1; i < ey - 1; i++) { + xx = window_copy_find_length(wp, i); + window_copy_copy_line(wp, &buf, &off, i, 0, xx); + } + } + window_copy_copy_line(wp, &buf, &off, ey, 0, ex); + } + + /* Terminate buffer, overwriting final \n. */ + if (off != 0) + buf[off - 1] = '\0'; + + /* Add the buffer to the stack. */ + limit = options_get_number(&c->session->options, "buffer-limit"); + paste_add(&c->session->buffers, buf, limit); +} + +void +window_copy_copy_line(struct window_pane *wp, + char **buf, size_t *off, u_int sy, u_int sx, u_int ex) +{ + const struct grid_cell *gc; + const struct grid_utf8 *gu; + u_int i, j, xx; + + if (sx > ex) + return; + + xx = window_copy_find_length(wp, sy); + if (ex > xx) + ex = xx; + if (sx > xx) + sx = xx; + + if (sx < ex) { + for (i = sx; i < ex; i++) { + gc = grid_peek_cell(wp->base.grid, i, sy); + if (gc->flags & GRID_FLAG_PADDING) + continue; + if (!(gc->flags & GRID_FLAG_UTF8)) { + *buf = xrealloc(*buf, 1, (*off) + 1); + (*buf)[(*off)++] = gc->data; + } else { + gu = grid_peek_utf8(wp->base.grid, i, sy); + *buf = xrealloc(*buf, 1, (*off) + UTF8_SIZE); + for (j = 0; j < UTF8_SIZE; j++) { + if (gu->data[j] == 0xff) + break; + (*buf)[(*off)++] = gu->data[j]; + } + } + } + } + + *buf = xrealloc(*buf, 1, (*off) + 1); + (*buf)[*off] = '\n'; + (*off)++; +} + +int +window_copy_is_space(struct window_pane *wp, u_int px, u_int py) +{ + const struct grid_cell *gc; + const char *spaces = " -_@"; + + gc = grid_peek_cell(wp->base.grid, px, py); + if (gc->flags & (GRID_FLAG_PADDING|GRID_FLAG_UTF8)) + return (0); + if (gc->data == 0x00 || gc->data == 0x7f) + return (0); + return (strchr(spaces, gc->data) != NULL); +} + +u_int +window_copy_find_length(struct window_pane *wp, u_int py) +{ + const struct grid_cell *gc; + u_int px; + + px = wp->base.grid->size[py]; + while (px > 0) { + gc = grid_peek_cell(wp->base.grid, px - 1, py); + if (gc->flags & GRID_FLAG_UTF8) + break; + if (gc->data != ' ') + break; + px--; + } + return (px); +} + +void +window_copy_cursor_start_of_line(struct window_pane *wp) +{ + struct window_copy_mode_data *data = wp->modedata; + + if (data->ox != 0) + window_copy_scroll_right(wp, data->ox); + data->cx = 0; + + if (window_copy_update_selection(wp)) + window_copy_redraw_lines(wp, data->cy, 1); + else + window_copy_update_cursor(wp); +} + +void +window_copy_cursor_end_of_line(struct window_pane *wp) +{ + struct window_copy_mode_data *data = wp->modedata; + struct screen *s = &data->screen; + u_int px, py; + + py = screen_hsize(&wp->base) + data->cy - data->oy; + px = window_copy_find_length(wp, py); + + /* On screen. */ + if (px > data->ox && px <= data->ox + screen_size_x(s) - 1) + data->cx = px - data->ox; + + /* Off right of screen. */ + if (px > data->ox + screen_size_x(s) - 1) { + /* Move cursor to last and scroll screen. */ + window_copy_scroll_left( + wp, px - data->ox - (screen_size_x(s) - 1)); + data->cx = screen_size_x(s) - 1; + } + + /* Off left of screen. */ + if (px <= data->ox) { + if (px < screen_size_x(s) - 1) { + /* Short enough to fit on screen. */ + window_copy_scroll_right(wp, data->ox); + data->cx = px; + } else { + /* Too long to fit on screen. */ + window_copy_scroll_right( + wp, data->ox - (px - (screen_size_x(s) - 1))); + data->cx = screen_size_x(s) - 1; + } + } + + if (window_copy_update_selection(wp)) + window_copy_redraw_lines(wp, data->cy, 1); + else + window_copy_update_cursor(wp); +} + +void +window_copy_cursor_left(struct window_pane *wp) +{ + struct window_copy_mode_data *data = wp->modedata; + + if (data->cx == 0) { + if (data->ox > 0) + window_copy_scroll_right(wp, 1); + else { + window_copy_cursor_up(wp); + window_copy_cursor_end_of_line(wp); + } + } else { + data->cx--; + if (window_copy_update_selection(wp)) + window_copy_redraw_lines(wp, data->cy, 1); + else + window_copy_update_cursor(wp); + } +} + +void +window_copy_cursor_right(struct window_pane *wp) +{ + struct window_copy_mode_data *data = wp->modedata; + u_int px, py; + + py = screen_hsize(&wp->base) + data->cy - data->oy; + px = window_copy_find_length(wp, py); + + if (data->cx >= px) { + window_copy_cursor_start_of_line(wp); + window_copy_cursor_down(wp); + } else { + data->cx++; + if (window_copy_update_selection(wp)) + window_copy_redraw_lines(wp, data->cy, 1); + else + window_copy_update_cursor(wp); + } +} + +void +window_copy_cursor_up(struct window_pane *wp) +{ + struct window_copy_mode_data *data = wp->modedata; + u_int ox, oy, px, py; + + oy = screen_hsize(&wp->base) + data->cy - data->oy; + ox = window_copy_find_length(wp, oy); + + if (data->cy == 0) + window_copy_scroll_down(wp, 1); + else { + data->cy--; + if (window_copy_update_selection(wp)) + window_copy_redraw_lines(wp, data->cy, 2); + else + window_copy_update_cursor(wp); + } + + py = screen_hsize(&wp->base) + data->cy - data->oy; + px = window_copy_find_length(wp, py); + + if (data->cx + data->ox >= px || data->cx + data->ox >= ox) + window_copy_cursor_end_of_line(wp); +} + +void +window_copy_cursor_down(struct window_pane *wp) +{ + struct window_copy_mode_data *data = wp->modedata; + struct screen *s = &data->screen; + u_int ox, oy, px, py; + + oy = screen_hsize(&wp->base) + data->cy - data->oy; + ox = window_copy_find_length(wp, oy); + + if (data->cy == screen_size_y(s) - 1) + window_copy_scroll_up(wp, 1); + else { + data->cy++; + if (window_copy_update_selection(wp)) + window_copy_redraw_lines(wp, data->cy - 1, 2); + else + window_copy_update_cursor(wp); + } + + py = screen_hsize(&wp->base) + data->cy - data->oy; + px = window_copy_find_length(wp, py); + + if (data->cx + data->ox >= px || data->cx + data->ox >= ox) + window_copy_cursor_end_of_line(wp); +} + +void +window_copy_cursor_next_word(struct window_pane *wp) +{ + struct window_copy_mode_data *data = wp->modedata; + struct screen *s = &data->screen; + u_int px, py, xx, skip; + + px = data->ox + data->cx; + py = screen_hsize(&wp->base) + data->cy - data->oy; + xx = window_copy_find_length(wp, py); + + skip = 1; + if (px < xx) { + /* If currently on a space, skip space. */ + if (window_copy_is_space(wp, px, py)) + skip = 0; + } else + skip = 0; + for (;;) { + if (px >= xx) { + if (skip) { + px = xx; + break; + } + + while (px >= xx) { + if (data->cy == screen_size_y(s) - 1) { + if (data->oy == 0) + goto out; + } + + px = 0; + window_copy_cursor_down(wp); + + py =screen_hsize( + &wp->base) + data->cy - data->oy; + xx = window_copy_find_length(wp, py); + } + } + + if (skip) { + /* Currently skipping non-space (until space). */ + if (window_copy_is_space(wp, px, py)) + break; + } else { + /* Currently skipping space (until non-space). */ + if (!window_copy_is_space(wp, px, py)) + skip = 1; + } + + px++; + } +out: + + /* On screen. */ + if (px > data->ox && px <= data->ox + screen_size_x(s) - 1) + data->cx = px - data->ox; + + /* Off right of screen. */ + if (px > data->ox + screen_size_x(s) - 1) { + /* Move cursor to last and scroll screen. */ + window_copy_scroll_left( + wp, px - data->ox - (screen_size_x(s) - 1)); + data->cx = screen_size_x(s) - 1; + } + + /* Off left of screen. */ + if (px <= data->ox) { + if (px < screen_size_x(s) - 1) { + /* Short enough to fit on screen. */ + window_copy_scroll_right(wp, data->ox); + data->cx = px; + } else { + /* Too long to fit on screen. */ + window_copy_scroll_right( + wp, data->ox - (px - (screen_size_x(s) - 1))); + data->cx = screen_size_x(s) - 1; + } + } + + if (window_copy_update_selection(wp)) + window_copy_redraw_lines(wp, data->cy, 1); + else + window_copy_update_cursor(wp); +} + +void +window_copy_cursor_previous_word(struct window_pane *wp) +{ + struct window_copy_mode_data *data = wp->modedata; + struct screen *s = &data->screen; + u_int ox, px, py, skip; + + ox = px = data->ox + data->cx; + py = screen_hsize(&wp->base) + data->cy - data->oy; + + skip = 1; + if (px != 0) { + /* If currently on a space, skip space. */ + if (window_copy_is_space(wp, px - 1, py)) + skip = 0; + } + for (;;) { + if (px == 0) { + if (ox != 0) + break; + + while (px == 0) { + if (data->cy == 0 && + (screen_hsize(&wp->base) == 0 || + data->oy >= screen_hsize(&wp->base) - 1)) + goto out; + + window_copy_cursor_up(wp); + + py = screen_hsize( + &wp->base) + data->cy - data->oy; + px = window_copy_find_length(wp, py); + } + goto out; + } + + if (skip) { + /* Currently skipping non-space (until space). */ + if (window_copy_is_space(wp, px - 1, py)) + skip = 0; + } else { + /* Currently skipping space (until non-space). */ + if (!window_copy_is_space(wp, px - 1, py)) + break; + } + + px--; + } +out: + + /* On screen. */ + if (px > data->ox && px <= data->ox + screen_size_x(s) - 1) + data->cx = px - data->ox; + + /* Off right of screen. */ + if (px > data->ox + screen_size_x(s) - 1) { + /* Move cursor to last and scroll screen. */ + window_copy_scroll_left( + wp, px - data->ox - (screen_size_x(s) - 1)); + data->cx = screen_size_x(s) - 1; + } + + /* Off left of screen. */ + if (px <= data->ox) { + if (px < screen_size_x(s) - 1) { + /* Short enough to fit on screen. */ + window_copy_scroll_right(wp, data->ox); + data->cx = px; + } else { + /* Too long to fit on screen. */ + window_copy_scroll_right( + wp, data->ox - (px - (screen_size_x(s) - 1))); + data->cx = screen_size_x(s) - 1; + } + } + + if (window_copy_update_selection(wp)) + window_copy_redraw_lines(wp, data->cy, 1); + else + window_copy_update_cursor(wp); +} + +void +window_copy_scroll_left(struct window_pane *wp, u_int nx) +{ + struct window_copy_mode_data *data = wp->modedata; + struct screen *s = &data->screen; + struct screen_write_ctx ctx; + u_int i; + + if (data->ox > SHRT_MAX - nx) + nx = SHRT_MAX - data->ox; + if (nx == 0) + return; + data->ox += nx; + window_copy_update_selection(wp); + + screen_write_start(&ctx, wp, NULL); + for (i = 1; i < screen_size_y(s); i++) { + screen_write_cursormove(&ctx, 0, i); + screen_write_deletecharacter(&ctx, nx); + } + window_copy_write_columns(wp, &ctx, screen_size_x(s) - nx, nx); + window_copy_write_line(wp, &ctx, 0); + if (s->sel.flag) { + window_copy_update_selection(wp); + window_copy_write_lines(wp, &ctx, data->cy, 1); + } + screen_write_cursormove(&ctx, data->cx, data->cy); + screen_write_stop(&ctx); +} + +void +window_copy_scroll_right(struct window_pane *wp, u_int nx) +{ + struct window_copy_mode_data *data = wp->modedata; + struct screen *s = &data->screen; + struct screen_write_ctx ctx; + u_int i; + + if (data->ox < nx) + nx = data->ox; + if (nx == 0) + return; + data->ox -= nx; + window_copy_update_selection(wp); + + screen_write_start(&ctx, wp, NULL); + for (i = 1; i < screen_size_y(s); i++) { + screen_write_cursormove(&ctx, 0, i); + screen_write_insertcharacter(&ctx, nx); + } + window_copy_write_columns(wp, &ctx, 0, nx); + window_copy_write_line(wp, &ctx, 0); + if (s->sel.flag) + window_copy_write_line(wp, &ctx, data->cy); + screen_write_cursormove(&ctx, data->cx, data->cy); + screen_write_stop(&ctx); +} + +void +window_copy_scroll_up(struct window_pane *wp, u_int ny) +{ + struct window_copy_mode_data *data = wp->modedata; + struct screen *s = &data->screen; + struct screen_write_ctx ctx; + + if (data->oy < ny) + ny = data->oy; + if (ny == 0) + return; + data->oy -= ny; + window_copy_update_selection(wp); + + screen_write_start(&ctx, wp, NULL); + screen_write_cursormove(&ctx, 0, 0); + screen_write_deleteline(&ctx, ny); + window_copy_write_lines(wp, &ctx, screen_size_y(s) - ny, ny); + window_copy_write_line(wp, &ctx, 0); + window_copy_write_line(wp, &ctx, 1); + if (s->sel.flag && screen_size_y(s) > ny) + window_copy_write_line(wp, &ctx, screen_size_y(s) - ny - 1); + screen_write_cursormove(&ctx, data->cx, data->cy); + screen_write_stop(&ctx); +} + +void +window_copy_scroll_down(struct window_pane *wp, u_int ny) +{ + struct window_copy_mode_data *data = wp->modedata; + struct screen *s = &data->screen; + struct screen_write_ctx ctx; + + if (ny > screen_hsize(&wp->base)) + return; + + if (data->oy > screen_hsize(&wp->base) - ny) + ny = screen_hsize(&wp->base) - data->oy; + if (ny == 0) + return; + data->oy += ny; + window_copy_update_selection(wp); + + screen_write_start(&ctx, wp, NULL); + screen_write_cursormove(&ctx, 0, 0); + screen_write_insertline(&ctx, ny); + window_copy_write_lines(wp, &ctx, 0, ny); + if (s->sel.flag && screen_size_y(s) > ny) + window_copy_write_line(wp, &ctx, ny); + else if (ny == 1) /* nuke position */ + window_copy_write_line(wp, &ctx, 1); + screen_write_cursormove(&ctx, data->cx, data->cy); + screen_write_stop(&ctx); +} diff --git a/window-more.c b/window-more.c new file mode 100644 index 00000000..b09cc23c --- /dev/null +++ b/window-more.c @@ -0,0 +1,252 @@ +/* $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 + +#include "tmux.h" + +struct screen *window_more_init(struct window_pane *); +void window_more_free(struct window_pane *); +void window_more_resize(struct window_pane *, u_int, u_int); +void window_more_key(struct window_pane *, struct client *, int); + +void window_more_redraw_screen(struct window_pane *); +void window_more_write_line( + struct window_pane *, struct screen_write_ctx *, u_int); + +void window_more_scroll_up(struct window_pane *); +void window_more_scroll_down(struct window_pane *); + +const struct window_mode window_more_mode = { + window_more_init, + window_more_free, + window_more_resize, + window_more_key, + NULL, + NULL, +}; + +struct window_more_mode_data { + struct screen screen; + + struct mode_key_data mdata; + + ARRAY_DECL(, char *) list; + u_int top; +}; + +void +window_more_vadd(struct window_pane *wp, const char *fmt, va_list ap) +{ + struct window_more_mode_data *data = wp->modedata; + struct screen *s = &data->screen; + struct screen_write_ctx ctx; + char *msg; + u_int size; + + xvasprintf(&msg, fmt, ap); + ARRAY_ADD(&data->list, msg); + + screen_write_start(&ctx, wp, NULL); + size = ARRAY_LENGTH(&data->list) - 1; + if (size >= data->top && size <= data->top + screen_size_y(s) - 1) { + window_more_write_line(wp, &ctx, size - data->top); + if (size != data->top) + window_more_write_line(wp, &ctx, 0); + } else + window_more_write_line(wp, &ctx, 0); + screen_write_stop(&ctx); +} + +void printflike2 +window_more_add(struct window_pane *wp, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + window_more_vadd(wp, fmt, ap); + va_end(ap); +} + +struct screen * +window_more_init(struct window_pane *wp) +{ + struct window_more_mode_data *data; + struct screen *s; + + wp->modedata = data = xmalloc(sizeof *data); + ARRAY_INIT(&data->list); + data->top = 0; + + s = &data->screen; + screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0); + s->mode &= ~MODE_CURSOR; + + mode_key_init(&data->mdata, + options_get_number(&wp->window->options, "mode-keys"), 0); + + return (s); +} + +void +window_more_free(struct window_pane *wp) +{ + struct window_more_mode_data *data = wp->modedata; + u_int i; + + mode_key_free(&data->mdata); + + for (i = 0; i < ARRAY_LENGTH(&data->list); i++) + xfree(ARRAY_ITEM(&data->list, i)); + ARRAY_FREE(&data->list); + + screen_free(&data->screen); + xfree(data); +} + +void +window_more_resize(struct window_pane *wp, u_int sx, u_int sy) +{ + struct window_more_mode_data *data = wp->modedata; + struct screen *s = &data->screen; + + screen_resize(s, sx, sy); + window_more_redraw_screen(wp); +} + +void +window_more_key(struct window_pane *wp, unused struct client *c, int key) +{ + struct window_more_mode_data *data = wp->modedata; + struct screen *s = &data->screen; + + switch (mode_key_lookup(&data->mdata, key)) { + case MODEKEYCMD_QUIT: + window_pane_reset_mode(wp); + break; + case MODEKEYCMD_UP: + window_more_scroll_up(wp); + break; + case MODEKEYCMD_DOWN: + window_more_scroll_down(wp); + break; + case MODEKEYCMD_PREVIOUSPAGE: + if (data->top < screen_size_y(s)) + data->top = 0; + else + data->top -= screen_size_y(s); + window_more_redraw_screen(wp); + break; + case MODEKEYCMD_NEXTPAGE: + if (data->top + screen_size_y(s) > ARRAY_LENGTH(&data->list)) + data->top = ARRAY_LENGTH(&data->list); + else + data->top += screen_size_y(s); + window_more_redraw_screen(wp); + break; + default: + break; + } +} + +void +window_more_write_line( + struct window_pane *wp, struct screen_write_ctx *ctx, u_int py) +{ + struct window_more_mode_data *data = wp->modedata; + struct screen *s = &data->screen; + struct grid_cell gc; + char *msg, hdr[32]; + size_t size; + + memcpy(&gc, &grid_default_cell, sizeof gc); + + if (py == 0) { + size = xsnprintf(hdr, sizeof hdr, + "[%u/%u]", data->top, ARRAY_LENGTH(&data->list)); + screen_write_cursormove(ctx, screen_size_x(s) - size, 0); + gc.bg = options_get_number(&wp->window->options, "mode-fg"); + gc.fg = options_get_number(&wp->window->options, "mode-bg"); + gc.attr |= options_get_number(&wp->window->options, "mode-attr"); + screen_write_puts(ctx, &gc, "%s", hdr); + memcpy(&gc, &grid_default_cell, sizeof gc); + } else + size = 0; + + screen_write_cursormove(ctx, 0, py); + if (data->top + py < ARRAY_LENGTH(&data->list)) { + msg = ARRAY_ITEM(&data->list, data->top + py); + screen_write_puts( + ctx, &gc, "%.*s", (int) (screen_size_x(s) - size), msg); + } + while (s->cx < screen_size_x(s) - size) + screen_write_putc(ctx, &gc, ' '); +} + +void +window_more_redraw_screen(struct window_pane *wp) +{ + struct window_more_mode_data *data = wp->modedata; + struct screen *s = &data->screen; + struct screen_write_ctx ctx; + u_int i; + + screen_write_start(&ctx, wp, NULL); + for (i = 0; i < screen_size_y(s); i++) + window_more_write_line(wp, &ctx, i); + screen_write_stop(&ctx); +} + +void +window_more_scroll_up(struct window_pane *wp) +{ + struct window_more_mode_data *data = wp->modedata; + struct screen_write_ctx ctx; + + if (data->top == 0) + return; + data->top--; + + screen_write_start(&ctx, wp, NULL); + screen_write_cursormove(&ctx, 0, 0); + screen_write_insertline(&ctx, 1); + window_more_write_line(wp, &ctx, 0); + window_more_write_line(wp, &ctx, 1); + screen_write_stop(&ctx); +} + +void +window_more_scroll_down(struct window_pane *wp) +{ + struct window_more_mode_data *data = wp->modedata; + struct screen *s = &data->screen; + struct screen_write_ctx ctx; + + if (data->top >= ARRAY_LENGTH(&data->list)) + return; + data->top++; + + screen_write_start(&ctx, wp, NULL); + screen_write_cursormove(&ctx, 0, 0); + screen_write_deleteline(&ctx, 1); + window_more_write_line(wp, &ctx, screen_size_y(s) - 1); + window_more_write_line(wp, &ctx, 0); + screen_write_stop(&ctx); +} diff --git a/window-scroll.c b/window-scroll.c new file mode 100644 index 00000000..9db91ebd --- /dev/null +++ b/window-scroll.c @@ -0,0 +1,296 @@ +/* $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 + +#include "tmux.h" + +struct screen *window_scroll_init(struct window_pane *); +void window_scroll_free(struct window_pane *); +void window_scroll_resize(struct window_pane *, u_int, u_int); +void window_scroll_key(struct window_pane *, struct client *, int); + +void window_scroll_redraw_screen(struct window_pane *); +void window_scroll_write_line( + struct window_pane *, struct screen_write_ctx *, u_int); +void window_scroll_write_column( + struct window_pane *, struct screen_write_ctx *, u_int); + +void window_scroll_scroll_up(struct window_pane *); +void window_scroll_scroll_down(struct window_pane *); +void window_scroll_scroll_left(struct window_pane *); +void window_scroll_scroll_right(struct window_pane *); + +const struct window_mode window_scroll_mode = { + window_scroll_init, + window_scroll_free, + window_scroll_resize, + window_scroll_key, + NULL, + NULL, +}; + +struct window_scroll_mode_data { + struct screen screen; + + struct mode_key_data mdata; + + u_int ox; + u_int oy; +}; + +struct screen * +window_scroll_init(struct window_pane *wp) +{ + struct window_scroll_mode_data *data; + struct screen *s; + struct screen_write_ctx ctx; + u_int i; + + wp->modedata = data = xmalloc(sizeof *data); + data->ox = 0; + data->oy = 0; + + s = &data->screen; + screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0); + s->mode &= ~MODE_CURSOR; + + mode_key_init(&data->mdata, + options_get_number(&wp->window->options, "mode-keys"), 0); + + screen_write_start(&ctx, NULL, s); + for (i = 0; i < screen_size_y(s); i++) + window_scroll_write_line(wp, &ctx, i); + screen_write_stop(&ctx); + + return (s); +} + +void +window_scroll_free(struct window_pane *wp) +{ + struct window_scroll_mode_data *data = wp->modedata; + + mode_key_free(&data->mdata); + + screen_free(&data->screen); + xfree(data); +} + +void +window_scroll_pageup(struct window_pane *wp) +{ + struct window_scroll_mode_data *data = wp->modedata; + struct screen *s = &data->screen; + + if (data->oy + screen_size_y(s) > screen_hsize(&wp->base)) + data->oy = screen_hsize(&wp->base); + else + data->oy += screen_size_y(s); + + window_scroll_redraw_screen(wp); +} + +void +window_scroll_resize(struct window_pane *wp, u_int sx, u_int sy) +{ + struct window_scroll_mode_data *data = wp->modedata; + struct screen *s = &data->screen; + struct screen_write_ctx ctx; + u_int i; + + screen_resize(s, sx, sy); + screen_write_start(&ctx, NULL, s); + for (i = 0; i < screen_size_y(s); i++) + window_scroll_write_line(wp, &ctx, i); + screen_write_stop(&ctx); +} + +void +window_scroll_key(struct window_pane *wp, unused struct client *c, int key) +{ + struct window_scroll_mode_data *data = wp->modedata; + struct screen *s = &data->screen; + + switch (mode_key_lookup(&data->mdata, key)) { + case MODEKEYCMD_QUIT: + window_pane_reset_mode(wp); + break; + case MODEKEYCMD_LEFT: + window_scroll_scroll_left(wp); + break; + case MODEKEYCMD_RIGHT: + window_scroll_scroll_right(wp); + break; + case MODEKEYCMD_UP: + window_scroll_scroll_up(wp); + break; + case MODEKEYCMD_DOWN: + window_scroll_scroll_down(wp); + break; + case MODEKEYCMD_PREVIOUSPAGE: + window_scroll_pageup(wp); + break; + case MODEKEYCMD_NEXTPAGE: + if (data->oy < screen_size_y(s)) + data->oy = 0; + else + data->oy -= screen_size_y(s); + window_scroll_redraw_screen(wp); + break; + default: + break; + } +} + +void +window_scroll_write_line( + struct window_pane *wp, struct screen_write_ctx *ctx, u_int py) +{ + struct window_scroll_mode_data *data = wp->modedata; + struct screen *s = &data->screen; + struct grid_cell gc; + char hdr[32]; + size_t size; + + if (py == 0) { + memcpy(&gc, &grid_default_cell, sizeof gc); + size = xsnprintf(hdr, sizeof hdr, + "[%u,%u/%u]", data->ox, data->oy, screen_hsize(&wp->base)); + gc.bg = options_get_number(&wp->window->options, "mode-fg"); + gc.fg = options_get_number(&wp->window->options, "mode-bg"); + gc.attr |= options_get_number(&wp->window->options, "mode-attr"); + screen_write_cursormove(ctx, screen_size_x(s) - size, 0); + screen_write_puts(ctx, &gc, "%s", hdr); + memcpy(&gc, &grid_default_cell, sizeof gc); + } else + size = 0; + + screen_write_cursormove(ctx, 0, py); + screen_write_copy(ctx, &wp->base, data->ox, (screen_hsize(&wp->base) - + data->oy) + py, screen_size_x(s) - size, 1); +} + +void +window_scroll_write_column( + struct window_pane *wp, struct screen_write_ctx *ctx, u_int px) +{ + struct window_scroll_mode_data *data = wp->modedata; + struct screen *s = &data->screen; + + screen_write_cursormove(ctx, px, 0); + screen_write_copy(ctx, &wp->base, data->ox + px, + screen_hsize(&wp->base) - data->oy, 1, screen_size_y(s)); +} + +void +window_scroll_redraw_screen(struct window_pane *wp) +{ + struct window_scroll_mode_data *data = wp->modedata; + struct screen *s = &data->screen; + struct screen_write_ctx ctx; + u_int i; + + screen_write_start(&ctx, wp, NULL); + for (i = 0; i < screen_size_y(s); i++) + window_scroll_write_line(wp, &ctx, i); + screen_write_stop(&ctx); +} + +void +window_scroll_scroll_up(struct window_pane *wp) +{ + struct window_scroll_mode_data *data = wp->modedata; + struct screen_write_ctx ctx; + + if (data->oy >= screen_hsize(&wp->base)) + return; + data->oy++; + + screen_write_start(&ctx, wp, NULL); + screen_write_cursormove(&ctx, 0, 0); + screen_write_insertline(&ctx, 1); + window_scroll_write_line(wp, &ctx, 0); + window_scroll_write_line(wp, &ctx, 1); + screen_write_stop(&ctx); +} + +void +window_scroll_scroll_down(struct window_pane *wp) +{ + struct window_scroll_mode_data *data = wp->modedata; + struct screen *s = &data->screen; + struct screen_write_ctx ctx; + + if (data->oy == 0) + return; + data->oy--; + + screen_write_start(&ctx, wp, NULL); + screen_write_cursormove(&ctx, 0, 0); + screen_write_deleteline(&ctx, 1); + window_scroll_write_line(wp, &ctx, screen_size_y(s) - 1); + window_scroll_write_line(wp, &ctx, 0); + screen_write_stop(&ctx); +} + +void +window_scroll_scroll_right(struct window_pane *wp) +{ + struct window_scroll_mode_data *data = wp->modedata; + struct screen *s = &data->screen; + struct screen_write_ctx ctx; + u_int i; + + if (data->ox >= SHRT_MAX) + return; + data->ox++; + + screen_write_start(&ctx, wp, NULL); + for (i = 1; i < screen_size_y(s); i++) { + screen_write_cursormove(&ctx, 0, i); + screen_write_deletecharacter(&ctx, 1); + } + window_scroll_write_column(wp, &ctx, screen_size_x(s) - 1); + window_scroll_write_line(wp, &ctx, 0); + screen_write_stop(&ctx); +} + +void +window_scroll_scroll_left(struct window_pane *wp) +{ + struct window_scroll_mode_data *data = wp->modedata; + struct screen *s = &data->screen; + struct screen_write_ctx ctx; + u_int i; + + if (data->ox == 0) + return; + data->ox--; + + screen_write_start(&ctx, wp, NULL); + for (i = 1; i < screen_size_y(s); i++) { + screen_write_cursormove(&ctx, 0, i); + screen_write_insertcharacter(&ctx, 1); + } + window_scroll_write_column(wp, &ctx, 0); + window_scroll_write_line(wp, &ctx, 0); + screen_write_stop(&ctx); +} diff --git a/window.c b/window.c new file mode 100644 index 00000000..06733201 --- /dev/null +++ b/window.c @@ -0,0 +1,625 @@ +/* $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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tmux.h" + +/* + * Each window is attached to one or two panes, each of which is a pty. This + * file contains code to handle them. + * + * A pane has two buffers attached, these are filled and emptied by the main + * server poll loop. Output data is received from pty's in screen format, + * translated and returned as a series of escape sequences and strings via + * input_parse (in input.c). Input data is received as key codes and written + * directly via input_key. + * + * Each pane also has a "virtual" screen (screen.c) which contains the current + * state and is redisplayed when the window is reattached to a client. + * + * Windows are stored directly on a global array and wrapped in any number of + * winlink structs to be linked onto local session RB trees. A reference count + * is maintained and a window removed from the global list and destroyed when + * it reaches zero. + */ + +/* Global window list. */ +struct windows windows; + +RB_GENERATE(winlinks, winlink, entry, winlink_cmp); + +int +winlink_cmp(struct winlink *wl1, struct winlink *wl2) +{ + return (wl1->idx - wl2->idx); +} + +struct winlink * +winlink_find_by_index(struct winlinks *wwl, int idx) +{ + struct winlink wl; + + if (idx < 0) + fatalx("bad index"); + + wl.idx = idx; + return (RB_FIND(winlinks, wwl, &wl)); +} + +int +winlink_next_index(struct winlinks *wwl) +{ + u_int i; + + for (i = 0; i < INT_MAX; i++) { + if (winlink_find_by_index(wwl, i) == NULL) + return (i); + } + + fatalx("no free indexes"); +} + +u_int +winlink_count(struct winlinks *wwl) +{ + struct winlink *wl; + u_int n; + + n = 0; + RB_FOREACH(wl, winlinks, wwl) + n++; + + return (n); +} + +struct winlink * +winlink_add(struct winlinks *wwl, struct window *w, int idx) +{ + struct winlink *wl; + + if (idx == -1) + idx = winlink_next_index(wwl); + else if (winlink_find_by_index(wwl, idx) != NULL) + return (NULL); + + if (idx < 0) + fatalx("bad index"); + + wl = xcalloc(1, sizeof *wl); + wl->idx = idx; + wl->window = w; + RB_INSERT(winlinks, wwl, wl); + + w->references++; + + return (wl); +} + +void +winlink_remove(struct winlinks *wwl, struct winlink *wl) +{ + struct window *w = wl->window; + + RB_REMOVE(winlinks, wwl, wl); + xfree(wl); + + if (w->references == 0) + fatal("bad reference count"); + w->references--; + if (w->references == 0) + window_destroy(w); +} + +struct winlink * +winlink_next(unused struct winlinks *wwl, struct winlink *wl) +{ + return (RB_NEXT(winlinks, wwl, wl)); +} + +struct winlink * +winlink_previous(unused struct winlinks *wwl, struct winlink *wl) +{ + return (RB_PREV(winlinks, wwl, wl)); +} + +void +winlink_stack_push(struct winlink_stack *stack, struct winlink *wl) +{ + if (wl == NULL) + return; + + winlink_stack_remove(stack, wl); + SLIST_INSERT_HEAD(stack, wl, sentry); +} + +void +winlink_stack_remove(struct winlink_stack *stack, struct winlink *wl) +{ + struct winlink *wl2; + + if (wl == NULL) + return; + + SLIST_FOREACH(wl2, stack, sentry) { + if (wl2 == wl) { + SLIST_REMOVE(stack, wl, winlink, sentry); + return; + } + } +} + +int +window_index(struct window *s, u_int *i) +{ + for (*i = 0; *i < ARRAY_LENGTH(&windows); (*i)++) { + if (s == ARRAY_ITEM(&windows, *i)) + return (0); + } + return (-1); +} + +struct window * +window_create1(u_int sx, u_int sy) +{ + struct window *w; + u_int i; + + w = xmalloc(sizeof *w); + w->name = NULL; + w->flags = 0; + + TAILQ_INIT(&w->panes); + w->active = NULL; + w->layout = 0; + + w->sx = sx; + w->sy = sy; + + options_init(&w->options, &global_window_options); + + for (i = 0; i < ARRAY_LENGTH(&windows); i++) { + if (ARRAY_ITEM(&windows, i) == NULL) { + ARRAY_SET(&windows, i, w); + break; + } + } + if (i == ARRAY_LENGTH(&windows)) + ARRAY_ADD(&windows, w); + w->references = 0; + + return (w); +} + +struct window * +window_create(const char *name, const char *cmd, const char *cwd, + const char **envp, u_int sx, u_int sy, u_int hlimit, char **cause) +{ + struct window *w; + + w = window_create1(sx, sy); + if (window_add_pane(w, -1, cmd, cwd, envp, hlimit, cause) == NULL) { + window_destroy(w); + return (NULL); + } + w->active = TAILQ_FIRST(&w->panes); + + if (name != NULL) { + w->name = xstrdup(name); + options_set_number(&w->options, "automatic-rename", 0); + } else + w->name = default_window_name(w); + return (w); +} + +void +window_destroy(struct window *w) +{ + u_int i; + + if (window_index(w, &i) != 0) + fatalx("index not found"); + ARRAY_SET(&windows, i, NULL); + while (!ARRAY_EMPTY(&windows) && ARRAY_LAST(&windows) == NULL) + ARRAY_TRUNC(&windows, 1); + + options_free(&w->options); + + window_destroy_panes(w); + + if (w->name != NULL) + xfree(w->name); + xfree(w); +} + +int +window_resize(struct window *w, u_int sx, u_int sy) +{ + w->sx = sx; + w->sy = sy; + + return (0); +} + +void +window_set_active_pane(struct window *w, struct window_pane *wp) +{ + w->active = wp; + while (w->active->flags & PANE_HIDDEN) + w->active = TAILQ_PREV(w->active, window_panes, entry); +} + +struct window_pane * +window_add_pane(struct window *w, int wanty, const char *cmd, + const char *cwd, const char **envp, u_int hlimit, char **cause) +{ + struct window_pane *wp; + u_int sizey; + + if (TAILQ_EMPTY(&w->panes)) + wanty = w->sy; + else { + sizey = w->active->sy - 1; /* for separator */ + if (sizey < PANE_MINIMUM * 2) { + *cause = xstrdup("pane too small"); + return (NULL); + } + + if (wanty == -1) + wanty = sizey / 2; + + if (wanty < PANE_MINIMUM) + wanty = PANE_MINIMUM; + if ((u_int) wanty > sizey - PANE_MINIMUM) + wanty = sizey - PANE_MINIMUM; + + window_pane_resize(w->active, w->sx, sizey - wanty); + } + + wp = window_pane_create(w, w->sx, wanty, hlimit); + if (TAILQ_EMPTY(&w->panes)) + TAILQ_INSERT_HEAD(&w->panes, wp, entry); + else + TAILQ_INSERT_AFTER(&w->panes, w->active, wp, entry); + if (window_pane_spawn(wp, cmd, cwd, envp, cause) != 0) { + window_remove_pane(w, wp); + return (NULL); + } + return (wp); +} + +void +window_remove_pane(struct window *w, struct window_pane *wp) +{ + w->active = TAILQ_PREV(wp, window_panes, entry); + if (w->active == NULL) + w->active = TAILQ_NEXT(wp, entry); + + TAILQ_REMOVE(&w->panes, wp, entry); + window_pane_destroy(wp); +} + +u_int +window_index_of_pane(struct window *w, struct window_pane *find) +{ + struct window_pane *wp; + u_int n; + + n = 0; + TAILQ_FOREACH(wp, &w->panes, entry) { + if (wp == find) + return (n); + n++; + } + fatalx("unknown pane"); +} + +struct window_pane * +window_pane_at_index(struct window *w, u_int idx) +{ + struct window_pane *wp; + u_int n; + + n = 0; + TAILQ_FOREACH(wp, &w->panes, entry) { + if (n == idx) + return (wp); + n++; + } + return (NULL); +} + +u_int +window_count_panes(struct window *w) +{ + struct window_pane *wp; + u_int n; + + n = 0; + TAILQ_FOREACH(wp, &w->panes, entry) + n++; + return (n); +} + +void +window_destroy_panes(struct window *w) +{ + struct window_pane *wp; + + while (!TAILQ_EMPTY(&w->panes)) { + wp = TAILQ_FIRST(&w->panes); + TAILQ_REMOVE(&w->panes, wp, entry); + window_pane_destroy(wp); + } +} + +struct window_pane * +window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit) +{ + struct window_pane *wp; + + wp = xcalloc(1, sizeof *wp); + wp->window = w; + + wp->cmd = NULL; + wp->cwd = NULL; + + wp->fd = -1; + wp->in = buffer_create(BUFSIZ); + wp->out = buffer_create(BUFSIZ); + + wp->mode = NULL; + + wp->xoff = 0; + wp->yoff = 0; + + wp->sx = sx; + wp->sy = sy; + + screen_init(&wp->base, sx, sy, hlimit); + wp->screen = &wp->base; + + input_init(wp); + + return (wp); +} + +void +window_pane_destroy(struct window_pane *wp) +{ + if (wp->fd != -1) + close(wp->fd); + + input_free(wp); + + window_pane_reset_mode(wp); + screen_free(&wp->base); + + buffer_destroy(wp->in); + buffer_destroy(wp->out); + + if (wp->cwd != NULL) + xfree(wp->cwd); + if (wp->cmd != NULL) + xfree(wp->cmd); + xfree(wp); +} + +int +window_pane_spawn(struct window_pane *wp, + const char *cmd, const char *cwd, const char **envp, char **cause) +{ + struct winsize ws; + int mode; + const char **envq; + struct timeval tv; + + if (wp->fd != -1) + close(wp->fd); + if (cmd != NULL) { + if (wp->cmd != NULL) + xfree(wp->cmd); + wp->cmd = xstrdup(cmd); + } + if (cwd != NULL) { + if (wp->cwd != NULL) + xfree(wp->cwd); + wp->cwd = xstrdup(cwd); + } + + memset(&ws, 0, sizeof ws); + ws.ws_col = screen_size_x(&wp->base); + ws.ws_row = screen_size_y(&wp->base); + + if (gettimeofday(&wp->window->name_timer, NULL) != 0) + fatal("gettimeofday"); + tv.tv_sec = 0; + tv.tv_usec = NAME_INTERVAL * 1000L; + timeradd(&wp->window->name_timer, &tv, &wp->window->name_timer); + + switch (wp->pid = forkpty(&wp->fd, wp->tty, NULL, &ws)) { + case -1: + wp->fd = -1; + xasprintf(cause, "%s: %s", cmd, strerror(errno)); + return (-1); + case 0: + if (chdir(wp->cwd) != 0) + chdir("/"); + for (envq = envp; *envq != NULL; envq++) { + if (putenv((char *) *envq) != 0) + fatal("putenv failed"); + } + sigreset(); + log_close(); + + execl(_PATH_BSHELL, "sh", "-c", wp->cmd, (char *) NULL); + fatal("execl failed"); + } + + if ((mode = fcntl(wp->fd, F_GETFL)) == -1) + fatal("fcntl failed"); + if (fcntl(wp->fd, F_SETFL, mode|O_NONBLOCK) == -1) + fatal("fcntl failed"); + if (fcntl(wp->fd, F_SETFD, FD_CLOEXEC) == -1) + fatal("fcntl failed"); + + return (0); +} + +int +window_pane_resize(struct window_pane *wp, u_int sx, u_int sy) +{ + struct winsize ws; + + if (sx == wp->sx && sy == wp->sy) + return (-1); + wp->sx = sx; + wp->sy = sy; + + memset(&ws, 0, sizeof ws); + ws.ws_col = sx; + ws.ws_row = sy; + + screen_resize(&wp->base, sx, sy); + if (wp->mode != NULL) + wp->mode->resize(wp, sx, sy); + + if (wp->fd != -1 && ioctl(wp->fd, TIOCSWINSZ, &ws) == -1) + fatal("ioctl failed"); + return (0); +} + +int +window_pane_set_mode(struct window_pane *wp, const struct window_mode *mode) +{ + struct screen *s; + + if (wp->mode != NULL || wp->mode == mode) + return (1); + + wp->mode = mode; + + if ((s = wp->mode->init(wp)) != NULL) + wp->screen = s; + server_redraw_window(wp->window); + return (0); +} + +void +window_pane_reset_mode(struct window_pane *wp) +{ + if (wp->mode == NULL) + return; + + wp->mode->free(wp); + wp->mode = NULL; + + wp->screen = &wp->base; + server_redraw_window(wp->window); +} + +void +window_pane_parse(struct window_pane *wp) +{ + input_parse(wp); +} + +void +window_pane_key(struct window_pane *wp, struct client *c, int key) +{ + if (wp->mode != NULL) { + if (wp->mode->key != NULL) + wp->mode->key(wp, c, key); + } else + input_key(wp, key); +} + +void +window_pane_mouse( + struct window_pane *wp, struct client *c, u_char b, u_char x, u_char y) +{ + /* XXX convert from 1-based? */ + + if (x < wp->xoff || x >= wp->xoff + wp->sx) + return; + if (y < wp->yoff || y >= wp->yoff + wp->sy) + return; + x -= wp->xoff; + y -= wp->yoff; + + if (wp->mode != NULL) { + if (wp->mode->mouse != NULL) + wp->mode->mouse(wp, c, b, x, y); + } else + input_mouse(wp, b, x, y); +} + +char * +window_pane_search(struct window_pane *wp, const char *searchstr) +{ + const struct grid_cell *gc; + const struct grid_utf8 *gu; + char *buf, *s; + size_t off; + u_int i, j, k; + + buf = xmalloc(1); + + for (j = 0; j < screen_size_y(&wp->base); j++) { + off = 0; + for (i = 0; i < screen_size_x(&wp->base); i++) { + gc = grid_view_peek_cell(wp->base.grid, i, j); + if (gc->flags & GRID_FLAG_UTF8) { + gu = grid_view_peek_utf8(wp->base.grid, i, j); + buf = xrealloc(buf, 1, off + 8); + for (k = 0; k < UTF8_SIZE; k++) { + if (gu->data[k] == 0xff) + break; + buf[off++] = gu->data[k]; + } + } else { + buf = xrealloc(buf, 1, off + 1); + buf[off++] = gc->data; + } + } + while (off > 0 && buf[off - 1] == ' ') + off--; + buf[off] = '\0'; + + if ((s = strstr(buf, searchstr)) != NULL) { + s = section_string(buf, off, s - buf, 40); + xfree(buf); + return (s); + } + } + + xfree(buf); + return (NULL); +} diff --git a/xmalloc.c b/xmalloc.c new file mode 100644 index 00000000..6bf63bef --- /dev/null +++ b/xmalloc.c @@ -0,0 +1,144 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2004 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 "tmux.h" + +char * +xstrdup(const char *s) +{ + void *ptr; + size_t len; + + len = strlen(s) + 1; + ptr = xmalloc(len); + + return (strncpy(ptr, s, len)); +} + +void * +xcalloc(size_t nmemb, size_t size) +{ + void *ptr; + + if (size == 0 || nmemb == 0) + fatalx("zero size"); + if (SIZE_MAX / nmemb < size) + fatalx("nmemb * size > SIZE_MAX"); + if ((ptr = calloc(nmemb, size)) == NULL) + fatal("xcalloc failed"); + + return (ptr); +} + +void * +xmalloc(size_t size) +{ + void *ptr; + + if (size == 0) + fatalx("zero size"); + if ((ptr = malloc(size)) == NULL) + fatal("xmalloc failed"); + + return (ptr); +} + +void * +xrealloc(void *oldptr, size_t nmemb, size_t size) +{ + size_t newsize = nmemb * size; + void *newptr; + + if (newsize == 0) + fatalx("zero size"); + if (SIZE_MAX / nmemb < size) + fatalx("nmemb * size > SIZE_MAX"); + if ((newptr = realloc(oldptr, newsize)) == NULL) + fatal("xrealloc failed"); + + return (newptr); +} + +void +xfree(void *ptr) +{ + if (ptr == NULL) + fatalx("null pointer"); + free(ptr); +} + +int printflike2 +xasprintf(char **ret, const char *fmt, ...) +{ + va_list ap; + int i; + + va_start(ap, fmt); + i = xvasprintf(ret, fmt, ap); + va_end(ap); + + return (i); +} + +int +xvasprintf(char **ret, const char *fmt, va_list ap) +{ + int i; + + i = vasprintf(ret, fmt, ap); + if (i < 0 || *ret == NULL) + fatal("xvasprintf failed"); + + return (i); +} + +int printflike3 +xsnprintf(char *buf, size_t len, const char *fmt, ...) +{ + va_list ap; + int i; + + va_start(ap, fmt); + i = xvsnprintf(buf, len, fmt, ap); + va_end(ap); + + return (i); +} + +int +xvsnprintf(char *buf, size_t len, const char *fmt, va_list ap) +{ + int i; + + if (len > INT_MAX) + fatalx("len > INT_MAX"); + + i = vsnprintf(buf, len, fmt, ap); + if (i < 0) + fatal("vsnprintf failed"); + + return (i); +} From 6e3f673ef7cebcb29cad6b609b5db0e3d5aa31b9 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 1 Jun 2009 23:00:54 +0000 Subject: [PATCH 0002/1180] Whoops, didn't mean to add this. --- tmux.cat1 | 813 ------------------------------------------------------ 1 file changed, 813 deletions(-) delete mode 100644 tmux.cat1 diff --git a/tmux.cat1 b/tmux.cat1 deleted file mode 100644 index fe815603..00000000 --- a/tmux.cat1 +++ /dev/null @@ -1,813 +0,0 @@ -TMUX(1) OpenBSD Reference Manual TMUX(1) - -NNAAMMEE - ttmmuuxx - terminal multiplexer - -SSYYNNOOPPSSIISS - ttmmuuxx [--2288ddqqUUuuvv] [--ff _f_i_l_e] [--LL _s_o_c_k_e_t_-_n_a_m_e] [--SS _s_o_c_k_e_t_-_p_a_t_h] - [_c_o_m_m_a_n_d [_f_l_a_g_s]] - -DDEESSCCRRIIPPTTIIOONN - ttmmuuxx is a terminal multiplexer; it enables a number of terminals to be - accessed and controlled from a single terminal. - - ttmmuuxx runs as a server-client system. A server is created automatically - when necessary and holds a number of _s_e_s_s_i_o_n_s, each of which may have a - number of _w_i_n_d_o_w_s linked to it. A window may be split on screen into one - or more _p_a_n_e_s, each of which is a separate terminal. Any number of - _c_l_i_e_n_t_s may connect to a session, or the server may be controlled by is- - suing commands with ttmmuuxx. Communication takes place through a socket, by - default placed in _/_t_m_p. - - The options are as follows: - - --22 Force ttmmuuxx to assume the terminal supports 256 colours. - - --88 Like --22, indicates the terminal supports 88 colours. - - --dd Force ttmmuuxx to assume the terminal supports default colours. - - --ff _f_i_l_e Specify an alternative configuration file. By default, - ttmmuuxx will look for a config file at _~_/_._t_m_u_x_._c_o_n_f. The con- - figuration file is a set of ttmmuuxx commands which are execut- - ed in sequence when the server is first started. - - --qq Prevent the server sending various information messages, - for example when window flags are altered. - - --LL _s_o_c_k_e_t_-_n_a_m_e - ttmmuuxx stores the server socket in a directory under _/_t_m_p; - the default socket is named _d_e_f_a_u_l_t. This option allows a - different socket name to be specified, allowing several in- - dependent ttmmuuxx servers to be run. Unlike --SS a full path is - not necessary: the sockets are all created in the same di- - rectory. - - --SS _s_o_c_k_e_t_-_p_a_t_h - Specify a full alternative path to the server socket. If - --SS is specified, the default socket directory is not used - and any --LL flag is ignored. - - --UU Unlock the server. - - --uu Instruct ttmmuuxx that the terminal support UTF-8. - - --vv Request verbose logging. This option may be specified mul- - tiple times for increasing verbosity. Log messages will be - saved into _t_m_u_x_-_c_l_i_e_n_t_-_P_I_D_._l_o_g and _t_m_u_x_-_s_e_r_v_e_r_-_P_I_D_._l_o_g - files in the current directory, where _P_I_D is the pid of the - server or client process. - - _c_o_m_m_a_n_d [_f_l_a_g_s] - This specifies one of a set of commands used to control - ttmmuuxx, and described in the following sections. If no com- - mand and flags is specified, the nneeww--sseessssiioonn command is as- - sumed. - -QQUUIICCKK SSTTAARRTT - To create a new tmux session running vi(1): - - $ tmux new-session vi - - Most commands have a shorter form, known as an alias. For new-session, - this is nneeww: - - $ tmux new vi - - Alternatively, the shortest unambiguous form of a command is accepted. - If there are several options, they are listed: - - $ tmux n - ambiguous command: n, could be: new-session, new-window, next-window - $ - - Within an active session, a new window may be created by typing `C-b' - (ctrl-b, known as the prefix key) followed by the `c' key. - - Windows may be navigated with: `C-b 0' (to select window 0), `C-b 1' (to - select window 1), and so on; `C-b n' to select the next window; and `C-b - p' to select the previous window. - - A session may be detached using `C-b d' and reattached with: - - $ tmux attach-session - - Typing `C-b ?' lists the current key bindings in the current window; up - and down may be used to navigate the list or `Q' to exit from it. - -KKEEYY BBIINNDDIINNGGSS - ttmmuuxx may be controlled from an attached client by using a key combination - of a prefix key, `C-b' (ctrl-b) by default, followed by a command key. - - Some of the default key bindings include: - - `d' Detach current client. - `c' Create new window. - `n' Change to next window in the current session. - `p' Change to previous window in the current session. - `l' Move to last (previously selected) window in the current session. - `t' Display a large clock. - `?' List current key bindings. - - A complete list may be obtained with the lliisstt--kkeeyyss command (bound to `?' - by default). Key bindings may be changed with the bbiinndd--kkeeyy and uunnbbiinndd-- - kkeeyy commands. - -HHIISSTTOORRYY - ttmmuuxx maintains a configurable history buffer for each window. By de- - fault, up to 2000 lines are kept, this can be altered with the hhiissttoorryy-- - lliimmiitt option (see the sseett--ooppttiioonn command below). - -MMOODDEESS - A ttmmuuxx window may be in one of several modes. The default permits direct - access to the terminal attached to the window. The others are: - - _o_u_t_p_u_t _m_o_d_e - This is entered when a command which produces output, such as - lliisstt--kkeeyyss, is executed from a key binding. - - _s_c_r_o_l_l _m_o_d_e - This is entered with the ssccrroollll--mmooddee command (bound to `=' by de- - fault) and permits the window history buffer to be inspected. - - _c_o_p_y _m_o_d_e - This permits a section of a window or its history to be copied to - a _p_a_s_t_e _b_u_f_f_e_r for later insertion into another window. This - mode is entered with the ccooppyy--mmooddee command, bound to `[' by de- - fault. - - The keys available depend on whether emacs(1) or vi(1) mode is selected - (see the mmooddee--kkeeyyss option). The following keys are supported as appro- - priate for the mode: - - FFuunnccttiioonn vvii eemmaaccss - Start of line 0 or ^ C-a - Clear selection Escape C-g - Copy selection Enter M-w - Cursor down j Down - End of line $ C-e - Cursor left h Left - Next page C-f Page down - Next word w M-f - Previous page C-u Page up - Previous word b M-b - Quit mode q Escape - Cursor right l Right - Start selection Space C-Space - Cursor up k Up - -BBUUFFFFEERRSS - ttmmuuxx maintains a stack of _p_a_s_t_e _b_u_f_f_e_r_s for each session. Up to the val- - ue of the bbuuffffeerr--lliimmiitt option are kept; when a new buffer is added, the - buffer at the bottom of the stack is removed. Buffers may be added using - ccooppyy--mmooddee or the sseett--bbuuffffeerr command, and pasted into a window using the - ppaassttee--bbuuffffeerr command. - -PPAANNEESS AANNDD LLAAYYOOUUTTSS - Each window displayed by ttmmuuxx may be split into one or more _p_a_n_e_s; each - pane takes up a certain area of the display and is a separate terminal. - A window may be split into panes using the sspplliitt--wwiinnddooww command. - - Panes are numbered beginning from zero; in horizontal layouts zero is the - leftmost pane and in vertical the topmost. - - Panes may be arranged using several layouts. The layout may be cycled - with the nneexxtt--llaayyoouutt command (bound to `C-space' by default), the current - pane may be changed with the uupp--ppaannee and ddoowwnn--ppaannee commands and the - rroottaattee--wwiinnddooww and sswwaapp--ppaannee commands may be used to swap panes without - changing the window layout. - - The following layouts are supported: - - mmaannuuaall Manual layout splits windows vertically (running across); only - with this layout may panes be resized using the rreessiizzee--ppaannee com- - mand. - - aaccttiivvee--oonnllyy - Only the active pane is shown - all other panes are hidden. - - eevveenn--hhoorriizzoonnttaall - Panes are spread out evenly from left to right across the window. - - eevveenn--vveerrttiiccaall - Panes are spread evenly from top to bottom. - - mmaaiinn--vveerrttiiccaall - A large (81 column) pane is shown on the left of the window and - the remaining panes are spread from top to bottom in the leftover - space to the right. - -CCOOMMMMAANNDDSS - This section contains a list of the commands supported by ttmmuuxx. Most - commands accept the optional --tt argument with one of _t_a_r_g_e_t_-_c_l_i_e_n_t, - _t_a_r_g_e_t_-_s_e_s_s_i_o_n or _t_a_r_g_e_t_-_w_i_n_d_o_w. These specify the client, session or - window which a command should affect. _t_a_r_g_e_t_-_c_l_i_e_n_t is the name of the - pty(4) file to which the client is connected, for example _/_d_e_v_/_t_t_y_p_1. - Clients may be listed with the lliisstt--cclliieennttss command. - - _t_a_r_g_e_t_-_s_e_s_s_i_o_n is either the name of a session (as listed by the lliisstt-- - sseessssiioonnss command); or the name of a client as for _t_a_r_g_e_t_-_c_l_i_e_n_t, in this - case, the session attached to the client is used. An fnmatch(3) pattern - may be used to match the session name. If a session is omitted when re- - quired, ttmmuuxx attempts to use the current session; if no current session - is available, the most recently created is chosen. If no client is spec- - ified, the current client is chosen, if possible, or an error is report- - ed. - - _t_a_r_g_e_t_-_w_i_n_d_o_w specifies a window in the form _s_e_s_s_i_o_n:_i_n_d_e_x, for example - mysession:1. The session is in the same form as for _t_a_r_g_e_t_-_s_e_s_s_i_o_n. - _s_e_s_s_i_o_n, _i_n_d_e_x or both may be omitted. If _s_e_s_s_i_o_n is omitted, the same - rules as for _t_a_r_g_e_t_-_s_e_s_s_i_o_n are followed; if _i_n_d_e_x is not present, the - current window for the given session is used. When the argument does not - contain a colon (:), ttmmuuxx first attempts to parse it as window index; if - that fails, an attempt is made to match a session or client name. - - Multiple commands may be specified together as part of a _c_o_m_m_a_n_d - _s_e_q_u_e_n_c_e. Each command should be separated by spaces and a semicolon (` - ; '); commands are executed sequentially from left to right. A literal - semicolon may be included by escaping it with a backslash (for example, - when specifying a command sequence to bbiinndd--kkeeyy). - - Examples include: - - refresh-client -t/dev/ttyp2 - - rename-session -tfirst newname - - set-window-option -t:0 monitor-activity on - - new-window ; split-window -d - - bind-key D detach-client \; lock-server - - The following commands are available: - - aattttaacchh--sseessssiioonn [--dd] [--tt _t_a_r_g_e_t_-_s_e_s_s_i_o_n] - (alias: aattttaacchh) - Create a new client in the current terminal and attach it to a - session. If --dd is specified, any other clients attached to the - session are detached. - - If no server is started, aattttaacchh--sseessssiioonn will attempt to start it; - this will fail unless sessions are created in the configuration - file. - - bbiinndd--kkeeyy [--rr] _k_e_y _c_o_m_m_a_n_d [_a_r_g_u_m_e_n_t_s] - (alias: bbiinndd) - Bind key _k_e_y to _c_o_m_m_a_n_d. Keys may be specified prefixed with - `C-' or `^' for ctrl keys, or `M-' for alt (meta) keys. The --rr - flag indicates this key may repeat, see the rreeppeeaatt--ttiimmee option. - - bbrreeaakk--ppaannee [--dd] [--pp _p_a_n_e_-_i_n_d_e_x] [--tt _t_a_r_g_e_t_-_w_i_n_d_o_w] - (alias: bbrreeaakkpp)) - Break the current pane off from its containing window to make it - the only pane in a new window. If --dd is given, the new window - does not become the current window. - - cchhoooossee--sseessssiioonn [--tt _t_a_r_g_e_t_-_w_i_n_d_o_w] - Put a window into session choice mode, where the session for the - current client may be selected interactively from a list. This - command works only from inside ttmmuuxx. - - cchhoooossee--wwiinnddooww [--tt _t_a_r_g_e_t_-_w_i_n_d_o_w] - Put a window into window choice mode, where the window for the - session attached to the current client may be selected interac- - tively from a list. This command works only from inside ttmmuuxx. - - cclloocckk--mmooddee [--tt _t_a_r_g_e_t_-_w_i_n_d_o_w] - Display a large clock. - - ccoommmmaanndd--pprroommpptt [--tt _t_a_r_g_e_t_-_c_l_i_e_n_t] [_t_e_m_p_l_a_t_e] - Open the command prompt in a client. This may be used from in- - side ttmmuuxx to execute commands interactively. If _t_e_m_p_l_a_t_e is - specified, it is used as the command; any %% in the template will - be replaced by what is entered at the prompt. - - ccoonnffiirrmm--bbeeffoorree [--tt _t_a_r_g_e_t_-_c_l_i_e_n_t] _c_o_m_m_a_n_d - (alias: ccoonnffiirrmm)) - Ask for confirmation before executing _c_o_m_m_a_n_d. This command - works only from inside ttmmuuxx. - - ccooppyy--bbuuffffeerr [--aa _s_r_c_-_i_n_d_e_x] [--bb _d_s_t_-_i_n_d_e_x] [--ss _s_r_c_-_s_e_s_s_i_o_n] [--tt - _d_s_t_-_s_e_s_s_i_o_n] - (alias: ccooppyybb)) - Copy a session paste buffer to another session. If no sessions - are specified, the current one is used instead. - - ccooppyy--mmooddee [--uu] [--tt _t_a_r_g_e_t_-_w_i_n_d_o_w] - Enter copy mode. The --uu option scrolls one page up. - - ddeelleettee--bbuuffffeerr [--bb _b_u_f_f_e_r_-_i_n_d_e_x] [--tt _t_a_r_g_e_t_-_s_e_s_s_i_o_n] - (alias: ddeelleetteebb) - Delete the buffer at _b_u_f_f_e_r_-_i_n_d_e_x, or the top buffer if not spec- - ified. - - ddeettaacchh--cclliieenntt [--tt _t_a_r_g_e_t_-_c_l_i_e_n_t] - (alias: ddeettaacchh) - Detach the current client if bound to a key, or the specified - client with --tt. - - ddoowwnn--ppaannee [--pp _p_a_n_e_-_i_n_d_e_x] [--tt _t_a_r_g_e_t_-_w_i_n_d_o_w] - (alias: ddoowwnnpp) - Move down a pane. - - ffiinndd--wwiinnddooww [--tt _t_a_r_g_e_t_-_w_i_n_d_o_w] _m_a_t_c_h_-_s_t_r_i_n_g - (alias: ffiinnddww) - Search for _m_a_t_c_h_-_s_t_r_i_n_g in window names, titles, and visible con- - tent (but not history). If only one window is matched, it'll be - automatically selected, otherwise a choice list is shown. This - command only works from inside ttmmuuxx. - - hhaass--sseessssiioonn [--tt _t_a_r_g_e_t_-_s_e_s_s_i_o_n] - (alias: hhaass) - Report an error and exit with 1 if the specified session does not - exist. If it does exist, exit with 0. - - kkiillll--ppaannee [--pp _p_a_n_e_-_i_n_d_e_x] [--tt _t_a_r_g_e_t_-_w_i_n_d_o_w] - (alias: kkiillllpp) - Destroy the given pane. - - kkiillll--sseerrvveerr - Kill the ttmmuuxx server and clients and destroy all sessions. - - kkiillll--sseessssiioonn [--tt _t_a_r_g_e_t_-_s_e_s_s_i_o_n] - Destroy the given session, closing any windows linked to it and - no other sessions, and detaching all clients attached to it. - - kkiillll--wwiinnddooww [--tt _t_a_r_g_e_t_-_w_i_n_d_o_w] - (alias: kkiillllww) - Kill the current window or the window at _t_a_r_g_e_t_-_w_i_n_d_o_w, removing - it from any sessions to which it is linked. - - llaasstt--wwiinnddooww [--tt _t_a_r_g_e_t_-_s_e_s_s_i_o_n] - (alias: llaasstt) - Select the last (previously selected) window. If no _t_a_r_g_e_t_- - _s_e_s_s_i_o_n is specified, select the last window of the current ses- - sion. - - lliinnkk--wwiinnddooww [--ddkk] [--ss _s_r_c_-_w_i_n_d_o_w] [--tt _d_s_t_-_w_i_n_d_o_w] - (alias: lliinnkkww) - Link the window at _s_r_c_-_w_i_n_d_o_w to the specified _d_s_t_-_w_i_n_d_o_w. If - _d_s_t_-_w_i_n_d_o_w is specified and no such window exists, the _s_r_c_-_w_i_n_d_o_w - is linked there. If --kk is given and _d_s_t_-_w_i_n_d_o_w exists, it is - killed, otherwise an error is generated. If --dd is given, the - newly linked window is not selected. - - lliisstt--bbuuffffeerrss [--tt _t_a_r_g_e_t_-_s_e_s_s_i_o_n] - (alias: llssbb) - List the buffers in the given session. - - lliisstt--cclliieennttss - (alias: llsscc) - List all clients attached to the server. - - lliisstt--ccoommmmaannddss - (alias: llssccmm) - List the syntax of all commands supported by ttmmuuxx. - - lliisstt--kkeeyyss - (alias: llsskk) - List all key bindings. - - lliisstt--sseessssiioonnss - (alias: llss) - List all sessions managed by the server. - - lliisstt--wwiinnddoowwss [--tt _t_a_r_g_e_t_-_s_e_s_s_i_o_n] - (alias: llssww) - List windows in the current session or in _t_a_r_g_e_t_-_s_e_s_s_i_o_n. - - llooaadd--bbuuffffeerr [--bb _b_u_f_f_e_r_-_i_n_d_e_x] [--tt _t_a_r_g_e_t_-_s_e_s_s_i_o_n] _p_a_t_h - (alias: llooaaddbb) - Load the contents of the specified paste buffer from _p_a_t_h. - - lloocckk--sseerrvveerr - (alias: lloocckk) - Lock the server until a password is entered. - - mmoovvee--wwiinnddooww [--dd] [--ss _s_r_c_-_w_i_n_d_o_w] [--tt _d_s_t_-_w_i_n_d_o_w] - (alias: mmoovveeww) - This is similar to lliinnkk--wwiinnddooww, except the window at _s_r_c_-_w_i_n_d_o_w - is moved to _d_s_t_-_w_i_n_d_o_w. - - nneeww--sseessssiioonn [--dd] [--nn _w_i_n_d_o_w_-_n_a_m_e] [--ss _s_e_s_s_i_o_n_-_n_a_m_e] [_c_o_m_m_a_n_d] - (alias: nneeww) - Create a new session with name _s_e_s_s_i_o_n_-_n_a_m_e. The new session is - attached to the current terminal unless --dd is given. _w_i_n_d_o_w_-_n_a_m_e - and _c_o_m_m_a_n_d are the name of and command to execute in the initial - window. - - nneeww--wwiinnddooww [--dd] [--nn _w_i_n_d_o_w_-_n_a_m_e] [--tt _t_a_r_g_e_t_-_w_i_n_d_o_w] [_c_o_m_m_a_n_d] - (alias: nneewwww) - Create a new window. If --dd is given, the session does not make - the new window the current window. _t_a_r_g_e_t_-_w_i_n_d_o_w represents the - window to be created. _c_o_m_m_a_n_d is the command to execute. If - _c_o_m_m_a_n_d is not specified, the default command is used. - - The TERM environment variable must be set to ``screen'' for all - programs running _i_n_s_i_d_e ttmmuuxx. New windows will automatically - have ``TERM=screen'' added to their environment, but care must be - taken not to reset this in shell start-up files. - - nneexxtt--llaayyoouutt [--tt _t_a_r_g_e_t_-_w_i_n_d_o_w] - (alias: nneexxttll) - Move a window to the next layout and rearrange the panes to fit. - - nneexxtt--wwiinnddooww [--tt _t_a_r_g_e_t_-_s_e_s_s_i_o_n] - (alias: nneexxtt) - Move to the next window in the session. - - ppaassttee--bbuuffffeerr [--dd] [--bb _b_u_f_f_e_r_-_i_n_d_e_x] [--tt _t_a_r_g_e_t_-_w_i_n_d_o_w] - (alias: ppaasstteebb) - Insert the contents of a paste buffer into the current window. - - pprreevviioouuss--wwiinnddooww [--tt _t_a_r_g_e_t_-_s_e_s_s_i_o_n] - (alias: pprreevv) - Move to the previous window in the session. - - rreeffrreesshh--cclliieenntt [--tt _t_a_r_g_e_t_-_c_l_i_e_n_t] - (alias: rreeffrreesshh) - Refresh the current client if bound to a key, or a single client - if one is given with --tt. - - rreennaammee--sseessssiioonn [--tt _t_a_r_g_e_t_-_s_e_s_s_i_o_n] _n_e_w_-_n_a_m_e - (alias: rreennaammee) - Rename the session to _n_e_w_-_n_a_m_e. - - rreennaammee--wwiinnddooww [--tt _t_a_r_g_e_t_-_w_i_n_d_o_w] _n_e_w_-_n_a_m_e - (alias: rreennaammeeww) - Rename the current window, or the window at _t_a_r_g_e_t_-_w_i_n_d_o_w if - specified, to _n_e_w_-_n_a_m_e. - - rreessiizzee--ppaannee [--DDUU] [--pp _p_a_n_e_-_i_n_d_e_x] [--tt _t_a_r_g_e_t_-_w_i_n_d_o_w] [_a_d_j_u_s_t_m_e_n_t] - (alias: rreessiizzeepp) - Resize a pane, upward with --UU (the default) or downward with --DD. - The _a_d_j_u_s_t_m_e_n_t is given in lines (the default is 1). - - rreessppaawwnn--wwiinnddooww [--kk] [--tt _t_a_r_g_e_t_-_w_i_n_d_o_w] [_c_o_m_m_a_n_d] - (alias: rreessppaawwnnww) - Reactive a window in which the command has exited (see the - rreemmaaiinn--oonn--eexxiitt window option). If _c_o_m_m_a_n_d is not given, the com- - mand used when the window was created is executed. The window - must be already inactive, unless --kk is given, in which case any - existing command is killed. - - rroottaattee--wwiinnddooww [--DDUU] [--tt _t_a_r_g_e_t_-_w_i_n_d_o_w] - (alias: rroottaatteeww) - Rotate the positions of the panes within a window, either upward - (numerically lower) with --UU or downward (numerically higher). - - ssaavvee--bbuuffffeerr [--aa] [--bb _b_u_f_f_e_r_-_i_n_d_e_x] [--tt _t_a_r_g_e_t_-_s_e_s_s_i_o_n] _p_a_t_h - (alias: ssaavveebb) - Save the contents of the specified paste buffer to _p_a_t_h. The --aa - option appends to rather than overwriting the file. - - ssccrroollll--mmooddee [--uu] [--tt _t_a_r_g_e_t_-_w_i_n_d_o_w] - Enter scroll mode. The --uu has the same meaning as in the ccooppyy-- - mmooddee command. - - sseelleecctt--ppaannee [--pp _p_a_n_e_-_i_n_d_e_x] [--tt _t_a_r_g_e_t_-_w_i_n_d_o_w] - (alias: sseelleeccttpp) - Make pane _p_a_n_e_-_i_n_d_e_x the active pane in window _t_a_r_g_e_t_-_w_i_n_d_o_w. - - sseelleecctt--pprroommpptt [--tt _t_a_r_g_e_t_-_c_l_i_e_n_t] - Open a prompt inside _t_a_r_g_e_t_-_c_l_i_e_n_t allowing a window index to be - entered interactively. - - sseelleecctt--wwiinnddooww [--tt _t_a_r_g_e_t_-_w_i_n_d_o_w] - (alias: sseelleeccttww) - Select the window at _t_a_r_g_e_t_-_w_i_n_d_o_w. - - sseenndd--kkeeyyss [--tt _t_a_r_g_e_t_-_w_i_n_d_o_w] _k_e_y _._._. - (alias: sseenndd) - Send a key or keys to a window. Each argument _k_e_y is the name of - the key (such as `C-a' or `npage' ) to send; if the string is not - recognised as a key, it is sent as a series of characters. All - arguments are sent sequentially from first to last. - - sseenndd--pprreeffiixx [--tt _t_a_r_g_e_t_-_w_i_n_d_o_w] - Send the prefix key to a window as if it was pressed. - - sseerrvveerr--iinnffoo - (alias: iinnffoo) - Show server information and terminal details. - - sseett--bbuuffffeerr [--bb _b_u_f_f_e_r_-_i_n_d_e_x] [--tt _t_a_r_g_e_t_-_s_e_s_s_i_o_n] _d_a_t_a - (alias: sseettbb) - Set the contents of the specified buffer to _d_a_t_a. - - sseett--ooppttiioonn [--gguu] [--tt _t_a_r_g_e_t_-_s_e_s_s_i_o_n] _o_p_t_i_o_n _v_a_l_u_e - (alias: sseett) - Set an option. If --gg is specified, the option is set as a global - option. Global options apply to all sessions which don't have - the option explicitly set. If --gg is not used, the option applies - only to _t_a_r_g_e_t_-_s_e_s_s_i_o_n. The --uu flag unsets an option, so a ses- - sion inherits the option from the global options - it is not pos- - sible to unset a global option. - - Possible options are: - - bbeellll--aaccttiioonn [aannyy | nnoonnee | ccuurrrreenntt] - Set action on window bell. aannyy means a bell in any win- - dow linked to a session causes a bell in the current win- - dow of that session, nnoonnee means all bells are ignored and - ccuurrrreenntt means only bell in windows other than the current - window are ignored. - - bbuuffffeerr--lliimmiitt _n_u_m_b_e_r - Set the number of buffers kept for each session; as new - buffers are added to the top of the stack, old ones are - removed from the bottom if necessary to maintain this - maximum length. - - ddeeffaauulltt--ccoommmmaanndd _c_o_m_m_a_n_d - Set the command used for new windows (if not specified - when the window is created) to _c_o_m_m_a_n_d. The default is - ``exec $SHELL''. - - ddeeffaauulltt--ppaatthh _p_a_t_h - Set the default working directory for processes created - from keys, or interactively from the prompt. The default - is the current working directory when the server is - started. - - hhiissttoorryy--lliimmiitt _l_i_n_e_s - Set the maximum number of lines held in window history. - This setting applies only to new windows - existing win- - dow histories are not resized and retain the limit at the - point they were created. - - lloocckk--aafftteerr--ttiimmee _n_u_m_b_e_r - Lock the server after _n_u_m_b_e_r seconds of inactivity. The - default is off (set to 0). This has no effect as a ses- - sion option; it must be set as a global option using --gg. - - mmeessssaaggee--aattttrr _a_t_t_r_i_b_u_t_e_s - Set status line message attributes, where _a_t_t_r_i_b_u_t_e_s is - either ddeeffaauulltt or a comma-delimited list of one or more - of: bbrriigghhtt (or bboolldd), ddiimm, uunnddeerrssccoorree, bblliinnkk, rreevveerrssee, - hhiiddddeenn, or iittaalliiccss. - - mmeessssaaggee--bbgg _c_o_l_o_u_r - Set status line message background colour, where _c_o_l_o_u_r - is one of: bbllaacckk, rreedd, ggrreeeenn, yyeellllooww, bblluuee, mmaaggeennttaa, - ccyyaann, wwhhiittee or ddeeffaauulltt. - - mmeessssaaggee--ffgg _c_o_l_o_u_r - Set status line message foreground colour. - - pprreeffiixx _k_e_y - Set the current prefix key. - - rreeppeeaatt--ttiimmee _n_u_m_b_e_r - Allow multiple commands to be entered without pressing - the prefix-key again in the specified _n_u_m_b_e_r milliseconds - (the default is 500). Whether a key repeats may be set - when it is bound using the --rr flag to bbiinndd--kkeeyy. Repeat - is enabled for the default keys of the uupp--ppaannee, ddoowwnn-- - ppaannee, rreessiizzee--ppaannee--uupp, and rreessiizzee--ppaannee--ddoowwnn commands. - - sseett--rreemmaaiinn--oonn--eexxiitt [oonn | ooffff] - Set the rreemmaaiinn--oonn--eexxiitt window option for any windows - first created in this session. - - sseett--ttiittlleess [oonn | ooffff] - Attempt to set the window title using the \e]2;...\007 - xterm code and the terminal appears to be an xterm. This - option is enabled by default. Note that elinks(1) will - only attempt to set the window title if the STY environ- - ment variable is set. - - ssttaattuuss [oonn | ooffff] - Show or hide the status line. - - ssttaattuuss--aattttrr _a_t_t_r_i_b_u_t_e_s - Set status line attributes. - - ssttaattuuss--bbgg _c_o_l_o_u_r - Set status line background colour. - - ssttaattuuss--ffgg _c_o_l_o_u_r - Set status line foreground colour. - - ssttaattuuss--iinntteerrvvaall _i_n_t_e_r_v_a_l - Update the status bar every _i_n_t_e_r_v_a_l seconds. By de- - fault, updates will occur every 15 seconds. A setting of - zero disables redrawing at interval. - - ssttaattuuss--kkeeyyss [vvii | eemmaaccss] - Use vi(1)- or emacs(1)-style key bindings in the status - line, for example at the command prompt. Defaults to - emacs. - - ssttaattuuss--lleefftt _s_t_r_i_n_g - Display _s_t_r_i_n_g to the left of the status bar. _s_t_r_i_n_g - will be passed through strftime(3) before being used. By - default, the session name is shown. _s_t_r_i_n_g may contain - any of the following special character pairs: - - CChhaarraacctteerr ppaaiirr RReeppllaacceedd wwiitthh - #(command) First line of command's output - #H Hostname of local host - #S Session name - #T Current window title - ## A literal `#' - - Where appropriate, these may be prefixed with a number to - specify the maximum length, for example `#24T'. - - ssttaattuuss--lleefftt--lleennggtthh _l_e_n_g_t_h - Set the maximum _l_e_n_g_t_h of the left component of the sta- - tus bar. The default is 10. - - ssttaattuuss--rriigghhtt _s_t_r_i_n_g - Display _s_t_r_i_n_g to the right of the status bar. By de- - fault, the date and time will be shown. As with ssttaattuuss-- - lleefftt, _s_t_r_i_n_g will be passed to strftime(3) and character - pairs are replaced. - - ssttaattuuss--rriigghhtt--lleennggtthh _l_e_n_g_t_h - Set the maximum _l_e_n_g_t_h of the right component of the sta- - tus bar. The default is 40. - - sseett--ppaasssswwoorrdd [--cc] _p_a_s_s_w_o_r_d - (alias: ppaassss) - Set the server password. If the --cc option is given, a pre-en- - crypted password may be specified. By default, the password is - blank, thus any entered password will be accepted when unlocking - the server (see the lloocckk--sseerrvveerr command). To prevent variable - expansion when an encrypted password is read from a configuration - file, enclose it in single quotes ('). - - sseett--wwiinnddooww--ooppttiioonn [--gguu] [--tt _t_a_r_g_e_t_-_w_i_n_d_o_w] _o_p_t_i_o_n _v_a_l_u_e - (alias: sseettww) - Set a window-specific option. The --gg and --uu flags work similarly - to the sseett--ooppttiioonn command. - - Supported options are: - - aaggggrreessssiivvee--rreessiizzee [oonn | ooffff] - Aggressively resize the chosen window. This means that - ttmmuuxx will resize the window to the size of the smallest - session for which it is the current window, rather than - the smallest session to which it is attached. The window - may resize when the current window is changed on another - sessions; this option is good for full-screen programs - which support SIGWINCH and poor for interactive programs - such as shells. - - aauuttoommaattiicc--rreennaammee [oonn | ooffff] - Control automatic window renaming. When this setting is - enabled, ttmmuuxx will attempt - on supported platforms - to - rename the window to reflect the command currently run- - ning in it. This flag is automatically disabled for an - individual window when a name is specified at creation - with nneeww--wwiinnddooww oorr nneeww--sseessssiioonn, or later with rreennaammee-- - wwiinnddooww. It may be switched off globally with: - - set-window-option -g automatic-rename off - - cclloocckk--mmooddee--ccoolloouurr _c_o_l_o_u_r - Set clock colour. - - cclloocckk--mmooddee--ssttyyllee [1122 | 2244] - Set clock hour format. - - ffoorrccee--hheeiigghhtt _h_e_i_g_h_t - - ffoorrccee--wwiiddtthh _w_i_d_t_h - Prevent ttmmuuxx from resizing a window to greater than _w_i_d_t_h - or _h_e_i_g_h_t. A value of zero restores the default unlimit- - ed setting. - - mmooddee--aattttrr _a_t_t_r_i_b_u_t_e_s - Set window modes attributes. - - mmooddee--bbgg _c_o_l_o_u_r - Set window modes background colour. - - mmooddee--ffgg _c_o_l_o_u_r - Set window modes foreground colour. - - mmooddee--kkeeyyss [vvii | eemmaaccss] - Use vi(1)- or emacs(1)-style key bindings in scroll and - copy modes. Key bindings default to emacs. - - mmoonniittoorr--aaccttiivviittyy [oonn | ooffff] - Monitor for activity in the window. Windows with activi- - ty are highlighted in the status line. - - mmoonniittoorr--ccoonntteenntt _m_a_t_c_h_-_s_t_r_i_n_g - Monitor content in the window. When _m_a_t_c_h_-_s_t_r_i_n_g appears - in the window, it is highlighted in the status line. - - rreemmaaiinn--oonn--eexxiitt [oonn | ooffff] - A window with this flag set is not destroyed when the - program running in it exits. The window may be reacti- - vated with the rreessppaawwnn--wwiinnddooww command. - - uuttff88 [oonn | ooffff] - Instructs ttmmuuxx to expect UTF-8 sequences to appear in - this window. - - wwiinnddooww--ssttaattuuss--aattttrr _a_t_t_r_i_b_u_t_e_s - Set status line attributes for a single window. - - wwiinnddooww--ssttaattuuss--bbgg _c_o_l_o_u_r - Set status line background colour for a single window. - - wwiinnddooww--ssttaattuuss--ffgg _c_o_l_o_u_r - Set status line foreground colour for a single window. - - xxtteerrmm--kkeeyyss [oonn | ooffff] - If this option is set, ttmmuuxx will generate xterm(1)-style - function key sequences; these have a number included to - indicate modifiers such as shift, meta or ctrl. - - sshhooww--bbuuffffeerr [--bb _b_u_f_f_e_r_-_i_n_d_e_x] [--tt _t_a_r_g_e_t_-_s_e_s_s_i_o_n] - (alias: sshhoowwbb) - Display the contents of the specified buffer. - - sshhooww--ooppttiioonnss [--tt _t_a_r_g_e_t_-_s_e_s_s_i_o_n] _o_p_t_i_o_n _v_a_l_u_e - (alias: sshhooww) - Show the currently set options. If a _t_a_r_g_e_t_-_s_e_s_s_i_o_n is speci- - fied, the options for that session are shown; otherwise, the - global options are listed. - - sshhooww--wwiinnddooww--ooppttiioonnss [--tt _t_a_r_g_e_t_-_w_i_n_d_o_w] _o_p_t_i_o_n _v_a_l_u_e - (alias: sshhoowwww) - List the current options for the given window. - - ssoouurrccee--ffiillee _p_a_t_h - (alias: ssoouurrccee) - Execute commands from _p_a_t_h. - - sspplliitt--wwiinnddooww [--dd] [--ll _l_i_n_e_s | --pp _p_e_r_c_e_n_t_a_g_e] [--tt _t_a_r_g_e_t_-_w_i_n_d_o_w] [_c_o_m_m_a_n_d] - (alias: splitw) - Creates a new window by splitting it vertically. The --ll and --pp - options specify the size of the new window in lines, or as a per- - centage, respectively. All other options have the same meaning - as in the nneeww--wwiinnddooww command. - - A few notes with regard to panes: - 1. If attempting to split a window with less than eight lines, - an error will be shown. - 2. If the window is resized, as many panes are shown as can fit - without reducing them below four lines. - 3. The minimum pane size is four lines (including the separator - line). - 4. The panes are indexed from top (0) to bottom, with no num- - bers skipped. - - ssttaarrtt--sseerrvveerr - (alias: ssttaarrtt) - Start the ttmmuuxx server, if not already running, without creating - any sessions. - - ssuussppeenndd--cclliieenntt [--cc --ttaarrggeett--cclliieenntt] - (alias: ssuussppeennddcc) - Suspend a client by sending SIGTSTP (tty stop). - - sswwaapp--ppaannee [--ddDDUU] [--pp _s_r_c_-_i_n_d_e_x] [--tt _t_a_r_g_e_t_-_w_i_n_d_o_w] [--qq _d_s_t_-_i_n_d_e_x] - (alias: sswwaapppp) - Swap two panes within a window. If --UU is used, the pane is - swapped with the pane above (before it numerically); --DD swaps - with the pane below (the next numerically); or _d_s_t_-_i_n_d_e_x may be - give to swap with a specific pane. - - sswwaapp--wwiinnddooww [--dd] [--ss _s_r_c_-_w_i_n_d_o_w] [--tt _d_s_t_-_w_i_n_d_o_w] - (alias: sswwaappww) - This is similar to lliinnkk--wwiinnddooww, except the source and destination - windows are swapped. It is an error if no window exists at _s_r_c_- - _w_i_n_d_o_w. - - sswwiittcchh--cclliieenntt [--cc _t_a_r_g_e_t_-_c_l_i_e_n_t --tt _t_a_r_g_e_t_-_s_e_s_s_i_o_n] - (alias: sswwiittcchhcc) - Switch the current session for client _t_a_r_g_e_t_-_c_l_i_e_n_t to _t_a_r_g_e_t_- - _s_e_s_s_i_o_n. - - uunnbbiinndd--kkeeyy _k_e_y - (alias: uunnbbiinndd) - Unbind the key bound to _k_e_y. - - uunnlliinnkk--wwiinnddooww [--tt _t_a_r_g_e_t_-_w_i_n_d_o_w] - (alias: uunnlliinnkkww) - Unlink _t_a_r_g_e_t_-_w_i_n_d_o_w. A window may be unlinked only if it is - linked to multiple sessions - windows may not be linked to no - sessions. - - uupp--ppaannee [--pp _p_a_n_e_-_i_n_d_e_x] [--tt _t_a_r_g_e_t_-_w_i_n_d_o_w] - (alias: uupppp) - Move up a pane. - -FFIILLEESS - ~/.tmux.conf - default ttmmuuxx configuration file - -SSEEEE AALLSSOO - pty(4) - -AAUUTTHHOORRSS - Nicholas Marriott - -OpenBSD 4.5 April 20, 2009 13 From 29d401657283e0a8ca86314daa585991dde994b8 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 1 Jun 2009 23:51:00 +0000 Subject: [PATCH 0003/1180] Update the man page with some recent changes to the code: - SIGUSR1 recreates the socket; - guesswork to work out if the terminal supports UTF-8; - a paste key for the command prompt; - main-horizontal layout to match main-vertical, and options to configure the size of the large pane; - clear-history command; - select-layout command. --- tmux.1 | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 52 insertions(+), 4 deletions(-) diff --git a/tmux.1 b/tmux.1 index 4b96ad47..17dc225f 100644 --- a/tmux.1 +++ b/tmux.1 @@ -92,6 +92,12 @@ Unlike .Fl S a full path is not necessary: the sockets are all created in the same directory. +.Pp +If the socket is accidentally removed, the +.Em SIGUSR1 +signal may be sent to the +.Nm +server process to recreate it. .It Fl S Ar socket-path Specify a full alternative path to the server socket. If @@ -102,9 +108,18 @@ flag is ignored. .It Fl U Unlock the server. .It Fl u -Instruct .Nm -that the terminal support UTF-8. +attempts to guess if the terminal is likely to support UTF-8 by first checking +the +.Ev LANG +environment variable for the string "UTF-8", and then by - if the terminal +looks suitable - trying to print a UTF-8 character and measuring the cursor +movement. +These are not always successful: the +.Fl u +flag explicitly informs +.Nm +that the UTF-8 is supported. .It Fl v Request verbose logging. This option may be specified multiple times for increasing verbosity. @@ -269,8 +284,11 @@ The following keys are supported as appropriate for the mode: .It Li "Cursor right" Ta "l" Ta "Right" .It Li "Start selection" Ta "Space" Ta "C-Space" .It Li "Cursor up" Ta "k" Ta "Up" +.It Li "Paste buffer" Ta "p" Ta "C-y" .El .Pp +The paste buffer key pastes the first line from the top paste buffer on the +stack. .Sh BUFFERS .Nm maintains a stack of @@ -328,9 +346,20 @@ Only the active pane is shown - all other panes are hidden. Panes are spread out evenly from left to right across the window. .It Ic even-vertical Panes are spread evenly from top to bottom. +.It Ic main-horizontal +A large (main) pane is shown at the top of the window and the remaining panes are +spread from left to right in the leftover space at the bottom. +Use the +.Em main-pane-height +window option to specify the height of the top pane. .It Ic main-vertical -A large (81 column) pane is shown on the left of the window and the remaining -panes are spread from top to bottom in the leftover space to the right. +Similar to +.Ic main-horizontal +but the large pane is placed on the left and the others spread from top to +bottom along the right. +See the +.Em main-pane-width +window option. .El .Sh COMMANDS This section contains a list of the commands supported by @@ -474,6 +503,12 @@ Put a window into window choice mode, where the window for the session attached to the current client may be selected interactively from a list. This command works only from inside .Nm . +.It Xo Ic clear-history +.Op Fl p Ar pane-index +.Op Fl t Ar target-window +.Xc +.D1 (alias: Ic clearhist) +Remove and free the history for the specified pane. .It Xo Ic clock-mode .Op Fl t Ar target-window .Xc @@ -811,6 +846,12 @@ The has the same meaning as in the .Ic copy-mode command. +.It Xo Ic select-layout +.Op Fl t Ar target-window +.Ar layout-name +.Xc +.D1 (alias: selectl) +Choose a specific layout for a window. .It Xo Ic select-pane .Op Fl p Ar pane-index .Op Fl t Ar target-window @@ -1134,6 +1175,13 @@ from resizing a window to greater than or .Ar height . A value of zero restores the default unlimited setting. +.It Ic main-pane-width Ar width +.It Ic main-pane-height Ar height +Set the width or height of the main (left or top) pane in the +.Ic main-horizontal +or +.Ic main-vertical +layouts. .It Ic mode-attr Ar attributes Set window modes attributes. .It Ic mode-bg Ar colour From df91860b522db207a04caeb95ccea16e2600afef Mon Sep 17 00:00:00 2001 From: Ray Lai Date: Tue, 2 Jun 2009 10:49:40 +0000 Subject: [PATCH 0004/1180] Don't leak memory if multiple -f flags are given. OK nicm@ --- tmux.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tmux.c b/tmux.c index b9d502e3..820ffb6b 100644 --- a/tmux.c +++ b/tmux.c @@ -227,6 +227,8 @@ main(int argc, char **argv) flags &= ~IDENTIFY_256COLOURS; break; case 'f': + if (cfg_file) + xfree(cfg_file); cfg_file = xstrdup(optarg); break; case 'L': From 3686645e775dafd7feb8452cc3e9d76445180237 Mon Sep 17 00:00:00 2001 From: Ray Lai Date: Tue, 2 Jun 2009 11:14:08 +0000 Subject: [PATCH 0005/1180] Don't dereference NULL if buf winds up being empty. Can't happen right now according to NicM but better safe than sorry. OK nicm@ --- attributes.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/attributes.c b/attributes.c index cfe46ecd..36b34ff1 100644 --- a/attributes.c +++ b/attributes.c @@ -45,7 +45,8 @@ attributes_tostring(u_char ch) strlcat(buf, "hidden,", sizeof (buf)); if (ch & GRID_ATTR_ITALICS) strlcat(buf, "italics,", sizeof (buf)); - *(strrchr(buf, ',')) = '\0'; + if (*buf) + *(strrchr(buf, ',')) = '\0'; return (buf); } From 49c776ea59c9af4ad5e2d1af3b93712ee6534abe Mon Sep 17 00:00:00 2001 From: Ray Lai Date: Tue, 2 Jun 2009 11:17:03 +0000 Subject: [PATCH 0006/1180] Make code clearer: - if (hdr->size > SIZE_MAX - 1) + if (hdr->size == SIZE_MAX) OK nicm@ --- client-msg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client-msg.c b/client-msg.c index fd48d403..2e2a6b49 100644 --- a/client-msg.c +++ b/client-msg.c @@ -73,7 +73,7 @@ client_msg_dispatch(struct client_ctx *cctx, char **error) int client_msg_fn_error(struct hdr *hdr, struct client_ctx *cctx, char **error) { - if (hdr->size > SIZE_MAX - 1) + if (hdr->size == SIZE_MAX) fatalx("bad MSG_ERROR size"); *error = xmalloc(hdr->size + 1); From f60bc7e03bc54f8170ca8eca325e14d31fe01a3a Mon Sep 17 00:00:00 2001 From: Ray Lai Date: Tue, 2 Jun 2009 11:18:59 +0000 Subject: [PATCH 0007/1180] Don't access array[-1] if array is an empty string. OK nicm@ --- arg.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arg.c b/arg.c index c02b2663..6fe36a15 100644 --- a/arg.c +++ b/arg.c @@ -76,7 +76,7 @@ arg_parse_client(const char *arg) /* Trim a trailing : if any from the argument. */ n = strlen(arg2); - if (arg2[n - 1] == ':') + if (n && arg2[n - 1] == ':') arg2[n - 1] = '\0'; /* Try and look up the client name. */ @@ -101,7 +101,7 @@ arg_parse_session(const char *arg) /* Trim a trailing : if any from the argument. */ n = strlen(arg2); - if (arg2[n - 1] == ':') + if (n && arg2[n - 1] == ':') arg2[n - 1] = '\0'; /* See if the argument matches a session. */ From dc373abba88155afb47e31c6f7785a8cedffba42 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Ritschard Date: Tue, 2 Jun 2009 15:55:32 +0000 Subject: [PATCH 0008/1180] spawn login shells by default, adapt manpage bits as well. ok nicm@ --- tmux.1 | 2 +- tmux.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tmux.1 b/tmux.1 index 17dc225f..9bada894 100644 --- a/tmux.1 +++ b/tmux.1 @@ -947,7 +947,7 @@ Set the command used for new windows (if not specified when the window is created) to .Ar command . The default is -.Dq exec $SHELL . +.Dq exec $SHELL -l . .It Ic default-path Ar path Set the default working directory for processes created from keys, or interactively from the prompt. diff --git a/tmux.c b/tmux.c index 820ffb6b..069dc551 100644 --- a/tmux.c +++ b/tmux.c @@ -369,7 +369,7 @@ main(int argc, char **argv) shell = _PATH_BSHELL; } options_set_string( - &global_options, "default-command", "exec %s", shell); + &global_options, "default-command", "exec %s -l", shell); if (getcwd(cwd, sizeof cwd) == NULL) { log_warn("getcwd"); From a35630838ff564350ed0c8066ec206c5e2dbd6e8 Mon Sep 17 00:00:00 2001 From: Igor Sobrado Date: Tue, 2 Jun 2009 16:46:00 +0000 Subject: [PATCH 0009/1180] sort options alphabetically. --- tmux.1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tmux.1 b/tmux.1 index 9bada894..03690a66 100644 --- a/tmux.1 +++ b/tmux.1 @@ -75,9 +75,6 @@ will look for a config file at The configuration file is a set of .Nm commands which are executed in sequence when the server is first started. -.It Fl q -Prevent the server sending various information messages, for example when -window flags are altered. .It Fl L Ar socket-name .Nm stores the server socket in a directory under @@ -98,6 +95,9 @@ If the socket is accidentally removed, the signal may be sent to the .Nm server process to recreate it. +.It Fl q +Prevent the server sending various information messages, for example when +window flags are altered. .It Fl S Ar socket-path Specify a full alternative path to the server socket. If From 4215d009a518d2763203a71e1ed51944951fd46e Mon Sep 17 00:00:00 2001 From: Igor Sobrado Date: Tue, 2 Jun 2009 16:53:20 +0000 Subject: [PATCH 0010/1180] remove unused flag; while here, make usage's output fit on 80-column displays. --- tmux.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tmux.c b/tmux.c index 069dc551..ea6793c2 100644 --- a/tmux.c +++ b/tmux.c @@ -60,8 +60,9 @@ char *makesockpath(const char *); __dead void usage(void) { - fprintf(stderr, "usage: %s [-28dqUuVv] [-f file] " - "[-L socket-name] [-S socket-path] [command [flags]]\n", + fprintf(stderr, + "usage: %s [-28dqUuv] [-f file] [-L socket-name] [-S socket-path]\n" + " [command [flags]]\n", __progname); exit(1); } From 3f76a973ee6b19071df1839cd218b2f6071c4380 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 2 Jun 2009 23:39:32 +0000 Subject: [PATCH 0011/1180] Recent code to try and detect if a terminal supports UTF-8 by printing to it fails spectacularly on (at least) sparc64, so disable it for now. Thanks to naddy and Josh Elsasser for help and testing. --- tmux.1 | 8 +++----- tty.c | 4 ++++ 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/tmux.1 b/tmux.1 index 03690a66..b55fae68 100644 --- a/tmux.1 +++ b/tmux.1 @@ -109,13 +109,11 @@ flag is ignored. Unlock the server. .It Fl u .Nm -attempts to guess if the terminal is likely to support UTF-8 by first checking +attempts to guess if the terminal is likely to support UTF-8 by checking the .Ev LANG -environment variable for the string "UTF-8", and then by - if the terminal -looks suitable - trying to print a UTF-8 character and measuring the cursor -movement. -These are not always successful: the +environment variable for the string "UTF-8". +This is not always correct: the .Fl u flag explicitly informs .Nm diff --git a/tty.c b/tty.c index 4d81910d..06ce9248 100644 --- a/tty.c +++ b/tty.c @@ -134,7 +134,9 @@ tty_start_tty(struct tty *tty) struct termios tio; int what; +#if 0 tty_detect_utf8(tty); +#endif if (tcgetattr(tty->fd, &tty->tio) != 0) fatal("tcgetattr failed"); @@ -204,6 +206,7 @@ tty_stop_tty(struct tty *tty) tty_raw(tty, "\033[?1000l"); } +#if 0 void tty_detect_utf8(struct tty *tty) { @@ -278,6 +281,7 @@ tty_detect_utf8(struct tty *tty) if (tcsetattr(tty->fd, TCSANOW, &old_tio) != 0) fatal("tcsetattr failed"); } +#endif void tty_fill_acs(struct tty *tty) From fdda4142bf21df7b67ebf88c56b4a1ab340bec46 Mon Sep 17 00:00:00 2001 From: Ray Lai Date: Wed, 3 Jun 2009 04:03:16 +0000 Subject: [PATCH 0012/1180] Cast char to u_char before passing to isalnum(). OK nicm@ --- names.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/names.c b/names.c index d5182d88..00c79fee 100644 --- a/names.c +++ b/names.c @@ -97,7 +97,7 @@ parse_window_name(const char *in) if (*name != '\0') { ptr = name + strlen(name) - 1; - while (ptr > name && !isalnum(*ptr)) + while (ptr > name && !isalnum((u_char)*ptr)) *ptr-- = '\0'; } From 646cfa6983fe739fbb5a908fcc412ae415248a9f Mon Sep 17 00:00:00 2001 From: Jason McIntyre Date: Wed, 3 Jun 2009 06:49:05 +0000 Subject: [PATCH 0013/1180] some cleanup; ok nicm --- tmux.1 | 128 +++++++++++++++++++++++++++------------------------------ 1 file changed, 60 insertions(+), 68 deletions(-) diff --git a/tmux.1 b/tmux.1 index b55fae68..efbfd8d7 100644 --- a/tmux.1 +++ b/tmux.1 @@ -14,12 +14,12 @@ .\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING .\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd April 20, 2009 +.Dd $Mdocdate$ .Dt TMUX 1 .Os .Sh NAME .Nm tmux -.Nd "terminal multiplexer" +.Nd terminal multiplexer .Sh SYNOPSIS .Nm tmux .Bk -words @@ -31,7 +31,7 @@ .Ek .Sh DESCRIPTION .Nm -is a terminal multiplexer; it enables a number of terminals to be accessed and +is a terminal multiplexer: it enables a number of terminals to be accessed and controlled from a single terminal. .Pp .Nm @@ -61,7 +61,7 @@ to assume the terminal supports 256 colours. .It Fl 8 Like .Fl 2 , -indicates the terminal supports 88 colours. +but indicates that the terminal supports 88 colours. .It Fl d Force .Nm @@ -91,12 +91,12 @@ a full path is not necessary: the sockets are all created in the same directory. .Pp If the socket is accidentally removed, the -.Em SIGUSR1 +.Dv SIGUSR1 signal may be sent to the .Nm server process to recreate it. .It Fl q -Prevent the server sending various information messages, for example when +Prevent the server sending various informational messages, for example when window flags are altered. .It Fl S Ar socket-path Specify a full alternative path to the server socket. @@ -117,7 +117,7 @@ This is not always correct: the .Fl u flag explicitly informs .Nm -that the UTF-8 is supported. +that UTF-8 is supported. .It Fl v Request verbose logging. This option may be specified multiple times for increasing verbosity. @@ -127,18 +127,19 @@ and .Pa tmux-server-PID.log files in the current directory, where .Em PID -is the pid of the server or client process. +is the PID of the server or client process. .It Ar command Op Ar flags This specifies one of a set of commands used to control .Nm , -and described in the following sections. -If no command and flags is specified, the +as described in the following sections. +If no command and flags are specified, the .Ic new-session command is assumed. -.Pp .El .Sh QUICK START -To create a new tmux session running +To create a new +.Nm +session running .Xr vi 1 : .Pp .Dl $ tmux new-session vi @@ -154,15 +155,14 @@ If there are several options, they are listed: .Bd -literal -offset indent $ tmux n ambiguous command: n, could be: new-session, new-window, next-window -$ .Ed .Pp Within an active session, a new window may be created by typing .Ql C-b -(ctrl-b, known as the prefix key) +(Ctrl, known as the prefix key, followed by the -.Ql c -key. +.Ql b +key). .Pp Windows may be navigated with: .Ql C-b 0 @@ -184,31 +184,31 @@ Typing .Ql C-b \&? lists the current key bindings in the current window; up and down may be used to navigate the list or -.Ql Q +.Ql q to exit from it. .Sh KEY BINDINGS .Nm may be controlled from an attached client by using a key combination of a prefix key, .Ql C-b -(ctrl-b) by default, followed by a command key. +(Ctrl-b) by default, followed by a command key. .Pp Some of the default key bindings include: .Pp -.Bl -tag -width Ds -compact -.It Ql d -Detach current client. -.It Ql c +.Bl -tag -width Ds -offset 3n -compact +.It c Create new window. -.It Ql n -Change to next window in the current session. -.It Ql p -Change to previous window in the current session. -.It Ql l +.It d +Detach current client. +.It l Move to last (previously selected) window in the current session. -.It Ql t +.It n +Change to next window in the current session. +.It p +Change to previous window in the current session. +.It t Display a large clock. -.It Ql \&? +.It \&? List current key bindings. .El .Pp @@ -225,7 +225,7 @@ commands. .Sh HISTORY .Nm maintains a configurable history buffer for each window. -By default, up to 2000 lines are kept, this can be altered with the +By default, up to 2000 lines are kept; this can be altered with the .Ic history-limit option (see the .Ic set-option @@ -258,11 +258,8 @@ command, bound to by default. .El .Pp -The keys available depend on whether -.Xr emacs 1 -or -.Xr vi 1 -mode is selected (see the +The keys available depend on whether emacs or vi mode is selected +(see the .Ic mode-keys option). The following keys are supported as appropriate for the mode: @@ -333,20 +330,15 @@ commands may be used to swap panes without changing the window layout. .Pp The following layouts are supported: .Bl -tag -width Ds -.It Ic manual -Manual layout splits windows vertically (running across); only with this layout -may panes be resized using the -.Ic resize-pane -command. .It Ic active-only -Only the active pane is shown - all other panes are hidden. +Only the active pane is shown \(en all other panes are hidden. .It Ic even-horizontal Panes are spread out evenly from left to right across the window. .It Ic even-vertical Panes are spread evenly from top to bottom. .It Ic main-horizontal A large (main) pane is shown at the top of the window and the remaining panes are -spread from left to right in the leftover space at the bottom. +spread from left to right in the leftover space at the bottom. Use the .Em main-pane-height window option to specify the height of the top pane. @@ -358,6 +350,11 @@ bottom along the right. See the .Em main-pane-width window option. +.It Ic manual +Manual layout splits windows vertically (running across); only with this layout +may panes be resized using the +.Ic resize-pane +command. .El .Sh COMMANDS This section contains a list of the commands supported by @@ -382,9 +379,9 @@ command. .Ar target-session is either the name of a session (as listed by the .Ic list-sessions -command); or the name of a client as for +command) or the name of a client, .Ar target-client , -in this case, the session attached to the client is used. +in which case the session attached to the client is used. An .Xr fnmatch 3 pattern may be used to match the session name. @@ -411,22 +408,20 @@ is omitted, the same rules as for are followed; if .Em index is not present, the current window for the given session is used. -When the argument does not contain a colon (:), +When the argument does not contain a colon, .Nm first attempts to parse it as window index; if that fails, an attempt is made to match a session or client name. .Pp Multiple commands may be specified together as part of a .Em command sequence . -Each command should be separated by spaces and a semicolon -.Eo ( Ql \& \&; \& Ec ) ; +Each command should be separated by spaces and a semicolon; commands are executed sequentially from left to right. A literal semicolon may be included by escaping it with a backslash (for example, when specifying a command sequence to .Ic bind-key ) . .Pp Examples include: -.Pp .Bd -literal -offset indent refresh-client -t/dev/ttyp2 @@ -468,9 +463,9 @@ Keys may be specified prefixed with .Ql C- or .Ql ^ -for ctrl keys, or +for Ctrl keys, or .Ql M- -for alt (meta) keys. +for Alt (meta) keys. The .Fl r flag indicates this key may repeat, see the @@ -1023,8 +1018,7 @@ window option for any windows first created in this session. Attempt to set the window title using the \ee]2;...\e007 xterm code and the terminal appears to be an xterm. This option is enabled by default. -Note that -.Xr elinks 1 +Note that elinks will only attempt to set the window title if the STY environment variable is set. .It Xo Ic status @@ -1046,10 +1040,7 @@ A setting of zero disables redrawing at interval. .It Xo Ic status-keys .Op Ic vi | Ic emacs .Xc -Use -.Xr vi 1 - -or -.Xr emacs 1 -style +Use vi or emacs-style key bindings in the status line, for example at the command prompt. Defaults to emacs. .It Ic status-left Ar string @@ -1138,8 +1129,9 @@ This means that will resize the window to the size of the smallest session for which it is the current window, rather than the smallest session to which it is attached. The window may resize when the current window is changed on another sessions; -this option is good for full-screen programs which support SIGWINCH and poor for -interactive programs such as shells. +this option is good for full-screen programs which support +.Dv SIGWINCH +and poor for interactive programs such as shells. .It Xo Ic automatic-rename .Op Ic on | Ic off .Xc @@ -1189,10 +1181,7 @@ Set window modes foreground colour. .It Xo Ic mode-keys .Op Ic vi | Ic emacs .Xc -Use -.Xr vi 1 - -or -.Xr emacs 1 -style +Use vi or emacs-style key bindings in scroll and copy modes. Key bindings default to emacs. .It Xo Ic monitor-activity @@ -1202,7 +1191,8 @@ Monitor for activity in the window. Windows with activity are highlighted in the status line. .It Xo Ic monitor-content Ar match-string .Xc -Monitor content in the window. When +Monitor content in the window. +When .Ar match-string appears in the window, it is highlighted in the status line. .It Xo Ic remain-on-exit @@ -1233,7 +1223,7 @@ If this option is set, will generate .Xr xterm 1 -style function key sequences; these have a number included to indicate modifiers such -as shift, meta or ctrl. +as Shift, Alt or Ctrl. .El .It Xo Ic show-buffer .Op Fl b Ar buffer-index @@ -1306,7 +1296,9 @@ server, if not already running, without creating any sessions. .Op Fl c target-client .Xc .D1 (alias: Ic suspendc ) -Suspend a client by sending SIGTSTP (tty stop). +Suspend a client by sending +.Dv SIGTSTP +(tty stop). .It Xo Ic swap-pane .Op Fl dDU .Op Fl p Ar src-index @@ -1363,11 +1355,11 @@ not be linked to no sessions. Move up a pane. .El .Sh FILES -.Bl -tag -width Ds -compact +.Bl -tag -width "~/.tmux.confXXX" -compact .It Pa ~/.tmux.conf -default +Default .Nm -configuration file +configuration file. .El .Sh SEE ALSO .Xr pty 4 From c5dbec9e856602e7b10a5e8f8e5f70585096ffb8 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 3 Jun 2009 07:51:24 +0000 Subject: [PATCH 0014/1180] When swapping pane positions, swap the PANE_HIDDEN flag as well, otherwise tmux crashes when trying to find the new active pane. While here, nuke an unused pane flag. Fixes PR 6160, reported by and a slightly different version of diff tested by ralf.horstmann at gmx.de. --- cmd-rotate-window.c | 13 ++++++++++++- cmd-swap-pane.c | 11 ++++++++++- tmux.h | 3 +-- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/cmd-rotate-window.c b/cmd-rotate-window.c index 354e6942..b7ac341d 100644 --- a/cmd-rotate-window.c +++ b/cmd-rotate-window.c @@ -60,6 +60,7 @@ cmd_rotate_window_exec(struct cmd *self, struct cmd_ctx *ctx) struct window *w; struct window_pane *wp, *wp2; u_int sx, sy, xoff, yoff; + int flags; if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) return (-1); @@ -71,14 +72,19 @@ cmd_rotate_window_exec(struct cmd *self, struct cmd_ctx *ctx) TAILQ_INSERT_HEAD(&w->panes, wp, entry); xoff = wp->xoff; yoff = wp->yoff; - sx = wp->sx; sy = wp->sy; + sx = wp->sx; sy = wp->sy; + flags = w->flags; TAILQ_FOREACH(wp, &w->panes, entry) { if ((wp2 = TAILQ_NEXT(wp, entry)) == NULL) break; wp->xoff = wp2->xoff; wp->yoff = wp2->yoff; + wp->flags &= ~PANE_HIDDEN; + wp->flags |= wp2->flags & PANE_HIDDEN; window_pane_resize(wp, wp2->sx, wp2->sy); } wp->xoff = xoff; wp->yoff = yoff; + wp->flags &= ~PANE_HIDDEN; + wp->flags |= flags & PANE_HIDDEN; window_pane_resize(wp, sx, sy); if ((wp = TAILQ_PREV(w->active, window_panes, entry)) == NULL) @@ -91,13 +97,18 @@ cmd_rotate_window_exec(struct cmd *self, struct cmd_ctx *ctx) xoff = wp->xoff; yoff = wp->yoff; sx = wp->sx; sy = wp->sy; + flags = w->flags; TAILQ_FOREACH_REVERSE(wp, &w->panes, window_panes, entry) { if ((wp2 = TAILQ_PREV(wp, window_panes, entry)) == NULL) break; wp->xoff = wp2->xoff; wp->yoff = wp2->yoff; + wp->flags &= ~PANE_HIDDEN; + wp->flags |= wp2->flags & PANE_HIDDEN; window_pane_resize(wp, wp2->sx, wp2->sy); } wp->xoff = xoff; wp->yoff = yoff; + wp->flags &= ~PANE_HIDDEN; + wp->flags |= flags & PANE_HIDDEN; window_pane_resize(wp, sx, sy); if ((wp = TAILQ_NEXT(w->active, entry)) == NULL) diff --git a/cmd-swap-pane.c b/cmd-swap-pane.c index 0a34d14d..e2f572dc 100644 --- a/cmd-swap-pane.c +++ b/cmd-swap-pane.c @@ -158,6 +158,7 @@ cmd_swap_pane_exec(struct cmd *self, struct cmd_ctx *ctx) struct window *w; struct window_pane *tmp_wp, *src_wp, *dst_wp; u_int xx, yy; + int flags; if (data == NULL) return (0); @@ -209,10 +210,15 @@ cmd_swap_pane_exec(struct cmd *self, struct cmd_ctx *ctx) xx = src_wp->xoff; yy = src_wp->yoff; + flags = src_wp->flags; src_wp->xoff = dst_wp->xoff; src_wp->yoff = dst_wp->yoff; + src_wp->flags &= ~PANE_HIDDEN; + src_wp->flags |= dst_wp->flags & PANE_HIDDEN; dst_wp->xoff = xx; dst_wp->yoff = yy; + dst_wp->flags &= ~PANE_HIDDEN; + dst_wp->flags |= flags & PANE_HIDDEN; xx = src_wp->sx; yy = src_wp->sy; @@ -220,7 +226,10 @@ cmd_swap_pane_exec(struct cmd *self, struct cmd_ctx *ctx) window_pane_resize(dst_wp, xx, yy); if (!data->flag_detached) { - window_set_active_pane(w, dst_wp); + tmp_wp = dst_wp; + if (tmp_wp->flags & PANE_HIDDEN) + tmp_wp = src_wp; + window_set_active_pane(w, tmp_wp); layout_refresh(w, 0); } diff --git a/tmux.h b/tmux.h index a2d5f0da..0c8e5929 100644 --- a/tmux.h +++ b/tmux.h @@ -589,8 +589,7 @@ struct window_pane { int flags; #define PANE_HIDDEN 0x1 -#define PANE_RESTART 0x2 -#define PANE_REDRAW 0x4 +#define PANE_REDRAW 0x2 char *cmd; char *cwd; From 5823854b5e4c5f382166de67fbb7486365259d5a Mon Sep 17 00:00:00 2001 From: Jason McIntyre Date: Wed, 3 Jun 2009 09:29:06 +0000 Subject: [PATCH 0015/1180] undo a mistake found by sobrado; --- tmux.1 | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tmux.1 b/tmux.1 index efbfd8d7..10f04e07 100644 --- a/tmux.1 +++ b/tmux.1 @@ -158,10 +158,13 @@ ambiguous command: n, could be: new-session, new-window, next-window .Ed .Pp Within an active session, a new window may be created by typing -.Ql C-b -(Ctrl, known as the prefix key, +.Ql C-b c +(Ctrl followed by the .Ql b +key +followed by the +.Ql c key). .Pp Windows may be navigated with: From e659aa86b9b88db6e84979cd9321884f8109424a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 3 Jun 2009 15:47:14 +0000 Subject: [PATCH 0016/1180] Add a section summarising the status line. There are quite a number of status line options, it is something many want to configure, and the meaning of some bits weren't really documented. --- tmux.1 | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/tmux.1 b/tmux.1 index 10f04e07..b8309605 100644 --- a/tmux.1 +++ b/tmux.1 @@ -359,6 +359,62 @@ may panes be resized using the .Ic resize-pane command. .El +.Sh STATUS LINE +.Nm +includes an optional status line which is displayed in the bottom line of each +terminal. +By default, the status line is enabled (it may be disabled with the +.Ic status +session option) and contains, from left-to-right: the name of the current +session in square brackets; the window list; the current window title in double +quotes; and the time and date. +.Pp +The status line is made of three parts: configurable left and right sections +(which may contain dynamic content such as the time or output from a shell +command, see the +.Ic status-left , +.Ic status-left-length , +.Ic status-right , +and +.Ic status-right-length +options below), and a central window list. +The window list shows the index, name and (if any) flag of the windows +present in the current session in ascending numerical order. +The flag is one of the following symbols appended to the window name: +.Bl -column "Symbol" "Meaning" -offset indent +.It Sy "Symbol" Ta Sy "Meaning" +.It Li "*" Ta "Denotes the current window." +.It Li "-" Ta "Marks the last window (previously selected)." +.It Li "#" Ta "Window is monitored and activity has been detected." +.It Li "!" Ta "A bell has occurred in the window." +.It Li "+" Ta "Window is monitored for content and it has appeared." +.El +.Pp +The # symbol relates to the +.Ic monitor-activity +and + to the +.Ic monitor-content +window options. +The window name is printed in inverted colours if an alert (bell, activity or +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. +.Pp +The status line is automatically refreshed at interval if it has changed, the interval may be +controlled with the +.Ic status-interval +session option. .Sh COMMANDS This section contains a list of the commands supported by .Nm . From 41d985ace3189c7375a8f1c2d1d2d028a20cf731 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 3 Jun 2009 15:58:40 +0000 Subject: [PATCH 0017/1180] Add missing documentation for the -a flag used to move to next/previous window with alert. --- cmd-next-window.c | 2 +- cmd-previous-window.c | 2 +- tmux.1 | 8 ++++++++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/cmd-next-window.c b/cmd-next-window.c index 71346764..d49fe4cb 100644 --- a/cmd-next-window.c +++ b/cmd-next-window.c @@ -29,7 +29,7 @@ int cmd_next_window_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_next_window_entry = { "next-window", "next", - CMD_TARGET_SESSION_USAGE, + "[-a] " CMD_TARGET_SESSION_USAGE, CMD_AFLAG, cmd_next_window_init, cmd_target_parse, diff --git a/cmd-previous-window.c b/cmd-previous-window.c index 7b880347..6163cec1 100644 --- a/cmd-previous-window.c +++ b/cmd-previous-window.c @@ -29,7 +29,7 @@ int cmd_previous_window_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_previous_window_entry = { "previous-window", "prev", - CMD_TARGET_SESSION_USAGE, + "[-a] " CMD_TARGET_SESSION_USAGE, CMD_AFLAG, cmd_previous_window_init, cmd_target_parse, diff --git a/tmux.1 b/tmux.1 index b8309605..d62acb91 100644 --- a/tmux.1 +++ b/tmux.1 @@ -799,10 +799,14 @@ start-up files. .D1 (alias: Ic nextl ) Move a window to the next layout and rearrange the panes to fit. .It Xo Ic next-window +.Op Fl a .Op Fl t Ar target-session .Xc .D1 (alias: Ic next ) Move to the next window in the session. +If +.Fl a +is used, move to the next window with a bell, activity or content alert. .It Xo Ic paste-buffer .Op Fl d .Op Fl b Ar buffer-index @@ -811,10 +815,14 @@ Move to the next window in the session. .D1 (alias: Ic pasteb ) Insert the contents of a paste buffer into the current window. .It Xo Ic previous-window +.Op Fl a .Op Fl t Ar target-session .Xc .D1 (alias: Ic prev ) Move to the previous window in the session. +With +.Fl a , +move to the previous window with a bell, activity or content alert. .It Xo Ic refresh-client .Op Fl t Ar target-client .Xc From 7d45e29683119b31179295b3712142ebf8897a0d Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 3 Jun 2009 16:05:46 +0000 Subject: [PATCH 0018/1180] Add a UTF-8 aware string length function and make UTF-8 in status-left/status-right work properly. At the moment any top-bit-set characters are assumed to be UTF-8: a status-utf8 option to configure this will come shortly. --- screen-write.c | 114 +++++++++++++++++++++++++++++++++++++++++++++++-- status.c | 19 +++++---- tmux.h | 9 +++- 3 files changed, 127 insertions(+), 15 deletions(-) diff --git a/screen-write.c b/screen-write.c index ac31fc6f..d55a29a4 100644 --- a/screen-write.c +++ b/screen-write.c @@ -52,20 +52,126 @@ screen_write_putc( screen_write_cell(ctx, gc, NULL); } +/* Calculate string length. */ +size_t printflike1 +screen_write_strlen(const char *fmt, ...) +{ + va_list ap; + char *msg; + u_char *ptr, utf8buf[4]; + size_t left, size = 0; + + va_start(ap, fmt); + xvasprintf(&msg, fmt, ap); + va_end(ap); + + ptr = msg; + while (*ptr != '\0') { + if (*ptr > 0x7f) { /* Assume this is UTF-8. */ + memset(utf8buf, 0xff, sizeof utf8buf); + + left = strlen(ptr); + if (*ptr >= 0xc2 && *ptr <= 0xdf && left >= 2) { + memcpy(utf8buf, ptr, 2); + ptr += 2; + } else if (*ptr >= 0xe0 && *ptr <= 0xef && left >= 3) { + memcpy(utf8buf, ptr, 3); + ptr += 3; + } else if (*ptr >= 0xf0 && *ptr <= 0xf4 && left >= 4) { + memcpy(utf8buf, ptr, 4); + ptr += 4; + } else { + *utf8buf = *ptr; + ptr++; + } + size += utf8_width(utf8buf); + } else { + size++; + ptr++; + } + } + + return (size); +} + /* Write string. */ void printflike3 screen_write_puts( struct screen_write_ctx *ctx, struct grid_cell *gc, const char *fmt, ...) { va_list ap; - char *msg, *ptr; va_start(ap, fmt); - xvasprintf(&msg, fmt, ap); + screen_write_vnputs(ctx, -1, gc, fmt, ap); va_end(ap); +} - for (ptr = msg; *ptr != '\0'; ptr++) - screen_write_putc(ctx, gc, (u_char) *ptr); +/* Write string with length limit (-1 for unlimited). */ +void printflike4 +screen_write_nputs(struct screen_write_ctx *ctx, + ssize_t maxlen, struct grid_cell *gc, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + screen_write_vnputs(ctx, maxlen, gc, fmt, ap); + va_end(ap); +} + +void +screen_write_vnputs(struct screen_write_ctx *ctx, + ssize_t maxlen, struct grid_cell *gc, const char *fmt, va_list ap) +{ + char *msg; + u_char *ptr, utf8buf[4]; + size_t left, size = 0; + int width; + + xvasprintf(&msg, fmt, ap); + + ptr = msg; + while (*ptr != '\0') { + if (*ptr > 0x7f) { /* Assume this is UTF-8. */ + memset(utf8buf, 0xff, sizeof utf8buf); + + left = strlen(ptr); + if (*ptr >= 0xc2 && *ptr <= 0xdf && left >= 2) { + memcpy(utf8buf, ptr, 2); + ptr += 2; + } else if (*ptr >= 0xe0 && *ptr <= 0xef && left >= 3) { + memcpy(utf8buf, ptr, 3); + ptr += 3; + } else if (*ptr >= 0xf0 && *ptr <= 0xf4 && left >= 4) { + memcpy(utf8buf, ptr, 4); + ptr += 4; + } else { + *utf8buf = *ptr; + ptr++; + } + + width = utf8_width(utf8buf); + if (maxlen > 0 && size + width > (size_t) maxlen) { + while (size < (size_t) maxlen) { + screen_write_putc(ctx, gc, ' '); + size++; + } + break; + } + size += width; + + gc->flags |= GRID_FLAG_UTF8; + screen_write_cell(ctx, gc, utf8buf); + gc->flags &= ~GRID_FLAG_UTF8; + + } else { + if (maxlen > 0 && size > (size_t) maxlen) + break; + + size++; + screen_write_putc(ctx, gc, *ptr); + ptr++; + } + } xfree(msg); } diff --git a/status.c b/status.c index a72e5a26..9d43803a 100644 --- a/status.c +++ b/status.c @@ -47,8 +47,8 @@ status_redraw(struct client *c) struct window_pane *wp; struct screen *sc = NULL, old_status; char *left, *right, *text, *ptr; - size_t llen, rlen, offset, xx, yy, sy; - size_t size, start, width; + size_t llen, llen2, rlen, rlen2, offset; + size_t xx, yy, sy, size, start, width; struct grid_cell stdgc, gc; int larrow, rarrow; @@ -78,15 +78,16 @@ status_redraw(struct client *c) left = status_replace(s, options_get_string( &s->options, "status-left"), c->status_timer.tv_sec); llen = options_get_number(&s->options, "status-left-length"); - if (strlen(left) < llen) - llen = strlen(left); - left[llen] = '\0'; + llen2 = screen_write_strlen("%s", left); + if (llen2 < llen) + llen = llen2; right = status_replace(s, options_get_string( &s->options, "status-right"), c->status_timer.tv_sec); rlen = options_get_number(&s->options, "status-right-length"); - if (strlen(right) < rlen) - rlen = strlen(right); + rlen2 = screen_write_strlen("%s", right); + if (rlen2 < rlen) + rlen = rlen2; right[rlen] = '\0'; /* @@ -163,7 +164,7 @@ draw: screen_write_start(&ctx, NULL, &c->status); if (llen != 0) { screen_write_cursormove(&ctx, 0, yy); - screen_write_puts(&ctx, &stdgc, "%s ", left); + screen_write_nputs(&ctx, llen + 1, &stdgc, "%s ", left); if (larrow) screen_write_putc(&ctx, &stdgc, ' '); } else { @@ -220,7 +221,7 @@ draw: /* Draw the last item. */ if (rlen != 0) { screen_write_cursormove(&ctx, c->tty.sx - rlen - 1, yy); - screen_write_puts(&ctx, &stdgc, " %s", right); + screen_write_nputs(&ctx, rlen + 1, &stdgc, " %s", right); } /* Draw the arrows. */ diff --git a/tmux.h b/tmux.h index 0c8e5929..fef8394c 100644 --- a/tmux.h +++ b/tmux.h @@ -1347,8 +1347,13 @@ void grid_view_delete_cells(struct grid *, u_int, u_int, u_int); void screen_write_start( struct screen_write_ctx *, struct window_pane *, struct screen *); void screen_write_stop(struct screen_write_ctx *); -void printflike3 screen_write_puts( - struct screen_write_ctx *, struct grid_cell *, const char *, ...); +size_t printflike1 screen_write_strlen(const char *, ...); +void printflike3 screen_write_puts(struct screen_write_ctx *, + struct grid_cell *, const char *, ...); +void printflike4 screen_write_nputs(struct screen_write_ctx *, + ssize_t, struct grid_cell *, const char *, ...); +void screen_write_vnputs(struct screen_write_ctx *, + ssize_t, struct grid_cell *, const char *, va_list); void screen_write_putc( struct screen_write_ctx *, struct grid_cell *, u_char); void screen_write_copy(struct screen_write_ctx *, From 6521427a451b4044b9bf035d54c594cb1453ba48 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 3 Jun 2009 16:54:26 +0000 Subject: [PATCH 0019/1180] New session option, status-utf8, to control the interpretation of top-bit-set characters in status-left and status-right (if on, they are treated as UTF-8; otherwise passed through). --- cmd-set-option.c | 1 + screen-write.c | 22 +++++++++++----------- status.c | 15 ++++++++++----- tmux.1 | 24 ++++++++++++++++++++++-- tmux.c | 1 + tmux.h | 11 ++++++----- 6 files changed, 51 insertions(+), 23 deletions(-) diff --git a/cmd-set-option.c b/cmd-set-option.c index d4e90957..5c417325 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -73,6 +73,7 @@ const struct set_option_entry set_option_table[NSETOPTION] = { { "status-left-length", SET_OPTION_NUMBER, 0, SHRT_MAX, NULL }, { "status-right", SET_OPTION_STRING, 0, 0, NULL }, { "status-right-length", SET_OPTION_NUMBER, 0, SHRT_MAX, NULL }, + { "status-utf8", SET_OPTION_FLAG, 0, 0, NULL }, }; int diff --git a/screen-write.c b/screen-write.c index d55a29a4..b57b0620 100644 --- a/screen-write.c +++ b/screen-write.c @@ -53,8 +53,8 @@ screen_write_putc( } /* Calculate string length. */ -size_t printflike1 -screen_write_strlen(const char *fmt, ...) +size_t printflike2 +screen_write_strlen(int utf8flag, const char *fmt, ...) { va_list ap; char *msg; @@ -67,7 +67,7 @@ screen_write_strlen(const char *fmt, ...) ptr = msg; while (*ptr != '\0') { - if (*ptr > 0x7f) { /* Assume this is UTF-8. */ + if (utf8flag && *ptr > 0x7f) { memset(utf8buf, 0xff, sizeof utf8buf); left = strlen(ptr); @@ -94,7 +94,7 @@ screen_write_strlen(const char *fmt, ...) return (size); } -/* Write string. */ +/* Write simple string (no UTF-8 or maximum length). */ void printflike3 screen_write_puts( struct screen_write_ctx *ctx, struct grid_cell *gc, const char *fmt, ...) @@ -102,25 +102,25 @@ screen_write_puts( va_list ap; va_start(ap, fmt); - screen_write_vnputs(ctx, -1, gc, fmt, ap); + screen_write_vnputs(ctx, -1, gc, 0, fmt, ap); va_end(ap); } /* Write string with length limit (-1 for unlimited). */ -void printflike4 +void printflike5 screen_write_nputs(struct screen_write_ctx *ctx, - ssize_t maxlen, struct grid_cell *gc, const char *fmt, ...) + ssize_t maxlen, struct grid_cell *gc, int utf8flag, const char *fmt, ...) { va_list ap; va_start(ap, fmt); - screen_write_vnputs(ctx, maxlen, gc, fmt, ap); + screen_write_vnputs(ctx, maxlen, gc, utf8flag, fmt, ap); va_end(ap); } void -screen_write_vnputs(struct screen_write_ctx *ctx, - ssize_t maxlen, struct grid_cell *gc, const char *fmt, va_list ap) +screen_write_vnputs(struct screen_write_ctx *ctx, ssize_t maxlen, + struct grid_cell *gc, int utf8flag, const char *fmt, va_list ap) { char *msg; u_char *ptr, utf8buf[4]; @@ -131,7 +131,7 @@ screen_write_vnputs(struct screen_write_ctx *ctx, ptr = msg; while (*ptr != '\0') { - if (*ptr > 0x7f) { /* Assume this is UTF-8. */ + if (utf8flag && *ptr > 0x7f) { memset(utf8buf, 0xff, sizeof utf8buf); left = strlen(ptr); diff --git a/status.c b/status.c index 9d43803a..dae0d5c4 100644 --- a/status.c +++ b/status.c @@ -50,7 +50,7 @@ status_redraw(struct client *c) size_t llen, llen2, rlen, rlen2, offset; size_t xx, yy, sy, size, start, width; struct grid_cell stdgc, gc; - int larrow, rarrow; + int larrow, rarrow, utf8flag; left = right = NULL; @@ -74,18 +74,21 @@ status_redraw(struct client *c) if (yy == 0) goto blank; + /* Caring about UTF-8 in status line? */ + utf8flag = options_get_number(&s->options, "status-utf8"); + /* Work out the left and right strings. */ left = status_replace(s, options_get_string( &s->options, "status-left"), c->status_timer.tv_sec); llen = options_get_number(&s->options, "status-left-length"); - llen2 = screen_write_strlen("%s", left); + llen2 = screen_write_strlen(utf8flag, "%s", left); if (llen2 < llen) llen = llen2; right = status_replace(s, options_get_string( &s->options, "status-right"), c->status_timer.tv_sec); rlen = options_get_number(&s->options, "status-right-length"); - rlen2 = screen_write_strlen("%s", right); + rlen2 = screen_write_strlen(utf8flag, "%s", right); if (rlen2 < rlen) rlen = rlen2; right[rlen] = '\0'; @@ -164,7 +167,8 @@ draw: screen_write_start(&ctx, NULL, &c->status); if (llen != 0) { screen_write_cursormove(&ctx, 0, yy); - screen_write_nputs(&ctx, llen + 1, &stdgc, "%s ", left); + screen_write_nputs( + &ctx, llen + 1, &stdgc, utf8flag, "%s ", left); if (larrow) screen_write_putc(&ctx, &stdgc, ' '); } else { @@ -221,7 +225,8 @@ draw: /* Draw the last item. */ if (rlen != 0) { screen_write_cursormove(&ctx, c->tty.sx - rlen - 1, yy); - screen_write_nputs(&ctx, rlen + 1, &stdgc, " %s", right); + screen_write_nputs( + &ctx, rlen + 1, &stdgc, utf8flag, " %s", right); } /* Draw the arrows. */ diff --git a/tmux.1 b/tmux.1 index d62acb91..f19256e6 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1133,6 +1133,12 @@ may contain any of the following special character pairs: Where appropriate, these may be prefixed with a number to specify the maximum length, for example .Ql #24T . +.Pp +By default, UTF-8 in +.Ar string +is not interpreted, to enable UTF-8, use the +.Ic status-utf8 +option. .It Ic status-left-length Ar length Set the maximum .Ar length @@ -1147,13 +1153,27 @@ As with .Ic status-left , .Ar string will be passed to -.Xr strftime 3 -and character pairs are replaced. +.Xr strftime 3 , +character pairs are replaced, and UTF-8 is dependent on the +.Ic status-utf8 +option. .It Ic status-right-length Ar length Set the maximum .Ar length of the right component of the status bar. The default is 40. +.Pp +.It Xo Ic status-utf8 +.Op Ic on | Ic off +.Xc +Instruct +.Nm +to treat top-bit-set characters in the +.Ic status-left +and +.Ic status-right +strings as UTF-8; notably, this is important for wide characters. +This option defaults to off. .El .It Xo Ic set-password .Op Fl c diff --git a/tmux.c b/tmux.c index ea6793c2..71df2bfb 100644 --- a/tmux.c +++ b/tmux.c @@ -299,6 +299,7 @@ main(int argc, char **argv) options_set_string(&global_options, "status-left", "[#S]"); options_set_string( &global_options, "status-right", "\"#24T\" %%H:%%M %%d-%%b-%%y"); + options_set_number(&global_options, "status-utf8", 0); options_init(&global_window_options, NULL); options_set_number(&global_window_options, "aggressive-resize", 0); diff --git a/tmux.h b/tmux.h index fef8394c..429a66a0 100644 --- a/tmux.h +++ b/tmux.h @@ -69,6 +69,7 @@ extern const char *__progname; #define printflike2 __attribute__ ((format (printf, 2, 3))) #define printflike3 __attribute__ ((format (printf, 3, 4))) #define printflike4 __attribute__ ((format (printf, 4, 5))) +#define printflike5 __attribute__ ((format (printf, 5, 6))) /* Number of items in array. */ #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) @@ -928,7 +929,7 @@ struct set_option_entry { }; extern const struct set_option_entry set_option_table[]; extern const struct set_option_entry set_window_option_table[]; -#define NSETOPTION 24 +#define NSETOPTION 25 #define NSETWINDOWOPTION 19 /* tmux.c */ @@ -1347,13 +1348,13 @@ void grid_view_delete_cells(struct grid *, u_int, u_int, u_int); void screen_write_start( struct screen_write_ctx *, struct window_pane *, struct screen *); void screen_write_stop(struct screen_write_ctx *); -size_t printflike1 screen_write_strlen(const char *, ...); +size_t printflike2 screen_write_strlen(int, const char *, ...); void printflike3 screen_write_puts(struct screen_write_ctx *, struct grid_cell *, const char *, ...); -void printflike4 screen_write_nputs(struct screen_write_ctx *, - ssize_t, struct grid_cell *, const char *, ...); +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 *, const char *, va_list); + ssize_t, struct grid_cell *, int, const char *, va_list); void screen_write_putc( struct screen_write_ctx *, struct grid_cell *, u_char); void screen_write_copy(struct screen_write_ctx *, From 655a1aea6cb6121c57240fee7ea4c85c478865c2 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 3 Jun 2009 17:04:16 +0000 Subject: [PATCH 0020/1180] Do not set the window title by default (make set-titles option default to off), wiping over the title is rude and annoying. Agreed by several. --- tmux.1 | 2 +- tmux.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tmux.1 b/tmux.1 index f19256e6..d2485119 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1084,7 +1084,7 @@ window option for any windows first created in this session. .Xc Attempt to set the window title using the \ee]2;...\e007 xterm code and the terminal appears to be an xterm. -This option is enabled by default. +This option is off by default. Note that elinks will only attempt to set the window title if the STY environment variable is set. diff --git a/tmux.c b/tmux.c index 71df2bfb..491e49d4 100644 --- a/tmux.c +++ b/tmux.c @@ -287,7 +287,7 @@ main(int argc, char **argv) options_set_number(&global_options, "prefix", '\002'); options_set_number(&global_options, "repeat-time", 500); options_set_number(&global_options, "set-remain-on-exit", 0); - options_set_number(&global_options, "set-titles", 1); + options_set_number(&global_options, "set-titles", 0); options_set_number(&global_options, "status", 1); options_set_number(&global_options, "status-attr", GRID_ATTR_REVERSE); options_set_number(&global_options, "status-bg", 2); From 2faec76afad7f1a2e4096d04d1d894dcfb646cbf Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 3 Jun 2009 19:33:04 +0000 Subject: [PATCH 0021/1180] Pass window titles through vis(1). <0x20 is dropped anyway by the input state machine but top-bit-set nonprintables could cause trouble, and they are neater like this anyway. Suggested by deraadt a few days ago. --- input.c | 2 +- screen.c | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/input.c b/input.c index 9483bae1..35ae4164 100644 --- a/input.c +++ b/input.c @@ -475,7 +475,7 @@ input_state_string_next(u_char ch, struct input_ctx *ictx) return; } - if (ch >= 0x20 && ch != 0x7f) { + if (ch >= 0x20) { if (input_add_string(ictx, ch) != 0) input_state(ictx, input_state_first); return; diff --git a/screen.c b/screen.c index 4b355115..53b17bce 100644 --- a/screen.c +++ b/screen.c @@ -19,6 +19,7 @@ #include #include +#include #include "tmux.h" @@ -65,8 +66,12 @@ screen_free(struct screen *s) void screen_set_title(struct screen *s, const char *title) { + char tmp[BUFSIZ]; + + strnvis(tmp, title, sizeof tmp, VIS_OCTAL|VIS_TAB|VIS_NL); + xfree(s->title); - s->title = xstrdup(title); + s->title = xstrdup(tmp); } /* Resize screen. */ From 3f16fcb30ab9865cb5cddb215da34842e1b8b5fe Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 3 Jun 2009 19:37:27 +0000 Subject: [PATCH 0022/1180] Use vis(3) instead of handrolled function. --- cmd-server-info.c | 5 +++-- util.c | 20 -------------------- 2 files changed, 3 insertions(+), 22 deletions(-) diff --git a/cmd-server-info.c b/cmd-server-info.c index 94373f01..2ce44841 100644 --- a/cmd-server-info.c +++ b/cmd-server-info.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "tmux.h" @@ -156,8 +157,8 @@ cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx) ent->code, ent->name); break; case TTYCODE_STRING: - clean_string( - code->value.string, out, sizeof out); + strnvis(out, code->value.string, sizeof out, + VIS_OCTAL|VIS_TAB|VIS_NL); ctx->print(ctx, "%2u: %s: (string) %s", ent->code, ent->name, out); break; diff --git a/util.c b/util.c index 1455214a..5c871ca1 100644 --- a/util.c +++ b/util.c @@ -50,23 +50,3 @@ section_string(char *buf, size_t len, size_t sectoff, size_t sectlen) (int) (last - first), buf + first, last == len ? "" : "..."); return (s); } - -/* Clean string of invisible characters. */ -void -clean_string(const char *in, char *buf, size_t len) -{ - const u_char *cp; - size_t off; - - off = 0; - for (cp = in; *cp != '\0'; cp++) { - if (off >= len) - break; - if (*cp >= 0x20 && *cp <= 0x7f) - buf[off++] = *cp; - else - off += xsnprintf(buf + off, len - off, "\\%03hho", *cp); - } - if (off < len) - buf[off] = '\0'; -} From ebe07c27260c295256e7c66480057a3fcfdc9e7f Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 3 Jun 2009 23:26:56 +0000 Subject: [PATCH 0023/1180] Fix some miscalculations when clearing to start of screen: the number of lines to the cursor is cy not cy - 1, and the current cursor cell should be included. --- screen-write.c | 4 ++-- tty.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/screen-write.c b/screen-write.c index b57b0620..033a1a52 100644 --- a/screen-write.c +++ b/screen-write.c @@ -605,11 +605,11 @@ screen_write_clearstartofscreen(struct screen_write_ctx *ctx) sx = screen_size_x(s); if (s->cy > 0) - grid_view_clear(s->grid, 0, 0, sx, s->cy - 1); + grid_view_clear(s->grid, 0, 0, sx, s->cy); if (s->cx > sx - 1) grid_view_clear(s->grid, 0, s->cy, sx, 1); else - grid_view_clear(s->grid, 0, s->cy, s->cx, 1); + grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1); tty_write_cmd(ctx->wp, TTY_CLEARSTARTOFSCREEN); } diff --git a/tty.c b/tty.c index 06ce9248..16a865eb 100644 --- a/tty.c +++ b/tty.c @@ -797,7 +797,7 @@ tty_cmd_clearstartofscreen( tty_putc(tty, ' '); } } - for (i = 0; i < s->old_cx; i++) + for (i = 0; i <= s->old_cx; i++) tty_putc(tty, ' '); } From 52ec9b9ec418dbb80e0ebaf8a418eab22e2dd21f Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 3 Jun 2009 23:30:40 +0000 Subject: [PATCH 0024/1180] Implement the DEC alignment test. With the last change this is enough for the first cursor test in vttest (in ports) to pass; it still shops a few more problems though. --- input.c | 27 ++++++++++++++++++++++----- screen-write.c | 25 +++++++++++++++++++++++++ tmux.h | 2 ++ tty.c | 20 ++++++++++++++++++++ 4 files changed, 69 insertions(+), 5 deletions(-) diff --git a/input.c b/input.c index 35ae4164..c635a842 100644 --- a/input.c +++ b/input.c @@ -630,6 +630,9 @@ input_handle_c1_control(u_char ch, struct input_ctx *ictx) log_debug2("-- c1 %zu: %hhu (%c)", ictx->off, ch, ch); switch (ch) { + case 'D': /* IND */ + screen_write_linefeed(&ictx->ctx); + break; case 'E': /* NEL */ screen_write_carriagereturn(&ictx->ctx); screen_write_linefeed(&ictx->ctx); @@ -652,7 +655,7 @@ input_handle_private_two(u_char ch, struct input_ctx *ictx) "-- p2 %zu: %hhu (%c) %hhu", ictx->off, ch, ch, ictx->intermediate); switch (ch) { - case '0': /* Dscs (graphics) */ + case '0': /* SCS */ /* * Not really supported, but fake it up enough for those that * use it to switch character sets (by redefining G0 to @@ -665,22 +668,36 @@ input_handle_private_two(u_char ch, struct input_ctx *ictx) } break; case '=': /* DECKPAM */ + if (ictx->intermediate != '\0') + break; screen_write_kkeypadmode(&ictx->ctx, 1); log_debug("kkeypad on (application mode)"); break; case '>': /* DECKPNM */ + if (ictx->intermediate != '\0') + break; screen_write_kkeypadmode(&ictx->ctx, 0); log_debug("kkeypad off (number mode)"); break; case '7': /* DECSC */ + if (ictx->intermediate != '\0') + break; memcpy(&ictx->saved_cell, &ictx->cell, sizeof ictx->saved_cell); ictx->saved_cx = s->cx; ictx->saved_cy = s->cy; break; - case '8': /* DECRC */ - memcpy(&ictx->cell, &ictx->saved_cell, sizeof ictx->cell); - screen_write_cursormove( - &ictx->ctx, ictx->saved_cx, ictx->saved_cy); + case '8': + switch (ictx->intermediate) { + case '\0': /* DECRC */ + memcpy( + &ictx->cell, &ictx->saved_cell, sizeof ictx->cell); + screen_write_cursormove( + &ictx->ctx, ictx->saved_cx, ictx->saved_cy); + break; + case '#': /* DECALN */ + screen_write_alignmenttest(&ictx->ctx); + break; + } break; default: log_debug("unknown p2: %hhu", ch); diff --git a/screen-write.c b/screen-write.c index 033a1a52..700e150c 100644 --- a/screen-write.c +++ b/screen-write.c @@ -291,6 +291,31 @@ screen_write_cursorleft(struct screen_write_ctx *ctx, u_int nx) s->cx -= nx; } +/* VT100 alignment test. */ +void +screen_write_alignmenttest(struct screen_write_ctx *ctx) +{ + struct screen *s = ctx->s; + struct grid_cell gc; + u_int xx, yy; + + memcpy(&gc, &grid_default_cell, sizeof gc); + gc.data = 'E'; + + for (yy = 0; yy < screen_size_y(s); yy++) { + for (xx = 0; xx < screen_size_x(s); xx++) + grid_view_set_cell(s->grid, xx, yy, &gc); + } + + s->cx = 0; + s->cy = 0; + + s->rupper = 0; + s->rlower = screen_size_y(s) - 1; + + tty_write_cmd(ctx->wp, TTY_ALIGNMENTTEST); +} + /* Insert nx characters. */ void screen_write_insertcharacter(struct screen_write_ctx *ctx, u_int nx) diff --git a/tmux.h b/tmux.h index 429a66a0..b2521ac2 100644 --- a/tmux.h +++ b/tmux.h @@ -279,6 +279,7 @@ struct tty_term_code_entry { /* Output commands. */ enum tty_cmd { + TTY_ALIGNMENTTEST, TTY_CELL, TTY_CLEARENDOFLINE, TTY_CLEARENDOFSCREEN, @@ -1363,6 +1364,7 @@ void screen_write_cursorup(struct screen_write_ctx *, u_int); void screen_write_cursordown(struct screen_write_ctx *, u_int); void screen_write_cursorright(struct screen_write_ctx *, u_int); void screen_write_cursorleft(struct screen_write_ctx *, u_int); +void screen_write_alignmenttest(struct screen_write_ctx *); void screen_write_insertcharacter(struct screen_write_ctx *, u_int); void screen_write_deletecharacter(struct screen_write_ctx *, u_int); void screen_write_insertline(struct screen_write_ctx *, u_int); diff --git a/tty.c b/tty.c index 16a865eb..3149c8fb 100644 --- a/tty.c +++ b/tty.c @@ -38,6 +38,7 @@ void tty_attributes(struct tty *, const struct grid_cell *); void tty_attributes_fg(struct tty *, const struct grid_cell *); void tty_attributes_bg(struct tty *, const struct grid_cell *); +void tty_cmd_alignmenttest(struct tty *, struct window_pane *, va_list); void tty_cmd_cell(struct tty *, struct window_pane *, va_list); void tty_cmd_clearendofline(struct tty *, struct window_pane *, va_list); void tty_cmd_clearendofscreen(struct tty *, struct window_pane *, va_list); @@ -54,6 +55,7 @@ void tty_cmd_raw(struct tty *, struct window_pane *, va_list); void tty_cmd_reverseindex(struct tty *, struct window_pane *, va_list); void (*tty_cmds[])(struct tty *, struct window_pane *, va_list) = { + tty_cmd_alignmenttest, tty_cmd_cell, tty_cmd_clearendofline, tty_cmd_clearendofscreen, @@ -830,6 +832,24 @@ tty_cmd_clearscreen( } } +void +tty_cmd_alignmenttest( + struct tty *tty, struct window_pane *wp, unused va_list ap) +{ + struct screen *s = wp->screen; + u_int i, j; + + tty_reset(tty); + + tty_region(tty, 0, screen_size_y(s) - 1, wp->yoff); + + for (j = 0; j < screen_size_y(s); j++) { + tty_cursor(tty, 0, j, wp->xoff, wp->yoff); + for (i = 0; i < screen_size_x(s); i++) + tty_putc(tty, 'E'); + } +} + void tty_cmd_cell(struct tty *tty, struct window_pane *wp, va_list ap) { From c1a4c0186a244c5efe3e3a9404a3c2e995d9b9b2 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 3 Jun 2009 23:37:30 +0000 Subject: [PATCH 0025/1180] Support insert mode by using insert character to shift the cells before writing as normal. --- screen-write.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/screen-write.c b/screen-write.c index 700e150c..d7d56d97 100644 --- a/screen-write.c +++ b/screen-write.c @@ -663,6 +663,7 @@ screen_write_cell( u_int width, xx, i; struct grid_cell tmp_gc, *tmp_gc2; size_t size; + int insert = 0; /* Ignore padding. */ if (gc->flags & GRID_FLAG_PADDING) @@ -714,6 +715,13 @@ screen_write_cell( gc = &tmp_gc; } + /* If in insert mode, make space for the cells. */ + if (s->mode & MODE_INSERT && s->cx <= screen_size_x(s) - width) { + xx = screen_size_x(s) - s->cx - width; + grid_move_cells(s->grid, s->cx + width, s->cx, s->cy, xx); + insert = 1; + } + /* Check this will fit on the current line; scroll if not. */ if (s->cx > screen_size_x(s) - width) { screen_write_carriagereturn(ctx); @@ -747,6 +755,8 @@ screen_write_cell( s->cx += width; /* Draw to the screen if necessary. */ + if (insert) + tty_write_cmd(ctx->wp, TTY_INSERTCHARACTER, width); if (screen_check_selection(s, s->cx - width, s->cy)) { s->sel.cell.data = gc->data; tty_write_cmd(ctx->wp, TTY_CELL, &s->sel.cell, &gu); From 0ba85cc326712c82d809dbebb1329a99f4cc6094 Mon Sep 17 00:00:00 2001 From: Jason McIntyre Date: Thu, 4 Jun 2009 13:36:25 +0000 Subject: [PATCH 0026/1180] zap trailing whitespace; --- tmux.1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tmux.1 b/tmux.1 index d2485119..c7a70240 100644 --- a/tmux.1 +++ b/tmux.1 @@ -112,7 +112,7 @@ Unlock the server. attempts to guess if the terminal is likely to support UTF-8 by checking the .Ev LANG -environment variable for the string "UTF-8". +environment variable for the string "UTF-8". This is not always correct: the .Fl u flag explicitly informs @@ -805,7 +805,7 @@ Move a window to the next layout and rearrange the panes to fit. .D1 (alias: Ic next ) Move to the next window in the session. If -.Fl a +.Fl a is used, move to the next window with a bell, activity or content alert. .It Xo Ic paste-buffer .Op Fl d @@ -1134,7 +1134,7 @@ Where appropriate, these may be prefixed with a number to specify the maximum length, for example .Ql #24T . .Pp -By default, UTF-8 in +By default, UTF-8 in .Ar string is not interpreted, to enable UTF-8, use the .Ic status-utf8 From 8dd2f0da3f9fbb6a08aa1438c83e0c9a1b7f4565 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 4 Jun 2009 14:15:50 +0000 Subject: [PATCH 0027/1180] More input compatibility love. Support C0 within escape sequences, and the C0 control character VT (vertical tab, \013), which is treated as LF like VT102. Makes another vttest happy. --- input.c | 45 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 7 deletions(-) diff --git a/input.c b/input.c index c635a842..07e6db0b 100644 --- a/input.c +++ b/input.c @@ -394,15 +394,28 @@ input_state_sequence_first(u_char ch, struct input_ctx *ictx) ictx->private = '\0'; ARRAY_CLEAR(&ictx->args); + /* Most C0 control are accepted within CSI. */ + if (INPUT_C0CONTROL(ch)) { + if (ch == 0x1b) { /* ESC */ + /* Abort sequence and begin with new. */ + input_state(ictx, input_state_escape); + } else if (ch != 0x18 && ch != 0x1a) { /* CAN and SUB */ + /* Handle C0 immediately. */ + input_handle_c0_control(ch, ictx); + } + /* + * Just come back to this state, in case the next character + * is the start of a private sequence. + */ + return; + } + input_state(ictx, input_state_sequence_next); - if (INPUT_PARAMETER(ch)) { - input_new_argument(ictx); - if (ch >= 0x3c && ch <= 0x3f) { - /* Private control sequence. */ - ictx->private = ch; - return; - } + /* Private sequence: always the first character. */ + if (ch >= 0x3c && ch <= 0x3f) { + ictx->private = ch; + return; } /* Pass character on directly. */ @@ -423,6 +436,9 @@ input_state_sequence_next(u_char ch, struct input_ctx *ictx) } if (INPUT_PARAMETER(ch)) { + if (ARRAY_EMPTY(&ictx->args)) + input_new_argument(ictx); + if (ch == ';') { if (input_add_argument(ictx, '\0') != 0) input_state(ictx, input_state_first); @@ -443,6 +459,18 @@ input_state_sequence_next(u_char ch, struct input_ctx *ictx) return; } + /* Most C0 control are accepted within CSI. */ + if (INPUT_C0CONTROL(ch)) { + if (ch == 0x1b) { /* ESC */ + /* Abort sequence and begin with new. */ + input_state(ictx, input_state_escape); + } else if (ch != 0x18 && ch != 0x1a) { /* CAN and SUB */ + /* Handle C0 immediately. */ + input_handle_c0_control(ch, ictx); + } + return; + } + input_state(ictx, input_state_first); } @@ -612,6 +640,9 @@ input_handle_c0_control(u_char ch, struct input_ctx *ictx) } screen_write_cursormove(&ictx->ctx, s->cx, s->cy); break; + case '\013': /* VT */ + screen_write_linefeed(&ictx->ctx); + break; case '\016': /* SO */ ictx->cell.attr |= GRID_ATTR_CHARSET; break; From 6c1f03578d7a616f96b04eccd5095d4f9463edb2 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 4 Jun 2009 14:24:49 +0000 Subject: [PATCH 0028/1180] Oops, CAN and SUB should abort the sequence (return to first state), not remain in the same state. --- input.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/input.c b/input.c index 07e6db0b..f7980c25 100644 --- a/input.c +++ b/input.c @@ -400,6 +400,9 @@ input_state_sequence_first(u_char ch, struct input_ctx *ictx) /* Abort sequence and begin with new. */ input_state(ictx, input_state_escape); } else if (ch != 0x18 && ch != 0x1a) { /* CAN and SUB */ + /* Abort sequence. */ + input_state(ictx, input_state_first); + } else { /* Handle C0 immediately. */ input_handle_c0_control(ch, ictx); } @@ -465,6 +468,9 @@ input_state_sequence_next(u_char ch, struct input_ctx *ictx) /* Abort sequence and begin with new. */ input_state(ictx, input_state_escape); } else if (ch != 0x18 && ch != 0x1a) { /* CAN and SUB */ + /* Abort sequence. */ + input_state(ictx, input_state_first); + } else { /* Handle C0 immediately. */ input_handle_c0_control(ch, ictx); } From d6015824ddcd2b0373232e528ade8b40e12c1a0a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 4 Jun 2009 14:42:14 +0000 Subject: [PATCH 0029/1180] Okay, so I screwed up when testing this, doh. Unbreak so that CAN/SUB actually do cancel the sequence, and tweak to make the code more clear. --- input.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/input.c b/input.c index f7980c25..61de9a4d 100644 --- a/input.c +++ b/input.c @@ -399,13 +399,16 @@ input_state_sequence_first(u_char ch, struct input_ctx *ictx) if (ch == 0x1b) { /* ESC */ /* Abort sequence and begin with new. */ input_state(ictx, input_state_escape); - } else if (ch != 0x18 && ch != 0x1a) { /* CAN and SUB */ + return; + } else if (ch == 0x18 || ch == 0x1a) { /* CAN and SUB */ /* Abort sequence. */ input_state(ictx, input_state_first); - } else { - /* Handle C0 immediately. */ - input_handle_c0_control(ch, ictx); + return; } + + /* Handle C0 immediately. */ + input_handle_c0_control(ch, ictx); + /* * Just come back to this state, in case the next character * is the start of a private sequence. @@ -467,13 +470,16 @@ input_state_sequence_next(u_char ch, struct input_ctx *ictx) if (ch == 0x1b) { /* ESC */ /* Abort sequence and begin with new. */ input_state(ictx, input_state_escape); - } else if (ch != 0x18 && ch != 0x1a) { /* CAN and SUB */ + return; + } else if (ch == 0x18 || ch == 0x1a) { /* CAN and SUB */ /* Abort sequence. */ input_state(ictx, input_state_first); - } else { - /* Handle C0 immediately. */ - input_handle_c0_control(ch, ictx); + return; } + + /* Handle C0 immediately. */ + input_handle_c0_control(ch, ictx); + return; } From d42fb43f4f8e21dcc37e9b090842f61e39e8d6f4 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 4 Jun 2009 18:48:24 +0000 Subject: [PATCH 0030/1180] Proper support for tab stops (\033H etc), using a bitstring(3). Makes another vttest test happy. --- input.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++------- screen.c | 31 ++++++++++++++++++++++++++++++- tmux.h | 4 ++++ 3 files changed, 80 insertions(+), 8 deletions(-) diff --git a/input.c b/input.c index 61de9a4d..2546eb0f 100644 --- a/input.c +++ b/input.c @@ -74,6 +74,7 @@ void input_handle_sequence_vpa(struct input_ctx *); void input_handle_sequence_hpa(struct input_ctx *); void input_handle_sequence_cup(struct input_ctx *); void input_handle_sequence_cup(struct input_ctx *); +void input_handle_sequence_tbc(struct input_ctx *); void input_handle_sequence_ed(struct input_ctx *); void input_handle_sequence_el(struct input_ctx *); void input_handle_sequence_sm(struct input_ctx *); @@ -103,6 +104,7 @@ const struct input_sequence_entry input_sequence_table[] = { { 'P', input_handle_sequence_dch }, { 'd', input_handle_sequence_vpa }, { 'f', input_handle_sequence_cup }, + { 'g', input_handle_sequence_tbc }, { 'h', input_handle_sequence_sm }, { 'l', input_handle_sequence_rm }, { 'm', input_handle_sequence_sgr }, @@ -645,12 +647,16 @@ input_handle_c0_control(u_char ch, struct input_ctx *ictx) screen_write_cursorleft(&ictx->ctx, 1); break; case '\011': /* TAB */ - s->cx = ((s->cx / 8) * 8) + 8; - if (s->cx > screen_size_x(s) - 1) { - s->cx = 0; - screen_write_cursordown(&ictx->ctx, 1); - } - screen_write_cursormove(&ictx->ctx, s->cx, s->cy); + /* Don't tab beyond the end of the line. */ + if (s->cx >= screen_size_x(s) - 1) + break; + + /* Find the next tab point, or use the last column if none. */ + do { + s->cx++; + if (bit_test(s->tabs, s->cx)) + break; + } while (s->cx < screen_size_x(s) - 1); break; case '\013': /* VT */ screen_write_linefeed(&ictx->ctx); @@ -670,6 +676,8 @@ input_handle_c0_control(u_char ch, struct input_ctx *ictx) void input_handle_c1_control(u_char ch, struct input_ctx *ictx) { + struct screen *s = ictx->ctx.s; + log_debug2("-- c1 %zu: %hhu (%c)", ictx->off, ch, ch); switch (ch) { @@ -680,6 +688,10 @@ input_handle_c1_control(u_char ch, struct input_ctx *ictx) screen_write_carriagereturn(&ictx->ctx); screen_write_linefeed(&ictx->ctx); break; + case 'H': /* HTS */ + if (s->cx < screen_size_x(s)) + bit_set(s->tabs, s->cx); + break; case 'M': /* RI */ screen_write_reverseindex(&ictx->ctx); break; @@ -755,7 +767,7 @@ input_handle_standard_two(u_char ch, struct input_ctx *ictx) "-- s2 %zu: %hhu (%c) %hhu", ictx->off, ch, ch, ictx->intermediate); switch (ch) { - case 'B': /* Dscs (ASCII) */ + case 'B': /* SCS */ /* * Not really supported, but fake it up enough for those that * use it to switch character sets (by redefining G0 to @@ -774,6 +786,8 @@ input_handle_standard_two(u_char ch, struct input_ctx *ictx) ictx->saved_cx = 0; ictx->saved_cy = 0; + screen_reset_tabs(ictx->ctx.s); + screen_write_scrollregion( &ictx->ctx, 0, screen_size_y(ictx->ctx.s) - 1); @@ -1027,6 +1041,31 @@ input_handle_sequence_cup(struct input_ctx *ictx) screen_write_cursormove(&ictx->ctx, m - 1, n - 1); } +void +input_handle_sequence_tbc(struct input_ctx *ictx) +{ + struct screen *s = ictx->ctx.s; + uint16_t n; + + if (ictx->private != '\0') + return; + + if (ARRAY_LENGTH(&ictx->args) > 1) + return; + if (input_get_argument(ictx, 0, &n, 1) != 0) + return; + + switch (n) { + case 0: + if (s->cx < screen_size_x(s)) + bit_clear(s->tabs, s->cx); + break; + case 3: + bit_nclear(s->tabs, 0, screen_size_x(s) - 1); + break; + } +} + void input_handle_sequence_ed(struct input_ctx *ictx) { diff --git a/screen.c b/screen.c index 53b17bce..5c689c8a 100644 --- a/screen.c +++ b/screen.c @@ -18,6 +18,7 @@ #include +#include #include #include @@ -34,6 +35,8 @@ screen_init(struct screen *s, u_int sx, u_int sy, u_int hlimit) s->title = xstrdup(""); + s->tabs = NULL; + screen_reinit(s); } @@ -48,6 +51,8 @@ screen_reinit(struct screen *s) s->rlower = screen_size_y(s) - 1; s->mode = MODE_CURSOR; + + screen_reset_tabs(s); grid_clear_lines(s->grid, s->grid->hsize, s->grid->sy - 1); @@ -62,6 +67,21 @@ screen_free(struct screen *s) grid_destroy(s->grid); } +/* Reset tabs to default, eight spaces apart. */ +void +screen_reset_tabs(struct screen *s) +{ + u_int i; + + if (s->tabs != NULL) + xfree(s->tabs); + + if ((s->tabs = bit_alloc(screen_size_x(s))) == NULL) + fatal("bit_alloc failed"); + for (i = 8; i < screen_size_x(s); i += 8) + bit_set(s->tabs, i); +} + /* Set screen title. */ void screen_set_title(struct screen *s, const char *title) @@ -83,8 +103,17 @@ screen_resize(struct screen *s, u_int sx, u_int sy) if (sy < 1) sy = 1; - if (sx != screen_size_x(s)) + if (sx != screen_size_x(s)) { screen_resize_x(s, sx); + + /* + * It is unclear what should happen to tabs on resize. xterm + * seems to try and maintain them, rxvt resets them. Resetting + * is simpler and more reliable so let's do that. + */ + screen_reset_tabs(s); + } + if (sy != screen_size_y(s)) screen_resize_y(s, sy); } diff --git a/tmux.h b/tmux.h index b2521ac2..645e5003 100644 --- a/tmux.h +++ b/tmux.h @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -507,6 +508,8 @@ struct screen { int mode; + bitstr_t *tabs; + struct screen_sel sel; }; @@ -1397,6 +1400,7 @@ void screen_redraw_status(struct client *); void screen_init(struct screen *, u_int, u_int, u_int); void screen_reinit(struct screen *); void screen_free(struct screen *); +void screen_reset_tabs(struct screen *); void screen_set_title(struct screen *, const char *); void screen_resize(struct screen *, u_int, u_int); void screen_set_selection( From f031975dc09b7be9bdb32fd5256f8c325848b1f9 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 4 Jun 2009 21:02:21 +0000 Subject: [PATCH 0031/1180] Implement the CBT (backward tab) sequence (\033[Z). --- input.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/input.c b/input.c index 2546eb0f..b1247f2b 100644 --- a/input.c +++ b/input.c @@ -67,6 +67,7 @@ void input_handle_sequence_cud(struct input_ctx *); void input_handle_sequence_cuf(struct input_ctx *); void input_handle_sequence_cub(struct input_ctx *); void input_handle_sequence_dch(struct input_ctx *); +void input_handle_sequence_cbt(struct input_ctx *); void input_handle_sequence_dl(struct input_ctx *); void input_handle_sequence_ich(struct input_ctx *); void input_handle_sequence_il(struct input_ctx *); @@ -102,6 +103,7 @@ const struct input_sequence_entry input_sequence_table[] = { { 'L', input_handle_sequence_il }, { 'M', input_handle_sequence_dl }, { 'P', input_handle_sequence_dch }, + { 'Z', input_handle_sequence_cbt }, { 'd', input_handle_sequence_vpa }, { 'f', input_handle_sequence_cup }, { 'g', input_handle_sequence_tbc }, @@ -927,6 +929,30 @@ input_handle_sequence_dch(struct input_ctx *ictx) screen_write_deletecharacter(&ictx->ctx, n); } +void +input_handle_sequence_cbt(struct input_ctx *ictx) +{ + struct screen *s = ictx->ctx.s; + uint16_t n; + + if (ictx->private != '\0') + return; + + if (ARRAY_LENGTH(&ictx->args) > 1) + return; + if (input_get_argument(ictx, 0, &n, 1) != 0) + return; + if (n == 0) + n = 1; + + /* Find the previous tab point, n times. */ + while (s->cx > 0 && n-- > 0) { + do + s->cx--; + while (s->cx > 0 && !bit_test(s->tabs, s->cx)); + } +} + void input_handle_sequence_dl(struct input_ctx *ictx) { From 50bd0948564c64d76acebf8f6c5b4f3ef7b6b4fc Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 4 Jun 2009 21:43:24 +0000 Subject: [PATCH 0032/1180] If the prompt is hidden or a password is sent with -U, zero it before freeing it. --- server-msg.c | 5 +++-- status.c | 6 ++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/server-msg.c b/server-msg.c index cff23cd5..5eaa04db 100644 --- a/server-msg.c +++ b/server-msg.c @@ -278,13 +278,14 @@ server_msg_fn_unlock(struct hdr *hdr, struct client *c) if (server_unlock(pass) != 0) { #define MSG "bad password" server_write_client(c, MSG_ERROR, MSG, (sizeof MSG) - 1); - server_write_client(c, MSG_EXIT, NULL, 0); - return (0); #undef MSG } server_write_client(c, MSG_EXIT, NULL, 0); + memset(pass, 0, strlen(pass)); + xfree(pass); + return (0); } diff --git a/status.c b/status.c index dae0d5c4..98061dd0 100644 --- a/status.c +++ b/status.c @@ -597,6 +597,8 @@ status_prompt_clear(struct client *c) xfree(c->prompt_string); c->prompt_string = NULL; + if (c->prompt_flags & PROMPT_HIDDEN) + memset(c->prompt_buffer, 0, strlen(c->prompt_buffer)); xfree(c->prompt_buffer); c->prompt_buffer = NULL; @@ -794,6 +796,8 @@ status_prompt_key(struct client *c, int key) if (ARRAY_LENGTH(&c->prompt_hdata) == 0) break; + if (c->prompt_flags & PROMPT_HIDDEN) + memset(c->prompt_buffer, 0, strlen(c->prompt_buffer)); xfree(c->prompt_buffer); c->prompt_buffer = xstrdup(ARRAY_ITEM(&c->prompt_hdata, @@ -808,6 +812,8 @@ status_prompt_key(struct client *c, int key) if (server_locked) break; + if (c->prompt_flags & PROMPT_HIDDEN) + memset(c->prompt_buffer, 0, strlen(c->prompt_buffer)); xfree(c->prompt_buffer); if (c->prompt_hindex != 0) { From 38b2c42f63eaa5fcd6f750aafc756b2a5e5b4395 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 4 Jun 2009 21:56:14 +0000 Subject: [PATCH 0033/1180] Zero the password given to -U in the client as well. --- tmux.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tmux.c b/tmux.c index 491e49d4..3dccbf1b 100644 --- a/tmux.c +++ b/tmux.c @@ -421,6 +421,7 @@ main(int argc, char **argv) b = buffer_create(BUFSIZ); if (unlock) { cmd_send_string(b, pass); + memset(pass, 0, strlen(pass)); client_write_server( &cctx, MSG_UNLOCK, BUFFER_OUT(b), BUFFER_USED(b)); } else { From 85e0d8a221314869458169955f218c9971f5bcb6 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 4 Jun 2009 23:34:32 +0000 Subject: [PATCH 0034/1180] Print a better message than '(null)' if no command is specified ("tmux \;"). --- cmd.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cmd.c b/cmd.c index fc87558d..68dd06a3 100644 --- a/cmd.c +++ b/cmd.c @@ -108,8 +108,10 @@ cmd_parse(int argc, char **argv, char **cause) int opt; *cause = NULL; - if (argc == 0) + if (argc == 0) { + xasprintf(cause, "no command"); return (NULL); + } entry = NULL; for (entryp = cmd_table; *entryp != NULL; entryp++) { From 74749e8705a49ddda7a742f44bae5865be3f7a70 Mon Sep 17 00:00:00 2001 From: Ray Lai Date: Fri, 5 Jun 2009 03:13:16 +0000 Subject: [PATCH 0035/1180] Remove trailing newlines, spaces, and tabs. No binary change. --- cmd-attach-session.c | 1 - cmd-rotate-window.c | 2 +- grid.c | 2 -- names.c | 1 - screen-write.c | 8 ++++---- tty-term.c | 1 - tty-write.c | 1 - 7 files changed, 5 insertions(+), 11 deletions(-) diff --git a/cmd-attach-session.c b/cmd-attach-session.c index 1de4eba6..1f0bb517 100644 --- a/cmd-attach-session.c +++ b/cmd-attach-session.c @@ -77,4 +77,3 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx) return (1); } - diff --git a/cmd-rotate-window.c b/cmd-rotate-window.c index b7ac341d..39605b64 100644 --- a/cmd-rotate-window.c +++ b/cmd-rotate-window.c @@ -72,7 +72,7 @@ cmd_rotate_window_exec(struct cmd *self, struct cmd_ctx *ctx) TAILQ_INSERT_HEAD(&w->panes, wp, entry); xoff = wp->xoff; yoff = wp->yoff; - sx = wp->sx; sy = wp->sy; + sx = wp->sx; sy = wp->sy; flags = w->flags; TAILQ_FOREACH(wp, &w->panes, entry) { if ((wp2 = TAILQ_NEXT(wp, entry)) == NULL) diff --git a/grid.c b/grid.c index 461d92ea..71761afe 100644 --- a/grid.c +++ b/grid.c @@ -493,5 +493,3 @@ grid_move_cells(struct grid *gd, u_int dx, u_int px, u_int py, u_int nx) grid_put_cell(gd, xx, py, &grid_default_cell); } } - - diff --git a/names.c b/names.c index 00c79fee..e4afa70f 100644 --- a/names.c +++ b/names.c @@ -107,4 +107,3 @@ parse_window_name(const char *in) xfree(copy); return (name); } - diff --git a/screen-write.c b/screen-write.c index d7d56d97..f0cdec30 100644 --- a/screen-write.c +++ b/screen-write.c @@ -89,7 +89,7 @@ screen_write_strlen(int utf8flag, const char *fmt, ...) size++; ptr++; } - } + } return (size); } @@ -148,7 +148,7 @@ screen_write_vnputs(struct screen_write_ctx *ctx, ssize_t maxlen, *utf8buf = *ptr; ptr++; } - + width = utf8_width(utf8buf); if (maxlen > 0 && size + width > (size_t) maxlen) { while (size < (size_t) maxlen) { @@ -301,12 +301,12 @@ screen_write_alignmenttest(struct screen_write_ctx *ctx) memcpy(&gc, &grid_default_cell, sizeof gc); gc.data = 'E'; - + for (yy = 0; yy < screen_size_y(s); yy++) { for (xx = 0; xx < screen_size_x(s); xx++) grid_view_set_cell(s->grid, xx, yy, &gc); } - + s->cx = 0; s->cy = 0; diff --git a/tty-term.c b/tty-term.c index 200cc020..e7aced73 100644 --- a/tty-term.c +++ b/tty-term.c @@ -390,4 +390,3 @@ tty_term_flag(struct tty_term *term, enum tty_code_code code) log_fatalx("not a flag: %d", code); return (term->codes[code].value.flag); } - diff --git a/tty-write.c b/tty-write.c index 46cb8e8c..83aeea75 100644 --- a/tty-write.c +++ b/tty-write.c @@ -88,4 +88,3 @@ tty_write_mode(struct window_pane *wp, int mode) tty_update_mode(&c->tty, mode); } } - From 1156467726a21f2126e0b382223118298c623b22 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 5 Jun 2009 07:15:58 +0000 Subject: [PATCH 0036/1180] Call setproctitle earlier in the client, and include the socket name. Makes it easier to match client to server in ps/pgrep when using several servers. --- client.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/client.c b/client.c index 12041eed..226f22fe 100644 --- a/client.c +++ b/client.c @@ -46,6 +46,11 @@ client_init(char *path, struct client_ctx *cctx, int start_server, int flags) int mode; struct buffer *b; char *name; + char rpathbuf[MAXPATHLEN]; + + if (realpath(path, rpathbuf) == NULL) + strlcpy(rpathbuf, path, sizeof rpathbuf); + setproctitle("client (%s)", rpathbuf); if (lstat(path, &sb) != 0) { if (start_server && errno == ENOENT) { @@ -135,7 +140,6 @@ client_main(struct client_ctx *cctx) siginit(); logfile("client"); - setproctitle("client"); error = NULL; xtimeout = INFTIM; From a3c32841e631590d26884731acd8f44a32516054 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 5 Jun 2009 07:18:37 +0000 Subject: [PATCH 0037/1180] strdup the input to putenv to avoid in one case passing a string that is later freed and in the other const strings. looks sane to millert, ok ray --- cmd-string.c | 2 +- window.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd-string.c b/cmd-string.c index 1e471081..a5c5dd12 100644 --- a/cmd-string.c +++ b/cmd-string.c @@ -63,7 +63,7 @@ cmd_string_parse(const char *s, struct cmd_list **cmdlist, char **cause) if ((t = strchr(s, ' ')) == NULL && (t = strchr(s, '\t')) == NULL) t = strchr(s, '\0'); if ((u = strchr(s, '=')) != NULL && u < t) { - if (putenv((char *) s) != 0) { + if (putenv(xstrdup(s)) != 0) { xasprintf(cause, "assignment failed: %s", s); return (-1); } diff --git a/window.c b/window.c index 06733201..aeed4bc9 100644 --- a/window.c +++ b/window.c @@ -473,7 +473,7 @@ window_pane_spawn(struct window_pane *wp, if (chdir(wp->cwd) != 0) chdir("/"); for (envq = envp; *envq != NULL; envq++) { - if (putenv((char *) *envq) != 0) + if (putenv(xstrdup(*envq)) != 0) fatal("putenv failed"); } sigreset(); From 18665b8cc90904db87c454346a3234488bb6a813 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 5 Jun 2009 07:22:23 +0000 Subject: [PATCH 0038/1180] Check the first of LC_CTYPE, LC_ALL and LANG, rather than just the last, when trying to decide about UTF-8, and use strcasestr. Reported by Geert Hendrickx. --- tmux.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tmux.c b/tmux.c index 3dccbf1b..88f76780 100644 --- a/tmux.c +++ b/tmux.c @@ -326,12 +326,17 @@ main(int argc, char **argv) if (!(flags & IDENTIFY_UTF8)) { /* - * If the user has set LANG to contain UTF-8, it is a safe + * If the user has set whichever of LC_ALL, LC_CTYPE or LANG + * exist (in that order) to contain UTF-8, it is a safe * assumption that either they are using a UTF-8 terminal, or * if not they know that output from UTF-8-capable programs may * be wrong. */ - if ((s = getenv("LANG")) != NULL && strstr(s, "UTF-8") != NULL) + if ((s = getenv("LC_CTYPE")) == NULL) { + if ((s = getenv("LC_ALL")) == NULL) + s = getenv("LANG"); + } + if (s != NULL && strcasestr(s, "UTF-8") != NULL) flags |= IDENTIFY_UTF8; } From 89262c62fe6c49e87f62acfcbb02edc8c8afaf17 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 5 Jun 2009 11:14:13 +0000 Subject: [PATCH 0039/1180] Terminate cwd buffer before running xstrdup on it. --- server-msg.c | 1 + 1 file changed, 1 insertion(+) diff --git a/server-msg.c b/server-msg.c index 5eaa04db..ef01e100 100644 --- a/server-msg.c +++ b/server-msg.c @@ -196,6 +196,7 @@ server_msg_fn_identify(struct hdr *hdr, struct client *c) c->tty.sy = data.sy; c->cwd = NULL; + data.cwd[(sizeof data.cwd) - 1] = '\0'; if (*data.cwd != '\0') c->cwd = xstrdup(data.cwd); From c2b0fdae5b8b3bb3c0ac79f890e180672af27bb3 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 23 Jun 2009 18:27:40 +0000 Subject: [PATCH 0040/1180] LC_ALL overrides LC_CTYPE and LANG. Comment was correct but the code wrong. Pointed out by Hannah Schroeter, thanks. --- tmux.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tmux.c b/tmux.c index 88f76780..ee05cc19 100644 --- a/tmux.c +++ b/tmux.c @@ -332,8 +332,8 @@ main(int argc, char **argv) * if not they know that output from UTF-8-capable programs may * be wrong. */ - if ((s = getenv("LC_CTYPE")) == NULL) { - if ((s = getenv("LC_ALL")) == NULL) + if ((s = getenv("LC_ALL")) == NULL) { + if ((s = getenv("LC_CTYPE")) == NULL) s = getenv("LANG"); } if (s != NULL && strcasestr(s, "UTF-8") != NULL) From 69f3c24647b2e8c2558a5dc1b4abd82f9e75bf91 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 23 Jun 2009 20:17:30 +0000 Subject: [PATCH 0041/1180] If a pane is "zombified" (remain-on-exit flag), don't continue to queue key and mouse input for it (otherwise they are processed after respawn). --- window.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/window.c b/window.c index aeed4bc9..b3dcd0f1 100644 --- a/window.c +++ b/window.c @@ -554,6 +554,9 @@ window_pane_parse(struct window_pane *wp) void window_pane_key(struct window_pane *wp, struct client *c, int key) { + if (wp->fd == -1) + return; + if (wp->mode != NULL) { if (wp->mode->key != NULL) wp->mode->key(wp, c, key); @@ -565,6 +568,9 @@ void window_pane_mouse( struct window_pane *wp, struct client *c, u_char b, u_char x, u_char y) { + if (wp->fd == -1) + return; + /* XXX convert from 1-based? */ if (x < wp->xoff || x >= wp->xoff + wp->sx) From 6d2830a473f8b710fca841f763b461b388630e14 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 23 Jun 2009 22:13:11 +0000 Subject: [PATCH 0042/1180] Add some common config file examples to the quick start section. --- tmux.1 | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/tmux.1 b/tmux.1 index c7a70240..88e4f7b2 100644 --- a/tmux.1 +++ b/tmux.1 @@ -189,6 +189,43 @@ lists the current key bindings in the current window; up and down may be used to navigate the list or .Ql q to exit from it. +.Pp +Commands to be run when the +.Nm +server is started may be placed in the +.Pa ~/.tmux.conf +configuration file. +Common examples include: +.Bl -ohang -width Ds +.It Changing the default prefix key: +.Bd -literal -offset indent +set-option -g prefix C-a +unbind-key C-b +bind-key C-a send-prefix +.Ed +.Pp +.It Xo +Turning the status line off, or changing its colour: +.Xc +.Bd -literal -offset indent +set-option -g status off +set-option -g status-bg blue +.Ed +.Pp +.It Xo +Setting other options, such as the default command, or locking after 30 minutes +of inactivity: +.Xc +.Bd -literal -offset indent +set-option -g default-command "exec /bin/ksh" +set-option -g lock-after-time 1800 +.Ed +.It Creating new key bindings: +.Bd -literal -offset indent +bind-key b set-option status +bind-key / command-prompt "split-window 'exec man %%'" +.Ed +.El .Sh KEY BINDINGS .Nm may be controlled from an attached client by using a key combination of a From 013b88dfc308691c5bbbeca23b567a6e27ebc735 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 23 Jun 2009 23:26:08 +0000 Subject: [PATCH 0043/1180] Mention LC_ALL, LC_CTYPE. --- tmux.1 | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tmux.1 b/tmux.1 index 88e4f7b2..5eb53b5b 100644 --- a/tmux.1 +++ b/tmux.1 @@ -109,10 +109,13 @@ flag is ignored. Unlock the server. .It Fl u .Nm -attempts to guess if the terminal is likely to support UTF-8 by checking -the +attempts to guess if the terminal is likely to support UTF-8 by checking the +first of the +.Ev LC_ALL , +.Ev LC_CTYPE +and .Ev LANG -environment variable for the string "UTF-8". +environment variables to be set for the string "UTF-8". This is not always correct: the .Fl u flag explicitly informs From 27cfa81110c26d2505d50443c330324faa8bf49b Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 24 Jun 2009 05:35:07 +0000 Subject: [PATCH 0044/1180] Constify utf8_width() function argument. --- tmux.h | 2 +- utf8.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tmux.h b/tmux.h index 645e5003..04088a16 100644 --- a/tmux.h +++ b/tmux.h @@ -1521,7 +1521,7 @@ int session_last(struct session *); /* utf8.c */ void utf8_build(void); -int utf8_width(u_char *); +int utf8_width(const u_char *); /* util.c */ char *section_string(char *, size_t, size_t, size_t); diff --git a/utf8.c b/utf8.c index b0e3c3cb..9458d8b2 100644 --- a/utf8.c +++ b/utf8.c @@ -297,7 +297,7 @@ utf8_split(u_int uvalue, u_char *data) } int -utf8_width(u_char *udata) +utf8_width(const u_char *udata) { struct utf8_width_entry *item; u_int uvalue; From 7b4077ef8710aead343ea306d598f457652ba5c0 Mon Sep 17 00:00:00 2001 From: Jason McIntyre Date: Wed, 24 Jun 2009 08:13:22 +0000 Subject: [PATCH 0045/1180] tweak previous; --- tmux.1 | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/tmux.1 b/tmux.1 index 5eb53b5b..4c5203bd 100644 --- a/tmux.1 +++ b/tmux.1 @@ -196,39 +196,35 @@ to exit from it. Commands to be run when the .Nm server is started may be placed in the -.Pa ~/.tmux.conf +.Pa ~/.tmux.conf configuration file. Common examples include: -.Bl -ohang -width Ds -.It Changing the default prefix key: +.Pp +Changing the default prefix key: .Bd -literal -offset indent set-option -g prefix C-a unbind-key C-b bind-key C-a send-prefix .Ed .Pp -.It Xo Turning the status line off, or changing its colour: -.Xc .Bd -literal -offset indent set-option -g status off set-option -g status-bg blue .Ed .Pp -.It Xo -Setting other options, such as the default command, or locking after 30 minutes -of inactivity: -.Xc +Setting other options, such as the default command, +or locking after 30 minutes of inactivity: .Bd -literal -offset indent set-option -g default-command "exec /bin/ksh" set-option -g lock-after-time 1800 .Ed -.It Creating new key bindings: +.Pp +Creating new key bindings: .Bd -literal -offset indent bind-key b set-option status bind-key / command-prompt "split-window 'exec man %%'" .Ed -.El .Sh KEY BINDINGS .Nm may be controlled from an attached client by using a key combination of a From 2de599ac0ec0634282a52711378258e25839bc7f Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 24 Jun 2009 16:01:02 +0000 Subject: [PATCH 0046/1180] Trying to predict the cursor position for UTF-8 output in the same way as for normal eight-bit output is wrong, separate it into a different function. Fixes spacing when mixing UTF-8 with some escape sequences, notably the way w3m does it. --- tmux.h | 1 + tty.c | 23 ++++++++++++++++++----- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/tmux.h b/tmux.h index 04088a16..2052b498 100644 --- a/tmux.h +++ b/tmux.h @@ -994,6 +994,7 @@ void tty_putcode1(struct tty *, enum tty_code_code, int); void tty_putcode2(struct tty *, enum tty_code_code, int, int); void tty_puts(struct tty *, const char *); void tty_putc(struct tty *, u_char); +void tty_pututf8(struct tty *, const struct grid_utf8 *); void tty_init(struct tty *, char *, char *); void tty_start_tty(struct tty *); void tty_stop_tty(struct tty *); diff --git a/tty.c b/tty.c index 3149c8fb..d0c89afd 100644 --- a/tty.c +++ b/tty.c @@ -408,6 +408,23 @@ tty_putc(struct tty *tty, u_char ch) write(tty->log_fd, &ch, 1); } +void +tty_pututf8(struct tty *tty, const struct grid_utf8 *gu) +{ + u_int i, width; + + for (i = 0; i < UTF8_SIZE; i++) { + if (gu->data[i] == 0xff) + break; + buffer_write8(tty->out, gu->data[i]); + if (tty->log_fd != -1) + write(tty->log_fd, &gu->data[i], 1); + } + + width = utf8_width(gu->data); + tty->cx += width; +} + void tty_set_title(struct tty *tty, const char *title) { @@ -912,11 +929,7 @@ tty_cell( } /* Otherwise, write UTF-8. */ - for (i = 0; i < UTF8_SIZE; i++) { - if (gu->data[i] == 0xff) - break; - tty_putc(tty, gu->data[i]); - } + tty_pututf8(tty, gu); } void From da8401d8bee19d9f5394ddef0c7905b6a8ac9932 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 24 Jun 2009 17:36:15 +0000 Subject: [PATCH 0047/1180] Make remain-on-exit work again when there is only one pane left, which was broken sometime during the pane/layout changes. Reported/tested by Iain Morgan, thanks. --- server.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/server.c b/server.c index 67931c99..ae2b071d 100644 --- a/server.c +++ b/server.c @@ -966,7 +966,7 @@ server_check_window_content( return (1); } -/* Check if window still exists.. */ +/* Check if window still exists. */ void server_check_window(struct window *w) { @@ -984,13 +984,18 @@ server_check_window(struct window *w) wp = TAILQ_FIRST(&w->panes); while (wp != NULL) { wq = TAILQ_NEXT(wp, entry); - if (wp->fd != -1) - destroyed = 0; - else if (!flag) { + /* + * If the pane has died and the remain-on-exit flag is not set, + * remove the pane; otherwise, if the flag is set, don't allow + * the window to be destroyed (or it'll close when the last + * pane dies). + */ + if (wp->fd == -1 && !flag) { window_remove_pane(w, wp); server_redraw_window(w); layout_refresh(w, 0); - } + } else + destroyed = 0; wp = wq; } From f4b8f00255eb4e5d1e7b5e989d8dd48f34716c46 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 24 Jun 2009 19:12:44 +0000 Subject: [PATCH 0048/1180] Change to match xterm's resizing behaviour, including pushing lines into the history from the top when reducing vertical size and pulling them again when increasing size. ok todd sthen --- screen.c | 78 +++++++++++++++++++++++++++++++++----------------------- 1 file changed, 46 insertions(+), 32 deletions(-) diff --git a/screen.c b/screen.c index 5c689c8a..a79a7d42 100644 --- a/screen.c +++ b/screen.c @@ -169,38 +169,42 @@ void screen_resize_y(struct screen *s, u_int sy) { struct grid *gd = s->grid; - u_int oy, yy, ny; + u_int needed, available, oldy, i; if (sy == 0) fatalx("zero size"); + oldy = screen_size_y(s); + + /* + * When resizing: + * + * If the height is decreasing, delete lines from the bottom until + * hitting the cursor, then push lines from the top into the history. + * + * When increasing, pull as many lines as possible from the history to + * the top, then fill the remaining with blanks at the bottom. + */ /* Size decreasing. */ - if (sy < screen_size_y(s)) { - oy = screen_size_y(s); + if (sy < oldy) { + needed = oldy - sy; - if (s->cy != 0) { - /* - * The cursor is not at the start. Try to remove as - * many lines as possible from the top. (Up to the - * cursor line.) - */ - ny = s->cy; - if (ny > oy - sy) - ny = oy - sy; - - grid_view_delete_lines(gd, 0, ny); - - s->cy -= ny; - oy -= ny; + /* Delete as many lines as possible from the bottom. */ + available = oldy - 1 - s->cy; + if (available > 0) { + if (available > needed) + available = needed; + grid_view_delete_lines(gd, oldy - available, available); } + needed -= available; - if (sy < oy) { - /* Remove any remaining lines from the bottom. */ - grid_view_delete_lines(gd, sy, oy - sy); - if (s->cy >= sy) - s->cy = sy - 1; - } - } + /* + * Now just increase the history size to take over the lines + * which are left. XXX Should apply history limit? + */ + gd->hsize += needed; + s->cy -= needed; + } /* Resize line arrays. */ gd->size = xrealloc(gd->size, gd->hsize + sy, sizeof *gd->size); @@ -209,18 +213,28 @@ screen_resize_y(struct screen *s, u_int sy) gd->udata = xrealloc(gd->udata, gd->hsize + sy, sizeof *gd->udata); /* Size increasing. */ - if (sy > screen_size_y(s)) { - oy = screen_size_y(s); - for (yy = gd->hsize + oy; yy < gd->hsize + sy; yy++) { - gd->size[yy] = 0; - gd->data[yy] = NULL; - gd->usize[yy] = 0; - gd->udata[yy] = NULL; + if (sy > oldy) { + needed = sy - oldy; + + /* Try to pull as much as possible out of the history. */ + available = gd->hsize; + if (available > 0) { + if (available > needed) + available = needed; + gd->hsize -= available; + s->cy += available; + } + needed -= available; + + /* Then fill the rest in with blanks. */ + for (i = gd->hsize + sy - needed; i < gd->hsize + sy; i++) { + gd->size[i] = gd->usize[i] = 0; + gd->data[i] = gd->udata[i] = NULL; } } + /* Set the new size, and reset the scroll region. */ gd->sy = sy; - s->rupper = 0; s->rlower = screen_size_y(s) - 1; } From 096cbf2ea558c0f66ee7bdaa8316e85c3e55ee69 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 24 Jun 2009 22:04:18 +0000 Subject: [PATCH 0049/1180] Add a dedicated function to convert a line into a string and use it to simplify the search window function. --- grid-view.c | 12 ++++++++++++ grid.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ tmux.h | 2 ++ window.c | 51 +++++++++++++++------------------------------------ 4 files changed, 75 insertions(+), 36 deletions(-) diff --git a/grid-view.c b/grid-view.c index f1224bf6..75dc686a 100644 --- a/grid-view.c +++ b/grid-view.c @@ -209,3 +209,15 @@ grid_view_delete_cells(struct grid *gd, u_int px, u_int py, u_int nx) grid_move_cells(gd, px, px + nx, py, (sx - 1) - (px + nx)); } + +/* Convert cells into a string. */ +char * +grid_view_string_cells(struct grid *gd, u_int px, u_int py, u_int nx) +{ + GRID_DEBUG(gd, "px=%u, py=%u, nx=%u", px, py, nx); + + px = grid_view_x(gd, px); + py = grid_view_y(gd, py); + + return (grid_string_cells(gd, px, py, nx)); +} diff --git a/grid.c b/grid.c index 71761afe..01bf7719 100644 --- a/grid.c +++ b/grid.c @@ -493,3 +493,49 @@ grid_move_cells(struct grid *gd, u_int dx, u_int px, u_int py, u_int nx) grid_put_cell(gd, xx, py, &grid_default_cell); } } + +/* Convert cells into a string. */ +char * +grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx) +{ + const struct grid_cell *gc; + const struct grid_utf8 *gu; + char *buf; + size_t len, off; + u_int xx; + + GRID_DEBUG(gd, "px=%u, py=%u, nx=%u", px, py, nx); + + len = 128; + buf = xmalloc(len); + off = 0; + + for (xx = px; xx < px + nx; xx++) { + gc = grid_peek_cell(gd, xx, py); + if (gc->flags & GRID_FLAG_PADDING) + continue; + + if (gc->flags & GRID_FLAG_UTF8) { + while (len < off + UTF8_SIZE + 1) { + buf = xrealloc(buf, 2, len); + len *= 2; + } + + gu = grid_peek_utf8(gd, xx, py); + memcpy(buf + off, gu->data, UTF8_SIZE); + off += UTF8_SIZE; + while (off > 0 && ((u_char) buf[off]) == 0xff) + off--; + } else { + while (len < off + 2) { + buf = xrealloc(buf, 2, len); + len *= 2; + } + + buf[off++] = gc->data; + } + } + + buf[off] = '\0'; + return (buf); +} diff --git a/tmux.h b/tmux.h index 2052b498..0bab2804 100644 --- a/tmux.h +++ b/tmux.h @@ -1327,6 +1327,7 @@ void grid_clear_lines(struct grid *, u_int, u_int); void grid_move_lines(struct grid *, u_int, u_int, u_int); void grid_clear_cells(struct grid *, u_int, u_int, u_int); void grid_move_cells(struct grid *, u_int, u_int, u_int, u_int); +char *grid_string_cells(struct grid *, u_int, u_int, u_int); /* grid-view.c */ const struct grid_cell *grid_view_peek_cell(struct grid *, u_int, u_int); @@ -1348,6 +1349,7 @@ void grid_view_delete_lines_region( struct grid *, u_int, u_int, u_int, u_int); void grid_view_insert_cells(struct grid *, u_int, u_int, u_int); void grid_view_delete_cells(struct grid *, u_int, u_int, u_int); +char *grid_view_string_cells(struct grid *, u_int, u_int, u_int); /* screen-write.c */ void screen_write_start( diff --git a/window.c b/window.c index b3dcd0f1..91606f53 100644 --- a/window.c +++ b/window.c @@ -590,42 +590,21 @@ window_pane_mouse( char * window_pane_search(struct window_pane *wp, const char *searchstr) { - const struct grid_cell *gc; - const struct grid_utf8 *gu; - char *buf, *s; - size_t off; - u_int i, j, k; + struct screen *s = &wp->base; + char *line, *ptr; + u_int i; - buf = xmalloc(1); - - for (j = 0; j < screen_size_y(&wp->base); j++) { - off = 0; - for (i = 0; i < screen_size_x(&wp->base); i++) { - gc = grid_view_peek_cell(wp->base.grid, i, j); - if (gc->flags & GRID_FLAG_UTF8) { - gu = grid_view_peek_utf8(wp->base.grid, i, j); - buf = xrealloc(buf, 1, off + 8); - for (k = 0; k < UTF8_SIZE; k++) { - if (gu->data[k] == 0xff) - break; - buf[off++] = gu->data[k]; - } - } else { - buf = xrealloc(buf, 1, off + 1); - buf[off++] = gc->data; - } - } - while (off > 0 && buf[off - 1] == ' ') - off--; - buf[off] = '\0'; - - if ((s = strstr(buf, searchstr)) != NULL) { - s = section_string(buf, off, s - buf, 40); - xfree(buf); - return (s); - } + ptr = NULL; + for (i = 0; i < screen_size_y(s); i++) { + line = grid_view_string_cells(s->grid, 0, i, screen_size_x(s)); + log_debug("XXX %s", line); + if ((ptr = strstr(line, searchstr)) != NULL) + break; + xfree(line); } - - xfree(buf); - return (NULL); + if (ptr != NULL) { + ptr = section_string(line, strlen(ptr), ptr - line, 40); + xfree(line); + } + return (ptr); } From 7e796dea035ed7028fc7188e65979725a24ff03d Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 24 Jun 2009 22:49:56 +0000 Subject: [PATCH 0050/1180] Change find-window and monitor-content to use fnmatch(3). For convenience and compatibility, *s are implicitly added at the start and end of the pattern. Also display the line number and the entire line in the results, and lose the nasty section_string function and the now empty util.c file. Initially from Tiago Cunha. --- Makefile | 2 +- cmd-find-window.c | 17 ++++++++++------ grid.c | 15 ++++++++------ server.c | 2 +- tmux.1 | 6 +++++- tmux.h | 7 ++----- util.c | 52 ----------------------------------------------- window.c | 26 ++++++++++++++---------- 8 files changed, 44 insertions(+), 83 deletions(-) delete mode 100644 util.c diff --git a/Makefile b/Makefile index 66204957..26571827 100644 --- a/Makefile +++ b/Makefile @@ -32,7 +32,7 @@ SRCS= arg.c attributes.c buffer-poll.c buffer.c cfg.c client-fn.c \ mode-key.c names.c options-cmd.c options.c paste.c procname.c \ resize.c screen-redraw.c screen-write.c screen.c server-fn.c \ server-msg.c server.c session.c status.c tmux.c tty-keys.c tty-term.c \ - tty-write.c tty.c utf8.c util.c window-choose.c window-clock.c \ + tty-write.c tty.c utf8.c window-choose.c window-clock.c \ window-copy.c window-more.c window-scroll.c window.c xmalloc.c CFLAGS+= -Wno-long-long -Wall -W -Wnested-externs -Wformat=2 diff --git a/cmd-find-window.c b/cmd-find-window.c index 42637168..9458fa8b 100644 --- a/cmd-find-window.c +++ b/cmd-find-window.c @@ -18,6 +18,7 @@ #include +#include #include #include "tmux.h" @@ -58,8 +59,8 @@ cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx) struct window_pane *wp; ARRAY_DECL(, u_int) list_idx; ARRAY_DECL(, char *) list_ctx; - char *sres, *sctx; - u_int i; + char *sres, *sctx, *searchstr; + u_int i, line; if (ctx->curclient == NULL) { ctx->error(ctx, "must be run interactively"); @@ -73,17 +74,18 @@ cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx) ARRAY_INIT(&list_idx); ARRAY_INIT(&list_ctx); + xasprintf(&searchstr, "*%s*", data->arg); RB_FOREACH(wm, winlinks, &s->windows) { i = 0; TAILQ_FOREACH(wp, &wm->window->panes, entry) { i++; - if (strstr(wm->window->name, data->arg) != NULL) + if (fnmatch(searchstr, wm->window->name, 0) == 0) sctx = xstrdup(""); else { - sres = window_pane_search(wp, data->arg); + sres = window_pane_search(wp, data->arg, &line); if (sres == NULL && - strstr(wp->base.title, data->arg) == NULL) + fnmatch(searchstr, wp->base.title, 0) != 0) continue; if (sres == NULL) { @@ -91,7 +93,9 @@ cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx) "pane %u title: \"%s\"", i - 1, wp->base.title); } else { - xasprintf(&sctx, "\"%s\"", sres); + xasprintf(&sctx, + "pane %u line %u: \"%s\"", i - 1, + line + 1, sres); xfree(sres); } } @@ -100,6 +104,7 @@ cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx) ARRAY_ADD(&list_ctx, sctx); } } + xfree(searchstr); if (ARRAY_LENGTH(&list_idx) == 0) { ctx->error(ctx, "no windows matching: %s", data->arg); diff --git a/grid.c b/grid.c index 01bf7719..071248ee 100644 --- a/grid.c +++ b/grid.c @@ -502,7 +502,7 @@ grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx) const struct grid_utf8 *gu; char *buf; size_t len, off; - u_int xx; + u_int xx, i; GRID_DEBUG(gd, "px=%u, py=%u, nx=%u", px, py, nx); @@ -522,10 +522,11 @@ grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx) } gu = grid_peek_utf8(gd, xx, py); - memcpy(buf + off, gu->data, UTF8_SIZE); - off += UTF8_SIZE; - while (off > 0 && ((u_char) buf[off]) == 0xff) - off--; + for (i = 0; i < UTF8_SIZE; i++) { + if (gu->data[i] == 0xff) + break; + buf[off++] = gu->data[i]; + } } else { while (len < off + 2) { buf = xrealloc(buf, 2, len); @@ -535,7 +536,9 @@ grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx) buf[off++] = gc->data; } } - + + while (off > 0 && buf[off - 1] == ' ') + off--; buf[off] = '\0'; return (buf); } diff --git a/server.c b/server.c index ae2b071d..b8c80fb3 100644 --- a/server.c +++ b/server.c @@ -959,7 +959,7 @@ server_check_window_content( return (0); if (session_alert_has_window(s, w, WINDOW_CONTENT)) return (0); - if ((found = window_pane_search(wp, ptr)) == NULL) + if ((found = window_pane_search(wp, ptr, NULL)) == NULL) return (0); session_alert_add(s, w, WINDOW_CONTENT); xfree(found); diff --git a/tmux.1 b/tmux.1 index 4c5203bd..9bba3874 100644 --- a/tmux.1 +++ b/tmux.1 @@ -664,7 +664,9 @@ Move down a pane. .Ar match-string .Xc .D1 (alias: Ic findw ) -Search for +Search for the +.Xr fnmatch 3 +pattern .Ar match-string in window names, titles, and visible content (but not history). If only one window is matched, it'll be automatically selected, otherwise a @@ -1316,6 +1318,8 @@ Windows with activity are highlighted in the status line. .Xc Monitor content in the window. When +.Xr fnmatch 3 +pattern .Ar match-string appears in the window, it is highlighted in the status line. .It Xo Ic remain-on-exit diff --git a/tmux.h b/tmux.h index 0bab2804..ba8fdd1d 100644 --- a/tmux.h +++ b/tmux.h @@ -1456,7 +1456,8 @@ void window_pane_parse(struct window_pane *); void window_pane_key(struct window_pane *, struct client *, int); void window_pane_mouse(struct window_pane *, struct client *, u_char, u_char, u_char); -char *window_pane_search(struct window_pane *, const char *); +char *window_pane_search( + struct window_pane *, const char *, u_int *); /* layout.c */ const char * layout_name(struct window *); @@ -1526,10 +1527,6 @@ int session_last(struct session *); void utf8_build(void); int utf8_width(const u_char *); -/* util.c */ -char *section_string(char *, size_t, size_t, size_t); -void clean_string(const char *, char *, size_t); - /* procname.c */ char *get_proc_name(int, char *); diff --git a/util.c b/util.c deleted file mode 100644 index 5c871ca1..00000000 --- a/util.c +++ /dev/null @@ -1,52 +0,0 @@ -/* $OpenBSD$ */ - -/* - * Copyright (c) 2009 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" - -/* Return a section of a string around a point. */ -char * -section_string(char *buf, size_t len, size_t sectoff, size_t sectlen) -{ - char *s; - size_t first, last; - - if (len <= sectlen) { - first = 0; - last = len; - } else if (sectoff < sectlen / 2) { - first = 0; - last = sectlen; - } else if (sectoff + sectlen / 2 > len) { - last = len; - first = last - sectlen; - } else { - first = sectoff - sectlen / 2; - last = first + sectlen; - } - - if (last - first > 3 && first != 0) - first += 3; - if (last - first > 3 && last != len) - last -= 3; - - xasprintf(&s, "%s%.*s%s", first == 0 ? "" : "...", - (int) (last - first), buf + first, last == len ? "" : "..."); - return (s); -} diff --git a/window.c b/window.c index 91606f53..834f1248 100644 --- a/window.c +++ b/window.c @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -588,23 +589,26 @@ window_pane_mouse( } char * -window_pane_search(struct window_pane *wp, const char *searchstr) +window_pane_search(struct window_pane *wp, const char *searchstr, u_int *lineno) { struct screen *s = &wp->base; - char *line, *ptr; + char *newsearchstr, *line, *msg; u_int i; - ptr = NULL; + msg = NULL; + xasprintf(&newsearchstr, "*%s*", searchstr); + for (i = 0; i < screen_size_y(s); i++) { line = grid_view_string_cells(s->grid, 0, i, screen_size_x(s)); - log_debug("XXX %s", line); - if ((ptr = strstr(line, searchstr)) != NULL) - break; + if (fnmatch(newsearchstr, line, 0) == 0) { + msg = line; + if (lineno != NULL) + *lineno = i; + break; + } xfree(line); } - if (ptr != NULL) { - ptr = section_string(line, strlen(ptr), ptr - line, 40); - xfree(line); - } - return (ptr); + + xfree(newsearchstr); + return (msg); } From 3db2433448c4084fc6b46ded52e9d8c8fc377d1c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 24 Jun 2009 22:51:47 +0000 Subject: [PATCH 0051/1180] Fix a type mismatch warning in assignment. --- screen.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/screen.c b/screen.c index a79a7d42..fb625aa9 100644 --- a/screen.c +++ b/screen.c @@ -228,8 +228,10 @@ screen_resize_y(struct screen *s, u_int sy) /* Then fill the rest in with blanks. */ for (i = gd->hsize + sy - needed; i < gd->hsize + sy; i++) { - gd->size[i] = gd->usize[i] = 0; - gd->data[i] = gd->udata[i] = NULL; + gd->size[i] = 0; + gd->data[i] = NULL; + gd->usize[i] = 0; + gd->udata[i] = NULL; } } From 23326e40cfe260bf7a30a99a653d8ec1ca5a625f Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 24 Jun 2009 23:00:31 +0000 Subject: [PATCH 0052/1180] Now that a UTF-8-capable puts function exists, use it for printing strings in choice/more modes - lines with UTF-8 now display properly in find-window results. --- window-choose.c | 7 ++++--- window-more.c | 6 ++++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/window-choose.c b/window-choose.c index 5470a7e8..f199b847 100644 --- a/window-choose.c +++ b/window-choose.c @@ -285,10 +285,12 @@ window_choose_write_line( struct window_choose_mode_item *item; struct screen *s = &data->screen; struct grid_cell gc; + int utf8flag; if (data->callback == NULL) fatalx("called before callback assigned"); + utf8flag = options_get_number(&wp->window->options, "utf8"); memcpy(&gc, &grid_default_cell, sizeof gc); if (data->selected == data->top + py) { gc.fg = options_get_number(&wp->window->options, "mode-bg"); @@ -299,12 +301,11 @@ window_choose_write_line( screen_write_cursormove(ctx, 0, py); if (data->top + py < ARRAY_LENGTH(&data->list)) { item = &ARRAY_ITEM(&data->list, data->top + py); - screen_write_puts( - ctx, &gc, "%.*s", (int) screen_size_x(s), item->name); + screen_write_nputs( + ctx, screen_size_x(s) - 1, &gc, utf8flag, "%s", item->name); } while (s->cx < screen_size_x(s)) screen_write_putc(ctx, &gc, ' '); - } void diff --git a/window-more.c b/window-more.c index b09cc23c..721dac3d 100644 --- a/window-more.c +++ b/window-more.c @@ -175,7 +175,9 @@ window_more_write_line( struct grid_cell gc; char *msg, hdr[32]; size_t size; + int utf8flag; + utf8flag = options_get_number(&wp->window->options, "utf8"); memcpy(&gc, &grid_default_cell, sizeof gc); if (py == 0) { @@ -193,8 +195,8 @@ window_more_write_line( screen_write_cursormove(ctx, 0, py); if (data->top + py < ARRAY_LENGTH(&data->list)) { msg = ARRAY_ITEM(&data->list, data->top + py); - screen_write_puts( - ctx, &gc, "%.*s", (int) (screen_size_x(s) - size), msg); + screen_write_nputs( + ctx, screen_size_x(s) - 1 - size, &gc, utf8flag, "%s", msg); } while (s->cx < screen_size_x(s) - size) screen_write_putc(ctx, &gc, ' '); From 74d0851ac5975a0dbaceb274056e518ca3e0b905 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 24 Jun 2009 23:32:18 +0000 Subject: [PATCH 0053/1180] Remove some cruft from the Makefile. --- Makefile | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Makefile b/Makefile index 26571827..ecbca212 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,5 @@ # $OpenBSD$ -.PATH: ${.CURDIR}/.. - PROG= tmux SRCS= arg.c attributes.c buffer-poll.c buffer.c cfg.c client-fn.c \ client-msg.c client.c clock.c cmd-attach-session.c cmd-bind-key.c \ @@ -43,6 +41,4 @@ CFLAGS+= -Wundef -Wbad-function-cast -Winline -Wcast-align LDADD= -lutil -lncurses DPADD= ${LIBUTIL} -MAN= tmux.1 - .include From 83078bdcbcc845ea56cf05374190d2115c06dfcb Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 25 Jun 2009 05:56:44 +0000 Subject: [PATCH 0054/1180] Unused variables. Found by lint, no binary change. --- screen-redraw.c | 2 -- tty.c | 4 +--- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/screen-redraw.c b/screen-redraw.c index 06033436..b95a5928 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -67,7 +67,6 @@ screen_redraw_screen(struct client *c) struct window *w = c->session->curw->window; struct tty *tty = &c->tty; struct window_pane *wp; - struct screen *s; u_int i, j, sx, sy; int status, has_acs; u_char choriz, cvert, cbackg; @@ -110,7 +109,6 @@ screen_redraw_screen(struct client *c) tty_reset(tty); - s = wp->screen; sx = wp->sx; sy = wp->sy; diff --git a/tty.c b/tty.c index d0c89afd..1a9307c5 100644 --- a/tty.c +++ b/tty.c @@ -759,9 +759,7 @@ tty_cmd_clearendofscreen( struct tty *tty, struct window_pane *wp, unused va_list ap) { struct screen *s = wp->screen; - u_int i, j, oy; - - oy = wp->yoff; + u_int i, j; tty_reset(tty); From 9144d308484e85d757592698dbce3a7b4cfeee53 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 25 Jun 2009 06:00:45 +0000 Subject: [PATCH 0055/1180] Unused prototypes. Found by lint, no binary change. --- cfg.c | 1 - cmd-clear-history.c | 1 - cmd-lock-server.c | 2 -- cmd-set-window-option.c | 5 ----- 4 files changed, 9 deletions(-) diff --git a/cfg.c b/cfg.c index e4278e14..fa5e1b05 100644 --- a/cfg.c +++ b/cfg.c @@ -30,7 +30,6 @@ * argv array and executed as a command. */ -char *cfg_string(FILE *, char, int); void printflike2 cfg_print(struct cmd_ctx *, const char *, ...); void printflike2 cfg_error(struct cmd_ctx *, const char *, ...); diff --git a/cmd-clear-history.c b/cmd-clear-history.c index 0c08f9b5..4399c6c2 100644 --- a/cmd-clear-history.c +++ b/cmd-clear-history.c @@ -24,7 +24,6 @@ * Clear pane history. */ -void cmd_clear_history_init(struct cmd *, int); int cmd_clear_history_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_clear_history_entry = { diff --git a/cmd-lock-server.c b/cmd-lock-server.c index 5dac3292..74b7b622 100644 --- a/cmd-lock-server.c +++ b/cmd-lock-server.c @@ -30,8 +30,6 @@ int cmd_lock_server_exec(struct cmd *, struct cmd_ctx *); -int cmd_lock_server_callback(void *, const char *); - const struct cmd_entry cmd_lock_server_entry = { "lock-server", "lock", "", diff --git a/cmd-set-window-option.c b/cmd-set-window-option.c index 8d17498e..cc9bf963 100644 --- a/cmd-set-window-option.c +++ b/cmd-set-window-option.c @@ -27,12 +27,7 @@ * Set a window option. */ -int cmd_set_window_option_parse(struct cmd *, int, char **, char **); int cmd_set_window_option_exec(struct cmd *, struct cmd_ctx *); -void cmd_set_window_option_send(struct cmd *, struct buffer *); -void cmd_set_window_option_recv(struct cmd *, struct buffer *); -void cmd_set_window_option_free(struct cmd *); -size_t cmd_set_window_option_print(struct cmd *, char *, size_t); const struct cmd_entry cmd_set_window_option_entry = { "set-window-option", "setw", From ed8350422e9472b657034367f39ab133f7913862 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 25 Jun 2009 06:05:47 +0000 Subject: [PATCH 0056/1180] Nuke unused buffer functions. Found by lint. Also remove some old debug output which was #if 0. --- buffer-poll.c | 43 -------------------------- buffer.c | 85 --------------------------------------------------- tmux.h | 10 ------ 3 files changed, 138 deletions(-) diff --git a/buffer-poll.c b/buffer-poll.c index 4dd4d234..cb645194 100644 --- a/buffer-poll.c +++ b/buffer-poll.c @@ -23,37 +23,17 @@ #include "tmux.h" -/* Set up pollfd for buffers. */ -void -buffer_set( - struct pollfd *pfd, int fd, unused struct buffer *in, struct buffer *out) -{ - pfd->fd = fd; - pfd->events = POLLIN; - if (BUFFER_USED(out) > 0) - pfd->events |= POLLOUT; -} - /* Fill buffers from socket based on poll results. */ int buffer_poll(struct pollfd *pfd, struct buffer *in, struct buffer *out) { ssize_t n; -#if 0 - log_debug("buffer_poll (%ld): fd=%d, revents=%d; out=%zu in=%zu", - (long) getpid(), - pfd->fd, pfd->revents, BUFFER_USED(out), BUFFER_USED(in)); -#endif - if (pfd->revents & (POLLERR|POLLNVAL|POLLHUP)) return (-1); if (pfd->revents & POLLIN) { buffer_ensure(in, BUFSIZ); n = read(pfd->fd, BUFFER_IN(in), BUFFER_FREE(in)); -#if 0 - log_debug("buffer_poll: fd=%d, read=%zd", pfd->fd, n); -#endif if (n == 0) return (-1); if (n == -1) { @@ -64,9 +44,6 @@ buffer_poll(struct pollfd *pfd, struct buffer *in, struct buffer *out) } if (BUFFER_USED(out) > 0 && pfd->revents & POLLOUT) { n = write(pfd->fd, BUFFER_OUT(out), BUFFER_USED(out)); -#if 0 - log_debug("buffer_poll: fd=%d, write=%zd", pfd->fd, n); -#endif if (n == -1) { if (errno != EINTR && errno != EAGAIN) return (-1); @@ -75,23 +52,3 @@ buffer_poll(struct pollfd *pfd, struct buffer *in, struct buffer *out) } return (0); } - -/* Flush buffer output to socket. */ -void -buffer_flush(int fd, struct buffer *in, struct buffer *out) -{ - struct pollfd pfd; - - while (BUFFER_USED(out) > 0) { - buffer_set(&pfd, fd, in, out); - - if (poll(&pfd, 1, INFTIM) == -1) { - if (errno == EAGAIN || errno == EINTR) - continue; - fatal("poll failed"); - } - - if (buffer_poll(&pfd, in, out) != 0) - break; - } -} diff --git a/buffer.c b/buffer.c index eea1fce7..f52d6352 100644 --- a/buffer.c +++ b/buffer.c @@ -47,14 +47,6 @@ buffer_destroy(struct buffer *b) xfree(b); } -/* Empty a buffer. */ -void -buffer_clear(struct buffer *b) -{ - b->size = 0; - b->off = 0; -} - /* Ensure free space for size in buffer. */ void buffer_ensure(struct buffer *b, size_t size) @@ -91,18 +83,6 @@ buffer_add(struct buffer *b, size_t size) b->size += size; } -/* Reverse buffer add. */ -void -buffer_reverse_add(struct buffer *b, size_t size) -{ - if (size == 0) - fatalx("zero size"); - if (size > b->size) - fatalx("underflow"); - - b->size -= size; -} - /* Adjust buffer after data removed. */ void buffer_remove(struct buffer *b, size_t size) @@ -116,50 +96,6 @@ buffer_remove(struct buffer *b, size_t size) b->off += size; } -/* Reverse buffer remove. */ -void -buffer_reverse_remove(struct buffer *b, size_t size) -{ - if (size == 0) - fatalx("zero size"); - if (size > b->off) - fatalx("overflow"); - - b->size += size; - b->off -= size; -} - -/* Insert a section into the buffer. */ -void -buffer_insert_range(struct buffer *b, size_t base, size_t size) -{ - if (size == 0) - fatalx("zero size"); - if (base > b->size) - fatalx("range outside buffer"); - - buffer_ensure(b, size); - memmove(b->base + b->off + base + size, - b->base + b->off + base, b->size - base); - b->size += size; -} - -/* Delete a section from the buffer. */ -void -buffer_delete_range(struct buffer *b, size_t base, size_t size) -{ - if (size == 0) - fatalx("zero size"); - if (size > b->size) - fatalx("size too big"); - if (base + size > b->size) - fatalx("range outside buffer"); - - memmove(b->base + b->off + base, - b->base + b->off + base + size, b->size - base - size); - b->size -= size; -} - /* Copy data into a buffer. */ void buffer_write(struct buffer *b, const void *data, size_t size) @@ -194,16 +130,6 @@ buffer_write8(struct buffer *b, uint8_t n) buffer_add(b, 1); } -/* Store a 16-bit value. */ -void -buffer_write16(struct buffer *b, uint16_t n) -{ - buffer_ensure(b, 2); - BUFFER_IN(b)[0] = n & 0xff; - BUFFER_IN(b)[1] = n >> 8; - buffer_add(b, 2); -} - /* Extract an 8-bit value. */ uint8_t buffer_read8(struct buffer *b) @@ -214,14 +140,3 @@ buffer_read8(struct buffer *b) buffer_remove(b, 1); return (n); } - -/* Extract a 16-bit value. */ -uint16_t -buffer_read16(struct buffer *b) -{ - uint16_t n; - - n = BUFFER_OUT(b)[0] | (BUFFER_OUT(b)[1] << 8); - buffer_remove(b, 2); - return (n); -} diff --git a/tmux.h b/tmux.h index ba8fdd1d..48c54c91 100644 --- a/tmux.h +++ b/tmux.h @@ -1533,26 +1533,16 @@ char *get_proc_name(int, char *); /* buffer.c */ struct buffer *buffer_create(size_t); void buffer_destroy(struct buffer *); -void buffer_clear(struct buffer *); void buffer_ensure(struct buffer *, size_t); void buffer_add(struct buffer *, size_t); -void buffer_reverse_add(struct buffer *, size_t); void buffer_remove(struct buffer *, size_t); -void buffer_reverse_remove(struct buffer *, size_t); -void buffer_insert_range(struct buffer *, size_t, size_t); -void buffer_delete_range(struct buffer *, size_t, size_t); void buffer_write(struct buffer *, const void *, size_t); void buffer_read(struct buffer *, void *, size_t); void buffer_write8(struct buffer *, uint8_t); -void buffer_write16(struct buffer *, uint16_t); uint8_t buffer_read8(struct buffer *); -uint16_t buffer_read16(struct buffer *); /* buffer-poll.c */ -void buffer_set( - struct pollfd *, int, struct buffer *, struct buffer *); int buffer_poll(struct pollfd *, struct buffer *, struct buffer *); -void buffer_flush(int, struct buffer *n, struct buffer *); /* log.c */ #define LOG_FACILITY LOG_DAEMON From 1675ddb4d1880b834a2bd0bbae5a9ffa17eb596d Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 25 Jun 2009 06:15:04 +0000 Subject: [PATCH 0057/1180] Miscellaneous unused functions, including one which was basically a duplicate. Found by lint. --- grid.c | 25 ------------------------- server-fn.c | 16 ---------------- tmux.h | 8 -------- tty-write.c | 25 ------------------------- tty.c | 10 ---------- utf8.c | 23 ----------------------- window-more.c | 10 ---------- window.c | 15 --------------- 8 files changed, 132 deletions(-) diff --git a/grid.c b/grid.c index 071248ee..2df28fd7 100644 --- a/grid.c +++ b/grid.c @@ -430,31 +430,6 @@ grid_move_lines(struct grid *gd, u_int dy, u_int py, u_int ny) } } -/* Clear a group of cells. */ -void -grid_clear_cells(struct grid *gd, u_int px, u_int py, u_int nx) -{ - u_int xx; - - GRID_DEBUG(gd, "px=%u, py=%u, nx=%u", px, py, nx); - - if (nx == 0) - return; - - if (grid_check_x(gd, px) != 0) - return; - if (grid_check_x(gd, px + nx - 1) != 0) - return; - if (grid_check_y(gd, py) != 0) - return; - - for (xx = px; xx < px + nx; xx++) { - if (xx >= gd->size[py]) - break; - grid_put_cell(gd, xx, py, &grid_default_cell); - } -} - /* Move a group of cells. */ void grid_move_cells(struct grid *gd, u_int dx, u_int px, u_int py, u_int nx) diff --git a/server-fn.c b/server-fn.c index 69926d8e..a025bf0a 100644 --- a/server-fn.c +++ b/server-fn.c @@ -75,22 +75,6 @@ server_write_session( } } -void -server_write_window( - struct window *w, enum hdrtype type, const void *buf, size_t len) -{ - struct client *c; - u_int i; - - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - c = ARRAY_ITEM(&clients, i); - if (c == NULL || c->session == NULL) - continue; - if (c->session->curw->window == w) - server_write_client(c, type, buf, len); - } -} - void server_redraw_client(struct client *c) { diff --git a/tmux.h b/tmux.h index 48c54c91..bd941887 100644 --- a/tmux.h +++ b/tmux.h @@ -1007,8 +1007,6 @@ void tty_redraw_region(struct tty *, struct window_pane *); int tty_open(struct tty *, char **); void tty_close(struct tty *, int); void tty_free(struct tty *, int); -void tty_write( - struct tty *, struct window_pane *, enum tty_cmd, ...); void tty_vwrite( struct tty *, struct window_pane *, enum tty_cmd, va_list); @@ -1034,7 +1032,6 @@ int tty_keys_next(struct tty *, int *, u_char *); /* tty-write.c */ void tty_write_cmd(struct window_pane *, enum tty_cmd, ...); -void tty_write_mode(struct window_pane *, int); /* options-cmd.c */ void set_option_string(struct cmd_ctx *, @@ -1263,8 +1260,6 @@ void server_write_client( struct client *, enum hdrtype, const void *, size_t); void server_write_session( struct session *, enum hdrtype, const void *, size_t); -void server_write_window( - struct window *, enum hdrtype, const void *, size_t); void server_redraw_client(struct client *); void server_status_client(struct client *); void server_redraw_session(struct session *); @@ -1325,7 +1320,6 @@ void grid_set_utf8(struct grid *, u_int, u_int, const struct grid_utf8 *); void grid_clear(struct grid *, u_int, u_int, u_int, u_int); void grid_clear_lines(struct grid *, u_int, u_int); void grid_move_lines(struct grid *, u_int, u_int, u_int); -void grid_clear_cells(struct grid *, u_int, u_int, u_int); void grid_move_cells(struct grid *, u_int, u_int, u_int, u_int); char *grid_string_cells(struct grid *, u_int, u_int, u_int); @@ -1439,7 +1433,6 @@ void window_set_active_pane(struct window *, struct window_pane *); struct window_pane *window_add_pane(struct window *, int, const char *, const char *, const char **, u_int, char **); void window_remove_pane(struct window *, struct window_pane *); -u_int window_index_of_pane(struct window *, struct window_pane *); struct window_pane *window_pane_at_index(struct window *, u_int); u_int window_count_panes(struct window *); void window_destroy_panes(struct window *); @@ -1486,7 +1479,6 @@ void window_scroll_pageup(struct window_pane *); /* window-more.c */ extern const struct window_mode window_more_mode; void window_more_vadd(struct window_pane *, const char *, va_list); -void printflike2 window_more_add(struct window_pane *, const char *, ...); /* window-choose.c */ extern const struct window_mode window_choose_mode; diff --git a/tty-write.c b/tty-write.c index 83aeea75..889075b2 100644 --- a/tty-write.c +++ b/tty-write.c @@ -63,28 +63,3 @@ tty_vwrite_cmd(struct window_pane *wp, enum tty_cmd cmd, va_list ap) } } } - -void -tty_write_mode(struct window_pane *wp, int mode) -{ - struct client *c; - u_int i; - - if (wp == NULL) - return; - - if (wp->window->flags & WINDOW_REDRAW || wp->flags & PANE_REDRAW) - return; - if (wp->window->flags & WINDOW_HIDDEN || wp->flags & PANE_HIDDEN) - return; - - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - c = ARRAY_ITEM(&clients, i); - if (c == NULL || c->session == NULL) - continue; - if (c->flags & CLIENT_SUSPENDED) - continue; - - tty_update_mode(&c->tty, mode); - } -} diff --git a/tty.c b/tty.c index 1a9307c5..459db0a4 100644 --- a/tty.c +++ b/tty.c @@ -546,16 +546,6 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int py, u_int ox, u_int oy) } } -void -tty_write(struct tty *tty, struct window_pane *wp, enum tty_cmd cmd, ...) -{ - va_list ap; - - va_start(ap, cmd); - tty_vwrite(tty, wp, cmd, ap); - va_end(ap); -} - void tty_vwrite( struct tty *tty, struct window_pane *wp, enum tty_cmd cmd, va_list ap) diff --git a/utf8.c b/utf8.c index 9458d8b2..9b499d1c 100644 --- a/utf8.c +++ b/utf8.c @@ -198,7 +198,6 @@ struct utf8_width_entry *utf8_width_root = NULL; int utf8_overlap(struct utf8_width_entry *, struct utf8_width_entry *); void utf8_print(struct utf8_width_entry *, int); u_int utf8_combine(const u_char *); -void utf8_split(u_int, u_char *); int utf8_overlap( @@ -274,28 +273,6 @@ utf8_combine(const u_char *data) return (uvalue); } -void -utf8_split(u_int uvalue, u_char *data) -{ - memset(data, 0xff, 4); - - if (uvalue <= 0x7f) - data[0] = uvalue; - else if (uvalue > 0x7f && uvalue <= 0x7ff) { - data[0] = (uvalue >> 6) | 0xc0; - data[1] = (uvalue & 0x3f) | 0x80; - } else if (uvalue > 0x7ff && uvalue <= 0xffff) { - data[0] = (uvalue >> 12) | 0xe0; - data[1] = ((uvalue >> 6) & 0x3f) | 0x80; - data[2] = (uvalue & 0x3f) | 0x80; - } else if (uvalue > 0xffff && uvalue <= 0x10ffff) { - data[0] = (uvalue >> 18) | 0xf0; - data[1] = ((uvalue >> 12) & 0x3f) | 0x80; - data[2] = ((uvalue >> 6) & 0x3f) | 0x80; - data[3] = (uvalue & 0x3f) | 0x80; - } -} - int utf8_width(const u_char *udata) { diff --git a/window-more.c b/window-more.c index 721dac3d..6f75f120 100644 --- a/window-more.c +++ b/window-more.c @@ -75,16 +75,6 @@ window_more_vadd(struct window_pane *wp, const char *fmt, va_list ap) screen_write_stop(&ctx); } -void printflike2 -window_more_add(struct window_pane *wp, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - window_more_vadd(wp, fmt, ap); - va_end(ap); -} - struct screen * window_more_init(struct window_pane *wp) { diff --git a/window.c b/window.c index 834f1248..37e65d83 100644 --- a/window.c +++ b/window.c @@ -327,21 +327,6 @@ window_remove_pane(struct window *w, struct window_pane *wp) window_pane_destroy(wp); } -u_int -window_index_of_pane(struct window *w, struct window_pane *find) -{ - struct window_pane *wp; - u_int n; - - n = 0; - TAILQ_FOREACH(wp, &w->panes, entry) { - if (wp == find) - return (n); - n++; - } - fatalx("unknown pane"); -} - struct window_pane * window_pane_at_index(struct window *w, u_int idx) { From a7075f1c66cf62bc28e715238099c7bd7aa5aeaa Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 25 Jun 2009 06:23:10 +0000 Subject: [PATCH 0058/1180] tmux doesn't and won't need syslog logging, so remove it and some other unused functions found by lint. Also move a couple of internal function declarations into file scope. --- log.c | 32 ++++---------------------------- tmux.h | 5 ----- 2 files changed, 4 insertions(+), 33 deletions(-) diff --git a/log.c b/log.c index b4a612d5..d0efaee1 100644 --- a/log.c +++ b/log.c @@ -29,9 +29,8 @@ /* Logging type. */ #define LOG_TYPE_OFF 0 -#define LOG_TYPE_SYSLOG 1 -#define LOG_TYPE_TTY 2 -#define LOG_TYPE_FILE 3 +#define LOG_TYPE_TTY 1 +#define LOG_TYPE_FILE 2 int log_type = LOG_TYPE_OFF; /* Log file, if needed. */ @@ -40,17 +39,8 @@ FILE *log_file; /* Debug level. */ int log_level; -/* Open logging to syslog. */ -void -log_open_syslog(int level) -{ - log_type = LOG_TYPE_SYSLOG; - log_level = level; - - openlog(__progname, LOG_PID|LOG_NDELAY, LOG_FACILITY); - - tzset(); -} +void log_vwrite(int, const char *, va_list); +__dead void log_vfatal(const char *, va_list); /* Open logging to tty. */ void @@ -91,17 +81,6 @@ log_close(void) log_type = LOG_TYPE_OFF; } -/* Write a log message. */ -void -log_write(int pri, const char *msg, ...) -{ - va_list ap; - - va_start(ap, msg); - log_vwrite(pri, msg, ap); - va_end(ap); -} - /* Write a log message. */ void log_vwrite(int pri, const char *msg, va_list ap) @@ -110,9 +89,6 @@ log_vwrite(int pri, const char *msg, va_list ap) FILE *f = log_file; switch (log_type) { - case LOG_TYPE_SYSLOG: - vsyslog(pri, msg, ap); - break; case LOG_TYPE_TTY: if (pri == LOG_INFO) f = stdout; diff --git a/tmux.h b/tmux.h index bd941887..6ca1254d 100644 --- a/tmux.h +++ b/tmux.h @@ -1537,20 +1537,15 @@ uint8_t buffer_read8(struct buffer *); int buffer_poll(struct pollfd *, struct buffer *, struct buffer *); /* log.c */ -#define LOG_FACILITY LOG_DAEMON -void log_open_syslog(int); void log_open_tty(int); void log_open_file(int, const char *); void log_close(void); -void log_vwrite(int, const char *, va_list); -void log_write(int, const char *, ...); void printflike1 log_warn(const char *, ...); void printflike1 log_warnx(const char *, ...); void printflike1 log_info(const char *, ...); void printflike1 log_debug(const char *, ...); void printflike1 log_debug2(const char *, ...); void printflike1 log_debug3(const char *, ...); -__dead void log_vfatal(const char *, va_list); __dead void log_fatal(const char *, ...); __dead void log_fatalx(const char *, ...); From 40c242a6d530250cc64ab05078581e598f20c314 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 25 Jun 2009 06:40:25 +0000 Subject: [PATCH 0059/1180] Remove error about using -L and -S together which was never displayed as logging wasn't yet enabled, was unnecessary, and contradicted the man page which says using -S will cause -L to be ignored. --- tmux.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/tmux.c b/tmux.c index ee05cc19..915d0acd 100644 --- a/tmux.c +++ b/tmux.c @@ -233,19 +233,11 @@ main(int argc, char **argv) cfg_file = xstrdup(optarg); break; case 'L': - if (path != NULL) { - log_warnx("-L and -S cannot be used together"); - exit(1); - } if (label != NULL) xfree(label); label = xstrdup(optarg); break; case 'S': - if (label != NULL) { - log_warnx("-L and -S cannot be used together"); - exit(1); - } if (path != NULL) xfree(path); path = xstrdup(optarg); From be17ac1eb2d77ddfd23f92825dd7cd10fda87389 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 25 Jun 2009 06:48:23 +0000 Subject: [PATCH 0060/1180] lines variable can be -1 (to be ignored), so should be signed. Found by lint. --- cmd-split-window.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmd-split-window.c b/cmd-split-window.c index 70822f7d..28f42b64 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -141,7 +141,8 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) struct window_pane *wp; const char **env; char *cmd, *cwd, *cause; - u_int hlimit, lines; + u_int hlimit; + int lines; if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL) return (-1); From dbbb297d5fc87f1e9f5bbd050a51f9d56dd0a26c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 25 Jun 2009 06:54:32 +0000 Subject: [PATCH 0061/1180] If getcwd() fails, use the user's home directory, or /, instead of failing with an error. --- tmux.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tmux.c b/tmux.c index 915d0acd..84e5a029 100644 --- a/tmux.c +++ b/tmux.c @@ -371,8 +371,11 @@ main(int argc, char **argv) &global_options, "default-command", "exec %s -l", shell); if (getcwd(cwd, sizeof cwd) == NULL) { - log_warn("getcwd"); - exit(1); + pw = getpwuid(getuid()); + if (pw->pw_dir != NULL && *pw->pw_dir != '\0') + strlcpy(cwd, pw->pw_dir, sizeof cwd); + else + strlcpy(cwd, "/", sizeof cwd); } options_set_string(&global_options, "default-path", "%s", cwd); From 5050171f6b5b7aadbb78a3ed6e039b0f15d21740 Mon Sep 17 00:00:00 2001 From: Marc Espie Date: Thu, 25 Jun 2009 07:42:41 +0000 Subject: [PATCH 0062/1180] diagflags for diags okay nicm@ --- Makefile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index ecbca212..73f543b2 100644 --- a/Makefile +++ b/Makefile @@ -33,10 +33,10 @@ SRCS= arg.c attributes.c buffer-poll.c buffer.c cfg.c client-fn.c \ tty-write.c tty.c utf8.c window-choose.c window-clock.c \ window-copy.c window-more.c window-scroll.c window.c xmalloc.c -CFLAGS+= -Wno-long-long -Wall -W -Wnested-externs -Wformat=2 -CFLAGS+= -Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations -CFLAGS+= -Wwrite-strings -Wshadow -Wpointer-arith -Wsign-compare -CFLAGS+= -Wundef -Wbad-function-cast -Winline -Wcast-align +CDIAGFLAGS+= -Wno-long-long -Wall -W -Wnested-externs -Wformat=2 +CDIAGFLAGS+= -Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations +CDIAGFLAGS+= -Wwrite-strings -Wshadow -Wpointer-arith -Wsign-compare +CDIAGFLAGS+= -Wundef -Wbad-function-cast -Winline -Wcast-align LDADD= -lutil -lncurses DPADD= ${LIBUTIL} From e8c10f5b342d4d2b0d905e8fc1cc1b7a8802c1ab Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 25 Jun 2009 08:08:18 +0000 Subject: [PATCH 0063/1180] Use the pane flags not the window flags. Doh. --- cmd-rotate-window.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd-rotate-window.c b/cmd-rotate-window.c index 39605b64..52b752e9 100644 --- a/cmd-rotate-window.c +++ b/cmd-rotate-window.c @@ -73,7 +73,7 @@ cmd_rotate_window_exec(struct cmd *self, struct cmd_ctx *ctx) xoff = wp->xoff; yoff = wp->yoff; sx = wp->sx; sy = wp->sy; - flags = w->flags; + flags = wp->flags; TAILQ_FOREACH(wp, &w->panes, entry) { if ((wp2 = TAILQ_NEXT(wp, entry)) == NULL) break; @@ -97,7 +97,7 @@ cmd_rotate_window_exec(struct cmd *self, struct cmd_ctx *ctx) xoff = wp->xoff; yoff = wp->yoff; sx = wp->sx; sy = wp->sy; - flags = w->flags; + flags = wp->flags; TAILQ_FOREACH_REVERSE(wp, &w->panes, window_panes, entry) { if ((wp2 = TAILQ_PREV(wp, window_panes, entry)) == NULL) break; From e225ce0fd71458cf8f03d0d122c6b3987162709f Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 25 Jun 2009 22:08:15 +0000 Subject: [PATCH 0064/1180] #ifndef nitems to avoid redefining it if it is already in a header. --- tmux.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tmux.h b/tmux.h index 6ca1254d..4aa50b67 100644 --- a/tmux.h +++ b/tmux.h @@ -73,7 +73,9 @@ extern const char *__progname; #define printflike5 __attribute__ ((format (printf, 5, 6))) /* Number of items in array. */ +#ifndef nitems #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) +#endif /* Buffer macros. */ #define BUFFER_USED(b) ((b)->size) From eb8ab96980ac0104b95f2fe58319394aa641d00e Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 25 Jun 2009 22:09:20 +0000 Subject: [PATCH 0065/1180] Remove some dead assignments, found by sthen with clang. --- client.c | 1 - server.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/client.c b/client.c index 226f22fe..a017e7a7 100644 --- a/client.c +++ b/client.c @@ -142,7 +142,6 @@ client_main(struct client_ctx *cctx) logfile("client"); error = NULL; - xtimeout = INFTIM; while (!sigterm) { if (sigchld) { waitpid(WAIT_ANY, NULL, WNOHANG); diff --git a/server.c b/server.c index b8c80fb3..c92426a4 100644 --- a/server.c +++ b/server.c @@ -288,7 +288,7 @@ server_main(int srv_fd) xtimeout = POLL_TIMEOUT; /* Do the poll. */ - if ((nfds = poll(pfds, nfds, xtimeout)) == -1) { + if (poll(pfds, nfds, xtimeout) == -1) { if (errno == EAGAIN || errno == EINTR) continue; fatal("poll failed"); From c506e7f71194b25c4ba2bf0087c7ebc3fff34b05 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 26 Jun 2009 10:55:37 +0000 Subject: [PATCH 0066/1180] Also #ifndef nitems here, caught by Thomas Jeunet. --- procname.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/procname.c b/procname.c index 262d63a4..e28b7535 100644 --- a/procname.c +++ b/procname.c @@ -25,7 +25,9 @@ #include #include +#ifndef nitems #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) +#endif #define is_runnable(p) \ ((p)->p_stat == SRUN || (p)->p_stat == SIDL || (p)->p_stat == SONPROC) From 1ec736a3dc43755a283c22c090f8d3183623cce6 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 26 Jun 2009 15:13:39 +0000 Subject: [PATCH 0067/1180] Status line fixes: don't truncate status-right now the length calculation is done for UTF-8, limit to the maximum length correctly when printing, and always print a space even if the left string is longer than the width available. --- screen-write.c | 2 +- status.c | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/screen-write.c b/screen-write.c index f0cdec30..e3a215ac 100644 --- a/screen-write.c +++ b/screen-write.c @@ -164,7 +164,7 @@ screen_write_vnputs(struct screen_write_ctx *ctx, ssize_t maxlen, gc->flags &= ~GRID_FLAG_UTF8; } else { - if (maxlen > 0 && size > (size_t) maxlen) + if (maxlen > 0 && size + 1 > (size_t) maxlen) break; size++; diff --git a/status.c b/status.c index 98061dd0..8aea62a7 100644 --- a/status.c +++ b/status.c @@ -91,7 +91,6 @@ status_redraw(struct client *c) rlen2 = screen_write_strlen(utf8flag, "%s", right); if (rlen2 < rlen) rlen = rlen2; - right[rlen] = '\0'; /* * Figure out how much space we have for the window list. If there isn't @@ -167,8 +166,8 @@ draw: screen_write_start(&ctx, NULL, &c->status); if (llen != 0) { screen_write_cursormove(&ctx, 0, yy); - screen_write_nputs( - &ctx, llen + 1, &stdgc, utf8flag, "%s ", left); + screen_write_nputs(&ctx, llen, &stdgc, utf8flag, "%s", left); + screen_write_putc(&ctx, &stdgc, ' '); if (larrow) screen_write_putc(&ctx, &stdgc, ' '); } else { @@ -225,8 +224,8 @@ draw: /* Draw the last item. */ if (rlen != 0) { screen_write_cursormove(&ctx, c->tty.sx - rlen - 1, yy); - screen_write_nputs( - &ctx, rlen + 1, &stdgc, utf8flag, " %s", right); + screen_write_putc(&ctx, &stdgc, ' '); + screen_write_nputs(&ctx, rlen, &stdgc, utf8flag, "%s", right); } /* Draw the arrows. */ From b11b1dd1c0666a98f167ad56370b920c7769a85b Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 26 Jun 2009 19:44:36 +0000 Subject: [PATCH 0068/1180] Remove some unused function declarations; no binary change. --- tmux.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tmux.h b/tmux.h index 4aa50b67..3fc30200 100644 --- a/tmux.h +++ b/tmux.h @@ -1217,7 +1217,6 @@ size_t cmd_pane_print(struct cmd *, char *, size_t); /* client.c */ int client_init(char *, struct client_ctx *, int, int); -int client_flush(struct client_ctx *); int client_main(struct client_ctx *); /* client-msg.c */ @@ -1406,8 +1405,6 @@ void screen_set_selection( struct screen *, u_int, u_int, u_int, u_int, struct grid_cell *); void screen_clear_selection(struct screen *); int screen_check_selection(struct screen *, u_int, u_int); -void screen_display_copy_area(struct screen *, struct screen *, - u_int, u_int, u_int, u_int, u_int, u_int); /* window.c */ extern struct windows windows; @@ -1443,7 +1440,6 @@ void window_pane_destroy(struct window_pane *); int window_pane_spawn(struct window_pane *, const char *, const char *, const char **, char **); int window_pane_resize(struct window_pane *, u_int, u_int); -void window_calculate_sizes(struct window *); int window_pane_set_mode( struct window_pane *, const struct window_mode *); void window_pane_reset_mode(struct window_pane *); @@ -1561,6 +1557,5 @@ int printflike2 xasprintf(char **, const char *, ...); int xvasprintf(char **, const char *, va_list); int printflike3 xsnprintf(char *, size_t, const char *, ...); int xvsnprintf(char *, size_t, const char *, va_list); -int printflike3 printpath(char *, size_t, const char *, ...); #endif /* TMUX_H */ From 46f80d01ff2c0e611b46acf309df45c4a2c21eb5 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 26 Jun 2009 22:12:19 +0000 Subject: [PATCH 0069/1180] After logging (if enabled) is switched to file, there is no reason to keep stdin/stdout/stderr active, so dup them to /dev/null. --- server.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/server.c b/server.c index c92426a4..ec88394c 100644 --- a/server.c +++ b/server.c @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -131,7 +132,7 @@ server_client_index(struct client *c) int server_start(char *path) { - int pair[2], srv_fd; + int pair[2], srv_fd, null_fd; char *cause; char rpathbuf[MAXPATHLEN]; @@ -176,6 +177,18 @@ server_start(char *path) } logfile("server"); + /* + * Close stdin/stdout/stderr. Can't let daemon() do this as they are + * needed until now to print configuration file errors. + */ + if ((null_fd = open(_PATH_DEVNULL, O_RDWR)) != -1) { + dup2(null_fd, STDIN_FILENO); + dup2(null_fd, STDOUT_FILENO); + dup2(null_fd, STDERR_FILENO); + if (null_fd > 2) + close(null_fd); + } + log_debug("server started, pid %ld", (long) getpid()); log_debug("socket path %s", socket_path); From 916669a24404f3850c12bdf7e7a284edd27549fa Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 26 Jun 2009 22:47:06 +0000 Subject: [PATCH 0070/1180] Add missing spaces before some alias closing brackets, otherwise they are shown in the wrong style. --- tmux.1 | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tmux.1 b/tmux.1 index 9bba3874..d42b1690 100644 --- a/tmux.1 +++ b/tmux.1 @@ -571,7 +571,7 @@ option. .Op Fl p Ar pane-index .Op Fl t Ar target-window .Xc -.D1 (alias: Ic breakp) +.D1 (alias: Ic breakp ) Break the current pane off from its containing window to make it the only pane in a new window. If @@ -595,7 +595,7 @@ This command works only from inside .Op Fl p Ar pane-index .Op Fl t Ar target-window .Xc -.D1 (alias: Ic clearhist) +.D1 (alias: Ic clearhist ) Remove and free the history for the specified pane. .It Xo Ic clock-mode .Op Fl t Ar target-window @@ -617,7 +617,7 @@ replaced by what is entered at the prompt. .Op Fl t Ar target-client .Ar command .Xc -.D1 (alias: Ic confirm) +.D1 (alias: Ic confirm ) Ask for confirmation before executing .Ar command . This command works only from inside @@ -628,7 +628,7 @@ This command works only from inside .Op Fl s Ar src-session .Op Fl t Ar dst-session .Xc -.D1 (alias: Ic copyb) +.D1 (alias: Ic copyb ) Copy a session paste buffer to another session. If no sessions are specified, the current one is used instead. .It Xo Ic copy-mode @@ -948,7 +948,7 @@ command. .Op Fl t Ar target-window .Ar layout-name .Xc -.D1 (alias: selectl) +.D1 (alias: selectl ) Choose a specific layout for a window. .It Xo Ic select-pane .Op Fl p Ar pane-index From 2660692fb18499bedd1f81f8ec88fab1acfd80bc Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 27 Jun 2009 12:57:14 +0000 Subject: [PATCH 0071/1180] Copy the 256-colour flag into the tty saved cell as well as the actual colour, otherwise colour 8 isn't reset properly. --- tty.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tty.c b/tty.c index 459db0a4..75986ef0 100644 --- a/tty.c +++ b/tty.c @@ -1005,6 +1005,8 @@ tty_attributes(struct tty *tty, const struct grid_cell *gc) (gc->flags & GRID_FLAG_FG256) != (tc->flags & GRID_FLAG_FG256)) { tty_attributes_fg(tty, gc); tc->fg = fg; + tc->flags &= ~GRID_FLAG_FG256; + tc->flags |= gc->flags & GRID_FLAG_FG256; } /* Set background colour. */ @@ -1012,6 +1014,8 @@ tty_attributes(struct tty *tty, const struct grid_cell *gc) (gc->flags & GRID_FLAG_BG256) != (tc->flags & GRID_FLAG_BG256)) { tty_attributes_bg(tty, gc); tc->bg = bg; + tc->flags &= ~GRID_FLAG_BG256; + tc->flags |= gc->flags & GRID_FLAG_BG256; } } From 710393e388c0adf8b36854b60c466b21f1a9eb12 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 27 Jun 2009 14:40:22 +0000 Subject: [PATCH 0072/1180] Use gmtime_r so the current time isn't overwritten, the minute comparison works and the clock is actually updated. It was already used for lock-server but not here. --- window-clock.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/window-clock.c b/window-clock.c index e84635f6..49239180 100644 --- a/window-clock.c +++ b/window-clock.c @@ -93,13 +93,13 @@ void window_clock_timer(struct window_pane *wp) { struct window_clock_mode_data *data = wp->modedata; - struct tm *now, *then; + struct tm now, then; time_t t; t = time(NULL); - now = gmtime(&t); - then = gmtime(&data->tim); - if (now->tm_min == then->tm_min) + gmtime_r(&t, &now); + gmtime_r(&data->tim, &then); + if (now.tm_min == then.tm_min) return; data->tim = t; From 003e8e65f7a3613a3f3004091ad1c57298dbf507 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 29 Jun 2009 07:11:20 +0000 Subject: [PATCH 0073/1180] Don't try to page up with scroll-mode -u or copy-mode -u unless the mode was successfully changed - if already in a different mode, it would corrupt the mode data. --- cmd-copy-mode.c | 8 +++++--- cmd-scroll-mode.c | 8 +++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/cmd-copy-mode.c b/cmd-copy-mode.c index af83e10c..681f8ba7 100644 --- a/cmd-copy-mode.c +++ b/cmd-copy-mode.c @@ -44,13 +44,15 @@ cmd_copy_mode_exec(struct cmd *self, struct cmd_ctx *ctx) { struct cmd_target_data *data = self->data; struct winlink *wl; + struct window_pane *wp; if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) return (-1); + wp = wl->window->active; - window_pane_set_mode(wl->window->active, &window_copy_mode); - if (data->flags & CMD_UFLAG) - window_copy_pageup(wl->window->active); + window_pane_set_mode(wp, &window_copy_mode); + if (wp->mode == &window_copy_mode && data->flags & CMD_UFLAG) + window_copy_pageup(wp); return (0); } diff --git a/cmd-scroll-mode.c b/cmd-scroll-mode.c index c34f9bd6..0d1f2291 100644 --- a/cmd-scroll-mode.c +++ b/cmd-scroll-mode.c @@ -60,13 +60,15 @@ cmd_scroll_mode_exec(struct cmd *self, struct cmd_ctx *ctx) { struct cmd_target_data *data = self->data; struct winlink *wl; + struct window_pane *wp; if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) return (-1); + wp = wl->window->active; - window_pane_set_mode(wl->window->active, &window_scroll_mode); - if (data->flags & CMD_UFLAG) - window_scroll_pageup(wl->window->active); + window_pane_set_mode(wp, &window_scroll_mode); + if (wp->mode == &window_scroll_mode && data->flags & CMD_UFLAG) + window_scroll_pageup(wp); return (0); } From 68e06fb6b76b250b1971867244f33eb809891b1f Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 29 Jun 2009 21:30:50 +0000 Subject: [PATCH 0074/1180] Fix two errors with character/line insertion and deletion: the maximum number of characters which may be inserted or deleted is the screen width, not one less (and similarly for lines and height); and if characters or lines are deleted by moving the ones that follow, the space at the end needs to be cleared. This appears to solve long-standing redraw issues most visible when using the force-width option then scrolling in view(1) or unwrapping lines in emacs. --- grid-view.c | 6 ++++-- screen-write.c | 16 ++++++++-------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/grid-view.c b/grid-view.c index 75dc686a..aa83da13 100644 --- a/grid-view.c +++ b/grid-view.c @@ -158,6 +158,7 @@ grid_view_delete_lines(struct grid *gd, u_int py, u_int ny) sy = grid_view_y(gd, gd->sy); grid_move_lines(gd, py, py + ny, sy - py - ny); + grid_clear(gd, 0, sy - ny, gd->sx, py + ny - (sy - ny)); } /* Delete lines inside scroll region. */ @@ -191,7 +192,7 @@ grid_view_insert_cells(struct grid *gd, u_int px, u_int py, u_int nx) if (px == sx - 1) grid_clear(gd, px, py, 1, 1); else - grid_move_cells(gd, px + nx, px, py, (sx - 1) - (px + nx)); + grid_move_cells(gd, px + nx, px, py, sx - px - nx); } /* Delete characters. */ @@ -207,7 +208,8 @@ grid_view_delete_cells(struct grid *gd, u_int px, u_int py, u_int nx) sx = grid_view_x(gd, gd->sx); - grid_move_cells(gd, px, px + nx, py, (sx - 1) - (px + nx)); + grid_move_cells(gd, px, px + nx, py, sx - px - nx); + grid_clear(gd, sx - nx, py, px + nx - (sx - nx), 1); } /* Convert cells into a string. */ diff --git a/screen-write.c b/screen-write.c index e3a215ac..d0049c63 100644 --- a/screen-write.c +++ b/screen-write.c @@ -325,8 +325,8 @@ screen_write_insertcharacter(struct screen_write_ctx *ctx, u_int nx) if (nx == 0) nx = 1; - if (nx > screen_size_x(s) - 1 - s->cx) - nx = screen_size_x(s) - 1 - s->cx; + if (nx > screen_size_x(s) - s->cx) + nx = screen_size_x(s) - s->cx; if (nx == 0) return; @@ -347,8 +347,8 @@ screen_write_deletecharacter(struct screen_write_ctx *ctx, u_int nx) if (nx == 0) nx = 1; - if (nx > screen_size_x(s) - 1 - s->cx) - nx = screen_size_x(s) - 1 - s->cx; + if (nx > screen_size_x(s) - s->cx) + nx = screen_size_x(s) - s->cx; if (nx == 0) return; @@ -369,8 +369,8 @@ screen_write_insertline(struct screen_write_ctx *ctx, u_int ny) if (ny == 0) ny = 1; - if (ny > screen_size_y(s) - 1 - s->cy) - ny = screen_size_y(s) - 1 - s->cy; + if (ny > screen_size_y(s) - s->cy) + ny = screen_size_y(s) - s->cy; if (ny == 0) return; @@ -395,8 +395,8 @@ screen_write_deleteline(struct screen_write_ctx *ctx, u_int ny) if (ny == 0) ny = 1; - if (ny > screen_size_y(s) - 1 - s->cy) - ny = screen_size_y(s) - 1 - s->cy; + if (ny > screen_size_y(s) - s->cy) + ny = screen_size_y(s) - s->cy; if (ny == 0) return; From 4c5c125173e07dcc061aa162b08d1722c73abe7d Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 30 Jun 2009 13:40:30 +0000 Subject: [PATCH 0075/1180] When unlocking the server, don't try to clear the prompt on clients without a prompt (such as the one issuing the unlock request). This caused the server to die if the wrong password was entered when unlocking from the command line with -U (nasty). --- server-fn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server-fn.c b/server-fn.c index a025bf0a..fb40a624 100644 --- a/server-fn.c +++ b/server-fn.c @@ -214,7 +214,7 @@ server_unlock(const char *s) wrong: for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); - if (c == NULL) + if (c == NULL || c->prompt_buffer == NULL) continue; *c->prompt_buffer = '\0'; From fe5edad1fcd60d94bc45ca49f94636eeecae210d Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 2 Jul 2009 16:15:43 +0000 Subject: [PATCH 0076/1180] Fix two copy/paste bugs: forbid zero-length buffers to prevent a fatal error when trying to paste them, found by me, and miscalculation of the start/end causing random fatal errors when copying in copy-mode, reported by sthen. ok sthen "put it in" deraadt --- cmd-paste-buffer.c | 2 +- paste.c | 3 +++ window-copy.c | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/cmd-paste-buffer.c b/cmd-paste-buffer.c index 35472d3d..3f4cfe2e 100644 --- a/cmd-paste-buffer.c +++ b/cmd-paste-buffer.c @@ -63,7 +63,7 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) } } - if (pb != NULL) + if (pb != NULL && *pb->data != '\0') buffer_write(w->active->out, pb->data, strlen(pb->data)); /* Delete the buffer if -d. */ diff --git a/paste.c b/paste.c index 3644381c..981385e9 100644 --- a/paste.c +++ b/paste.c @@ -101,6 +101,9 @@ paste_add(struct paste_stack *ps, char *data, u_int limit) { struct paste_buffer *pb; + if (*data == '\0') + return; + while (ARRAY_LENGTH(ps) >= limit) ARRAY_TRUNC(ps, 1); diff --git a/window-copy.c b/window-copy.c index dc2a4d45..a64be760 100644 --- a/window-copy.c +++ b/window-copy.c @@ -423,7 +423,7 @@ window_copy_copy_selection(struct window_pane *wp, struct client *c) /* Find start and end. */ xx = data->cx + data->ox; yy = screen_hsize(&wp->base) + data->cy - data->oy; - if (xx < data->selx || (yy == data->sely && xx < data->selx)) { + if (yy < data->sely || (yy == data->sely && xx < data->selx)) { sx = xx; sy = yy; ex = data->selx; ey = data->sely; } else { From 69e150b7e38243e73e3841fe0567ac38b6579357 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 6 Jul 2009 19:50:04 +0000 Subject: [PATCH 0077/1180] Add a section summarising how options work, make the distinction between window and session options clearer, and fix the incorrect synopses and descriptions of show-options and show-window-options. --- tmux.1 | 67 +++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 48 insertions(+), 19 deletions(-) diff --git a/tmux.1 b/tmux.1 index d42b1690..9d09c5a6 100644 --- a/tmux.1 +++ b/tmux.1 @@ -339,6 +339,38 @@ or the command, and pasted into a window using the .Ic paste-buffer command. +.Sh OPTIONS +The appearance and behaviour of +.Nm +may be modified by changing the value of various options. +There are two types of option: +.Em session options +and +.Em window options . +.Pp +Each individual session may have a set of session options, and there is a +separate set of global session options. +Sessions which do not have a particular option configured inherit the value +from the global session options. +Session options are set or unset with the +.Ic set-option +command and may be listed with the +.Ic show-options +command. +The available session options are listed under the +.Ic set-option +command. +.Pp +Similarly, a set of window options is attached to each window, and there is +a set of global window options from which any unset options are inherited. +Window options are altered with the +.Ic set-window-option +command and can be listed with the +.Ic show-window-options +command. +All window options are documented with the +.Ic set-window-option +command. .Sh PANES AND LAYOUTS Each window displayed by .Nm @@ -1008,22 +1040,16 @@ Set the contents of the specified buffer to .Ar option Ar value .Xc .D1 (alias: Ic set ) -Set an option. +Set a session option. If .Fl g -is specified, the option is set as a global option. -Global options apply to all sessions which don't have the option explicitly -set. -If -.Fl g -is not used, the option applies only to -.Ar target-session . +is specified, the global session option is set. The .Fl u flag unsets an option, so a session inherits the option from the global options - it is not possible to unset a global option. .Pp -Possible options are: +Available session options are: .Bl -tag -width Ds .It Xo Ic bell-action .Op Ic any | Ic none | Ic current @@ -1234,7 +1260,7 @@ configuration file, enclose it in single quotes ('). .Ar option Ar value .Xc .D1 (alias: Ic setw ) -Set a window-specific option. +Set a window option. The .Fl g and @@ -1243,7 +1269,7 @@ flags work similarly to the .Ic set-option command. .Pp -Supported options are: +Supported window options are: .Bl -tag -width Ds .It Xo Ic aggressive-resize .Op Ic on | Ic off @@ -1359,21 +1385,24 @@ as Shift, Alt or Ctrl. .D1 (alias: Ic showb ) Display the contents of the specified buffer. .It Xo Ic show-options +.Op Fl g .Op Fl t Ar target-session -.Ar option Ar value .Xc .D1 (alias: Ic show ) -Show the currently set options. -If a -.Ar target-session -is specified, the options for that session are shown; otherwise, the global -options are listed. +Show the session options for +.Ar target session , +or the global session options with +.Fl g . .It Xo Ic show-window-options +.Op Fl g .Op Fl t Ar target-window -.Ar option Ar value .Xc .D1 (alias: Ic showw ) -List the current options for the given window. +List the window options for +.Ar target-window , +or the global window options if +.Fl g +is used. .It Xo Ic source-file .Ar path .Xc From eb424cf63d0a4d0e9f8531ed8c4dab632725b0fe Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 7 Jul 2009 06:58:49 +0000 Subject: [PATCH 0078/1180] Minor fix: look for default-path in the options for the specified session first rather than just the global options. From Brandon Mercer, thanks. --- cmd-new-window.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd-new-window.c b/cmd-new-window.c index 7d3eeb45..30b84ac3 100644 --- a/cmd-new-window.c +++ b/cmd-new-window.c @@ -164,7 +164,7 @@ cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx) if (cmd == NULL) cmd = options_get_string(&s->options, "default-command"); if (ctx->cmdclient == NULL || ctx->cmdclient->cwd == NULL) - cwd = options_get_string(&global_options, "default-path"); + cwd = options_get_string(&s->options, "default-path"); else cwd = ctx->cmdclient->cwd; From e538d4adae2b17ad177f340091a241d212b2b5c1 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 7 Jul 2009 07:01:10 +0000 Subject: [PATCH 0079/1180] The fix for default-path (use target session options instead of global options) is required here as well, doh. --- cmd-split-window.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd-split-window.c b/cmd-split-window.c index 28f42b64..a46b23a5 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -154,7 +154,7 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) if (cmd == NULL) cmd = options_get_string(&s->options, "default-command"); if (ctx->cmdclient == NULL || ctx->cmdclient->cwd == NULL) - cwd = options_get_string(&global_options, "default-path"); + cwd = options_get_string(&s->options, "default-path"); else cwd = ctx->cmdclient->cwd; From 9ced016cbce01342b414a7aedaa0fe6c8f03d671 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 7 Jul 2009 12:34:47 +0000 Subject: [PATCH 0080/1180] When sending a "protocol mismatch" error message, tell the client to exit afterwards, otherwise it hangs. --- server-msg.c | 1 + 1 file changed, 1 insertion(+) diff --git a/server-msg.c b/server-msg.c index ef01e100..c52fe800 100644 --- a/server-msg.c +++ b/server-msg.c @@ -189,6 +189,7 @@ server_msg_fn_identify(struct hdr *hdr, struct client *c) #define MSG "protocol version mismatch" server_write_client(c, MSG_ERROR, MSG, (sizeof MSG) - 1); #undef MSG + server_write_client(c, MSG_EXIT, NULL, 0); return (0); } From 474fdebb7abf08aecbcf00a92b7d53cd9528649c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 7 Jul 2009 17:24:32 +0000 Subject: [PATCH 0081/1180] Handle empty or unset TERM correctly; also fix a fatal() message while here. --- server-msg.c | 4 +++- tty.c | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/server-msg.c b/server-msg.c index c52fe800..9f33fad3 100644 --- a/server-msg.c +++ b/server-msg.c @@ -211,7 +211,9 @@ server_msg_fn_identify(struct hdr *hdr, struct client *c) c->tty.term_flags |= TERM_88COLOURS; if (data.flags & IDENTIFY_HASDEFAULTS) c->tty.term_flags |= TERM_HASDEFAULTS; - xfree(term); + + if (term != NULL) + xfree(term); c->flags |= CLIENT_TERMINAL; diff --git a/tty.c b/tty.c index 75986ef0..1ce8b226 100644 --- a/tty.c +++ b/tty.c @@ -76,7 +76,7 @@ void tty_init(struct tty *tty, char *path, char *term) { tty->path = xstrdup(path); - if (term == NULL) + if (term == NULL || *term == '\0') tty->termname = xstrdup("unknown"); else tty->termname = xstrdup(term); @@ -98,7 +98,7 @@ tty_open(struct tty *tty, char **cause) if ((mode = fcntl(tty->fd, F_GETFL)) == -1) fatal("fcntl failed"); if (fcntl(tty->fd, F_SETFL, mode|O_NONBLOCK) == -1) - fatal("fcntl failedo"); + fatal("fcntl failed"); if (fcntl(tty->fd, F_SETFD, FD_CLOEXEC) == -1) fatal("fcntl failed"); From 923ccfa2e8dfddc1611213bc027fd2968a84c04b Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 7 Jul 2009 19:49:19 +0000 Subject: [PATCH 0082/1180] Rename the global options variables to be shorter and to make session options clear. No functional change, getting this out of the way to make later options changes easier. --- cmd-new-session.c | 6 +-- cmd-set-option.c | 2 +- cmd-set-window-option.c | 2 +- cmd-show-options.c | 2 +- cmd-show-window-options.c | 2 +- server.c | 12 ++--- session.c | 2 +- tmux.c | 103 +++++++++++++++++++------------------- tmux.h | 4 +- window.c | 2 +- 10 files changed, 67 insertions(+), 70 deletions(-) diff --git a/cmd-new-session.c b/cmd-new-session.c index 7c2c664b..95fc08b2 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -137,9 +137,9 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) cmd = data->cmd; if (cmd == NULL) - cmd = options_get_string(&global_options, "default-command"); + cmd = options_get_string(&global_s_options, "default-command"); if (c == NULL || c->cwd == NULL) - cwd = options_get_string(&global_options, "default-path"); + cwd = options_get_string(&global_s_options, "default-path"); else cwd = c->cwd; @@ -150,7 +150,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) sy = c->tty.sy; } - if (options_get_number(&global_options, "status")) { + if (options_get_number(&global_s_options, "status")) { if (sy == 0) sy = 1; else diff --git a/cmd-set-option.c b/cmd-set-option.c index 5c417325..9befb085 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -87,7 +87,7 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) u_int i; if (data->flags & CMD_GFLAG) - oo = &global_options; + oo = &global_s_options; else { if ((s = cmd_find_session(ctx, data->target)) == NULL) return (-1); diff --git a/cmd-set-window-option.c b/cmd-set-window-option.c index cc9bf963..99b1a907 100644 --- a/cmd-set-window-option.c +++ b/cmd-set-window-option.c @@ -82,7 +82,7 @@ cmd_set_window_option_exec(struct cmd *self, struct cmd_ctx *ctx) u_int i; if (data->flags & CMD_GFLAG) - oo = &global_window_options; + oo = &global_w_options; else { if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) return (-1); diff --git a/cmd-show-options.c b/cmd-show-options.c index 13482525..3cc3be58 100644 --- a/cmd-show-options.c +++ b/cmd-show-options.c @@ -54,7 +54,7 @@ cmd_show_options_exec(struct cmd *self, struct cmd_ctx *ctx) long long vn; if (data->flags & CMD_GFLAG) - oo = &global_options; + oo = &global_s_options; else { if ((s = cmd_find_session(ctx, data->target)) == NULL) return (-1); diff --git a/cmd-show-window-options.c b/cmd-show-window-options.c index dd8914a1..9f9c65ca 100644 --- a/cmd-show-window-options.c +++ b/cmd-show-window-options.c @@ -54,7 +54,7 @@ cmd_show_window_options_exec(struct cmd *self, struct cmd_ctx *ctx) long long vn; if (data->flags & CMD_GFLAG) - oo = &global_window_options; + oo = &global_w_options; else { if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) return (-1); diff --git a/server.c b/server.c index ec88394c..6ba83d87 100644 --- a/server.c +++ b/server.c @@ -373,8 +373,8 @@ server_main(int srv_fd) unlink(socket_path); xfree(socket_path); - options_free(&global_options); - options_free(&global_window_options); + options_free(&global_s_options); + options_free(&global_w_options); if (server_password != NULL) xfree(server_password); @@ -573,10 +573,8 @@ server_redraw_locked(struct client *c) yy = c->tty.sy - 1; if (xx == 0 || yy == 0) return; - colour = options_get_number( - &global_window_options, "clock-mode-colour"); - style = options_get_number( - &global_window_options, "clock-mode-style"); + colour = options_get_number(&global_w_options, "clock-mode-colour"); + style = options_get_number(&global_w_options, "clock-mode-style"); screen_init(&screen, xx, yy, 0); @@ -1062,7 +1060,7 @@ server_second_timers(void) time_t t; t = time(NULL); - xtimeout = options_get_number(&global_options, "lock-after-time"); + xtimeout = options_get_number(&global_s_options, "lock-after-time"); if (xtimeout > 0 && t > server_activity + xtimeout) server_lock(); diff --git a/session.c b/session.c index 3b65127c..6bf2a3ea 100644 --- a/session.c +++ b/session.c @@ -127,7 +127,7 @@ session_create(const char *name, RB_INIT(&s->windows); SLIST_INIT(&s->alerts); paste_init_stack(&s->buffers); - options_init(&s->options, &global_options); + options_init(&s->options, &global_s_options); s->sx = sx; s->sy = sy; diff --git a/tmux.c b/tmux.c index 84e5a029..9f946b7c 100644 --- a/tmux.c +++ b/tmux.c @@ -42,8 +42,8 @@ volatile sig_atomic_t sigusr1; volatile sig_atomic_t sigusr2; char *cfg_file; -struct options global_options; -struct options global_window_options; +struct options global_s_options; /* session options */ +struct options global_w_options; /* window options */ int server_locked; char *server_password; @@ -267,54 +267,53 @@ main(int argc, char **argv) log_open_tty(debug_level); siginit(); - options_init(&global_options, NULL); - options_set_number(&global_options, "bell-action", BELL_ANY); - options_set_number(&global_options, "buffer-limit", 9); - options_set_number(&global_options, "display-time", 750); - options_set_number(&global_options, "history-limit", 2000); - options_set_number(&global_options, "lock-after-time", 0); - options_set_number(&global_options, "message-attr", GRID_ATTR_REVERSE); - options_set_number(&global_options, "message-bg", 3); - options_set_number(&global_options, "message-fg", 0); - options_set_number(&global_options, "prefix", '\002'); - options_set_number(&global_options, "repeat-time", 500); - options_set_number(&global_options, "set-remain-on-exit", 0); - options_set_number(&global_options, "set-titles", 0); - options_set_number(&global_options, "status", 1); - options_set_number(&global_options, "status-attr", GRID_ATTR_REVERSE); - options_set_number(&global_options, "status-bg", 2); - options_set_number(&global_options, "status-fg", 0); - options_set_number(&global_options, "status-interval", 15); - options_set_number(&global_options, "status-keys", MODEKEY_EMACS); - options_set_number(&global_options, "status-left-length", 10); - options_set_number(&global_options, "status-right-length", 40); - options_set_string(&global_options, "status-left", "[#S]"); + options_init(&global_s_options, NULL); + options_set_number(&global_s_options, "bell-action", BELL_ANY); + options_set_number(&global_s_options, "buffer-limit", 9); + options_set_number(&global_s_options, "display-time", 750); + options_set_number(&global_s_options, "history-limit", 2000); + options_set_number(&global_s_options, "lock-after-time", 0); + options_set_number(&global_s_options, "message-attr", GRID_ATTR_REVERSE); + options_set_number(&global_s_options, "message-bg", 3); + options_set_number(&global_s_options, "message-fg", 0); + options_set_number(&global_s_options, "prefix", '\002'); + options_set_number(&global_s_options, "repeat-time", 500); + options_set_number(&global_s_options, "set-remain-on-exit", 0); + options_set_number(&global_s_options, "set-titles", 0); + options_set_number(&global_s_options, "status", 1); + options_set_number(&global_s_options, "status-attr", GRID_ATTR_REVERSE); + options_set_number(&global_s_options, "status-bg", 2); + options_set_number(&global_s_options, "status-fg", 0); + options_set_number(&global_s_options, "status-interval", 15); + options_set_number(&global_s_options, "status-keys", MODEKEY_EMACS); + options_set_number(&global_s_options, "status-left-length", 10); + options_set_number(&global_s_options, "status-right-length", 40); + options_set_string(&global_s_options, "status-left", "[#S]"); options_set_string( - &global_options, "status-right", "\"#24T\" %%H:%%M %%d-%%b-%%y"); - options_set_number(&global_options, "status-utf8", 0); + &global_s_options, "status-right", "\"#24T\" %%H:%%M %%d-%%b-%%y"); + options_set_number(&global_s_options, "status-utf8", 0); - options_init(&global_window_options, NULL); - options_set_number(&global_window_options, "aggressive-resize", 0); - options_set_number(&global_window_options, "automatic-rename", 1); - options_set_number(&global_window_options, "clock-mode-colour", 4); - options_set_number(&global_window_options, "clock-mode-style", 1); - options_set_number(&global_window_options, "force-height", 0); - options_set_number(&global_window_options, "force-width", 0); - options_set_number( - &global_window_options, "mode-attr", GRID_ATTR_REVERSE); - options_set_number(&global_window_options, "main-pane-width", 81); - options_set_number(&global_window_options, "main-pane-height", 24); - options_set_number(&global_window_options, "mode-bg", 3); - options_set_number(&global_window_options, "mode-fg", 0); - options_set_number(&global_window_options, "mode-keys", MODEKEY_EMACS); - options_set_number(&global_window_options, "monitor-activity", 0); - options_set_string(&global_window_options, "monitor-content", "%s", ""); - options_set_number(&global_window_options, "utf8", 0); - options_set_number(&global_window_options, "window-status-attr", 0); - options_set_number(&global_window_options, "window-status-bg", 8); - options_set_number(&global_window_options, "window-status-fg", 8); - options_set_number(&global_window_options, "xterm-keys", 0); - options_set_number(&global_window_options, "remain-on-exit", 0); + options_init(&global_w_options, NULL); + options_set_number(&global_w_options, "aggressive-resize", 0); + options_set_number(&global_w_options, "automatic-rename", 1); + options_set_number(&global_w_options, "clock-mode-colour", 4); + options_set_number(&global_w_options, "clock-mode-style", 1); + options_set_number(&global_w_options, "force-height", 0); + options_set_number(&global_w_options, "force-width", 0); + options_set_number(&global_w_options, "mode-attr", GRID_ATTR_REVERSE); + options_set_number(&global_w_options, "main-pane-width", 81); + options_set_number(&global_w_options, "main-pane-height", 24); + options_set_number(&global_w_options, "mode-bg", 3); + options_set_number(&global_w_options, "mode-fg", 0); + options_set_number(&global_w_options, "mode-keys", MODEKEY_EMACS); + options_set_number(&global_w_options, "monitor-activity", 0); + options_set_string(&global_w_options, "monitor-content", "%s", ""); + options_set_number(&global_w_options, "utf8", 0); + options_set_number(&global_w_options, "window-status-attr", 0); + options_set_number(&global_w_options, "window-status-bg", 8); + options_set_number(&global_w_options, "window-status-fg", 8); + options_set_number(&global_w_options, "xterm-keys", 0); + options_set_number(&global_w_options, "remain-on-exit", 0); if (!(flags & IDENTIFY_UTF8)) { /* @@ -368,7 +367,7 @@ main(int argc, char **argv) shell = _PATH_BSHELL; } options_set_string( - &global_options, "default-command", "exec %s -l", shell); + &global_s_options, "default-command", "exec %s -l", shell); if (getcwd(cwd, sizeof cwd) == NULL) { pw = getpwuid(getuid()); @@ -377,7 +376,7 @@ main(int argc, char **argv) else strlcpy(cwd, "/", sizeof cwd); } - options_set_string(&global_options, "default-path", "%s", cwd); + options_set_string(&global_s_options, "default-path", "%s", cwd); if (unlock) { if (argc != 0) { @@ -481,8 +480,8 @@ main(int argc, char **argv) } out: - options_free(&global_options); - options_free(&global_window_options); + options_free(&global_s_options); + options_free(&global_w_options); close(cctx.srv_fd); buffer_destroy(cctx.srv_in); diff --git a/tmux.h b/tmux.h index 3fc30200..f9bf547a 100644 --- a/tmux.h +++ b/tmux.h @@ -945,8 +945,8 @@ extern volatile sig_atomic_t sigcont; extern volatile sig_atomic_t sigchld; extern volatile sig_atomic_t sigusr1; extern volatile sig_atomic_t sigusr2; -extern struct options global_options; -extern struct options global_window_options; +extern struct options global_s_options; +extern struct options global_w_options; extern char *cfg_file; extern int server_locked; extern char *server_password; diff --git a/window.c b/window.c index 37e65d83..c60f0453 100644 --- a/window.c +++ b/window.c @@ -204,7 +204,7 @@ window_create1(u_int sx, u_int sy) w->sx = sx; w->sy = sy; - options_init(&w->options, &global_window_options); + options_init(&w->options, &global_w_options); for (i = 0; i < ARRAY_LENGTH(&windows); i++) { if (ARRAY_ITEM(&windows, i) == NULL) { From b4efd1ca89132dcf24acd6dc7b1ccee369b7d90c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 7 Jul 2009 21:23:22 +0000 Subject: [PATCH 0083/1180] Don't let ambiguous commands override an exact alias match: eg if commands "abc-1", "abc-2", "abc-3" exist and "abc-3" has the alias "abc", "tmux abc" should execute abc-3, not complain about the command being ambiguous. Not a problem at the moment but will be soon. --- cmd.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/cmd.c b/cmd.c index 68dd06a3..af520f0f 100644 --- a/cmd.c +++ b/cmd.c @@ -105,7 +105,7 @@ cmd_parse(int argc, char **argv, char **cause) const struct cmd_entry **entryp, *entry; struct cmd *cmd; char s[BUFSIZ]; - int opt; + int opt, ambiguous = 0; *cause = NULL; if (argc == 0) { @@ -117,6 +117,7 @@ cmd_parse(int argc, char **argv, char **cause) for (entryp = cmd_table; *entryp != NULL; entryp++) { if ((*entryp)->alias != NULL && strcmp((*entryp)->alias, argv[0]) == 0) { + ambiguous = 0; entry = *entryp; break; } @@ -124,13 +125,15 @@ cmd_parse(int argc, char **argv, char **cause) if (strncmp((*entryp)->name, argv[0], strlen(argv[0])) != 0) continue; if (entry != NULL) - goto ambiguous; + ambiguous = 1; entry = *entryp; /* Bail now if an exact match. */ if (strcmp(entry->name, argv[0]) == 0) break; } + if (ambiguous) + goto ambiguous; if (entry == NULL) { xasprintf(cause, "unknown command: %s", argv[0]); return (NULL); From 084d07f4eb5dc3d90e28725524147e66a25b869b Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 8 Jul 2009 05:26:45 +0000 Subject: [PATCH 0084/1180] Just appending -l to $SHELL to create a login shell is wrong: -l is not POSIX, and some people may use shells which do not support it. Instead, make an empty default-command option mean a login shell, and fork it with a - in argv[0] which is the method used by login(1). Also fix the automatic-rename code to handle this correctly and to strip a leading - if present. --- names.c | 15 +++++++++++++-- tmux.1 | 8 ++++++-- tmux.c | 13 +------------ tmux.h | 1 + window.c | 34 ++++++++++++++++++++++++++++++++-- 5 files changed, 53 insertions(+), 18 deletions(-) diff --git a/names.c b/names.c index e4afa70f..172dc496 100644 --- a/names.c +++ b/names.c @@ -59,7 +59,16 @@ set_window_names(void) if (name == NULL) wname = default_window_name(w); else { - wname = parse_window_name(name); + /* + * If tmux is using the default command, it will be a + * login shell and argv[0] may have a - prefix. Remove + * this if it is present. Ick. + */ + if (w->active->cmd != NULL && *w->active->cmd == '\0' && + name != NULL && name[0] == '-' && name[1] != '\0') + wname = parse_window_name(name + 1); + else + wname = parse_window_name(name); xfree(name); } @@ -78,7 +87,9 @@ default_window_name(struct window *w) { if (w->active->screen != &w->active->base) return (xstrdup("[tmux]")); - return (parse_window_name(w->active->cmd)); + if (w->active->cmd != NULL && *w->active->cmd != '\0') + return (parse_window_name(w->active->cmd)); + return (parse_window_name(window_default_command())); } char * diff --git a/tmux.1 b/tmux.1 index 9d09c5a6..31e94d62 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1070,8 +1070,12 @@ maintain this maximum length. Set the command used for new windows (if not specified when the window is created) to .Ar command . -The default is -.Dq exec $SHELL -l . +The default is an empty string, which instructs +.Nm +to create a login shell using the +.Ev SHELL +environment variable or, if it is unset, the user's shell returned by +.Xr getpwuid 3 . .It Ic default-path Ar path Set the default working directory for processes created from keys, or interactively from the prompt. diff --git a/tmux.c b/tmux.c index 9f946b7c..c71c7264 100644 --- a/tmux.c +++ b/tmux.c @@ -209,7 +209,6 @@ main(int argc, char **argv) struct cmd *cmd; struct pollfd pfd; struct hdr hdr; - const char *shell; struct passwd *pw; char *s, *path, *label, *cause, *home, *pass = NULL; char cwd[MAXPATHLEN]; @@ -270,6 +269,7 @@ main(int argc, char **argv) options_init(&global_s_options, NULL); options_set_number(&global_s_options, "bell-action", BELL_ANY); options_set_number(&global_s_options, "buffer-limit", 9); + options_set_string(&global_s_options, "default-command", "%s", ""); options_set_number(&global_s_options, "display-time", 750); options_set_number(&global_s_options, "history-limit", 2000); options_set_number(&global_s_options, "lock-after-time", 0); @@ -358,17 +358,6 @@ main(int argc, char **argv) } xfree(label); - shell = getenv("SHELL"); - if (shell == NULL || *shell == '\0') { - pw = getpwuid(getuid()); - if (pw != NULL) - shell = pw->pw_shell; - if (shell == NULL || *shell == '\0') - shell = _PATH_BSHELL; - } - options_set_string( - &global_s_options, "default-command", "exec %s -l", shell); - if (getcwd(cwd, sizeof cwd) == NULL) { pw = getpwuid(getuid()); if (pw->pw_dir != NULL && *pw->pw_dir != '\0') diff --git a/tmux.h b/tmux.h index f9bf547a..5f3a3611 100644 --- a/tmux.h +++ b/tmux.h @@ -1408,6 +1408,7 @@ int screen_check_selection(struct screen *, u_int, u_int); /* window.c */ extern struct windows windows; +const char *window_default_command(void); int window_cmp(struct window *, struct window *); int winlink_cmp(struct winlink *, struct winlink *); RB_PROTOTYPE(windows, window, entry, window_cmp); diff --git a/window.c b/window.c index c60f0453..95addc41 100644 --- a/window.c +++ b/window.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -57,6 +58,23 @@ struct windows windows; RB_GENERATE(winlinks, winlink, entry, winlink_cmp); +const char * +window_default_command(void) +{ + const char *shell; + struct passwd *pw; + + shell = getenv("SHELL"); + if (shell != NULL && *shell != '\0') + return (shell); + + pw = getpwuid(getuid()); + if (pw != NULL && pw->pw_shell != NULL && *pw->pw_shell != '\0') + return (pw->pw_shell); + + return (_PATH_BSHELL); +} + int winlink_cmp(struct winlink *wl1, struct winlink *wl2) { @@ -424,7 +442,8 @@ window_pane_spawn(struct window_pane *wp, { struct winsize ws; int mode; - const char **envq; + const char **envq, *ptr; + char *argv0; struct timeval tv; if (wp->fd != -1) @@ -465,7 +484,18 @@ window_pane_spawn(struct window_pane *wp, sigreset(); log_close(); - execl(_PATH_BSHELL, "sh", "-c", wp->cmd, (char *) NULL); + if (*wp->cmd != '\0') { + execl(_PATH_BSHELL, "sh", "-c", wp->cmd, (char *) NULL); + fatal("execl failed"); + } + + /* No command; fork a login shell. */ + cmd = window_default_command(); + if ((ptr = strrchr(cmd, '/')) != NULL && *(ptr + 1) != '\0') + xasprintf(&argv0, "-%s", ptr + 1); + else + xasprintf(&argv0, "-%s", cmd); + execl(cmd, argv0, (char *) NULL); fatal("execl failed"); } From 8c497ecac0ba0d20b0129e195e1bebf443772faf Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 8 Jul 2009 05:56:11 +0000 Subject: [PATCH 0085/1180] When reinitialising the screen, do not omit to clear the last line. --- screen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/screen.c b/screen.c index fb625aa9..d296cd78 100644 --- a/screen.c +++ b/screen.c @@ -54,7 +54,7 @@ screen_reinit(struct screen *s) screen_reset_tabs(s); - grid_clear_lines(s->grid, s->grid->hsize, s->grid->sy - 1); + grid_clear_lines(s->grid, s->grid->hsize, s->grid->sy); screen_clear_selection(s); } From f63761eabcab7c8e1c623be366974441c5877651 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 8 Jul 2009 16:04:56 +0000 Subject: [PATCH 0086/1180] Fix two memory leaks when assigning shell variables in configuration file/command prompt. From Tiago Cunha. --- cmd-string.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmd-string.c b/cmd-string.c index a5c5dd12..c6ef61b0 100644 --- a/cmd-string.c +++ b/cmd-string.c @@ -114,6 +114,7 @@ cmd_string_parse(const char *s, struct cmd_list **cmdlist, char **cause) buf = xrealloc(buf, 1, len + strlen(t) + 1); strlcpy(buf + len, t, strlen(t) + 1); len += strlen(t); + xfree(t); have_arg = 1; break; @@ -219,6 +220,7 @@ cmd_string_string(const char *s, size_t *p, char endch, int esc) buf = xrealloc(buf, 1, len + strlen(t) + 1); strlcpy(buf + len, t, strlen(t) + 1); len += strlen(t); + xfree(t); continue; } From 643c219d180be584092f406c52602fb7f84c8852 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 9 Jul 2009 00:29:32 +0000 Subject: [PATCH 0087/1180] Tidy by removing unused argument from grid_view_{insert,delete}_line_region functions (currently don't fully work, this is to make fix easier). --- grid-view.c | 12 ++++-------- screen-write.c | 12 ++++-------- tmux.h | 6 ++---- 3 files changed, 10 insertions(+), 20 deletions(-) diff --git a/grid-view.c b/grid-view.c index aa83da13..a9144a1f 100644 --- a/grid-view.c +++ b/grid-view.c @@ -132,11 +132,9 @@ grid_view_insert_lines(struct grid *gd, u_int py, u_int ny) /* Insert lines in region. */ void -grid_view_insert_lines_region( - struct grid *gd, unused u_int rupper, u_int rlower, u_int py, u_int ny) +grid_view_insert_lines_region(struct grid *gd, u_int rlower, u_int py, u_int ny) { - GRID_DEBUG( - gd, "rupper=%u, rlower=%u, py=%u, ny=%u", rupper, rlower, py, ny); + GRID_DEBUG(gd, "rlower=%u, py=%u, ny=%u", rlower, py, ny); rlower = grid_view_y(gd, rlower); @@ -163,11 +161,9 @@ grid_view_delete_lines(struct grid *gd, u_int py, u_int ny) /* Delete lines inside scroll region. */ void -grid_view_delete_lines_region( - struct grid *gd, unused u_int rupper, u_int rlower, u_int py, u_int ny) +grid_view_delete_lines_region(struct grid *gd, u_int rlower, u_int py, u_int ny) { - GRID_DEBUG( - gd, "rupper=%u, rlower=%u, py=%u, ny=%u", rupper, rlower, py, ny); + GRID_DEBUG(gd, "rlower=%u, py=%u, ny=%u", rlower, py, ny); rlower = grid_view_y(gd, rlower); diff --git a/screen-write.c b/screen-write.c index d0049c63..00a56c46 100644 --- a/screen-write.c +++ b/screen-write.c @@ -378,10 +378,8 @@ screen_write_insertline(struct screen_write_ctx *ctx, u_int ny) if (s->cy < s->rupper || s->cy > s->rlower) grid_view_insert_lines(s->grid, s->cy, ny); - else { - grid_view_insert_lines_region( - s->grid, s->rupper, s->rlower, s->cy, ny); - } + else + grid_view_insert_lines_region(s->grid, s->rlower, s->cy, ny); tty_write_cmd(ctx->wp, TTY_INSERTLINE, ny); } @@ -404,10 +402,8 @@ screen_write_deleteline(struct screen_write_ctx *ctx, u_int ny) if (s->cy < s->rupper || s->cy > s->rlower) grid_view_delete_lines(s->grid, s->cy, ny); - else { - grid_view_delete_lines_region( - s->grid, s->rupper, s->rlower, s->cy, ny); - } + else + grid_view_delete_lines_region(s->grid, s->rlower, s->cy, ny); tty_write_cmd(ctx->wp, TTY_DELETELINE, ny); } diff --git a/tmux.h b/tmux.h index 5f3a3611..bc60cab1 100644 --- a/tmux.h +++ b/tmux.h @@ -1337,11 +1337,9 @@ void grid_view_clear(struct grid *, u_int, u_int, u_int, u_int); void grid_view_scroll_region_up(struct grid *, u_int, u_int); void grid_view_scroll_region_down(struct grid *, u_int, u_int); void grid_view_insert_lines(struct grid *, u_int, u_int); -void grid_view_insert_lines_region( - struct grid *, u_int, u_int, u_int, u_int); +void grid_view_insert_lines_region(struct grid *, u_int, u_int, u_int); void grid_view_delete_lines(struct grid *, u_int, u_int); -void grid_view_delete_lines_region( - struct grid *, u_int, u_int, u_int, u_int); +void grid_view_delete_lines_region(struct grid *, u_int, u_int, u_int); void grid_view_insert_cells(struct grid *, u_int, u_int, u_int); void grid_view_delete_cells(struct grid *, u_int, u_int, u_int); char *grid_view_string_cells(struct grid *, u_int, u_int, u_int); From 86c93c6e34cfe927e8d4e2901febf2ee063fa88b Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 9 Jul 2009 07:58:14 +0000 Subject: [PATCH 0088/1180] Change inserting and deleting lines inside the scroll region to properly clear lines that should be inserted/deleted but not moved. Fixes problems with mutt reported by Brian Lewis, thanks. --- grid-view.c | 14 +++++++++++--- screen-write.c | 38 +++++++++++++++++++++++++++++++++----- 2 files changed, 44 insertions(+), 8 deletions(-) diff --git a/grid-view.c b/grid-view.c index a9144a1f..5ad8fc2f 100644 --- a/grid-view.c +++ b/grid-view.c @@ -134,13 +134,17 @@ grid_view_insert_lines(struct grid *gd, u_int py, u_int ny) void grid_view_insert_lines_region(struct grid *gd, u_int rlower, u_int py, u_int ny) { + u_int ny2; + GRID_DEBUG(gd, "rlower=%u, py=%u, ny=%u", rlower, py, ny); rlower = grid_view_y(gd, rlower); py = grid_view_y(gd, py); - grid_move_lines(gd, py + ny, py, (rlower + 1) - py - ny); + ny2 = rlower + 1 - py - ny; + grid_move_lines(gd, rlower + 1 - ny2, py, ny2); + grid_clear(gd, 0, py + ny2, gd->sx, ny - ny2); } /* Delete lines. */ @@ -156,20 +160,24 @@ grid_view_delete_lines(struct grid *gd, u_int py, u_int ny) sy = grid_view_y(gd, gd->sy); grid_move_lines(gd, py, py + ny, sy - py - ny); - grid_clear(gd, 0, sy - ny, gd->sx, py + ny - (sy - ny)); + grid_clear(gd, 0, sy - ny, gd->sx, py + ny - (sy - ny)); } /* Delete lines inside scroll region. */ void grid_view_delete_lines_region(struct grid *gd, u_int rlower, u_int py, u_int ny) { + u_int ny2; + GRID_DEBUG(gd, "rlower=%u, py=%u, ny=%u", rlower, py, ny); rlower = grid_view_y(gd, rlower); py = grid_view_y(gd, py); - grid_move_lines(gd, py, py + ny, (rlower + 1) - py - ny); + ny2 = rlower + 1 - py - ny; + grid_move_lines(gd, py, py + ny, ny2); + grid_clear(gd, 0, py + ny2, gd->sx, ny - ny2); } /* Insert characters. */ diff --git a/screen-write.c b/screen-write.c index 00a56c46..fb0cba6a 100644 --- a/screen-write.c +++ b/screen-write.c @@ -369,11 +369,25 @@ screen_write_insertline(struct screen_write_ctx *ctx, u_int ny) if (ny == 0) ny = 1; - if (ny > screen_size_y(s) - s->cy) - ny = screen_size_y(s) - s->cy; + if (s->cy < s->rupper || s->cy > s->rlower) { + if (ny > screen_size_y(s) - s->cy) + ny = screen_size_y(s) - s->cy; + if (ny == 0) + return; + + screen_write_save(ctx); + + grid_view_insert_lines(s->grid, s->cy, ny); + + tty_write_cmd(ctx->wp, TTY_INSERTLINE, ny); + return; + } + + if (ny > s->rlower + 1 - s->cy) + ny = s->rlower + 1 - s->cy; if (ny == 0) return; - + screen_write_save(ctx); if (s->cy < s->rupper || s->cy > s->rlower) @@ -393,8 +407,22 @@ screen_write_deleteline(struct screen_write_ctx *ctx, u_int ny) if (ny == 0) ny = 1; - if (ny > screen_size_y(s) - s->cy) - ny = screen_size_y(s) - s->cy; + if (s->cy < s->rupper || s->cy > s->rlower) { + if (ny > screen_size_y(s) - s->cy) + ny = screen_size_y(s) - s->cy; + if (ny == 0) + return; + + screen_write_save(ctx); + + grid_view_delete_lines(s->grid, s->cy, ny); + + tty_write_cmd(ctx->wp, TTY_DELETELINE, ny); + return; + } + + if (ny > s->rlower + 1 - s->cy) + ny = s->rlower + 1 - s->cy; if (ny == 0) return; From 29f9d5f3352175fcbfab36da18beb29490f13ae8 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 9 Jul 2009 09:54:56 +0000 Subject: [PATCH 0089/1180] Don't leak FILE * on malloc failure. From ivoire at users dot sourceforge dot net. --- cmd-load-buffer.c | 1 + 1 file changed, 1 insertion(+) diff --git a/cmd-load-buffer.c b/cmd-load-buffer.c index 23adfec2..11d2d548 100644 --- a/cmd-load-buffer.c +++ b/cmd-load-buffer.c @@ -78,6 +78,7 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) */ if ((buf = malloc(statbuf.st_size + 1)) == NULL) { ctx->error(ctx, "malloc error: %s", strerror(errno)); + fclose(f); return (-1); } From 24e1327d0d77f0c8e022e0cd5109db321da7b324 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 9 Jul 2009 15:02:00 +0000 Subject: [PATCH 0090/1180] Stop in the right place so all the lines selected are copied. Reported by Kalle Olavi Niemitalo, thanks. --- window-copy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/window-copy.c b/window-copy.c index a64be760..26a54f4c 100644 --- a/window-copy.c +++ b/window-copy.c @@ -443,7 +443,7 @@ window_copy_copy_selection(struct window_pane *wp, struct client *c) xx = window_copy_find_length(wp, sy); window_copy_copy_line(wp, &buf, &off, sy, sx, xx); if (ey - sy > 1) { - for (i = sy + 1; i < ey - 1; i++) { + for (i = sy + 1; i < ey; i++) { xx = window_copy_find_length(wp, i); window_copy_copy_line(wp, &buf, &off, i, 0, xx); } From 81181bfb72b306aed736ad7d8c9aaff0425e6730 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 9 Jul 2009 15:47:49 +0000 Subject: [PATCH 0091/1180] New command, if-shell (alias if). Executes the tmux command in the second argument if the shell command in the first succeeds, for example: if "[ -e ~/.tmux.conf.alt ]" "source .tmux.conf.alt" Written by Tiago Cunha, many thanks. --- Makefile | 2 +- cmd-if-shell.c | 176 +++++++++++++++++++++++++++++++++++++++++++++++++ cmd.c | 1 + tmux.1 | 10 +++ tmux.h | 1 + 5 files changed, 189 insertions(+), 1 deletion(-) create mode 100644 cmd-if-shell.c diff --git a/Makefile b/Makefile index 73f543b2..774e8341 100644 --- a/Makefile +++ b/Makefile @@ -22,7 +22,7 @@ SRCS= arg.c attributes.c buffer-poll.c buffer.c cfg.c client-fn.c \ cmd-send-prefix.c cmd-server-info.c cmd-set-buffer.c cmd-set-option.c \ cmd-set-password.c cmd-set-window-option.c cmd-show-buffer.c \ cmd-show-options.c cmd-show-window-options.c cmd-source-file.c \ - cmd-split-window.c cmd-start-server.c cmd-string.c \ + cmd-split-window.c cmd-start-server.c cmd-string.c cmd-if-shell.c \ cmd-suspend-client.c cmd-swap-pane.c cmd-swap-window.c \ cmd-switch-client.c cmd-unbind-key.c cmd-unlink-window.c \ cmd-up-pane.c cmd.c colour.c grid-view.c grid.c input-keys.c \ diff --git a/cmd-if-shell.c b/cmd-if-shell.c new file mode 100644 index 00000000..4f348a7e --- /dev/null +++ b/cmd-if-shell.c @@ -0,0 +1,176 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2009 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 +#include +#include + +#include "tmux.h" + +/* + * Executes a tmux command if a shell command returns true. + */ + +int cmd_if_shell_parse(struct cmd *, int, char **, char **); +int cmd_if_shell_exec(struct cmd *, struct cmd_ctx *); +void cmd_if_shell_send(struct cmd *, struct buffer *); +void cmd_if_shell_recv(struct cmd *, struct buffer *); +void cmd_if_shell_free(struct cmd *); +void cmd_if_shell_init(struct cmd *, int); +size_t cmd_if_shell_print(struct cmd *, char *, size_t); + +struct cmd_if_shell_data { + char *cmd; + char *sh_cmd; +}; + +const struct cmd_entry cmd_if_shell_entry = { + "if-shell", "if", + "shell-command command", + 0, + cmd_if_shell_init, + cmd_if_shell_parse, + cmd_if_shell_exec, + cmd_if_shell_send, + cmd_if_shell_recv, + cmd_if_shell_free, + cmd_if_shell_print +}; + +void +cmd_if_shell_init(struct cmd *self, unused int arg) +{ + struct cmd_if_shell_data *data; + + self->data = data = xmalloc(sizeof *data); + data->cmd = NULL; + data->sh_cmd = NULL; +} + +int +cmd_if_shell_parse(struct cmd *self, int argc, char **argv, char **cause) +{ + struct cmd_if_shell_data *data; + int opt; + + self->entry->init(self, 0); + data = self->data; + + while ((opt = getopt(argc, argv, "")) != -1) { + switch (opt) { + default: + goto usage; + } + } + argc -= optind; + argv += optind; + if (argc != 2) + goto usage; + + data->sh_cmd = xstrdup(argv[0]); + data->cmd = xstrdup(argv[1]); + return (0); + +usage: + xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); + + self->entry->free(self); + return (-1); +} + +int +cmd_if_shell_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_if_shell_data *data = self->data; + struct cmd_list *cmdlist; + char *cause; + int ret; + + if ((ret = system(data->sh_cmd)) < 0) { + ctx->error(ctx, "system error: %s", strerror(errno)); + return (-1); + } else if (ret != 0) + return (0); + + if (cmd_string_parse(data->cmd, &cmdlist, &cause) != 0) { + if (cause != NULL) { + ctx->error(ctx, "%s", cause); + xfree(cause); + } + return (-1); + } + + if (cmd_list_exec(cmdlist, ctx) < 0) { + cmd_list_free(cmdlist); + return (-1); + } + + cmd_list_free(cmdlist); + return (0); +} + +void +cmd_if_shell_send(struct cmd *self, struct buffer *b) +{ + struct cmd_if_shell_data *data = self->data; + + buffer_write(b, data, sizeof *data); + cmd_send_string(b, data->cmd); + cmd_send_string(b, data->sh_cmd); +} + +void +cmd_if_shell_recv(struct cmd *self, struct buffer *b) +{ + struct cmd_if_shell_data *data; + + self->data = data = xmalloc(sizeof *data); + buffer_read(b, data, sizeof *data); + data->cmd = cmd_recv_string(b); + data->sh_cmd = cmd_recv_string(b); +} + +void +cmd_if_shell_free(struct cmd *self) +{ + struct cmd_if_shell_data *data = self->data; + + if (data->cmd != NULL) + xfree(data->cmd); + if (data->sh_cmd != NULL) + xfree(data->sh_cmd); + xfree(data); +} + +size_t +cmd_if_shell_print(struct cmd *self, char *buf, size_t len) +{ + struct cmd_if_shell_data *data = self->data; + size_t off = 0; + + off += xsnprintf(buf, len, "%s", self->entry->name); + if (data == NULL) + return (off); + if (off < len && data->sh_cmd != NULL) + off += cmd_prarg(buf + off, len - off, " ", data->sh_cmd); + if (off < len && data->cmd != NULL) + off += cmd_prarg(buf + off, len - off, " ", data->cmd); + return (off); +} diff --git a/cmd.c b/cmd.c index af520f0f..7e98f8cc 100644 --- a/cmd.c +++ b/cmd.c @@ -42,6 +42,7 @@ const struct cmd_entry *cmd_table[] = { &cmd_down_pane_entry, &cmd_find_window_entry, &cmd_has_session_entry, + &cmd_if_shell_entry, &cmd_kill_pane_entry, &cmd_kill_server_entry, &cmd_kill_session_entry, diff --git a/tmux.1 b/tmux.1 index 31e94d62..a6ccd459 100644 --- a/tmux.1 +++ b/tmux.1 @@ -711,6 +711,16 @@ This command only works from inside .D1 (alias: Ic has ) Report an error and exit with 1 if the specified session does not exist. If it does exist, exit with 0. +.It Xo Ic if-shell +.Ar shell-command +.Ar command +.Xc +.D1 (alias: Ic if ) +Execute +.Ar command +if +.Ar shell-command +returns success. .It Xo Ic kill-pane .Op Fl p Ar pane-index .Op Fl t Ar target-window diff --git a/tmux.h b/tmux.h index bc60cab1..9df75e2c 100644 --- a/tmux.h +++ b/tmux.h @@ -1101,6 +1101,7 @@ extern const struct cmd_entry cmd_detach_client_entry; extern const struct cmd_entry cmd_down_pane_entry; extern const struct cmd_entry cmd_find_window_entry; extern const struct cmd_entry cmd_has_session_entry; +extern const struct cmd_entry cmd_if_shell_entry; extern const struct cmd_entry cmd_kill_pane_entry; extern const struct cmd_entry cmd_kill_server_entry; extern const struct cmd_entry cmd_kill_session_entry; From 5f2f07ed8a0ecaa2aacda59768c55e615b897cfb Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 9 Jul 2009 17:57:11 +0000 Subject: [PATCH 0092/1180] Cursor up and down should be limited by the scroll region (cuu should stop at the scroll region top if starting from below it and cud stop at the bottom if starting from above). Fixes another vttest test. --- screen-write.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/screen-write.c b/screen-write.c index fb0cba6a..5a2a3882 100644 --- a/screen-write.c +++ b/screen-write.c @@ -232,8 +232,15 @@ screen_write_cursorup(struct screen_write_ctx *ctx, u_int ny) if (ny == 0) ny = 1; - if (ny > s->cy) - ny = s->cy; + if (s->cy < s->rupper) { + /* Above region. */ + if (ny > s->cy) + ny = s->cy; + } else { + /* Below region. */ + if (ny > s->cy - s->rupper) + ny = s->cy - s->rupper; + } if (ny == 0) return; @@ -249,8 +256,15 @@ screen_write_cursordown(struct screen_write_ctx *ctx, u_int ny) if (ny == 0) ny = 1; - if (ny > screen_size_y(s) - 1 - s->cy) - ny = screen_size_y(s) - 1 - s->cy; + if (s->cy > s->rlower) { + /* Below region. */ + if (ny > screen_size_y(s) - 1 - s->cy) + ny = screen_size_y(s) - 1 - s->cy; + } else { + /* Above region. */ + if (ny > s->rlower - s->cy) + ny = s->rlower - s->cy; + } if (ny == 0) return; From 58361eb96520787c9105b0031efd3a6d8414acf1 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 9 Jul 2009 22:48:20 +0000 Subject: [PATCH 0093/1180] When the terminal size is reduced horizontally, don't truncate lines to the new width, so that if the same lines are later increased in size the content reappears. --- screen.c | 43 +++++++++---------------------------------- 1 file changed, 9 insertions(+), 34 deletions(-) diff --git a/screen.c b/screen.c index d296cd78..16c3b5ea 100644 --- a/screen.c +++ b/screen.c @@ -122,44 +122,19 @@ void screen_resize_x(struct screen *s, u_int sx) { struct grid *gd = s->grid; - const struct grid_cell *gc; - const struct grid_utf8 *gu; - u_int xx, yy; if (sx == 0) fatalx("zero size"); - /* If getting larger, not much to do. */ - if (sx > screen_size_x(s)) { - gd->sx = sx; - return; - } - - /* If getting smaller, nuke any data in lines over the new size. */ - for (yy = gd->hsize; yy < gd->hsize + screen_size_y(s); yy++) { - /* - * If the character after the last is wide or padding, remove - * it and any leading padding. - */ - gc = &grid_default_cell; - for (xx = sx; xx > 0; xx--) { - gc = grid_peek_cell(gd, xx - 1, yy); - if (!(gc->flags & GRID_FLAG_PADDING)) - break; - grid_set_cell(gd, xx - 1, yy, &grid_default_cell); - } - if (xx > 0 && xx != sx && gc->flags & GRID_FLAG_UTF8) { - gu = grid_peek_utf8(gd, xx - 1, yy); - if (gu->width > 1) { - grid_set_cell( - gd, xx - 1, yy, &grid_default_cell); - } - } - - /* Reduce the line size. */ - grid_reduce_line(gd, yy, sx); - } - + /* + * Treat resizing horizontally simply: just ensure the cursor is + * on-screen and change the size. Don't bother to truncate any lines - + * then the data should be accessible if the size is then incrased. + * + * The only potential wrinkle is if UTF-8 double-width characters are + * left in the last column, but UTF-8 terminals should deal with this + * sanely. + */ if (s->cx >= sx) s->cx = sx - 1; gd->sx = sx; From 25d57344966902e9d5a93eb46727a2f1ebd46a82 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 10 Jul 2009 05:43:01 +0000 Subject: [PATCH 0094/1180] Document display-time option which seems to have been missed. --- tmux.1 | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tmux.1 b/tmux.1 index a6ccd459..9a02ee47 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1090,6 +1090,10 @@ environment variable or, if it is unset, the user's shell returned by Set the default working directory for processes created from keys, or interactively from the prompt. The default is the current working directory when the server is started. +.It Ic display-time Ar time +Set the amount of time for which status line messages are displayed. +.Ar time +is in milliseconds. .It Ic history-limit Ar lines Set the maximum number of lines held in window history. This setting applies only to new windows - existing window histories are not @@ -1135,10 +1139,10 @@ or Set status line message foreground colour. .It Ic prefix Ar key Set the current prefix key. -.It Ic repeat-time Ar number +.It Ic repeat-time Ar time Allow multiple commands to be entered without pressing the prefix-key again in the specified -.Ar number +.Ar time milliseconds (the default is 500). Whether a key repeats may be set when it is bound using the .Fl r From daa1faa90510c09ddface800101ea86b167d1154 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 10 Jul 2009 05:50:54 +0000 Subject: [PATCH 0095/1180] Add a default-terminal option to set the starting value of $TERM in new windows. This is "screen" by default and must be either that or something closely related. This does makes it easier to customise it if necessary. --- cmd-set-option.c | 1 + server-fn.c | 8 ++++++-- tmux.1 | 12 ++++++++++++ tmux.c | 1 + tmux.h | 2 +- 5 files changed, 21 insertions(+), 3 deletions(-) diff --git a/cmd-set-option.c b/cmd-set-option.c index 9befb085..88e297b0 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -53,6 +53,7 @@ const struct set_option_entry set_option_table[NSETOPTION] = { { "buffer-limit", SET_OPTION_NUMBER, 1, INT_MAX, NULL }, { "default-command", SET_OPTION_STRING, 0, 0, NULL }, { "default-path", SET_OPTION_STRING, 0, 0, NULL }, + { "default-terminal", SET_OPTION_STRING, 0, 0, NULL }, { "display-time", SET_OPTION_NUMBER, 1, INT_MAX, NULL }, { "history-limit", SET_OPTION_NUMBER, 0, INT_MAX, NULL }, { "lock-after-time", SET_OPTION_NUMBER, 0, INT_MAX, NULL }, diff --git a/server-fn.c b/server-fn.c index fb40a624..2d6709f5 100644 --- a/server-fn.c +++ b/server-fn.c @@ -29,8 +29,8 @@ int server_lock_callback(void *, const char *); const char ** server_fill_environ(struct session *s) { - static const char *env[] = { NULL /* TMUX= */, "TERM=screen", NULL }; - static char tmuxvar[MAXPATHLEN + 256]; + static const char *env[] = { NULL /* TMUX= */, NULL /* TERM */, NULL }; + static char tmuxvar[MAXPATHLEN + 256], termvar[256]; u_int idx; if (session_index(s, &idx) != 0) @@ -40,6 +40,10 @@ server_fill_environ(struct session *s) "TMUX=%s,%ld,%u", socket_path, (long) getpid(), idx); env[0] = tmuxvar; + xsnprintf(termvar, sizeof termvar, + "TERM=%s", options_get_string(&s->options, "default-terminal")); + env[1] = termvar; + return (env); } diff --git a/tmux.1 b/tmux.1 index 9a02ee47..db292b16 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1090,6 +1090,18 @@ environment variable or, if it is unset, the user's shell returned by Set the default working directory for processes created from keys, or interactively from the prompt. The default is the current working directory when the server is started. +.It Ic default-terminal Ar terminal +Set the default terminal for new windows created in this session - the +default value of the +.Ev TERM +environment variable. +For +.Nm +to work correctly, this +.Em must +be set to +.Ql screen +or a derivative of it. .It Ic display-time Ar time Set the amount of time for which status line messages are displayed. .Ar time diff --git a/tmux.c b/tmux.c index c71c7264..a2f6e73b 100644 --- a/tmux.c +++ b/tmux.c @@ -270,6 +270,7 @@ main(int argc, char **argv) options_set_number(&global_s_options, "bell-action", BELL_ANY); options_set_number(&global_s_options, "buffer-limit", 9); options_set_string(&global_s_options, "default-command", "%s", ""); + options_set_string(&global_s_options, "default-terminal", "screen"); options_set_number(&global_s_options, "display-time", 750); options_set_number(&global_s_options, "history-limit", 2000); options_set_number(&global_s_options, "lock-after-time", 0); diff --git a/tmux.h b/tmux.h index 9df75e2c..a2d3063d 100644 --- a/tmux.h +++ b/tmux.h @@ -935,7 +935,7 @@ struct set_option_entry { }; extern const struct set_option_entry set_option_table[]; extern const struct set_option_entry set_window_option_table[]; -#define NSETOPTION 25 +#define NSETOPTION 26 #define NSETWINDOWOPTION 19 /* tmux.c */ From 4a6d62e40168fc8c33c0804dbe67bab2f29d4f68 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 10 Jul 2009 07:11:59 +0000 Subject: [PATCH 0096/1180] Don't send initialisation strings is1/2/3 (barely anything else does) and move smcup to the first and rmcup to the last sequences output to the terminal. This allows tmux to use the alternate screen (smcup/rmcup) when available. --- tty.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/tty.c b/tty.c index 1ce8b226..3a536bae 100644 --- a/tty.c +++ b/tty.c @@ -157,11 +157,8 @@ tty_start_tty(struct tty *tty) if (ioctl(tty->fd, TIOCFLUSH, &what) != 0) fatal("ioctl(TIOCFLUSH)"); - tty_putcode(tty, TTYC_IS1); - tty_putcode(tty, TTYC_IS2); - tty_putcode(tty, TTYC_IS3); - tty_putcode(tty, TTYC_SMCUP); + tty_putcode(tty, TTYC_SMKX); tty_putcode(tty, TTYC_ENACS); tty_putcode(tty, TTYC_CLEAR); @@ -200,12 +197,13 @@ tty_stop_tty(struct tty *tty) tty_raw(tty, tty_term_string(tty->term, TTYC_RMACS)); tty_raw(tty, tty_term_string(tty->term, TTYC_SGR0)); tty_raw(tty, tty_term_string(tty->term, TTYC_RMKX)); - tty_raw(tty, tty_term_string(tty->term, TTYC_RMCUP)); tty_raw(tty, tty_term_string(tty->term, TTYC_CLEAR)); tty_raw(tty, tty_term_string(tty->term, TTYC_CNORM)); if (tty_term_has(tty->term, TTYC_KMOUS)) tty_raw(tty, "\033[?1000l"); + + tty_raw(tty, tty_term_string(tty->term, TTYC_RMCUP)); } #if 0 From 9cd5ba40d3adf23c7a93252ebc39e9d9a19a0664 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 10 Jul 2009 17:34:51 +0000 Subject: [PATCH 0097/1180] Redraw the status line after renaming a session (it may contain the name). --- cmd-rename-session.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmd-rename-session.c b/cmd-rename-session.c index b05835f1..305795fd 100644 --- a/cmd-rename-session.c +++ b/cmd-rename-session.c @@ -53,5 +53,7 @@ cmd_rename_session_exec(struct cmd *self, struct cmd_ctx *ctx) xfree(s->name); s->name = xstrdup(data->arg); + server_status_session(s); + return (0); } From 4cbbbddf22a74b7e3d13576641e650775880295c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 10 Jul 2009 19:01:40 +0000 Subject: [PATCH 0098/1180] paste-buffer -d was not documented. From Kalle Olavi Niemitalo. --- tmux.1 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tmux.1 b/tmux.1 index db292b16..20b92cdb 100644 --- a/tmux.1 +++ b/tmux.1 @@ -894,6 +894,9 @@ is used, move to the next window with a bell, activity or content alert. .Xc .D1 (alias: Ic pasteb ) Insert the contents of a paste buffer into the current window. +With +.Fl d , +also delete the paste buffer from the stack. .It Xo Ic previous-window .Op Fl a .Op Fl t Ar target-session From 289320a9b19e6be855756e54a545615026b099f8 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 11 Jul 2009 19:09:24 +0000 Subject: [PATCH 0099/1180] Copy was using the real line length which after resize can be larger than the screen width. When built with -DDEBUG, this made the grid bounds checking code kill the server. Restrict copying to the actual width. From Kalle Olavi Niemitalo, thanks. --- window-copy.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/window-copy.c b/window-copy.c index 26a54f4c..5aff70ff 100644 --- a/window-copy.c +++ b/window-copy.c @@ -522,7 +522,15 @@ window_copy_find_length(struct window_pane *wp, u_int py) const struct grid_cell *gc; u_int px; + /* + * If the pane has been resized, its grid can contain old overlong + * lines. grid_peek_cell does not allow accessing cells beyond the + * width of the grid, and screen_write_copy treats them as spaces, so + * ignore them here too. + */ px = wp->base.grid->size[py]; + if (px > screen_size_x(&wp->base)) + px = screen_size_x(&wp->base); while (px > 0) { gc = grid_peek_cell(wp->base.grid, px - 1, py); if (gc->flags & GRID_FLAG_UTF8) From 2f7198246e1074e0ff132036182c5a4050506073 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 11 Jul 2009 19:14:56 +0000 Subject: [PATCH 0100/1180] When pasting, translate \n into \r. This matches xterm and putty's behaviour, and makes emacs happy when pasting into some modes. A new -r (raw) flag to paste-buffer pastes without the translation. From Kalle Olavi Niemitalo, thanks! --- cmd-generic.c | 12 ++++++++++-- cmd-paste-buffer.c | 35 +++++++++++++++++++++++++++++++---- tmux.1 | 5 +++++ tmux.h | 1 + 4 files changed, 47 insertions(+), 6 deletions(-) diff --git a/cmd-generic.c b/cmd-generic.c index 01254a06..1b2e17a9 100644 --- a/cmd-generic.c +++ b/cmd-generic.c @@ -23,9 +23,9 @@ #include "tmux.h" -#define CMD_FLAGS "adDgkuU" +#define CMD_FLAGS "adDgkruU" #define CMD_FLAGMASK (CMD_AFLAG|CMD_DFLAG|CMD_BIGDFLAG|CMD_GFLAG|CMD_KFLAG| \ - CMD_UFLAG|CMD_BIGUFLAG) + CMD_RFLAG|CMD_UFLAG|CMD_BIGUFLAG) int cmd_do_flags(int, int, int *); size_t cmd_print_flags(char *, size_t, size_t, int); @@ -73,6 +73,12 @@ cmd_do_flags(int opt, int iflags, int *oflags) return (0); } return (-1); + case 'r': + if (iflags & CMD_RFLAG) { + (*oflags) |= CMD_RFLAG; + return (0); + } + return (-1); case 'u': if (iflags & CMD_UFLAG) { (*oflags) |= CMD_UFLAG; @@ -107,6 +113,8 @@ cmd_print_flags(char *buf, size_t len, size_t off, int flags) off += xsnprintf(buf + off, len - off, "g"); if (off < len && flags & CMD_KFLAG) off += xsnprintf(buf + off, len - off, "k"); + if (off < len && flags & CMD_RFLAG) + off += xsnprintf(buf + off, len - off, "r"); if (off < len && flags & CMD_UFLAG) off += xsnprintf(buf + off, len - off, "u"); if (off < len && flags & CMD_BIGUFLAG) diff --git a/cmd-paste-buffer.c b/cmd-paste-buffer.c index 3f4cfe2e..c586e0fc 100644 --- a/cmd-paste-buffer.c +++ b/cmd-paste-buffer.c @@ -27,11 +27,12 @@ */ int cmd_paste_buffer_exec(struct cmd *, struct cmd_ctx *); +void cmd_paste_buffer_lf2cr(struct buffer *, const char *, size_t); const struct cmd_entry cmd_paste_buffer_entry = { "paste-buffer", "pasteb", - "[-d] " CMD_BUFFER_WINDOW_USAGE, - CMD_DFLAG, + "[-dr] " CMD_BUFFER_WINDOW_USAGE, + CMD_DFLAG|CMD_RFLAG, cmd_buffer_init, cmd_buffer_parse, cmd_paste_buffer_exec, @@ -63,8 +64,16 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) } } - if (pb != NULL && *pb->data != '\0') - buffer_write(w->active->out, pb->data, strlen(pb->data)); + if (pb != NULL && *pb->data != '\0') { + /* -r means raw data without LF->CR conversion. */ + if (data->flags & CMD_RFLAG) { + buffer_write( + w->active->out, pb->data, strlen(pb->data)); + } else { + cmd_paste_buffer_lf2cr( + w->active->out, pb->data, strlen(pb->data)); + } + } /* Delete the buffer if -d. */ if (data->flags & CMD_DFLAG) { @@ -76,3 +85,21 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) return (0); } + +/* Add bytes to a buffer but change every '\n' to '\r'. */ +void +cmd_paste_buffer_lf2cr(struct buffer *b, const char *data, size_t size) +{ + const char *end = data + size; + const char *lf; + + while ((lf = memchr(data, '\n', end - data)) != NULL) { + if (lf != data) + buffer_write(b, data, lf - data); + buffer_write8(b, '\r'); + data = lf + 1; + } + + if (end != data) + buffer_write(b, data, end - data); +} diff --git a/tmux.1 b/tmux.1 index 20b92cdb..62b98b97 100644 --- a/tmux.1 +++ b/tmux.1 @@ -897,6 +897,11 @@ Insert the contents of a paste buffer into the current window. With .Fl d , also delete the paste buffer from the stack. +When output, any linefeed (LF) characters in the paste buffer are replaced with +carriage returns (CR). +This translation may be disabled with the +.Fl r +flag. .It Xo Ic previous-window .Op Fl a .Op Fl t Ar target-session diff --git a/tmux.h b/tmux.h index a2d3063d..02f08ed4 100644 --- a/tmux.h +++ b/tmux.h @@ -858,6 +858,7 @@ struct cmd_entry { #define CMD_UFLAG 0x100 #define CMD_BIGDFLAG 0x200 #define CMD_BIGUFLAG 0x400 +#define CMD_RFLAG 0x800 int flags; From e415ead361e7b0a9af9290579949cf42f4fa0f00 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 11 Jul 2009 20:04:19 +0000 Subject: [PATCH 0101/1180] Add -r to the synopsis of the paste-buffer command, prompted by jmc. --- tmux.1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tmux.1 b/tmux.1 index 62b98b97..f0294ce1 100644 --- a/tmux.1 +++ b/tmux.1 @@ -888,7 +888,7 @@ If .Fl a is used, move to the next window with a bell, activity or content alert. .It Xo Ic paste-buffer -.Op Fl d +.Op Fl dr .Op Fl b Ar buffer-index .Op Fl t Ar target-window .Xc From bd098c273b6a8ac6a0d493194cacd2e231bbeefe Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 11 Jul 2009 20:11:18 +0000 Subject: [PATCH 0102/1180] Limit the history to hlimit not hlimit - 1. This makes a history-limit setting of 0 work as expected. --- grid.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grid.c b/grid.c index 2df28fd7..92683716 100644 --- a/grid.c +++ b/grid.c @@ -172,7 +172,7 @@ grid_scroll_line(struct grid *gd) GRID_DEBUG(gd, ""); - if (gd->hsize >= gd->hlimit - 1) { + if (gd->hsize >= gd->hlimit) { /* If the limit is hit, free the bottom 10% and shift up. */ yy = gd->hlimit / 10; if (yy < 1) From 22355ce947da7acd8863d7f7a467324ad030faec Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 12 Jul 2009 16:07:56 +0000 Subject: [PATCH 0103/1180] If it exist, load a system-wide configuration file /etc/tmux.conf before any user-specified one. --- server.c | 11 +++++++++++ tmux.1 | 8 ++++++-- tmux.h | 3 ++- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/server.c b/server.c index 6ba83d87..e9986a72 100644 --- a/server.c +++ b/server.c @@ -171,6 +171,17 @@ server_start(char *path) start_time = time(NULL); socket_path = path; + if (access(SYSTEM_CFG, R_OK) != 0) { + if (errno != ENOENT) { + log_warn("%s", SYSTEM_CFG); + exit(1); + } + } else { + if (load_cfg(SYSTEM_CFG, &cause) != 0) { + log_warnx("%s", cause); + exit(1); + } + } if (cfg_file != NULL && load_cfg(cfg_file, &cause) != 0) { log_warnx("%s", cause); exit(1); diff --git a/tmux.1 b/tmux.1 index f0294ce1..588d70e4 100644 --- a/tmux.1 +++ b/tmux.1 @@ -70,7 +70,9 @@ to assume the terminal supports default colours. Specify an alternative configuration file. By default, .Nm -will look for a config file at +loads the system configuration file from +.Pa /etc/tmux.conf , +if present, then looks for a user configuration file at .Pa ~/.tmux.conf . The configuration file is a set of .Nm @@ -1549,11 +1551,13 @@ not be linked to no sessions. Move up a pane. .El .Sh FILES -.Bl -tag -width "~/.tmux.confXXX" -compact +.Bl -tag -width "/etc/tmux.confXXX" -compact .It Pa ~/.tmux.conf Default .Nm configuration file. +.It Pa /etc/tmux.conf +System-wide configuration file. .El .Sh SEE ALSO .Xr pty 4 diff --git a/tmux.h b/tmux.h index 02f08ed4..d2409f62 100644 --- a/tmux.h +++ b/tmux.h @@ -40,8 +40,9 @@ extern const char *__progname; -/* Default configuration file. */ +/* Default configuration files. */ #define DEFAULT_CFG ".tmux.conf" +#define SYSTEM_CFG "/etc/tmux.conf" /* Default prompt history length. */ #define PROMPT_HISTORY 100 From fa8333eddb747e9b3c2a72c4fab4308137891f49 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 12 Jul 2009 16:12:34 +0000 Subject: [PATCH 0104/1180] Merge three copies of identical code to move the cursor x position into a single function, from Kalle Olavi Niemitalo. --- window-copy.c | 116 +++++++++++++++----------------------------------- 1 file changed, 35 insertions(+), 81 deletions(-) diff --git a/window-copy.c b/window-copy.c index 5aff70ff..fb249698 100644 --- a/window-copy.c +++ b/window-copy.c @@ -48,6 +48,7 @@ void window_copy_copy_line( struct window_pane *, char **, size_t *, u_int, u_int, u_int); int window_copy_is_space(struct window_pane *, u_int, u_int); u_int window_copy_find_length(struct window_pane *, u_int); +void window_copy_set_cursor_x(struct window_pane *, u_int); void window_copy_cursor_start_of_line(struct window_pane *); void window_copy_cursor_end_of_line(struct window_pane *); void window_copy_cursor_left(struct window_pane *); @@ -542,30 +543,15 @@ window_copy_find_length(struct window_pane *wp, u_int py) return (px); } +/* + * Set the cursor X coordinate and scroll horizontally to make it visible. + * Also redraw the selection or the cursor, as needed. + */ void -window_copy_cursor_start_of_line(struct window_pane *wp) -{ - struct window_copy_mode_data *data = wp->modedata; - - if (data->ox != 0) - window_copy_scroll_right(wp, data->ox); - data->cx = 0; - - if (window_copy_update_selection(wp)) - window_copy_redraw_lines(wp, data->cy, 1); - else - window_copy_update_cursor(wp); -} - -void -window_copy_cursor_end_of_line(struct window_pane *wp) +window_copy_set_cursor_x(struct window_pane *wp, u_int px) { struct window_copy_mode_data *data = wp->modedata; struct screen *s = &data->screen; - u_int px, py; - - py = screen_hsize(&wp->base) + data->cy - data->oy; - px = window_copy_find_length(wp, py); /* On screen. */ if (px > data->ox && px <= data->ox + screen_size_x(s) - 1) @@ -599,6 +585,33 @@ window_copy_cursor_end_of_line(struct window_pane *wp) window_copy_update_cursor(wp); } +void +window_copy_cursor_start_of_line(struct window_pane *wp) +{ + struct window_copy_mode_data *data = wp->modedata; + + if (data->ox != 0) + window_copy_scroll_right(wp, data->ox); + data->cx = 0; + + if (window_copy_update_selection(wp)) + window_copy_redraw_lines(wp, data->cy, 1); + else + window_copy_update_cursor(wp); +} + +void +window_copy_cursor_end_of_line(struct window_pane *wp) +{ + struct window_copy_mode_data *data = wp->modedata; + u_int px, py; + + py = screen_hsize(&wp->base) + data->cy - data->oy; + px = window_copy_find_length(wp, py); + + window_copy_set_cursor_x(wp, px); +} + void window_copy_cursor_left(struct window_pane *wp) { @@ -748,43 +761,13 @@ window_copy_cursor_next_word(struct window_pane *wp) } out: - /* On screen. */ - if (px > data->ox && px <= data->ox + screen_size_x(s) - 1) - data->cx = px - data->ox; - - /* Off right of screen. */ - if (px > data->ox + screen_size_x(s) - 1) { - /* Move cursor to last and scroll screen. */ - window_copy_scroll_left( - wp, px - data->ox - (screen_size_x(s) - 1)); - data->cx = screen_size_x(s) - 1; - } - - /* Off left of screen. */ - if (px <= data->ox) { - if (px < screen_size_x(s) - 1) { - /* Short enough to fit on screen. */ - window_copy_scroll_right(wp, data->ox); - data->cx = px; - } else { - /* Too long to fit on screen. */ - window_copy_scroll_right( - wp, data->ox - (px - (screen_size_x(s) - 1))); - data->cx = screen_size_x(s) - 1; - } - } - - if (window_copy_update_selection(wp)) - window_copy_redraw_lines(wp, data->cy, 1); - else - window_copy_update_cursor(wp); + window_copy_set_cursor_x(wp, px); } void window_copy_cursor_previous_word(struct window_pane *wp) { struct window_copy_mode_data *data = wp->modedata; - struct screen *s = &data->screen; u_int ox, px, py, skip; ox = px = data->ox + data->cx; @@ -830,36 +813,7 @@ window_copy_cursor_previous_word(struct window_pane *wp) } out: - /* On screen. */ - if (px > data->ox && px <= data->ox + screen_size_x(s) - 1) - data->cx = px - data->ox; - - /* Off right of screen. */ - if (px > data->ox + screen_size_x(s) - 1) { - /* Move cursor to last and scroll screen. */ - window_copy_scroll_left( - wp, px - data->ox - (screen_size_x(s) - 1)); - data->cx = screen_size_x(s) - 1; - } - - /* Off left of screen. */ - if (px <= data->ox) { - if (px < screen_size_x(s) - 1) { - /* Short enough to fit on screen. */ - window_copy_scroll_right(wp, data->ox); - data->cx = px; - } else { - /* Too long to fit on screen. */ - window_copy_scroll_right( - wp, data->ox - (px - (screen_size_x(s) - 1))); - data->cx = screen_size_x(s) - 1; - } - } - - if (window_copy_update_selection(wp)) - window_copy_redraw_lines(wp, data->cy, 1); - else - window_copy_update_cursor(wp); + window_copy_set_cursor_x(wp, px); } void From 22d51ec1ead8077f9528727db56e54e997da1775 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 12 Jul 2009 16:15:34 +0000 Subject: [PATCH 0105/1180] Add a "back to indentation" key in copy mode to move the cursor to the first non-whitespace character. ^ with vi and M-m with emacs key bindings. Another from Kalle Olavi Niemitalo, thanks. --- mode-key.c | 5 ++++- status.c | 1 + tmux.1 | 3 ++- tmux.h | 1 + window-copy.c | 31 +++++++++++++++++++++++++++++++ 5 files changed, 39 insertions(+), 2 deletions(-) diff --git a/mode-key.c b/mode-key.c index ba1d12d1..8f822cb0 100644 --- a/mode-key.c +++ b/mode-key.c @@ -105,8 +105,9 @@ mode_key_lookup_vi(struct mode_key_data *mdata, int key) return (MODEKEYCMD_CHOOSE); return (MODEKEYCMD_COPYSELECTION); case '0': - case '^': return (MODEKEYCMD_STARTOFLINE); + case '^': + return (MODEKEYCMD_BACKTOINDENTATION); case '\033': return (MODEKEYCMD_CLEARSELECTION); case 'j': @@ -160,6 +161,8 @@ mode_key_lookup_emacs(struct mode_key_data *mdata, int key) return (MODEKEYCMD_CHOOSE); case '\001': return (MODEKEYCMD_STARTOFLINE); + case KEYC_ADDESC('m'): + return (MODEKEYCMD_BACKTOINDENTATION); case '\007': return (MODEKEYCMD_CLEARSELECTION); case '\027': diff --git a/status.c b/status.c index 8aea62a7..6841468f 100644 --- a/status.c +++ b/status.c @@ -709,6 +709,7 @@ status_prompt_key(struct client *c, int key) } break; case MODEKEYCMD_STARTOFLINE: + case MODEKEYCMD_BACKTOINDENTATION: if (c->prompt_index != 0) { c->prompt_index = 0; c->flags |= CLIENT_STATUS; diff --git a/tmux.1 b/tmux.1 index 588d70e4..30ab53e4 100644 --- a/tmux.1 +++ b/tmux.1 @@ -306,7 +306,8 @@ option). The following keys are supported as appropriate for the mode: .Bl -column "FunctionXXXXXXXXXXXX" "viXXXXXX" "emacs" -offset indent .It Sy "Function" Ta Sy "vi" Ta Sy "emacs" -.It Li "Start of line" Ta "0 or ^" Ta "C-a" +.It Li "Start of line" Ta "0" Ta "C-a" +.It Li "Back to indentation" Ta "^" Ta "M-m" .It Li "Clear selection" Ta "Escape" Ta "C-g" .It Li "Copy selection" Ta "Enter" Ta "M-w" .It Li "Cursor down" Ta "j" Ta "Down" diff --git a/tmux.h b/tmux.h index d2409f62..3aed2560 100644 --- a/tmux.h +++ b/tmux.h @@ -357,6 +357,7 @@ struct msg_resize_data { /* Editing keys. */ enum mode_key_cmd { MODEKEYCMD_BACKSPACE = 0x1000, + MODEKEYCMD_BACKTOINDENTATION, MODEKEYCMD_CHOOSE, MODEKEYCMD_CLEARSELECTION, MODEKEYCMD_COMPLETE, diff --git a/window-copy.c b/window-copy.c index fb249698..04f22a8a 100644 --- a/window-copy.c +++ b/window-copy.c @@ -50,6 +50,7 @@ int window_copy_is_space(struct window_pane *, u_int, u_int); u_int window_copy_find_length(struct window_pane *, u_int); void window_copy_set_cursor_x(struct window_pane *, u_int); void window_copy_cursor_start_of_line(struct window_pane *); +void window_copy_cursor_back_to_indentation(struct window_pane *); void window_copy_cursor_end_of_line(struct window_pane *); void window_copy_cursor_left(struct window_pane *); void window_copy_cursor_right(struct window_pane *); @@ -207,6 +208,9 @@ window_copy_key(struct window_pane *wp, struct client *c, int key) case MODEKEYCMD_STARTOFLINE: window_copy_cursor_start_of_line(wp); break; + case MODEKEYCMD_BACKTOINDENTATION: + window_copy_cursor_back_to_indentation(wp); + break; case MODEKEYCMD_ENDOFLINE: window_copy_cursor_end_of_line(wp); break; @@ -600,6 +604,33 @@ window_copy_cursor_start_of_line(struct window_pane *wp) window_copy_update_cursor(wp); } +void +window_copy_cursor_back_to_indentation(struct window_pane *wp) +{ + struct window_copy_mode_data *data = wp->modedata; + u_int px, py, xx; + const struct grid_cell *gc; + + px = 0; + py = screen_hsize(&wp->base) + data->cy - data->oy; + xx = window_copy_find_length(wp, py); + + /* + * Don't use window_copy_is_space because that treats some word + * delimiters as spaces. + */ + while (px < xx) { + gc = grid_peek_cell(wp->base.grid, px, py); + if (gc->flags & GRID_FLAG_UTF8) + break; + if (gc->data != ' ') + break; + px++; + } + + window_copy_set_cursor_x(wp, px); +} + void window_copy_cursor_end_of_line(struct window_pane *wp) { From 9e49ec6cd325bf521f63450f3f87525cb82c63a9 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 12 Jul 2009 17:33:18 +0000 Subject: [PATCH 0106/1180] Creating a key binding which replaces itself (such as "bind x bind x lsw") frees the command list bound to the key while it is still being executed, leading to a use after free. To prevent this, create a dead keys list and defer freeing replaced or removed key bindings until the main loop when the key binding will have finished executing. Found by Johan Friis when creating a key binding to reload his configuration file. --- key-bindings.c | 29 +++++++++++++++++++++-------- server.c | 3 +++ 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/key-bindings.c b/key-bindings.c index fc232928..438836f3 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -27,6 +27,7 @@ SPLAY_GENERATE(key_bindings, key_binding, entry, key_bindings_cmp); struct key_bindings key_bindings; +struct key_bindings dead_key_bindings; int key_bindings_cmp(struct key_binding *bd1, struct key_binding *bd2) @@ -48,12 +49,12 @@ key_bindings_add(int key, int can_repeat, struct cmd_list *cmdlist) { struct key_binding *bd; - if ((bd = key_bindings_lookup(key)) == NULL) { - bd = xmalloc(sizeof *bd); - bd->key = key; - SPLAY_INSERT(key_bindings, &key_bindings, bd); - } else - cmd_list_free(bd->cmdlist); + key_bindings_remove(key); + + bd = xmalloc(sizeof *bd); + bd->key = key; + SPLAY_INSERT(key_bindings, &key_bindings, bd); + bd->can_repeat = can_repeat; bd->cmdlist = cmdlist; } @@ -66,9 +67,20 @@ key_bindings_remove(int key) if ((bd = key_bindings_lookup(key)) == NULL) return; SPLAY_REMOVE(key_bindings, &key_bindings, bd); + SPLAY_INSERT(key_bindings, &dead_key_bindings, bd); +} - cmd_list_free(bd->cmdlist); - xfree(bd); +void +key_bindings_clean(void) +{ + struct key_binding *bd; + + while (!SPLAY_EMPTY(&dead_key_bindings)) { + bd = SPLAY_ROOT(&dead_key_bindings); + SPLAY_REMOVE(key_bindings, &dead_key_bindings, bd); + cmd_list_free(bd->cmdlist); + xfree(bd); + } } void @@ -162,6 +174,7 @@ key_bindings_free(void) { struct key_binding *bd; + key_bindings_clean(); while (!SPLAY_EMPTY(&key_bindings)) { bd = SPLAY_ROOT(&key_bindings); SPLAY_REMOVE(key_bindings, &key_bindings, bd); diff --git a/server.c b/server.c index e9986a72..71b619ae 100644 --- a/server.c +++ b/server.c @@ -346,6 +346,9 @@ server_main(int srv_fd) server_handle_windows(&pfd); server_handle_clients(&pfd); + /* Collect any unset key bindings. */ + key_bindings_clean(); + /* * If we have no sessions and clients left, let's get out * of here... From 88555d96d5c979a2675e079dbd26188ed092fb88 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 12 Jul 2009 23:45:03 +0000 Subject: [PATCH 0107/1180] Document the -k flag to new-window. --- tmux.1 | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tmux.1 b/tmux.1 index 30ab53e4..e3965c7a 100644 --- a/tmux.1 +++ b/tmux.1 @@ -847,7 +847,7 @@ and .Ar command are the name of and command to execute in the initial window. .It Xo Ic new-window -.Op Fl d +.Op Fl dk .Op Fl n Ar window-name .Op Fl t Ar target-window .Op Ar command @@ -858,7 +858,10 @@ If .Fl d is given, the session does not make the new window the current window. .Ar target-window -represents the window to be created. +represents the window to be created; if the target already exists an error is +shown, unless the +.Fl k +flag is used, in which case it is destroyed. .Ar command is the command to execute. If From 0b788a3d61994e5a7a98e36d104c130dcbb5e0c9 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 12 Jul 2009 23:46:49 +0000 Subject: [PATCH 0108/1180] Missed this declaration in key bindings change. Whoops. --- tmux.h | 1 + 1 file changed, 1 insertion(+) diff --git a/tmux.h b/tmux.h index 3aed2560..28778e9f 100644 --- a/tmux.h +++ b/tmux.h @@ -1239,6 +1239,7 @@ SPLAY_PROTOTYPE(key_bindings, key_binding, entry, key_bindings_cmp); struct key_binding *key_bindings_lookup(int); void key_bindings_add(int, int, struct cmd_list *); void key_bindings_remove(int); +void key_bindings_clean(void); void key_bindings_init(void); void key_bindings_free(void); void key_bindings_dispatch(struct key_binding *, struct client *); From 359285928b63605a130990699c33c8af42be9fd2 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 13 Jul 2009 10:43:52 +0000 Subject: [PATCH 0109/1180] Support "alternate screen" mode (terminfo smcup/rmcup) typically used by full screen interactive programs to preserve the screen contents. When activated, it saves a copy of the visible grid and disables scrolling into and resizing out of the history; when deactivated the visible data is restored and the history reenabled. --- grid-view.c | 2 +- grid.c | 46 +++++++++++++++++++++++++++++++++ input.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++-- screen.c | 26 ++++++++++++++----- tmux.h | 10 ++++++++ window.c | 4 +++ 6 files changed, 153 insertions(+), 9 deletions(-) diff --git a/grid-view.c b/grid-view.c index 5ad8fc2f..bf58c61f 100644 --- a/grid-view.c +++ b/grid-view.c @@ -92,7 +92,7 @@ grid_view_scroll_region_up(struct grid *gd, u_int rupper, u_int rlower) { GRID_DEBUG(gd, "rupper=%u, rlower=%u", rupper, rlower); - if (rupper == 0 && rlower == gd->sy - 1) { + if (gd->flags & GRID_HISTORY && rupper == 0 && rlower == gd->sy - 1) { grid_scroll_line(gd); return; } diff --git a/grid.c b/grid.c index 92683716..38560f73 100644 --- a/grid.c +++ b/grid.c @@ -95,6 +95,8 @@ grid_create(u_int sx, u_int sy, u_int hlimit) gd->sx = sx; gd->sy = sy; + gd->flags = GRID_HISTORY; + gd->hsize = 0; gd->hlimit = hlimit; @@ -517,3 +519,47 @@ grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx) buf[off] = '\0'; return (buf); } + +/* + * Duplicate a set of lines between two grids. If there aren't enough lines in + * either source or destination, the number of lines is limited to the number + * available. + */ +void +grid_duplicate_lines( + struct grid *dst, u_int dy, struct grid *src, u_int sy, u_int ny) +{ + u_int yy; + + GRID_DEBUG(src, "dy=%u, sy=%u, ny=%u", dy, sy, ny); + + if (dy + ny > dst->hsize + dst->sy) + ny = dst->hsize + dst->sy - dy; + if (sy + ny > src->hsize + src->sy) + ny = src->hsize + src->sy - sy; + grid_clear_lines(dst, dy, ny); + + for (yy = 0; yy < ny; yy++) { + dst->size[dy] = src->size[sy]; + if (src->size[sy] == 0) + dst->data[dy] = NULL; + else { + dst->data[dy] = xcalloc( + src->size[sy], sizeof **dst->data); + memcpy(dst->data[dy], src->data[sy], + src->size[sy] * (sizeof **dst->data)); + } + + dst->usize[dy] = src->usize[sy]; + if (src->usize[sy] == 0) + dst->udata[dy] = NULL; + else { + dst->udata[sy] = xcalloc( + src->usize[sy], sizeof **dst->udata); + memcpy(dst->udata[dy], src->udata[sy], + src->usize[sy] * (sizeof **dst->udata)); + } + + sy++; dy++; + } +} diff --git a/input.c b/input.c index b1247f2b..b75494c8 100644 --- a/input.c +++ b/input.c @@ -1151,7 +1151,10 @@ input_handle_sequence_el(struct input_ctx *ictx) void input_handle_sequence_sm(struct input_ctx *ictx) { - uint16_t n; + struct window_pane *wp = ictx->wp; + struct screen *s = &wp->base; + u_int sx, sy; + uint16_t n; if (ARRAY_LENGTH(&ictx->args) > 1) return; @@ -1172,6 +1175,29 @@ input_handle_sequence_sm(struct input_ctx *ictx) screen_write_mousemode(&ictx->ctx, 1); log_debug("mouse on"); break; + case 1049: + if (wp->saved_grid != NULL) + break; + sx = screen_size_x(s); + sy = screen_size_y(s); + + /* + * Enter alternative screen mode. A copy of the visible + * screen is saved and the history is not updated + */ + + wp->saved_grid = grid_create(sx, sy, 0); + grid_duplicate_lines( + wp->saved_grid, 0, s->grid, screen_hsize(s), sy); + wp->saved_cx = s->cx; + wp->saved_cy = s->cy; + + grid_view_clear(s->grid, 0, 0, sx, sy); + + wp->base.grid->flags &= ~GRID_HISTORY; + + wp->flags |= PANE_REDRAW; + break; default: log_debug("unknown SM [%hhu]: %u", ictx->private, n); break; @@ -1195,7 +1221,10 @@ input_handle_sequence_sm(struct input_ctx *ictx) void input_handle_sequence_rm(struct input_ctx *ictx) { - uint16_t n; + struct window_pane *wp = ictx->wp; + struct screen *s = &wp->base; + u_int sx, sy; + uint16_t n; if (ARRAY_LENGTH(&ictx->args) > 1) return; @@ -1216,6 +1245,47 @@ input_handle_sequence_rm(struct input_ctx *ictx) screen_write_mousemode(&ictx->ctx, 0); log_debug("mouse off"); break; + case 1049: + if (wp->saved_grid == NULL) + break; + sx = screen_size_x(s); + sy = screen_size_y(s); + + /* + * Exit alternative screen mode and restore the copied + * grid. + */ + + /* + * If the current size is bigger, temporarily resize + * to the old size before copying back. + */ + if (sy > wp->saved_grid->sy) + screen_resize(s, sx, wp->saved_grid->sy); + + /* Restore the grid and cursor position. */ + grid_duplicate_lines( + s->grid, screen_hsize(s), wp->saved_grid, 0, sy); + s->cx = wp->saved_cx; + if (s->cx > screen_size_x(s) - 1) + s->cx = screen_size_x(s) - 1; + s->cy = wp->saved_cy; + if (s->cy > screen_size_y(s) - 1) + s->cy = screen_size_y(s) - 1; + + /* + * Turn history back on (so resize can use it) and then + * resize back to the current size. + */ + wp->base.grid->flags |= GRID_HISTORY; + if (sy > wp->saved_grid->sy) + screen_resize(s, sx, sy); + + grid_destroy(wp->saved_grid); + wp->saved_grid = NULL; + + wp->flags |= PANE_REDRAW; + break; default: log_debug("unknown RM [%hhu]: %u", ictx->private, n); break; diff --git a/screen.c b/screen.c index 16c3b5ea..f1a723a3 100644 --- a/screen.c +++ b/screen.c @@ -174,10 +174,20 @@ screen_resize_y(struct screen *s, u_int sy) needed -= available; /* - * Now just increase the history size to take over the lines - * which are left. XXX Should apply history limit? + * Now just increase the history size, if possible, to take + * over the lines which are left. If history is off, delete + * lines from the top. + * + * XXX Should apply history limit? */ - gd->hsize += needed; + available = s->cy; + if (gd->flags & GRID_HISTORY) + gd->hsize += needed; + else if (available > 0) { + if (available > needed) + available = needed; + grid_view_delete_lines(gd, 0, available); + } s->cy -= needed; } @@ -191,14 +201,18 @@ screen_resize_y(struct screen *s, u_int sy) if (sy > oldy) { needed = sy - oldy; - /* Try to pull as much as possible out of the history. */ + /* + * Try to pull as much as possible out of the history, if is + * is enabled. + */ available = gd->hsize; - if (available > 0) { + if (gd->flags & GRID_HISTORY && available > 0) { if (available > needed) available = needed; gd->hsize -= available; s->cy += available; - } + } else + available = 0; needed -= available; /* Then fill the rest in with blanks. */ diff --git a/tmux.h b/tmux.h index 28778e9f..481b0ca7 100644 --- a/tmux.h +++ b/tmux.h @@ -443,6 +443,9 @@ struct grid_utf8 { /* Entire grid of cells. */ struct grid { + int flags; +#define GRID_HISTORY 0x1 /* scroll lines into history */ + u_int sx; u_int sy; @@ -614,6 +617,11 @@ struct window_pane { struct screen *screen; struct screen base; + /* Saved in alternative screen mode. */ + u_int saved_cx; + u_int saved_cy; + struct grid *saved_grid; + const struct window_mode *mode; void *modedata; @@ -1328,6 +1336,8 @@ void grid_clear_lines(struct grid *, u_int, u_int); void grid_move_lines(struct grid *, u_int, u_int, u_int); void grid_move_cells(struct grid *, u_int, u_int, u_int, u_int); char *grid_string_cells(struct grid *, u_int, u_int, u_int); +void grid_duplicate_lines( + struct grid *, u_int, struct grid *, u_int, u_int); /* grid-view.c */ const struct grid_cell *grid_view_peek_cell(struct grid *, u_int, u_int); diff --git a/window.c b/window.c index 95addc41..753f796a 100644 --- a/window.c +++ b/window.c @@ -407,6 +407,8 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit) wp->sx = sx; wp->sy = sy; + wp->saved_grid = NULL; + screen_init(&wp->base, sx, sy, hlimit); wp->screen = &wp->base; @@ -425,6 +427,8 @@ window_pane_destroy(struct window_pane *wp) window_pane_reset_mode(wp); screen_free(&wp->base); + if (wp->saved_grid != NULL) + grid_destroy(wp->saved_grid); buffer_destroy(wp->in); buffer_destroy(wp->out); From 023d8d38ec7d59bbf635253f10e82e0b62ba59ca Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 13 Jul 2009 17:47:46 +0000 Subject: [PATCH 0110/1180] Tidy up and improve target (-t) argument parsing: - move the code back into cmd.c and merge with the existing functions where possible; - accept "-tttyp0" as well as "-t/dev/ttyp0" for clients; - when looking up session names, try an exact match first, and if that fails look for it as an fnmatch pattern and then as the start of a name - if more that one session matches an error is given; so if there is one session called "mysession", -tmysession, -tmysess, -tmysess* are equivalent but if there is also "mysession2", the last two are errors; - similarly for windows, if the argument is not a valid index or exact window name match, try it against the window names as an fnmatch pattern and a prefix. --- Makefile | 2 +- arg.c | 194 --------------------- cmd-link-window.c | 13 +- cmd-move-window.c | 13 +- cmd-new-window.c | 12 +- cmd.c | 420 ++++++++++++++++++++++++++++++++++++++++------ tmux.1 | 41 +++-- tmux.h | 9 +- 8 files changed, 406 insertions(+), 298 deletions(-) delete mode 100644 arg.c diff --git a/Makefile b/Makefile index 774e8341..4630160c 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # $OpenBSD$ PROG= tmux -SRCS= arg.c attributes.c buffer-poll.c buffer.c cfg.c client-fn.c \ +SRCS= attributes.c buffer-poll.c buffer.c cfg.c client-fn.c \ client-msg.c client.c clock.c cmd-attach-session.c cmd-bind-key.c \ cmd-break-pane.c cmd-choose-session.c cmd-choose-window.c \ cmd-clear-history.c cmd-clock-mode.c cmd-command-prompt.c \ diff --git a/arg.c b/arg.c deleted file mode 100644 index 6fe36a15..00000000 --- a/arg.c +++ /dev/null @@ -1,194 +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 "tmux.h" - -struct client *arg_lookup_client(const char *); -struct session *arg_lookup_session(const char *); - -struct client * -arg_lookup_client(const char *name) -{ - struct client *c; - u_int i; - - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - c = ARRAY_ITEM(&clients, i); - if (c != NULL && strcmp(name, c->tty.path) == 0) - return (c); - } - - return (NULL); -} - -struct session * -arg_lookup_session(const char *name) -{ - struct session *s, *newest = NULL; - struct timeval *tv; - u_int i; - - tv = NULL; - for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { - s = ARRAY_ITEM(&sessions, i); - if (s == NULL || fnmatch(name, s->name, 0) != 0) - continue; - - if (tv == NULL || timercmp(&s->tv, tv, >)) { - newest = s; - tv = &s->tv; - } - } - - return (newest); -} - -struct client * -arg_parse_client(const char *arg) -{ - struct client *c; - char *arg2; - size_t n; - - if (arg != NULL && (arg[0] != ':' || arg[1] != '\0')) { - arg2 = xstrdup(arg); - - /* Trim a trailing : if any from the argument. */ - n = strlen(arg2); - if (n && arg2[n - 1] == ':') - arg2[n - 1] = '\0'; - - /* Try and look up the client name. */ - c = arg_lookup_client(arg2); - xfree(arg2); - return (c); - } - - return (NULL); -} - -struct session * -arg_parse_session(const char *arg) -{ - struct session *s; - struct client *c; - char *arg2; - size_t n; - - if (arg != NULL && (arg[0] != ':' || arg[1] != '\0')) { - arg2 = xstrdup(arg); - - /* Trim a trailing : if any from the argument. */ - n = strlen(arg2); - if (n && arg2[n - 1] == ':') - arg2[n - 1] = '\0'; - - /* See if the argument matches a session. */ - if ((s = arg_lookup_session(arg2)) != NULL) { - xfree(arg2); - return (s); - } - - /* If not try a client. */ - if ((c = arg_lookup_client(arg2)) != NULL) { - xfree(arg2); - return (c->session); - } - - xfree(arg2); - } - - return (NULL); -} - -int -arg_parse_window(const char *arg, struct session **s, int *idx) -{ - char *arg2, *ptr; - const char *errstr; - - *idx = -1; - - /* Handle no argument or a single :. */ - if (arg == NULL || (arg[0] == ':' && arg[1] == '\0')) { - *s = arg_parse_session(NULL); - return (0); - } - - /* Find the separator if any. */ - arg2 = xstrdup(arg); - ptr = strrchr(arg2, ':'); - - /* - * If it is first, this means no session name, so use current session - * and try to convert the rest as index. - */ - if (ptr == arg2) { - *idx = strtonum(ptr + 1, 0, INT_MAX, &errstr); - if (errstr != NULL) { - xfree(arg2); - return (1); - } - - xfree(arg2); - *s = arg_parse_session(NULL); - return (0); - } - - /* If missing, try as an index, else look up immediately. */ - if (ptr == NULL) { - *idx = strtonum(arg2, 0, INT_MAX, &errstr); - if (errstr == NULL) { - /* This is good as an index; use current session. */ - xfree(arg2); - *s = arg_parse_session(NULL); - return (0); - } - - *idx = -1; - goto lookup; - } - - /* If last, strip it and look up as a session. */ - if (ptr[1] == '\0') { - *ptr = '\0'; - goto lookup; - } - - /* Present but not first and not last. Break and convert both. */ - *ptr = '\0'; - *idx = strtonum(ptr + 1, 0, INT_MAX, &errstr); - if (errstr != NULL) { - xfree(arg2); - return (1); - } - -lookup: - /* Look up as session. */ - *s = arg_parse_session(arg2); - xfree(arg2); - if (*s == NULL) - return (1); - return (0); -} diff --git a/cmd-link-window.c b/cmd-link-window.c index 143e3cf0..4e1ada81 100644 --- a/cmd-link-window.c +++ b/cmd-link-window.c @@ -52,19 +52,8 @@ cmd_link_window_exec(struct cmd *self, struct cmd_ctx *ctx) if ((wl_src = cmd_find_window(ctx, data->src, NULL)) == NULL) return (-1); - - if (arg_parse_window(data->dst, &dst, &idx) != 0) { - ctx->error(ctx, "bad window: %s", data->dst); + if ((idx = cmd_find_index(ctx, data->dst, &dst)) == -2) return (-1); - } - if (dst == NULL) - dst = ctx->cursession; - if (dst == NULL) - dst = cmd_current_session(ctx); - if (dst == NULL) { - ctx->error(ctx, "session not found: %s", data->dst); - return (-1); - } wl_dst = NULL; if (idx != -1) diff --git a/cmd-move-window.c b/cmd-move-window.c index 9f356a64..c9117c4b 100644 --- a/cmd-move-window.c +++ b/cmd-move-window.c @@ -54,19 +54,8 @@ cmd_move_window_exec(struct cmd *self, struct cmd_ctx *ctx) if ((wl_src = cmd_find_window(ctx, data->src, &src)) == NULL) return (-1); - - if (arg_parse_window(data->dst, &dst, &idx) != 0) { - ctx->error(ctx, "bad window: %s", data->dst); + if ((idx = cmd_find_index(ctx, data->dst, &dst)) == -2) return (-1); - } - if (dst == NULL) - dst = ctx->cursession; - if (dst == NULL) - dst = cmd_current_session(ctx); - if (dst == NULL) { - ctx->error(ctx, "session not found: %s", data->dst); - return (-1); - } wl_dst = NULL; if (idx != -1) diff --git a/cmd-new-window.c b/cmd-new-window.c index 30b84ac3..ee8cd8b7 100644 --- a/cmd-new-window.c +++ b/cmd-new-window.c @@ -126,18 +126,8 @@ cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx) if (data == NULL) return (0); - if (arg_parse_window(data->target, &s, &idx) != 0) { - ctx->error(ctx, "bad window: %s", data->target); + if ((idx = cmd_find_index(ctx, data->target, &s)) == -2) return (-1); - } - if (s == NULL) - s = ctx->cursession; - if (s == NULL) - s = cmd_current_session(ctx); - if (s == NULL) { - ctx->error(ctx, "session not found: %s", data->target); - return (-1); - } wl = NULL; if (idx != -1) diff --git a/cmd.c b/cmd.c index 7e98f8cc..a2264081 100644 --- a/cmd.c +++ b/cmd.c @@ -19,6 +19,8 @@ #include #include +#include +#include #include #include #include @@ -100,6 +102,11 @@ const struct cmd_entry *cmd_table[] = { NULL }; +struct session *cmd_newest_session(void); +struct client *cmd_lookup_client(const char *); +struct session *cmd_lookup_session(const char *, int *); +struct winlink *cmd_lookup_window(struct session *, const char *, int *); + struct cmd * cmd_parse(int argc, char **argv, char **cause) { @@ -294,106 +301,421 @@ cmd_recv_string(struct buffer *b) return (s); } +/* + * Figure out the current session. Use: 1) the current session, if the command + * context has one; 2) the session specified in the TMUX variable from the + * environment (as passed from the client); 3) the newest session. + */ struct session * cmd_current_session(struct cmd_ctx *ctx) { struct msg_command_data *data = ctx->msgdata; - struct timeval *tv; - struct session *s, *newest = NULL; - u_int i; + struct session *s; if (ctx->cursession != NULL) return (ctx->cursession); if (data != NULL && data->pid != -1) { - if (data->pid != getpid()) { - ctx->error(ctx, "wrong server: %ld", (long) data->pid); + if (data->pid != getpid()) return (NULL); - } - if (data->idx > ARRAY_LENGTH(&sessions)) { - ctx->error(ctx, "index out of range: %d", data->idx); + if (data->idx > ARRAY_LENGTH(&sessions)) return (NULL); - } - if ((s = ARRAY_ITEM(&sessions, data->idx)) == NULL) { - ctx->error(ctx, "session doesn't exist: %u", data->idx); + if ((s = ARRAY_ITEM(&sessions, data->idx)) == NULL) return (NULL); - } return (s); } - tv = NULL; + return (cmd_newest_session()); +} + +/* Find the newest session. */ +struct session * +cmd_newest_session(void) +{ + struct session *s, *snewest; + struct timeval *tv = NULL; + u_int i; + + snewest = NULL; for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { - s = ARRAY_ITEM(&sessions, i); - if (s != NULL && (tv == NULL || timercmp(&s->tv, tv, >))) { - newest = ARRAY_ITEM(&sessions, i); + if ((s = ARRAY_ITEM(&sessions, i)) == NULL) + continue; + + if (tv == NULL || timercmp(&s->tv, tv, >)) { + snewest = s; tv = &s->tv; } } - return (newest); + + return (snewest); } +/* Find the target client or report an error and return NULL. */ struct client * cmd_find_client(struct cmd_ctx *ctx, const char *arg) { struct client *c; + char *tmparg; + size_t arglen; + /* A NULL argument means the current client. */ if (arg == NULL) - c = ctx->curclient; - else { - if ((c = arg_parse_client(arg)) == NULL) { - if (arg != NULL) - ctx->error(ctx, "client not found: %s", arg); - else - ctx->error(ctx, "no client found"); - } - } + return (ctx->curclient); + tmparg = xstrdup(arg); + + /* Trim a single trailing colon if any. */ + arglen = strlen(tmparg); + if (arglen != 0 && tmparg[arglen - 1] == ':') + tmparg[arglen - 1] = '\0'; + + /* Find the client, if any. */ + c = cmd_lookup_client(tmparg); + + /* If no client found, report an error. */ + if (c == NULL) + ctx->error(ctx, "client not found: %s", tmparg); + + xfree(tmparg); return (c); } +/* + * Lookup a client by device path. Either of a full match and a match without a + * leading _PATH_DEV ("/dev/") is accepted. + */ +struct client * +cmd_lookup_client(const char *name) +{ + struct client *c; + const char *path; + u_int i; + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + if ((c = ARRAY_ITEM(&clients, i)) == NULL) + continue; + path = c->tty.path; + + /* Check for exact matches. */ + if (strcmp(name, path) == 0) + return (c); + + /* Check without leading /dev if present. */ + if (strncmp(path, _PATH_DEV, (sizeof _PATH_DEV) - 1) != 0) + continue; + if (strcmp(name, path + (sizeof _PATH_DEV) - 1) == 0) + return (c); + } + + return (NULL); +} + +/* Lookup a session by name. If no session is found, NULL is returned. */ +struct session * +cmd_lookup_session(const char *name, int *ambiguous) +{ + struct session *s, *sfound; + u_int i; + + *ambiguous = 0; + + /* + * Look for matches. Session names must be unique so an exact match + * can't be ambigious and can just be returned. + */ + sfound = NULL; + for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { + if ((s = ARRAY_ITEM(&sessions, i)) == NULL) + continue; + + /* Check for an exact match and return it if found. */ + if (strcmp(name, s->name) == 0) + return (s); + + /* Then check for pattern matches. */ + if (strncmp(name, s->name, strlen(name)) == 0 || + fnmatch(name, s->name, 0) == 0) { + if (sfound != NULL) { + *ambiguous = 1; + return (NULL); + } + sfound = s; + } + } + + return (sfound); +} + +/* + * Lookup a window or return -1 if not found or ambigious. First try as an index + * and if invalid, use fnmatch or leading prefix. + */ +struct winlink * +cmd_lookup_window(struct session *s, const char *name, int *ambiguous) +{ + struct winlink *wl, *wlfound; + struct window *w; + const char *errstr; + u_int idx; + + *ambiguous = 0; + + /* First see if this is a valid window index in this session. */ + idx = strtonum(name, 0, INT_MAX, &errstr); + if (errstr == NULL) { + if ((wl = winlink_find_by_index(&s->windows, idx)) != NULL) + return (wl); + } + + /* Look for exact matches, error if more than one. */ + wlfound = NULL; + RB_FOREACH(wl, winlinks, &s->windows) { + w = wl->window; + if (strcmp(name, w->name) == 0) { + if (wlfound != NULL) { + *ambiguous = 1; + return (NULL); + } + wlfound = wl; + } + } + if (wlfound != NULL) + return (wlfound); + + /* Now look for pattern matches, again error if multiple. */ + wlfound = NULL; + RB_FOREACH(wl, winlinks, &s->windows) { + w = wl->window; + if (strncmp(name, w->name, strlen(name)) == 0 || + fnmatch(name, w->name, 0) == 0) { + if (wlfound != NULL) { + *ambiguous = 1; + return (NULL); + } + wlfound = wl; + } + } + if (wlfound != NULL) + return (wlfound); + + return (NULL); +} + +/* Find the target session or report an error and return NULL. */ struct session * cmd_find_session(struct cmd_ctx *ctx, const char *arg) { struct session *s; + struct client *c; + char *tmparg; + size_t arglen; + int ambiguous; + /* A NULL argument means the current session. */ if (arg == NULL) - s = cmd_current_session(ctx); - else { - if ((s = arg_parse_session(arg)) == NULL) { - if (arg != NULL) - ctx->error(ctx, "session not found: %s", arg); - else - ctx->error(ctx, "no session found"); - } + return (cmd_current_session(ctx)); + tmparg = xstrdup(arg); + + /* Trim a single trailing colon if any. */ + arglen = strlen(tmparg); + if (arglen != 0 && tmparg[arglen - 1] == ':') + tmparg[arglen - 1] = '\0'; + + /* Find the session, if any. */ + s = cmd_lookup_session(tmparg, &ambiguous); + + /* If it doesn't, try to match it as a client. */ + if (s == NULL && (c = cmd_lookup_client(tmparg)) != NULL) + s = c->session; + + /* If no session found, report an error. */ + if (s == NULL) { + if (ambiguous) + ctx->error(ctx, "more than one session: %s", tmparg); + else + ctx->error(ctx, "session not found: %s", tmparg); } + + xfree(tmparg); return (s); } +/* Find the target session and window or report an error and return NULL. */ struct winlink * cmd_find_window(struct cmd_ctx *ctx, const char *arg, struct session **sp) { struct session *s; struct winlink *wl; - int idx; + const char *winptr; + char *sessptr = NULL; + int ambiguous = 0; - wl = NULL; - if (arg_parse_window(arg, &s, &idx) != 0) { - ctx->error(ctx, "bad window: %s", arg); + /* + * Find the current session. There must always be a current session, if + * it can't be found, report an error. + */ + if ((s = cmd_current_session(ctx)) == NULL) { + ctx->error(ctx, "can't establish current session"); return (NULL); } - if (s == NULL) - s = ctx->cursession; - if (s == NULL) - s = cmd_current_session(ctx); - if (s == NULL) - return (NULL); + + /* A NULL argument means the current session and window. */ + if (arg == NULL) { + if (sp != NULL) + *sp = s; + return (s->curw); + } + + /* Time to look at the argument. If it is empty, that is an error. */ + if (*arg == '\0') + goto not_found; + + /* Find the separating colon. If none, assume the current session. */ + winptr = strchr(arg, ':'); + if (winptr == NULL) + winptr = xstrdup(arg); + else { + winptr++; /* skip : */ + sessptr = xstrdup(arg); + *strchr(sessptr, ':') = '\0'; + } + + log_debug("%s: winptr=%s, sessptr=%s", __func__, winptr, sessptr); + + /* Try to lookup the session if present. */ + if (sessptr != NULL && *sessptr != '\0') { + if ((s = cmd_lookup_session(sessptr, &ambiguous)) == NULL) + goto no_session; + } if (sp != NULL) *sp = s; - if (idx == -1) + /* + * Then work out the window. An empty string is the current window, + * otherwise try to look it up in the session. + */ + if (winptr == NULL || *winptr == '\0') wl = s->curw; - else - wl = winlink_find_by_index(&s->windows, idx); - if (wl == NULL) - ctx->error(ctx, "window not found: %s:%d", s->name, idx); + else if ((wl = cmd_lookup_window(s, winptr, &ambiguous)) == NULL) + goto not_found; + + if (sessptr != NULL) + xfree(sessptr); return (wl); + +no_session: + if (ambiguous) + ctx->error(ctx, "multiple sessions: %s", sessptr); + else + ctx->error(ctx, "session not found: %s", sessptr); + if (sessptr != NULL) + xfree(sessptr); + return (NULL); + +not_found: + if (ambiguous) + ctx->error(ctx, "multiple windows: %s", arg); + else + ctx->error(ctx, "window not found: %s", arg); + if (sessptr != NULL) + xfree(sessptr); + return (NULL); +} + +/* + * Find the target session and window index, whether or not it exists in the + * session. Return -2 on error or -1 if no window index is specified. This is + * used when parsing an argument for a window target that may not be exist (for + * example it is going to be created). + */ +int +cmd_find_index(struct cmd_ctx *ctx, const char *arg, struct session **sp) +{ + struct session *s; + struct winlink *wl; + const char *winptr, *errstr; + char *sessptr = NULL; + int idx, ambiguous = 0; + + /* + * Find the current session. There must always be a current session, if + * it can't be found, report an error. + */ + if ((s = cmd_current_session(ctx)) == NULL) { + ctx->error(ctx, "can't establish current session"); + return (NULL); + } + + /* A NULL argument means the current session and "no window" (-1). */ + if (arg == NULL) { + if (sp != NULL) + *sp = s; + return (-1); + } + + /* Time to look at the argument. If it is empty, that is an error. */ + if (*arg == '\0') + goto not_found; + + /* Find the separating colon. If none, assume the current session. */ + winptr = strchr(arg, ':'); + if (winptr == NULL) + winptr = xstrdup(arg); + else { + winptr++; /* skip : */ + sessptr = xstrdup(arg); + *strchr(sessptr, ':') = '\0'; + } + + log_debug("%s: winptr=%s, sessptr=%s", __func__, winptr, sessptr); + + /* Try to lookup the session if present. */ + if (sessptr != NULL && *sessptr != '\0') { + if ((s = cmd_lookup_session(sessptr, &ambiguous)) == NULL) + goto no_session; + } + if (sp != NULL) + *sp = s; + + /* + * Then work out the window. No : means "no window" (-1), an empty + * string is the current window, otherwise try to look it up in the + * session. + */ + if (winptr == NULL) + idx = -1; + else if (*winptr == '\0') + idx = s->curw->idx; + else if ((wl = cmd_lookup_window(s, winptr, &ambiguous)) == NULL) { + if (ambiguous) + goto not_found; + /* Don't care it doesn't exist if this is a valid index. */ + idx = strtonum(winptr, 0, INT_MAX, &errstr); + if (errstr != NULL) { + ctx->error(ctx, "index %s: %s", errstr, winptr); + idx = -2; + } + } else + idx = wl->idx; + + if (sessptr != NULL) + xfree(sessptr); + return (idx); + +no_session: + if (ambiguous) + ctx->error(ctx, "multiple sessions: %s", sessptr); + else + ctx->error(ctx, "session not found: %s", sessptr); + if (sessptr != NULL) + xfree(sessptr); + return (-2); + +not_found: + if (ambiguous) + ctx->error(ctx, "multiple windows: %s", arg); + else + ctx->error(ctx, "window not found: %s", arg); + if (sessptr != NULL) + xfree(sessptr); + return (-2); } diff --git a/tmux.1 b/tmux.1 index e3965c7a..552907b0 100644 --- a/tmux.1 +++ b/tmux.1 @@ -500,8 +500,14 @@ These specify the client, session or window which a command should affect. .Ar target-client is the name of the .Xr pty 4 -file to which the client is connected, for example +file to which the client is connected, for example either of +.Pa /dev/ttyp1 +or +.Pa ttyp1 +for the client attached to .Pa /dev/ttyp1 . +If no client is specified, the current client is chosen, if possible, or an +error is reported. Clients may be listed with the .Ic list-clients command. @@ -509,23 +515,32 @@ command. .Ar target-session is either the name of a session (as listed by the .Ic list-sessions -command) or the name of a client, +command) or the name of a client with the same syntax as .Ar target-client , in which case the session attached to the client is used. -An +When looking for the session name, +.Nm +initially searches for an exact match; if none is found, the session names +are checked for any for which +.Ar target-session +is a prefix or for which it matches as an .Xr fnmatch 3 -pattern may be used to match the session name. -If a session is omitted when required, -.Nm tmux -attempts to use the current session; if no current session is available, the -most recently created is chosen. -If no client is specified, the current client is chosen, if possible, or an -error is reported. +pattern. +If a single match is found, it is used as the target session; multiple matches +produce an error +If a session is omitted, the current session is used if available; if no +current session is available, the most recently created is chosen. .Pp .Ar target-window specifies a window in the form -.Em session Ns \&: Ns Em index , -for example mysession:1. +.Em session Ns \&: Ns Em window , +where +.Em window +is a window index, for example mysession:1, or a window name, +.Xr fnmatch 3 +pattern, or prefix, such as mysession:mywin[0-3]. +If the latter, the window is looked up in a similar fashion to session name +searches described above. The session is in the same form as for .Ar target-session . .Em session , @@ -536,7 +551,7 @@ If is omitted, the same rules as for .Ar target-session are followed; if -.Em index +.Em window is not present, the current window for the given session is used. When the argument does not contain a colon, .Nm diff --git a/tmux.h b/tmux.h index 481b0ca7..585daeb9 100644 --- a/tmux.h +++ b/tmux.h @@ -1076,11 +1076,6 @@ int paste_replace(struct paste_stack *, u_int, char *); /* clock.c */ void clock_draw(struct screen_write_ctx *, u_int, int); -/* arg.c */ -struct client *arg_parse_client(const char *); -struct session *arg_parse_session(const char *); -int arg_parse_window(const char *, struct session **, int *); - /* cmd.c */ struct cmd *cmd_parse(int, char **, char **); int cmd_exec(struct cmd *, struct cmd_ctx *); @@ -1094,7 +1089,9 @@ struct session *cmd_current_session(struct cmd_ctx *); struct client *cmd_find_client(struct cmd_ctx *, const char *); struct session *cmd_find_session(struct cmd_ctx *, const char *); struct winlink *cmd_find_window( - struct cmd_ctx *, const char *, struct session **); + struct cmd_ctx *, const char *, struct session **); +int cmd_find_index( + struct cmd_ctx *, const char *, struct session **); 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 cf411053c7773bbf9f7bdb8e6004ae10d006f05a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 13 Jul 2009 18:44:17 +0000 Subject: [PATCH 0111/1180] copy-mode and scroll-mode have a -u flag missing from usage, add it. --- cmd-copy-mode.c | 2 +- cmd-scroll-mode.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd-copy-mode.c b/cmd-copy-mode.c index 681f8ba7..0600d116 100644 --- a/cmd-copy-mode.c +++ b/cmd-copy-mode.c @@ -28,7 +28,7 @@ int cmd_copy_mode_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_copy_mode_entry = { "copy-mode", NULL, - CMD_TARGET_WINDOW_USAGE, + "[-u] " CMD_TARGET_WINDOW_USAGE, CMD_UFLAG, cmd_target_init, cmd_target_parse, diff --git a/cmd-scroll-mode.c b/cmd-scroll-mode.c index 0d1f2291..f376d703 100644 --- a/cmd-scroll-mode.c +++ b/cmd-scroll-mode.c @@ -29,7 +29,7 @@ int cmd_scroll_mode_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_scroll_mode_entry = { "scroll-mode", NULL, - CMD_TARGET_WINDOW_USAGE, + "[-u] " CMD_TARGET_WINDOW_USAGE, CMD_UFLAG, cmd_scroll_mode_init, cmd_target_parse, From cba885a67c654a5546cb5d077f15aea8c4e7ed3a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 13 Jul 2009 18:49:36 +0000 Subject: [PATCH 0112/1180] Expand leading tildes in arguments, from Tiage Cunha. --- cmd-string.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/cmd-string.c b/cmd-string.c index c6ef61b0..9ba399b2 100644 --- a/cmd-string.c +++ b/cmd-string.c @@ -19,9 +19,11 @@ #include #include +#include #include #include #include +#include #include "tmux.h" @@ -33,6 +35,7 @@ int cmd_string_getc(const char *, size_t *); void cmd_string_ungetc(const char *, size_t *); char *cmd_string_string(const char *, size_t *, char, int); char *cmd_string_variable(const char *, size_t *); +char *cmd_string_expand_tilde(const char *, size_t *); int cmd_string_getc(const char *s, size_t *p) @@ -154,6 +157,17 @@ cmd_string_parse(const char *s, struct cmd_list **cmdlist, char **cause) rval = 0; goto out; + case '~': + if (have_arg == 0) { + if ((t = cmd_string_expand_tilde(s, &p)) == NULL) + goto error; + buf = xrealloc(buf, 1, len + strlen(t) + 1); + strlcpy(buf + len, t, strlen(t) + 1); + len += strlen(t); + xfree(t); + break; + } + /* FALLTHROUGH */ default: if (len >= SIZE_MAX - 2) goto error; @@ -309,3 +323,31 @@ error: xfree(buf); return (NULL); } + +char * +cmd_string_expand_tilde(const char *s, size_t *p) +{ + struct passwd *pw; + char *home, *path, *username; + + home = NULL; + if (cmd_string_getc(s, p) == '/') { + if ((home = getenv("HOME")) == NULL) { + if ((pw = getpwuid(getuid())) != NULL) + home = pw->pw_dir; + } + } else { + cmd_string_ungetc(s, p); + if ((username = cmd_string_string(s, p, '/', 0)) == NULL) + return (NULL); + if ((pw = getpwnam(username)) != NULL) + home = pw->pw_dir; + if (username != NULL) + xfree(username); + } + if (home == NULL) + return (NULL); + + xasprintf(&path, "%s/", home); + return (path); +} From 5d91555c7c8d88577892e0a2e2bde2cde60a2882 Mon Sep 17 00:00:00 2001 From: Jason McIntyre Date: Mon, 13 Jul 2009 20:14:23 +0000 Subject: [PATCH 0113/1180] zap trailing whitespace; --- tmux.1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tmux.1 b/tmux.1 index 552907b0..172e0e4d 100644 --- a/tmux.1 +++ b/tmux.1 @@ -504,7 +504,7 @@ file to which the client is connected, for example either of .Pa /dev/ttyp1 or .Pa ttyp1 -for the client attached to +for the client attached to .Pa /dev/ttyp1 . If no client is specified, the current client is chosen, if possible, or an error is reported. @@ -518,7 +518,7 @@ is either the name of a session (as listed by the command) or the name of a client with the same syntax as .Ar target-client , in which case the session attached to the client is used. -When looking for the session name, +When looking for the session name, .Nm initially searches for an exact match; if none is found, the session names are checked for any for which From 5f108d9df6bada119def52518152a487f8695702 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 13 Jul 2009 23:11:35 +0000 Subject: [PATCH 0114/1180] Having fixed flags for single-character getopt options is a bit hard to maintain and is only going to get worse as more are used. So instead, add a new uint64_t member to cmd_entry which is a bitmask of upper and lowercase options accepted by the command. This means new single character options can be used without the need to add it explicitly to the list. --- cmd-attach-session.c | 4 +- cmd-bind-key.c | 2 +- cmd-break-pane.c | 4 +- cmd-choose-session.c | 2 +- cmd-choose-window.c | 2 +- cmd-clear-history.c | 2 +- cmd-clock-mode.c | 2 +- cmd-command-prompt.c | 2 +- cmd-confirm-before.c | 2 +- cmd-copy-buffer.c | 2 +- cmd-copy-mode.c | 4 +- cmd-delete-buffer.c | 2 +- cmd-detach-client.c | 2 +- cmd-down-pane.c | 2 +- cmd-find-window.c | 2 +- cmd-generic.c | 198 ++++++++++++++++---------------------- cmd-has-session.c | 2 +- cmd-if-shell.c | 2 +- cmd-kill-pane.c | 2 +- cmd-kill-server.c | 2 +- cmd-kill-session.c | 2 +- cmd-kill-window.c | 2 +- cmd-last-window.c | 2 +- cmd-link-window.c | 8 +- cmd-list-buffers.c | 2 +- cmd-list-clients.c | 2 +- cmd-list-commands.c | 2 +- cmd-list-keys.c | 2 +- cmd-list-sessions.c | 2 +- cmd-list-windows.c | 2 +- cmd-load-buffer.c | 2 +- cmd-lock-server.c | 2 +- cmd-move-window.c | 8 +- cmd-new-session.c | 2 +- cmd-new-window.c | 2 +- cmd-next-layout.c | 2 +- cmd-next-window.c | 6 +- cmd-paste-buffer.c | 6 +- cmd-previous-layout.c | 2 +- cmd-previous-window.c | 6 +- cmd-refresh-client.c | 2 +- cmd-rename-session.c | 2 +- cmd-rename-window.c | 2 +- cmd-resize-pane.c | 8 +- cmd-respawn-window.c | 4 +- cmd-rotate-window.c | 6 +- cmd-save-buffer.c | 4 +- cmd-scroll-mode.c | 6 +- cmd-select-layout.c | 2 +- cmd-select-pane.c | 2 +- cmd-select-prompt.c | 2 +- cmd-select-window.c | 2 +- cmd-send-keys.c | 2 +- cmd-send-prefix.c | 2 +- cmd-server-info.c | 2 +- cmd-set-buffer.c | 2 +- cmd-set-option.c | 8 +- cmd-set-password.c | 2 +- cmd-set-window-option.c | 8 +- cmd-show-buffer.c | 2 +- cmd-show-options.c | 4 +- cmd-show-window-options.c | 4 +- cmd-source-file.c | 2 +- cmd-split-window.c | 2 +- cmd-start-server.c | 2 +- cmd-suspend-client.c | 2 +- cmd-swap-pane.c | 2 +- cmd-swap-window.c | 4 +- cmd-switch-client.c | 2 +- cmd-unbind-key.c | 2 +- cmd-unlink-window.c | 2 +- cmd-up-pane.c | 2 +- tmux.h | 24 ++--- 73 files changed, 196 insertions(+), 234 deletions(-) diff --git a/cmd-attach-session.c b/cmd-attach-session.c index 1f0bb517..196d5d13 100644 --- a/cmd-attach-session.c +++ b/cmd-attach-session.c @@ -29,7 +29,7 @@ int cmd_attach_session_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_attach_session_entry = { "attach-session", "attach", "[-d] " CMD_TARGET_SESSION_USAGE, - CMD_DFLAG|CMD_CANTNEST|CMD_STARTSERVER, + CMD_CANTNEST|CMD_STARTSERVER, CMD_CHFLAG('d'), cmd_target_init, cmd_target_parse, cmd_attach_session_exec, @@ -67,7 +67,7 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx) return (-1); } - if (data->flags & CMD_DFLAG) + if (data->chflags & CMD_CHFLAG('d')) server_write_session(s, MSG_DETACH, NULL, 0); ctx->cmdclient->session = s; diff --git a/cmd-bind-key.c b/cmd-bind-key.c index f0988899..14a93831 100644 --- a/cmd-bind-key.c +++ b/cmd-bind-key.c @@ -40,7 +40,7 @@ struct cmd_bind_key_data { const struct cmd_entry cmd_bind_key_entry = { "bind-key", "bind", "[-r] key command [arguments]", - 0, + 0, 0, NULL, cmd_bind_key_parse, cmd_bind_key_exec, diff --git a/cmd-break-pane.c b/cmd-break-pane.c index f2b51edf..74e052d5 100644 --- a/cmd-break-pane.c +++ b/cmd-break-pane.c @@ -31,7 +31,7 @@ int cmd_break_pane_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_break_pane_entry = { "break-pane", "breakp", CMD_PANE_WINDOW_USAGE " [-d]", - CMD_DFLAG, + 0, CMD_CHFLAG('d'), cmd_pane_init, cmd_pane_parse, cmd_break_pane_exec, @@ -82,7 +82,7 @@ cmd_break_pane_exec(struct cmd *self, struct cmd_ctx *ctx) w->name = default_window_name(w); wl = session_attach(s, w, -1, &cause); /* can't fail */ - if (!(data->flags & CMD_DFLAG)) + if (!(data->chflags & CMD_CHFLAG('d'))) session_select(s, wl->idx); layout_refresh(w, 0); diff --git a/cmd-choose-session.c b/cmd-choose-session.c index d1f6ba23..22f7d04b 100644 --- a/cmd-choose-session.c +++ b/cmd-choose-session.c @@ -31,7 +31,7 @@ void cmd_choose_session_callback(void *, int); const struct cmd_entry cmd_choose_session_entry = { "choose-session", NULL, CMD_TARGET_WINDOW_USAGE, - 0, + 0, 0, cmd_target_init, cmd_target_parse, cmd_choose_session_exec, diff --git a/cmd-choose-window.c b/cmd-choose-window.c index 64eab882..baa55eb2 100644 --- a/cmd-choose-window.c +++ b/cmd-choose-window.c @@ -31,7 +31,7 @@ void cmd_choose_window_callback(void *, int); const struct cmd_entry cmd_choose_window_entry = { "choose-window", NULL, CMD_TARGET_WINDOW_USAGE, - 0, + 0, 0, cmd_target_init, cmd_target_parse, cmd_choose_window_exec, diff --git a/cmd-clear-history.c b/cmd-clear-history.c index 4399c6c2..de24ac57 100644 --- a/cmd-clear-history.c +++ b/cmd-clear-history.c @@ -29,7 +29,7 @@ int cmd_clear_history_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_clear_history_entry = { "clear-history", "clearhist", CMD_PANE_WINDOW_USAGE, - 0, + 0, 0, cmd_pane_init, cmd_pane_parse, cmd_clear_history_exec, diff --git a/cmd-clock-mode.c b/cmd-clock-mode.c index 7f3f0d07..4399b7ba 100644 --- a/cmd-clock-mode.c +++ b/cmd-clock-mode.c @@ -29,7 +29,7 @@ int cmd_clock_mode_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_clock_mode_entry = { "clock-mode", NULL, CMD_TARGET_WINDOW_USAGE, - 0, + 0, 0, cmd_target_init, cmd_target_parse, cmd_clock_mode_exec, diff --git a/cmd-command-prompt.c b/cmd-command-prompt.c index cf914648..841dfd78 100644 --- a/cmd-command-prompt.c +++ b/cmd-command-prompt.c @@ -35,7 +35,7 @@ int cmd_command_prompt_callback(void *, const char *); const struct cmd_entry cmd_command_prompt_entry = { "command-prompt", NULL, CMD_TARGET_CLIENT_USAGE " [template]", - CMD_ARG01, + CMD_ARG01, 0, cmd_command_prompt_init, cmd_target_parse, cmd_command_prompt_exec, diff --git a/cmd-confirm-before.c b/cmd-confirm-before.c index f544d810..0819e3e9 100644 --- a/cmd-confirm-before.c +++ b/cmd-confirm-before.c @@ -38,7 +38,7 @@ struct cmd_confirm_before_data { const struct cmd_entry cmd_confirm_before_entry = { "confirm-before", "confirm", CMD_TARGET_CLIENT_USAGE " command", - CMD_ARG1, + CMD_ARG1, 0, cmd_confirm_before_init, cmd_target_parse, cmd_confirm_before_exec, diff --git a/cmd-copy-buffer.c b/cmd-copy-buffer.c index ab6fe14b..544cf1c6 100644 --- a/cmd-copy-buffer.c +++ b/cmd-copy-buffer.c @@ -42,7 +42,7 @@ struct cmd_copy_buffer_data { const struct cmd_entry cmd_copy_buffer_entry = { "copy-buffer", "copyb", "[-a src-index] [-b dst-index] [-s src-session] [-t dst-session]", - 0, + 0, 0, cmd_copy_buffer_init, cmd_copy_buffer_parse, cmd_copy_buffer_exec, diff --git a/cmd-copy-mode.c b/cmd-copy-mode.c index 0600d116..e9891179 100644 --- a/cmd-copy-mode.c +++ b/cmd-copy-mode.c @@ -29,7 +29,7 @@ int cmd_copy_mode_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_copy_mode_entry = { "copy-mode", NULL, "[-u] " CMD_TARGET_WINDOW_USAGE, - CMD_UFLAG, + 0, CMD_CHFLAG('u'), cmd_target_init, cmd_target_parse, cmd_copy_mode_exec, @@ -51,7 +51,7 @@ cmd_copy_mode_exec(struct cmd *self, struct cmd_ctx *ctx) wp = wl->window->active; window_pane_set_mode(wp, &window_copy_mode); - if (wp->mode == &window_copy_mode && data->flags & CMD_UFLAG) + if (wp->mode == &window_copy_mode && data->chflags & CMD_CHFLAG('u')) window_copy_pageup(wp); return (0); diff --git a/cmd-delete-buffer.c b/cmd-delete-buffer.c index 7351cf2c..81b69417 100644 --- a/cmd-delete-buffer.c +++ b/cmd-delete-buffer.c @@ -31,7 +31,7 @@ int cmd_delete_buffer_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_delete_buffer_entry = { "delete-buffer", "deleteb", CMD_BUFFER_SESSION_USAGE, - 0, + 0, 0, cmd_buffer_init, cmd_buffer_parse, cmd_delete_buffer_exec, diff --git a/cmd-detach-client.c b/cmd-detach-client.c index b900d84a..0a28cdc7 100644 --- a/cmd-detach-client.c +++ b/cmd-detach-client.c @@ -29,7 +29,7 @@ int cmd_detach_client_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_detach_client_entry = { "detach-client", "detach", CMD_TARGET_CLIENT_USAGE, - 0, + 0, 0, cmd_target_init, cmd_target_parse, cmd_detach_client_exec, diff --git a/cmd-down-pane.c b/cmd-down-pane.c index ddfe412a..9b1dfe1e 100644 --- a/cmd-down-pane.c +++ b/cmd-down-pane.c @@ -29,7 +29,7 @@ int cmd_down_pane_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_down_pane_entry = { "down-pane", "downp", CMD_TARGET_WINDOW_USAGE, - 0, + 0, 0, cmd_target_init, cmd_target_parse, cmd_down_pane_exec, diff --git a/cmd-find-window.c b/cmd-find-window.c index 9458fa8b..21461cdc 100644 --- a/cmd-find-window.c +++ b/cmd-find-window.c @@ -34,7 +34,7 @@ void cmd_find_window_callback(void *, int); const struct cmd_entry cmd_find_window_entry = { "find-window", "findw", CMD_TARGET_WINDOW_USAGE " match-string", - CMD_ARG1, + CMD_ARG1, 0, cmd_target_init, cmd_target_parse, cmd_find_window_exec, diff --git a/cmd-generic.c b/cmd-generic.c index 1b2e17a9..ea0d4d16 100644 --- a/cmd-generic.c +++ b/cmd-generic.c @@ -23,12 +23,9 @@ #include "tmux.h" -#define CMD_FLAGS "adDgkruU" -#define CMD_FLAGMASK (CMD_AFLAG|CMD_DFLAG|CMD_BIGDFLAG|CMD_GFLAG|CMD_KFLAG| \ - CMD_RFLAG|CMD_UFLAG|CMD_BIGUFLAG) - -int cmd_do_flags(int, int, int *); -size_t cmd_print_flags(char *, size_t, size_t, int); +int cmd_getopt(int, char **, const char *, uint64_t); +int cmd_flags(int, uint64_t, uint64_t *); +size_t cmd_print_flags(char *, size_t, size_t, uint64_t); int cmd_fill_argument(int, char **, int, char **); size_t @@ -39,86 +36,70 @@ cmd_prarg(char *buf, size_t len, const char *prefix, char *arg) return (xsnprintf(buf, len, "%s%s", prefix, arg)); } +/* Prepend flags from chflags onto flagstr and call getopt. */ int -cmd_do_flags(int opt, int iflags, int *oflags) +cmd_getopt(int argc, char **argv, const char *flagstr, uint64_t chflags) { - switch (opt) { - case 'a': - if (iflags & CMD_AFLAG) { - (*oflags) |= CMD_AFLAG; - return (0); - } - return (-1); - case 'd': - if (iflags & CMD_DFLAG) { - (*oflags) |= CMD_DFLAG; - return (0); - } - return (-1); - case 'D': - if (iflags & CMD_BIGDFLAG) { - (*oflags) |= CMD_BIGDFLAG; - return (0); - } - return (-1); - case 'g': - if (iflags & CMD_GFLAG) { - (*oflags) |= CMD_GFLAG; - return (0); - } - return (-1); - case 'k': - if (iflags & CMD_KFLAG) { - (*oflags) |= CMD_KFLAG; - return (0); - } - return (-1); - case 'r': - if (iflags & CMD_RFLAG) { - (*oflags) |= CMD_RFLAG; - return (0); - } - return (-1); - case 'u': - if (iflags & CMD_UFLAG) { - (*oflags) |= CMD_UFLAG; - return (0); - } - return (-1); - case 'U': - if (iflags & CMD_BIGUFLAG) { - (*oflags) |= CMD_BIGUFLAG; - return (0); - } - return (-1); + u_char ch; + char buf[128]; + size_t len, off; + + *buf = '\0'; + + len = sizeof buf; + off = 0; + + for (ch = 0; ch < 26; ch++) { + if (chflags & CMD_CHFLAG('a' + ch)) + off += xsnprintf(buf + off, len - off, "%c", 'a' + ch); + if (chflags & CMD_CHFLAG('A' + ch)) + off += xsnprintf(buf + off, len - off, "%c", 'A' + ch); } - return (1); + + strlcat(buf, flagstr, sizeof buf); + + return (getopt(argc, argv, buf)); } -size_t -cmd_print_flags(char *buf, size_t len, size_t off, int flags) +/* + * If this option is expected (in ichflags), set it in ochflags, otherwise + * return -1. + */ +int +cmd_flags(int opt, uint64_t ichflags, uint64_t *ochflags) { + u_char ch; + + for (ch = 0; ch < 26; ch++) { + if (opt == 'a' + ch && ichflags & CMD_CHFLAG(opt)) { + (*ochflags) |= CMD_CHFLAG(opt); + return (0); + } + if (opt == 'A' + ch && ichflags & CMD_CHFLAG(opt)) { + (*ochflags) |= CMD_CHFLAG(opt); + return (0); + } + } + return (-1); +} + +/* Print the flags supported in chflags. */ +size_t +cmd_print_flags(char *buf, size_t len, size_t off, uint64_t chflags) +{ + u_char ch; size_t boff = off; - if ((flags & CMD_FLAGMASK) == 0) + if (chflags == 0) return (0); off += xsnprintf(buf + off, len - off, " -"); - if (off < len && flags & CMD_AFLAG) - off += xsnprintf(buf + off, len - off, "a"); - if (off < len && flags & CMD_BIGDFLAG) - off += xsnprintf(buf + off, len - off, "D"); - if (off < len && flags & CMD_DFLAG) - off += xsnprintf(buf + off, len - off, "d"); - if (off < len && flags & CMD_GFLAG) - off += xsnprintf(buf + off, len - off, "g"); - if (off < len && flags & CMD_KFLAG) - off += xsnprintf(buf + off, len - off, "k"); - if (off < len && flags & CMD_RFLAG) - off += xsnprintf(buf + off, len - off, "r"); - if (off < len && flags & CMD_UFLAG) - off += xsnprintf(buf + off, len - off, "u"); - if (off < len && flags & CMD_BIGUFLAG) - off += xsnprintf(buf + off, len - off, "U"); + + for (ch = 0; ch < 26; ch++) { + if (chflags & CMD_CHFLAG('a' + ch)) + off += xsnprintf(buf + off, len - off, "%c", 'a' + ch); + if (chflags & CMD_CHFLAG('A' + ch)) + off += xsnprintf(buf + off, len - off, "%c", 'A' + ch); + } return (off - boff); } @@ -153,7 +134,7 @@ cmd_target_init(struct cmd *self, unused int key) struct cmd_target_data *data; self->data = data = xmalloc(sizeof *data); - data->flags = 0; + data->chflags = 0; data->target = NULL; data->arg = NULL; } @@ -162,19 +143,16 @@ int cmd_target_parse(struct cmd *self, int argc, char **argv, char **cause) { struct cmd_target_data *data; + const struct cmd_entry *entry = self->entry; int opt; /* Don't use the entry version since it may be dependent on key. */ cmd_target_init(self, 0); data = self->data; - while ((opt = getopt(argc, argv, CMD_FLAGS "t:")) != -1) { - switch (cmd_do_flags(opt, self->entry->flags, &data->flags)) { - case -1: - goto usage; - case 0: + while ((opt = cmd_getopt(argc, argv, "t:", entry->chflags)) != -1) { + if (cmd_flags(opt, entry->chflags, &data->chflags) == 0) continue; - } switch (opt) { case 't': if (data->target == NULL) @@ -240,7 +218,7 @@ cmd_target_print(struct cmd *self, char *buf, size_t len) off += xsnprintf(buf, len, "%s", self->entry->name); if (data == NULL) return (off); - off += cmd_print_flags(buf, len, off, data->flags); + off += cmd_print_flags(buf, len, off, data->chflags); if (off < len && data->target != NULL) off += cmd_prarg(buf + off, len - off, " -t ", data->target); if (off < len && data->arg != NULL) @@ -254,7 +232,7 @@ cmd_srcdst_init(struct cmd *self, unused int key) struct cmd_srcdst_data *data; self->data = data = xmalloc(sizeof *data); - data->flags = 0; + data->chflags = 0; data->src = NULL; data->dst = NULL; data->arg = NULL; @@ -264,18 +242,15 @@ int cmd_srcdst_parse(struct cmd *self, int argc, char **argv, char **cause) { struct cmd_srcdst_data *data; + const struct cmd_entry *entry = self->entry; int opt; cmd_srcdst_init(self, 0); data = self->data; - while ((opt = getopt(argc, argv, CMD_FLAGS "s:t:")) != -1) { - switch (cmd_do_flags(opt, self->entry->flags, &data->flags)) { - case -1: - goto usage; - case 0: + while ((opt = cmd_getopt(argc, argv, "s:t:", entry->chflags)) != -1) { + if (cmd_flags(opt, entry->chflags, &data->chflags) == 0) continue; - } switch (opt) { case 's': if (data->src == NULL) @@ -349,7 +324,7 @@ cmd_srcdst_print(struct cmd *self, char *buf, size_t len) off += xsnprintf(buf, len, "%s", self->entry->name); if (data == NULL) return (off); - off += cmd_print_flags(buf, len, off, data->flags); + off += cmd_print_flags(buf, len, off, data->chflags); if (off < len && data->src != NULL) off += xsnprintf(buf + off, len - off, " -s %s", data->src); if (off < len && data->dst != NULL) @@ -365,7 +340,7 @@ cmd_buffer_init(struct cmd *self, unused int key) struct cmd_buffer_data *data; self->data = data = xmalloc(sizeof *data); - data->flags = 0; + data->chflags = 0; data->target = NULL; data->buffer = -1; data->arg = NULL; @@ -375,19 +350,16 @@ int cmd_buffer_parse(struct cmd *self, int argc, char **argv, char **cause) { struct cmd_buffer_data *data; + const struct cmd_entry *entry = self->entry; int opt, n; const char *errstr; cmd_buffer_init(self, 0); data = self->data; - while ((opt = getopt(argc, argv, CMD_FLAGS "b:t:")) != -1) { - switch (cmd_do_flags(opt, self->entry->flags, &data->flags)) { - case -1: - goto usage; - case 0: + while ((opt = cmd_getopt(argc, argv, "b:t:", entry->chflags)) != -1) { + if (cmd_flags(opt, entry->chflags, &data->chflags) == 0) continue; - } switch (opt) { case 'b': if (data->buffer == -1) { @@ -464,7 +436,7 @@ cmd_buffer_print(struct cmd *self, char *buf, size_t len) off += xsnprintf(buf, len, "%s", self->entry->name); if (data == NULL) return (off); - off += cmd_print_flags(buf, len, off, data->flags); + off += cmd_print_flags(buf, len, off, data->chflags); if (off < len && data->buffer != -1) off += xsnprintf(buf + off, len - off, " -b %d", data->buffer); if (off < len && data->target != NULL) @@ -480,7 +452,7 @@ cmd_option_init(struct cmd *self, unused int key) struct cmd_option_data *data; self->data = data = xmalloc(sizeof *data); - data->flags = 0; + data->chflags = 0; data->target = NULL; data->option = NULL; data->value = NULL; @@ -490,19 +462,16 @@ int cmd_option_parse(struct cmd *self, int argc, char **argv, char **cause) { struct cmd_option_data *data; + const struct cmd_entry *entry = self->entry; int opt; /* Don't use the entry version since it may be dependent on key. */ cmd_option_init(self, 0); data = self->data; - while ((opt = getopt(argc, argv, CMD_FLAGS "t:")) != -1) { - switch (cmd_do_flags(opt, self->entry->flags, &data->flags)) { - case -1: - goto usage; - case 0: + while ((opt = cmd_getopt(argc, argv, "t:", entry->chflags)) != -1) { + if (cmd_flags(opt, entry->chflags, &data->chflags) == 0) continue; - } switch (opt) { case 't': if (data->target == NULL) @@ -577,7 +546,7 @@ cmd_option_print(struct cmd *self, char *buf, size_t len) off += xsnprintf(buf, len, "%s", self->entry->name); if (data == NULL) return (off); - off += cmd_print_flags(buf, len, off, data->flags); + off += cmd_print_flags(buf, len, off, data->chflags); if (off < len && data->target != NULL) off += cmd_prarg(buf + off, len - off, " -t ", data->target); if (off < len && data->option != NULL) @@ -593,7 +562,7 @@ cmd_pane_init(struct cmd *self, unused int key) struct cmd_pane_data *data; self->data = data = xmalloc(sizeof *data); - data->flags = 0; + data->chflags = 0; data->target = NULL; data->arg = NULL; data->pane = -1; @@ -603,6 +572,7 @@ int cmd_pane_parse(struct cmd *self, int argc, char **argv, char **cause) { struct cmd_pane_data *data; + const struct cmd_entry *entry = self->entry; int opt, n; const char *errstr; @@ -610,13 +580,9 @@ cmd_pane_parse(struct cmd *self, int argc, char **argv, char **cause) cmd_pane_init(self, 0); data = self->data; - while ((opt = getopt(argc, argv, CMD_FLAGS "p:t:")) != -1) { - switch (cmd_do_flags(opt, self->entry->flags, &data->flags)) { - case -1: - goto usage; - case 0: + while ((opt = cmd_getopt(argc, argv, "p:t:", entry->chflags)) != -1) { + if (cmd_flags(opt, entry->chflags, &data->chflags) == 0) continue; - } switch (opt) { case 'p': if (data->pane == -1) { @@ -693,7 +659,7 @@ cmd_pane_print(struct cmd *self, char *buf, size_t len) off += xsnprintf(buf, len, "%s", self->entry->name); if (data == NULL) return (off); - off += cmd_print_flags(buf, len, off, data->flags); + off += cmd_print_flags(buf, len, off, data->chflags); if (off < len && data->target != NULL) off += cmd_prarg(buf + off, len - off, " -t ", data->target); if (off < len && data->arg != NULL) diff --git a/cmd-has-session.c b/cmd-has-session.c index c0620e58..9999946b 100644 --- a/cmd-has-session.c +++ b/cmd-has-session.c @@ -29,7 +29,7 @@ int cmd_has_session_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_has_session_entry = { "has-session", "has", CMD_TARGET_SESSION_USAGE, - 0, + 0, 0, cmd_target_init, cmd_target_parse, cmd_has_session_exec, diff --git a/cmd-if-shell.c b/cmd-if-shell.c index 4f348a7e..e73e8d5d 100644 --- a/cmd-if-shell.c +++ b/cmd-if-shell.c @@ -44,7 +44,7 @@ struct cmd_if_shell_data { const struct cmd_entry cmd_if_shell_entry = { "if-shell", "if", "shell-command command", - 0, + 0, 0, cmd_if_shell_init, cmd_if_shell_parse, cmd_if_shell_exec, diff --git a/cmd-kill-pane.c b/cmd-kill-pane.c index b0e1dc7e..d3a54c92 100644 --- a/cmd-kill-pane.c +++ b/cmd-kill-pane.c @@ -31,7 +31,7 @@ int cmd_kill_pane_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_kill_pane_entry = { "kill-pane", "killp", CMD_PANE_WINDOW_USAGE, - 0, + 0, 0, cmd_pane_init, cmd_pane_parse, cmd_kill_pane_exec, diff --git a/cmd-kill-server.c b/cmd-kill-server.c index b2627a0a..0002a655 100644 --- a/cmd-kill-server.c +++ b/cmd-kill-server.c @@ -32,7 +32,7 @@ int cmd_kill_server_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_kill_server_entry = { "kill-server", NULL, "", - 0, + 0, 0, NULL, NULL, cmd_kill_server_exec, diff --git a/cmd-kill-session.c b/cmd-kill-session.c index 0ef9e4f1..83eabca1 100644 --- a/cmd-kill-session.c +++ b/cmd-kill-session.c @@ -32,7 +32,7 @@ int cmd_kill_session_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_kill_session_entry = { "kill-session", NULL, CMD_TARGET_SESSION_USAGE, - 0, + 0, 0, cmd_target_init, cmd_target_parse, cmd_kill_session_exec, diff --git a/cmd-kill-window.c b/cmd-kill-window.c index 155968d0..ca9ee1fa 100644 --- a/cmd-kill-window.c +++ b/cmd-kill-window.c @@ -29,7 +29,7 @@ int cmd_kill_window_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_kill_window_entry = { "kill-window", "killw", CMD_TARGET_WINDOW_USAGE, - 0, + 0, 0, cmd_target_init, cmd_target_parse, cmd_kill_window_exec, diff --git a/cmd-last-window.c b/cmd-last-window.c index 48c7fe0e..5ea2ad7e 100644 --- a/cmd-last-window.c +++ b/cmd-last-window.c @@ -29,7 +29,7 @@ int cmd_last_window_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_last_window_entry = { "last-window", "last", CMD_TARGET_SESSION_USAGE, - 0, + 0, 0, cmd_target_init, cmd_target_parse, cmd_last_window_exec, diff --git a/cmd-link-window.c b/cmd-link-window.c index 4e1ada81..e4e05f11 100644 --- a/cmd-link-window.c +++ b/cmd-link-window.c @@ -31,7 +31,7 @@ int cmd_link_window_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_link_window_entry = { "link-window", "linkw", "[-dk] " CMD_SRCDST_WINDOW_USAGE, - CMD_DFLAG|CMD_KFLAG, + 0, CMD_CHFLAG('d')|CMD_CHFLAG('k'), cmd_srcdst_init, cmd_srcdst_parse, cmd_link_window_exec, @@ -62,7 +62,7 @@ cmd_link_window_exec(struct cmd *self, struct cmd_ctx *ctx) if (wl_dst->window == wl_src->window) return (0); - if (data->flags & CMD_KFLAG) { + if (data->chflags & CMD_CHFLAG('k')) { /* * Can't use session_detach as it will destroy session * if this makes it empty. @@ -73,7 +73,7 @@ cmd_link_window_exec(struct cmd *self, struct cmd_ctx *ctx) /* Force select/redraw if current. */ if (wl_dst == dst->curw) { - data->flags &= ~CMD_DFLAG; + data->chflags &= ~CMD_CHFLAG('d'); dst->curw = NULL; } } @@ -86,7 +86,7 @@ cmd_link_window_exec(struct cmd *self, struct cmd_ctx *ctx) return (-1); } - if (data->flags & CMD_DFLAG) + if (data->chflags & CMD_CHFLAG('d')) server_status_session(dst); else { session_select(dst, wl_dst->idx); diff --git a/cmd-list-buffers.c b/cmd-list-buffers.c index 4edc38c3..6a57a723 100644 --- a/cmd-list-buffers.c +++ b/cmd-list-buffers.c @@ -31,7 +31,7 @@ int cmd_list_buffers_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_list_buffers_entry = { "list-buffers", "lsb", CMD_TARGET_SESSION_USAGE, - 0, + 0, 0, cmd_target_init, cmd_target_parse, cmd_list_buffers_exec, diff --git a/cmd-list-clients.c b/cmd-list-clients.c index 343afc20..bec90530 100644 --- a/cmd-list-clients.c +++ b/cmd-list-clients.c @@ -32,7 +32,7 @@ int cmd_list_clients_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_list_clients_entry = { "list-clients", "lsc", "", - 0, + 0, 0, NULL, NULL, cmd_list_clients_exec, diff --git a/cmd-list-commands.c b/cmd-list-commands.c index 59938ae2..9701a1bc 100644 --- a/cmd-list-commands.c +++ b/cmd-list-commands.c @@ -29,7 +29,7 @@ int cmd_list_commands_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_list_commands_entry = { "list-commands", "lscm", "", - 0, + 0, 0, NULL, NULL, cmd_list_commands_exec, diff --git a/cmd-list-keys.c b/cmd-list-keys.c index 1b22b4ab..17612449 100644 --- a/cmd-list-keys.c +++ b/cmd-list-keys.c @@ -29,7 +29,7 @@ int cmd_list_keys_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_list_keys_entry = { "list-keys", "lsk", "", - 0, + 0, 0, NULL, NULL, cmd_list_keys_exec, diff --git a/cmd-list-sessions.c b/cmd-list-sessions.c index 01f86524..3dac0107 100644 --- a/cmd-list-sessions.c +++ b/cmd-list-sessions.c @@ -31,7 +31,7 @@ int cmd_list_sessions_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_list_sessions_entry = { "list-sessions", "ls", "", - 0, + 0, 0, NULL, NULL, cmd_list_sessions_exec, diff --git a/cmd-list-windows.c b/cmd-list-windows.c index c9c3ad8c..8b2162a5 100644 --- a/cmd-list-windows.c +++ b/cmd-list-windows.c @@ -31,7 +31,7 @@ int cmd_list_windows_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_list_windows_entry = { "list-windows", "lsw", CMD_TARGET_SESSION_USAGE, - 0, + 0, 0, cmd_target_init, cmd_target_parse, cmd_list_windows_exec, diff --git a/cmd-load-buffer.c b/cmd-load-buffer.c index 11d2d548..f2f2c08c 100644 --- a/cmd-load-buffer.c +++ b/cmd-load-buffer.c @@ -35,7 +35,7 @@ int cmd_load_buffer_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_load_buffer_entry = { "load-buffer", "loadb", CMD_BUFFER_SESSION_USAGE " path", - CMD_ARG1, + CMD_ARG1, 0, cmd_buffer_init, cmd_buffer_parse, cmd_load_buffer_exec, diff --git a/cmd-lock-server.c b/cmd-lock-server.c index 74b7b622..5e0356e1 100644 --- a/cmd-lock-server.c +++ b/cmd-lock-server.c @@ -33,7 +33,7 @@ int cmd_lock_server_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_lock_server_entry = { "lock-server", "lock", "", - 0, + 0, 0, NULL, NULL, cmd_lock_server_exec, diff --git a/cmd-move-window.c b/cmd-move-window.c index c9117c4b..2a967cdf 100644 --- a/cmd-move-window.c +++ b/cmd-move-window.c @@ -31,7 +31,7 @@ int cmd_move_window_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_move_window_entry = { "move-window", "movew", "[-dk] " CMD_SRCDST_WINDOW_USAGE, - CMD_DFLAG|CMD_KFLAG, + 0, CMD_CHFLAG('d')|CMD_CHFLAG('k'), cmd_srcdst_init, cmd_srcdst_parse, cmd_move_window_exec, @@ -64,7 +64,7 @@ cmd_move_window_exec(struct cmd *self, struct cmd_ctx *ctx) if (wl_dst->window == wl_src->window) return (0); - if (data->flags & CMD_KFLAG) { + if (data->chflags & CMD_CHFLAG('k')) { /* * Can't use session_detach as it will destroy session * if this makes it empty. @@ -75,7 +75,7 @@ cmd_move_window_exec(struct cmd *self, struct cmd_ctx *ctx) /* Force select/redraw if current. */ if (wl_dst == dst->curw) { - data->flags &= ~CMD_DFLAG; + data->chflags &= ~CMD_CHFLAG('d'); dst->curw = NULL; } } @@ -100,7 +100,7 @@ cmd_move_window_exec(struct cmd *self, struct cmd_ctx *ctx) server_redraw_client(c); } - if (data->flags & CMD_DFLAG) + if (data->chflags & CMD_CHFLAG('d')) server_status_session(dst); else { session_select(dst, wl_dst->idx); diff --git a/cmd-new-session.c b/cmd-new-session.c index 95fc08b2..cf086a87 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -42,7 +42,7 @@ struct cmd_new_session_data { const struct cmd_entry cmd_new_session_entry = { "new-session", "new", "[-d] [-n window-name] [-s session-name] [command]", - CMD_STARTSERVER|CMD_CANTNEST, + CMD_STARTSERVER|CMD_CANTNEST, 0, cmd_new_session_init, cmd_new_session_parse, cmd_new_session_exec, diff --git a/cmd-new-window.c b/cmd-new-window.c index ee8cd8b7..e54bfc7d 100644 --- a/cmd-new-window.c +++ b/cmd-new-window.c @@ -45,7 +45,7 @@ struct cmd_new_window_data { const struct cmd_entry cmd_new_window_entry = { "new-window", "neww", "[-dk] [-n window-name] [-t target-window] [command]", - 0, + 0, 0, cmd_new_window_init, cmd_new_window_parse, cmd_new_window_exec, diff --git a/cmd-next-layout.c b/cmd-next-layout.c index 85fd8d35..b89dda3d 100644 --- a/cmd-next-layout.c +++ b/cmd-next-layout.c @@ -29,7 +29,7 @@ int cmd_next_layout_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_next_layout_entry = { "next-layout", "nextl", CMD_TARGET_WINDOW_USAGE, - 0, + 0, 0, cmd_target_init, cmd_target_parse, cmd_next_layout_exec, diff --git a/cmd-next-window.c b/cmd-next-window.c index d49fe4cb..f0f8d18e 100644 --- a/cmd-next-window.c +++ b/cmd-next-window.c @@ -30,7 +30,7 @@ int cmd_next_window_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_next_window_entry = { "next-window", "next", "[-a] " CMD_TARGET_SESSION_USAGE, - CMD_AFLAG, + 0, CMD_CHFLAG('a'), cmd_next_window_init, cmd_target_parse, cmd_next_window_exec, @@ -49,7 +49,7 @@ cmd_next_window_init(struct cmd *self, int key) data = self->data; if (key == KEYC_ADDESC('n')) - data->flags |= CMD_AFLAG; + data->chflags |= CMD_CHFLAG('a'); } int @@ -63,7 +63,7 @@ cmd_next_window_exec(struct cmd *self, struct cmd_ctx *ctx) return (-1); activity = 0; - if (data->flags & CMD_AFLAG) + if (data->chflags & CMD_CHFLAG('a')) activity = 1; if (session_next(s, activity) == 0) diff --git a/cmd-paste-buffer.c b/cmd-paste-buffer.c index c586e0fc..76a92eaf 100644 --- a/cmd-paste-buffer.c +++ b/cmd-paste-buffer.c @@ -32,7 +32,7 @@ void cmd_paste_buffer_lf2cr(struct buffer *, const char *, size_t); const struct cmd_entry cmd_paste_buffer_entry = { "paste-buffer", "pasteb", "[-dr] " CMD_BUFFER_WINDOW_USAGE, - CMD_DFLAG|CMD_RFLAG, + 0, CMD_CHFLAG('d')|CMD_CHFLAG('r'), cmd_buffer_init, cmd_buffer_parse, cmd_paste_buffer_exec, @@ -66,7 +66,7 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) if (pb != NULL && *pb->data != '\0') { /* -r means raw data without LF->CR conversion. */ - if (data->flags & CMD_RFLAG) { + if (data->chflags & CMD_CHFLAG('r')) { buffer_write( w->active->out, pb->data, strlen(pb->data)); } else { @@ -76,7 +76,7 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) } /* Delete the buffer if -d. */ - if (data->flags & CMD_DFLAG) { + if (data->chflags & CMD_CHFLAG('d')) { if (data->buffer == -1) paste_free_top(&s->buffers); else diff --git a/cmd-previous-layout.c b/cmd-previous-layout.c index 5b662ede..f4270f14 100644 --- a/cmd-previous-layout.c +++ b/cmd-previous-layout.c @@ -29,7 +29,7 @@ int cmd_previous_layout_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_previous_layout_entry = { "previous-layout", "prevl", CMD_TARGET_WINDOW_USAGE, - 0, + 0, 0, cmd_target_init, cmd_target_parse, cmd_previous_layout_exec, diff --git a/cmd-previous-window.c b/cmd-previous-window.c index 6163cec1..2c5088b2 100644 --- a/cmd-previous-window.c +++ b/cmd-previous-window.c @@ -30,7 +30,7 @@ int cmd_previous_window_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_previous_window_entry = { "previous-window", "prev", "[-a] " CMD_TARGET_SESSION_USAGE, - CMD_AFLAG, + 0, CMD_CHFLAG('a'), cmd_previous_window_init, cmd_target_parse, cmd_previous_window_exec, @@ -49,7 +49,7 @@ cmd_previous_window_init(struct cmd *self, int key) data = self->data; if (key == KEYC_ADDESC('p')) - data->flags |= CMD_AFLAG; + data->chflags |= CMD_CHFLAG('a'); } int @@ -63,7 +63,7 @@ cmd_previous_window_exec(struct cmd *self, struct cmd_ctx *ctx) return (-1); activity = 0; - if (data->flags & CMD_AFLAG) + if (data->chflags & CMD_CHFLAG('a')) activity = 1; if (session_previous(s, activity) == 0) diff --git a/cmd-refresh-client.c b/cmd-refresh-client.c index 9193a953..9ff0ae8d 100644 --- a/cmd-refresh-client.c +++ b/cmd-refresh-client.c @@ -29,7 +29,7 @@ int cmd_refresh_client_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_refresh_client_entry = { "refresh-client", "refresh", CMD_TARGET_CLIENT_USAGE, - 0, + 0, 0, cmd_target_init, cmd_target_parse, cmd_refresh_client_exec, diff --git a/cmd-rename-session.c b/cmd-rename-session.c index 305795fd..7e5e81e6 100644 --- a/cmd-rename-session.c +++ b/cmd-rename-session.c @@ -31,7 +31,7 @@ int cmd_rename_session_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_rename_session_entry = { "rename-session", "rename", CMD_TARGET_SESSION_USAGE " new-name", - CMD_ARG1, + CMD_ARG1, 0, cmd_target_init, cmd_target_parse, cmd_rename_session_exec, diff --git a/cmd-rename-window.c b/cmd-rename-window.c index 985a7b58..9d314eb5 100644 --- a/cmd-rename-window.c +++ b/cmd-rename-window.c @@ -31,7 +31,7 @@ int cmd_rename_window_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_rename_window_entry = { "rename-window", "renamew", CMD_TARGET_WINDOW_USAGE " new-name", - CMD_ARG1, + CMD_ARG1, 0, cmd_target_init, cmd_target_parse, cmd_rename_window_exec, diff --git a/cmd-resize-pane.c b/cmd-resize-pane.c index 2f1c3ad7..64ac95b2 100644 --- a/cmd-resize-pane.c +++ b/cmd-resize-pane.c @@ -32,7 +32,7 @@ int cmd_resize_pane_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_resize_pane_entry = { "resize-pane", "resizep", CMD_PANE_WINDOW_USAGE "[-DU] [adjustment]", - CMD_ARG01|CMD_BIGUFLAG|CMD_BIGDFLAG, + CMD_ARG01, CMD_CHFLAG('D')|CMD_CHFLAG('U'), cmd_resize_pane_init, cmd_pane_parse, cmd_resize_pane_exec, @@ -51,12 +51,12 @@ cmd_resize_pane_init(struct cmd *self, int key) data = self->data; if (key == KEYC_ADDCTL(KEYC_DOWN)) - data->flags |= CMD_BIGDFLAG; + data->chflags |= CMD_CHFLAG('D'); if (key == KEYC_ADDESC(KEYC_UP)) data->arg = xstrdup("5"); if (key == KEYC_ADDESC(KEYC_DOWN)) { - data->flags |= CMD_BIGDFLAG; + data->chflags |= CMD_CHFLAG('D'); data->arg = xstrdup("5"); } } @@ -92,7 +92,7 @@ cmd_resize_pane_exec(struct cmd *self, struct cmd_ctx *ctx) } } - if (!(data->flags & CMD_BIGDFLAG)) + if (!(data->chflags & CMD_CHFLAG('D'))) adjust = -adjust; if (layout_resize(wp, adjust) != 0) { ctx->error(ctx, "layout %s " diff --git a/cmd-respawn-window.c b/cmd-respawn-window.c index 7c5b2fd5..5d70aa63 100644 --- a/cmd-respawn-window.c +++ b/cmd-respawn-window.c @@ -31,7 +31,7 @@ int cmd_respawn_window_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_respawn_window_entry = { "respawn-window", "respawnw", "[-k] " CMD_TARGET_WINDOW_USAGE " [command]", - CMD_ARG01|CMD_KFLAG, + CMD_ARG01, CMD_CHFLAG('k'), cmd_target_init, cmd_target_parse, cmd_respawn_window_exec, @@ -56,7 +56,7 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_ctx *ctx) return (-1); w = wl->window; - if (!(data->flags & CMD_KFLAG)) { + if (!(data->chflags & CMD_CHFLAG('k'))) { TAILQ_FOREACH(wp, &w->panes, entry) { if (wp->fd == -1) continue; diff --git a/cmd-rotate-window.c b/cmd-rotate-window.c index 52b752e9..3f40603a 100644 --- a/cmd-rotate-window.c +++ b/cmd-rotate-window.c @@ -30,7 +30,7 @@ int cmd_rotate_window_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_rotate_window_entry = { "rotate-window", "rotatew", "[-DU] " CMD_TARGET_WINDOW_USAGE, - CMD_BIGUFLAG|CMD_BIGDFLAG, + 0, CMD_CHFLAG('D')|CMD_CHFLAG('U'), cmd_rotate_window_init, cmd_target_parse, cmd_rotate_window_exec, @@ -49,7 +49,7 @@ cmd_rotate_window_init(struct cmd *self, int key) data = self->data; if (key == KEYC_ADDESC('o')) - data->flags |= CMD_BIGDFLAG; + data->chflags |= CMD_CHFLAG('D'); } int @@ -66,7 +66,7 @@ cmd_rotate_window_exec(struct cmd *self, struct cmd_ctx *ctx) return (-1); w = wl->window; - if (data->flags & CMD_BIGDFLAG) { + if (data->chflags & CMD_CHFLAG('D')) { wp = TAILQ_LAST(&w->panes, window_panes); TAILQ_REMOVE(&w->panes, wp, entry); TAILQ_INSERT_HEAD(&w->panes, wp, entry); diff --git a/cmd-save-buffer.c b/cmd-save-buffer.c index 7c5af7a4..1eef28c4 100644 --- a/cmd-save-buffer.c +++ b/cmd-save-buffer.c @@ -33,7 +33,7 @@ int cmd_save_buffer_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_save_buffer_entry = { "save-buffer", "saveb", "[-a] " CMD_BUFFER_SESSION_USAGE " path", - CMD_AFLAG|CMD_ARG1, + CMD_ARG1, CMD_CHFLAG('a'), cmd_buffer_init, cmd_buffer_parse, cmd_save_buffer_exec, @@ -68,7 +68,7 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) } mask = umask(S_IRWXG | S_IRWXO); - if (data->flags & CMD_AFLAG) + if (data->chflags & CMD_CHFLAG('a')) f = fopen(data->arg, "ab"); else f = fopen(data->arg, "wb"); diff --git a/cmd-scroll-mode.c b/cmd-scroll-mode.c index f376d703..898e3a60 100644 --- a/cmd-scroll-mode.c +++ b/cmd-scroll-mode.c @@ -30,7 +30,7 @@ int cmd_scroll_mode_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_scroll_mode_entry = { "scroll-mode", NULL, "[-u] " CMD_TARGET_WINDOW_USAGE, - CMD_UFLAG, + 0, CMD_CHFLAG('u'), cmd_scroll_mode_init, cmd_target_parse, cmd_scroll_mode_exec, @@ -50,7 +50,7 @@ cmd_scroll_mode_init(struct cmd *self, int key) switch (key) { case KEYC_PPAGE: - data->flags |= CMD_UFLAG; + data->chflags |= CMD_CHFLAG('u'); break; } } @@ -67,7 +67,7 @@ cmd_scroll_mode_exec(struct cmd *self, struct cmd_ctx *ctx) wp = wl->window->active; window_pane_set_mode(wp, &window_scroll_mode); - if (wp->mode == &window_scroll_mode && data->flags & CMD_UFLAG) + if (wp->mode == &window_scroll_mode && data->chflags & CMD_CHFLAG('u')) window_scroll_pageup(wp); return (0); diff --git a/cmd-select-layout.c b/cmd-select-layout.c index ef921660..01d7ef6e 100644 --- a/cmd-select-layout.c +++ b/cmd-select-layout.c @@ -30,7 +30,7 @@ int cmd_select_layout_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_select_layout_entry = { "select-layout", "selectl", CMD_TARGET_WINDOW_USAGE " layout-name", - CMD_ARG1, + CMD_ARG1, 0, cmd_select_layout_init, cmd_target_parse, cmd_select_layout_exec, diff --git a/cmd-select-pane.c b/cmd-select-pane.c index 33c94a33..ab3f0b3f 100644 --- a/cmd-select-pane.c +++ b/cmd-select-pane.c @@ -29,7 +29,7 @@ int cmd_select_pane_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_select_pane_entry = { "select-pane", "selectp", CMD_PANE_WINDOW_USAGE, - 0, + 0, 0, cmd_pane_init, cmd_pane_parse, cmd_select_pane_exec, diff --git a/cmd-select-prompt.c b/cmd-select-prompt.c index 81da9dbb..5221fa1e 100644 --- a/cmd-select-prompt.c +++ b/cmd-select-prompt.c @@ -33,7 +33,7 @@ int cmd_select_prompt_callback(void *, const char *); const struct cmd_entry cmd_select_prompt_entry = { "select-prompt", NULL, CMD_TARGET_CLIENT_USAGE, - 0, + 0, 0, cmd_target_init, cmd_target_parse, cmd_select_prompt_exec, diff --git a/cmd-select-window.c b/cmd-select-window.c index 55f8318c..41bf78fa 100644 --- a/cmd-select-window.c +++ b/cmd-select-window.c @@ -32,7 +32,7 @@ int cmd_select_window_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_select_window_entry = { "select-window", "selectw", CMD_TARGET_WINDOW_USAGE, - 0, + 0, 0, cmd_select_window_init, cmd_target_parse, cmd_select_window_exec, diff --git a/cmd-send-keys.c b/cmd-send-keys.c index 849fe7be..df02efc5 100644 --- a/cmd-send-keys.c +++ b/cmd-send-keys.c @@ -43,7 +43,7 @@ struct cmd_send_keys_data { const struct cmd_entry cmd_send_keys_entry = { "send-keys", "send", "[-t target-window] key ...", - 0, + 0, 0, NULL, cmd_send_keys_parse, cmd_send_keys_exec, diff --git a/cmd-send-prefix.c b/cmd-send-prefix.c index d45ca0c1..ca4fae6e 100644 --- a/cmd-send-prefix.c +++ b/cmd-send-prefix.c @@ -29,7 +29,7 @@ int cmd_send_prefix_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_send_prefix_entry = { "send-prefix", NULL, CMD_TARGET_WINDOW_USAGE, - 0, + 0, 0, cmd_target_init, cmd_target_parse, cmd_send_prefix_exec, diff --git a/cmd-server-info.c b/cmd-server-info.c index 2ce44841..2678facd 100644 --- a/cmd-server-info.c +++ b/cmd-server-info.c @@ -36,7 +36,7 @@ int cmd_server_info_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_server_info_entry = { "server-info", "info", "", - 0, + 0, 0, NULL, NULL, cmd_server_info_exec, diff --git a/cmd-set-buffer.c b/cmd-set-buffer.c index 3e1aa0a5..3620dfde 100644 --- a/cmd-set-buffer.c +++ b/cmd-set-buffer.c @@ -31,7 +31,7 @@ int cmd_set_buffer_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_set_buffer_entry = { "set-buffer", "setb", CMD_BUFFER_SESSION_USAGE " data", - CMD_ARG1, + CMD_ARG1, 0, cmd_buffer_init, cmd_buffer_parse, cmd_set_buffer_exec, diff --git a/cmd-set-option.c b/cmd-set-option.c index 88e297b0..77972e92 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -32,7 +32,7 @@ int cmd_set_option_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_set_option_entry = { "set-option", "set", CMD_OPTION_SESSION_USAGE, - CMD_GFLAG|CMD_UFLAG, + 0, CMD_CHFLAG('g')|CMD_CHFLAG('u'), NULL, cmd_option_parse, cmd_set_option_exec, @@ -87,7 +87,7 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) const struct set_option_entry *entry; u_int i; - if (data->flags & CMD_GFLAG) + if (data->chflags & CMD_CHFLAG('g')) oo = &global_s_options; else { if ((s = cmd_find_session(ctx, data->target)) == NULL) @@ -120,8 +120,8 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) return (-1); } - if (data->flags & CMD_UFLAG) { - if (data->flags & CMD_GFLAG) { + if (data->chflags & CMD_CHFLAG('u')) { + if (data->chflags & CMD_CHFLAG('g')) { ctx->error(ctx, "can't unset global option: %s", entry->name); return (-1); diff --git a/cmd-set-password.c b/cmd-set-password.c index 93705cab..1ec956c9 100644 --- a/cmd-set-password.c +++ b/cmd-set-password.c @@ -43,7 +43,7 @@ struct cmd_set_password_data { const struct cmd_entry cmd_set_password_entry = { "set-password", "pass", "[-c] password", - 0, + 0, 0, cmd_set_password_init, cmd_set_password_parse, cmd_set_password_exec, diff --git a/cmd-set-window-option.c b/cmd-set-window-option.c index 99b1a907..5f24af72 100644 --- a/cmd-set-window-option.c +++ b/cmd-set-window-option.c @@ -32,7 +32,7 @@ int cmd_set_window_option_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_set_window_option_entry = { "set-window-option", "setw", CMD_OPTION_WINDOW_USAGE, - CMD_GFLAG|CMD_UFLAG, + 0, CMD_CHFLAG('g')|CMD_CHFLAG('u'), NULL, cmd_option_parse, cmd_set_window_option_exec, @@ -81,7 +81,7 @@ cmd_set_window_option_exec(struct cmd *self, struct cmd_ctx *ctx) const struct set_option_entry *entry; u_int i; - if (data->flags & CMD_GFLAG) + if (data->chflags & CMD_CHFLAG('g')) oo = &global_w_options; else { if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) @@ -114,8 +114,8 @@ cmd_set_window_option_exec(struct cmd *self, struct cmd_ctx *ctx) return (-1); } - if (data->flags & CMD_UFLAG) { - if (data->flags & CMD_GFLAG) { + if (data->chflags & CMD_CHFLAG('u')) { + if (data->chflags & CMD_CHFLAG('g')) { ctx->error(ctx, "can't unset global option: %s", entry->name); return (-1); diff --git a/cmd-show-buffer.c b/cmd-show-buffer.c index 3e779f31..e5a646d9 100644 --- a/cmd-show-buffer.c +++ b/cmd-show-buffer.c @@ -31,7 +31,7 @@ int cmd_show_buffer_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_show_buffer_entry = { "show-buffer", "showb", CMD_BUFFER_SESSION_USAGE, - 0, + 0, 0, cmd_buffer_init, cmd_buffer_parse, cmd_show_buffer_exec, diff --git a/cmd-show-options.c b/cmd-show-options.c index 3cc3be58..e5f50859 100644 --- a/cmd-show-options.c +++ b/cmd-show-options.c @@ -32,7 +32,7 @@ int cmd_show_options_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_show_options_entry = { "show-options", "show", "[-g] " CMD_TARGET_SESSION_USAGE, - CMD_GFLAG, + 0, CMD_CHFLAG('g'), cmd_target_init, cmd_target_parse, cmd_show_options_exec, @@ -53,7 +53,7 @@ cmd_show_options_exec(struct cmd *self, struct cmd_ctx *ctx) char *vs; long long vn; - if (data->flags & CMD_GFLAG) + if (data->chflags & CMD_CHFLAG('g')) oo = &global_s_options; else { if ((s = cmd_find_session(ctx, data->target)) == NULL) diff --git a/cmd-show-window-options.c b/cmd-show-window-options.c index 9f9c65ca..9fd35177 100644 --- a/cmd-show-window-options.c +++ b/cmd-show-window-options.c @@ -32,7 +32,7 @@ int cmd_show_window_options_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_show_window_options_entry = { "show-window-options", "showw", "[-g] " CMD_TARGET_WINDOW_USAGE, - CMD_GFLAG, + 0, CMD_CHFLAG('g'), cmd_target_init, cmd_target_parse, cmd_show_window_options_exec, @@ -53,7 +53,7 @@ cmd_show_window_options_exec(struct cmd *self, struct cmd_ctx *ctx) char *vs; long long vn; - if (data->flags & CMD_GFLAG) + if (data->chflags & CMD_CHFLAG('g')) oo = &global_w_options; else { if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) diff --git a/cmd-source-file.c b/cmd-source-file.c index f22322ee..c9075530 100644 --- a/cmd-source-file.c +++ b/cmd-source-file.c @@ -39,7 +39,7 @@ struct cmd_source_file_data { const struct cmd_entry cmd_source_file_entry = { "source-file", "source", "path", - 0, + 0, 0, cmd_source_file_init, cmd_source_file_parse, cmd_source_file_exec, diff --git a/cmd-split-window.c b/cmd-split-window.c index a46b23a5..74d28313 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -46,7 +46,7 @@ struct cmd_split_window_data { const struct cmd_entry cmd_split_window_entry = { "split-window", "splitw", "[-d] [-p percentage|-l lines] [-t target-window] [command]", - 0, + 0, 0, cmd_split_window_init, cmd_split_window_parse, cmd_split_window_exec, diff --git a/cmd-start-server.c b/cmd-start-server.c index 21bc2395..b8f00949 100644 --- a/cmd-start-server.c +++ b/cmd-start-server.c @@ -29,7 +29,7 @@ int cmd_start_server_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_start_server_entry = { "start-server", "start", "", - CMD_STARTSERVER, + CMD_STARTSERVER, 0, NULL, NULL, cmd_start_server_exec, diff --git a/cmd-suspend-client.c b/cmd-suspend-client.c index 00941f61..5642bbec 100644 --- a/cmd-suspend-client.c +++ b/cmd-suspend-client.c @@ -37,7 +37,7 @@ struct cmd_suspend_client_data { const struct cmd_entry cmd_suspend_client_entry = { "suspend-client", "suspendc", "[-c target-client]", - 0, + 0, 0, cmd_target_init, cmd_target_parse, cmd_suspend_client_exec, diff --git a/cmd-swap-pane.c b/cmd-swap-pane.c index e2f572dc..49c8611b 100644 --- a/cmd-swap-pane.c +++ b/cmd-swap-pane.c @@ -46,7 +46,7 @@ struct cmd_swap_pane_data { const struct cmd_entry cmd_swap_pane_entry = { "swap-pane", "swapp", "[-dDU] [-t target-window] [-p src-index] [-q dst-index]", - 0, + 0, 0, cmd_swap_pane_init, cmd_swap_pane_parse, cmd_swap_pane_exec, diff --git a/cmd-swap-window.c b/cmd-swap-window.c index 4a72a3e5..61e9c423 100644 --- a/cmd-swap-window.c +++ b/cmd-swap-window.c @@ -31,7 +31,7 @@ int cmd_swap_window_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_swap_window_entry = { "swap-window", "swapw", "[-d] " CMD_SRCDST_WINDOW_USAGE, - CMD_DFLAG, + 0, CMD_CHFLAG('d'), cmd_srcdst_init, cmd_srcdst_parse, cmd_swap_window_exec, @@ -61,7 +61,7 @@ cmd_swap_window_exec(struct cmd *self, struct cmd_ctx *ctx) wl_dst->window = wl_src->window; wl_src->window = w; - if (!(data->flags & CMD_DFLAG)) { + if (!(data->chflags & CMD_CHFLAG('d'))) { session_select(dst, wl_dst->idx); if (src != dst) session_select(src, wl_src->idx); diff --git a/cmd-switch-client.c b/cmd-switch-client.c index 9df443db..1ad4701f 100644 --- a/cmd-switch-client.c +++ b/cmd-switch-client.c @@ -42,7 +42,7 @@ struct cmd_switch_client_data { const struct cmd_entry cmd_switch_client_entry = { "switch-client", "switchc", "[-c target-client] [-t target-session]", - 0, + 0, 0, NULL, cmd_switch_client_parse, cmd_switch_client_exec, diff --git a/cmd-unbind-key.c b/cmd-unbind-key.c index d9389752..7272bc77 100644 --- a/cmd-unbind-key.c +++ b/cmd-unbind-key.c @@ -37,7 +37,7 @@ struct cmd_unbind_key_data { const struct cmd_entry cmd_unbind_key_entry = { "unbind-key", "unbind", "key", - 0, + 0, 0, NULL, cmd_unbind_key_parse, cmd_unbind_key_exec, diff --git a/cmd-unlink-window.c b/cmd-unlink-window.c index 5d9734b6..1befabd9 100644 --- a/cmd-unlink-window.c +++ b/cmd-unlink-window.c @@ -29,7 +29,7 @@ int cmd_unlink_window_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_unlink_window_entry = { "unlink-window", "unlinkw", CMD_TARGET_WINDOW_USAGE, - 0, + 0, 0, cmd_target_init, cmd_target_parse, cmd_unlink_window_exec, diff --git a/cmd-up-pane.c b/cmd-up-pane.c index fc62173e..ec532370 100644 --- a/cmd-up-pane.c +++ b/cmd-up-pane.c @@ -29,7 +29,7 @@ int cmd_up_pane_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_up_pane_entry = { "up-pane", "upp", CMD_TARGET_WINDOW_USAGE, - 0, + 0, 0, cmd_target_init, cmd_target_parse, cmd_up_pane_exec, diff --git a/tmux.h b/tmux.h index 585daeb9..bd4cbf9a 100644 --- a/tmux.h +++ b/tmux.h @@ -861,17 +861,13 @@ struct cmd_entry { #define CMD_CANTNEST 0x2 #define CMD_ARG1 0x4 #define CMD_ARG01 0x8 -#define CMD_AFLAG 0x10 -#define CMD_DFLAG 0x20 -#define CMD_GFLAG 0x40 -#define CMD_KFLAG 0x80 -#define CMD_UFLAG 0x100 -#define CMD_BIGDFLAG 0x200 -#define CMD_BIGUFLAG 0x400 -#define CMD_RFLAG 0x800 - int flags; +#define CMD_CHFLAG(flag) \ + ((flag) >= 'a' && (flag) <= 'z' ? 1ULL << ((flag) - 'a') : \ + (flag) >= 'A' && (flag) <= 'Z' ? 1ULL << (26 + (flag) - 'A') : 0) + uint64_t chflags; + void (*init)(struct cmd *, int); int (*parse)(struct cmd *, int, char **, char **); int (*exec)(struct cmd *, struct cmd_ctx *); @@ -883,34 +879,34 @@ struct cmd_entry { /* Generic command data. */ struct cmd_target_data { - int flags; + uint64_t chflags; char *target; char *arg; }; struct cmd_srcdst_data { - int flags; + uint64_t chflags; char *src; char *dst; char *arg; }; struct cmd_buffer_data { - int flags; + uint64_t chflags; char *target; int buffer; char *arg; }; struct cmd_option_data { - int flags; + uint64_t chflags; char *target; char *option; char *value; }; struct cmd_pane_data { - int flags; + uint64_t chflags; char *target; char *arg; int pane; From ceace9c6bdbbdf8970b84517b78ee44869596287 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 14 Jul 2009 06:30:45 +0000 Subject: [PATCH 0115/1180] Since tmux doesn't actually need ncurses, use -lcurses/curses.h instead. Pointed out by millert a while ago. --- Makefile | 2 +- tty-term.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 4630160c..ef628faa 100644 --- a/Makefile +++ b/Makefile @@ -38,7 +38,7 @@ CDIAGFLAGS+= -Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations CDIAGFLAGS+= -Wwrite-strings -Wshadow -Wpointer-arith -Wsign-compare CDIAGFLAGS+= -Wundef -Wbad-function-cast -Winline -Wcast-align -LDADD= -lutil -lncurses +LDADD= -lutil -lcurses DPADD= ${LIBUTIL} .include diff --git a/tty-term.c b/tty-term.c index e7aced73..0f50a269 100644 --- a/tty-term.c +++ b/tty-term.c @@ -18,7 +18,7 @@ #include -#include +#include #include #include @@ -183,7 +183,7 @@ tty_term_find(char *name, int fd, char **cause) term->flags = 0; SLIST_INSERT_HEAD(&tty_terms, term, entry); - /* Set up ncurses terminal. */ + /* Set up curses terminal. */ if (setupterm(name, fd, &error) != OK) { switch (error) { case 0: @@ -237,7 +237,7 @@ tty_term_find(char *name, int fd, char **cause) } tty_term_quirks(term); - /* Delete ncurses data. */ + /* Delete curses data. */ del_curterm(cur_term); /* These are always required. */ @@ -358,7 +358,7 @@ tty_term_string(struct tty_term *term, enum tty_code_code code) return (term->codes[code].value.string); } -/* No vtparm. Fucking ncurses. */ +/* No vtparm. Fucking curses. */ const char * tty_term_string1(struct tty_term *term, enum tty_code_code code, int a) { From 6910458a92a12c3d073ea4f5839060ee0914cc17 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 14 Jul 2009 06:56:30 +0000 Subject: [PATCH 0116/1180] Add backspace key to named keys. --- key-string.c | 1 + 1 file changed, 1 insertion(+) diff --git a/key-string.c b/key-string.c index b2f1fad2..cf146b98 100644 --- a/key-string.c +++ b/key-string.c @@ -57,6 +57,7 @@ struct { { "PPage", KEYC_PPAGE }, { "Tab", '\011' }, { "BTab", KEYC_BTAB }, + { "BSpace", '\177' }, /* Arrow keys. */ { "Up", KEYC_UP }, From 4a9b01eb0d328f13a03f967759bfd76d749da17f Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 14 Jul 2009 06:59:06 +0000 Subject: [PATCH 0117/1180] Need time.h not sys/time.h for time(2). --- server-fn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server-fn.c b/server-fn.c index 2d6709f5..b5cc00f5 100644 --- a/server-fn.c +++ b/server-fn.c @@ -17,9 +17,9 @@ */ #include -#include #include +#include #include #include "tmux.h" From fe20c0d89ef5b8581c28067496f0f4c545d55ef8 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 14 Jul 2009 07:23:36 +0000 Subject: [PATCH 0118/1180] Get rid of the PANE_HIDDEN flag in favour of a function, and moving the decision for whether or not a pane should be drawn out of the layout code and into the redraw code. This is needed for the new layout design, getting it in now to make that easier to work on. --- cmd-down-pane.c | 2 +- cmd-rotate-window.c | 11 -------- cmd-select-pane.c | 4 +-- cmd-swap-pane.c | 8 +----- cmd-up-pane.c | 2 +- layout-manual.c | 43 +++++++++++------------------- layout.c | 65 ++++++++++++++++++++------------------------- resize.c | 15 +++++++++++ screen-redraw.c | 5 +++- tmux.h | 6 ++--- tty-write.c | 2 +- window.c | 20 +++++++++++++- 12 files changed, 92 insertions(+), 91 deletions(-) diff --git a/cmd-down-pane.c b/cmd-down-pane.c index 9b1dfe1e..73736946 100644 --- a/cmd-down-pane.c +++ b/cmd-down-pane.c @@ -55,7 +55,7 @@ cmd_down_pane_exec(struct cmd *self, struct cmd_ctx *ctx) if (w->active == NULL) w->active = TAILQ_FIRST(&w->panes); layout_refresh(w, 1); - } while (w->active->flags & PANE_HIDDEN); + } while (!window_pane_visible(w->active)); return (0); } diff --git a/cmd-rotate-window.c b/cmd-rotate-window.c index 3f40603a..e730dc59 100644 --- a/cmd-rotate-window.c +++ b/cmd-rotate-window.c @@ -60,7 +60,6 @@ cmd_rotate_window_exec(struct cmd *self, struct cmd_ctx *ctx) struct window *w; struct window_pane *wp, *wp2; u_int sx, sy, xoff, yoff; - int flags; if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) return (-1); @@ -73,18 +72,13 @@ cmd_rotate_window_exec(struct cmd *self, struct cmd_ctx *ctx) xoff = wp->xoff; yoff = wp->yoff; sx = wp->sx; sy = wp->sy; - flags = wp->flags; TAILQ_FOREACH(wp, &w->panes, entry) { if ((wp2 = TAILQ_NEXT(wp, entry)) == NULL) break; wp->xoff = wp2->xoff; wp->yoff = wp2->yoff; - wp->flags &= ~PANE_HIDDEN; - wp->flags |= wp2->flags & PANE_HIDDEN; window_pane_resize(wp, wp2->sx, wp2->sy); } wp->xoff = xoff; wp->yoff = yoff; - wp->flags &= ~PANE_HIDDEN; - wp->flags |= flags & PANE_HIDDEN; window_pane_resize(wp, sx, sy); if ((wp = TAILQ_PREV(w->active, window_panes, entry)) == NULL) @@ -97,18 +91,13 @@ cmd_rotate_window_exec(struct cmd *self, struct cmd_ctx *ctx) xoff = wp->xoff; yoff = wp->yoff; sx = wp->sx; sy = wp->sy; - flags = wp->flags; TAILQ_FOREACH_REVERSE(wp, &w->panes, window_panes, entry) { if ((wp2 = TAILQ_PREV(wp, window_panes, entry)) == NULL) break; wp->xoff = wp2->xoff; wp->yoff = wp2->yoff; - wp->flags &= ~PANE_HIDDEN; - wp->flags |= wp2->flags & PANE_HIDDEN; window_pane_resize(wp, wp2->sx, wp2->sy); } wp->xoff = xoff; wp->yoff = yoff; - wp->flags &= ~PANE_HIDDEN; - wp->flags |= flags & PANE_HIDDEN; window_pane_resize(wp, sx, sy); if ((wp = TAILQ_NEXT(w->active, entry)) == NULL) diff --git a/cmd-select-pane.c b/cmd-select-pane.c index ab3f0b3f..d112f919 100644 --- a/cmd-select-pane.c +++ b/cmd-select-pane.c @@ -58,8 +58,8 @@ cmd_select_pane_exec(struct cmd *self, struct cmd_ctx *ctx) } } - if (wp->flags & PANE_HIDDEN) { - ctx->error(ctx, "pane %d is hidden", data->pane); + if (!window_pane_visible(wp)) { + ctx->error(ctx, "pane %d is not visible", data->pane); return (-1); } window_set_active_pane(wl->window, wp); diff --git a/cmd-swap-pane.c b/cmd-swap-pane.c index 49c8611b..1c3cb508 100644 --- a/cmd-swap-pane.c +++ b/cmd-swap-pane.c @@ -158,7 +158,6 @@ cmd_swap_pane_exec(struct cmd *self, struct cmd_ctx *ctx) struct window *w; struct window_pane *tmp_wp, *src_wp, *dst_wp; u_int xx, yy; - int flags; if (data == NULL) return (0); @@ -210,15 +209,10 @@ cmd_swap_pane_exec(struct cmd *self, struct cmd_ctx *ctx) xx = src_wp->xoff; yy = src_wp->yoff; - flags = src_wp->flags; src_wp->xoff = dst_wp->xoff; src_wp->yoff = dst_wp->yoff; - src_wp->flags &= ~PANE_HIDDEN; - src_wp->flags |= dst_wp->flags & PANE_HIDDEN; dst_wp->xoff = xx; dst_wp->yoff = yy; - dst_wp->flags &= ~PANE_HIDDEN; - dst_wp->flags |= flags & PANE_HIDDEN; xx = src_wp->sx; yy = src_wp->sy; @@ -227,7 +221,7 @@ cmd_swap_pane_exec(struct cmd *self, struct cmd_ctx *ctx) if (!data->flag_detached) { tmp_wp = dst_wp; - if (tmp_wp->flags & PANE_HIDDEN) + if (!window_pane_visible(tmp_wp)) tmp_wp = src_wp; window_set_active_pane(w, tmp_wp); layout_refresh(w, 0); diff --git a/cmd-up-pane.c b/cmd-up-pane.c index ec532370..2f092ece 100644 --- a/cmd-up-pane.c +++ b/cmd-up-pane.c @@ -55,7 +55,7 @@ cmd_up_pane_exec(struct cmd *self, struct cmd_ctx *ctx) if (w->active == NULL) w->active = TAILQ_LAST(&w->panes, window_panes); layout_refresh(w, 1); - } while (w->active->flags & PANE_HIDDEN); + } while (!window_pane_visible(w->active)); return (0); } diff --git a/layout-manual.c b/layout-manual.c index eee21d41..7edce667 100644 --- a/layout-manual.c +++ b/layout-manual.c @@ -26,7 +26,7 @@ void layout_manual_v_refresh(struct window *w, unused int active_only) { struct window_pane *wp; - u_int npanes, canfit, total; + u_int npanes, total, height; int left; if (active_only) @@ -35,34 +35,25 @@ layout_manual_v_refresh(struct window *w, unused int active_only) if (TAILQ_EMPTY(&w->panes)) return; - /* Clear hidden flags. */ - TAILQ_FOREACH(wp, &w->panes, entry) - wp->flags &= ~PANE_HIDDEN; - /* Check the new size. */ npanes = window_count_panes(w); if (w->sy <= PANE_MINIMUM * npanes) { - /* How many can we fit? */ - canfit = w->sy / PANE_MINIMUM; - if (canfit == 0) { - /* None. Just use this size for the first. */ - TAILQ_FOREACH(wp, &w->panes, entry) { - if (wp == TAILQ_FIRST(&w->panes)) - wp->sy = w->sy; - else - wp->flags |= PANE_HIDDEN; - } - } else { - /* >=1, set minimum for them all. */ - TAILQ_FOREACH(wp, &w->panes, entry) { - if (canfit-- > 0) - wp->sy = PANE_MINIMUM - 1; - else - wp->flags |= PANE_HIDDEN; - } - /* And increase the first by the rest. */ - TAILQ_FIRST(&w->panes)->sy += 1 + w->sy % PANE_MINIMUM; + /* + * Make the first pane the smaller of the minimum and total (it + * must fit to be visible) and the rest the minimum size. + */ + height = PANE_MINIMUM; + if (height > w->sy) + height = w->sy + 1; + TAILQ_FOREACH(wp, &w->panes, entry) { + if (wp == TAILQ_FIRST(&w->panes)) + wp->sy = height - 1; + else + wp->sy = PANE_MINIMUM - 1; } + /* And increase the first by the rest if possible. */ + if (w->sy >= PANE_MINIMUM) + TAILQ_FIRST(&w->panes)->sy += 1 + w->sy % PANE_MINIMUM; } else { /* In theory they will all fit. Find the current total. */ total = 0; @@ -174,8 +165,6 @@ layout_manual_v_update_offsets(struct window *w) yoff = 0; TAILQ_FOREACH(wp, &w->panes, entry) { - if (wp->flags & PANE_HIDDEN) - continue; wp->xoff = 0; wp->yoff = yoff; yoff += wp->sy + 1; diff --git a/layout.c b/layout.c index 1ae946e5..66cf7af2 100644 --- a/layout.c +++ b/layout.c @@ -125,14 +125,19 @@ void layout_active_only_refresh(struct window *w, unused int active_only) { struct window_pane *wp; + u_int xoff; + xoff = w->sx; TAILQ_FOREACH(wp, &w->panes, entry) { - if (wp == w->active) { - wp->flags &= ~PANE_HIDDEN; - wp->xoff = wp->yoff = 0; - window_pane_resize(wp, w->sx, w->sy); - } else - wp->flags |= PANE_HIDDEN; + /* Put the active pane on screen and the rest to the right. */ + if (wp == w->active) + wp->xoff = 0; + else { + wp->xoff = xoff; + xoff += w->sx; + } + wp->yoff = 0; + window_pane_resize(wp, w->sx, w->sy); } } @@ -145,6 +150,12 @@ layout_even_h_refresh(struct window *w, int active_only) if (active_only) return; + /* If the screen is too small, show active only. */ + if (w->sx < PANE_MINIMUM || w->sy < PANE_MINIMUM) { + layout_active_only_refresh(w, active_only); + return; + } + /* Get number of panes. */ n = window_count_panes(w); if (n == 0) @@ -153,19 +164,13 @@ layout_even_h_refresh(struct window *w, int active_only) /* How many can we fit? */ if (w->sx / n < PANE_MINIMUM) { width = PANE_MINIMUM; - n = w->sx / PANE_MINIMUM; + n = UINT_MAX; } else width = w->sx / n; /* Fit the panes. */ i = xoff = 0; TAILQ_FOREACH(wp, &w->panes, entry) { - if (i > n) { - wp->flags |= PANE_HIDDEN; - continue; - } - wp->flags &= ~PANE_HIDDEN; - wp->xoff = xoff; wp->yoff = 0; if (i != n - 1) @@ -193,6 +198,12 @@ layout_even_v_refresh(struct window *w, int active_only) if (active_only) return; + /* If the screen is too small, show active only. */ + if (w->sx < PANE_MINIMUM || w->sy < PANE_MINIMUM) { + layout_active_only_refresh(w, active_only); + return; + } + /* Get number of panes. */ n = window_count_panes(w); if (n == 0) @@ -201,19 +212,13 @@ layout_even_v_refresh(struct window *w, int active_only) /* How many can we fit? */ if (w->sy / n < PANE_MINIMUM) { height = PANE_MINIMUM; - n = w->sy / PANE_MINIMUM; + n = UINT_MAX; } else height = w->sy / n; /* Fit the panes. */ i = yoff = 0; TAILQ_FOREACH(wp, &w->panes, entry) { - if (i > n) { - wp->flags |= PANE_HIDDEN; - continue; - } - wp->flags &= ~PANE_HIDDEN; - wp->xoff = 0; wp->yoff = yoff; if (i != n - 1) @@ -250,7 +255,8 @@ layout_main_v_refresh(struct window *w, int active_only) mainwidth = options_get_number(&w->options, "main-pane-width") + 1; /* Need >1 pane and minimum columns; if fewer, display active only. */ - if (n == 1 || w->sx < mainwidth + PANE_MINIMUM) { + if (n == 1 || + w->sx < mainwidth + PANE_MINIMUM || w->sy < PANE_MINIMUM) { layout_active_only_refresh(w, active_only); return; } @@ -270,16 +276,9 @@ layout_main_v_refresh(struct window *w, int active_only) wp->xoff = 0; wp->yoff = 0; window_pane_resize(wp, mainwidth - 1, w->sy); - wp->flags &= ~PANE_HIDDEN; continue; } - if (i > n) { - wp->flags |= PANE_HIDDEN; - continue; - } - wp->flags &= ~PANE_HIDDEN; - wp->xoff = mainwidth; wp->yoff = yoff; if (i != n - 1) @@ -320,7 +319,8 @@ layout_main_h_refresh(struct window *w, int active_only) mainheight = options_get_number(&w->options, "main-pane-height") + 1; /* Need >1 pane and minimum rows; if fewer, display active only. */ - if (n == 1 || w->sy < mainheight + PANE_MINIMUM) { + if (n == 1 || + w->sy < mainheight + PANE_MINIMUM || w->sx < PANE_MINIMUM) { layout_active_only_refresh(w, active_only); return; } @@ -340,16 +340,9 @@ layout_main_h_refresh(struct window *w, int active_only) wp->xoff = 0; wp->yoff = 0; window_pane_resize(wp, w->sx, mainheight - 1); - wp->flags &= ~PANE_HIDDEN; continue; } - if (i > n) { - wp->flags |= PANE_HIDDEN; - continue; - } - wp->flags &= ~PANE_HIDDEN; - wp->xoff = xoff; wp->yoff = mainheight; if (i != n - 1) diff --git a/resize.c b/resize.c index 50e12fb0..1c2377f5 100644 --- a/resize.c +++ b/resize.c @@ -48,6 +48,7 @@ recalculate_sizes(void) struct session *s; struct client *c; struct window *w; + struct window_pane *wp; u_int i, j, ssx, ssy, has, limit; int flag; @@ -132,6 +133,20 @@ recalculate_sizes(void) "window size %u,%u (was %u,%u)", ssx, ssy, w->sx, w->sy); window_resize(w, ssx, ssy); + + /* + * If the current pane is now not visible, move to the next + * that is. + */ + wp = w->active; + while (!window_pane_visible(w->active)) { + w->active = TAILQ_PREV(w->active, window_panes, entry); + if (w->active == NULL) + w->active = TAILQ_LAST(&w->panes, window_panes); + if (w->active == wp) + break; + } + server_redraw_window(w); layout_refresh(w, 0); } diff --git a/screen-redraw.c b/screen-redraw.c index b95a5928..952cb37a 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -35,6 +35,9 @@ screen_redraw_check_cell(struct client *c, u_int px, u_int py) return (0); TAILQ_FOREACH(wp, &w->panes, entry) { + if (!window_pane_visible(wp)) + continue; + /* Inside pane. */ if (px >= wp->xoff && px < wp->xoff + wp->sx && py >= wp->yoff && py < wp->yoff + wp->sy) @@ -104,7 +107,7 @@ screen_redraw_screen(struct client *c) /* Draw the panes. */ TAILQ_FOREACH(wp, &w->panes, entry) { - if (wp->flags & PANE_HIDDEN) + if (!window_pane_visible(wp)) continue; tty_reset(tty); diff --git a/tmux.h b/tmux.h index bd4cbf9a..d895d640 100644 --- a/tmux.h +++ b/tmux.h @@ -48,7 +48,7 @@ extern const char *__progname; #define PROMPT_HISTORY 100 /* Minimum pane size. */ -#define PANE_MINIMUM 4 /* includes separator line */ +#define PANE_MINIMUM 5 /* includes separator line */ /* Automatic name refresh interval, in milliseconds. */ #define NAME_INTERVAL 500 @@ -600,8 +600,7 @@ struct window_pane { u_int yoff; int flags; -#define PANE_HIDDEN 0x1 -#define PANE_REDRAW 0x2 +#define PANE_REDRAW 0x1 char *cmd; char *cwd; @@ -1454,6 +1453,7 @@ void window_pane_parse(struct window_pane *); void window_pane_key(struct window_pane *, struct client *, int); void window_pane_mouse(struct window_pane *, struct client *, u_char, u_char, u_char); +int window_pane_visible(struct window_pane *); char *window_pane_search( struct window_pane *, const char *, u_int *); diff --git a/tty-write.c b/tty-write.c index 889075b2..87e6c383 100644 --- a/tty-write.c +++ b/tty-write.c @@ -44,7 +44,7 @@ tty_vwrite_cmd(struct window_pane *wp, enum tty_cmd cmd, va_list ap) if (wp->window->flags & WINDOW_REDRAW || wp->flags & PANE_REDRAW) return; - if (wp->window->flags & WINDOW_HIDDEN || wp->flags & PANE_HIDDEN) + if (wp->window->flags & WINDOW_HIDDEN || !window_pane_visible(wp)) return; for (i = 0; i < ARRAY_LENGTH(&clients); i++) { diff --git a/window.c b/window.c index 753f796a..3dfe89ec 100644 --- a/window.c +++ b/window.c @@ -291,8 +291,14 @@ void window_set_active_pane(struct window *w, struct window_pane *wp) { w->active = wp; - while (w->active->flags & PANE_HIDDEN) + + while (!window_pane_visible(w->active)) { w->active = TAILQ_PREV(w->active, window_panes, entry); + if (w->active == NULL) + w->active = TAILQ_LAST(&w->panes, window_panes); + if (w->active == wp) + return; + } } struct window_pane * @@ -607,6 +613,18 @@ window_pane_mouse( input_mouse(wp, b, x, y); } +int +window_pane_visible(struct window_pane *wp) +{ + struct window *w = wp->window; + + if (wp->xoff >= w->sx || wp->yoff >= w->sy) + return (0); + if (wp->xoff + wp->sx > w->sx || wp->yoff + wp->sy > w->sy) + return (0); + return (1); +} + char * window_pane_search(struct window_pane *wp, const char *searchstr, u_int *lineno) { From 975f516f516600cf373a1e9642734ccbc7f68197 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 14 Jul 2009 14:47:32 +0000 Subject: [PATCH 0119/1180] The scroll region cannot be one line only, ignore attempts to make it so. --- screen-write.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/screen-write.c b/screen-write.c index 5a2a3882..59b8b027 100644 --- a/screen-write.c +++ b/screen-write.c @@ -553,7 +553,7 @@ screen_write_scrollregion( rupper = screen_size_y(s) - 1; if (rlower > screen_size_y(s) - 1) rlower = screen_size_y(s) - 1; - if (rupper > rlower) + if (rupper >= rlower) /* cannot be one line */ return; /* Cursor moves to top-left. */ From e76caa0017795c3ec4ad9406b55f4937bf7ccae0 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 14 Jul 2009 16:52:50 +0000 Subject: [PATCH 0120/1180] Don't accept input to a window if it not visible. --- window.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/window.c b/window.c index 3dfe89ec..46a713df 100644 --- a/window.c +++ b/window.c @@ -580,7 +580,7 @@ window_pane_parse(struct window_pane *wp) void window_pane_key(struct window_pane *wp, struct client *c, int key) { - if (wp->fd == -1) + if (wp->fd == -1 || !window_pane_visible(wp)) return; if (wp->mode != NULL) { @@ -594,7 +594,7 @@ void window_pane_mouse( struct window_pane *wp, struct client *c, u_char b, u_char x, u_char y) { - if (wp->fd == -1) + if (wp->fd == -1 || !window_pane_visible(wp)) return; /* XXX convert from 1-based? */ From ae2ea525752c9eb1be9e9d7b3fa71b390a70f2ec Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 14 Jul 2009 19:03:16 +0000 Subject: [PATCH 0121/1180] Instead of faking up a status line in status_redraw, use the same code to redraw it as to draw the entire screen, just skip all lines but the last. This makes horizontal split redraw properly when the status line is off. --- screen-redraw.c | 54 ++++++++++++++++++++++++++++++++----------------- server.c | 6 +++--- status.c | 47 +++++++++++++----------------------------- tmux.h | 3 +-- 4 files changed, 53 insertions(+), 57 deletions(-) diff --git a/screen-redraw.c b/screen-redraw.c index 952cb37a..70f94a28 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -63,9 +63,9 @@ screen_redraw_check_cell(struct client *c, u_int px, u_int py) return (0); } -/* Redraw entire screen.. */ +/* Redraw entire screen. */ void -screen_redraw_screen(struct client *c) +screen_redraw_screen(struct client *c, int status_only) { struct window *w = c->session->curw->window; struct tty *tty = &c->tty; @@ -75,7 +75,16 @@ screen_redraw_screen(struct client *c) u_char choriz, cvert, cbackg; /* Get status line, er, status. */ - status = options_get_number(&c->session->options, "status"); + if (c->message_string != NULL || c->prompt_string != NULL) + status = 1; + else + status = options_get_number(&c->session->options, "status"); + + /* If only drawing status and it is present, don't need the rest. */ + if (status_only && status) { + tty_draw_line(tty, &c->status, 0, 0, tty->sy - 1); + return; + } /* Work out ACS characters. */ if (tty_term_has(tty->term, TTYC_ACSC)) { @@ -95,6 +104,8 @@ screen_redraw_screen(struct client *c) if (has_acs) tty_putcode(tty, TTYC_SMACS); for (j = 0; j < tty->sy - status; j++) { + if (status_only && j != tty->sy - 1) + continue; for (i = 0; i < tty->sx; i++) { if (!screen_redraw_check_cell(c, i, j)) { tty_cursor(tty, i, j, 0, 0); @@ -120,12 +131,16 @@ screen_redraw_screen(struct client *c) tty_putcode(tty, TTYC_SMACS); if (wp->xoff > 0) { for (i = wp->yoff; i < wp->yoff + sy; i++) { + if (status_only && i != tty->sy - 1) + continue; tty_cursor(tty, wp->xoff - 1, i, 0, 0); tty_putc(tty, cvert); } } if (wp->xoff + sx < tty->sx) { for (i = wp->yoff; i < wp->yoff + sy; i++) { + if (status_only && i != tty->sy - 1) + continue; tty_cursor(tty, wp->xoff + sx, i, 0, 0); tty_putc(&c->tty, cvert); } @@ -133,24 +148,33 @@ screen_redraw_screen(struct client *c) /* Draw top and bottom borders. */ if (wp->yoff > 0) { - tty_cursor(tty, wp->xoff, wp->yoff - 1, 0, 0); - for (i = 0; i < sx; i++) - tty_putc(tty, choriz); + if (!status_only || wp->yoff - 1 == tty->sy - 1) { + tty_cursor(tty, wp->xoff, wp->yoff - 1, 0, 0); + for (i = 0; i < sx; i++) + tty_putc(tty, choriz); + } } if (wp->yoff + sy < tty->sy - status) { - tty_cursor(tty, wp->xoff, wp->yoff + sy, 0, 0); - for (i = 0; i < sx; i++) - tty_putc(tty, choriz); + if (!status_only || wp->yoff + sy == tty->sy - 1) { + tty_cursor(tty, wp->xoff, wp->yoff + sy, 0, 0); + for (i = 0; i < sx; i++) + tty_putc(tty, choriz); + } } if (has_acs) tty_putcode(tty, TTYC_RMACS); /* Draw the pane. */ - screen_redraw_pane(c, wp); + for (i = 0; i < wp->sy; i++) { + if (status_only && i != tty->sy - 1) + continue; + tty_draw_line(tty, wp->screen, i, wp->xoff, wp->yoff); + } } /* Draw the status line. */ - screen_redraw_status(c); + if (status) + tty_draw_line(tty, &c->status, 0, 0, tty->sy - 1); } /* Draw a single pane. */ @@ -162,11 +186,3 @@ screen_redraw_pane(struct client *c, struct window_pane *wp) for (i = 0; i < wp->sy; i++) tty_draw_line(&c->tty, wp->screen, i, wp->xoff, wp->yoff); } - - -/* Draw the status line. */ -void -screen_redraw_status(struct client *c) -{ - tty_draw_line(&c->tty, &c->status, 0, 0, c->tty.sy - 1); -} diff --git a/server.c b/server.c index 71b619ae..ec1b1924 100644 --- a/server.c +++ b/server.c @@ -557,7 +557,7 @@ server_check_redraw(struct client *c) if (server_locked) server_redraw_locked(c); else - screen_redraw_screen(c); + screen_redraw_screen(c, 0); c->flags &= ~CLIENT_STATUS; } else { TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry) { @@ -567,7 +567,7 @@ server_check_redraw(struct client *c) } if (c->flags & CLIENT_STATUS) - screen_redraw_status(c); + screen_redraw_screen(c, 1); c->tty.flags |= flags; @@ -598,7 +598,7 @@ server_redraw_locked(struct client *c) for (i = 0; i < screen_size_y(&screen); i++) tty_draw_line(&c->tty, &screen, i, 0, 0); - screen_redraw_status(c); + screen_redraw_screen(c, 1); screen_free(&screen); } diff --git a/status.c b/status.c index 6841468f..e2ffa0a7 100644 --- a/status.c +++ b/status.c @@ -44,24 +44,27 @@ status_redraw(struct client *c) struct screen_write_ctx ctx; struct session *s = c->session; struct winlink *wl; - struct window_pane *wp; - struct screen *sc = NULL, old_status; + struct screen old_status; char *left, *right, *text, *ptr; size_t llen, llen2, rlen, rlen2, offset; - size_t xx, yy, sy, size, start, width; + size_t xx, yy, size, start, width; struct grid_cell stdgc, gc; int larrow, rarrow, utf8flag; left = right = NULL; + /* No status line?*/ + if (c->tty.sy == 0 || !options_get_number(&s->options, "status")) + return (1); + larrow = rarrow = 0; + /* Create the target screen. */ memcpy(&old_status, &c->status, sizeof old_status); screen_init(&c->status, c->tty.sx, 1, 0); - /* No status line? */ - if (c->tty.sy == 0 || !options_get_number(&s->options, "status")) - goto off; - larrow = rarrow = 0; + /* Create the target screen. */ + memcpy(&old_status, &c->status, sizeof old_status); + screen_init(&c->status, c->tty.sx, 1, 0); if (gettimeofday(&c->status_timer, NULL) != 0) fatal("gettimeofday"); @@ -259,32 +262,6 @@ blank: for (offset = 0; offset < c->tty.sx; offset++) screen_write_putc(&ctx, &stdgc, ' '); - goto out; - -off: - /* - * Draw the real window last line. Necessary to wipe over message if - * status is off. Not sure this is the right place for this. - */ - memcpy(&stdgc, &grid_default_cell, sizeof stdgc); - screen_write_start(&ctx, NULL, &c->status); - - sy = 0; - TAILQ_FOREACH(wp, &s->curw->window->panes, entry) { - sy += wp->sy + 1; - sc = wp->screen; - } - - screen_write_cursormove(&ctx, 0, 0); - if (sy < c->tty.sy) { - /* If the screen is too small, use blank. */ - for (offset = 0; offset < c->tty.sx; offset++) - screen_write_putc(&ctx, &stdgc, ' '); - } else { - screen_write_copy(&ctx, - sc, 0, sc->grid->hsize + screen_size_y(sc) - 1, c->tty.sx, 1); - } - out: screen_write_stop(&ctx); @@ -518,6 +495,8 @@ status_message_clear(struct client *c) c->tty.flags &= ~(TTY_NOCURSOR|TTY_FREEZE); c->flags |= CLIENT_REDRAW; + + screen_reinit(&c->status); } /* Draw client message on status line of present else on last line. */ @@ -603,6 +582,8 @@ status_prompt_clear(struct client *c) c->tty.flags &= ~(TTY_NOCURSOR|TTY_FREEZE); c->flags |= CLIENT_REDRAW; + + screen_reinit(&c->status); } /* Draw client prompt on status line of present else on last line. */ diff --git a/tmux.h b/tmux.h index d895d640..2b26b699 100644 --- a/tmux.h +++ b/tmux.h @@ -1395,9 +1395,8 @@ void screen_write_cell( struct screen_write_ctx *, const struct grid_cell *, u_char *); /* screen-redraw.c */ -void screen_redraw_screen(struct client *); +void screen_redraw_screen(struct client *, int); void screen_redraw_pane(struct client *, struct window_pane *); -void screen_redraw_status(struct client *); /* screen.c */ void screen_init(struct screen *, u_int, u_int, u_int); From f08c9b2217c148e25a18a11fd55d96d93cbb3736 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 14 Jul 2009 19:11:58 +0000 Subject: [PATCH 0122/1180] For some reason when clearing status/message it was redrawing the entire client not just the status line. Changing this also revealed the check for the status line was incorrect when drawing the pane. --- screen-redraw.c | 2 +- status.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/screen-redraw.c b/screen-redraw.c index 70f94a28..e63f8725 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -166,7 +166,7 @@ screen_redraw_screen(struct client *c, int status_only) /* Draw the pane. */ for (i = 0; i < wp->sy; i++) { - if (status_only && i != tty->sy - 1) + if (status_only && wp->yoff + i != tty->sy - 1) continue; tty_draw_line(tty, wp->screen, i, wp->xoff, wp->yoff); } diff --git a/status.c b/status.c index e2ffa0a7..60d7799c 100644 --- a/status.c +++ b/status.c @@ -494,7 +494,7 @@ status_message_clear(struct client *c) c->message_string = NULL; c->tty.flags &= ~(TTY_NOCURSOR|TTY_FREEZE); - c->flags |= CLIENT_REDRAW; + c->flags |= CLIENT_STATUS; screen_reinit(&c->status); } @@ -581,7 +581,7 @@ status_prompt_clear(struct client *c) c->prompt_buffer = NULL; c->tty.flags &= ~(TTY_NOCURSOR|TTY_FREEZE); - c->flags |= CLIENT_REDRAW; + c->flags |= CLIENT_STATUS; screen_reinit(&c->status); } From 615d85fb23e8eea75d3c630eccc21e98dd8a8ec7 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 14 Jul 2009 20:20:04 +0000 Subject: [PATCH 0123/1180] Add main-pane-height to the options list (was missed before). --- cmd-set-window-option.c | 1 + tmux.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/cmd-set-window-option.c b/cmd-set-window-option.c index 5f24af72..46e94732 100644 --- a/cmd-set-window-option.c +++ b/cmd-set-window-option.c @@ -56,6 +56,7 @@ const struct set_option_entry set_window_option_table[NSETWINDOWOPTION] = { SET_OPTION_CHOICE, 0, 0, set_option_clock_mode_style_list }, { "force-height", SET_OPTION_NUMBER, 0, INT_MAX, NULL }, { "force-width", SET_OPTION_NUMBER, 0, INT_MAX, NULL }, + { "main-pane-height", SET_OPTION_NUMBER, 1, INT_MAX, NULL }, { "main-pane-width", SET_OPTION_NUMBER, 1, INT_MAX, NULL }, { "mode-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL }, { "mode-bg", SET_OPTION_COLOUR, 0, 0, NULL }, diff --git a/tmux.h b/tmux.h index 2b26b699..680a4ee1 100644 --- a/tmux.h +++ b/tmux.h @@ -942,7 +942,7 @@ struct set_option_entry { extern const struct set_option_entry set_option_table[]; extern const struct set_option_entry set_window_option_table[]; #define NSETOPTION 26 -#define NSETWINDOWOPTION 19 +#define NSETWINDOWOPTION 20 /* tmux.c */ extern volatile sig_atomic_t sigwinch; From ca617d679ff296a4abe0e7526d8e8cab4f87e338 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 15 Jul 2009 07:50:34 +0000 Subject: [PATCH 0124/1180] Having to update NSETOPTION/NSETWINDOWOPTION when adding new options is a bit annoying and it is only use for iterating, so use a sentinel to mark the end of each array instead. Different fix for a problem pointed out by Kalle Olavi Niemitalo. --- cmd-set-option.c | 12 ++++++------ cmd-set-window-option.c | 12 ++++++------ cmd-show-options.c | 5 +---- cmd-show-window-options.c | 5 +---- status.c | 8 +++----- tmux.h | 2 -- 6 files changed, 17 insertions(+), 27 deletions(-) diff --git a/cmd-set-option.c b/cmd-set-option.c index 77972e92..c9b1fd99 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -48,7 +48,7 @@ const char *set_option_status_keys_list[] = { const char *set_option_bell_action_list[] = { "none", "any", "current", NULL }; -const struct set_option_entry set_option_table[NSETOPTION] = { +const struct set_option_entry set_option_table[] = { { "bell-action", SET_OPTION_CHOICE, 0, 0, set_option_bell_action_list }, { "buffer-limit", SET_OPTION_NUMBER, 1, INT_MAX, NULL }, { "default-command", SET_OPTION_STRING, 0, 0, NULL }, @@ -75,6 +75,7 @@ const struct set_option_entry set_option_table[NSETOPTION] = { { "status-right", SET_OPTION_STRING, 0, 0, NULL }, { "status-right-length", SET_OPTION_NUMBER, 0, SHRT_MAX, NULL }, { "status-utf8", SET_OPTION_FLAG, 0, 0, NULL }, + { NULL, 0, 0, 0, NULL } }; int @@ -84,7 +85,7 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) struct session *s; struct client *c; struct options *oo; - const struct set_option_entry *entry; + const struct set_option_entry *entry, *opt; u_int i; if (data->chflags & CMD_CHFLAG('g')) @@ -101,15 +102,14 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) } entry = NULL; - for (i = 0; i < NSETOPTION; i++) { - if (strncmp(set_option_table[i].name, - data->option, strlen(data->option)) != 0) + for (opt = set_option_table; opt->name != NULL; opt++) { + if (strncmp(opt->name, data->option, strlen(data->option)) != 0) continue; if (entry != NULL) { ctx->error(ctx, "ambiguous option: %s", data->option); return (-1); } - entry = &set_option_table[i]; + entry = opt; /* Bail now if an exact match. */ if (strcmp(entry->name, data->option) == 0) diff --git a/cmd-set-window-option.c b/cmd-set-window-option.c index 46e94732..9499b46a 100644 --- a/cmd-set-window-option.c +++ b/cmd-set-window-option.c @@ -48,7 +48,7 @@ const char *set_option_mode_keys_list[] = { const char *set_option_clock_mode_style_list[] = { "12", "24", NULL }; -const struct set_option_entry set_window_option_table[NSETWINDOWOPTION] = { +const struct set_option_entry set_window_option_table[] = { { "aggressive-resize", SET_OPTION_FLAG, 0, 0, NULL }, { "automatic-rename", SET_OPTION_FLAG, 0, 0, NULL }, { "clock-mode-colour", SET_OPTION_COLOUR, 0, 0, NULL }, @@ -70,6 +70,7 @@ const struct set_option_entry set_window_option_table[NSETWINDOWOPTION] = { { "window-status-bg", SET_OPTION_COLOUR, 0, 0, NULL }, { "window-status-fg", SET_OPTION_COLOUR, 0, 0, NULL }, { "xterm-keys", SET_OPTION_FLAG, 0, 0, NULL }, + { NULL, 0, 0, 0, NULL } }; int @@ -79,7 +80,7 @@ cmd_set_window_option_exec(struct cmd *self, struct cmd_ctx *ctx) struct winlink *wl; struct client *c; struct options *oo; - const struct set_option_entry *entry; + const struct set_option_entry *entry, *opt; u_int i; if (data->chflags & CMD_CHFLAG('g')) @@ -96,15 +97,14 @@ cmd_set_window_option_exec(struct cmd *self, struct cmd_ctx *ctx) } entry = NULL; - for (i = 0; i < NSETWINDOWOPTION; i++) { - if (strncmp(set_window_option_table[i].name, - data->option, strlen(data->option)) != 0) + for (opt = set_window_option_table; opt->name != NULL; opt++) { + if (strncmp(opt->name, data->option, strlen(data->option)) != 0) continue; if (entry != NULL) { ctx->error(ctx, "ambiguous option: %s", data->option); return (-1); } - entry = &set_window_option_table[i]; + entry = opt; /* Bail now if an exact match. */ if (strcmp(entry->name, data->option) == 0) diff --git a/cmd-show-options.c b/cmd-show-options.c index e5f50859..dab08917 100644 --- a/cmd-show-options.c +++ b/cmd-show-options.c @@ -49,7 +49,6 @@ cmd_show_options_exec(struct cmd *self, struct cmd_ctx *ctx) struct session *s; struct options *oo; const struct set_option_entry *entry; - u_int i; char *vs; long long vn; @@ -61,9 +60,7 @@ cmd_show_options_exec(struct cmd *self, struct cmd_ctx *ctx) oo = &s->options; } - for (i = 0; i < NSETOPTION; i++) { - entry = &set_option_table[i]; - + for (entry = set_option_table; entry->name != NULL; entry++) { if (options_find1(oo, entry->name) == NULL) continue; diff --git a/cmd-show-window-options.c b/cmd-show-window-options.c index 9fd35177..4365b098 100644 --- a/cmd-show-window-options.c +++ b/cmd-show-window-options.c @@ -49,7 +49,6 @@ cmd_show_window_options_exec(struct cmd *self, struct cmd_ctx *ctx) struct winlink *wl; struct options *oo; const struct set_option_entry *entry; - u_int i; char *vs; long long vn; @@ -61,9 +60,7 @@ cmd_show_window_options_exec(struct cmd *self, struct cmd_ctx *ctx) oo = &wl->window->options; } - for (i = 0; i < NSETWINDOWOPTION; i++) { - entry = &set_window_option_table[i]; - + for (entry = set_window_option_table; entry->name != NULL; entry++) { if (options_find1(oo, entry->name) == NULL) continue; diff --git a/status.c b/status.c index 60d7799c..89a83cba 100644 --- a/status.c +++ b/status.c @@ -898,7 +898,7 @@ status_prompt_complete(const char *s) const struct set_option_entry *optent; ARRAY_DECL(, const char *) list; char *prefix, *s2; - u_int i; + u_int i; size_t j; if (*s == '\0') @@ -910,13 +910,11 @@ status_prompt_complete(const char *s) if (strncmp((*cmdent)->name, s, strlen(s)) == 0) ARRAY_ADD(&list, (*cmdent)->name); } - for (i = 0; i < NSETOPTION; i++) { - optent = &set_option_table[i]; + for (optent = set_option_table; optent->name != NULL; optent++) { if (strncmp(optent->name, s, strlen(s)) == 0) ARRAY_ADD(&list, optent->name); } - for (i = 0; i < NSETWINDOWOPTION; i++) { - optent = &set_window_option_table[i]; + for (optent = set_window_option_table; optent->name != NULL; optent++) { if (strncmp(optent->name, s, strlen(s)) == 0) ARRAY_ADD(&list, optent->name); } diff --git a/tmux.h b/tmux.h index 680a4ee1..533a8797 100644 --- a/tmux.h +++ b/tmux.h @@ -941,8 +941,6 @@ struct set_option_entry { }; extern const struct set_option_entry set_option_table[]; extern const struct set_option_entry set_window_option_table[]; -#define NSETOPTION 26 -#define NSETWINDOWOPTION 20 /* tmux.c */ extern volatile sig_atomic_t sigwinch; From 9601b72e4ced58d08f4c1351865746b46ab5895e Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 15 Jul 2009 08:00:49 +0000 Subject: [PATCH 0125/1180] The man page says that kill-window removes the window entirely, unlinking it from any sessions. In fact the implementation only affected the current session, making it the same as unlink-window but destroying the window if it was linked into only one session (unlinkw gives an error). Change the behaviour to match what it documented and was originally intended. --- cmd-kill-window.c | 33 ++++++++++++++++++++++----------- window.c | 13 +++++++++++++ 2 files changed, 35 insertions(+), 11 deletions(-) diff --git a/cmd-kill-window.c b/cmd-kill-window.c index ca9ee1fa..77b9b79d 100644 --- a/cmd-kill-window.c +++ b/cmd-kill-window.c @@ -44,24 +44,35 @@ cmd_kill_window_exec(struct cmd *self, struct cmd_ctx *ctx) { struct cmd_target_data *data = self->data; struct winlink *wl; + struct window *w; struct session *s; struct client *c; - u_int i; + u_int i, j; int destroyed; - if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL) + if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) return (-1); + w = wl->window; - destroyed = session_detach(s, wl); - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - c = ARRAY_ITEM(&clients, i); - if (c == NULL || c->session != s) + for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { + s = ARRAY_ITEM(&sessions, i); + if (s == NULL || !session_has(s, w)) continue; - if (destroyed) { - c->session = NULL; - server_write_client(c, MSG_EXIT, NULL, 0); - } else - server_redraw_client(c); + if ((wl = winlink_find_by_window(&s->windows, w)) == NULL) + continue; + + destroyed = session_detach(s, wl); + for (j = 0; j < ARRAY_LENGTH(&clients); j++) { + c = ARRAY_ITEM(&clients, j); + if (c == NULL || c->session != s) + continue; + + if (destroyed) { + c->session = NULL; + server_write_client(c, MSG_EXIT, NULL, 0); + } else + server_redraw_client(c); + } } recalculate_sizes(); diff --git a/window.c b/window.c index 46a713df..7823d2f5 100644 --- a/window.c +++ b/window.c @@ -81,6 +81,19 @@ winlink_cmp(struct winlink *wl1, struct winlink *wl2) return (wl1->idx - wl2->idx); } +struct winlink * +winlink_find_by_window(struct winlinks *wwl, struct window *w) +{ + struct winlink *wl; + + RB_FOREACH(wl, winlinks, wwl) { + if (wl->window == w) + return (wl); + } + + return (NULL); +} + struct winlink * winlink_find_by_index(struct winlinks *wwl, int idx) { From aa3403a3432532984b7057c0f0a34d0c71133c1c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 15 Jul 2009 08:05:56 +0000 Subject: [PATCH 0126/1180] Add a -k flag to unlink-window which makes it behave the same as the old kill-window - if a window is linked into only one session it unlinked and destroyed. --- cmd-unlink-window.c | 6 +++--- tmux.1 | 11 +++++++++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/cmd-unlink-window.c b/cmd-unlink-window.c index 1befabd9..2ef1ca04 100644 --- a/cmd-unlink-window.c +++ b/cmd-unlink-window.c @@ -28,8 +28,8 @@ int cmd_unlink_window_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_unlink_window_entry = { "unlink-window", "unlinkw", - CMD_TARGET_WINDOW_USAGE, - 0, 0, + "[-k] " CMD_TARGET_WINDOW_USAGE, + 0, CMD_CHFLAG('k'), cmd_target_init, cmd_target_parse, cmd_unlink_window_exec, @@ -52,7 +52,7 @@ cmd_unlink_window_exec(struct cmd *self, struct cmd_ctx *ctx) if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL) return (-1); - if (wl->window->references == 1) { + if (!(data->chflags & CMD_CHFLAG('k')) && wl->window->references == 1) { ctx->error(ctx, "window is only linked to one session"); return (-1); } diff --git a/tmux.1 b/tmux.1 index 172e0e4d..fb5d0cc0 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1555,13 +1555,20 @@ to Unbind the key bound to .Ar key . .It Xo Ic unlink-window +.Op Fl k .Op Fl t Ar target-window .Xc .D1 (alias: Ic unlinkw ) Unlink .Ar target-window . -A window may be unlinked only if it is linked to multiple sessions - windows may -not be linked to no sessions. +Unless +.Fl k +is given, a window may be unlinked only if it is linked to multiple sessions - +windows may not be linked to no sessions; +if +.Fl k +is specified and the window is linked to only one session, it is unlinked and +destroyed. .It Xo Ic up-pane .Op Fl p Ar pane-index .Op Fl t Ar target-window From 780fd8f7a6fde6f14016f3c4f94f04d8118859c1 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 15 Jul 2009 15:09:17 +0000 Subject: [PATCH 0127/1180] Return -1 not NULL on error, pointed out by Roy Marples. --- cmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd.c b/cmd.c index a2264081..f2466216 100644 --- a/cmd.c +++ b/cmd.c @@ -642,7 +642,7 @@ cmd_find_index(struct cmd_ctx *ctx, const char *arg, struct session **sp) */ if ((s = cmd_current_session(ctx)) == NULL) { ctx->error(ctx, "can't establish current session"); - return (NULL); + return (-1); } /* A NULL argument means the current session and "no window" (-1). */ From 92da443a9e02a2238d4415e0dcf3796d3929b290 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 15 Jul 2009 17:39:00 +0000 Subject: [PATCH 0128/1180] Make status_message_set a variadic printf-like function. No functional change - helpful for a couple of things coming soon. --- cmd-command-prompt.c | 2 +- cmd-confirm-before.c | 2 +- cmd-select-prompt.c | 4 ++-- key-bindings.c | 4 ++-- status.c | 9 ++++++--- tmux.h | 2 +- 6 files changed, 13 insertions(+), 10 deletions(-) diff --git a/cmd-command-prompt.c b/cmd-command-prompt.c index 841dfd78..e4660e99 100644 --- a/cmd-command-prompt.c +++ b/cmd-command-prompt.c @@ -150,7 +150,7 @@ cmd_command_prompt_callback(void *data, const char *s) if (cause == NULL) return (0); *cause = toupper((u_char) *cause); - status_message_set(c, cause); + status_message_set(c, "%s", cause); xfree(cause); cmdlist = NULL; } diff --git a/cmd-confirm-before.c b/cmd-confirm-before.c index 0819e3e9..2dbd72ce 100644 --- a/cmd-confirm-before.c +++ b/cmd-confirm-before.c @@ -113,7 +113,7 @@ cmd_confirm_before_callback(void *data, const char *s) if (cmd_string_parse(cdata->cmd, &cmdlist, &cause) != 0) { if (cause != NULL) { *cause = toupper((u_char) *cause); - status_message_set(c, cause); + status_message_set(c, "%s", cause); xfree(cause); } goto out; diff --git a/cmd-select-prompt.c b/cmd-select-prompt.c index 5221fa1e..8b707342 100644 --- a/cmd-select-prompt.c +++ b/cmd-select-prompt.c @@ -74,14 +74,14 @@ cmd_select_prompt_callback(void *data, const char *s) idx = strtonum(s, 0, UINT_MAX, &errstr); if (errstr != NULL) { xsnprintf(msg, sizeof msg, "Index %s: %s", errstr, s); - status_message_set(c, msg); + status_message_set(c, "%s", msg); return (0); } if (winlink_find_by_index(&c->session->windows, idx) == NULL) { xsnprintf(msg, sizeof msg, "Window not found: %s:%d", c->session->name, idx); - status_message_set(c, msg); + status_message_set(c, "%s", msg); return (0); } diff --git a/key-bindings.c b/key-bindings.c index 438836f3..6fb3b89d 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -194,7 +194,7 @@ key_bindings_error(struct cmd_ctx *ctx, const char *fmt, ...) va_end(ap); *msg = toupper((u_char) *msg); - status_message_set(ctx->curclient, msg); + status_message_set(ctx->curclient, "%s", msg); xfree(msg); } @@ -227,7 +227,7 @@ key_bindings_info(struct cmd_ctx *ctx, const char *fmt, ...) va_end(ap); *msg = toupper((u_char) *msg); - status_message_set(ctx->curclient, msg); + status_message_set(ctx->curclient, "%s", msg); xfree(msg); } diff --git a/status.c b/status.c index 89a83cba..67d0274d 100644 --- a/status.c +++ b/status.c @@ -465,17 +465,20 @@ status_print(struct session *s, struct winlink *wl, struct grid_cell *gc) return (text); } -void -status_message_set(struct client *c, const char *msg) +void printflike2 +status_message_set(struct client *c, const char *fmt, ...) { struct timeval tv; + va_list ap; int delay; delay = options_get_number(&c->session->options, "display-time"); tv.tv_sec = delay / 1000; tv.tv_usec = (delay % 1000) * 1000L; - c->message_string = xstrdup(msg); + va_start(ap, fmt); + xvasprintf(&c->message_string, fmt, ap); + va_end(ap); if (gettimeofday(&c->message_timer, NULL) != 0) fatal("gettimeofday"); timeradd(&c->message_timer, &tv, &c->message_timer); diff --git a/tmux.h b/tmux.h index 533a8797..53688eed 100644 --- a/tmux.h +++ b/tmux.h @@ -1275,7 +1275,7 @@ int server_unlock(const char *); /* status.c */ int status_redraw(struct client *); -void status_message_set(struct client *, const char *); +void printflike2 status_message_set(struct client *, const char *, ...); void status_message_clear(struct client *); int status_message_redraw(struct client *); void status_prompt_set(struct client *, From 924bf8477fc30af5ed241e7f7536eb133ab9b702 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 16 Jul 2009 07:34:37 +0000 Subject: [PATCH 0129/1180] Typo in grid_duplicate_lines (sy for dy) causing it to write into the wrong place when copying UTF-8 data. Found by Dan Colish. --- grid.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grid.c b/grid.c index 38560f73..0fbdbd0a 100644 --- a/grid.c +++ b/grid.c @@ -554,7 +554,7 @@ grid_duplicate_lines( if (src->usize[sy] == 0) dst->udata[dy] = NULL; else { - dst->udata[sy] = xcalloc( + dst->udata[dy] = xcalloc( src->usize[sy], sizeof **dst->udata); memcpy(dst->udata[dy], src->udata[sy], src->usize[sy] * (sizeof **dst->udata)); From 3e9d9a2119dbfccc7a1a45158008283e874a5c96 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 16 Jul 2009 22:50:49 +0000 Subject: [PATCH 0130/1180] Fix arguments to switch-client. --- tmux.1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tmux.1 b/tmux.1 index fb5d0cc0..a025cbbc 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1541,7 +1541,8 @@ except the source and destination windows are swapped. It is an error if no window exists at .Ar src-window . .It Xo Ic switch-client -.Op Fl c Ar target-client Fl t Ar target-session +.Op Fl c Ar target-client +.Op Fl t Ar target-session .Xc .D1 (alias: Ic switchc ) Switch the current session for client From 9642f0373f94d6015e66806c95ba1570c7bb06ea Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 16 Jul 2009 23:25:21 +0000 Subject: [PATCH 0131/1180] Remove some duplicate code that was causing the status line to be redrawn even when it hadn't changed. --- status.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/status.c b/status.c index 67d0274d..49215adf 100644 --- a/status.c +++ b/status.c @@ -62,10 +62,6 @@ status_redraw(struct client *c) memcpy(&old_status, &c->status, sizeof old_status); screen_init(&c->status, c->tty.sx, 1, 0); - /* Create the target screen. */ - memcpy(&old_status, &c->status, sizeof old_status); - screen_init(&c->status, c->tty.sx, 1, 0); - if (gettimeofday(&c->status_timer, NULL) != 0) fatal("gettimeofday"); memcpy(&stdgc, &grid_default_cell, sizeof gc); From 65deba3a350f760dacdb170fbecfa07edf4e4711 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 17 Jul 2009 06:13:27 +0000 Subject: [PATCH 0132/1180] Memory could be leaked if a second prompt or message appeared while another was still present, so add a separate prompt free callback and make the _clear function responsible for calling it if necessary (rather than the individual prompt callbacks). Also make both messages and prompts clear any existing when a new is set. In addition, the screen could be modified while the prompt is there, restore the redraw-entire-screen behaviour on prompt clear; add a comment as a reminder. --- cmd-command-prompt.c | 22 +++++++++++++++------- cmd-confirm-before.c | 31 +++++++++++++++++++------------ cmd-select-prompt.c | 2 +- server-fn.c | 4 ++-- status.c | 29 ++++++++++++++++++++--------- tmux.h | 7 ++++--- 6 files changed, 61 insertions(+), 34 deletions(-) diff --git a/cmd-command-prompt.c b/cmd-command-prompt.c index e4660e99..196376b1 100644 --- a/cmd-command-prompt.c +++ b/cmd-command-prompt.c @@ -31,6 +31,7 @@ void cmd_command_prompt_init(struct cmd *, int); int cmd_command_prompt_exec(struct cmd *, struct cmd_ctx *); int cmd_command_prompt_callback(void *, const char *); +void cmd_command_prompt_free(void *); const struct cmd_entry cmd_command_prompt_entry = { "command-prompt", NULL, @@ -96,7 +97,8 @@ cmd_command_prompt_exec(struct cmd *self, struct cmd_ctx *ctx) cdata->template = NULL; hdr = xstrdup(":"); } - status_prompt_set(c, hdr, cmd_command_prompt_callback, cdata, 0); + status_prompt_set(c, hdr, + cmd_command_prompt_callback, cmd_command_prompt_free, cdata, 0); xfree(hdr); return (0); @@ -112,10 +114,8 @@ cmd_command_prompt_callback(void *data, const char *s) char *cause, *ptr, *buf, ch; size_t len, slen; - if (s == NULL) { - xfree(cdata); + if (s == NULL) return (0); - } slen = strlen(s); len = 0; @@ -139,12 +139,10 @@ cmd_command_prompt_callback(void *data, const char *s) break; } } - xfree(cdata->template); buf[len] = '\0'; s = buf; } - xfree(cdata); if (cmd_string_parse(s, &cmdlist, &cause) != 0) { if (cause == NULL) @@ -172,7 +170,17 @@ cmd_command_prompt_callback(void *data, const char *s) cmd_list_exec(cmdlist, &ctx); cmd_list_free(cmdlist); - if (c->prompt_callback != (void *) &cmd_command_prompt_callback) + if (c->prompt_callbackfn != (void *) &cmd_command_prompt_callback) return (1); return (0); } + +void +cmd_command_prompt_free(void *data) +{ + struct cmd_command_prompt_data *cdata = data; + + if (cdata->template != NULL) + xfree(cdata->template); + xfree(cdata); +} diff --git a/cmd-confirm-before.c b/cmd-confirm-before.c index 2dbd72ce..c0fbe130 100644 --- a/cmd-confirm-before.c +++ b/cmd-confirm-before.c @@ -29,11 +29,7 @@ int cmd_confirm_before_exec(struct cmd *, struct cmd_ctx *); void cmd_confirm_before_init(struct cmd *, int); int cmd_confirm_before_callback(void *, const char *); - -struct cmd_confirm_before_data { - struct client *c; - char *cmd; -}; +void cmd_confirm_before_free(void *); const struct cmd_entry cmd_confirm_before_entry = { "confirm-before", "confirm", @@ -48,6 +44,11 @@ const struct cmd_entry cmd_confirm_before_entry = { cmd_target_print }; +struct cmd_confirm_before_data { + struct client *c; + char *cmd; +}; + void cmd_confirm_before_init(struct cmd *self, int key) { @@ -91,8 +92,9 @@ cmd_confirm_before_exec(unused struct cmd *self, struct cmd_ctx *ctx) cdata = xmalloc(sizeof *cdata); cdata->cmd = xstrdup(data->arg); cdata->c = c; - status_prompt_set( - cdata->c, buf, cmd_confirm_before_callback, cdata, PROMPT_SINGLE); + status_prompt_set(cdata->c, buf, + cmd_confirm_before_callback, cmd_confirm_before_free, cdata, + PROMPT_SINGLE); xfree(buf); return (1); @@ -108,7 +110,7 @@ cmd_confirm_before_callback(void *data, const char *s) char *cause; if (s == NULL || tolower((u_char) s[0]) != 'y' || s[1] != '\0') - goto out; + return (0); if (cmd_string_parse(cdata->cmd, &cmdlist, &cause) != 0) { if (cause != NULL) { @@ -116,7 +118,7 @@ cmd_confirm_before_callback(void *data, const char *s) status_message_set(c, "%s", cause); xfree(cause); } - goto out; + return (0); } ctx.msgdata = NULL; @@ -132,10 +134,15 @@ cmd_confirm_before_callback(void *data, const char *s) cmd_list_exec(cmdlist, &ctx); cmd_list_free(cmdlist); -out: + return (0); +} + +void +cmd_confirm_before_free(void *data) +{ + struct cmd_confirm_before_data *cdata = data; + if (cdata->cmd != NULL) xfree(cdata->cmd); xfree(cdata); - - return (0); } diff --git a/cmd-select-prompt.c b/cmd-select-prompt.c index 8b707342..67bb8ff3 100644 --- a/cmd-select-prompt.c +++ b/cmd-select-prompt.c @@ -55,7 +55,7 @@ cmd_select_prompt_exec(struct cmd *self, struct cmd_ctx *ctx) if (c->prompt_string != NULL) return (0); - status_prompt_set(c, "index ", cmd_select_prompt_callback, c, 0); + status_prompt_set(c, "index ", cmd_select_prompt_callback, NULL, c, 0); return (0); } diff --git a/server-fn.c b/server-fn.c index b5cc00f5..4ecb9ce9 100644 --- a/server-fn.c +++ b/server-fn.c @@ -171,8 +171,8 @@ server_lock(void) continue; status_prompt_clear(c); - status_prompt_set( - c, "Password: ", server_lock_callback, c, PROMPT_HIDDEN); + status_prompt_set(c, + "Password: ", server_lock_callback, c, NULL, PROMPT_HIDDEN); server_redraw_client(c); } server_locked = 1; diff --git a/status.c b/status.c index 49215adf..32effe5d 100644 --- a/status.c +++ b/status.c @@ -468,6 +468,9 @@ status_message_set(struct client *c, const char *fmt, ...) va_list ap; int delay; + status_prompt_clear(c); + status_message_clear(c); + delay = options_get_number(&c->session->options, "display-time"); tv.tv_sec = delay / 1000; tv.tv_usec = (delay % 1000) * 1000L; @@ -493,7 +496,7 @@ status_message_clear(struct client *c) c->message_string = NULL; c->tty.flags &= ~(TTY_NOCURSOR|TTY_FREEZE); - c->flags |= CLIENT_STATUS; + c->flags |= CLIENT_REDRAW; /* screen was frozen and may have changed */ screen_reinit(&c->status); } @@ -540,15 +543,20 @@ status_message_redraw(struct client *c) } void -status_prompt_set(struct client *c, - const char *msg, int (*fn)(void *, const char *), void *data, int flags) +status_prompt_set(struct client *c, const char *msg, + int (*callbackfn)(void *, const char *), void (*freefn)(void *), + void *data, int flags) { + status_message_clear(c); + status_prompt_clear(c); + c->prompt_string = xstrdup(msg); c->prompt_buffer = xstrdup(""); c->prompt_index = 0; - c->prompt_callback = fn; + c->prompt_callbackfn = callbackfn; + c->prompt_freefn = freefn; c->prompt_data = data; c->prompt_hindex = 0; @@ -566,9 +574,12 @@ status_prompt_set(struct client *c, void status_prompt_clear(struct client *c) { - if (c->prompt_string == NULL) + if (c->prompt_string == NULL) return; + if (c->prompt_freefn != NULL && c->prompt_data != NULL) + c->prompt_freefn(c->prompt_data); + mode_key_free(&c->prompt_mdata); xfree(c->prompt_string); @@ -580,7 +591,7 @@ status_prompt_clear(struct client *c) c->prompt_buffer = NULL; c->tty.flags &= ~(TTY_NOCURSOR|TTY_FREEZE); - c->flags |= CLIENT_STATUS; + c->flags |= CLIENT_REDRAW; /* screen was frozen and may have changed */ screen_reinit(&c->status); } @@ -832,14 +843,14 @@ status_prompt_key(struct client *c, int key) case MODEKEYCMD_CHOOSE: if (*c->prompt_buffer != '\0') { status_prompt_add_history(c); - if (c->prompt_callback( + if (c->prompt_callbackfn( c->prompt_data, c->prompt_buffer) == 0) status_prompt_clear(c); break; } /* FALLTHROUGH */ case MODEKEYCMD_QUIT: - if (c->prompt_callback(c->prompt_data, NULL) == 0) + if (c->prompt_callbackfn(c->prompt_data, NULL) == 0) status_prompt_clear(c); break; case MODEKEYCMD_OTHERKEY: @@ -858,7 +869,7 @@ status_prompt_key(struct client *c, int key) } if (c->prompt_flags & PROMPT_SINGLE) { - if (c->prompt_callback( + if (c->prompt_callbackfn( c->prompt_data, c->prompt_buffer) == 0) status_prompt_clear(c); } diff --git a/tmux.h b/tmux.h index 53688eed..1e8e37a3 100644 --- a/tmux.h +++ b/tmux.h @@ -802,7 +802,8 @@ struct client { char *prompt_string; char *prompt_buffer; size_t prompt_index; - int (*prompt_callback)(void *, const char *); + int (*prompt_callbackfn)(void *, const char *); + void (*prompt_freefn)(void *); void *prompt_data; #define PROMPT_HIDDEN 0x1 @@ -1278,8 +1279,8 @@ int status_redraw(struct client *); void printflike2 status_message_set(struct client *, const char *, ...); void status_message_clear(struct client *); int status_message_redraw(struct client *); -void status_prompt_set(struct client *, - const char *, int (*)(void *, const char *), void *, int); +void status_prompt_set(struct client *, const char *, + int (*)(void *, const char *), void (*)(void *), void *, int); void status_prompt_clear(struct client *); int status_prompt_redraw(struct client *); void status_prompt_key(struct client *, int); From 216df07688c3811983d4e3430ad59689ebaab889 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 17 Jul 2009 07:05:58 +0000 Subject: [PATCH 0133/1180] A similar for fix for window_choose: don't rely on the callback always being called to free data, have a separate free callback and call it from the mode cleanup code. --- cmd-choose-session.c | 3 +-- cmd-choose-window.c | 3 +-- cmd-find-window.c | 3 +-- tmux.h | 2 +- window-choose.c | 27 ++++++++++++++++++--------- 5 files changed, 22 insertions(+), 16 deletions(-) diff --git a/cmd-choose-session.c b/cmd-choose-session.c index 22f7d04b..09c8216d 100644 --- a/cmd-choose-session.c +++ b/cmd-choose-session.c @@ -84,7 +84,7 @@ cmd_choose_session_exec(struct cmd *self, struct cmd_ctx *ctx) cdata->client = server_client_index(ctx->curclient); window_choose_ready( - wl->window->active, cur, cmd_choose_session_callback, cdata); + wl->window->active, cur, cmd_choose_session_callback, xfree, cdata); return (0); } @@ -103,5 +103,4 @@ cmd_choose_session_callback(void *data, int idx) server_redraw_client(c); } } - xfree(cdata); } diff --git a/cmd-choose-window.c b/cmd-choose-window.c index baa55eb2..33487e27 100644 --- a/cmd-choose-window.c +++ b/cmd-choose-window.c @@ -85,7 +85,7 @@ cmd_choose_window_exec(struct cmd *self, struct cmd_ctx *ctx) fatalx("session not found"); window_choose_ready( - wl->window->active, cur, cmd_choose_window_callback, cdata); + wl->window->active, cur, cmd_choose_window_callback, xfree, cdata); return (0); } @@ -102,5 +102,4 @@ cmd_choose_window_callback(void *data, int idx) server_redraw_session(s); recalculate_sizes(); } - xfree(cdata); } diff --git a/cmd-find-window.c b/cmd-find-window.c index 21461cdc..34ea75ec 100644 --- a/cmd-find-window.c +++ b/cmd-find-window.c @@ -140,7 +140,7 @@ cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx) fatalx("session not found"); window_choose_ready( - wl->window->active, 0, cmd_find_window_callback, cdata); + wl->window->active, 0, cmd_find_window_callback, xfree, cdata); out: ARRAY_FREE(&list_idx); @@ -161,5 +161,4 @@ cmd_find_window_callback(void *data, int idx) server_redraw_session(s); recalculate_sizes(); } - xfree(cdata); } diff --git a/tmux.h b/tmux.h index 1e8e37a3..0720b25b 100644 --- a/tmux.h +++ b/tmux.h @@ -1490,7 +1490,7 @@ void window_choose_vadd( void printflike3 window_choose_add( struct window_pane *, int, const char *, ...); void window_choose_ready(struct window_pane *, - u_int, void (*)(void *, int), void *); + u_int, void (*)(void *, int), void (*)(void *), void *); /* names.c */ void set_window_names(void); diff --git a/window-choose.c b/window-choose.c index f199b847..a1f1a069 100644 --- a/window-choose.c +++ b/window-choose.c @@ -59,7 +59,8 @@ struct window_choose_mode_data { u_int top; u_int selected; - void (*callback)(void *, int); + void (*callbackfn)(void *, int); + void (*freefn)(void *); void *data; }; @@ -86,8 +87,8 @@ window_choose_add(struct window_pane *wp, int idx, const char *fmt, ...) } void -window_choose_ready(struct window_pane *wp, - u_int cur, void (*callback)(void *, int), void *cdata) +window_choose_ready(struct window_pane *wp, u_int cur, + void (*callbackfn)(void *, int), void (*freefn)(void *), void *cdata) { struct window_choose_mode_data *data = wp->modedata; struct screen *s = &data->screen; @@ -96,7 +97,8 @@ window_choose_ready(struct window_pane *wp, if (data->selected > screen_size_y(s) - 1) data->top = ARRAY_LENGTH(&data->list) - screen_size_y(s); - data->callback = callback; + data->callbackfn = callbackfn; + data->freefn = freefn; data->data = cdata; window_choose_redraw_screen(wp); @@ -109,7 +111,11 @@ window_choose_init(struct window_pane *wp) struct screen *s; wp->modedata = data = xmalloc(sizeof *data); - data->callback = NULL; + + data->callbackfn = NULL; + data->freefn = NULL; + data->data = NULL; + ARRAY_INIT(&data->list); data->top = 0; @@ -131,6 +137,9 @@ window_choose_free(struct window_pane *wp) struct window_choose_mode_data *data = wp->modedata; u_int i; + if (data->freefn != NULL && data->data != NULL) + data->freefn(data->data); + mode_key_free(&data->mdata); for (i = 0; i < ARRAY_LENGTH(&data->list); i++) @@ -168,12 +177,12 @@ window_choose_key(struct window_pane *wp, unused struct client *c, int key) switch (mode_key_lookup(&data->mdata, key)) { case MODEKEYCMD_QUIT: - data->callback(data->data, -1); + data->callbackfn(data->data, -1); window_pane_reset_mode(wp); break; case MODEKEYCMD_CHOOSE: item = &ARRAY_ITEM(&data->list, data->selected); - data->callback(data->data, item->idx); + data->callbackfn(data->data, item->idx); window_pane_reset_mode(wp); break; case MODEKEYCMD_UP: @@ -273,7 +282,7 @@ window_choose_mouse(struct window_pane *wp, data->selected = idx; item = &ARRAY_ITEM(&data->list, data->selected); - data->callback(data->data, item->idx); + data->callbackfn(data->data, item->idx); window_pane_reset_mode(wp); } @@ -287,7 +296,7 @@ window_choose_write_line( struct grid_cell gc; int utf8flag; - if (data->callback == NULL) + if (data->callbackfn == NULL) fatalx("called before callback assigned"); utf8flag = options_get_number(&wp->window->options, "utf8"); From d3b5c242cc01a41820b696cf6f6420879ce24adc Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 17 Jul 2009 07:09:46 +0000 Subject: [PATCH 0134/1180] Oops, it is always a good idea to get arguments the right way round. --- server-fn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server-fn.c b/server-fn.c index 4ecb9ce9..d6cec8f9 100644 --- a/server-fn.c +++ b/server-fn.c @@ -172,7 +172,7 @@ server_lock(void) status_prompt_clear(c); status_prompt_set(c, - "Password: ", server_lock_callback, c, NULL, PROMPT_HIDDEN); + "Password: ", server_lock_callback, NULL, c, PROMPT_HIDDEN); server_redraw_client(c); } server_locked = 1; From 7ddba901a491a6adea93e35a5903f4125e53bdbc Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 17 Jul 2009 13:38:03 +0000 Subject: [PATCH 0135/1180] If -u is specified or UTF-8 is otherwise detected when the server is started, enable the utf8 and status-utf8 optons. While here, note in the man page that the server is started with the first session and exits when none remain. --- tmux.1 | 12 +++++++++++- tmux.c | 42 ++++++++++++++++++++++++------------------ 2 files changed, 35 insertions(+), 19 deletions(-) diff --git a/tmux.1 b/tmux.1 index a025cbbc..34501931 100644 --- a/tmux.1 +++ b/tmux.1 @@ -36,11 +36,13 @@ controlled from a single terminal. .Pp .Nm runs as a server-client system. -A server is created automatically when necessary and holds a number of +A server holds a number of .Em sessions , each of which may have a number of .Em windows linked to it. +A server is started automatically when the first session is created and exits +when all the sessions it contains are destroyed. A window may be split on screen into one or more .Em panes , each of which is a separate terminal. @@ -123,6 +125,14 @@ This is not always correct: the flag explicitly informs .Nm that UTF-8 is supported. +.Pp +If the server is started from a client passed +.Fl u +or where UTF-8 is detected, the +.Ic utf8 +and +.Ic status-utf8 +options are enabled in the global window and session options respectively. .It Fl v Request verbose logging. This option may be specified multiple times for increasing verbosity. diff --git a/tmux.c b/tmux.c index a2f6e73b..a5edb460 100644 --- a/tmux.c +++ b/tmux.c @@ -266,6 +266,22 @@ main(int argc, char **argv) log_open_tty(debug_level); siginit(); + if (!(flags & IDENTIFY_UTF8)) { + /* + * If the user has set whichever of LC_ALL, LC_CTYPE or LANG + * exist (in that order) to contain UTF-8, it is a safe + * assumption that either they are using a UTF-8 terminal, or + * if not they know that output from UTF-8-capable programs may + * be wrong. + */ + if ((s = getenv("LC_ALL")) == NULL) { + if ((s = getenv("LC_CTYPE")) == NULL) + s = getenv("LANG"); + } + if (s != NULL && strcasestr(s, "UTF-8") != NULL) + flags |= IDENTIFY_UTF8; + } + options_init(&global_s_options, NULL); options_set_number(&global_s_options, "bell-action", BELL_ANY); options_set_number(&global_s_options, "buffer-limit", 9); @@ -292,7 +308,10 @@ main(int argc, char **argv) options_set_string(&global_s_options, "status-left", "[#S]"); options_set_string( &global_s_options, "status-right", "\"#24T\" %%H:%%M %%d-%%b-%%y"); - options_set_number(&global_s_options, "status-utf8", 0); + if (flags & IDENTIFY_UTF8) + options_set_number(&global_s_options, "status-utf8", 1); + else + options_set_number(&global_s_options, "status-utf8", 0); options_init(&global_w_options, NULL); options_set_number(&global_w_options, "aggressive-resize", 0); @@ -309,29 +328,16 @@ main(int argc, char **argv) options_set_number(&global_w_options, "mode-keys", MODEKEY_EMACS); options_set_number(&global_w_options, "monitor-activity", 0); options_set_string(&global_w_options, "monitor-content", "%s", ""); - options_set_number(&global_w_options, "utf8", 0); + if (flags & IDENTIFY_UTF8) + options_set_number(&global_w_options, "utf8", 1); + else + options_set_number(&global_w_options, "utf8", 0); options_set_number(&global_w_options, "window-status-attr", 0); options_set_number(&global_w_options, "window-status-bg", 8); options_set_number(&global_w_options, "window-status-fg", 8); options_set_number(&global_w_options, "xterm-keys", 0); options_set_number(&global_w_options, "remain-on-exit", 0); - if (!(flags & IDENTIFY_UTF8)) { - /* - * If the user has set whichever of LC_ALL, LC_CTYPE or LANG - * exist (in that order) to contain UTF-8, it is a safe - * assumption that either they are using a UTF-8 terminal, or - * if not they know that output from UTF-8-capable programs may - * be wrong. - */ - if ((s = getenv("LC_ALL")) == NULL) { - if ((s = getenv("LC_CTYPE")) == NULL) - s = getenv("LANG"); - } - if (s != NULL && strcasestr(s, "UTF-8") != NULL) - flags |= IDENTIFY_UTF8; - } - if (cfg_file == NULL) { home = getenv("HOME"); if (home == NULL || *home == '\0') { From 1938c994e7d9a27741735e6821217a16a134f039 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 17 Jul 2009 13:43:07 +0000 Subject: [PATCH 0136/1180] Remove a duplicate key binding, and turn off autorepeat for up/down as it is kind of annoying by default. --- key-bindings.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/key-bindings.c b/key-bindings.c index 6fb3b89d..56b1d58b 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -135,12 +135,11 @@ key_bindings_init(void) { KEYC_ADDESC('1'), 0, &cmd_select_layout_entry }, { KEYC_ADDESC('2'), 0, &cmd_select_layout_entry }, { KEYC_ADDESC('9'), 0, &cmd_select_layout_entry }, - { KEYC_ADDCTL(KEYC_DOWN), 1, &cmd_resize_pane_entry }, { KEYC_PPAGE, 0, &cmd_scroll_mode_entry }, { KEYC_ADDESC('n'), 0, &cmd_next_window_entry }, { KEYC_ADDESC('p'), 0, &cmd_previous_window_entry }, - { KEYC_UP, 1, &cmd_up_pane_entry }, - { KEYC_DOWN, 1, &cmd_down_pane_entry }, + { KEYC_UP, 0, &cmd_up_pane_entry }, + { KEYC_DOWN, 0, &cmd_down_pane_entry }, { KEYC_ADDESC(KEYC_UP), 1, &cmd_resize_pane_entry }, { KEYC_ADDESC(KEYC_DOWN), 1, &cmd_resize_pane_entry }, { KEYC_ADDCTL(KEYC_UP), 1, &cmd_resize_pane_entry }, From ce53936a2b56521903d69bac565391e37ad7e115 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 17 Jul 2009 15:03:11 +0000 Subject: [PATCH 0137/1180] Tidy up new-session and attach-session and change them to work from inside tmux, switching the current client to the new or requested session. Written with Josh Elsasser. --- cmd-attach-session.c | 59 +++++++++++++------- cmd-new-session.c | 129 ++++++++++++++++++++++++++----------------- tmux.1 | 6 +- tmux.h | 10 ++++ 4 files changed, 133 insertions(+), 71 deletions(-) diff --git a/cmd-attach-session.c b/cmd-attach-session.c index 196d5d13..aae8abe7 100644 --- a/cmd-attach-session.c +++ b/cmd-attach-session.c @@ -44,10 +44,9 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx) { struct cmd_target_data *data = self->data; struct session *s; + struct client *c; char *cause; - - if (ctx->curclient != NULL) - return (0); + u_int i; if (ARRAY_LENGTH(&sessions) == 0) { ctx->error(ctx, "no sessions"); @@ -56,24 +55,44 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx) if ((s = cmd_find_session(ctx, data->target)) == NULL) return (-1); - if (!(ctx->cmdclient->flags & CLIENT_TERMINAL)) { - ctx->error(ctx, "not a terminal"); - return (-1); + if (ctx->cmdclient == NULL) { + if (data->chflags & CMD_CHFLAG('d')) { + /* + * Can't use server_write_session in case attaching to + * the same session as currently attached to. + */ + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c == NULL || c->session != s) + continue; + if (c == ctx->curclient) + continue; + server_write_client(c, MSG_DETACH, NULL, 0); + } + } + + ctx->curclient->session = s; + server_redraw_client(ctx->curclient); + } else { + if (!(ctx->cmdclient->flags & CLIENT_TERMINAL)) { + ctx->error(ctx, "not a terminal"); + return (-1); + } + + if (tty_open(&ctx->cmdclient->tty, &cause) != 0) { + ctx->error(ctx, "terminal open failed: %s", cause); + xfree(cause); + return (-1); + } + + if (data->chflags & CMD_CHFLAG('d')) + server_write_session(s, MSG_DETACH, NULL, 0); + + ctx->cmdclient->session = s; + server_write_client(ctx->cmdclient, MSG_READY, NULL, 0); + server_redraw_client(ctx->cmdclient); } - - if (tty_open(&ctx->cmdclient->tty, &cause) != 0) { - ctx->error(ctx, "terminal open failed: %s", cause); - xfree(cause); - return (-1); - } - - if (data->chflags & CMD_CHFLAG('d')) - server_write_session(s, MSG_DETACH, NULL, 0); - ctx->cmdclient->session = s; - - server_write_client(ctx->cmdclient, MSG_READY, NULL, 0); recalculate_sizes(); - server_redraw_client(ctx->cmdclient); - return (1); + return (1); /* 1 means don't tell command client to exit */ } diff --git a/cmd-new-session.c b/cmd-new-session.c index cf086a87..53e752ac 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -111,65 +111,80 @@ int cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) { struct cmd_new_session_data *data = self->data; - struct client *c = ctx->cmdclient; struct session *s; char *cmd, *cwd, *cause; u_int sx, sy; - if (ctx->curclient != NULL) - return (0); - - if (!data->flag_detached) { - if (c == NULL) { - ctx->error(ctx, "no client to attach to"); - return (-1); - } - if (!(c->flags & CLIENT_TERMINAL)) { - ctx->error(ctx, "not a terminal"); - return (-1); - } - } - if (data->newname != NULL && session_find(data->newname) != NULL) { ctx->error(ctx, "duplicate session: %s", data->newname); return (-1); } - cmd = data->cmd; - if (cmd == NULL) - cmd = options_get_string(&global_s_options, "default-command"); - if (c == NULL || c->cwd == NULL) - cwd = options_get_string(&global_s_options, "default-path"); + /* + * There are two cases: + * + * 1. If cmdclient is non-NULL, new-session has been called from the + * command-line - cmdclient is to become a new attached, interactive + * client. Unless -d is given, the terminal must be opened and then + * the client sent MSG_READY. + * + * 2. If cmdclient is NULL, new-session has been called from an + * existing client (such as a key binding). + * + * In both cases, a new additional session needs to be created and + * (unless -d) set as the current session for the client. + */ + + /* Open the terminal if necessary. */ + if (!data->flag_detached && ctx->cmdclient != NULL) { + if (!(ctx->cmdclient->flags & CLIENT_TERMINAL)) { + ctx->error(ctx, "not a terminal"); + return (-1); + } + + if (tty_open(&ctx->cmdclient->tty, &cause) != 0) { + ctx->error(ctx, "open terminal failed: %s", cause); + xfree(cause); + return (-1); + } + } + + /* Find new session size and options. */ + if (data->flag_detached) { + sx = 80; + sy = 25; + } else { + if (ctx->cmdclient != NULL) { + sx = ctx->cmdclient->tty.sx; + sy = ctx->cmdclient->tty.sy; + } else { + sx = ctx->curclient->tty.sx; + sy = ctx->curclient->tty.sy; + } + } + if (sy > 0 && options_get_number(&global_s_options, "status")) + sy--; + if (sx == 0) + sx = 1; + if (sy == 0) + sy = 1; + if (ctx->cmdclient != NULL && ctx->cmdclient->cwd != NULL) + cwd = ctx->cmdclient->cwd; else - cwd = c->cwd; - - sx = 80; - sy = 25; - if (!data->flag_detached) { - sx = c->tty.sx; - sy = c->tty.sy; - } - - if (options_get_number(&global_s_options, "status")) { - if (sy == 0) - sy = 1; - else - sy--; - } - - if (!data->flag_detached && tty_open(&c->tty, &cause) != 0) { - ctx->error(ctx, "open terminal failed: %s", cause); - xfree(cause); - return (-1); - } - + cwd = options_get_string(&global_s_options, "default-path"); + if (data->cmd != NULL) + cmd = data->cmd; + else + cmd = options_get_string(&global_s_options, "default-command"); + /* Create the new session. */ s = session_create(data->newname, cmd, cwd, sx, sy, &cause); if (s == NULL) { ctx->error(ctx, "create session failed: %s", cause); xfree(cause); return (-1); } + if (data->winname != NULL) { xfree(s->curw->window->name); s->curw->window->name = xstrdup(data->winname); @@ -177,17 +192,31 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) &s->curw->window->options, "automatic-rename", 0); } - if (data->flag_detached) { - if (c != NULL) - server_write_client(c, MSG_EXIT, NULL, 0); - } else { - c->session = s; - server_write_client(c, MSG_READY, NULL, 0); - server_redraw_client(c); + /* + * If a command client exists, it is either taking this session (and + * needs to get MSG_READY and stay around), or -d is given and it needs + * to exit. + */ + if (ctx->cmdclient != NULL) { + if (!data->flag_detached) + server_write_client(ctx->cmdclient, MSG_READY, NULL, 0); + else + server_write_client(ctx->cmdclient, MSG_EXIT, NULL, 0); + } + + /* Set the client to the new session. */ + if (!data->flag_detached) { + if (ctx->cmdclient != NULL) { + ctx->cmdclient->session = s; + server_redraw_client(ctx->cmdclient); + } else { + ctx->curclient->session = s; + server_redraw_client(ctx->curclient); + } } recalculate_sizes(); - return (1); + return (1); /* 1 means don't tell command client to exit */ } void diff --git a/tmux.1 b/tmux.1 index 34501931..dcc30a25 100644 --- a/tmux.1 +++ b/tmux.1 @@ -596,7 +596,11 @@ The following commands are available: .Op Fl t Ar target-session .Xc .D1 (alias: Ic attach ) -Create a new client in the current terminal and attach it to a session. +If run from outside +.Nm , +create a new client in the current terminal and attach it to +.Ar target-session . +If used from inside, switch the current client. If .Fl d is specified, any other clients attached to the session are detached. diff --git a/tmux.h b/tmux.h index 0720b25b..60455df1 100644 --- a/tmux.h +++ b/tmux.h @@ -835,8 +835,18 @@ struct client_ctx { struct cmd_ctx { struct client *cmdclient; + /* + * curclient is the client where this command was executed if inside + * tmux. This is NULL if the command came from the command-line. + * + * cmdclient is the client which sent the MSG_COMMAND to the server, if + * any. This is NULL unless the command came from the command-line. + * + * One of curclient or cmdclient is always NULL and the other not. + */ struct client *curclient; struct session *cursession; + struct msg_command_data *msgdata; void (*print)(struct cmd_ctx *, const char *, ...); From ad006bc6b66f335e87c0876d1b77af3541a4b517 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 17 Jul 2009 18:35:11 +0000 Subject: [PATCH 0138/1180] When resizing a screen smaller in alternate screen mode, all the lines needed could be consumed by deleting from the bottom, leaving none to be removed from the top. In this case, don't call grid_view_delete_lines with ny of 0 as this is incorrect and causes a bounds check to fatal error if built with -DDEBUG. --- screen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/screen.c b/screen.c index f1a723a3..650278b2 100644 --- a/screen.c +++ b/screen.c @@ -183,7 +183,7 @@ screen_resize_y(struct screen *s, u_int sy) available = s->cy; if (gd->flags & GRID_HISTORY) gd->hsize += needed; - else if (available > 0) { + else if (needed > 0 && available > 0) { if (available > needed) available = needed; grid_view_delete_lines(gd, 0, available); From 6f5150a943425d7d5d65ae443f956931fcb82d0b Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 17 Jul 2009 18:45:08 +0000 Subject: [PATCH 0139/1180] - New command display-message (alias display) to display a message in the status line (bound to "i" and displays the current window and time by default). The same substitutions are applied as for status-left/right. - Add support for including the window index (#I), pane index (#P) and window name (#W) in the message, and status-left or status-right. - Bump protocol version. From Tiago Cunha, thanks! --- Makefile | 3 +- cmd-display-message.c | 65 +++++++++++++++++++++++++++++++++++++++++++ cmd.c | 1 + key-bindings.c | 1 + status.c | 21 ++++++++++++-- tmux.1 | 12 ++++++++ tmux.h | 5 +++- window.c | 15 ++++++++++ 8 files changed, 119 insertions(+), 4 deletions(-) create mode 100644 cmd-display-message.c diff --git a/Makefile b/Makefile index ef628faa..6f6644a0 100644 --- a/Makefile +++ b/Makefile @@ -25,7 +25,8 @@ SRCS= attributes.c buffer-poll.c buffer.c cfg.c client-fn.c \ cmd-split-window.c cmd-start-server.c cmd-string.c cmd-if-shell.c \ cmd-suspend-client.c cmd-swap-pane.c cmd-swap-window.c \ cmd-switch-client.c cmd-unbind-key.c cmd-unlink-window.c \ - cmd-up-pane.c cmd.c colour.c grid-view.c grid.c input-keys.c \ + cmd-up-pane.c cmd-display-message.c cmd.c \ + colour.c grid-view.c grid.c input-keys.c \ input.c key-bindings.c key-string.c layout-manual.c layout.c log.c \ mode-key.c names.c options-cmd.c options.c paste.c procname.c \ resize.c screen-redraw.c screen-write.c screen.c server-fn.c \ diff --git a/cmd-display-message.c b/cmd-display-message.c new file mode 100644 index 00000000..332b6e28 --- /dev/null +++ b/cmd-display-message.c @@ -0,0 +1,65 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2009 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 + +#include "tmux.h" + +/* + * Displays a message in the status line. + */ + +int cmd_display_message_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_display_message_entry = { + "display-message", "display", + CMD_TARGET_CLIENT_USAGE " [message]", + CMD_ARG01, 0, + cmd_target_init, + cmd_target_parse, + cmd_display_message_exec, + cmd_target_send, + cmd_target_recv, + cmd_target_free, + cmd_target_print +}; + +int +cmd_display_message_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_target_data *data = self->data; + struct client *c; + const char *template; + char *msg; + + if ((c = cmd_find_client(ctx, data->target)) == NULL) + return (-1); + + if (data->arg == NULL) + template = "[#S] #I:#W, current pane #P - (%H:%M %d-%b-%y)"; + else + template = data->arg; + + msg = status_replace(c->session, template, time(NULL)); + status_message_set(c, "%s", msg); + xfree(msg); + + return (0); +} diff --git a/cmd.c b/cmd.c index f2466216..30553287 100644 --- a/cmd.c +++ b/cmd.c @@ -41,6 +41,7 @@ const struct cmd_entry *cmd_table[] = { &cmd_copy_mode_entry, &cmd_delete_buffer_entry, &cmd_detach_client_entry, + &cmd_display_message_entry, &cmd_down_pane_entry, &cmd_find_window_entry, &cmd_has_session_entry, diff --git a/key-bindings.c b/key-bindings.c index 56b1d58b..c298c79d 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -119,6 +119,7 @@ key_bindings_init(void) { 'c', 0, &cmd_new_window_entry }, { 'd', 0, &cmd_detach_client_entry }, { 'f', 0, &cmd_command_prompt_entry }, + { 'i', 0, &cmd_display_message_entry }, { 'l', 0, &cmd_last_window_entry }, { 'n', 0, &cmd_next_window_entry }, { 'o', 0, &cmd_down_pane_entry }, diff --git a/status.c b/status.c index 32effe5d..c5190b54 100644 --- a/status.c +++ b/status.c @@ -29,7 +29,6 @@ #include "tmux.h" -char *status_replace(struct session *, char *, time_t); char *status_replace_popen(char **); size_t status_width(struct winlink *); char *status_print(struct session *, struct winlink *, struct grid_cell *); @@ -275,7 +274,7 @@ out: } char * -status_replace(struct session *s, char *fmt, time_t t) +status_replace(struct session *s, const char *fmt, time_t t) { struct winlink *wl = s->curw; static char out[BUFSIZ]; @@ -323,6 +322,20 @@ status_replace(struct session *s, char *fmt, time_t t) ptr = tmp; } /* FALLTHROUGH */ + case 'I': + if (ptr == NULL) { + xsnprintf(tmp, sizeof tmp, "%d", wl->idx); + ptr = tmp; + } + /* FALLTHROUGH */ + case 'P': + if (ptr == NULL) { + xsnprintf(tmp, sizeof tmp, "%u", + window_pane_index(wl->window, + wl->window->active)); + ptr = tmp; + } + /* FALLTHOUGH */ case 'S': if (ptr == NULL) ptr = s->name; @@ -330,6 +343,10 @@ status_replace(struct session *s, char *fmt, time_t t) case 'T': if (ptr == NULL) ptr = wl->window->active->base.title; + /* FALLTHROUGH */ + case 'W': + if (ptr == NULL) + ptr = wl->window->name; len = strlen(ptr); if ((size_t) n < len) len = n; diff --git a/tmux.1 b/tmux.1 index dcc30a25..9b2f344c 100644 --- a/tmux.1 +++ b/tmux.1 @@ -717,6 +717,15 @@ or the top buffer if not specified. .D1 (alias: Ic detach ) Detach the current client if bound to a key, or the specified client with .Fl t . +.It Xo Ic display-message +.Op Fl t Ar target-client +.Op Ar message +.Xc +.D1 (alias: Ic display ) +Display a message (see the +.Ic status-left +option below) +in the status line. .It Xo Ic down-pane .Op Fl p Ar pane-index .Op Fl t Ar target-window @@ -1262,8 +1271,11 @@ may contain any of the following special character pairs: .It Sy "Character pair" Ta Sy "Replaced with" .It Li "#(command)" Ta "First line of command's output" .It Li "#H" Ta "Hostname of local host" +.It Li "#I" Ta "Current window index" +.It Li "#P" Ta "Current pane index" .It Li "#S" Ta "Session name" .It Li "#T" Ta "Current window title" +.It Li "#W" Ta "Current window name" .It Li "##" Ta "A literal" Ql # .El .Pp diff --git a/tmux.h b/tmux.h index 60455df1..2a0412ba 100644 --- a/tmux.h +++ b/tmux.h @@ -19,7 +19,7 @@ #ifndef TMUX_H #define TMUX_H -#define PROTOCOL_VERSION -13 +#define PROTOCOL_VERSION -14 #include #include @@ -1110,6 +1110,7 @@ extern const struct cmd_entry cmd_copy_buffer_entry; extern const struct cmd_entry cmd_copy_mode_entry; extern const struct cmd_entry cmd_delete_buffer_entry; extern const struct cmd_entry cmd_detach_client_entry; +extern const struct cmd_entry cmd_display_message_entry; extern const struct cmd_entry cmd_down_pane_entry; extern const struct cmd_entry cmd_find_window_entry; extern const struct cmd_entry cmd_has_session_entry; @@ -1286,6 +1287,7 @@ int server_unlock(const char *); /* status.c */ int status_redraw(struct client *); +char *status_replace(struct session *, const char *, time_t); void printflike2 status_message_set(struct client *, const char *, ...); void status_message_clear(struct client *); int status_message_redraw(struct client *); @@ -1447,6 +1449,7 @@ struct window_pane *window_add_pane(struct window *, int, const char *, const char *, const char **, u_int, char **); void window_remove_pane(struct window *, struct window_pane *); struct window_pane *window_pane_at_index(struct window *, u_int); +u_int window_pane_index(struct window *, struct window_pane *); u_int window_count_panes(struct window *); void window_destroy_panes(struct window *); struct window_pane *window_pane_create(struct window *, u_int, u_int, u_int); diff --git a/window.c b/window.c index 7823d2f5..81b4d34e 100644 --- a/window.c +++ b/window.c @@ -379,6 +379,21 @@ window_pane_at_index(struct window *w, u_int idx) return (NULL); } +u_int +window_pane_index(struct window *w, struct window_pane *wp) +{ + struct window_pane *wq; + u_int n; + + n = 0; + TAILQ_FOREACH(wq, &w->panes, entry) { + if (wp == wq) + break; + n++; + } + return (n); +} + u_int window_count_panes(struct window *w) { From 0ca6f667e3e6f26e92db01ee2a769d0ba49509ca Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 17 Jul 2009 20:37:03 +0000 Subject: [PATCH 0140/1180] Make it so using kill-pane to destroy the last pane in a window destroys the window instead of being an error. --- cmd-kill-pane.c | 5 +++-- cmd-kill-window.c | 28 +--------------------------- server-fn.c | 33 +++++++++++++++++++++++++++++++++ tmux.1 | 1 + tmux.h | 1 + 5 files changed, 39 insertions(+), 29 deletions(-) diff --git a/cmd-kill-pane.c b/cmd-kill-pane.c index d3a54c92..b501e416 100644 --- a/cmd-kill-pane.c +++ b/cmd-kill-pane.c @@ -61,8 +61,9 @@ cmd_kill_pane_exec(struct cmd *self, struct cmd_ctx *ctx) } if (window_count_panes(wl->window) == 1) { - ctx->error(ctx, "can't kill pane: %d", data->pane); - return (-1); + /* Only one pane, kill the window. */ + server_kill_window(wl->window); + return (0); } window_remove_pane(wl->window, wp); diff --git a/cmd-kill-window.c b/cmd-kill-window.c index 77b9b79d..66d8be88 100644 --- a/cmd-kill-window.c +++ b/cmd-kill-window.c @@ -44,37 +44,11 @@ cmd_kill_window_exec(struct cmd *self, struct cmd_ctx *ctx) { struct cmd_target_data *data = self->data; struct winlink *wl; - struct window *w; - struct session *s; - struct client *c; - u_int i, j; - int destroyed; if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) return (-1); - w = wl->window; - for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { - s = ARRAY_ITEM(&sessions, i); - if (s == NULL || !session_has(s, w)) - continue; - if ((wl = winlink_find_by_window(&s->windows, w)) == NULL) - continue; - - destroyed = session_detach(s, wl); - for (j = 0; j < ARRAY_LENGTH(&clients); j++) { - c = ARRAY_ITEM(&clients, j); - if (c == NULL || c->session != s) - continue; - - if (destroyed) { - c->session = NULL; - server_write_client(c, MSG_EXIT, NULL, 0); - } else - server_redraw_client(c); - } - } - recalculate_sizes(); + server_kill_window(wl->window); return (0); } diff --git a/server-fn.c b/server-fn.c index d6cec8f9..3080bed4 100644 --- a/server-fn.c +++ b/server-fn.c @@ -228,3 +228,36 @@ wrong: return (-1); } + +void +server_kill_window(struct window *w) +{ + struct session *s; + struct winlink *wl; + struct client *c; + u_int i, j; + int destroyed; + + + for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { + s = ARRAY_ITEM(&sessions, i); + if (s == NULL || !session_has(s, w)) + continue; + if ((wl = winlink_find_by_window(&s->windows, w)) == NULL) + continue; + + destroyed = session_detach(s, wl); + for (j = 0; j < ARRAY_LENGTH(&clients); j++) { + c = ARRAY_ITEM(&clients, j); + if (c == NULL || c->session != s) + continue; + + if (destroyed) { + c->session = NULL; + server_write_client(c, MSG_EXIT, NULL, 0); + } else + server_redraw_client(c); + } + } + recalculate_sizes(); +} diff --git a/tmux.1 b/tmux.1 index 9b2f344c..af7ad53d 100644 --- a/tmux.1 +++ b/tmux.1 @@ -768,6 +768,7 @@ returns success. .Xc .D1 (alias: Ic killp ) Destroy the given pane. +If no panes remain in the containing window, it is also destroyed. .It Xo Ic kill-server .Xc Kill the diff --git a/tmux.h b/tmux.h index 2a0412ba..d6bfcc4b 100644 --- a/tmux.h +++ b/tmux.h @@ -1284,6 +1284,7 @@ void server_redraw_window(struct window *); void server_status_window(struct window *); void server_lock(void); int server_unlock(const char *); +void server_kill_window(struct window *); /* status.c */ int status_redraw(struct client *); From fc6a65c6207dbefcd8b5f187148978f8d4111b2b Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 18 Jul 2009 14:59:25 +0000 Subject: [PATCH 0141/1180] Add three new session options: visual-activity, visual-bell, visual-content. If these are enabled (and the monitor-activity, bell-actio and monitor-content options are configurated appropriately), when activity, a bell, or content is detected, a message is shown. Also tidy up the bell/activity/content code in server.c slightly and fix a couple of errors. --- cmd-set-option.c | 3 ++ server.c | 88 +++++++++++++++++++++++++++++++++++++++--------- tmux.1 | 24 +++++++++++++ tmux.c | 3 ++ tmux.h | 4 +-- 5 files changed, 104 insertions(+), 18 deletions(-) diff --git a/cmd-set-option.c b/cmd-set-option.c index c9b1fd99..fc665e84 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -75,6 +75,9 @@ const struct set_option_entry set_option_table[] = { { "status-right", SET_OPTION_STRING, 0, 0, NULL }, { "status-right-length", SET_OPTION_NUMBER, 0, SHRT_MAX, NULL }, { "status-utf8", SET_OPTION_FLAG, 0, 0, NULL }, + { "visual-activity", SET_OPTION_FLAG, 0, 0, NULL }, + { "visual-bell", SET_OPTION_FLAG, 0, 0, NULL }, + { "visual-content", SET_OPTION_FLAG, 0, 0, NULL }, { NULL, 0, 0, 0, NULL } }; diff --git a/server.c b/server.c index ec1b1924..cdde3996 100644 --- a/server.c +++ b/server.c @@ -55,8 +55,7 @@ void server_handle_clients(struct pollfd **); struct client *server_accept_client(int); void server_handle_client(struct client *); void server_handle_window(struct window *, struct window_pane *); -int server_check_window_bell(struct session *, struct window *, - struct window_pane *); +int server_check_window_bell(struct session *, struct window *); int server_check_window_activity(struct session *, struct window *); int server_check_window_content(struct session *, struct window *, @@ -909,7 +908,7 @@ server_handle_window(struct window *w, struct window_pane *wp) if (s == NULL || !session_has(s, w)) continue; - update += server_check_window_bell(s, w, wp); + update += server_check_window_bell(s, w); update += server_check_window_activity(s, w); update += server_check_window_content(s, w, wp); } @@ -920,12 +919,11 @@ server_handle_window(struct window *w, struct window_pane *wp) } int -server_check_window_bell( - struct session *s, struct window *w, struct window_pane *wp) +server_check_window_bell(struct session *s, struct window *w) { struct client *c; u_int i; - int action; + int action, visual; if (!(w->flags & WINDOW_BELL)) return (0); @@ -938,19 +936,38 @@ server_check_window_bell( case BELL_ANY: if (s->flags & SESSION_UNATTACHED) break; + visual = options_get_number(&s->options, "visual-bell"); for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); - if (c != NULL && c->session == s) + if (c == NULL || c->session != s) + continue; + if (!visual) { tty_putcode(&c->tty, TTYC_BEL); + continue; + } + if (c->session->curw->window == w) { + status_message_set(c, "Bell in current window"); + continue; + } + status_message_set(c, "Bell in window %u", + winlink_find_by_window(&s->windows, w)->idx); } break; case BELL_CURRENT: - if (w->active != wp) + if (s->flags & SESSION_UNATTACHED) break; + visual = options_get_number(&s->options, "visual-bell"); for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); - if (c != NULL && c->session == s) + if (c == NULL || c->session != s) + continue; + if (c->session->curw->window != w) + continue; + if (!visual) { tty_putcode(&c->tty, TTYC_BEL); + continue; + } + status_message_set(c, "Bell in current window"); } break; } @@ -960,13 +977,33 @@ server_check_window_bell( int server_check_window_activity(struct session *s, struct window *w) { + struct client *c; + u_int i; + if (!(w->flags & WINDOW_ACTIVITY)) return (0); + if (!options_get_number(&w->options, "monitor-activity")) return (0); + if (session_alert_has_window(s, w, WINDOW_ACTIVITY)) return (0); + if (s->curw->window == w) + return (0); + session_alert_add(s, w, WINDOW_ACTIVITY); + if (s->flags & SESSION_UNATTACHED) + return (0); + if (options_get_number(&s->options, "visual-activity")) { + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c == NULL || c->session != s) + continue; + status_message_set(c, "Activity in window %u", + winlink_find_by_window(&s->windows, w)->idx); + } + } + return (1); } @@ -974,20 +1011,39 @@ int server_check_window_content( struct session *s, struct window *w, struct window_pane *wp) { - char *found, *ptr; + struct client *c; + u_int i; + char *found, *ptr; + + if (!(w->flags & WINDOW_ACTIVITY)) /* activity for new content */ + return (0); - if (!(w->flags & WINDOW_CONTENT)) - return (0); - if ((ptr = options_get_string(&w->options, "monitor-content")) == NULL) - return (0); - if (*ptr == '\0') + ptr = options_get_string(&w->options, "monitor-content"); + if (ptr == NULL || *ptr == '\0') return (0); + if (session_alert_has_window(s, w, WINDOW_CONTENT)) return (0); + if (s->curw->window == w) + return (0); + if ((found = window_pane_search(wp, ptr, NULL)) == NULL) return (0); - session_alert_add(s, w, WINDOW_CONTENT); xfree(found); + + session_alert_add(s, w, WINDOW_CONTENT); + if (s->flags & SESSION_UNATTACHED) + return (0); + if (options_get_number(&s->options, "visual-content")) { + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c == NULL || c->session != s) + continue; + status_message_set(c, "Content in window %u", + winlink_find_by_window(&s->windows, w)->idx); + } + } + return (1); } diff --git a/tmux.1 b/tmux.1 index af7ad53d..e7041ec1 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1324,6 +1324,30 @@ and .Ic status-right strings as UTF-8; notably, this is important for wide characters. This option defaults to off. +.It Xo Ic visual-activity +.Op Ic on | Ic off +.Xc +If on, display a status line message when activity occurs in a window +for with the +.Ic monitor-activity +window option is enabled. +.It Xo Ic visual-bell +.Op Ic on | Ic off +.Xc +If this option is on, a message is shown on a bell instead of it being passed +through to the terminal (which normally makes a sound). +Also see the +.Ic bell-action +option. +.It Xo Ic visual-content +.Op Ic on | Ic off +.Xc +Like +.Ic visual-activity , +display a message when content is present in a window +for with the +.Ic monitor-content +window option is enabled. .El .It Xo Ic set-password .Op Fl c diff --git a/tmux.c b/tmux.c index a5edb460..5cca15f6 100644 --- a/tmux.c +++ b/tmux.c @@ -312,6 +312,9 @@ main(int argc, char **argv) options_set_number(&global_s_options, "status-utf8", 1); else options_set_number(&global_s_options, "status-utf8", 0); + options_set_number(&global_s_options, "visual-activity", 0); + options_set_number(&global_s_options, "visual-bell", 0); + options_set_number(&global_s_options, "visual-content", 0); options_init(&global_w_options, NULL); options_set_number(&global_w_options, "aggressive-resize", 0); diff --git a/tmux.h b/tmux.h index d6bfcc4b..62c399f3 100644 --- a/tmux.h +++ b/tmux.h @@ -644,8 +644,8 @@ struct window { #define WINDOW_BELL 0x1 #define WINDOW_HIDDEN 0x2 #define WINDOW_ACTIVITY 0x4 -#define WINDOW_CONTENT 0x6 -#define WINDOW_REDRAW 0x8 +#define WINDOW_CONTENT 0x8 +#define WINDOW_REDRAW 0x10 struct options options; From 6036bdd06cba9fa500098f1f17983d62955b24e5 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 19 Jul 2009 13:21:40 +0000 Subject: [PATCH 0142/1180] Improved layout code. Each window now has a tree of layout cells associated with it. In this tree, each node is either a horizontal or vertical cell containing a list of other cells running from left-to-right or top-to-bottom, or a leaf cell which is associated with a pane. The major functional changes are: - panes may now be split arbitrarily both horizontally (splitw -h, C-b %) and vertically (splitw -v, C-b "); - panes may be resized both horizontally and vertically (resizep -L/-R/-U/-D, bound to C-b left/right/up/down and C-b M-left/right/up/down); - layouts are now applied and then may be modified by resizing or splitting panes, rather than being fixed and reapplied when the window is resized or panes are added; - manual-vertical layout is no longer necessary, and active-only layout is gone (but may return in future); - the main-pane layouts now reduce the size of the main pane to fit all panes if possible. Thanks to all who tested. --- Makefile | 2 +- cmd-break-pane.c | 4 +- cmd-choose-window.c | 4 +- cmd-down-pane.c | 1 - cmd-kill-pane.c | 2 +- cmd-list-windows.c | 5 +- cmd-next-layout.c | 5 +- cmd-previous-layout.c | 7 +- cmd-resize-pane.c | 35 +- cmd-respawn-window.c | 2 + cmd-rotate-window.c | 19 +- cmd-select-layout.c | 22 +- cmd-select-pane.c | 1 - cmd-split-window.c | 97 +++-- cmd-swap-pane.c | 14 +- cmd-up-pane.c | 1 - key-bindings.c | 13 +- layout-manual.c | 172 --------- layout-set.c | 436 +++++++++++++++++++++ layout.c | 869 ++++++++++++++++++++++++++++-------------- resize.c | 2 +- server.c | 6 +- tmux.1 | 81 ++-- tmux.h | 81 +++- window.c | 53 +-- 25 files changed, 1298 insertions(+), 636 deletions(-) delete mode 100644 layout-manual.c create mode 100644 layout-set.c diff --git a/Makefile b/Makefile index 6f6644a0..924ac4ec 100644 --- a/Makefile +++ b/Makefile @@ -27,7 +27,7 @@ SRCS= attributes.c buffer-poll.c buffer.c cfg.c client-fn.c \ cmd-switch-client.c cmd-unbind-key.c cmd-unlink-window.c \ cmd-up-pane.c cmd-display-message.c cmd.c \ colour.c grid-view.c grid.c input-keys.c \ - input.c key-bindings.c key-string.c layout-manual.c layout.c log.c \ + input.c key-bindings.c key-string.c layout-set.c layout.c log.c \ mode-key.c names.c options-cmd.c options.c paste.c procname.c \ resize.c screen-redraw.c screen-write.c screen.c server-fn.c \ server-msg.c server.c session.c status.c tmux.c tty-keys.c tty-term.c \ diff --git a/cmd-break-pane.c b/cmd-break-pane.c index 74e052d5..8eeb7f42 100644 --- a/cmd-break-pane.c +++ b/cmd-break-pane.c @@ -74,17 +74,17 @@ cmd_break_pane_exec(struct cmd *self, struct cmd_ctx *ctx) if (wl->window->active == NULL) wl->window->active = TAILQ_NEXT(wp, entry); } - layout_refresh(wl->window, 0); + layout_close_pane(wp); w = wp->window = window_create1(s->sx, s->sy); TAILQ_INSERT_HEAD(&w->panes, wp, entry); w->active = wp; w->name = default_window_name(w); + layout_init(w); wl = session_attach(s, w, -1, &cause); /* can't fail */ if (!(data->chflags & CMD_CHFLAG('d'))) session_select(s, wl->idx); - layout_refresh(w, 0); server_redraw_session(s); diff --git a/cmd-choose-window.c b/cmd-choose-window.c index 33487e27..80a2518e 100644 --- a/cmd-choose-window.c +++ b/cmd-choose-window.c @@ -76,8 +76,8 @@ cmd_choose_window_exec(struct cmd *self, struct cmd_ctx *ctx) idx++; window_choose_add(wl->window->active, - wm->idx, "%3d: %s [%ux%u %s] (%u panes)", wm->idx, w->name, - w->sx, w->sy, layout_name(w), window_count_panes(w)); + wm->idx, "%3d: %s [%ux%u] (%u panes)", + wm->idx, w->name, w->sx, w->sy, window_count_panes(w)); } cdata = xmalloc(sizeof *cdata); diff --git a/cmd-down-pane.c b/cmd-down-pane.c index 73736946..640ad5bd 100644 --- a/cmd-down-pane.c +++ b/cmd-down-pane.c @@ -54,7 +54,6 @@ cmd_down_pane_exec(struct cmd *self, struct cmd_ctx *ctx) w->active = TAILQ_NEXT(w->active, entry); if (w->active == NULL) w->active = TAILQ_FIRST(&w->panes); - layout_refresh(w, 1); } while (!window_pane_visible(w->active)); return (0); diff --git a/cmd-kill-pane.c b/cmd-kill-pane.c index b501e416..d219f399 100644 --- a/cmd-kill-pane.c +++ b/cmd-kill-pane.c @@ -66,8 +66,8 @@ cmd_kill_pane_exec(struct cmd *self, struct cmd_ctx *ctx) return (0); } + layout_close_pane(wp); window_remove_pane(wl->window, wp); server_redraw_window(wl->window); - layout_refresh(wl->window, 0); return (0); } diff --git a/cmd-list-windows.c b/cmd-list-windows.c index 8b2162a5..197d683f 100644 --- a/cmd-list-windows.c +++ b/cmd-list-windows.c @@ -78,9 +78,8 @@ cmd_list_windows_exec(struct cmd *self, struct cmd_ctx *ctx) else name = "unknown"; ctx->print(ctx, - " %s [%ux%u %s] [history %u/%u, %llu bytes]", - name, wp->sx, wp->sy, layout_name(w), gd->hsize, - gd->hlimit, size); + " %s [%ux%u] [history %u/%u, %llu bytes]", + name, wp->sx, wp->sy, gd->hsize, gd->hlimit, size); } } diff --git a/cmd-next-layout.c b/cmd-next-layout.c index b89dda3d..088046fa 100644 --- a/cmd-next-layout.c +++ b/cmd-next-layout.c @@ -44,12 +44,13 @@ cmd_next_layout_exec(struct cmd *self, struct cmd_ctx *ctx) { struct cmd_target_data *data = self->data; struct winlink *wl; + u_int layout; if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) return (-1); - layout_next(wl->window); - ctx->info(ctx, "layout now: %s", layout_name(wl->window)); + layout = layout_set_next(wl->window); + ctx->info(ctx, "arranging in: %s", layout_set_name(layout)); return (0); } diff --git a/cmd-previous-layout.c b/cmd-previous-layout.c index f4270f14..44071eb5 100644 --- a/cmd-previous-layout.c +++ b/cmd-previous-layout.c @@ -44,12 +44,13 @@ cmd_previous_layout_exec(struct cmd *self, struct cmd_ctx *ctx) { struct cmd_target_data *data = self->data; struct winlink *wl; - + u_int layout; + if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) return (-1); - layout_previous(wl->window); - ctx->info(ctx, "layout now: %s", layout_name(wl->window)); + layout = layout_set_previous(wl->window); + ctx->info(ctx, "arranging in: %s", layout_set_name(layout)); return (0); } diff --git a/cmd-resize-pane.c b/cmd-resize-pane.c index 64ac95b2..5e9f67e3 100644 --- a/cmd-resize-pane.c +++ b/cmd-resize-pane.c @@ -32,7 +32,8 @@ int cmd_resize_pane_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_resize_pane_entry = { "resize-pane", "resizep", CMD_PANE_WINDOW_USAGE "[-DU] [adjustment]", - CMD_ARG01, CMD_CHFLAG('D')|CMD_CHFLAG('U'), + CMD_ARG01, + CMD_CHFLAG('D')|CMD_CHFLAG('L')|CMD_CHFLAG('R')|CMD_CHFLAG('U'), cmd_resize_pane_init, cmd_pane_parse, cmd_resize_pane_exec, @@ -50,15 +51,31 @@ cmd_resize_pane_init(struct cmd *self, int key) cmd_pane_init(self, key); data = self->data; + if (key == KEYC_ADDCTL(KEYC_UP)) + data->chflags |= CMD_CHFLAG('U'); if (key == KEYC_ADDCTL(KEYC_DOWN)) data->chflags |= CMD_CHFLAG('D'); + if (key == KEYC_ADDCTL(KEYC_LEFT)) + data->chflags |= CMD_CHFLAG('L'); + if (key == KEYC_ADDCTL(KEYC_RIGHT)) + data->chflags |= CMD_CHFLAG('R'); - if (key == KEYC_ADDESC(KEYC_UP)) + if (key == KEYC_ADDESC(KEYC_UP)) { + data->chflags |= CMD_CHFLAG('U'); data->arg = xstrdup("5"); + } if (key == KEYC_ADDESC(KEYC_DOWN)) { data->chflags |= CMD_CHFLAG('D'); data->arg = xstrdup("5"); } + if (key == KEYC_ADDESC(KEYC_LEFT)) { + data->chflags |= CMD_CHFLAG('L'); + data->arg = xstrdup("5"); + } + if (key == KEYC_ADDESC(KEYC_RIGHT)) { + data->chflags |= CMD_CHFLAG('R'); + data->arg = xstrdup("5"); + } } int @@ -92,12 +109,14 @@ cmd_resize_pane_exec(struct cmd *self, struct cmd_ctx *ctx) } } - if (!(data->chflags & CMD_CHFLAG('D'))) - adjust = -adjust; - if (layout_resize(wp, adjust) != 0) { - ctx->error(ctx, "layout %s " - "does not support resizing", layout_name(wp->window)); - return (-1); + if (data->chflags & (CMD_CHFLAG('L')|CMD_CHFLAG('R'))) { + if (data->chflags & CMD_CHFLAG('L')) + adjust = -adjust; + layout_resize_pane(wp, LAYOUT_LEFTRIGHT, adjust); + } else { + if (data->chflags & CMD_CHFLAG('U')) + adjust = -adjust; + layout_resize_pane(wp, LAYOUT_TOPBOTTOM, adjust); } server_redraw_window(wl->window); diff --git a/cmd-respawn-window.c b/cmd-respawn-window.c index 5d70aa63..3a795461 100644 --- a/cmd-respawn-window.c +++ b/cmd-respawn-window.c @@ -70,6 +70,7 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_ctx *ctx) wp = TAILQ_FIRST(&w->panes); TAILQ_REMOVE(&w->panes, wp, entry); + layout_free(w); window_destroy_panes(w); TAILQ_INSERT_HEAD(&w->panes, wp, entry); window_pane_resize(wp, w->sx, w->sy); @@ -78,6 +79,7 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_ctx *ctx) xfree(cause); return (-1); } + layout_init(w); screen_reinit(&wp->base); recalculate_sizes(); diff --git a/cmd-rotate-window.c b/cmd-rotate-window.c index e730dc59..c69fa8d1 100644 --- a/cmd-rotate-window.c +++ b/cmd-rotate-window.c @@ -59,6 +59,7 @@ cmd_rotate_window_exec(struct cmd *self, struct cmd_ctx *ctx) struct winlink *wl; struct window *w; struct window_pane *wp, *wp2; + struct layout_cell *lc; u_int sx, sy, xoff, yoff; if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) @@ -70,42 +71,56 @@ cmd_rotate_window_exec(struct cmd *self, struct cmd_ctx *ctx) TAILQ_REMOVE(&w->panes, wp, entry); TAILQ_INSERT_HEAD(&w->panes, wp, entry); + lc = wp->layout_cell; xoff = wp->xoff; yoff = wp->yoff; sx = wp->sx; sy = wp->sy; TAILQ_FOREACH(wp, &w->panes, entry) { if ((wp2 = TAILQ_NEXT(wp, entry)) == NULL) break; + wp->layout_cell = wp2->layout_cell; + if (wp->layout_cell != NULL) + wp->layout_cell->wp = wp; wp->xoff = wp2->xoff; wp->yoff = wp2->yoff; window_pane_resize(wp, wp2->sx, wp2->sy); } + wp->layout_cell = lc; + if (wp->layout_cell != NULL) + wp->layout_cell->wp = wp; wp->xoff = xoff; wp->yoff = yoff; window_pane_resize(wp, sx, sy); if ((wp = TAILQ_PREV(w->active, window_panes, entry)) == NULL) wp = TAILQ_LAST(&w->panes, window_panes); window_set_active_pane(w, wp); + server_redraw_window(w); } else { wp = TAILQ_FIRST(&w->panes); TAILQ_REMOVE(&w->panes, wp, entry); TAILQ_INSERT_TAIL(&w->panes, wp, entry); + lc = wp->layout_cell; xoff = wp->xoff; yoff = wp->yoff; sx = wp->sx; sy = wp->sy; TAILQ_FOREACH_REVERSE(wp, &w->panes, window_panes, entry) { if ((wp2 = TAILQ_PREV(wp, window_panes, entry)) == NULL) break; + wp->layout_cell = wp2->layout_cell; + if (wp->layout_cell != NULL) + wp->layout_cell->wp = wp; wp->xoff = wp2->xoff; wp->yoff = wp2->yoff; window_pane_resize(wp, wp2->sx, wp2->sy); } + wp->layout_cell = lc; + if (wp->layout_cell != NULL) + wp->layout_cell->wp = wp; wp->xoff = xoff; wp->yoff = yoff; window_pane_resize(wp, sx, sy); if ((wp = TAILQ_NEXT(w->active, entry)) == NULL) wp = TAILQ_FIRST(&w->panes); window_set_active_pane(w, wp); + server_redraw_window(w); } - layout_refresh(w, 0); - return (0); } diff --git a/cmd-select-layout.c b/cmd-select-layout.c index 01d7ef6e..953cb69f 100644 --- a/cmd-select-layout.c +++ b/cmd-select-layout.c @@ -49,17 +49,17 @@ cmd_select_layout_init(struct cmd *self, int key) data = self->data; switch (key) { - case KEYC_ADDESC('0'): - data->arg = xstrdup("manual-vertical"); - break; case KEYC_ADDESC('1'): data->arg = xstrdup("even-horizontal"); break; case KEYC_ADDESC('2'): data->arg = xstrdup("even-vertical"); break; - case KEYC_ADDESC('9'): - data->arg = xstrdup("active-only"); + case KEYC_ADDESC('3'): + data->arg = xstrdup("main-horizontal"); + break; + case KEYC_ADDESC('4'): + data->arg = xstrdup("main-vertical"); break; } } @@ -74,13 +74,13 @@ cmd_select_layout_exec(struct cmd *self, struct cmd_ctx *ctx) if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) return (-1); - if ((layout = layout_lookup(data->arg)) == -1) { - ctx->error(ctx, "unknown or ambiguous layout: %s", data->arg); - return (-1); - } + if ((layout = layout_set_lookup(data->arg)) == -1) { + ctx->error(ctx, "unknown or ambiguous layout: %s", data->arg); + return (-1); + } - if (layout_select(wl->window, layout) == 0) - ctx->info(ctx, "layout now: %s", layout_name(wl->window)); + layout = layout_set_select(wl->window, layout); + ctx->info(ctx, "arranging in: %s", layout_set_name(layout)); return (0); } diff --git a/cmd-select-pane.c b/cmd-select-pane.c index d112f919..6a9dec42 100644 --- a/cmd-select-pane.c +++ b/cmd-select-pane.c @@ -63,7 +63,6 @@ cmd_select_pane_exec(struct cmd *self, struct cmd_ctx *ctx) return (-1); } window_set_active_pane(wl->window, wp); - layout_refresh(wl->window, 1); return (0); } diff --git a/cmd-split-window.c b/cmd-split-window.c index 74d28313..f1b21d51 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -39,13 +39,14 @@ struct cmd_split_window_data { char *target; char *cmd; int flag_detached; + int flag_horizontal; int percentage; - int lines; + int size; }; const struct cmd_entry cmd_split_window_entry = { "split-window", "splitw", - "[-d] [-p percentage|-l lines] [-t target-window] [command]", + "[-dhv] [-p percentage|-l size] [-t target-window] [command]", 0, 0, cmd_split_window_init, cmd_split_window_parse, @@ -57,7 +58,7 @@ const struct cmd_entry cmd_split_window_entry = { }; void -cmd_split_window_init(struct cmd *self, unused int arg) +cmd_split_window_init(struct cmd *self, int key) { struct cmd_split_window_data *data; @@ -65,50 +66,63 @@ cmd_split_window_init(struct cmd *self, unused int arg) data->target = NULL; data->cmd = NULL; data->flag_detached = 0; + data->flag_horizontal = 0; data->percentage = -1; - data->lines = -1; + data->size = -1; + + switch (key) { + case '%': + data->flag_horizontal = 1; + break; + case '"': + data->flag_horizontal = 0; + break; + } } int cmd_split_window_parse(struct cmd *self, int argc, char **argv, char **cause) { struct cmd_split_window_data *data; - int opt, n; + int opt; const char *errstr; self->entry->init(self, 0); data = self->data; - while ((opt = getopt(argc, argv, "dl:p:t:")) != -1) { + while ((opt = getopt(argc, argv, "dhl:p:t:v")) != -1) { switch (opt) { case 'd': data->flag_detached = 1; break; + case 'h': + data->flag_horizontal = 1; + break; case 't': if (data->target == NULL) data->target = xstrdup(optarg); break; case 'l': - if (data->percentage == -1 && data->lines == -1) { - n = strtonum(optarg, 1, INT_MAX, &errstr); - if (errstr != NULL) { - xasprintf(cause, "lines %s", errstr); - goto error; - } - data->lines = n; + if (data->percentage != -1 || data->size != -1) + break; + data->size = strtonum(optarg, 1, INT_MAX, &errstr); + if (errstr != NULL) { + xasprintf(cause, "size %s", errstr); + goto error; } break; case 'p': - if (data->lines == -1 && data->percentage == -1) { - n = strtonum(optarg, 1, 100, &errstr); - if (errstr != NULL) { - xasprintf( - cause, "percentage %s", errstr); - goto error; - } - data->percentage = n; + if (data->size != -1 || data->percentage != -1) + break; + data->percentage = strtonum(optarg, 1, 100, &errstr); + if (errstr != NULL) { + xasprintf(cause, "percentage %s", errstr); + goto error; } break; + case 'v': + data->flag_horizontal = 0; + break; default: goto usage; } @@ -142,7 +156,8 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) const char **env; char *cmd, *cwd, *cause; u_int hlimit; - int lines; + int size; + enum layout_type type; if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL) return (-1); @@ -158,19 +173,27 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) else cwd = ctx->cmdclient->cwd; - lines = -1; - if (data->lines != -1) - lines = data->lines; + size = -1; + if (data->size != -1) + size = data->size; else if (data->percentage != -1) - lines = (w->active->sy * data->percentage) / 100; - + size = (w->active->sy * data->percentage) / 100; hlimit = options_get_number(&s->options, "history-limit"); - wp = window_add_pane(w, lines, cmd, cwd, env, hlimit, &cause); - if (wp == NULL) { - ctx->error(ctx, "create pane failed: %s", cause); - xfree(cause); - return (-1); + + type = LAYOUT_TOPBOTTOM; + if (data->flag_horizontal) + type = LAYOUT_LEFTRIGHT; + + wp = window_add_pane(w, hlimit, &cause); + if (wp == NULL) + goto error; + if (window_pane_spawn(wp, cmd, cwd, env, &cause) != 0) + goto error; + if (layout_split_pane(w->active, type, size, wp) != 0) { + cause = xstrdup("pane too small"); + goto error; } + server_redraw_window(w); if (!data->flag_detached) { @@ -179,9 +202,15 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) server_redraw_session(s); } else server_status_session(s); - layout_refresh(w, 0); return (0); + +error: + if (wp != NULL) + window_remove_pane(w, wp); + ctx->error(ctx, "create pane failed: %s", cause); + xfree(cause); + return (-1); } void @@ -228,6 +257,8 @@ cmd_split_window_print(struct cmd *self, char *buf, size_t len) return (off); if (off < len && data->flag_detached) off += xsnprintf(buf + off, len - off, " -d"); + if (off < len && data->flag_horizontal) + off += xsnprintf(buf + off, len - off, " -h"); if (off < len && data->target != NULL) off += cmd_prarg(buf + off, len - off, " -t ", data->target); if (off < len && data->cmd != NULL) diff --git a/cmd-swap-pane.c b/cmd-swap-pane.c index 1c3cb508..0f0633d8 100644 --- a/cmd-swap-pane.c +++ b/cmd-swap-pane.c @@ -157,6 +157,7 @@ cmd_swap_pane_exec(struct cmd *self, struct cmd_ctx *ctx) struct winlink *wl; struct window *w; struct window_pane *tmp_wp, *src_wp, *dst_wp; + struct layout_cell *lc; u_int xx, yy; if (data == NULL) @@ -207,12 +208,15 @@ cmd_swap_pane_exec(struct cmd *self, struct cmd_ctx *ctx) else TAILQ_INSERT_AFTER(&w->panes, tmp_wp, src_wp, entry); + lc = src_wp->layout_cell; xx = src_wp->xoff; yy = src_wp->yoff; - src_wp->xoff = dst_wp->xoff; - src_wp->yoff = dst_wp->yoff; - dst_wp->xoff = xx; - dst_wp->yoff = yy; + src_wp->layout_cell = dst_wp->layout_cell; + if (src_wp->layout_cell != NULL) + src_wp->layout_cell->wp = src_wp; + dst_wp->layout_cell = lc; + if (dst_wp->layout_cell != NULL) + dst_wp->layout_cell->wp = dst_wp; xx = src_wp->sx; yy = src_wp->sy; @@ -224,8 +228,8 @@ cmd_swap_pane_exec(struct cmd *self, struct cmd_ctx *ctx) if (!window_pane_visible(tmp_wp)) tmp_wp = src_wp; window_set_active_pane(w, tmp_wp); - layout_refresh(w, 0); } + server_redraw_window(w); return (0); } diff --git a/cmd-up-pane.c b/cmd-up-pane.c index 2f092ece..8b262c60 100644 --- a/cmd-up-pane.c +++ b/cmd-up-pane.c @@ -54,7 +54,6 @@ cmd_up_pane_exec(struct cmd *self, struct cmd_ctx *ctx) w->active = TAILQ_PREV(w->active, window_panes, entry); if (w->active == NULL) w->active = TAILQ_LAST(&w->panes, window_panes); - layout_refresh(w, 1); } while (!window_pane_visible(w->active)); return (0); diff --git a/key-bindings.c b/key-bindings.c index c298c79d..66ed4927 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -93,7 +93,8 @@ key_bindings_init(void) } table[] = { { ' ', 0, &cmd_next_layout_entry }, { '!', 0, &cmd_break_pane_entry }, - { '"', 0, &cmd_split_window_entry }, + { '"', 0, &cmd_split_window_entry }, + { '%', 0, &cmd_split_window_entry }, { '#', 0, &cmd_list_buffers_entry }, { '&', 0, &cmd_confirm_before_entry }, { ',', 0, &cmd_command_prompt_entry }, @@ -132,10 +133,10 @@ key_bindings_init(void) { '{', 0, &cmd_swap_pane_entry }, { '}', 0, &cmd_swap_pane_entry }, { '\002', 0, &cmd_send_prefix_entry }, - { KEYC_ADDESC('0'), 0, &cmd_select_layout_entry }, { KEYC_ADDESC('1'), 0, &cmd_select_layout_entry }, { KEYC_ADDESC('2'), 0, &cmd_select_layout_entry }, - { KEYC_ADDESC('9'), 0, &cmd_select_layout_entry }, + { KEYC_ADDESC('3'), 0, &cmd_select_layout_entry }, + { KEYC_ADDESC('4'), 0, &cmd_select_layout_entry }, { KEYC_PPAGE, 0, &cmd_scroll_mode_entry }, { KEYC_ADDESC('n'), 0, &cmd_next_window_entry }, { KEYC_ADDESC('p'), 0, &cmd_previous_window_entry }, @@ -143,8 +144,12 @@ key_bindings_init(void) { KEYC_DOWN, 0, &cmd_down_pane_entry }, { KEYC_ADDESC(KEYC_UP), 1, &cmd_resize_pane_entry }, { KEYC_ADDESC(KEYC_DOWN), 1, &cmd_resize_pane_entry }, + { KEYC_ADDESC(KEYC_LEFT), 1, &cmd_resize_pane_entry }, + { KEYC_ADDESC(KEYC_RIGHT),1, &cmd_resize_pane_entry }, { KEYC_ADDCTL(KEYC_UP), 1, &cmd_resize_pane_entry }, - { KEYC_ADDCTL(KEYC_DOWN), 1, &cmd_resize_pane_entry }, + { KEYC_ADDCTL(KEYC_DOWN), 1, &cmd_resize_pane_entry }, + { KEYC_ADDCTL(KEYC_LEFT), 1, &cmd_resize_pane_entry }, + { KEYC_ADDCTL(KEYC_RIGHT),1, &cmd_resize_pane_entry }, { KEYC_ADDESC('o'), 0, &cmd_rotate_window_entry }, { '\017', 0, &cmd_rotate_window_entry }, }; diff --git a/layout-manual.c b/layout-manual.c deleted file mode 100644 index 7edce667..00000000 --- a/layout-manual.c +++ /dev/null @@ -1,172 +0,0 @@ -/* $OpenBSD$ */ - -/* - * Copyright (c) 2009 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" - -void layout_manual_v_update_offsets(struct window *); - -void -layout_manual_v_refresh(struct window *w, unused int active_only) -{ - struct window_pane *wp; - u_int npanes, total, height; - int left; - - if (active_only) - return; - - if (TAILQ_EMPTY(&w->panes)) - return; - - /* Check the new size. */ - npanes = window_count_panes(w); - if (w->sy <= PANE_MINIMUM * npanes) { - /* - * Make the first pane the smaller of the minimum and total (it - * must fit to be visible) and the rest the minimum size. - */ - height = PANE_MINIMUM; - if (height > w->sy) - height = w->sy + 1; - TAILQ_FOREACH(wp, &w->panes, entry) { - if (wp == TAILQ_FIRST(&w->panes)) - wp->sy = height - 1; - else - wp->sy = PANE_MINIMUM - 1; - } - /* And increase the first by the rest if possible. */ - if (w->sy >= PANE_MINIMUM) - TAILQ_FIRST(&w->panes)->sy += 1 + w->sy % PANE_MINIMUM; - } else { - /* In theory they will all fit. Find the current total. */ - total = 0; - TAILQ_FOREACH(wp, &w->panes, entry) - total += wp->sy; - total += npanes - 1; - - /* Growing or shrinking? */ - left = w->sy - total; - if (left > 0) { - /* Growing. Expand evenly. */ - while (left > 0) { - TAILQ_FOREACH(wp, &w->panes, entry) { - wp->sy++; - if (--left == 0) - break; - } - } - } else { - /* Shrinking. Reduce evenly down to minimum. */ - while (left < 0) { - TAILQ_FOREACH(wp, &w->panes, entry) { - if (wp->sy <= PANE_MINIMUM - 1) - continue; - wp->sy--; - if (++left == 0) - break; - } - } - } - } - - /* Now do the resize. */ - TAILQ_FOREACH(wp, &w->panes, entry) { - wp->sy--; - window_pane_resize(wp, w->sx, wp->sy + 1); - } - - /* Fill in the offsets. */ - layout_manual_v_update_offsets(w); - - /* Switch the active window if necessary. */ - window_set_active_pane(w, w->active); -} - -void -layout_manual_v_resize(struct window_pane *wp, int adjust) -{ - struct window *w = wp->window; - struct window_pane *wq; - - if (adjust > 0) { - /* - * If this is not the last pane, keep trying to increase size - * and remove it from the next panes. If it is the last, do - * so on the previous pane. - */ - if (TAILQ_NEXT(wp, entry) == NULL) { - if (wp == TAILQ_FIRST(&w->panes)) { - /* Only one pane. */ - return; - } - wp = TAILQ_PREV(wp, window_panes, entry); - } - while (adjust-- > 0) { - wq = wp; - while ((wq = TAILQ_NEXT(wq, entry)) != NULL) { - if (wq->sy <= PANE_MINIMUM) - continue; - window_pane_resize(wq, wq->sx, wq->sy - 1); - break; - } - if (wq == NULL) - break; - window_pane_resize(wp, wp->sx, wp->sy + 1); - } - } else { - adjust = -adjust; - /* - * If this is not the last pane, keep trying to reduce size - * and add to the following pane. If it is the last, do so on - * the previous pane. - */ - wq = TAILQ_NEXT(wp, entry); - if (wq == NULL) { - if (wp == TAILQ_FIRST(&w->panes)) { - /* Only one pane. */ - return; - } - wq = wp; - wp = TAILQ_PREV(wq, window_panes, entry); - } - while (adjust-- > 0) { - if (wp->sy <= PANE_MINIMUM) - break; - window_pane_resize(wq, wq->sx, wq->sy + 1); - window_pane_resize(wp, wp->sx, wp->sy - 1); - } - } - - layout_manual_v_update_offsets(w); -} - -void -layout_manual_v_update_offsets(struct window *w) -{ - struct window_pane *wp; - u_int yoff; - - yoff = 0; - TAILQ_FOREACH(wp, &w->panes, entry) { - wp->xoff = 0; - wp->yoff = yoff; - yoff += wp->sy + 1; - } -} diff --git a/layout-set.c b/layout-set.c new file mode 100644 index 00000000..ae99f6ff --- /dev/null +++ b/layout-set.c @@ -0,0 +1,436 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2009 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 "tmux.h" + +/* + * Set window layouts - predefined methods to arrange windows. These are one-off + * and generate a layout tree. + */ + +void layout_set_even_h(struct window *); +void layout_set_even_v(struct window *); +void layout_set_main_h(struct window *); +void layout_set_main_v(struct window *); + +const struct { + const char *name; + void (*arrange)(struct window *); +} layout_sets[] = { + { "even-horizontal", layout_set_even_h }, + { "even-vertical", layout_set_even_v }, + { "main-horizontal", layout_set_main_h }, + { "main-vertical", layout_set_main_v }, +}; + +const char * +layout_set_name(u_int layout) +{ + return (layout_sets[layout].name); +} + +int +layout_set_lookup(const char *name) +{ + u_int i; + int matched = -1; + + for (i = 0; i < nitems(layout_sets); i++) { + if (strncmp(layout_sets[i].name, name, strlen(name)) == 0) { + if (matched != -1) /* ambiguous */ + return (-1); + matched = i; + } + } + + return (matched); +} + +u_int +layout_set_select(struct window *w, u_int layout) +{ + if (layout > nitems(layout_sets) - 1) + layout = nitems(layout_sets) - 1; + + if (layout_sets[layout].arrange != NULL) + layout_sets[layout].arrange(w); + + w->layout = layout; + return (layout); +} + +u_int +layout_set_next(struct window *w) +{ + u_int layout = w->layout; + + if (layout_sets[layout].arrange != NULL) + layout_sets[layout].arrange(w); + + w->layout++; + if (w->layout > nitems(layout_sets) - 1) + w->layout = 0; + return (layout); +} + +u_int +layout_set_previous(struct window *w) +{ + u_int layout = w->layout; + + if (layout_sets[layout].arrange != NULL) + layout_sets[layout].arrange(w); + + if (w->layout == 0) + w->layout = nitems(layout_sets) - 1; + else + w->layout--; + return (layout); +} + +void +layout_set_even_h(struct window *w) +{ + struct window_pane *wp; + struct layout_cell *lc, *lcnew; + u_int i, n, width, xoff; + + layout_print_cell(w->layout_root, __func__, 1); + + /* Get number of panes. */ + n = window_count_panes(w); + if (n <= 1) + return; + + /* How many can we fit? */ + if (w->sx / n < PANE_MINIMUM + 1) { + width = PANE_MINIMUM + 1; + n = UINT_MAX; + } else + width = w->sx / n; + + /* Free the old root and construct a new. */ + layout_free(w); + lc = w->layout_root = layout_create_cell(NULL); + layout_set_size(lc, w->sx, w->sy, 0, 0); + layout_make_node(lc, LAYOUT_LEFTRIGHT); + + /* Build new leaf cells. */ + i = xoff = 0; + TAILQ_FOREACH(wp, &w->panes, entry) { + /* Create child cell. */ + lcnew = layout_create_cell(lc); + layout_set_size(lcnew, width - 1, w->sy, xoff, 0); + layout_make_leaf(lcnew, wp); + TAILQ_INSERT_TAIL(&lc->cells, lcnew, entry); + + i++; + xoff += width; + } + + /* Allocate any remaining space. */ + if (w->sx > xoff - 1) { + lc = TAILQ_LAST(&lc->cells, layout_cells); + layout_resize_adjust(lc, LAYOUT_LEFTRIGHT, w->sx - (xoff - 1)); + } + + /* Fix cell offsets. */ + layout_fix_offsets(lc); + layout_fix_panes(w, w->sx, w->sy); + + layout_print_cell(w->layout_root, __func__, 1); + + server_redraw_window(w); +} + +void +layout_set_even_v(struct window *w) +{ + struct window_pane *wp; + struct layout_cell *lc, *lcnew; + u_int i, n, height, yoff; + + layout_print_cell(w->layout_root, __func__, 1); + + /* Get number of panes. */ + n = window_count_panes(w); + if (n <= 1) + return; + + /* How many can we fit? */ + if (w->sy / n < PANE_MINIMUM + 1) { + height = PANE_MINIMUM + 1; + n = UINT_MAX; + } else + height = w->sy / n; + + /* Free the old root and construct a new. */ + layout_free(w); + lc = w->layout_root = layout_create_cell(NULL); + layout_set_size(lc, w->sx, w->sy, 0, 0); + layout_make_node(lc, LAYOUT_TOPBOTTOM); + + /* Build new leaf cells. */ + i = yoff = 0; + TAILQ_FOREACH(wp, &w->panes, entry) { + /* Create child cell. */ + lcnew = layout_create_cell(lc); + layout_set_size(lcnew, w->sx, height - 1, 0, yoff); + layout_make_leaf(lcnew, wp); + TAILQ_INSERT_TAIL(&lc->cells, lcnew, entry); + + i++; + yoff += height; + } + + /* Allocate any remaining space. */ + if (w->sy > yoff - 1) { + lc = TAILQ_LAST(&lc->cells, layout_cells); + layout_resize_adjust(lc, LAYOUT_TOPBOTTOM, w->sy - (yoff - 1)); + } + + /* Fix cell offsets. */ + layout_fix_offsets(lc); + layout_fix_panes(w, w->sx, w->sy); + + layout_print_cell(w->layout_root, __func__, 1); + + server_redraw_window(w); +} + +void +layout_set_main_h(struct window *w) +{ + struct window_pane *wp; + struct layout_cell *lc, *lcmain, *lcrow, *lcchild; + u_int n, mainheight, width, height, used; + u_int i, j, columns, rows, totalrows; + + layout_print_cell(w->layout_root, __func__, 1); + + /* Get number of panes. */ + n = window_count_panes(w); + if (n <= 1) + return; + n--; /* take off main pane */ + + /* How many rows and columns will be needed? */ + columns = w->sx / (PANE_MINIMUM + 1); /* maximum columns */ + rows = 1 + (n - 1) / columns; + columns = 1 + (n - 1) / rows; + width = w->sx / columns; + + /* Get the main pane height and add one for separator line. */ + mainheight = options_get_number(&w->options, "main-pane-height") + 1; + if (mainheight < PANE_MINIMUM + 1) + mainheight = PANE_MINIMUM + 1; + + /* Try and make everything fit. */ + totalrows = rows * (PANE_MINIMUM + 1) - 1; + if (mainheight + totalrows > w->sy) { + if (totalrows + PANE_MINIMUM + 1 > w->sy) + mainheight = PANE_MINIMUM + 2; + else + mainheight = w->sy - totalrows; + height = PANE_MINIMUM + 1; + } else + height = (w->sy - mainheight) / rows; + + /* Free old tree and create a new root. */ + layout_free(w); + lc = w->layout_root = layout_create_cell(NULL); + layout_set_size(lc, w->sx, mainheight + rows * height, 0, 0); + layout_make_node(lc, LAYOUT_TOPBOTTOM); + + /* Create the main pane. */ + lcmain = layout_create_cell(lc); + layout_set_size(lcmain, w->sx, mainheight - 1, 0, 0); + layout_make_leaf(lcmain, TAILQ_FIRST(&w->panes)); + TAILQ_INSERT_TAIL(&lc->cells, lcmain, entry); + + /* Create a grid of the remaining cells. */ + wp = TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry); + for (j = 0; j < rows; j++) { + /* If this is the last cell, all done. */ + if (wp == NULL) + break; + + /* Create the new row. */ + lcrow = layout_create_cell(lc); + layout_set_size(lcrow, w->sx, height - 1, 0, 0); + TAILQ_INSERT_TAIL(&lc->cells, lcrow, entry); + + /* If only one column, just use the row directly. */ + if (columns == 1) { + layout_make_leaf(lcrow, wp); + wp = TAILQ_NEXT(wp, entry); + continue; + } + + /* Add in the columns. */ + layout_make_node(lcrow, LAYOUT_LEFTRIGHT); + for (i = 0; i < columns; i++) { + /* Create and add a pane cell. */ + lcchild = layout_create_cell(lcrow); + layout_set_size(lcchild, width - 1, height - 1, 0, 0); + layout_make_leaf(lcchild, wp); + TAILQ_INSERT_TAIL(&lcrow->cells, lcchild, entry); + + /* Move to the next cell. */ + if ((wp = TAILQ_NEXT(wp, entry)) == NULL) + break; + } + + /* Adjust the row to fit the full width if necessary. */ + if (i == columns) + i--; + used = ((i + 1) * width) - 1; + if (w->sx <= used) + continue; + lcchild = TAILQ_LAST(&lcrow->cells, layout_cells); + layout_resize_adjust(lcchild, LAYOUT_LEFTRIGHT, w->sx - used); + } + + /* Adjust the last row height to fit if necessary. */ + used = mainheight + (rows * height) - 1; + if (w->sy > used) { + lcrow = TAILQ_LAST(&lc->cells, layout_cells); + layout_resize_adjust(lcrow, LAYOUT_TOPBOTTOM, w->sy - used); + } + + /* Fix cell offsets. */ + layout_fix_offsets(lc); + layout_fix_panes(w, w->sx, w->sy); + + layout_print_cell(w->layout_root, __func__, 1); + + server_redraw_window(w); +} + +void +layout_set_main_v(struct window *w) +{ + struct window_pane *wp; + struct layout_cell *lc, *lcmain, *lccolumn, *lcchild; + u_int n, mainwidth, width, height, used; + u_int i, j, columns, rows, totalcolumns; + + layout_print_cell(w->layout_root, __func__, 1); + + /* Get number of panes. */ + n = window_count_panes(w); + if (n <= 1) + return; + n--; /* take off main pane */ + + /* How many rows and columns will be needed? */ + rows = w->sy / (PANE_MINIMUM + 1); /* maximum rows */ + columns = 1 + (n - 1) / rows; + rows = 1 + (n - 1) / columns; + height = w->sy / rows; + + /* Get the main pane width and add one for separator line. */ + mainwidth = options_get_number(&w->options, "main-pane-width") + 1; + if (mainwidth < PANE_MINIMUM + 1) + mainwidth = PANE_MINIMUM + 1; + + /* Try and make everything fit. */ + totalcolumns = columns * (PANE_MINIMUM + 1) - 1; + if (mainwidth + totalcolumns > w->sx) { + if (totalcolumns + PANE_MINIMUM + 1 > w->sx) + mainwidth = PANE_MINIMUM + 2; + else + mainwidth = w->sx - totalcolumns; + width = PANE_MINIMUM + 1; + } else + width = (w->sx - mainwidth) / columns; + + /* Free old tree and create a new root. */ + layout_free(w); + lc = w->layout_root = layout_create_cell(NULL); + layout_set_size(lc, mainwidth + columns * width, w->sy, 0, 0); + layout_make_node(lc, LAYOUT_LEFTRIGHT); + + /* Create the main pane. */ + lcmain = layout_create_cell(lc); + layout_set_size(lcmain, mainwidth - 1, w->sy, 0, 0); + layout_make_leaf(lcmain, TAILQ_FIRST(&w->panes)); + TAILQ_INSERT_TAIL(&lc->cells, lcmain, entry); + + /* Create a grid of the remaining cells. */ + wp = TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry); + for (j = 0; j < columns; j++) { + /* If this is the last cell, all done. */ + if (wp == NULL) + break; + + /* Create the new column. */ + lccolumn = layout_create_cell(lc); + layout_set_size(lccolumn, width - 1, w->sy, 0, 0); + TAILQ_INSERT_TAIL(&lc->cells, lccolumn, entry); + + /* If only one row, just use the row directly. */ + if (rows == 1) { + layout_make_leaf(lccolumn, wp); + wp = TAILQ_NEXT(wp, entry); + continue; + } + + /* Add in the rows. */ + layout_make_node(lccolumn, LAYOUT_TOPBOTTOM); + for (i = 0; i < rows; i++) { + /* Create and add a pane cell. */ + lcchild = layout_create_cell(lccolumn); + layout_set_size(lcchild, width - 1, height - 1, 0, 0); + layout_make_leaf(lcchild, wp); + TAILQ_INSERT_TAIL(&lccolumn->cells, lcchild, entry); + + /* Move to the next cell. */ + if ((wp = TAILQ_NEXT(wp, entry)) == NULL) + break; + } + + /* Adjust the column to fit the full height if necessary. */ + if (i == rows) + i--; + used = ((i + 1) * height) - 1; + if (w->sy <= used) + continue; + lcchild = TAILQ_LAST(&lccolumn->cells, layout_cells); + layout_resize_adjust(lcchild, LAYOUT_TOPBOTTOM, w->sy - used); + } + + /* Adjust the last column width to fit if necessary. */ + used = mainwidth + (columns * width) - 1; + if (w->sx > used) { + lccolumn = TAILQ_LAST(&lc->cells, layout_cells); + layout_resize_adjust(lccolumn, LAYOUT_LEFTRIGHT, w->sx - used); + } + + /* Fix cell offsets. */ + layout_fix_offsets(lc); + layout_fix_panes(w, w->sx, w->sy); + + layout_print_cell(w->layout_root, __func__, 1); + + server_redraw_window(w); +} diff --git a/layout.c b/layout.c index 66cf7af2..0cf6e387 100644 --- a/layout.c +++ b/layout.c @@ -18,349 +18,632 @@ #include -#include +#include #include "tmux.h" /* - * Each layout has two functions, _refresh to relayout the panes and _resize to - * resize a single pane. + * The window layout is a tree of cells each of which can be one of: a + * left-right container for a list of cells, a top-bottom container for a list + * of cells, or a container for a window pane. * - * Second argument (int) to _refresh is 1 if the only change has been that the - * active pane has changed. If 0 then panes, active pane or both may have - * changed. + * Each window has a pointer to the root of its layout tree (containing its + * panes), every pane has a pointer back to the cell containing it, and each + * cell a pointer to its parent cell. */ -void layout_active_only_refresh(struct window *, int); -void layout_even_h_refresh(struct window *, int); -void layout_even_v_refresh(struct window *, int); -void layout_main_h_refresh(struct window *, int); -void layout_main_v_refresh(struct window *, int); +int layout_resize_pane_grow(struct layout_cell *, enum layout_type, int); +int layout_resize_pane_shrink(struct layout_cell *, enum layout_type, int); -const struct { - const char *name; - void (*refresh)(struct window *, int); - void (*resize)(struct window_pane *, int); -} layouts[] = { - { "manual-vertical", layout_manual_v_refresh, layout_manual_v_resize }, - { "active-only", layout_active_only_refresh, NULL }, - { "even-horizontal", layout_even_h_refresh, NULL }, - { "even-vertical", layout_even_v_refresh, NULL }, - { "main-horizontal", layout_main_h_refresh, NULL }, - { "main-vertical", layout_main_v_refresh, NULL }, -}; - -const char * -layout_name(struct window *w) +struct layout_cell * +layout_create_cell(struct layout_cell *lcparent) { - return (layouts[w->layout].name); + struct layout_cell *lc; + + lc = xmalloc(sizeof *lc); + lc->type = LAYOUT_WINDOWPANE; + lc->parent = lcparent; + + TAILQ_INIT(&lc->cells); + + lc->sx = UINT_MAX; + lc->sy = UINT_MAX; + + lc->xoff = UINT_MAX; + lc->yoff = UINT_MAX; + + lc->wp = NULL; + + return (lc); } -int -layout_lookup(const char *name) +void +layout_free_cell(struct layout_cell *lc) { - u_int i; - int matched = -1; + struct layout_cell *lcchild; - for (i = 0; i < nitems(layouts); i++) { - if (strncmp(layouts[i].name, name, strlen(name)) == 0) { - if (matched != -1) /* ambiguous */ - return (-1); - matched = i; + switch (lc->type) { + case LAYOUT_LEFTRIGHT: + case LAYOUT_TOPBOTTOM: + while (!TAILQ_EMPTY(&lc->cells)) { + lcchild = TAILQ_FIRST(&lc->cells); + TAILQ_REMOVE(&lc->cells, lcchild, entry); + layout_free_cell(lcchild); } + break; + case LAYOUT_WINDOWPANE: + if (lc->wp != NULL) + lc->wp->layout_cell = NULL; + break; } - return (matched); -} - -int -layout_select(struct window *w, u_int layout) -{ - if (layout > nitems(layouts) - 1 || layout == w->layout) - return (-1); - w->layout = layout; - - layout_refresh(w, 0); - return (0); + xfree(lc); } void -layout_next(struct window *w) +layout_print_cell(struct layout_cell *lc, const char *hdr, u_int n) { - w->layout++; - if (w->layout > nitems(layouts) - 1) - w->layout = 0; - layout_refresh(w, 0); + struct layout_cell *lcchild; + + log_debug( + "%s:%*s%p type %u [parent %p] wp=%p [%u,%u %ux%u]", hdr, n, " ", lc, + lc->type, lc->parent, lc->wp, lc->xoff, lc->yoff, lc->sx, lc->sy); + switch (lc->type) { + case LAYOUT_LEFTRIGHT: + case LAYOUT_TOPBOTTOM: + TAILQ_FOREACH(lcchild, &lc->cells, entry) + layout_print_cell(lcchild, hdr, n + 1); + break; + case LAYOUT_WINDOWPANE: + break; + } } void -layout_previous(struct window *w) +layout_set_size( + struct layout_cell *lc, u_int sx, u_int sy, u_int xoff, u_int yoff) { - if (w->layout == 0) - w->layout = nitems(layouts) - 1; - else - w->layout--; - layout_refresh(w, 0); + lc->sx = sx; + lc->sy = sy; + + lc->xoff = xoff; + lc->yoff = yoff; } void -layout_refresh(struct window *w, int active_only) +layout_make_leaf(struct layout_cell *lc, struct window_pane *wp) { - layouts[w->layout].refresh(w, active_only); - server_redraw_window(w); -} + lc->type = LAYOUT_WINDOWPANE; -int -layout_resize(struct window_pane *wp, int adjust) -{ - struct window *w = wp->window; + TAILQ_INIT(&lc->cells); - if (layouts[w->layout].resize == NULL) - return (-1); - layouts[w->layout].resize(wp, adjust); - return (0); + wp->layout_cell = lc; + lc->wp = wp; } void -layout_active_only_refresh(struct window *w, unused int active_only) +layout_make_node(struct layout_cell *lc, enum layout_type type) +{ + if (type == LAYOUT_WINDOWPANE) + fatalx("bad layout type"); + lc->type = type; + + TAILQ_INIT(&lc->cells); + + if (lc->wp != NULL) + lc->wp->layout_cell = NULL; + lc->wp = NULL; +} + +/* Fix cell offsets based on their sizes. */ +void +layout_fix_offsets(struct layout_cell *lc) +{ + struct layout_cell *lcchild; + u_int xoff, yoff; + + if (lc->type == LAYOUT_LEFTRIGHT) { + xoff = lc->xoff; + TAILQ_FOREACH(lcchild, &lc->cells, entry) { + lcchild->xoff = xoff; + lcchild->yoff = lc->yoff; + if (lcchild->type != LAYOUT_WINDOWPANE) + layout_fix_offsets(lcchild); + xoff += lcchild->sx + 1; + } + } else { + yoff = lc->yoff; + TAILQ_FOREACH(lcchild, &lc->cells, entry) { + lcchild->xoff = lc->xoff; + lcchild->yoff = yoff; + if (lcchild->type != LAYOUT_WINDOWPANE) + layout_fix_offsets(lcchild); + yoff += lcchild->sy + 1; + } + } +} + +/* Update pane offsets and sizes based on their cells. */ +void +layout_fix_panes(struct window *w, u_int wsx, u_int wsy) { struct window_pane *wp; - u_int xoff; + struct layout_cell *lc; + u_int sx, sy; - xoff = w->sx; TAILQ_FOREACH(wp, &w->panes, entry) { - /* Put the active pane on screen and the rest to the right. */ - if (wp == w->active) - wp->xoff = 0; + if ((lc = wp->layout_cell) == NULL) + continue; + wp->xoff = lc->xoff; + wp->yoff = lc->yoff; + + /* + * Layout cells are limited by the smallest size of other cells + * within the same row or column; if this isn't the case + * resizing becomes difficult. + * + * However, panes do not have to take up their entire cell, so + * they can be cropped to the window edge if the layout + * overflows and they are partly visible. + * + * This stops cells being hidden unnecessarily. + */ + + /* + * Work out the horizontal size. If the pane is actually + * outside the window or the entire pane is already visible, + * don't crop. + */ + if (lc->xoff >= wsx || lc->xoff + lc->sx < wsx) + sx = lc->sx; else { - wp->xoff = xoff; - xoff += w->sx; + sx = wsx - lc->xoff; + if (sx < 1) + sx = lc->sx; } - wp->yoff = 0; - window_pane_resize(wp, w->sx, w->sy); - } -} - -void -layout_even_h_refresh(struct window *w, int active_only) -{ - struct window_pane *wp; - u_int i, n, width, xoff; - - if (active_only) - return; - - /* If the screen is too small, show active only. */ - if (w->sx < PANE_MINIMUM || w->sy < PANE_MINIMUM) { - layout_active_only_refresh(w, active_only); - return; - } - - /* Get number of panes. */ - n = window_count_panes(w); - if (n == 0) - return; - - /* How many can we fit? */ - if (w->sx / n < PANE_MINIMUM) { - width = PANE_MINIMUM; - n = UINT_MAX; - } else - width = w->sx / n; - - /* Fit the panes. */ - i = xoff = 0; - TAILQ_FOREACH(wp, &w->panes, entry) { - wp->xoff = xoff; - wp->yoff = 0; - if (i != n - 1) - window_pane_resize(wp, width - 1, w->sy); - else - window_pane_resize(wp, width, w->sy); - - i++; - xoff += width; - } - - /* Any space left? */ - while (xoff++ < w->sx) { - wp = TAILQ_LAST(&w->panes, window_panes); - window_pane_resize(wp, wp->sx + 1, wp->sy); - } -} - -void -layout_even_v_refresh(struct window *w, int active_only) -{ - struct window_pane *wp; - u_int i, n, height, yoff; - - if (active_only) - return; - - /* If the screen is too small, show active only. */ - if (w->sx < PANE_MINIMUM || w->sy < PANE_MINIMUM) { - layout_active_only_refresh(w, active_only); - return; - } - - /* Get number of panes. */ - n = window_count_panes(w); - if (n == 0) - return; - - /* How many can we fit? */ - if (w->sy / n < PANE_MINIMUM) { - height = PANE_MINIMUM; - n = UINT_MAX; - } else - height = w->sy / n; - - /* Fit the panes. */ - i = yoff = 0; - TAILQ_FOREACH(wp, &w->panes, entry) { - wp->xoff = 0; - wp->yoff = yoff; - if (i != n - 1) - window_pane_resize(wp, w->sx, height - 1); - else - window_pane_resize(wp, w->sx, height); - - i++; - yoff += height; - } - - /* Any space left? */ - while (yoff++ < w->sy) { - wp = TAILQ_LAST(&w->panes, window_panes); - window_pane_resize(wp, wp->sx, wp->sy + 1); - } -} - -void -layout_main_v_refresh(struct window *w, int active_only) -{ - struct window_pane *wp; - u_int i, n, mainwidth, height, yoff; - - if (active_only) - return; - - /* Get number of panes. */ - n = window_count_panes(w); - if (n == 0) - return; - - /* Get the main pane width and add one for separator line. */ - mainwidth = options_get_number(&w->options, "main-pane-width") + 1; - - /* Need >1 pane and minimum columns; if fewer, display active only. */ - if (n == 1 || - w->sx < mainwidth + PANE_MINIMUM || w->sy < PANE_MINIMUM) { - layout_active_only_refresh(w, active_only); - return; - } - n--; - - /* How many can we fit, not including first? */ - if (w->sy / n < PANE_MINIMUM) { - height = PANE_MINIMUM; - n = w->sy / PANE_MINIMUM; - } else - height = w->sy / n; - - /* Fit the panes. */ - i = yoff = 0; - TAILQ_FOREACH(wp, &w->panes, entry) { - if (wp == TAILQ_FIRST(&w->panes)) { - wp->xoff = 0; - wp->yoff = 0; - window_pane_resize(wp, mainwidth - 1, w->sy); - continue; + + /* + * Similarly for the vertical size; the minimum vertical size + * is two because scroll regions cannot be one line. + */ + if (lc->yoff >= wsy || lc->yoff + lc->sy < wsy) + sy = lc->sy; + else { + sy = wsy - lc->yoff; + if (sy < 2) + sy = lc->sy; } - wp->xoff = mainwidth; - wp->yoff = yoff; - if (i != n - 1) - window_pane_resize(wp, w->sx - mainwidth, height - 1); - else - window_pane_resize(wp, w->sx - mainwidth, height); + window_pane_resize(wp, sx, sy); + } +} - i++; - yoff += height; +/* Calculate how much size is available to be removed from a cell. */ +u_int +layout_resize_check(struct layout_cell *lc, enum layout_type type) +{ + struct layout_cell *lcchild; + u_int available, minimum; + + if (lc->type == LAYOUT_WINDOWPANE) { + /* Space available in this cell only. */ + if (type == LAYOUT_LEFTRIGHT) + available = lc->sx; + else + available = lc->sy; + + if (available > PANE_MINIMUM) + available -= PANE_MINIMUM; + else + available = 0; + } else if (lc->type == type) { + /* Same type: total of available space in all child cells. */ + available = 0; + TAILQ_FOREACH(lcchild, &lc->cells, entry) + available += layout_resize_check(lcchild, type); + } else { + /* Different type: minimum of available space in child cells. */ + minimum = UINT_MAX; + TAILQ_FOREACH(lcchild, &lc->cells, entry) { + available = layout_resize_check(lcchild, type); + if (available < minimum) + minimum = available; + } + available = minimum; } - /* Any space left? */ - while (yoff++ < w->sy) { - wp = TAILQ_LAST(&w->panes, window_panes); - while (wp != NULL && wp == TAILQ_FIRST(&w->panes)) - wp = TAILQ_PREV(wp, window_panes, entry); - if (wp == NULL) + return (available); +} + +/* + * Adjust cell size evenly, including altering its children. This function + * expects the change to have already been bounded to the space available. + */ +void +layout_resize_adjust(struct layout_cell *lc, enum layout_type type, int change) +{ + struct layout_cell *lcchild; + + /* Adjust the cell size. */ + if (type == LAYOUT_LEFTRIGHT) + lc->sx += change; + else + lc->sy += change; + + /* If this is a leaf cell, that is all that is necessary. */ + if (type == LAYOUT_WINDOWPANE) + return; + + /* Child cell runs in a different direction. */ + if (lc->type != type) { + TAILQ_FOREACH(lcchild, &lc->cells, entry) + layout_resize_adjust(lcchild, type, change); + return; + } + + /* + * Child cell runs in the same direction. Adjust each child equally + * until no further change is possible. + */ + while (change != 0) { + TAILQ_FOREACH(lcchild, &lc->cells, entry) { + if (change == 0) + break; + if (change > 0) { + layout_resize_adjust(lcchild, type, 1); + change--; + continue; + } + if (layout_resize_check(lcchild, type) > 0) { + layout_resize_adjust(lcchild, type, -1); + change++; + } + } + } +} + +void +layout_init(struct window *w) +{ + struct layout_cell *lc; + + lc = w->layout_root = layout_create_cell(NULL); + layout_set_size(lc, w->sx, w->sy, 0, 0); + layout_make_leaf(lc, TAILQ_FIRST(&w->panes)); + + layout_fix_panes(w, w->sx, w->sy); +} + +void +layout_free(struct window *w) +{ + layout_free_cell(w->layout_root); +} + +/* Resize the entire layout after window resize. */ +void +layout_resize(struct window *w, u_int sx, u_int sy) +{ + struct layout_cell *lc = w->layout_root; + int xlimit, ylimit, xchange, ychange; + + /* + * Adjust horizontally. Do not attempt to reduce the layout lower than + * the minimum (more than the amount returned by layout_resize_check). + * + * This can mean that the window size is smaller than the total layout + * size: redrawing this is handled at a higher level, but it does leave + * a problem with growing the window size here: if the current size is + * < the minimum, growing proportionately by adding to each pane is + * wrong as it would keep the layout size larger than the window size. + * Instead, spread the difference between the minimum and the new size + * out proportionately - this should leave the layout fitting the new + * window size. + */ + xchange = sx - w->sx; + xlimit = layout_resize_check(lc, LAYOUT_LEFTRIGHT); + if (xchange < 0 && xchange < -xlimit) + xchange = -xlimit; + if (xlimit == 0) { + if (sx <= lc->sx) /* lc->sx is minimum possible */ + xchange = 0; + else + xchange = sx - lc->sx; + } + if (xchange != 0) + layout_resize_adjust(lc, LAYOUT_LEFTRIGHT, xchange); + + /* Adjust vertically in a similar fashion. */ + ychange = sy - w->sy; + ylimit = layout_resize_check(lc, LAYOUT_TOPBOTTOM); + if (ychange < 0 && ychange < -ylimit) + ychange = -ylimit; + if (ylimit == 0) { + if (sy <= lc->sy) /* lc->sy is minimum possible */ + ychange = 0; + else + ychange = sy - lc->sy; + } + if (ychange != 0) + layout_resize_adjust(lc, LAYOUT_TOPBOTTOM, ychange); + + /* Fix cell offsets. */ + layout_fix_offsets(lc); + layout_fix_panes(w, sx, sy); +} + +/* Resize a single pane within the layout. */ +void +layout_resize_pane(struct window_pane *wp, enum layout_type type, int change) +{ + struct layout_cell *lc, *lcparent; + int needed, size; + + lc = wp->layout_cell; + + /* Find next parent of the same type. */ + lcparent = lc->parent; + while (lcparent != NULL && lcparent->type != type) { + lc = lcparent; + lcparent = lc->parent; + } + if (lcparent == NULL) + return; + + /* If this is the last cell, move back one. */ + if (lc == TAILQ_LAST(&lcparent->cells, layout_cells)) + lc = TAILQ_PREV(lc, layout_cells, entry); + + /* Grow or shrink the cell. */ + needed = change; + while (needed != 0) { + if (change > 0) { + size = layout_resize_pane_grow(lc, type, needed); + needed -= size; + } else { + size = layout_resize_pane_shrink(lc, type, needed); + needed += size; + } + + if (size == 0) /* no more change possible */ break; - window_pane_resize(wp, wp->sx, wp->sy + 1); } + + /* Fix cell offsets. */ + layout_fix_offsets(wp->window->layout_root); + layout_fix_panes(wp->window, wp->window->sx, wp->window->sy); } -void -layout_main_h_refresh(struct window *w, int active_only) +int +layout_resize_pane_grow( + struct layout_cell *lc, enum layout_type type, int needed) { - struct window_pane *wp; - u_int i, n, mainheight, width, xoff; + struct layout_cell *lcadd, *lcremove; + u_int size; - if (active_only) - return; - - /* Get number of panes. */ - n = window_count_panes(w); - if (n == 0) - return; - - /* Get the main pane height and add one for separator line. */ - mainheight = options_get_number(&w->options, "main-pane-height") + 1; - - /* Need >1 pane and minimum rows; if fewer, display active only. */ - if (n == 1 || - w->sy < mainheight + PANE_MINIMUM || w->sx < PANE_MINIMUM) { - layout_active_only_refresh(w, active_only); - return; - } - n--; - - /* How many can we fit, not including first? */ - if (w->sx / n < PANE_MINIMUM) { - width = PANE_MINIMUM; - n = w->sx / PANE_MINIMUM; - } else - width = w->sx / n; - - /* Fit the panes. */ - i = xoff = 0; - TAILQ_FOREACH(wp, &w->panes, entry) { - if (wp == TAILQ_FIRST(&w->panes)) { - wp->xoff = 0; - wp->yoff = 0; - window_pane_resize(wp, w->sx, mainheight - 1); - continue; - } - - wp->xoff = xoff; - wp->yoff = mainheight; - if (i != n - 1) - window_pane_resize(wp, width - 1, w->sy - mainheight); - else - window_pane_resize(wp, width - 1, w->sy - mainheight); - - i++; - xoff += width; - } - - /* Any space left? */ - while (xoff++ < w->sx + 1) { - wp = TAILQ_LAST(&w->panes, window_panes); - while (wp != NULL && wp == TAILQ_FIRST(&w->panes)) - wp = TAILQ_PREV(wp, window_panes, entry); - if (wp == NULL) + /* Growing. Always add to the current cell. */ + lcadd = lc; + + /* Look towards the tail for a suitable cell for reduction. */ + lcremove = TAILQ_NEXT(lc, entry); + while (lcremove != NULL) { + size = layout_resize_check(lcremove, type); + if (size > 0) break; - window_pane_resize(wp, wp->sx + 1, wp->sy); + lcremove = TAILQ_NEXT(lcremove, entry); } + + /* If none found, look towards the head. */ + if (lcremove == NULL) { + lcremove = TAILQ_PREV(lc, layout_cells, entry); + while (lcremove != NULL) { + size = layout_resize_check(lcremove, type); + if (size > 0) + break; + lcremove = TAILQ_PREV(lcremove, layout_cells, entry); + } + if (lcremove == NULL) + return (0); + } + + /* Change the cells. */ + if (size > (u_int) needed) + size = needed; + layout_resize_adjust(lcadd, type, size); + layout_resize_adjust(lcremove, type, -size); + return (size); } + +int +layout_resize_pane_shrink( + struct layout_cell *lc, enum layout_type type, int needed) +{ + struct layout_cell *lcadd, *lcremove; + u_int size; + + /* Shrinking. Find cell to remove from by walking towards head. */ + lcremove = lc; + do { + size = layout_resize_check(lcremove, type); + if (size != 0) + break; + lcremove = TAILQ_PREV(lcremove, layout_cells, entry); + } while (lcremove != NULL); + if (lcremove == NULL) + return (0); + + /* And add onto the next cell (from the original cell). */ + lcadd = TAILQ_NEXT(lc, entry); + if (lcadd == NULL) + return (0); + + /* Change the cells. */ + if (size > (u_int) -needed) + size = -needed; + layout_resize_adjust(lcadd, type, size); + layout_resize_adjust(lcremove, type, -size); + return (size); +} + +/* Split a pane into two. size is a hint, or -1 for default half/half split. */ +int +layout_split_pane(struct window_pane *wp, + enum layout_type type, int size, struct window_pane *new_wp) +{ + struct layout_cell *lc, *lcparent, *lcnew; + u_int sx, sy, xoff, yoff, size1, size2; + + lc = wp->layout_cell; + + /* Copy the old cell size. */ + sx = lc->sx; + sy = lc->sy; + xoff = lc->xoff; + yoff = lc->yoff; + + /* Check there is enough space for the two new panes. */ + switch (type) { + case LAYOUT_LEFTRIGHT: + if (sx < PANE_MINIMUM * 2 + 1) + return (-1); + break; + case LAYOUT_TOPBOTTOM: + if (sy < PANE_MINIMUM * 2 + 1) + return (-1); + break; + default: + fatalx("bad layout type"); + } + + if (lc->parent != NULL && lc->parent->type == type) { + /* + * If the parent exists and is of the same type as the split, + * create a new cell and insert it after this one. + */ + + /* Create the new child cell. */ + lcnew = layout_create_cell(lc->parent); + TAILQ_INSERT_AFTER(&lc->parent->cells, lc, lcnew, entry); + } else { + /* + * Otherwise create a new parent and insert it. + */ + + /* Create and insert the replacement parent. */ + lcparent = layout_create_cell(lc->parent); + layout_make_node(lcparent, type); + layout_set_size(lcparent, sx, sy, xoff, yoff); + if (lc->parent == NULL) + wp->window->layout_root = lcparent; + else + TAILQ_REPLACE(&lc->parent->cells, lc, lcparent, entry); + + /* Insert the old cell. */ + lc->parent = lcparent; + TAILQ_INSERT_HEAD(&lcparent->cells, lc, entry); + + /* Create the new child cell. */ + lcnew = layout_create_cell(lcparent); + TAILQ_INSERT_TAIL(&lcparent->cells, lcnew, entry); + } + + /* Set new cell sizes. size is the target size or -1 for middle split, + * size1 is the size of the top/left and size2 the bottom/right. + */ + switch (type) { + case LAYOUT_LEFTRIGHT: + if (size < 0) + size2 = ((sx + 1) / 2) - 1; + else + size2 = size; + if (size2 < PANE_MINIMUM) + size2 = PANE_MINIMUM; + else if (size2 > sx - 2) + size2 = sx - 2; + size1 = sx - 1 - size2; + layout_set_size(lc, size1, sy, xoff, yoff); + layout_set_size(lcnew, size2, sy, xoff + lc->sx + 1, yoff); + break; + case LAYOUT_TOPBOTTOM: + if (size < 0) + size2 = ((sy + 1) / 2) - 1; + else + size2 = size; + if (size2 < PANE_MINIMUM) + size2 = PANE_MINIMUM; + else if (size2 > sy - 2) + size2 = sy - 2; + size1 = sy - 1 - size2; + layout_set_size(lc, sx, size1, xoff, yoff); + layout_set_size(lcnew, sx, size2, xoff, yoff + lc->sy + 1); + break; + default: + fatalx("bad layout type"); + } + + /* Assign the panes. */ + layout_make_leaf(lc, wp); + layout_make_leaf(lcnew, new_wp); + + /* Fix pane offsets and sizes. */ + layout_fix_panes(wp->window, wp->window->sx, wp->window->sy); + + return (0); +} + +/* Destroy the layout associated with a pane and redistribute the space. */ +void +layout_close_pane(struct window_pane *wp) +{ + struct layout_cell *lc, *lcother, *lcparent; + + lc = wp->layout_cell; + lcparent = lc->parent; + + /* + * If no parent, this is the last pane so window close is imminent and + * there is no need to resize anything. + */ + if (lcparent == NULL) { + layout_free_cell(lc); + wp->window->layout_root = NULL; + return; + } + + /* Merge the space into the previous or next cell. */ + if (lc == TAILQ_FIRST(&lcparent->cells)) + lcother = TAILQ_NEXT(lc, entry); + else + lcother = TAILQ_PREV(lc, layout_cells, entry); + if (lcparent->type == LAYOUT_LEFTRIGHT) + layout_resize_adjust(lcother, lcparent->type, lc->sx + 1); + else + layout_resize_adjust(lcother, lcparent->type, lc->sy + 1); + + /* Remove this from the parent's list. */ + TAILQ_REMOVE(&lcparent->cells, lc, entry); + layout_free_cell(lc); + + /* + * If the parent now has one cell, remove the parent from the tree and + * replace it by that cell. + */ + lc = TAILQ_FIRST(&lcparent->cells); + if (TAILQ_NEXT(lc, entry) == NULL) { + TAILQ_REMOVE(&lcparent->cells, lc, entry); + + lc->parent = lcparent->parent; + if (lc->parent == NULL) { + lc->xoff = 0; lc->yoff = 0; + wp->window->layout_root = lc; + } else + TAILQ_REPLACE(&lc->parent->cells, lcparent, lc, entry); + + layout_free_cell(lcparent); + } + + /* Fix pane offsets and sizes. */ + layout_fix_offsets(wp->window->layout_root); + layout_fix_panes(wp->window, wp->window->sx, wp->window->sy); +} + diff --git a/resize.c b/resize.c index 1c2377f5..d549ea5b 100644 --- a/resize.c +++ b/resize.c @@ -132,6 +132,7 @@ recalculate_sizes(void) log_debug( "window size %u,%u (was %u,%u)", ssx, ssy, w->sx, w->sy); + layout_resize(w, ssx, ssy); window_resize(w, ssx, ssy); /* @@ -148,6 +149,5 @@ recalculate_sizes(void) } server_redraw_window(w); - layout_refresh(w, 0); } } diff --git a/server.c b/server.c index cdde3996..250f3187 100644 --- a/server.c +++ b/server.c @@ -840,7 +840,9 @@ server_handle_client(struct client *c) /* Ensure cursor position and mode settings. */ status = options_get_number(&c->session->options, "status"); - if (wp->yoff + s->cy < c->tty.sy - status) + if (!window_pane_visible(wp) || wp->yoff + s->cy >= c->tty.sy - status) + tty_cursor(&c->tty, 0, 0, 0, 0); + else tty_cursor(&c->tty, s->cx, s->cy, wp->xoff, wp->yoff); mode = s->mode; @@ -1072,9 +1074,9 @@ server_check_window(struct window *w) * pane dies). */ if (wp->fd == -1 && !flag) { + layout_close_pane(wp); window_remove_pane(w, wp); server_redraw_window(w); - layout_refresh(w, 0); } else destroyed = 0; wp = wq; diff --git a/tmux.1 b/tmux.1 index e7041ec1..3540ae98 100644 --- a/tmux.1 +++ b/tmux.1 @@ -393,15 +393,17 @@ each pane takes up a certain area of the display and is a separate terminal. A window may be split into panes using the .Ic split-window command. -.Pp -Panes are numbered beginning from zero; in horizontal layouts zero is the -leftmost pane and in vertical the topmost. -.Pp -Panes may be arranged using several layouts. -The layout may be cycled with the -.Ic next-layout +Windows may be split horizontally (with the +.Fl h +flag) or vertically. +Panes may be resized with the +.Ic resize-pane command (bound to -.Ql C-space +.Ql C-up , +.Ql C-down +.Ql C-left +and +.Ql C-right by default), the current pane may be changed with the .Ic up-pane and @@ -410,12 +412,22 @@ commands and the .Ic rotate-window and .Ic swap-pane -commands may be used to swap panes without changing the window layout. +commands may be used to swap panes without changing their position. +Panes are numbered beginning from zero in the order they are created. +.Pp +A number of preset +.Em layouts +are available. +These may be selected with the +.Ic select-layout +command or cycled with +.Ic next-layout +(bound to +.Ql C-space +by default); once a layout is chosen, panes within it may be moved and resized as normal. .Pp The following layouts are supported: .Bl -tag -width Ds -.It Ic active-only -Only the active pane is shown \(en all other panes are hidden. .It Ic even-horizontal Panes are spread out evenly from left to right across the window. .It Ic even-vertical @@ -434,11 +446,6 @@ bottom along the right. See the .Em main-pane-width window option. -.It Ic manual -Manual layout splits windows vertically (running across); only with this layout -may panes be resized using the -.Ic resize-pane -command. .El .Sh STATUS LINE .Nm @@ -980,7 +987,7 @@ Rename the current window, or the window at if specified, to .Ar new-name . .It Xo Ic resize-pane -.Op Fl DU +.Op Fl DLUR .Op Fl p Ar pane-index .Op Fl t Ar target-window .Op Ar adjustment @@ -988,11 +995,15 @@ if specified, to .D1 (alias: Ic resizep ) Resize a pane, upward with .Fl U -(the default) or downward with -.Fl D . +(the default), downward with +.Fl D , +to the left with +.Fl L +and to the right with +.Fl R. The .Ar adjustment -is given in lines (the default is 1). +is given in lines or cells (the default is 1). .It Xo Ic respawn-window .Op Fl k .Op Fl t Ar target-window @@ -1520,38 +1531,30 @@ is used. Execute commands from .Ar path . .It Xo Ic split-window -.Op Fl d +.Op Fl dhv .Oo Fl l -.Ar lines | +.Ar size | .Fl p Ar percentage Oc .Op Fl t Ar target-window .Op Ar command .Xc .D1 (alias: splitw ) -Creates a new window by splitting it vertically. +Creates a new pane by splitting the active pane: +.Fl h +does a horizontal split and +.Fl v +a vertical split; if neither is specified, +.Fl v +is assumed. The .Fl l and .Fl p -options specify the size of the new window in lines, or as a percentage, -respectively. +options specify the size of the new window in lines (for vertical split) or in +cells (for horizontal split), or as a percentage, respectively. All other options have the same meaning as in the .Ic new-window command. -.Pp -A few notes with regard to panes: -.Bl -enum -compact -.It -If attempting to split a window with less than eight lines, an error will be -shown. -.It -If the window is resized, as many panes are shown as can fit without reducing -them below four lines. -.It -The minimum pane size is four lines (including the separator line). -.It -The panes are indexed from top (0) to bottom, with no numbers skipped. -.El .It Xo Ic start-server .Xc .D1 (alias: Ic start ) diff --git a/tmux.h b/tmux.h index 62c399f3..22621c4c 100644 --- a/tmux.h +++ b/tmux.h @@ -47,8 +47,11 @@ extern const char *__progname; /* Default prompt history length. */ #define PROMPT_HISTORY 100 -/* Minimum pane size. */ -#define PANE_MINIMUM 5 /* includes separator line */ +/* + * Minimum layout cell size, NOT including separator line. The scroll region + * cannot be one line in height so this must be at least two. + */ +#define PANE_MINIMUM 2 /* Automatic name refresh interval, in milliseconds. */ #define NAME_INTERVAL 500 @@ -592,6 +595,7 @@ struct window_mode { /* Child window structure. */ struct window_pane { struct window *window; + struct layout_cell *layout_cell; u_int sx; u_int sy; @@ -635,7 +639,9 @@ struct window { struct window_pane *active; struct window_panes panes; + u_int layout; + struct layout_cell *layout_root; u_int sx; u_int sy; @@ -664,6 +670,34 @@ struct winlink { RB_HEAD(winlinks, winlink); SLIST_HEAD(winlink_stack, winlink); +/* Layout direction. */ +enum layout_type { + LAYOUT_LEFTRIGHT, + LAYOUT_TOPBOTTOM, + LAYOUT_WINDOWPANE +}; + +/* Layout cells queue. */ +TAILQ_HEAD(layout_cells, layout_cell); + +/* Layout cell. */ +struct layout_cell { + enum layout_type type; + + struct layout_cell *parent; + + u_int sx; + u_int sy; + + u_int xoff; + u_int yoff; + + struct window_pane *wp; + struct layout_cells cells; + + TAILQ_ENTRY(layout_cell) entry; +}; + /* Paste buffer. */ struct paste_buffer { char *data; @@ -1446,8 +1480,7 @@ struct window *window_create(const char *, const char *, void window_destroy(struct window *); int window_resize(struct window *, u_int, u_int); void window_set_active_pane(struct window *, struct window_pane *); -struct window_pane *window_add_pane(struct window *, int, - const char *, const char *, const char **, u_int, char **); +struct window_pane *window_add_pane(struct window *, u_int, char **); void window_remove_pane(struct window *, struct window_pane *); struct window_pane *window_pane_at_index(struct window *, u_int); u_int window_pane_index(struct window *, struct window_pane *); @@ -1467,20 +1500,38 @@ void window_pane_mouse(struct window_pane *, struct client *, u_char, u_char, u_char); int window_pane_visible(struct window_pane *); char *window_pane_search( - struct window_pane *, const char *, u_int *); + struct window_pane *, const char *, u_int *); /* layout.c */ -const char * layout_name(struct window *); -int layout_lookup(const char *); -void layout_refresh(struct window *, int); -int layout_resize(struct window_pane *, int); -int layout_select(struct window *, u_int); -void layout_next(struct window *); -void layout_previous(struct window *); +struct layout_cell *layout_create_cell(struct layout_cell *); +void layout_free_cell(struct layout_cell *); +void layout_print_cell(struct layout_cell *, const char *, u_int); +void layout_set_size( + struct layout_cell *, u_int, u_int, u_int, u_int); +void layout_make_leaf( + struct layout_cell *, struct window_pane *); +void layout_make_node(struct layout_cell *, enum layout_type); +void layout_fix_offsets(struct layout_cell *); +void layout_fix_panes(struct window *, u_int, u_int); +u_int layout_resize_check(struct layout_cell *, enum layout_type); +void layout_resize_adjust( + struct layout_cell *, enum layout_type, int); +void layout_init(struct window *); +void layout_free(struct window *); +void layout_resize(struct window *, u_int, u_int); +void layout_resize_pane( + struct window_pane *, enum layout_type, int); +int layout_split_pane(struct window_pane *, + enum layout_type, int, struct window_pane *); +void layout_close_pane(struct window_pane *); -/* layout-manual.c */ -void layout_manual_v_refresh(struct window *, int); -void layout_manual_v_resize(struct window_pane *, int); +/* layout-set.c */ +const char *layout_set_name(u_int); +int layout_set_lookup(const char *); +u_int layout_set_select(struct window *, u_int); +u_int layout_set_next(struct window *); +u_int layout_set_previous(struct window *); +void layout_set_active_changed(struct window *); /* window-clock.c */ extern const struct window_mode window_clock_mode; diff --git a/window.c b/window.c index 81b4d34e..d7d16ed3 100644 --- a/window.c +++ b/window.c @@ -35,7 +35,7 @@ #include "tmux.h" /* - * Each window is attached to one or two panes, each of which is a pty. This + * Each window is attached to a number of panes, each of which is a pty. This * file contains code to handle them. * * A pane has two buffers attached, these are filled and emptied by the main @@ -230,8 +230,10 @@ window_create1(u_int sx, u_int sy) TAILQ_INIT(&w->panes); w->active = NULL; - w->layout = 0; + w->layout = 0; + w->layout_root = NULL; + w->sx = sx; w->sy = sy; @@ -254,15 +256,20 @@ struct window * window_create(const char *name, const char *cmd, const char *cwd, const char **envp, u_int sx, u_int sy, u_int hlimit, char **cause) { - struct window *w; + struct window *w; + struct window_pane *wp; w = window_create1(sx, sy); - if (window_add_pane(w, -1, cmd, cwd, envp, hlimit, cause) == NULL) { + if ((wp = window_add_pane(w, hlimit, cause)) == NULL) { + window_destroy(w); + return (NULL); + } + layout_init(w); + if (window_pane_spawn(wp, cmd, cwd, envp, cause) != 0) { window_destroy(w); return (NULL); } w->active = TAILQ_FIRST(&w->panes); - if (name != NULL) { w->name = xstrdup(name); options_set_number(&w->options, "automatic-rename", 0); @@ -282,6 +289,9 @@ window_destroy(struct window *w) while (!ARRAY_EMPTY(&windows) && ARRAY_LAST(&windows) == NULL) ARRAY_TRUNC(&windows, 1); + if (w->layout_root != NULL) + layout_free(w); + options_free(&w->options); window_destroy_panes(w); @@ -304,7 +314,6 @@ void window_set_active_pane(struct window *w, struct window_pane *wp) { w->active = wp; - while (!window_pane_visible(w->active)) { w->active = TAILQ_PREV(w->active, window_panes, entry); if (w->active == NULL) @@ -315,41 +324,15 @@ window_set_active_pane(struct window *w, struct window_pane *wp) } struct window_pane * -window_add_pane(struct window *w, int wanty, const char *cmd, - const char *cwd, const char **envp, u_int hlimit, char **cause) +window_add_pane(struct window *w, u_int hlimit, unused char **cause) { struct window_pane *wp; - u_int sizey; - if (TAILQ_EMPTY(&w->panes)) - wanty = w->sy; - else { - sizey = w->active->sy - 1; /* for separator */ - if (sizey < PANE_MINIMUM * 2) { - *cause = xstrdup("pane too small"); - return (NULL); - } - - if (wanty == -1) - wanty = sizey / 2; - - if (wanty < PANE_MINIMUM) - wanty = PANE_MINIMUM; - if ((u_int) wanty > sizey - PANE_MINIMUM) - wanty = sizey - PANE_MINIMUM; - - window_pane_resize(w->active, w->sx, sizey - wanty); - } - - wp = window_pane_create(w, w->sx, wanty, hlimit); + wp = window_pane_create(w, w->sx, w->sy, hlimit); if (TAILQ_EMPTY(&w->panes)) TAILQ_INSERT_HEAD(&w->panes, wp, entry); else TAILQ_INSERT_AFTER(&w->panes, w->active, wp, entry); - if (window_pane_spawn(wp, cmd, cwd, envp, cause) != 0) { - window_remove_pane(w, wp); - return (NULL); - } return (wp); } @@ -435,6 +418,8 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit) wp->mode = NULL; + wp->layout_cell = NULL; + wp->xoff = 0; wp->yoff = 0; From 550b855c9d41cfb576007e20ba55f0f53937e8f6 Mon Sep 17 00:00:00 2001 From: Jason McIntyre Date: Sun, 19 Jul 2009 14:07:47 +0000 Subject: [PATCH 0143/1180] tweak previous; --- tmux.1 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tmux.1 b/tmux.1 index 3540ae98..d621c8d0 100644 --- a/tmux.1 +++ b/tmux.1 @@ -987,7 +987,7 @@ Rename the current window, or the window at if specified, to .Ar new-name . .It Xo Ic resize-pane -.Op Fl DLUR +.Op Fl DLRU .Op Fl p Ar pane-index .Op Fl t Ar target-window .Op Ar adjustment @@ -1000,7 +1000,7 @@ Resize a pane, upward with to the left with .Fl L and to the right with -.Fl R. +.Fl R . The .Ar adjustment is given in lines or cells (the default is 1). @@ -1339,7 +1339,7 @@ This option defaults to off. .Op Ic on | Ic off .Xc If on, display a status line message when activity occurs in a window -for with the +for which the .Ic monitor-activity window option is enabled. .It Xo Ic visual-bell @@ -1356,7 +1356,7 @@ option. Like .Ic visual-activity , display a message when content is present in a window -for with the +for which the .Ic monitor-content window option is enabled. .El From ff2cc0e38709b285293fd38ab720f4eb785ce361 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 20 Jul 2009 07:13:31 +0000 Subject: [PATCH 0144/1180] Move the offsets as well when swapping panes. --- cmd-swap-pane.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cmd-swap-pane.c b/cmd-swap-pane.c index 0f0633d8..be8b2e07 100644 --- a/cmd-swap-pane.c +++ b/cmd-swap-pane.c @@ -158,7 +158,7 @@ cmd_swap_pane_exec(struct cmd *self, struct cmd_ctx *ctx) struct window *w; struct window_pane *tmp_wp, *src_wp, *dst_wp; struct layout_cell *lc; - u_int xx, yy; + u_int sx, sy, xoff, yoff; if (data == NULL) return (0); @@ -209,8 +209,6 @@ cmd_swap_pane_exec(struct cmd *self, struct cmd_ctx *ctx) TAILQ_INSERT_AFTER(&w->panes, tmp_wp, src_wp, entry); lc = src_wp->layout_cell; - xx = src_wp->xoff; - yy = src_wp->yoff; src_wp->layout_cell = dst_wp->layout_cell; if (src_wp->layout_cell != NULL) src_wp->layout_cell->wp = src_wp; @@ -218,10 +216,12 @@ cmd_swap_pane_exec(struct cmd *self, struct cmd_ctx *ctx) if (dst_wp->layout_cell != NULL) dst_wp->layout_cell->wp = dst_wp; - xx = src_wp->sx; - yy = src_wp->sy; + sx = src_wp->sx; sy = src_wp->sy; + xoff = src_wp->xoff; yoff = src_wp->yoff; + src_wp->xoff = dst_wp->xoff; src_wp->yoff = dst_wp->yoff; window_pane_resize(src_wp, dst_wp->sx, dst_wp->sy); - window_pane_resize(dst_wp, xx, yy); + dst_wp->xoff = xoff; dst_wp->yoff = yoff; + window_pane_resize(dst_wp, sx, sy); if (!data->flag_detached) { tmp_wp = dst_wp; From 73732ffa0585faacb53b6f7bb9f741c54251dd6d Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 20 Jul 2009 07:31:10 +0000 Subject: [PATCH 0145/1180] Kill some dead stores and fix a null pointer deref, found by clang. --- cmd-command-prompt.c | 2 ++ layout-set.c | 10 ++++------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cmd-command-prompt.c b/cmd-command-prompt.c index 196376b1..872fa326 100644 --- a/cmd-command-prompt.c +++ b/cmd-command-prompt.c @@ -140,6 +140,8 @@ cmd_command_prompt_callback(void *data, const char *s) } } + if (buf == NULL) + return (0); buf[len] = '\0'; s = buf; } diff --git a/layout-set.c b/layout-set.c index ae99f6ff..4433d0cf 100644 --- a/layout-set.c +++ b/layout-set.c @@ -122,10 +122,9 @@ layout_set_even_h(struct window *w) return; /* How many can we fit? */ - if (w->sx / n < PANE_MINIMUM + 1) { + if (w->sx / n < PANE_MINIMUM + 1) width = PANE_MINIMUM + 1; - n = UINT_MAX; - } else + else width = w->sx / n; /* Free the old root and construct a new. */ @@ -177,10 +176,9 @@ layout_set_even_v(struct window *w) return; /* How many can we fit? */ - if (w->sy / n < PANE_MINIMUM + 1) { + if (w->sy / n < PANE_MINIMUM + 1) height = PANE_MINIMUM + 1; - n = UINT_MAX; - } else + else height = w->sy / n; /* Free the old root and construct a new. */ From e32e0d569294ca7162f197cc7c369cd57050b193 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 20 Jul 2009 09:15:18 +0000 Subject: [PATCH 0146/1180] New options, window-status-current-{fg,bg,attr}, to set the fg, bg and attributes with which the current window is shown in the status line. From Johan Friis, thanks. --- cmd-set-window-option.c | 3 +++ status.c | 12 +++++++++++- tmux.1 | 6 ++++++ tmux.c | 3 +++ 4 files changed, 23 insertions(+), 1 deletion(-) diff --git a/cmd-set-window-option.c b/cmd-set-window-option.c index 9499b46a..8c0faa0d 100644 --- a/cmd-set-window-option.c +++ b/cmd-set-window-option.c @@ -68,6 +68,9 @@ const struct set_option_entry set_window_option_table[] = { { "utf8", SET_OPTION_FLAG, 0, 0, NULL }, { "window-status-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL }, { "window-status-bg", SET_OPTION_COLOUR, 0, 0, NULL }, + { "window-status-current-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL }, + { "window-status-current-bg", SET_OPTION_COLOUR, 0, 0, NULL }, + { "window-status-current-fg", SET_OPTION_COLOUR, 0, 0, NULL }, { "window-status-fg", SET_OPTION_COLOUR, 0, 0, NULL }, { "xterm-keys", SET_OPTION_FLAG, 0, 0, NULL }, { NULL, 0, 0, 0, NULL } diff --git a/status.c b/status.c index c5190b54..61f5e22c 100644 --- a/status.c +++ b/status.c @@ -460,8 +460,18 @@ status_print(struct session *s, struct winlink *wl, struct grid_cell *gc) flag = ' '; if (wl == SLIST_FIRST(&s->lastw)) flag = '-'; - if (wl == s->curw) + if (wl == s->curw) { + fg = options_get_number(&wl->window->options, "window-status-current-fg"); + if (fg != 8) + gc->fg = fg; + bg = options_get_number(&wl->window->options, "window-status-current-bg"); + if (bg != 8) + gc->bg = bg; + attr = options_get_number(&wl->window->options, "window-status-current-attr"); + if (attr != 0) + gc->attr = attr; flag = '*'; + } if (session_alert_has(s, wl, WINDOW_ACTIVITY)) { flag = '#'; diff --git a/tmux.1 b/tmux.1 index d621c8d0..c4841b8c 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1489,6 +1489,12 @@ Set status line attributes for a single window. Set status line background colour for a single window. .It Ic window-status-fg Ar colour Set status line foreground colour for a single window. +.It Ic window-status-current-attr Ar attributes +Set status line attributes for the currently active window. +.It Ic window-status-current-bg Ar colour +Set status line background colour for the currently active window. +.It Ic window-status-current-fg Ar colour +Set status line foreground colour for the currently active window. .It Xo Ic xterm-keys .Op Ic on | Ic off .Xc diff --git a/tmux.c b/tmux.c index 5cca15f6..915bb432 100644 --- a/tmux.c +++ b/tmux.c @@ -338,6 +338,9 @@ main(int argc, char **argv) options_set_number(&global_w_options, "window-status-attr", 0); options_set_number(&global_w_options, "window-status-bg", 8); options_set_number(&global_w_options, "window-status-fg", 8); + options_set_number(&global_w_options, "window-status-current-attr", 0); + options_set_number(&global_w_options, "window-status-current-bg", 8); + options_set_number(&global_w_options, "window-status-current-fg", 8); options_set_number(&global_w_options, "xterm-keys", 0); options_set_number(&global_w_options, "remain-on-exit", 0); From b292f71c49b4222b34684aee44029ca2d6aeb4dd Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 20 Jul 2009 14:32:09 +0000 Subject: [PATCH 0147/1180] Add a status-justify option to allow the window list in the status line to be positioned at the left, centre, or right. --- cmd-set-option.c | 5 +++++ status.c | 17 ++++++++++++++++- tmux.1 | 5 +++++ tmux.c | 1 + 4 files changed, 27 insertions(+), 1 deletion(-) diff --git a/cmd-set-option.c b/cmd-set-option.c index fc665e84..5144418e 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -45,6 +45,9 @@ const struct cmd_entry cmd_set_option_entry = { const char *set_option_status_keys_list[] = { "emacs", "vi", NULL }; +const char *set_option_status_justify_list[] = { + "left", "centre", "right", NULL +}; const char *set_option_bell_action_list[] = { "none", "any", "current", NULL }; @@ -69,6 +72,8 @@ const struct set_option_entry set_option_table[] = { { "status-bg", SET_OPTION_COLOUR, 0, 0, NULL }, { "status-fg", SET_OPTION_COLOUR, 0, 0, NULL }, { "status-interval", SET_OPTION_NUMBER, 0, INT_MAX, NULL }, + { "status-justify", + SET_OPTION_CHOICE, 0, 0, set_option_status_justify_list }, { "status-keys", SET_OPTION_CHOICE, 0, 0, set_option_status_keys_list }, { "status-left", SET_OPTION_STRING, 0, 0, NULL }, { "status-left-length", SET_OPTION_NUMBER, 0, SHRT_MAX, NULL }, diff --git a/status.c b/status.c index 61f5e22c..b4cbc6b1 100644 --- a/status.c +++ b/status.c @@ -46,7 +46,7 @@ status_redraw(struct client *c) struct screen old_status; char *left, *right, *text, *ptr; size_t llen, llen2, rlen, rlen2, offset; - size_t xx, yy, size, start, width; + size_t ox, xx, yy, size, start, width; struct grid_cell stdgc, gc; int larrow, rarrow, utf8flag; @@ -175,6 +175,21 @@ draw: screen_write_cursormove(&ctx, 0, yy); } + ox = 0; + if (width < xx) { + switch (options_get_number(&s->options, "status-justify")) { + case 1: /* centered */ + ox = 1 + (xx - width) / 2; + break; + case 2: /* right */ + ox = 1 + (xx - width); + break; + } + xx -= ox; + while (ox-- > 0) + screen_write_putc(&ctx, &stdgc, ' '); + } + /* Draw each character in succession. */ offset = 0; RB_FOREACH(wl, winlinks, &s->windows) { diff --git a/tmux.1 b/tmux.1 index c4841b8c..fc2f4c31 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1262,6 +1262,11 @@ Update the status bar every seconds. By default, updates will occur every 15 seconds. A setting of zero disables redrawing at interval. +.It Xo Ic status-justify +.Op Ic left | Ic centre | Ic right +.Xc +Set the position of the window list component of the status line: left, centre +or right justified. .It Xo Ic status-keys .Op Ic vi | Ic emacs .Xc diff --git a/tmux.c b/tmux.c index 915bb432..d8499202 100644 --- a/tmux.c +++ b/tmux.c @@ -303,6 +303,7 @@ main(int argc, char **argv) options_set_number(&global_s_options, "status-fg", 0); options_set_number(&global_s_options, "status-interval", 15); options_set_number(&global_s_options, "status-keys", MODEKEY_EMACS); + options_set_number(&global_s_options, "status-justify", 0); options_set_number(&global_s_options, "status-left-length", 10); options_set_number(&global_s_options, "status-right-length", 40); options_set_string(&global_s_options, "status-left", "[#S]"); From 54afcfbfb4e0e972455b870887151cb04d29c9c7 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 20 Jul 2009 14:37:51 +0000 Subject: [PATCH 0148/1180] Display the number of failed password attempts (if any) when the server is locked. From Tom Doherty. --- server-fn.c | 4 +++- server.c | 12 ++++++++++++ tmux.c | 1 + tmux.h | 1 + 4 files changed, 17 insertions(+), 1 deletion(-) diff --git a/server-fn.c b/server-fn.c index 3080bed4..409f65bc 100644 --- a/server-fn.c +++ b/server-fn.c @@ -213,9 +213,11 @@ server_unlock(const char *s) } server_locked = 0; + password_failures = 0; return (0); wrong: + password_failures++; for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); if (c == NULL || c->prompt_buffer == NULL) @@ -223,7 +225,7 @@ wrong: *c->prompt_buffer = '\0'; c->prompt_index = 0; - server_status_client(c); + server_redraw_client(c); } return (-1); diff --git a/server.c b/server.c index 250f3187..7207ae94 100644 --- a/server.c +++ b/server.c @@ -579,6 +579,7 @@ server_redraw_locked(struct client *c) { struct screen_write_ctx ctx; struct screen screen; + struct grid_cell gc; u_int colour, xx, yy, i; int style; @@ -589,10 +590,21 @@ server_redraw_locked(struct client *c) colour = options_get_number(&global_w_options, "clock-mode-colour"); style = options_get_number(&global_w_options, "clock-mode-style"); + memcpy(&gc, &grid_default_cell, sizeof gc); + gc.fg = colour; + gc.attr |= GRID_ATTR_BRIGHT; + screen_init(&screen, xx, yy, 0); screen_write_start(&ctx, NULL, &screen); clock_draw(&ctx, colour, style); + + if (password_failures != 0) { + screen_write_cursormove(&ctx, 0, 0); + screen_write_puts( + &ctx, &gc, "%u failed attempts", password_failures); + } + screen_write_stop(&ctx); for (i = 0; i < screen_size_y(&screen); i++) diff --git a/tmux.c b/tmux.c index d8499202..9ca1783f 100644 --- a/tmux.c +++ b/tmux.c @@ -46,6 +46,7 @@ struct options global_s_options; /* session options */ struct options global_w_options; /* window options */ int server_locked; +u_int password_failures; char *server_password; time_t server_activity; diff --git a/tmux.h b/tmux.h index 22621c4c..37162f77 100644 --- a/tmux.h +++ b/tmux.h @@ -998,6 +998,7 @@ extern struct options global_s_options; extern struct options global_w_options; extern char *cfg_file; extern int server_locked; +extern u_int password_failures; extern char *server_password; extern time_t server_activity; extern int debug_level; From c0862dae458ed6a656069815317cf8d05faaafa3 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 20 Jul 2009 15:51:55 +0000 Subject: [PATCH 0149/1180] Tweak unbind-key language very slightly. --- tmux.1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tmux.1 b/tmux.1 index fc2f4c31..7e67e782 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1618,7 +1618,7 @@ to .Ar key .Xc .D1 (alias: Ic unbind ) -Unbind the key bound to +Unbind the command bound to .Ar key . .It Xo Ic unlink-window .Op Fl k From c6012aaabc1eb10f42f77a1836c6e38faa7e396e Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 20 Jul 2009 19:35:33 +0000 Subject: [PATCH 0150/1180] Now that #P could be in the status line, flag it for redraw when the active pane changes. --- cmd-down-pane.c | 1 + cmd-select-pane.c | 1 + cmd-up-pane.c | 1 + 3 files changed, 3 insertions(+) diff --git a/cmd-down-pane.c b/cmd-down-pane.c index 640ad5bd..c3c12dba 100644 --- a/cmd-down-pane.c +++ b/cmd-down-pane.c @@ -55,6 +55,7 @@ cmd_down_pane_exec(struct cmd *self, struct cmd_ctx *ctx) if (w->active == NULL) w->active = TAILQ_FIRST(&w->panes); } while (!window_pane_visible(w->active)); + server_status_window(wl->window); return (0); } diff --git a/cmd-select-pane.c b/cmd-select-pane.c index 6a9dec42..39b89cac 100644 --- a/cmd-select-pane.c +++ b/cmd-select-pane.c @@ -63,6 +63,7 @@ cmd_select_pane_exec(struct cmd *self, struct cmd_ctx *ctx) return (-1); } window_set_active_pane(wl->window, wp); + server_status_window(wl->window); return (0); } diff --git a/cmd-up-pane.c b/cmd-up-pane.c index 8b262c60..c2d063d0 100644 --- a/cmd-up-pane.c +++ b/cmd-up-pane.c @@ -55,6 +55,7 @@ cmd_up_pane_exec(struct cmd *self, struct cmd_ctx *ctx) if (w->active == NULL) w->active = TAILQ_LAST(&w->panes, window_panes); } while (!window_pane_visible(w->active)); + server_status_window(wl->window); return (0); } From 725938fb85290ca67ab50e27f9cacb870ff56c63 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 21 Jul 2009 17:57:29 +0000 Subject: [PATCH 0151/1180] Tidy up keys: use an enum for the key codes, and remove the macros which just wrap flag sets/clears/tests. --- cmd-next-window.c | 2 +- cmd-previous-window.c | 2 +- cmd-resize-pane.c | 18 +++--- cmd-rotate-window.c | 2 +- cmd-select-layout.c | 10 ++-- input-keys.c | 50 ++++++++--------- key-bindings.c | 30 +++++----- key-string.c | 18 +++--- mode-key.c | 14 ++--- tmux.h | 127 +++++++++++++++++++----------------------- tty-keys.c | 41 ++++++-------- 11 files changed, 149 insertions(+), 165 deletions(-) diff --git a/cmd-next-window.c b/cmd-next-window.c index f0f8d18e..b7608f33 100644 --- a/cmd-next-window.c +++ b/cmd-next-window.c @@ -48,7 +48,7 @@ cmd_next_window_init(struct cmd *self, int key) cmd_target_init(self, key); data = self->data; - if (key == KEYC_ADDESC('n')) + if (key == ('n' | KEYC_ESCAPE)) data->chflags |= CMD_CHFLAG('a'); } diff --git a/cmd-previous-window.c b/cmd-previous-window.c index 2c5088b2..6b26704e 100644 --- a/cmd-previous-window.c +++ b/cmd-previous-window.c @@ -48,7 +48,7 @@ cmd_previous_window_init(struct cmd *self, int key) cmd_target_init(self, key); data = self->data; - if (key == KEYC_ADDESC('p')) + if (key == ('p' | KEYC_ESCAPE)) data->chflags |= CMD_CHFLAG('a'); } diff --git a/cmd-resize-pane.c b/cmd-resize-pane.c index 5e9f67e3..b0ea214c 100644 --- a/cmd-resize-pane.c +++ b/cmd-resize-pane.c @@ -51,28 +51,28 @@ cmd_resize_pane_init(struct cmd *self, int key) cmd_pane_init(self, key); data = self->data; - if (key == KEYC_ADDCTL(KEYC_UP)) + if (key == (KEYC_UP | KEYC_CTRL)) data->chflags |= CMD_CHFLAG('U'); - if (key == KEYC_ADDCTL(KEYC_DOWN)) + if (key == (KEYC_DOWN | KEYC_CTRL)) data->chflags |= CMD_CHFLAG('D'); - if (key == KEYC_ADDCTL(KEYC_LEFT)) + if (key == (KEYC_LEFT | KEYC_CTRL)) data->chflags |= CMD_CHFLAG('L'); - if (key == KEYC_ADDCTL(KEYC_RIGHT)) + if (key == (KEYC_RIGHT | KEYC_CTRL)) data->chflags |= CMD_CHFLAG('R'); - - if (key == KEYC_ADDESC(KEYC_UP)) { + + if (key == (KEYC_UP | KEYC_ESCAPE)) { data->chflags |= CMD_CHFLAG('U'); data->arg = xstrdup("5"); } - if (key == KEYC_ADDESC(KEYC_DOWN)) { + if (key == (KEYC_DOWN | KEYC_ESCAPE)) { data->chflags |= CMD_CHFLAG('D'); data->arg = xstrdup("5"); } - if (key == KEYC_ADDESC(KEYC_LEFT)) { + if (key == (KEYC_LEFT | KEYC_ESCAPE)) { data->chflags |= CMD_CHFLAG('L'); data->arg = xstrdup("5"); } - if (key == KEYC_ADDESC(KEYC_RIGHT)) { + if (key == (KEYC_RIGHT | KEYC_ESCAPE)) { data->chflags |= CMD_CHFLAG('R'); data->arg = xstrdup("5"); } diff --git a/cmd-rotate-window.c b/cmd-rotate-window.c index c69fa8d1..c12345d6 100644 --- a/cmd-rotate-window.c +++ b/cmd-rotate-window.c @@ -48,7 +48,7 @@ cmd_rotate_window_init(struct cmd *self, int key) cmd_target_init(self, key); data = self->data; - if (key == KEYC_ADDESC('o')) + if (key == ('o' | KEYC_ESCAPE)) data->chflags |= CMD_CHFLAG('D'); } diff --git a/cmd-select-layout.c b/cmd-select-layout.c index 953cb69f..6329a9b7 100644 --- a/cmd-select-layout.c +++ b/cmd-select-layout.c @@ -49,16 +49,16 @@ cmd_select_layout_init(struct cmd *self, int key) data = self->data; switch (key) { - case KEYC_ADDESC('1'): + case ('1' | KEYC_ESCAPE): data->arg = xstrdup("even-horizontal"); break; - case KEYC_ADDESC('2'): + case ('2' | KEYC_ESCAPE): data->arg = xstrdup("even-vertical"); - break; - case KEYC_ADDESC('3'): + break; + case ('3' | KEYC_ESCAPE): data->arg = xstrdup("main-horizontal"); break; - case KEYC_ADDESC('4'): + case ('4' | KEYC_ESCAPE): data->arg = xstrdup("main-vertical"); break; } diff --git a/input-keys.c b/input-keys.c index 24c0bbaa..0afe6e47 100644 --- a/input-keys.c +++ b/input-keys.c @@ -66,16 +66,16 @@ struct input_key_ent input_keys[] = { { KEYC_BTAB, "\033[Z", INPUTKEY_CTRL }, /* Arrow keys. Cursor versions must come first. */ - { KEYC_ADDCTL(KEYC_UP), "\033Oa", 0 }, - { KEYC_ADDCTL(KEYC_DOWN), "\033Ob", 0 }, - { KEYC_ADDCTL(KEYC_RIGHT), "\033Oc", 0 }, - { KEYC_ADDCTL(KEYC_LEFT), "\033Od", 0 }, - - { KEYC_ADDSFT(KEYC_UP), "\033[a", 0 }, - { KEYC_ADDSFT(KEYC_DOWN), "\033[b", 0 }, - { KEYC_ADDSFT(KEYC_RIGHT), "\033[c", 0 }, - { KEYC_ADDSFT(KEYC_LEFT), "\033[d", 0 }, - + { KEYC_UP | KEYC_CTRL, "\033Oa", 0 }, + { KEYC_DOWN | KEYC_CTRL, "\033Ob", 0 }, + { KEYC_RIGHT | KEYC_CTRL, "\033Oc", 0 }, + { KEYC_LEFT | KEYC_CTRL, "\033Od", 0 }, + + { KEYC_UP | KEYC_SHIFT, "\033[a", 0 }, + { KEYC_DOWN | KEYC_SHIFT, "\033[b", 0 }, + { KEYC_RIGHT | KEYC_SHIFT, "\033[c", 0 }, + { KEYC_LEFT | KEYC_SHIFT, "\033[d", 0 }, + { KEYC_UP, "\033OA", INPUTKEY_CURSOR }, { KEYC_DOWN, "\033OB", INPUTKEY_CURSOR }, { KEYC_RIGHT, "\033OC", INPUTKEY_CURSOR }, @@ -133,10 +133,10 @@ input_key(struct window_pane *wp, int key) log_debug2("writing key 0x%x", key); - if (key != KEYC_NONE && KEYC_REMOVEESC(key) < KEYC_OFFSET) { - if (KEYC_ISESC(key)) + if (key != KEYC_NONE && (key & ~KEYC_ESCAPE) < 0x100) { + if (key & KEYC_ESCAPE) buffer_write8(wp->out, '\033'); - buffer_write8(wp->out, (uint8_t) KEYC_REMOVEESC(key)); + buffer_write8(wp->out, (uint8_t) (key & ~KEYC_ESCAPE)); return; } @@ -150,11 +150,11 @@ input_key(struct window_pane *wp, int key) !(wp->screen->mode & MODE_KCURSOR)) continue; - if (KEYC_ISESC(key) && KEYC_ADDESC(ike->key) == key) + if ((key & KEYC_ESCAPE) && (ike->key | KEYC_ESCAPE) == key) break; - if (KEYC_ISSFT(key) && KEYC_ADDSFT(ike->key) == key) + if ((key & KEYC_SHIFT) && (ike->key | KEYC_SHIFT) == key) break; - if (KEYC_ISCTL(key) && KEYC_ADDCTL(ike->key) == key) { + if ((key & KEYC_CTRL) && (ike->key | KEYC_CTRL) == key) { if (ike->flags & INPUTKEY_CTRL) break; } @@ -176,19 +176,19 @@ input_key(struct window_pane *wp, int key) xterm_keys = options_get_number(&wp->window->options, "xterm-keys"); if (xterm_keys && ike->flags & INPUTKEY_XTERM) { ch = '\0'; - if (KEYC_ISSFT(key) && KEYC_ISESC(key) && KEYC_ISCTL(key)) + if (key & (KEYC_SHIFT|KEYC_ESCAPE|KEYC_CTRL)) ch = '8'; - else if (KEYC_ISESC(key) && KEYC_ISCTL(key)) + else if (key & (KEYC_ESCAPE|KEYC_CTRL)) ch = '7'; - else if (KEYC_ISSFT(key) && KEYC_ISCTL(key)) + else if (key & (KEYC_SHIFT|KEYC_CTRL)) ch = '6'; - else if (KEYC_ISCTL(key)) + else if (key & KEYC_CTRL) ch = '5'; - else if (KEYC_ISSFT(key) && KEYC_ISESC(key)) + else if (key & (KEYC_SHIFT|KEYC_ESCAPE)) ch = '4'; - else if (KEYC_ISESC(key)) + else if (key & KEYC_ESCAPE) ch = '3'; - else if (KEYC_ISSFT(key)) + else if (key & KEYC_SHIFT) ch = '2'; if (ch != '\0') { buffer_write(wp->out, ike->data, dlen - 1); @@ -204,9 +204,9 @@ input_key(struct window_pane *wp, int key) * Not in xterm mode. Prefix a \033 for escape, and set bit 5 of the * last byte for ctrl. */ - if (KEYC_ISESC(key)) + if (key & KEYC_ESCAPE) buffer_write8(wp->out, '\033'); - if (KEYC_ISCTL(key) && ike->flags & INPUTKEY_CTRL) { + if (key & KEYC_CTRL && ike->flags & INPUTKEY_CTRL) { buffer_write(wp->out, ike->data, dlen - 1); buffer_write8(wp->out, ike->data[dlen - 1] ^ 0x20); return; diff --git a/key-bindings.c b/key-bindings.c index 66ed4927..d37e23b3 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -133,24 +133,24 @@ key_bindings_init(void) { '{', 0, &cmd_swap_pane_entry }, { '}', 0, &cmd_swap_pane_entry }, { '\002', 0, &cmd_send_prefix_entry }, - { KEYC_ADDESC('1'), 0, &cmd_select_layout_entry }, - { KEYC_ADDESC('2'), 0, &cmd_select_layout_entry }, - { KEYC_ADDESC('3'), 0, &cmd_select_layout_entry }, - { KEYC_ADDESC('4'), 0, &cmd_select_layout_entry }, + { '1' | KEYC_ESCAPE, 0, &cmd_select_layout_entry }, + { '2' | KEYC_ESCAPE, 0, &cmd_select_layout_entry }, + { '3' | KEYC_ESCAPE, 0, &cmd_select_layout_entry }, + { '4' | KEYC_ESCAPE, 0, &cmd_select_layout_entry }, { KEYC_PPAGE, 0, &cmd_scroll_mode_entry }, - { KEYC_ADDESC('n'), 0, &cmd_next_window_entry }, - { KEYC_ADDESC('p'), 0, &cmd_previous_window_entry }, + { 'n' | KEYC_ESCAPE, 0, &cmd_next_window_entry }, + { 'p' | KEYC_ESCAPE, 0, &cmd_previous_window_entry }, { KEYC_UP, 0, &cmd_up_pane_entry }, { KEYC_DOWN, 0, &cmd_down_pane_entry }, - { KEYC_ADDESC(KEYC_UP), 1, &cmd_resize_pane_entry }, - { KEYC_ADDESC(KEYC_DOWN), 1, &cmd_resize_pane_entry }, - { KEYC_ADDESC(KEYC_LEFT), 1, &cmd_resize_pane_entry }, - { KEYC_ADDESC(KEYC_RIGHT),1, &cmd_resize_pane_entry }, - { KEYC_ADDCTL(KEYC_UP), 1, &cmd_resize_pane_entry }, - { KEYC_ADDCTL(KEYC_DOWN), 1, &cmd_resize_pane_entry }, - { KEYC_ADDCTL(KEYC_LEFT), 1, &cmd_resize_pane_entry }, - { KEYC_ADDCTL(KEYC_RIGHT),1, &cmd_resize_pane_entry }, - { KEYC_ADDESC('o'), 0, &cmd_rotate_window_entry }, + { KEYC_UP | KEYC_ESCAPE, 1, &cmd_resize_pane_entry }, + { KEYC_DOWN | KEYC_ESCAPE, 1, &cmd_resize_pane_entry }, + { KEYC_LEFT | KEYC_ESCAPE, 1, &cmd_resize_pane_entry }, + { KEYC_RIGHT | KEYC_ESCAPE, 1, &cmd_resize_pane_entry }, + { KEYC_UP | KEYC_CTRL, 1, &cmd_resize_pane_entry }, + { KEYC_DOWN | KEYC_CTRL, 1, &cmd_resize_pane_entry }, + { KEYC_LEFT | KEYC_CTRL, 1, &cmd_resize_pane_entry }, + { KEYC_RIGHT | KEYC_CTRL, 1, &cmd_resize_pane_entry }, + { 'o' | KEYC_ESCAPE, 0, &cmd_rotate_window_entry }, { '\017', 0, &cmd_rotate_window_entry }, }; u_int i; diff --git a/key-string.c b/key-string.c index cf146b98..d70fe69b 100644 --- a/key-string.c +++ b/key-string.c @@ -126,7 +126,7 @@ key_string_lookup_string(const char *string) } key = key_string_search_table(ptr); if (key != KEYC_NONE) - return (KEYC_ADDCTL(key)); + return (key | KEYC_CTRL); return (KEYC_NONE); } @@ -137,11 +137,11 @@ key_string_lookup_string(const char *string) if (ptr[1] == '\0') { if (ptr[0] < 32 || ptr[0] > 127) return (KEYC_NONE); - return (KEYC_ADDESC(ptr[0])); + return (ptr[0] | KEYC_ESCAPE); } key = key_string_lookup_string(ptr); if (key != KEYC_NONE) - return (KEYC_ADDESC(key)); + return (key | KEYC_ESCAPE); return (KEYC_NONE); } @@ -158,20 +158,20 @@ key_string_lookup_key(int key) if (key == 127) return (NULL); - if (KEYC_ISESC(key)) { - if ((s = key_string_lookup_key(KEYC_REMOVEESC(key))) == NULL) + if (key & KEYC_ESCAPE) { + if ((s = key_string_lookup_key(key & ~KEYC_ESCAPE)) == NULL) return (NULL); xsnprintf(tmp2, sizeof tmp2, "M-%s", s); return (tmp2); } - if (KEYC_ISCTL(key)) { - if ((s = key_string_lookup_key(KEYC_REMOVECTL(key))) == NULL) + if (key & KEYC_CTRL) { + if ((s = key_string_lookup_key(key & ~KEYC_CTRL)) == NULL) return (NULL); xsnprintf(tmp2, sizeof tmp2, "C-%s", s); return (tmp2); } - if (KEYC_ISSFT(key)) { - if ((s = key_string_lookup_key(KEYC_REMOVESFT(key))) == NULL) + if (key & KEYC_SHIFT) { + if ((s = key_string_lookup_key(key & ~KEYC_SHIFT)) == NULL) return (NULL); xsnprintf(tmp2, sizeof tmp2, "S-%s", s); return (tmp2); diff --git a/mode-key.c b/mode-key.c index 8f822cb0..508760bd 100644 --- a/mode-key.c +++ b/mode-key.c @@ -54,8 +54,8 @@ mode_key_lookup(struct mode_key_data *mdata, int key) enum mode_key_cmd mode_key_lookup_vi(struct mode_key_data *mdata, int key) { - if (KEYC_ISESC(key)) { - key = KEYC_REMOVEESC(key); + if (key & KEYC_ESCAPE) { + key &= ~KEYC_ESCAPE; if (mdata->flags & MODEKEY_CANEDIT) mdata->flags ^= MODEKEY_EDITMODE; } @@ -161,12 +161,12 @@ mode_key_lookup_emacs(struct mode_key_data *mdata, int key) return (MODEKEYCMD_CHOOSE); case '\001': return (MODEKEYCMD_STARTOFLINE); - case KEYC_ADDESC('m'): + case 'm' | KEYC_ESCAPE: return (MODEKEYCMD_BACKTOINDENTATION); case '\007': return (MODEKEYCMD_CLEARSELECTION); case '\027': - case KEYC_ADDESC('w'): + case 'w' | KEYC_ESCAPE: return (MODEKEYCMD_COPYSELECTION); case '\016': case KEYC_DOWN: @@ -183,14 +183,14 @@ mode_key_lookup_emacs(struct mode_key_data *mdata, int key) case '\026': case KEYC_NPAGE: return (MODEKEYCMD_NEXTPAGE); - case KEYC_ADDESC('f'): + case 'f' | KEYC_ESCAPE: return (MODEKEYCMD_NEXTWORD); case '\031': return (MODEKEYCMD_PASTE); - case KEYC_ADDESC('v'): + case 'v' | KEYC_ESCAPE: case KEYC_PPAGE: return (MODEKEYCMD_PREVIOUSPAGE); - case KEYC_ADDESC('b'): + case 'b' | KEYC_ESCAPE: return (MODEKEYCMD_PREVIOUSWORD); case '\006': case KEYC_RIGHT: diff --git a/tmux.h b/tmux.h index 37162f77..34a0fd9b 100644 --- a/tmux.h +++ b/tmux.h @@ -102,79 +102,68 @@ struct buffer { #define BELL_CURRENT 2 /* Key codes. ncurses defines KEY_*. Grrr. */ -#define KEYC_NONE 0x00ffff -#define KEYC_OFFSET 0x010000 -#define KEYC_ESCAPE 0x020000 -#define KEYC_CONTROL 0x080000 -#define KEYC_SHIFT 0x100000 +#define KEYC_NONE 0x0fff +#define KEYC_ESCAPE 0x2000 +#define KEYC_CTRL 0x4000 +#define KEYC_SHIFT 0x8000 -#define KEYC_ADDESC(k) ((k) | KEYC_ESCAPE) -#define KEYC_REMOVEESC(k) ((k) & ~KEYC_ESCAPE) -#define KEYC_ISESC(k) ((k) != KEYC_NONE && ((k) & KEYC_ESCAPE)) +enum key_code { + /* Mouse key. */ + KEYC_MOUSE = 0x1000, -#define KEYC_ADDCTL(k) ((k) | KEYC_CONTROL) -#define KEYC_REMOVECTL(k) ((k) & ~KEYC_CONTROL) -#define KEYC_ISCTL(k) ((k) != KEYC_NONE && ((k) & KEYC_CONTROL)) + /* Function keys. */ + KEYC_F1, + KEYC_F2, + KEYC_F3, + KEYC_F4, + KEYC_F5, + KEYC_F6, + KEYC_F7, + KEYC_F8, + KEYC_F9, + KEYC_F10, + KEYC_F11, + KEYC_F12, + KEYC_F13, + KEYC_F14, + KEYC_F15, + KEYC_F16, + KEYC_F17, + KEYC_F18, + KEYC_F19, + KEYC_F20, + KEYC_IC, + KEYC_DC, + KEYC_HOME, + KEYC_END, + KEYC_NPAGE, + KEYC_PPAGE, + KEYC_BTAB, -#define KEYC_ADDSFT(k) ((k) | KEYC_SHIFT) -#define KEYC_REMOVESFT(k) ((k) & ~KEYC_SHIFT) -#define KEYC_ISSFT(k) ((k) != KEYC_NONE && ((k) & KEYC_SHIFT)) + /* Arrow keys. */ + KEYC_UP, + KEYC_DOWN, + KEYC_LEFT, + KEYC_RIGHT, -/* Mouse key. */ -#define KEYC_MOUSE (KEYC_OFFSET + 0x00) - -/* Function keys. */ -#define KEYC_F1 (KEYC_OFFSET + 0x01) -#define KEYC_F2 (KEYC_OFFSET + 0x02) -#define KEYC_F3 (KEYC_OFFSET + 0x03) -#define KEYC_F4 (KEYC_OFFSET + 0x04) -#define KEYC_F5 (KEYC_OFFSET + 0x05) -#define KEYC_F6 (KEYC_OFFSET + 0x06) -#define KEYC_F7 (KEYC_OFFSET + 0x07) -#define KEYC_F8 (KEYC_OFFSET + 0x08) -#define KEYC_F9 (KEYC_OFFSET + 0x09) -#define KEYC_F10 (KEYC_OFFSET + 0x10) -#define KEYC_F11 (KEYC_OFFSET + 0x11) -#define KEYC_F12 (KEYC_OFFSET + 0x12) -#define KEYC_F13 (KEYC_OFFSET + 0x13) -#define KEYC_F14 (KEYC_OFFSET + 0x14) -#define KEYC_F15 (KEYC_OFFSET + 0x15) -#define KEYC_F16 (KEYC_OFFSET + 0x16) -#define KEYC_F17 (KEYC_OFFSET + 0x17) -#define KEYC_F18 (KEYC_OFFSET + 0x18) -#define KEYC_F19 (KEYC_OFFSET + 0x19) -#define KEYC_F20 (KEYC_OFFSET + 0x1a) -#define KEYC_IC (KEYC_OFFSET + 0x1b) -#define KEYC_DC (KEYC_OFFSET + 0x1c) -#define KEYC_HOME (KEYC_OFFSET + 0x1d) -#define KEYC_END (KEYC_OFFSET + 0x1e) -#define KEYC_NPAGE (KEYC_OFFSET + 0x1f) -#define KEYC_PPAGE (KEYC_OFFSET + 0x20) -#define KEYC_BTAB (KEYC_OFFSET + 0x21) - -/* Arrow keys. */ -#define KEYC_UP (KEYC_OFFSET + 0x50) -#define KEYC_DOWN (KEYC_OFFSET + 0x51) -#define KEYC_LEFT (KEYC_OFFSET + 0x52) -#define KEYC_RIGHT (KEYC_OFFSET + 0x53) - -/* Numeric keypad. Numbered from top-left, KPY_X. */ -#define KEYC_KP0_1 (KEYC_OFFSET + 0x100) -#define KEYC_KP0_2 (KEYC_OFFSET + 0x101) -#define KEYC_KP0_3 (KEYC_OFFSET + 0x102) -#define KEYC_KP1_0 (KEYC_OFFSET + 0x103) -#define KEYC_KP1_1 (KEYC_OFFSET + 0x104) -#define KEYC_KP1_2 (KEYC_OFFSET + 0x105) -#define KEYC_KP1_3 (KEYC_OFFSET + 0x106) -#define KEYC_KP2_0 (KEYC_OFFSET + 0x107) -#define KEYC_KP2_1 (KEYC_OFFSET + 0x108) -#define KEYC_KP2_2 (KEYC_OFFSET + 0x109) -#define KEYC_KP3_0 (KEYC_OFFSET + 0x10a) -#define KEYC_KP3_1 (KEYC_OFFSET + 0x10b) -#define KEYC_KP3_2 (KEYC_OFFSET + 0x10c) -#define KEYC_KP3_3 (KEYC_OFFSET + 0x10d) -#define KEYC_KP4_0 (KEYC_OFFSET + 0x10e) -#define KEYC_KP4_2 (KEYC_OFFSET + 0x10f) + /* Numeric keypad. Numbered from top-left, KPY_X. */ + KEYC_KP0_1, + KEYC_KP0_2, + KEYC_KP0_3, + KEYC_KP1_0, + KEYC_KP1_1, + KEYC_KP1_2, + KEYC_KP1_3, + KEYC_KP2_0, + KEYC_KP2_1, + KEYC_KP2_2, + KEYC_KP3_0, + KEYC_KP3_1, + KEYC_KP3_2, + KEYC_KP3_3, + KEYC_KP4_0, + KEYC_KP4_2, +}; /* Termcap codes. */ enum tty_code_code { diff --git a/tty-keys.c b/tty-keys.c index 3b8a3b45..5e207aa6 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -76,14 +76,14 @@ struct tty_key_ent tty_keys[] = { { 0, "\033[C", KEYC_RIGHT, TTYKEY_RAW }, { 0, "\033[D", KEYC_LEFT, TTYKEY_RAW }, - { 0, "\033Oa", KEYC_ADDCTL(KEYC_UP), TTYKEY_RAW }, - { 0, "\033Ob", KEYC_ADDCTL(KEYC_DOWN), TTYKEY_RAW }, - { 0, "\033Oc", KEYC_ADDCTL(KEYC_RIGHT), TTYKEY_RAW }, - { 0, "\033Od", KEYC_ADDCTL(KEYC_LEFT), TTYKEY_RAW }, - { 0, "\033[a", KEYC_ADDSFT(KEYC_UP), TTYKEY_RAW }, - { 0, "\033[b", KEYC_ADDSFT(KEYC_DOWN), TTYKEY_RAW }, - { 0, "\033[c", KEYC_ADDSFT(KEYC_RIGHT), TTYKEY_RAW }, - { 0, "\033[d", KEYC_ADDSFT(KEYC_LEFT), TTYKEY_RAW }, + { 0, "\033Oa", KEYC_UP | KEYC_CTRL, TTYKEY_RAW }, + { 0, "\033Ob", KEYC_DOWN | KEYC_CTRL, TTYKEY_RAW }, + { 0, "\033Oc", KEYC_RIGHT | KEYC_CTRL, TTYKEY_RAW }, + { 0, "\033Od", KEYC_LEFT | KEYC_CTRL, TTYKEY_RAW }, + { 0, "\033[a", KEYC_UP | KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[b", KEYC_DOWN | KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[c", KEYC_RIGHT | KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[d", KEYC_LEFT | KEYC_SHIFT, TTYKEY_RAW }, { TTYC_KCUU1, NULL, KEYC_UP, TTYKEY_CTRL }, { TTYC_KCUD1, NULL, KEYC_DOWN, TTYKEY_CTRL }, @@ -179,7 +179,7 @@ tty_keys_init(struct tty *tty) if (strlcpy(tmp, s, sizeof tmp) >= sizeof tmp) continue; tmp[strlen(tmp) - 1] ^= 0x20; - tty_keys_add(tty, tmp + 1, KEYC_ADDCTL(tke->key), 0); + tty_keys_add(tty, tmp + 1, tke->key | KEYC_CTRL, 0); } } } @@ -289,7 +289,7 @@ tty_keys_next(struct tty *tty, int *key, u_char *mouse) /* Is there a normal key following? */ if (len != 0 && *buf != '\033') { buffer_remove(tty->in, 1); - *key = KEYC_ADDESC(buffer_read8(tty->in)); + *key = buffer_read8(tty->in) | KEYC_ESCAPE; goto found; } @@ -298,7 +298,7 @@ tty_keys_next(struct tty *tty, int *key, u_char *mouse) tk = tty_keys_find(tty, buf + 1, len - 1, &size); if (tk != NULL) { buffer_remove(tty->in, size + 2); - *key = KEYC_ADDESC(tk->key); + *key = tk->key | KEYC_ESCAPE; goto found; } } @@ -380,30 +380,25 @@ tty_keys_parse_xterm(struct tty *tty, char *buf, size_t len, size_t *size) switch (buf[4]) { case '8': - key = KEYC_ADDSFT(key); - key = KEYC_ADDESC(key); - key = KEYC_ADDCTL(key); + key |= KEYC_SHIFT|KEYC_ESCAPE|KEYC_CTRL; break; case '7': - key = KEYC_ADDESC(key); - key = KEYC_ADDCTL(key); + key |= KEYC_ESCAPE|KEYC_CTRL; break; case '6': - key = KEYC_ADDSFT(key); - key = KEYC_ADDCTL(key); + key |= KEYC_SHIFT|KEYC_CTRL; break; case '5': - key = KEYC_ADDCTL(key); + key |= KEYC_CTRL; break; case '4': - key = KEYC_ADDSFT(key); - key = KEYC_ADDESC(key); + key |= KEYC_SHIFT|KEYC_ESCAPE; break; case '3': - key = KEYC_ADDESC(key); + key |= KEYC_ESCAPE; break; case '2': - key = KEYC_ADDSFT(key); + key |= KEYC_SHIFT; break; } From b9a179089b7edec7930115ac7f1b5ae8e96f8792 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 21 Jul 2009 18:38:52 +0000 Subject: [PATCH 0152/1180] __progname is not const, pointed out by deraadt. --- tmux.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tmux.h b/tmux.h index 34a0fd9b..ca946e7b 100644 --- a/tmux.h +++ b/tmux.h @@ -38,7 +38,7 @@ #include "array.h" -extern const char *__progname; +extern char *__progname; /* Default configuration files. */ #define DEFAULT_CFG ".tmux.conf" From 044ebf195237c2c5ea13df5f1f93d61eaacf9d7b Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 21 Jul 2009 18:40:30 +0000 Subject: [PATCH 0153/1180] Remove a couple of unused functions and fix a type ("FALLTHOUGH"), found by lint. --- grid.c | 14 -------------- log.c | 13 ------------- status.c | 2 +- tmux.h | 2 -- 4 files changed, 1 insertion(+), 30 deletions(-) diff --git a/grid.c b/grid.c index 0fbdbd0a..8842371a 100644 --- a/grid.c +++ b/grid.c @@ -199,20 +199,6 @@ grid_scroll_line(struct grid *gd) gd->hsize++; } -/* Reduce line to fit to cell. */ -void -grid_reduce_line(struct grid *gd, u_int py, u_int sx) -{ - if (sx < gd->size[py]) { - gd->data[py] = xrealloc(gd->data[py], sx, sizeof **gd->data); - gd->size[py] = sx; - } - if (sx < gd->usize[py]) { - gd->udata[py] = xrealloc(gd->udata[py], sx, sizeof **gd->udata); - gd->usize[py] = sx; - } -} - /* Expand line to fit to cell. */ void grid_expand_line(struct grid *gd, u_int py, u_int sx) diff --git a/log.c b/log.c index d0efaee1..3aeec59f 100644 --- a/log.c +++ b/log.c @@ -171,19 +171,6 @@ log_debug2(const char *msg, ...) } } -/* Log a debug message at level 3. */ -void printflike1 -log_debug3(const char *msg, ...) -{ - va_list ap; - - if (log_level > 2) { - va_start(ap, msg); - log_vwrite(LOG_DEBUG, msg, ap); - va_end(ap); - } -} - /* Log a critical error, with error string if necessary, and die. */ __dead void log_vfatal(const char *msg, va_list ap) diff --git a/status.c b/status.c index b4cbc6b1..46d05fd5 100644 --- a/status.c +++ b/status.c @@ -350,7 +350,7 @@ status_replace(struct session *s, const char *fmt, time_t t) wl->window->active)); ptr = tmp; } - /* FALLTHOUGH */ + /* FALLTHROUGH */ case 'S': if (ptr == NULL) ptr = s->name; diff --git a/tmux.h b/tmux.h index ca946e7b..8024eb45 100644 --- a/tmux.h +++ b/tmux.h @@ -1349,7 +1349,6 @@ extern const struct grid_cell grid_default_cell; struct grid *grid_create(u_int, u_int, u_int); void grid_destroy(struct grid *); int grid_compare(struct grid *, struct grid *); -void grid_reduce_line(struct grid *, u_int, u_int); void grid_expand_line(struct grid *, u_int, u_int); void grid_expand_line_utf8(struct grid *, u_int, u_int); void grid_scroll_line(struct grid *); @@ -1603,7 +1602,6 @@ void printflike1 log_warnx(const char *, ...); void printflike1 log_info(const char *, ...); void printflike1 log_debug(const char *, ...); void printflike1 log_debug2(const char *, ...); -void printflike1 log_debug3(const char *, ...); __dead void log_fatal(const char *, ...); __dead void log_fatalx(const char *, ...); From 6945e86fd7540c610f7e58e4a964fed384048823 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 21 Jul 2009 18:52:03 +0000 Subject: [PATCH 0154/1180] Nix a few unused attributes on arguments which are no longer unused. --- client-msg.c | 6 +++--- cmd-confirm-before.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/client-msg.c b/client-msg.c index 2e2a6b49..7d7166ca 100644 --- a/client-msg.c +++ b/client-msg.c @@ -85,7 +85,7 @@ client_msg_fn_error(struct hdr *hdr, struct client_ctx *cctx, char **error) int client_msg_fn_detach( - struct hdr *hdr, unused struct client_ctx *cctx, unused char **error) + struct hdr *hdr, struct client_ctx *cctx, unused char **error) { if (hdr->size != 0) fatalx("bad MSG_DETACH size"); @@ -98,7 +98,7 @@ client_msg_fn_detach( int client_msg_fn_shutdown( - struct hdr *hdr, unused struct client_ctx *cctx, unused char **error) + struct hdr *hdr, struct client_ctx *cctx, unused char **error) { if (hdr->size != 0) fatalx("bad MSG_SHUTDOWN size"); @@ -111,7 +111,7 @@ client_msg_fn_shutdown( int client_msg_fn_exit( - struct hdr *hdr, unused struct client_ctx *cctx, unused char **error) + struct hdr *hdr, struct client_ctx *cctx, unused char **error) { if (hdr->size != 0) fatalx("bad MSG_EXIT size"); diff --git a/cmd-confirm-before.c b/cmd-confirm-before.c index c0fbe130..f1f5bfe1 100644 --- a/cmd-confirm-before.c +++ b/cmd-confirm-before.c @@ -68,7 +68,7 @@ cmd_confirm_before_init(struct cmd *self, int key) } int -cmd_confirm_before_exec(unused struct cmd *self, struct cmd_ctx *ctx) +cmd_confirm_before_exec(struct cmd *self, struct cmd_ctx *ctx) { struct cmd_target_data *data = self->data; struct cmd_confirm_before_data *cdata; From 76a9d9856272dc8210e1f2a2a832ef4455e2ca1e Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 21 Jul 2009 19:54:22 +0000 Subject: [PATCH 0155/1180] Make some functions which return unused values void (mostly found by lint) and tweak a redundant expression in window_pane_set_mode. --- input.c | 6 ++---- options.c | 5 ++--- server.c | 16 ++++++++-------- tmux.h | 7 +++---- window.c | 12 ++++-------- 5 files changed, 19 insertions(+), 27 deletions(-) diff --git a/input.c b/input.c index b75494c8..e3bba5d3 100644 --- a/input.c +++ b/input.c @@ -35,7 +35,7 @@ #define INPUT_SPECIAL(ch) (ch == 0xff) int input_get_argument(struct input_ctx *, u_int, uint16_t *, uint16_t); -int input_new_argument(struct input_ctx *); +void input_new_argument(struct input_ctx *); int input_add_argument(struct input_ctx *, u_char); void input_start_string(struct input_ctx *, int); @@ -123,7 +123,7 @@ input_sequence_cmp(const void *a, const void *b) return (ai - bi); } -int +void input_new_argument(struct input_ctx *ictx) { struct input_arg *arg; @@ -132,8 +132,6 @@ input_new_argument(struct input_ctx *ictx) arg = &ARRAY_LAST(&ictx->args); arg->used = 0; - - return (0); } int diff --git a/options.c b/options.c index c742e092..45d9f714 100644 --- a/options.c +++ b/options.c @@ -83,20 +83,19 @@ options_find(struct options *oo, const char *name) return (o); } -int +void options_remove(struct options *oo, const char *name) { struct options_entry *o; if ((o = options_find1(oo, name)) == NULL) - return (-1); + return; SPLAY_REMOVE(options_tree, &oo->tree, o); xfree(o->name); if (o->type == OPTIONS_STRING) xfree(o->value.string); xfree(o); - return (0); } void printflike3 diff --git a/server.c b/server.c index 7207ae94..8012e900 100644 --- a/server.c +++ b/server.c @@ -44,6 +44,7 @@ /* Client list. */ struct clients clients; +void server_create_client(int); int server_create_socket(void); int server_main(int); void server_shutdown(void); @@ -52,7 +53,7 @@ void server_fill_windows(struct pollfd **); void server_handle_windows(struct pollfd **); void server_fill_clients(struct pollfd **); void server_handle_clients(struct pollfd **); -struct client *server_accept_client(int); +void server_accept_client(int); void server_handle_client(struct client *); void server_handle_window(struct window *, struct window_pane *); int server_check_window_bell(struct session *, struct window *); @@ -69,7 +70,7 @@ void server_second_timers(void); int server_update_socket(void); /* Create a new client. */ -struct client * +void server_create_client(int fd) { struct client *c; @@ -107,11 +108,10 @@ server_create_client(int fd) for (i = 0; i < ARRAY_LENGTH(&clients); i++) { if (ARRAY_ITEM(&clients, i) == NULL) { ARRAY_SET(&clients, i, c); - return (c); + return; } } ARRAY_ADD(&clients, c); - return (c); } /* Find client index. */ @@ -735,7 +735,7 @@ server_handle_clients(struct pollfd **pfd) } /* accept(2) and create new client. */ -struct client * +void server_accept_client(int srv_fd) { struct sockaddr_storage sa; @@ -745,14 +745,14 @@ server_accept_client(int srv_fd) fd = accept(srv_fd, (struct sockaddr *) &sa, &slen); if (fd == -1) { if (errno == EAGAIN || errno == EINTR || errno == ECONNABORTED) - return (NULL); + return; fatal("accept failed"); } if (sigterm) { close(fd); - return (NULL); + return; } - return (server_create_client(fd)); + server_create_client(fd); } /* Input data from client. */ diff --git a/tmux.h b/tmux.h index 8024eb45..38ef0a5f 100644 --- a/tmux.h +++ b/tmux.h @@ -1014,7 +1014,7 @@ void options_init(struct options *, struct options *); void options_free(struct options *); struct options_entry *options_find1(struct options *, const char *); struct options_entry *options_find(struct options *, const char *); -int options_remove(struct options *, const char *); +void options_remove(struct options *, const char *); void printflike3 options_set_string( struct options *, const char *, const char *, ...); char *options_get_string(struct options *, const char *); @@ -1287,7 +1287,6 @@ const char *key_string_lookup_key(int); /* server.c */ extern struct clients clients; -struct client *server_create_client(int); int server_client_index(struct client *); int server_start(char *); @@ -1467,9 +1466,9 @@ struct window *window_create1(u_int, u_int); struct window *window_create(const char *, const char *, const char *, const char **, u_int, u_int, u_int, char **); void window_destroy(struct window *); -int window_resize(struct window *, u_int, u_int); void window_set_active_pane(struct window *, struct window_pane *); struct window_pane *window_add_pane(struct window *, u_int, char **); +void window_resize(struct window *, u_int, u_int); void window_remove_pane(struct window *, struct window_pane *); struct window_pane *window_pane_at_index(struct window *, u_int); u_int window_pane_index(struct window *, struct window_pane *); @@ -1479,7 +1478,7 @@ struct window_pane *window_pane_create(struct window *, u_int, u_int, u_int); void window_pane_destroy(struct window_pane *); int window_pane_spawn(struct window_pane *, const char *, const char *, const char **, char **); -int window_pane_resize(struct window_pane *, u_int, u_int); +void window_pane_resize(struct window_pane *, u_int, u_int); int window_pane_set_mode( struct window_pane *, const struct window_mode *); void window_pane_reset_mode(struct window_pane *); diff --git a/window.c b/window.c index d7d16ed3..5af60da3 100644 --- a/window.c +++ b/window.c @@ -301,13 +301,11 @@ window_destroy(struct window *w) xfree(w); } -int +void window_resize(struct window *w, u_int sx, u_int sy) { w->sx = sx; w->sy = sy; - - return (0); } void @@ -532,13 +530,13 @@ window_pane_spawn(struct window_pane *wp, return (0); } -int +void window_pane_resize(struct window_pane *wp, u_int sx, u_int sy) { struct winsize ws; if (sx == wp->sx && sy == wp->sy) - return (-1); + return; wp->sx = sx; wp->sy = sy; @@ -552,7 +550,6 @@ window_pane_resize(struct window_pane *wp, u_int sx, u_int sy) if (wp->fd != -1 && ioctl(wp->fd, TIOCSWINSZ, &ws) == -1) fatal("ioctl failed"); - return (0); } int @@ -560,9 +557,8 @@ window_pane_set_mode(struct window_pane *wp, const struct window_mode *mode) { struct screen *s; - if (wp->mode != NULL || wp->mode == mode) + if (wp->mode != NULL) return (1); - wp->mode = mode; if ((s = wp->mode->init(wp)) != NULL) From 3eb6080de39f995cc2fb90c63dc314e98ac169df Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 21 Jul 2009 21:20:07 +0000 Subject: [PATCH 0156/1180] Remove leftover debug logging of password. --- cmd-set-password.c | 1 - 1 file changed, 1 deletion(-) diff --git a/cmd-set-password.c b/cmd-set-password.c index 1ec956c9..37702cde 100644 --- a/cmd-set-password.c +++ b/cmd-set-password.c @@ -118,7 +118,6 @@ cmd_set_password_exec(struct cmd *self, struct cmd_ctx *ctx) server_password = NULL; else server_password = xstrdup(data->password); - log_debug("pw now %s", server_password); return (0); } From e43b6a2dd2a52b49cd92481fc09074b595e83386 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 21 Jul 2009 22:41:00 +0000 Subject: [PATCH 0157/1180] Adjust field width to fit longest key when listing. --- cmd-list-keys.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/cmd-list-keys.c b/cmd-list-keys.c index 17612449..af3a0208 100644 --- a/cmd-list-keys.c +++ b/cmd-list-keys.c @@ -18,6 +18,8 @@ #include +#include + #include "tmux.h" /* @@ -45,6 +47,18 @@ cmd_list_keys_exec(unused struct cmd *self, struct cmd_ctx *ctx) struct key_binding *bd; const char *key; char tmp[BUFSIZ]; + int width, keywidth; + + width = 0; + SPLAY_FOREACH(bd, key_bindings, &key_bindings) { + if ((key = key_string_lookup_key(bd->key)) == NULL) + continue; + + keywidth = strlen(key) + 1; + if (keywidth > width) + width = keywidth; + } + SPLAY_FOREACH(bd, key_bindings, &key_bindings) { if ((key = key_string_lookup_key(bd->key)) == NULL) @@ -52,7 +66,8 @@ cmd_list_keys_exec(unused struct cmd *self, struct cmd_ctx *ctx) *tmp = '\0'; cmd_list_print(bd->cmdlist, tmp, sizeof tmp); - ctx->print(ctx, "%11s: %s", key, tmp); + + ctx->print(ctx, "%*s: %s", width, key, tmp); } return (0); From 5bd72ec62990d96c3af87858e263bff7a1c0f220 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 22 Jul 2009 15:55:32 +0000 Subject: [PATCH 0158/1180] tty_cmd_raw is only used once, for raw UTF-8 output, so rename it to tty_cmd_utf8character and eliminate the size argument. --- screen-write.c | 7 +------ tmux.h | 2 +- tty.c | 17 ++++++++++------- 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/screen-write.c b/screen-write.c index 59b8b027..ba8a226e 100644 --- a/screen-write.c +++ b/screen-write.c @@ -700,7 +700,6 @@ screen_write_cell( struct grid_utf8 gu, *tmp_gu; u_int width, xx, i; struct grid_cell tmp_gc, *tmp_gc2; - size_t size; int insert = 0; /* Ignore padding. */ @@ -737,11 +736,7 @@ screen_write_cell( memcpy(tmp_gu->data + i, udata, UTF8_SIZE - i); /* Assume the previous character has just been input. */ - for (size = 0; size < UTF8_SIZE; size++) { - if (udata[size] == 0xff) - break; - } - tty_write_cmd(ctx->wp, TTY_RAW, udata, size); + tty_write_cmd(ctx->wp, TTY_UTF8CHARACTER, udata); return; } diff --git a/tmux.h b/tmux.h index 38ef0a5f..3e532f75 100644 --- a/tmux.h +++ b/tmux.h @@ -288,7 +288,7 @@ enum tty_cmd { TTY_INSERTCHARACTER, TTY_INSERTLINE, TTY_LINEFEED, - TTY_RAW, + TTY_UTF8CHARACTER, TTY_REVERSEINDEX, }; diff --git a/tty.c b/tty.c index 3a536bae..0643a356 100644 --- a/tty.c +++ b/tty.c @@ -51,7 +51,7 @@ void tty_cmd_deleteline(struct tty *, struct window_pane *, va_list); void tty_cmd_insertcharacter(struct tty *, struct window_pane *, va_list); void tty_cmd_insertline(struct tty *, struct window_pane *, va_list); void tty_cmd_linefeed(struct tty *, struct window_pane *, va_list); -void tty_cmd_raw(struct tty *, struct window_pane *, va_list); +void tty_cmd_utf8character(struct tty *, struct window_pane *, va_list); void tty_cmd_reverseindex(struct tty *, struct window_pane *, va_list); void (*tty_cmds[])(struct tty *, struct window_pane *, va_list) = { @@ -68,7 +68,7 @@ void (*tty_cmds[])(struct tty *, struct window_pane *, va_list) = { tty_cmd_insertcharacter, tty_cmd_insertline, tty_cmd_linefeed, - tty_cmd_raw, + tty_cmd_utf8character, tty_cmd_reverseindex, }; @@ -869,16 +869,19 @@ tty_cmd_cell(struct tty *tty, struct window_pane *wp, va_list ap) } void -tty_cmd_raw(struct tty *tty, unused struct window_pane *wp, va_list ap) +tty_cmd_utf8character( + struct tty *tty, unused struct window_pane *wp, va_list ap) { u_char *buf; - size_t i, len; + size_t i; buf = va_arg(ap, u_char *); - len = va_arg(ap, size_t); - - for (i = 0; i < len; i++) + + for (i = 0; i < UTF8_SIZE; i++) { + if (buf[i] == 0xff) + break; tty_putc(tty, buf[i]); + } } void From 6a309c53a8ae3142d132fe1c12e55bed9b62e4d5 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 22 Jul 2009 16:45:31 +0000 Subject: [PATCH 0159/1180] There are relatively few arguments to tty_cmd_* functions now, so tidy them up by using a struct rather than hiding everything with varargs. --- screen-write.c | 46 ++++++++------ tmux.h | 18 +++++- tty-write.c | 48 +++++++++----- tty.c | 165 +++++++++++++++++++++++-------------------------- 4 files changed, 151 insertions(+), 126 deletions(-) diff --git a/screen-write.c b/screen-write.c index ba8a226e..b8ec57ea 100644 --- a/screen-write.c +++ b/screen-write.c @@ -327,7 +327,7 @@ screen_write_alignmenttest(struct screen_write_ctx *ctx) s->rupper = 0; s->rlower = screen_size_y(s) - 1; - tty_write_cmd(ctx->wp, TTY_ALIGNMENTTEST); + tty_write0(ctx->wp, TTY_ALIGNMENTTEST); } /* Insert nx characters. */ @@ -349,7 +349,7 @@ screen_write_insertcharacter(struct screen_write_ctx *ctx, u_int nx) if (s->cx <= screen_size_x(s) - 1) grid_view_insert_cells(s->grid, s->cx, s->cy, nx); - tty_write_cmd(ctx->wp, TTY_INSERTCHARACTER, nx); + tty_writenum(ctx->wp, TTY_INSERTCHARACTER, nx); } /* Delete nx characters. */ @@ -371,7 +371,7 @@ screen_write_deletecharacter(struct screen_write_ctx *ctx, u_int nx) if (s->cx <= screen_size_x(s) - 1) grid_view_delete_cells(s->grid, s->cx, s->cy, nx); - tty_write_cmd(ctx->wp, TTY_DELETECHARACTER, nx); + tty_writenum(ctx->wp, TTY_DELETECHARACTER, nx); } /* Insert ny lines. */ @@ -393,7 +393,7 @@ screen_write_insertline(struct screen_write_ctx *ctx, u_int ny) grid_view_insert_lines(s->grid, s->cy, ny); - tty_write_cmd(ctx->wp, TTY_INSERTLINE, ny); + tty_writenum(ctx->wp, TTY_INSERTLINE, ny); return; } @@ -409,7 +409,7 @@ screen_write_insertline(struct screen_write_ctx *ctx, u_int ny) else grid_view_insert_lines_region(s->grid, s->rlower, s->cy, ny); - tty_write_cmd(ctx->wp, TTY_INSERTLINE, ny); + tty_writenum(ctx->wp, TTY_INSERTLINE, ny); } /* Delete ny lines. */ @@ -431,7 +431,7 @@ screen_write_deleteline(struct screen_write_ctx *ctx, u_int ny) grid_view_delete_lines(s->grid, s->cy, ny); - tty_write_cmd(ctx->wp, TTY_DELETELINE, ny); + tty_writenum(ctx->wp, TTY_DELETELINE, ny); return; } @@ -447,7 +447,7 @@ screen_write_deleteline(struct screen_write_ctx *ctx, u_int ny) else grid_view_delete_lines_region(s->grid, s->rlower, s->cy, ny); - tty_write_cmd(ctx->wp, TTY_DELETELINE, ny); + tty_writenum(ctx->wp, TTY_DELETELINE, ny); } /* Clear line at cursor. */ @@ -460,7 +460,7 @@ screen_write_clearline(struct screen_write_ctx *ctx) grid_view_clear(s->grid, 0, s->cy, screen_size_x(s), 1); - tty_write_cmd(ctx->wp, TTY_CLEARLINE); + tty_writenum(ctx->wp, TTY_CLEARLINE, 0); } /* Clear to end of line from cursor. */ @@ -477,7 +477,7 @@ screen_write_clearendofline(struct screen_write_ctx *ctx) if (s->cx <= sx - 1) grid_view_clear(s->grid, s->cx, s->cy, sx - s->cx, 1); - tty_write_cmd(ctx->wp, TTY_CLEARENDOFLINE); + tty_writenum(ctx->wp, TTY_CLEARENDOFLINE, 0); } /* Clear to start of line from cursor. */ @@ -496,7 +496,7 @@ screen_write_clearstartofline(struct screen_write_ctx *ctx) else grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1); - tty_write_cmd(ctx->wp, TTY_CLEARSTARTOFLINE); + tty_writenum(ctx->wp, TTY_CLEARSTARTOFLINE, 0); } /* Move cursor to px,py. */ @@ -539,7 +539,7 @@ screen_write_reverseindex(struct screen_write_ctx *ctx) else if (s->cy > 0) s->cy--; - tty_write_cmd(ctx->wp, TTY_REVERSEINDEX); + tty_writenum(ctx->wp, TTY_REVERSEINDEX, 0); } /* Set scroll region. */ @@ -601,7 +601,7 @@ screen_write_linefeed(struct screen_write_ctx *ctx) else if (s->cy < screen_size_y(s) - 1) s->cy++; - tty_write_cmd(ctx->wp, TTY_LINEFEED); + tty_writenum(ctx->wp, TTY_LINEFEED, 0); } /* Carriage return (cursor to start of line). */ @@ -653,7 +653,7 @@ screen_write_clearendofscreen(struct screen_write_ctx *ctx) grid_view_clear(s->grid, s->cx, s->cy, sx - s->cx, 1); grid_view_clear(s->grid, 0, s->cy + 1, sx, sy - (s->cy + 1)); - tty_write_cmd(ctx->wp, TTY_CLEARENDOFSCREEN); + tty_writenum(ctx->wp, TTY_CLEARENDOFSCREEN, 0); } /* Clear to start of screen. */ @@ -674,7 +674,7 @@ screen_write_clearstartofscreen(struct screen_write_ctx *ctx) else grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1); - tty_write_cmd(ctx->wp, TTY_CLEARSTARTOFSCREEN); + tty_writenum(ctx->wp, TTY_CLEARSTARTOFSCREEN, 0); } /* Clear entire screen. */ @@ -687,7 +687,7 @@ screen_write_clearscreen(struct screen_write_ctx *ctx) grid_view_clear(s->grid, 0, 0, screen_size_x(s), screen_size_y(s)); - tty_write_cmd(ctx->wp, TTY_CLEARSCREEN); + tty_writenum(ctx->wp, TTY_CLEARSCREEN, 0); } /* Write cell data. */ @@ -697,6 +697,7 @@ screen_write_cell( { struct screen *s = ctx->s; struct grid *gd = s->grid; + struct tty_ctx ttyctx; struct grid_utf8 gu, *tmp_gu; u_int width, xx, i; struct grid_cell tmp_gc, *tmp_gc2; @@ -736,7 +737,7 @@ screen_write_cell( memcpy(tmp_gu->data + i, udata, UTF8_SIZE - i); /* Assume the previous character has just been input. */ - tty_write_cmd(ctx->wp, TTY_UTF8CHARACTER, udata); + tty_writeptr(ctx->wp, TTY_UTF8CHARACTER, udata); return; } @@ -789,12 +790,17 @@ screen_write_cell( /* Draw to the screen if necessary. */ if (insert) - tty_write_cmd(ctx->wp, TTY_INSERTCHARACTER, width); + tty_writenum(ctx->wp, TTY_INSERTCHARACTER, width); + ttyctx.wp = ctx->wp; + ttyctx.utf8 = &gu; if (screen_check_selection(s, s->cx - width, s->cy)) { s->sel.cell.data = gc->data; - tty_write_cmd(ctx->wp, TTY_CELL, &s->sel.cell, &gu); - } else - tty_write_cmd(ctx->wp, TTY_CELL, gc, &gu); + ttyctx.cell = &s->sel.cell; + tty_write_cmd(TTY_CELL, &ttyctx); + } else { + ttyctx.cell = gc; + tty_write_cmd(TTY_CELL, &ttyctx); + } } /* diff --git a/tmux.h b/tmux.h index 3e532f75..2062dfff 100644 --- a/tmux.h +++ b/tmux.h @@ -292,6 +292,16 @@ enum tty_cmd { TTY_REVERSEINDEX, }; +struct tty_ctx { + struct window_pane *wp; + + const struct grid_cell *cell; + const struct grid_utf8 *utf8; + + u_int num; + void *ptr; +}; + /* Message codes. */ enum hdrtype { MSG_COMMAND, @@ -1048,8 +1058,7 @@ void tty_redraw_region(struct tty *, struct window_pane *); int tty_open(struct tty *, char **); void tty_close(struct tty *, int); void tty_free(struct tty *, int); -void tty_vwrite( - struct tty *, struct window_pane *, enum tty_cmd, va_list); +void tty_write(struct tty *, enum tty_cmd, struct tty_ctx *); /* tty-term.c */ extern struct tty_terms tty_terms; @@ -1072,7 +1081,10 @@ void tty_keys_free(struct tty *); int tty_keys_next(struct tty *, int *, u_char *); /* tty-write.c */ -void tty_write_cmd(struct window_pane *, enum tty_cmd, ...); +void tty_write0(struct window_pane *, enum tty_cmd); +void tty_writenum(struct window_pane *, enum tty_cmd, u_int); +void tty_writeptr(struct window_pane *, enum tty_cmd, void *); +void tty_write_cmd(enum tty_cmd, struct tty_ctx *); /* options-cmd.c */ void set_option_string(struct cmd_ctx *, diff --git a/tty-write.c b/tty-write.c index 87e6c383..b8e39837 100644 --- a/tty-write.c +++ b/tty-write.c @@ -18,26 +18,48 @@ #include +#include + #include "tmux.h" -void tty_vwrite_cmd(struct window_pane *, enum tty_cmd, va_list); - void -tty_write_cmd(struct window_pane *wp, enum tty_cmd cmd, ...) +tty_write0(struct window_pane *wp, enum tty_cmd cmd) { - va_list ap; + struct tty_ctx ctx; - va_start(ap, cmd); - tty_vwrite_cmd(wp, cmd, ap); - va_end(ap); + memset(&ctx, 0, sizeof ctx); + ctx.wp = wp; + tty_write_cmd(cmd, &ctx); } void -tty_vwrite_cmd(struct window_pane *wp, enum tty_cmd cmd, va_list ap) +tty_writenum(struct window_pane *wp, enum tty_cmd cmd, u_int num) { - struct client *c; - va_list aq; - u_int i; + struct tty_ctx ctx; + + memset(&ctx, 0, sizeof ctx); + ctx.wp = wp; + ctx.num = num; + tty_write_cmd(cmd, &ctx); +} + +void +tty_writeptr(struct window_pane *wp, enum tty_cmd cmd, void *ptr) +{ + struct tty_ctx ctx; + + memset(&ctx, 0, sizeof ctx); + ctx.wp = wp; + ctx.ptr = ptr; + tty_write_cmd(cmd, &ctx); +} + +void +tty_write_cmd(enum tty_cmd cmd, struct tty_ctx *ctx) +{ + struct window_pane *wp = ctx->wp; + struct client *c; + u_int i; if (wp == NULL) return; @@ -57,9 +79,7 @@ tty_vwrite_cmd(struct window_pane *wp, enum tty_cmd cmd, va_list ap) if (c->session->curw->window == wp->window) { tty_update_mode(&c->tty, c->tty.mode & ~MODE_CURSOR); - va_copy(aq, ap); - tty_vwrite(&c->tty, wp, cmd, aq); - va_end(aq); + tty_write(&c->tty, cmd, ctx); } } } diff --git a/tty.c b/tty.c index 0643a356..dfa36a5e 100644 --- a/tty.c +++ b/tty.c @@ -38,23 +38,23 @@ void tty_attributes(struct tty *, const struct grid_cell *); void tty_attributes_fg(struct tty *, const struct grid_cell *); void tty_attributes_bg(struct tty *, const struct grid_cell *); -void tty_cmd_alignmenttest(struct tty *, struct window_pane *, va_list); -void tty_cmd_cell(struct tty *, struct window_pane *, va_list); -void tty_cmd_clearendofline(struct tty *, struct window_pane *, va_list); -void tty_cmd_clearendofscreen(struct tty *, struct window_pane *, va_list); -void tty_cmd_clearline(struct tty *, struct window_pane *, va_list); -void tty_cmd_clearscreen(struct tty *, struct window_pane *, va_list); -void tty_cmd_clearstartofline(struct tty *, struct window_pane *, va_list); -void tty_cmd_clearstartofscreen(struct tty *, struct window_pane *, va_list); -void tty_cmd_deletecharacter(struct tty *, struct window_pane *, va_list); -void tty_cmd_deleteline(struct tty *, struct window_pane *, va_list); -void tty_cmd_insertcharacter(struct tty *, struct window_pane *, va_list); -void tty_cmd_insertline(struct tty *, struct window_pane *, va_list); -void tty_cmd_linefeed(struct tty *, struct window_pane *, va_list); -void tty_cmd_utf8character(struct tty *, struct window_pane *, va_list); -void tty_cmd_reverseindex(struct tty *, struct window_pane *, va_list); +void tty_cmd_alignmenttest(struct tty *, struct tty_ctx *); +void tty_cmd_cell(struct tty *, struct tty_ctx *); +void tty_cmd_clearendofline(struct tty *, struct tty_ctx *); +void tty_cmd_clearendofscreen(struct tty *, struct tty_ctx *); +void tty_cmd_clearline(struct tty *, struct tty_ctx *); +void tty_cmd_clearscreen(struct tty *, struct tty_ctx *); +void tty_cmd_clearstartofline(struct tty *, struct tty_ctx *); +void tty_cmd_clearstartofscreen(struct tty *, struct tty_ctx *); +void tty_cmd_deletecharacter(struct tty *, struct tty_ctx *); +void tty_cmd_deleteline(struct tty *, struct tty_ctx *); +void tty_cmd_insertcharacter(struct tty *, struct tty_ctx *); +void tty_cmd_insertline(struct tty *, struct tty_ctx *); +void tty_cmd_linefeed(struct tty *, struct tty_ctx *); +void tty_cmd_utf8character(struct tty *, struct tty_ctx *); +void tty_cmd_reverseindex(struct tty *, struct tty_ctx *); -void (*tty_cmds[])(struct tty *, struct window_pane *, va_list) = { +void (*tty_cmds[])(struct tty *, struct tty_ctx *) = { tty_cmd_alignmenttest, tty_cmd_cell, tty_cmd_clearendofline, @@ -545,66 +545,61 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int py, u_int ox, u_int oy) } void -tty_vwrite( - struct tty *tty, struct window_pane *wp, enum tty_cmd cmd, va_list ap) +tty_write(struct tty *tty, enum tty_cmd cmd, struct tty_ctx *ctx) { if (tty->flags & TTY_FREEZE || tty->term == NULL) return; if (tty_cmds[cmd] != NULL) - tty_cmds[cmd](tty, wp, ap); + tty_cmds[cmd](tty, ctx); } void -tty_cmd_insertcharacter(struct tty *tty, struct window_pane *wp, va_list ap) +tty_cmd_insertcharacter(struct tty *tty, struct tty_ctx *ctx) { - struct screen *s = wp->screen; - u_int ua; + struct window_pane *wp = ctx->wp; + struct screen *s = wp->screen; if (wp->xoff != 0 || screen_size_x(s) < tty->sx) { tty_draw_line(tty, wp->screen, s->old_cy, wp->xoff, wp->yoff); return; } - ua = va_arg(ap, u_int); - tty_reset(tty); tty_cursor(tty, s->old_cx, s->old_cy, wp->xoff, wp->yoff); if (tty_term_has(tty->term, TTYC_ICH) || tty_term_has(tty->term, TTYC_ICH1)) - tty_emulate_repeat(tty, TTYC_ICH, TTYC_ICH1, ua); + tty_emulate_repeat(tty, TTYC_ICH, TTYC_ICH1, ctx->num); else { tty_putcode(tty, TTYC_SMIR); - while (ua-- > 0) + while (ctx->num-- > 0) tty_putc(tty, ' '); tty_putcode(tty, TTYC_RMIR); } } void -tty_cmd_deletecharacter(struct tty *tty, struct window_pane *wp, va_list ap) +tty_cmd_deletecharacter(struct tty *tty, struct tty_ctx *ctx) { - struct screen *s = wp->screen; - u_int ua; + struct window_pane *wp = ctx->wp; + struct screen *s = wp->screen; if (wp->xoff != 0 || screen_size_x(s) < tty->sx) { tty_draw_line(tty, wp->screen, s->old_cy, wp->xoff, wp->yoff); return; } - ua = va_arg(ap, u_int); - tty_reset(tty); tty_cursor(tty, s->old_cx, s->old_cy, wp->xoff, wp->yoff); - tty_emulate_repeat(tty, TTYC_DCH, TTYC_DCH1, ua); + tty_emulate_repeat(tty, TTYC_DCH, TTYC_DCH1, ctx->num); } void -tty_cmd_insertline(struct tty *tty, struct window_pane *wp, va_list ap) +tty_cmd_insertline(struct tty *tty, struct tty_ctx *ctx) { - struct screen *s = wp->screen; - u_int ua; + struct window_pane *wp = ctx->wp; + struct screen *s = wp->screen; if (wp->xoff != 0 || screen_size_x(s) < tty->sx || !tty_term_has(tty->term, TTYC_CSR)) { @@ -612,21 +607,19 @@ tty_cmd_insertline(struct tty *tty, struct window_pane *wp, va_list ap) return; } - ua = va_arg(ap, u_int); - tty_reset(tty); tty_region(tty, s->old_rupper, s->old_rlower, wp->yoff); tty_cursor(tty, s->old_cx, s->old_cy, wp->xoff, wp->yoff); - tty_emulate_repeat(tty, TTYC_IL, TTYC_IL1, ua); + tty_emulate_repeat(tty, TTYC_IL, TTYC_IL1, ctx->num); } void -tty_cmd_deleteline(struct tty *tty, struct window_pane *wp, va_list ap) +tty_cmd_deleteline(struct tty *tty, struct tty_ctx *ctx) { - struct screen *s = wp->screen; - u_int ua; + struct window_pane *wp = ctx->wp; + struct screen *s = wp->screen; if (wp->xoff != 0 || screen_size_x(s) < tty->sx || !tty_term_has(tty->term, TTYC_CSR)) { @@ -634,21 +627,20 @@ tty_cmd_deleteline(struct tty *tty, struct window_pane *wp, va_list ap) return; } - ua = va_arg(ap, u_int); - tty_reset(tty); tty_region(tty, s->old_rupper, s->old_rlower, wp->yoff); tty_cursor(tty, s->old_cx, s->old_cy, wp->xoff, wp->yoff); - tty_emulate_repeat(tty, TTYC_DL, TTYC_DL1, ua); + tty_emulate_repeat(tty, TTYC_DL, TTYC_DL1, ctx->num); } void -tty_cmd_clearline(struct tty *tty, struct window_pane *wp, unused va_list ap) +tty_cmd_clearline(struct tty *tty, struct tty_ctx *ctx) { - struct screen *s = wp->screen; - u_int i; + struct window_pane *wp = ctx->wp; + struct screen *s = wp->screen; + u_int i; tty_reset(tty); @@ -663,11 +655,11 @@ tty_cmd_clearline(struct tty *tty, struct window_pane *wp, unused va_list ap) } void -tty_cmd_clearendofline( - struct tty *tty, struct window_pane *wp, unused va_list ap) +tty_cmd_clearendofline(struct tty *tty, struct tty_ctx *ctx) { - struct screen *s = wp->screen; - u_int i; + struct window_pane *wp = ctx->wp; + struct screen *s = wp->screen; + u_int i; tty_reset(tty); @@ -682,11 +674,11 @@ tty_cmd_clearendofline( } void -tty_cmd_clearstartofline( - struct tty *tty, struct window_pane *wp, unused va_list ap) +tty_cmd_clearstartofline(struct tty *tty, struct tty_ctx *ctx) { - struct screen *s = wp->screen; - u_int i; + struct window_pane *wp = ctx->wp; + struct screen *s = wp->screen; + u_int i; tty_reset(tty); @@ -701,9 +693,10 @@ tty_cmd_clearstartofline( } void -tty_cmd_reverseindex(struct tty *tty, struct window_pane *wp, unused va_list ap) +tty_cmd_reverseindex(struct tty *tty, struct tty_ctx *ctx) { - struct screen *s = wp->screen; + struct window_pane *wp = ctx->wp; + struct screen *s = wp->screen; if (wp->xoff != 0 || screen_size_x(s) < tty->sx || !tty_term_has(tty->term, TTYC_CSR)) { @@ -722,9 +715,10 @@ tty_cmd_reverseindex(struct tty *tty, struct window_pane *wp, unused va_list ap) } void -tty_cmd_linefeed(struct tty *tty, struct window_pane *wp, unused va_list ap) +tty_cmd_linefeed(struct tty *tty, struct tty_ctx *ctx) { - struct screen *s = wp->screen; + struct window_pane *wp = ctx->wp; + struct screen *s = wp->screen; if (wp->xoff != 0 || screen_size_x(s) < tty->sx || !tty_term_has(tty->term, TTYC_CSR)) { @@ -743,11 +737,11 @@ tty_cmd_linefeed(struct tty *tty, struct window_pane *wp, unused va_list ap) } void -tty_cmd_clearendofscreen( - struct tty *tty, struct window_pane *wp, unused va_list ap) +tty_cmd_clearendofscreen(struct tty *tty, struct tty_ctx *ctx) { - struct screen *s = wp->screen; - u_int i, j; + struct window_pane *wp = ctx->wp; + struct screen *s = wp->screen; + u_int i, j; tty_reset(tty); @@ -778,11 +772,11 @@ tty_cmd_clearendofscreen( } void -tty_cmd_clearstartofscreen( - struct tty *tty, struct window_pane *wp, unused va_list ap) +tty_cmd_clearstartofscreen(struct tty *tty, struct tty_ctx *ctx) { - struct screen *s = wp->screen; - u_int i, j; + struct window_pane *wp = ctx->wp; + struct screen *s = wp->screen; + u_int i, j; tty_reset(tty); @@ -807,11 +801,11 @@ tty_cmd_clearstartofscreen( } void -tty_cmd_clearscreen( - struct tty *tty, struct window_pane *wp, unused va_list ap) +tty_cmd_clearscreen(struct tty *tty, struct tty_ctx *ctx) { - struct screen *s = wp->screen; - u_int i, j; + struct window_pane *wp = ctx->wp; + struct screen *s = wp->screen; + u_int i, j; tty_reset(tty); @@ -836,11 +830,11 @@ tty_cmd_clearscreen( } void -tty_cmd_alignmenttest( - struct tty *tty, struct window_pane *wp, unused va_list ap) +tty_cmd_alignmenttest(struct tty *tty, struct tty_ctx *ctx) { - struct screen *s = wp->screen; - u_int i, j; + struct window_pane *wp = ctx->wp; + struct screen *s = wp->screen; + u_int i, j; tty_reset(tty); @@ -854,33 +848,26 @@ tty_cmd_alignmenttest( } void -tty_cmd_cell(struct tty *tty, struct window_pane *wp, va_list ap) +tty_cmd_cell(struct tty *tty, struct tty_ctx *ctx) { + struct window_pane *wp = ctx->wp; struct screen *s = wp->screen; - struct grid_cell *gc; - struct grid_utf8 *gu; - - gc = va_arg(ap, struct grid_cell *); - gu = va_arg(ap, struct grid_utf8 *); tty_cursor(tty, s->old_cx, s->old_cy, wp->xoff, wp->yoff); - tty_cell(tty, gc, gu); + tty_cell(tty, ctx->cell, ctx->utf8); } void -tty_cmd_utf8character( - struct tty *tty, unused struct window_pane *wp, va_list ap) +tty_cmd_utf8character(struct tty *tty, struct tty_ctx *ctx) { - u_char *buf; + u_char *ptr = ctx->ptr; size_t i; - buf = va_arg(ap, u_char *); - for (i = 0; i < UTF8_SIZE; i++) { - if (buf[i] == 0xff) + if (ptr[i] == 0xff) break; - tty_putc(tty, buf[i]); + tty_putc(tty, ptr[i]); } } From 2ec2837daa428def7116848a17355f3423bf038e Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 22 Jul 2009 18:02:23 +0000 Subject: [PATCH 0160/1180] enum tty_cmd is only used as an index into the array of command function pointers, so remove it and use the function pointers directly to represent themselves. --- screen-write.c | 38 ++++++++-------- tmux.h | 120 +++++++++++++++++++++++-------------------------- tty-write.c | 19 ++++---- tty.c | 46 ++----------------- 4 files changed, 89 insertions(+), 134 deletions(-) diff --git a/screen-write.c b/screen-write.c index b8ec57ea..2f41ae55 100644 --- a/screen-write.c +++ b/screen-write.c @@ -327,7 +327,7 @@ screen_write_alignmenttest(struct screen_write_ctx *ctx) s->rupper = 0; s->rlower = screen_size_y(s) - 1; - tty_write0(ctx->wp, TTY_ALIGNMENTTEST); + tty_write0(ctx->wp, tty_cmd_alignmenttest); } /* Insert nx characters. */ @@ -349,7 +349,7 @@ screen_write_insertcharacter(struct screen_write_ctx *ctx, u_int nx) if (s->cx <= screen_size_x(s) - 1) grid_view_insert_cells(s->grid, s->cx, s->cy, nx); - tty_writenum(ctx->wp, TTY_INSERTCHARACTER, nx); + tty_writenum(ctx->wp, tty_cmd_insertcharacter, nx); } /* Delete nx characters. */ @@ -371,7 +371,7 @@ screen_write_deletecharacter(struct screen_write_ctx *ctx, u_int nx) if (s->cx <= screen_size_x(s) - 1) grid_view_delete_cells(s->grid, s->cx, s->cy, nx); - tty_writenum(ctx->wp, TTY_DELETECHARACTER, nx); + tty_writenum(ctx->wp, tty_cmd_deletecharacter, nx); } /* Insert ny lines. */ @@ -393,7 +393,7 @@ screen_write_insertline(struct screen_write_ctx *ctx, u_int ny) grid_view_insert_lines(s->grid, s->cy, ny); - tty_writenum(ctx->wp, TTY_INSERTLINE, ny); + tty_writenum(ctx->wp, tty_cmd_insertline, ny); return; } @@ -409,7 +409,7 @@ screen_write_insertline(struct screen_write_ctx *ctx, u_int ny) else grid_view_insert_lines_region(s->grid, s->rlower, s->cy, ny); - tty_writenum(ctx->wp, TTY_INSERTLINE, ny); + tty_writenum(ctx->wp, tty_cmd_insertline, ny); } /* Delete ny lines. */ @@ -431,7 +431,7 @@ screen_write_deleteline(struct screen_write_ctx *ctx, u_int ny) grid_view_delete_lines(s->grid, s->cy, ny); - tty_writenum(ctx->wp, TTY_DELETELINE, ny); + tty_writenum(ctx->wp, tty_cmd_deleteline, ny); return; } @@ -447,7 +447,7 @@ screen_write_deleteline(struct screen_write_ctx *ctx, u_int ny) else grid_view_delete_lines_region(s->grid, s->rlower, s->cy, ny); - tty_writenum(ctx->wp, TTY_DELETELINE, ny); + tty_writenum(ctx->wp, tty_cmd_deleteline, ny); } /* Clear line at cursor. */ @@ -460,7 +460,7 @@ screen_write_clearline(struct screen_write_ctx *ctx) grid_view_clear(s->grid, 0, s->cy, screen_size_x(s), 1); - tty_writenum(ctx->wp, TTY_CLEARLINE, 0); + tty_write0(ctx->wp, tty_cmd_clearline); } /* Clear to end of line from cursor. */ @@ -477,7 +477,7 @@ screen_write_clearendofline(struct screen_write_ctx *ctx) if (s->cx <= sx - 1) grid_view_clear(s->grid, s->cx, s->cy, sx - s->cx, 1); - tty_writenum(ctx->wp, TTY_CLEARENDOFLINE, 0); + tty_write0(ctx->wp, tty_cmd_clearendofline); } /* Clear to start of line from cursor. */ @@ -496,7 +496,7 @@ screen_write_clearstartofline(struct screen_write_ctx *ctx) else grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1); - tty_writenum(ctx->wp, TTY_CLEARSTARTOFLINE, 0); + tty_write0(ctx->wp, tty_cmd_clearstartofline); } /* Move cursor to px,py. */ @@ -539,7 +539,7 @@ screen_write_reverseindex(struct screen_write_ctx *ctx) else if (s->cy > 0) s->cy--; - tty_writenum(ctx->wp, TTY_REVERSEINDEX, 0); + tty_write0(ctx->wp, tty_cmd_reverseindex); } /* Set scroll region. */ @@ -601,7 +601,7 @@ screen_write_linefeed(struct screen_write_ctx *ctx) else if (s->cy < screen_size_y(s) - 1) s->cy++; - tty_writenum(ctx->wp, TTY_LINEFEED, 0); + tty_write0(ctx->wp, tty_cmd_linefeed); } /* Carriage return (cursor to start of line). */ @@ -653,7 +653,7 @@ screen_write_clearendofscreen(struct screen_write_ctx *ctx) grid_view_clear(s->grid, s->cx, s->cy, sx - s->cx, 1); grid_view_clear(s->grid, 0, s->cy + 1, sx, sy - (s->cy + 1)); - tty_writenum(ctx->wp, TTY_CLEARENDOFSCREEN, 0); + tty_write0(ctx->wp, tty_cmd_clearendofscreen); } /* Clear to start of screen. */ @@ -674,7 +674,7 @@ screen_write_clearstartofscreen(struct screen_write_ctx *ctx) else grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1); - tty_writenum(ctx->wp, TTY_CLEARSTARTOFSCREEN, 0); + tty_write0(ctx->wp, tty_cmd_clearstartofscreen); } /* Clear entire screen. */ @@ -687,7 +687,7 @@ screen_write_clearscreen(struct screen_write_ctx *ctx) grid_view_clear(s->grid, 0, 0, screen_size_x(s), screen_size_y(s)); - tty_writenum(ctx->wp, TTY_CLEARSCREEN, 0); + tty_write0(ctx->wp, tty_cmd_clearscreen); } /* Write cell data. */ @@ -737,7 +737,7 @@ screen_write_cell( memcpy(tmp_gu->data + i, udata, UTF8_SIZE - i); /* Assume the previous character has just been input. */ - tty_writeptr(ctx->wp, TTY_UTF8CHARACTER, udata); + tty_writeptr(ctx->wp, tty_cmd_utf8character, udata); return; } @@ -790,16 +790,16 @@ screen_write_cell( /* Draw to the screen if necessary. */ if (insert) - tty_writenum(ctx->wp, TTY_INSERTCHARACTER, width); + tty_writenum(ctx->wp, tty_cmd_insertcharacter, width); ttyctx.wp = ctx->wp; ttyctx.utf8 = &gu; if (screen_check_selection(s, s->cx - width, s->cy)) { s->sel.cell.data = gc->data; ttyctx.cell = &s->sel.cell; - tty_write_cmd(TTY_CELL, &ttyctx); + tty_write(tty_cmd_cell, &ttyctx); } else { ttyctx.cell = gc; - tty_write_cmd(TTY_CELL, &ttyctx); + tty_write(tty_cmd_cell, &ttyctx); } } diff --git a/tmux.h b/tmux.h index 2062dfff..bcf0f8a8 100644 --- a/tmux.h +++ b/tmux.h @@ -273,35 +273,6 @@ struct tty_term_code_entry { const char *name; }; -/* Output commands. */ -enum tty_cmd { - TTY_ALIGNMENTTEST, - TTY_CELL, - TTY_CLEARENDOFLINE, - TTY_CLEARENDOFSCREEN, - TTY_CLEARLINE, - TTY_CLEARSCREEN, - TTY_CLEARSTARTOFLINE, - TTY_CLEARSTARTOFSCREEN, - TTY_DELETECHARACTER, - TTY_DELETELINE, - TTY_INSERTCHARACTER, - TTY_INSERTLINE, - TTY_LINEFEED, - TTY_UTF8CHARACTER, - TTY_REVERSEINDEX, -}; - -struct tty_ctx { - struct window_pane *wp; - - const struct grid_cell *cell; - const struct grid_utf8 *utf8; - - u_int num; - void *ptr; -}; - /* Message codes. */ enum hdrtype { MSG_COMMAND, @@ -805,6 +776,18 @@ struct tty { RB_HEAD(tty_keys, tty_key) ktree; }; +/* TTY command context and function pointer. */ +struct tty_ctx { + struct window_pane *wp; + + const struct grid_cell *cell; + const struct grid_utf8 *utf8; + + u_int num; + void *ptr; +}; +typedef void tty_cmd_func(struct tty *, struct tty_ctx *); + /* Client connection. */ struct client { int fd; @@ -1032,33 +1015,42 @@ void options_set_number(struct options *, const char *, long long); long long options_get_number(struct options *, const char *); /* tty.c */ -u_char tty_get_acs(struct tty *, u_char); -void tty_emulate_repeat(struct tty *, - enum tty_code_code, enum tty_code_code, u_int); -void tty_reset(struct tty *); -void tty_region(struct tty *, u_int, u_int, u_int); -void tty_cursor(struct tty *, u_int, u_int, u_int, u_int); -void tty_cell(struct tty *, - const struct grid_cell *, const struct grid_utf8 *); -void tty_putcode(struct tty *, enum tty_code_code); -void tty_putcode1(struct tty *, enum tty_code_code, int); -void tty_putcode2(struct tty *, enum tty_code_code, int, int); -void tty_puts(struct tty *, const char *); -void tty_putc(struct tty *, u_char); -void tty_pututf8(struct tty *, const struct grid_utf8 *); -void tty_init(struct tty *, char *, char *); -void tty_start_tty(struct tty *); -void tty_stop_tty(struct tty *); -void tty_detect_utf8(struct tty *); -void tty_set_title(struct tty *, const char *); -void tty_update_mode(struct tty *, int); -void tty_draw_line( - struct tty *, struct screen *, u_int, u_int, u_int); -void tty_redraw_region(struct tty *, struct window_pane *); -int tty_open(struct tty *, char **); -void tty_close(struct tty *, int); -void tty_free(struct tty *, int); -void tty_write(struct tty *, enum tty_cmd, struct tty_ctx *); +u_char tty_get_acs(struct tty *, u_char); +void tty_reset(struct tty *); +void tty_region(struct tty *, u_int, u_int, u_int); +void tty_cursor(struct tty *, u_int, u_int, u_int, u_int); +void tty_putcode(struct tty *, enum tty_code_code); +void tty_putcode1(struct tty *, enum tty_code_code, int); +void tty_putcode2(struct tty *, enum tty_code_code, int, int); +void tty_puts(struct tty *, const char *); +void tty_putc(struct tty *, u_char); +void tty_pututf8(struct tty *, const struct grid_utf8 *); +void tty_init(struct tty *, char *, char *); +void tty_start_tty(struct tty *); +void tty_stop_tty(struct tty *); +void tty_detect_utf8(struct tty *); +void tty_set_title(struct tty *, const char *); +void tty_update_mode(struct tty *, int); +void tty_draw_line(struct tty *, struct screen *, u_int, u_int, u_int); +void tty_redraw_region(struct tty *, struct window_pane *); +int tty_open(struct tty *, char **); +void tty_close(struct tty *, int); +void tty_free(struct tty *, int); +void tty_cmd_alignmenttest(struct tty *, struct tty_ctx *); +void tty_cmd_cell(struct tty *, struct tty_ctx *); +void tty_cmd_clearendofline(struct tty *, struct tty_ctx *); +void tty_cmd_clearendofscreen(struct tty *, struct tty_ctx *); +void tty_cmd_clearline(struct tty *, struct tty_ctx *); +void tty_cmd_clearscreen(struct tty *, struct tty_ctx *); +void tty_cmd_clearstartofline(struct tty *, struct tty_ctx *); +void tty_cmd_clearstartofscreen(struct tty *, struct tty_ctx *); +void tty_cmd_deletecharacter(struct tty *, struct tty_ctx *); +void tty_cmd_deleteline(struct tty *, struct tty_ctx *); +void tty_cmd_insertcharacter(struct tty *, struct tty_ctx *); +void tty_cmd_insertline(struct tty *, struct tty_ctx *); +void tty_cmd_linefeed(struct tty *, struct tty_ctx *); +void tty_cmd_utf8character(struct tty *, struct tty_ctx *); +void tty_cmd_reverseindex(struct tty *, struct tty_ctx *); /* tty-term.c */ extern struct tty_terms tty_terms; @@ -1074,17 +1066,17 @@ int tty_term_number(struct tty_term *, enum tty_code_code); int tty_term_flag(struct tty_term *, enum tty_code_code); /* tty-keys.c */ -int tty_keys_cmp(struct tty_key *, struct tty_key *); +int tty_keys_cmp(struct tty_key *, struct tty_key *); RB_PROTOTYPE(tty_keys, tty_key, entry, tty_keys_cmp); -void tty_keys_init(struct tty *); -void tty_keys_free(struct tty *); -int tty_keys_next(struct tty *, int *, u_char *); +void tty_keys_init(struct tty *); +void tty_keys_free(struct tty *); +int tty_keys_next(struct tty *, int *, u_char *); /* tty-write.c */ -void tty_write0(struct window_pane *, enum tty_cmd); -void tty_writenum(struct window_pane *, enum tty_cmd, u_int); -void tty_writeptr(struct window_pane *, enum tty_cmd, void *); -void tty_write_cmd(enum tty_cmd, struct tty_ctx *); +void tty_write0(struct window_pane *, tty_cmd_func *); +void tty_writenum(struct window_pane *, tty_cmd_func *, u_int); +void tty_writeptr(struct window_pane *, tty_cmd_func *, void *); +void tty_write(tty_cmd_func *, struct tty_ctx *); /* options-cmd.c */ void set_option_string(struct cmd_ctx *, diff --git a/tty-write.c b/tty-write.c index b8e39837..c9bc534e 100644 --- a/tty-write.c +++ b/tty-write.c @@ -23,39 +23,39 @@ #include "tmux.h" void -tty_write0(struct window_pane *wp, enum tty_cmd cmd) +tty_write0(struct window_pane *wp, tty_cmd_func *cmdfn) { struct tty_ctx ctx; memset(&ctx, 0, sizeof ctx); ctx.wp = wp; - tty_write_cmd(cmd, &ctx); + tty_write(cmdfn, &ctx); } void -tty_writenum(struct window_pane *wp, enum tty_cmd cmd, u_int num) +tty_writenum(struct window_pane *wp, tty_cmd_func *cmdfn, u_int num) { struct tty_ctx ctx; memset(&ctx, 0, sizeof ctx); ctx.wp = wp; ctx.num = num; - tty_write_cmd(cmd, &ctx); + tty_write(cmdfn, &ctx); } void -tty_writeptr(struct window_pane *wp, enum tty_cmd cmd, void *ptr) +tty_writeptr(struct window_pane *wp, tty_cmd_func *cmdfn, void *ptr) { struct tty_ctx ctx; memset(&ctx, 0, sizeof ctx); ctx.wp = wp; ctx.ptr = ptr; - tty_write_cmd(cmd, &ctx); + tty_write(cmdfn, &ctx); } void -tty_write_cmd(enum tty_cmd cmd, struct tty_ctx *ctx) +tty_write(tty_cmd_func *cmdfn, struct tty_ctx *ctx) { struct window_pane *wp = ctx->wp; struct client *c; @@ -77,9 +77,10 @@ tty_write_cmd(enum tty_cmd cmd, struct tty_ctx *ctx) continue; if (c->session->curw->window == wp->window) { + if (c->tty.flags & TTY_FREEZE || c->tty.term == NULL) + continue; tty_update_mode(&c->tty, c->tty.mode & ~MODE_CURSOR); - - tty_write(&c->tty, cmd, ctx); + cmdfn(&c->tty, ctx); } } } diff --git a/tty.c b/tty.c index dfa36a5e..c09fe6c4 100644 --- a/tty.c +++ b/tty.c @@ -38,39 +38,10 @@ void tty_attributes(struct tty *, const struct grid_cell *); void tty_attributes_fg(struct tty *, const struct grid_cell *); void tty_attributes_bg(struct tty *, const struct grid_cell *); -void tty_cmd_alignmenttest(struct tty *, struct tty_ctx *); -void tty_cmd_cell(struct tty *, struct tty_ctx *); -void tty_cmd_clearendofline(struct tty *, struct tty_ctx *); -void tty_cmd_clearendofscreen(struct tty *, struct tty_ctx *); -void tty_cmd_clearline(struct tty *, struct tty_ctx *); -void tty_cmd_clearscreen(struct tty *, struct tty_ctx *); -void tty_cmd_clearstartofline(struct tty *, struct tty_ctx *); -void tty_cmd_clearstartofscreen(struct tty *, struct tty_ctx *); -void tty_cmd_deletecharacter(struct tty *, struct tty_ctx *); -void tty_cmd_deleteline(struct tty *, struct tty_ctx *); -void tty_cmd_insertcharacter(struct tty *, struct tty_ctx *); -void tty_cmd_insertline(struct tty *, struct tty_ctx *); -void tty_cmd_linefeed(struct tty *, struct tty_ctx *); -void tty_cmd_utf8character(struct tty *, struct tty_ctx *); -void tty_cmd_reverseindex(struct tty *, struct tty_ctx *); - -void (*tty_cmds[])(struct tty *, struct tty_ctx *) = { - tty_cmd_alignmenttest, - tty_cmd_cell, - tty_cmd_clearendofline, - tty_cmd_clearendofscreen, - tty_cmd_clearline, - tty_cmd_clearscreen, - tty_cmd_clearstartofline, - tty_cmd_clearstartofscreen, - tty_cmd_deletecharacter, - tty_cmd_deleteline, - tty_cmd_insertcharacter, - tty_cmd_insertline, - tty_cmd_linefeed, - tty_cmd_utf8character, - tty_cmd_reverseindex, -}; +void tty_emulate_repeat( + struct tty *, enum tty_code_code, enum tty_code_code, u_int); +void tty_cell(struct tty *, + const struct grid_cell *, const struct grid_utf8 *); void tty_init(struct tty *tty, char *path, char *term) @@ -544,15 +515,6 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int py, u_int ox, u_int oy) } } -void -tty_write(struct tty *tty, enum tty_cmd cmd, struct tty_ctx *ctx) -{ - if (tty->flags & TTY_FREEZE || tty->term == NULL) - return; - if (tty_cmds[cmd] != NULL) - tty_cmds[cmd](tty, ctx); -} - void tty_cmd_insertcharacter(struct tty *tty, struct tty_ctx *ctx) { From bb4bab4c262f3b7b8bc2df8857b417a229c595e1 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 22 Jul 2009 18:06:58 +0000 Subject: [PATCH 0161/1180] log_debug3 no longer exists, change the sole use in GRID_DEBUG to log_debug2. --- tmux.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tmux.h b/tmux.h index bcf0f8a8..8b64ee36 100644 --- a/tmux.h +++ b/tmux.h @@ -376,7 +376,7 @@ struct mode_key_data { #if defined(DEBUG) && \ ((defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || \ (defined(__GNUC__) && __GNUC__ >= 3)) -#define GRID_DEBUG(gd, fmt, ...) log_debug3("%s: (sx=%u, sy=%u, hsize=%u) " \ +#define GRID_DEBUG(gd, fmt, ...) log_debug2("%s: (sx=%u, sy=%u, hsize=%u) " \ fmt, __func__, (gd)->sx, (gd)->sy, (gd)->hsize, ## __VA_ARGS__) #else #define GRID_DEBUG(...) From ddad0be5f773978c09e7c86ad79596ce7af9ec71 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 22 Jul 2009 20:53:38 +0000 Subject: [PATCH 0162/1180] More tty code tidying: move the saved cursor/region position (from before the screen was updated) out of struct screen and into struct tty_ctx. --- screen-write.c | 108 ++++++++++++++++++++++++++++++------------------- tmux.h | 26 ++++++------ tty-write.c | 34 ---------------- tty.c | 90 ++++++++++++++++++++--------------------- 4 files changed, 126 insertions(+), 132 deletions(-) diff --git a/screen-write.c b/screen-write.c index 2f41ae55..e2fbfbf4 100644 --- a/screen-write.c +++ b/screen-write.c @@ -22,7 +22,7 @@ #include "tmux.h" -void screen_write_save(struct screen_write_ctx *); +void screen_write_initctx(struct screen_write_ctx *, struct tty_ctx *); void screen_write_overwrite(struct screen_write_ctx *); /* Initialise writing with a window. */ @@ -210,17 +210,19 @@ screen_write_copy(struct screen_write_ctx *ctx, } } -/* Save cursor and region positions. */ +/* Set up context for TTY command. */ void -screen_write_save(struct screen_write_ctx *ctx) +screen_write_initctx(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx) { struct screen *s = ctx->s; - s->old_cx = s->cx; - s->old_cy = s->cy; + ttyctx->wp = ctx->wp; - s->old_rlower = s->rlower; - s->old_rupper = s->rupper; + ttyctx->ocx = s->cx; + ttyctx->ocy = s->cy; + + ttyctx->orlower = s->rlower; + ttyctx->orupper = s->rupper; } /* Cursor up by ny. */ @@ -310,9 +312,12 @@ void screen_write_alignmenttest(struct screen_write_ctx *ctx) { struct screen *s = ctx->s; + struct tty_ctx ttyctx; struct grid_cell gc; u_int xx, yy; + screen_write_initctx(ctx, &ttyctx); + memcpy(&gc, &grid_default_cell, sizeof gc); gc.data = 'E'; @@ -327,7 +332,7 @@ screen_write_alignmenttest(struct screen_write_ctx *ctx) s->rupper = 0; s->rlower = screen_size_y(s) - 1; - tty_write0(ctx->wp, tty_cmd_alignmenttest); + tty_write(tty_cmd_alignmenttest, &ttyctx); } /* Insert nx characters. */ @@ -335,6 +340,7 @@ void screen_write_insertcharacter(struct screen_write_ctx *ctx, u_int nx) { struct screen *s = ctx->s; + struct tty_ctx ttyctx; if (nx == 0) nx = 1; @@ -344,12 +350,13 @@ screen_write_insertcharacter(struct screen_write_ctx *ctx, u_int nx) if (nx == 0) return; - screen_write_save(ctx); + screen_write_initctx(ctx, &ttyctx); if (s->cx <= screen_size_x(s) - 1) grid_view_insert_cells(s->grid, s->cx, s->cy, nx); - tty_writenum(ctx->wp, tty_cmd_insertcharacter, nx); + ttyctx.num = nx; + tty_write(tty_cmd_insertcharacter, &ttyctx); } /* Delete nx characters. */ @@ -357,6 +364,7 @@ void screen_write_deletecharacter(struct screen_write_ctx *ctx, u_int nx) { struct screen *s = ctx->s; + struct tty_ctx ttyctx; if (nx == 0) nx = 1; @@ -366,12 +374,13 @@ screen_write_deletecharacter(struct screen_write_ctx *ctx, u_int nx) if (nx == 0) return; - screen_write_save(ctx); + screen_write_initctx(ctx, &ttyctx); if (s->cx <= screen_size_x(s) - 1) grid_view_delete_cells(s->grid, s->cx, s->cy, nx); - tty_writenum(ctx->wp, tty_cmd_deletecharacter, nx); + ttyctx.num = nx; + tty_write(tty_cmd_deletecharacter, &ttyctx); } /* Insert ny lines. */ @@ -379,6 +388,7 @@ void screen_write_insertline(struct screen_write_ctx *ctx, u_int ny) { struct screen *s = ctx->s; + struct tty_ctx ttyctx; if (ny == 0) ny = 1; @@ -389,11 +399,12 @@ screen_write_insertline(struct screen_write_ctx *ctx, u_int ny) if (ny == 0) return; - screen_write_save(ctx); + screen_write_initctx(ctx, &ttyctx); grid_view_insert_lines(s->grid, s->cy, ny); - tty_writenum(ctx->wp, tty_cmd_insertline, ny); + ttyctx.num = ny; + tty_write(tty_cmd_insertline, &ttyctx); return; } @@ -402,14 +413,15 @@ screen_write_insertline(struct screen_write_ctx *ctx, u_int ny) if (ny == 0) return; - screen_write_save(ctx); + screen_write_initctx(ctx, &ttyctx); if (s->cy < s->rupper || s->cy > s->rlower) grid_view_insert_lines(s->grid, s->cy, ny); else grid_view_insert_lines_region(s->grid, s->rlower, s->cy, ny); - tty_writenum(ctx->wp, tty_cmd_insertline, ny); + ttyctx.num = ny; + tty_write(tty_cmd_insertline, &ttyctx); } /* Delete ny lines. */ @@ -417,6 +429,7 @@ void screen_write_deleteline(struct screen_write_ctx *ctx, u_int ny) { struct screen *s = ctx->s; + struct tty_ctx ttyctx; if (ny == 0) ny = 1; @@ -427,11 +440,12 @@ screen_write_deleteline(struct screen_write_ctx *ctx, u_int ny) if (ny == 0) return; - screen_write_save(ctx); + screen_write_initctx(ctx, &ttyctx); grid_view_delete_lines(s->grid, s->cy, ny); - tty_writenum(ctx->wp, tty_cmd_deleteline, ny); + ttyctx.num = ny; + tty_write(tty_cmd_deleteline, &ttyctx); return; } @@ -440,14 +454,15 @@ screen_write_deleteline(struct screen_write_ctx *ctx, u_int ny) if (ny == 0) return; - screen_write_save(ctx); + screen_write_initctx(ctx, &ttyctx); if (s->cy < s->rupper || s->cy > s->rlower) grid_view_delete_lines(s->grid, s->cy, ny); else grid_view_delete_lines_region(s->grid, s->rlower, s->cy, ny); - tty_writenum(ctx->wp, tty_cmd_deleteline, ny); + ttyctx.num = ny; + tty_write(tty_cmd_deleteline, &ttyctx); } /* Clear line at cursor. */ @@ -455,12 +470,13 @@ void screen_write_clearline(struct screen_write_ctx *ctx) { struct screen *s = ctx->s; + struct tty_ctx ttyctx; - screen_write_save(ctx); + screen_write_initctx(ctx, &ttyctx); grid_view_clear(s->grid, 0, s->cy, screen_size_x(s), 1); - tty_write0(ctx->wp, tty_cmd_clearline); + tty_write(tty_cmd_clearline, &ttyctx); } /* Clear to end of line from cursor. */ @@ -468,16 +484,17 @@ void screen_write_clearendofline(struct screen_write_ctx *ctx) { struct screen *s = ctx->s; + struct tty_ctx ttyctx; u_int sx; - screen_write_save(ctx); + screen_write_initctx(ctx, &ttyctx); sx = screen_size_x(s); if (s->cx <= sx - 1) grid_view_clear(s->grid, s->cx, s->cy, sx - s->cx, 1); - tty_write0(ctx->wp, tty_cmd_clearendofline); + tty_write(tty_cmd_clearendofline, &ttyctx); } /* Clear to start of line from cursor. */ @@ -485,9 +502,10 @@ void screen_write_clearstartofline(struct screen_write_ctx *ctx) { struct screen *s = ctx->s; + struct tty_ctx ttyctx; u_int sx; - screen_write_save(ctx); + screen_write_initctx(ctx, &ttyctx); sx = screen_size_x(s); @@ -496,7 +514,7 @@ screen_write_clearstartofline(struct screen_write_ctx *ctx) else grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1); - tty_write0(ctx->wp, tty_cmd_clearstartofline); + tty_write(tty_cmd_clearstartofline, &ttyctx); } /* Move cursor to px,py. */ @@ -531,15 +549,16 @@ void screen_write_reverseindex(struct screen_write_ctx *ctx) { struct screen *s = ctx->s; + struct tty_ctx ttyctx; - screen_write_save(ctx); + screen_write_initctx(ctx, &ttyctx); if (s->cy == s->rupper) grid_view_scroll_region_down(s->grid, s->rupper, s->rlower); else if (s->cy > 0) s->cy--; - tty_write0(ctx->wp, tty_cmd_reverseindex); + tty_write(tty_cmd_reverseindex, &ttyctx); } /* Set scroll region. */ @@ -593,15 +612,16 @@ void screen_write_linefeed(struct screen_write_ctx *ctx) { struct screen *s = ctx->s; + struct tty_ctx ttyctx; - screen_write_save(ctx); + screen_write_initctx(ctx, &ttyctx); if (s->cy == s->rlower) grid_view_scroll_region_up(s->grid, s->rupper, s->rlower); else if (s->cy < screen_size_y(s) - 1) s->cy++; - tty_write0(ctx->wp, tty_cmd_linefeed); + tty_write(tty_cmd_linefeed, &ttyctx); } /* Carriage return (cursor to start of line). */ @@ -642,9 +662,10 @@ void screen_write_clearendofscreen(struct screen_write_ctx *ctx) { struct screen *s = ctx->s; + struct tty_ctx ttyctx; u_int sx, sy; - screen_write_save(ctx); + screen_write_initctx(ctx, &ttyctx); sx = screen_size_x(s); sy = screen_size_y(s); @@ -653,7 +674,7 @@ screen_write_clearendofscreen(struct screen_write_ctx *ctx) grid_view_clear(s->grid, s->cx, s->cy, sx - s->cx, 1); grid_view_clear(s->grid, 0, s->cy + 1, sx, sy - (s->cy + 1)); - tty_write0(ctx->wp, tty_cmd_clearendofscreen); + tty_write(tty_cmd_clearendofscreen, &ttyctx); } /* Clear to start of screen. */ @@ -661,9 +682,10 @@ void screen_write_clearstartofscreen(struct screen_write_ctx *ctx) { struct screen *s = ctx->s; + struct tty_ctx ttyctx; u_int sx; - screen_write_save(ctx); + screen_write_initctx(ctx, &ttyctx); sx = screen_size_x(s); @@ -674,7 +696,7 @@ screen_write_clearstartofscreen(struct screen_write_ctx *ctx) else grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1); - tty_write0(ctx->wp, tty_cmd_clearstartofscreen); + tty_write(tty_cmd_clearstartofscreen, &ttyctx); } /* Clear entire screen. */ @@ -682,12 +704,13 @@ void screen_write_clearscreen(struct screen_write_ctx *ctx) { struct screen *s = ctx->s; + struct tty_ctx ttyctx; - screen_write_save(ctx); + screen_write_initctx(ctx, &ttyctx); grid_view_clear(s->grid, 0, 0, screen_size_x(s), screen_size_y(s)); - tty_write0(ctx->wp, tty_cmd_clearscreen); + tty_write(tty_cmd_clearscreen, &ttyctx); } /* Write cell data. */ @@ -737,7 +760,9 @@ screen_write_cell( memcpy(tmp_gu->data + i, udata, UTF8_SIZE - i); /* Assume the previous character has just been input. */ - tty_writeptr(ctx->wp, tty_cmd_utf8character, udata); + screen_write_initctx(ctx, &ttyctx); + ttyctx.ptr = udata; + tty_write(tty_cmd_utf8character, &ttyctx); return; } @@ -785,13 +810,14 @@ screen_write_cell( grid_view_set_utf8(gd, s->cx, s->cy, &gu); /* Move the cursor. */ - screen_write_save(ctx); + screen_write_initctx(ctx, &ttyctx); s->cx += width; /* Draw to the screen if necessary. */ - if (insert) - tty_writenum(ctx->wp, tty_cmd_insertcharacter, width); - ttyctx.wp = ctx->wp; + if (insert) { + ttyctx.num = width; + tty_write(tty_cmd_insertcharacter, &ttyctx); + } ttyctx.utf8 = &gu; if (screen_check_selection(s, s->cx - width, s->cy)) { s->sel.cell.data = gc->data; diff --git a/tmux.h b/tmux.h index 8b64ee36..d8d1c659 100644 --- a/tmux.h +++ b/tmux.h @@ -477,15 +477,9 @@ struct screen { u_int cx; /* cursor x */ u_int cy; /* cursor y */ - u_int old_cx; - u_int old_cy; - u_int rupper; /* scroll region top */ u_int rlower; /* scroll region bottom */ - u_int old_rupper; - u_int old_rlower; - int mode; bitstr_t *tabs; @@ -783,8 +777,19 @@ struct tty_ctx { const struct grid_cell *cell; const struct grid_utf8 *utf8; - u_int num; - void *ptr; + u_int num; + void *ptr; + + /* + * Cursor and region position before the screen was updated - this is + * where the command should be applied; the values in the screen have + * already been updated. + */ + u_int ocx; + u_int ocy; + + u_int orupper; + u_int orlower; }; typedef void tty_cmd_func(struct tty *, struct tty_ctx *); @@ -1032,10 +1037,10 @@ void tty_detect_utf8(struct tty *); void tty_set_title(struct tty *, const char *); void tty_update_mode(struct tty *, int); void tty_draw_line(struct tty *, struct screen *, u_int, u_int, u_int); -void tty_redraw_region(struct tty *, struct window_pane *); int tty_open(struct tty *, char **); void tty_close(struct tty *, int); void tty_free(struct tty *, int); +void tty_write(void (*)(struct tty *, struct tty_ctx *), struct tty_ctx *); void tty_cmd_alignmenttest(struct tty *, struct tty_ctx *); void tty_cmd_cell(struct tty *, struct tty_ctx *); void tty_cmd_clearendofline(struct tty *, struct tty_ctx *); @@ -1073,9 +1078,6 @@ void tty_keys_free(struct tty *); int tty_keys_next(struct tty *, int *, u_char *); /* tty-write.c */ -void tty_write0(struct window_pane *, tty_cmd_func *); -void tty_writenum(struct window_pane *, tty_cmd_func *, u_int); -void tty_writeptr(struct window_pane *, tty_cmd_func *, void *); void tty_write(tty_cmd_func *, struct tty_ctx *); /* options-cmd.c */ diff --git a/tty-write.c b/tty-write.c index c9bc534e..2d44d7f8 100644 --- a/tty-write.c +++ b/tty-write.c @@ -18,42 +18,8 @@ #include -#include - #include "tmux.h" -void -tty_write0(struct window_pane *wp, tty_cmd_func *cmdfn) -{ - struct tty_ctx ctx; - - memset(&ctx, 0, sizeof ctx); - ctx.wp = wp; - tty_write(cmdfn, &ctx); -} - -void -tty_writenum(struct window_pane *wp, tty_cmd_func *cmdfn, u_int num) -{ - struct tty_ctx ctx; - - memset(&ctx, 0, sizeof ctx); - ctx.wp = wp; - ctx.num = num; - tty_write(cmdfn, &ctx); -} - -void -tty_writeptr(struct window_pane *wp, tty_cmd_func *cmdfn, void *ptr) -{ - struct tty_ctx ctx; - - memset(&ctx, 0, sizeof ctx); - ctx.wp = wp; - ctx.ptr = ptr; - tty_write(cmdfn, &ctx); -} - void tty_write(tty_cmd_func *cmdfn, struct tty_ctx *ctx) { diff --git a/tty.c b/tty.c index c09fe6c4..cae894b8 100644 --- a/tty.c +++ b/tty.c @@ -38,10 +38,11 @@ void tty_attributes(struct tty *, const struct grid_cell *); void tty_attributes_fg(struct tty *, const struct grid_cell *); void tty_attributes_bg(struct tty *, const struct grid_cell *); +void tty_redraw_region(struct tty *, struct tty_ctx *); void tty_emulate_repeat( struct tty *, enum tty_code_code, enum tty_code_code, u_int); -void tty_cell(struct tty *, - const struct grid_cell *, const struct grid_utf8 *); +void tty_cell(struct tty *, + const struct grid_cell *, const struct grid_utf8 *); void tty_init(struct tty *tty, char *path, char *term) @@ -449,10 +450,11 @@ tty_emulate_repeat( * width of the terminal. */ void -tty_redraw_region(struct tty *tty, struct window_pane *wp) +tty_redraw_region(struct tty *tty, struct tty_ctx *ctx) { - struct screen *s = wp->screen; - u_int i; + struct window_pane *wp = ctx->wp; + struct screen *s = wp->screen; + u_int i; /* * If region is >= 50% of the screen, just schedule a window redraw. In @@ -460,16 +462,16 @@ tty_redraw_region(struct tty *tty, struct window_pane *wp) * without this, the entire pane ends up being redrawn many times which * can be much more data. */ - if (s->old_rupper - s->old_rlower >= screen_size_y(s) / 2) { + if (ctx->orupper - ctx->orlower >= screen_size_y(s) / 2) { wp->flags |= PANE_REDRAW; return; } - if (s->old_cy < s->old_rupper || s->old_cy > s->old_rlower) { - for (i = s->old_cy; i < screen_size_y(s); i++) + if (ctx->ocy < ctx->orupper || ctx->ocy > ctx->orlower) { + for (i = ctx->ocy; i < screen_size_y(s); i++) tty_draw_line(tty, s, i, wp->xoff, wp->yoff); } else { - for (i = s->old_rupper; i <= s->old_rlower; i++) + for (i = ctx->orupper; i <= ctx->orlower; i++) tty_draw_line(tty, s, i, wp->xoff, wp->yoff); } } @@ -522,13 +524,13 @@ tty_cmd_insertcharacter(struct tty *tty, struct tty_ctx *ctx) struct screen *s = wp->screen; if (wp->xoff != 0 || screen_size_x(s) < tty->sx) { - tty_draw_line(tty, wp->screen, s->old_cy, wp->xoff, wp->yoff); + tty_draw_line(tty, wp->screen, ctx->ocy, wp->xoff, wp->yoff); return; } tty_reset(tty); - tty_cursor(tty, s->old_cx, s->old_cy, wp->xoff, wp->yoff); + tty_cursor(tty, ctx->ocx, ctx->ocy, wp->xoff, wp->yoff); if (tty_term_has(tty->term, TTYC_ICH) || tty_term_has(tty->term, TTYC_ICH1)) tty_emulate_repeat(tty, TTYC_ICH, TTYC_ICH1, ctx->num); @@ -547,13 +549,13 @@ tty_cmd_deletecharacter(struct tty *tty, struct tty_ctx *ctx) struct screen *s = wp->screen; if (wp->xoff != 0 || screen_size_x(s) < tty->sx) { - tty_draw_line(tty, wp->screen, s->old_cy, wp->xoff, wp->yoff); + tty_draw_line(tty, wp->screen, ctx->ocy, wp->xoff, wp->yoff); return; } tty_reset(tty); - tty_cursor(tty, s->old_cx, s->old_cy, wp->xoff, wp->yoff); + tty_cursor(tty, ctx->ocx, ctx->ocy, wp->xoff, wp->yoff); tty_emulate_repeat(tty, TTYC_DCH, TTYC_DCH1, ctx->num); } @@ -565,15 +567,15 @@ tty_cmd_insertline(struct tty *tty, struct tty_ctx *ctx) if (wp->xoff != 0 || screen_size_x(s) < tty->sx || !tty_term_has(tty->term, TTYC_CSR)) { - tty_redraw_region(tty, wp); + tty_redraw_region(tty, ctx); return; } tty_reset(tty); - tty_region(tty, s->old_rupper, s->old_rlower, wp->yoff); + tty_region(tty, ctx->orupper, ctx->orlower, wp->yoff); - tty_cursor(tty, s->old_cx, s->old_cy, wp->xoff, wp->yoff); + tty_cursor(tty, ctx->ocx, ctx->ocy, wp->xoff, wp->yoff); tty_emulate_repeat(tty, TTYC_IL, TTYC_IL1, ctx->num); } @@ -585,15 +587,15 @@ tty_cmd_deleteline(struct tty *tty, struct tty_ctx *ctx) if (wp->xoff != 0 || screen_size_x(s) < tty->sx || !tty_term_has(tty->term, TTYC_CSR)) { - tty_redraw_region(tty, wp); + tty_redraw_region(tty, ctx); return; } tty_reset(tty); - tty_region(tty, s->old_rupper, s->old_rlower, wp->yoff); + tty_region(tty, ctx->orupper, ctx->orlower, wp->yoff); - tty_cursor(tty, s->old_cx, s->old_cy, wp->xoff, wp->yoff); + tty_cursor(tty, ctx->ocx, ctx->ocy, wp->xoff, wp->yoff); tty_emulate_repeat(tty, TTYC_DL, TTYC_DL1, ctx->num); } @@ -606,7 +608,7 @@ tty_cmd_clearline(struct tty *tty, struct tty_ctx *ctx) tty_reset(tty); - tty_cursor(tty, 0, s->old_cy, wp->xoff, wp->yoff); + tty_cursor(tty, 0, ctx->ocy, wp->xoff, wp->yoff); if (wp->xoff == 0 && screen_size_x(s) >= tty->sx && tty_term_has(tty->term, TTYC_EL)) { tty_putcode(tty, TTYC_EL); @@ -625,12 +627,12 @@ tty_cmd_clearendofline(struct tty *tty, struct tty_ctx *ctx) tty_reset(tty); - tty_cursor(tty, s->old_cx, s->old_cy, wp->xoff, wp->yoff); + tty_cursor(tty, ctx->ocx, ctx->ocy, wp->xoff, wp->yoff); if (wp->xoff == 0 && screen_size_x(s) >= tty->sx && tty_term_has(tty->term, TTYC_EL)) tty_putcode(tty, TTYC_EL); else { - for (i = s->old_cx; i < screen_size_x(s); i++) + for (i = ctx->ocx; i < screen_size_x(s); i++) tty_putc(tty, ' '); } } @@ -639,17 +641,16 @@ void tty_cmd_clearstartofline(struct tty *tty, struct tty_ctx *ctx) { struct window_pane *wp = ctx->wp; - struct screen *s = wp->screen; u_int i; tty_reset(tty); if (wp->xoff == 0 && tty_term_has(tty->term, TTYC_EL1)) { - tty_cursor(tty, s->old_cx, s->old_cy, wp->xoff, wp->yoff); + tty_cursor(tty, ctx->ocx, ctx->ocy, wp->xoff, wp->yoff); tty_putcode(tty, TTYC_EL1); } else { - tty_cursor(tty, 0, s->old_cy, wp->xoff, wp->yoff); - for (i = 0; i < s->old_cx + 1; i++) + tty_cursor(tty, 0, ctx->ocy, wp->xoff, wp->yoff); + for (i = 0; i < ctx->ocx + 1; i++) tty_putc(tty, ' '); } } @@ -662,16 +663,16 @@ tty_cmd_reverseindex(struct tty *tty, struct tty_ctx *ctx) if (wp->xoff != 0 || screen_size_x(s) < tty->sx || !tty_term_has(tty->term, TTYC_CSR)) { - tty_redraw_region(tty, wp); + tty_redraw_region(tty, ctx); return; } tty_reset(tty); - tty_region(tty, s->old_rupper, s->old_rlower, wp->yoff); + tty_region(tty, ctx->orupper, ctx->orlower, wp->yoff); - if (s->old_cy == s->old_rupper) { - tty_cursor(tty, s->old_cx, s->old_rupper, wp->xoff, wp->yoff); + if (ctx->ocy == ctx->orupper) { + tty_cursor(tty, ctx->ocx, ctx->orupper, wp->xoff, wp->yoff); tty_putcode(tty, TTYC_RI); } } @@ -684,16 +685,16 @@ tty_cmd_linefeed(struct tty *tty, struct tty_ctx *ctx) if (wp->xoff != 0 || screen_size_x(s) < tty->sx || !tty_term_has(tty->term, TTYC_CSR)) { - tty_redraw_region(tty, wp); + tty_redraw_region(tty, ctx); return; } tty_reset(tty); - tty_region(tty, s->old_rupper, s->old_rlower, wp->yoff); + tty_region(tty, ctx->orupper, ctx->orlower, wp->yoff); - if (s->old_cy == s->old_rlower) { - tty_cursor(tty, s->old_cx, s->old_cy, wp->xoff, wp->yoff); + if (ctx->ocy == ctx->orlower) { + tty_cursor(tty, ctx->ocx, ctx->ocy, wp->xoff, wp->yoff); tty_putc(tty, '\n'); } } @@ -708,13 +709,13 @@ tty_cmd_clearendofscreen(struct tty *tty, struct tty_ctx *ctx) tty_reset(tty); tty_region(tty, 0, screen_size_y(s) - 1, wp->yoff); - tty_cursor(tty, s->old_cx, s->old_cy, wp->xoff, wp->yoff); + tty_cursor(tty, ctx->ocx, ctx->ocy, wp->xoff, wp->yoff); if (wp->xoff == 0 && screen_size_x(s) >= tty->sx && tty_term_has(tty->term, TTYC_EL)) { tty_putcode(tty, TTYC_EL); - if (s->old_cy != screen_size_y(s) - 1) { - tty_cursor(tty, 0, s->old_cy + 1, wp->xoff, wp->yoff); - for (i = s->old_cy + 1; i < screen_size_y(s); i++) { + if (ctx->ocy != screen_size_y(s) - 1) { + tty_cursor(tty, 0, ctx->ocy + 1, wp->xoff, wp->yoff); + for (i = ctx->ocy + 1; i < screen_size_y(s); i++) { tty_putcode(tty, TTYC_EL); if (i == screen_size_y(s) - 1) continue; @@ -723,9 +724,9 @@ tty_cmd_clearendofscreen(struct tty *tty, struct tty_ctx *ctx) } } } else { - for (i = s->old_cx; i < screen_size_x(s); i++) + for (i = ctx->ocx; i < screen_size_x(s); i++) tty_putc(tty, ' '); - for (j = s->old_cy; j < screen_size_y(s); j++) { + for (j = ctx->ocy; j < screen_size_y(s); j++) { tty_cursor(tty, 0, j, wp->xoff, wp->yoff); for (i = 0; i < screen_size_x(s); i++) tty_putc(tty, ' '); @@ -746,19 +747,19 @@ tty_cmd_clearstartofscreen(struct tty *tty, struct tty_ctx *ctx) tty_cursor(tty, 0, 0, wp->xoff, wp->yoff); if (wp->xoff == 0 && screen_size_x(s) >= tty->sx && tty_term_has(tty->term, TTYC_EL)) { - for (i = 0; i < s->old_cy; i++) { + for (i = 0; i < ctx->ocy; i++) { tty_putcode(tty, TTYC_EL); tty_emulate_repeat(tty, TTYC_CUD, TTYC_CUD1, 1); tty->cy++; } } else { - for (j = 0; j < s->old_cy; j++) { + for (j = 0; j < ctx->ocy; j++) { tty_cursor(tty, 0, j, wp->xoff, wp->yoff); for (i = 0; i < screen_size_x(s); i++) tty_putc(tty, ' '); } } - for (i = 0; i <= s->old_cx; i++) + for (i = 0; i <= ctx->ocx; i++) tty_putc(tty, ' '); } @@ -813,9 +814,8 @@ void tty_cmd_cell(struct tty *tty, struct tty_ctx *ctx) { struct window_pane *wp = ctx->wp; - struct screen *s = wp->screen; - tty_cursor(tty, s->old_cx, s->old_cy, wp->xoff, wp->yoff); + tty_cursor(tty, ctx->ocx, ctx->ocy, wp->xoff, wp->yoff); tty_cell(tty, ctx->cell, ctx->utf8); } From dd4a3b24fc5b0d6e38e87b3a3c1bc0a47bdc9700 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 22 Jul 2009 20:56:58 +0000 Subject: [PATCH 0163/1180] tty_write is relatively short and the only function left in tty-write.c so move it into tty.c. --- Makefile | 2 +- tmux.h | 4 ---- tty-write.c | 52 ---------------------------------------------------- tty.c | 31 +++++++++++++++++++++++++++++++ 4 files changed, 32 insertions(+), 57 deletions(-) delete mode 100644 tty-write.c diff --git a/Makefile b/Makefile index 924ac4ec..b565c44b 100644 --- a/Makefile +++ b/Makefile @@ -31,7 +31,7 @@ SRCS= attributes.c buffer-poll.c buffer.c cfg.c client-fn.c \ mode-key.c names.c options-cmd.c options.c paste.c procname.c \ resize.c screen-redraw.c screen-write.c screen.c server-fn.c \ server-msg.c server.c session.c status.c tmux.c tty-keys.c tty-term.c \ - tty-write.c tty.c utf8.c window-choose.c window-clock.c \ + tty.c utf8.c window-choose.c window-clock.c \ window-copy.c window-more.c window-scroll.c window.c xmalloc.c CDIAGFLAGS+= -Wno-long-long -Wall -W -Wnested-externs -Wformat=2 diff --git a/tmux.h b/tmux.h index d8d1c659..70c5a4b8 100644 --- a/tmux.h +++ b/tmux.h @@ -791,7 +791,6 @@ struct tty_ctx { u_int orupper; u_int orlower; }; -typedef void tty_cmd_func(struct tty *, struct tty_ctx *); /* Client connection. */ struct client { @@ -1077,9 +1076,6 @@ void tty_keys_init(struct tty *); void tty_keys_free(struct tty *); int tty_keys_next(struct tty *, int *, u_char *); -/* tty-write.c */ -void tty_write(tty_cmd_func *, struct tty_ctx *); - /* options-cmd.c */ void set_option_string(struct cmd_ctx *, struct options *, const struct set_option_entry *, char *); diff --git a/tty-write.c b/tty-write.c deleted file mode 100644 index 2d44d7f8..00000000 --- a/tty-write.c +++ /dev/null @@ -1,52 +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" - -void -tty_write(tty_cmd_func *cmdfn, struct tty_ctx *ctx) -{ - struct window_pane *wp = ctx->wp; - struct client *c; - u_int i; - - if (wp == NULL) - return; - - if (wp->window->flags & WINDOW_REDRAW || wp->flags & PANE_REDRAW) - return; - if (wp->window->flags & WINDOW_HIDDEN || !window_pane_visible(wp)) - return; - - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - c = ARRAY_ITEM(&clients, i); - if (c == NULL || c->session == NULL) - continue; - if (c->flags & CLIENT_SUSPENDED) - continue; - - if (c->session->curw->window == wp->window) { - if (c->tty.flags & TTY_FREEZE || c->tty.term == NULL) - continue; - tty_update_mode(&c->tty, c->tty.mode & ~MODE_CURSOR); - cmdfn(&c->tty, ctx); - } - } -} diff --git a/tty.c b/tty.c index cae894b8..05342b82 100644 --- a/tty.c +++ b/tty.c @@ -517,6 +517,37 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int py, u_int ox, u_int oy) } } +void +tty_write(void (*cmdfn)(struct tty *, struct tty_ctx *), struct tty_ctx *ctx) +{ + struct window_pane *wp = ctx->wp; + struct client *c; + u_int i; + + if (wp == NULL) + return; + + if (wp->window->flags & WINDOW_REDRAW || wp->flags & PANE_REDRAW) + return; + if (wp->window->flags & WINDOW_HIDDEN || !window_pane_visible(wp)) + return; + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c == NULL || c->session == NULL) + continue; + if (c->flags & CLIENT_SUSPENDED) + continue; + + if (c->session->curw->window == wp->window) { + if (c->tty.flags & TTY_FREEZE || c->tty.term == NULL) + continue; + tty_update_mode(&c->tty, c->tty.mode & ~MODE_CURSOR); + cmdfn(&c->tty, ctx); + } + } +} + void tty_cmd_insertcharacter(struct tty *tty, struct tty_ctx *ctx) { From f7df0bac96bffd0f737d4e72578e1287061e42a4 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 22 Jul 2009 21:23:29 +0000 Subject: [PATCH 0164/1180] Tidy the target parsing code a bit and correct the behaviour so that as before a string with no colon as a target window is first looked up as a window then as a session, noted by Iain Morgan. Also attempt to clarify the description of the target specification in the man page. --- cmd.c | 142 ++++++++++++++++++++++++++++++++++++--------------------- tmux.1 | 42 ++++++++--------- 2 files changed, 110 insertions(+), 74 deletions(-) diff --git a/cmd.c b/cmd.c index 30553287..2bf4d46a 100644 --- a/cmd.c +++ b/cmd.c @@ -107,6 +107,7 @@ struct session *cmd_newest_session(void); struct client *cmd_lookup_client(const char *); struct session *cmd_lookup_session(const char *, int *); struct winlink *cmd_lookup_window(struct session *, const char *, int *); +int cmd_lookup_index(struct session *, const char *, int *); struct cmd * cmd_parse(int argc, char **argv, char **cause) @@ -447,14 +448,15 @@ cmd_lookup_session(const char *name, int *ambiguous) } /* - * Lookup a window or return -1 if not found or ambigious. First try as an index - * and if invalid, use fnmatch or leading prefix. + * Lookup a window or return -1 if not found or ambigious. First try as an + * index and if invalid, use fnmatch or leading prefix. Return NULL but fill in + * idx if the window index is a valid number but there is now window with that + * index. */ struct winlink * cmd_lookup_window(struct session *s, const char *name, int *ambiguous) { struct winlink *wl, *wlfound; - struct window *w; const char *errstr; u_int idx; @@ -470,8 +472,7 @@ cmd_lookup_window(struct session *s, const char *name, int *ambiguous) /* Look for exact matches, error if more than one. */ wlfound = NULL; RB_FOREACH(wl, winlinks, &s->windows) { - w = wl->window; - if (strcmp(name, w->name) == 0) { + if (strcmp(name, wl->window->name) == 0) { if (wlfound != NULL) { *ambiguous = 1; return (NULL); @@ -485,9 +486,8 @@ cmd_lookup_window(struct session *s, const char *name, int *ambiguous) /* Now look for pattern matches, again error if multiple. */ wlfound = NULL; RB_FOREACH(wl, winlinks, &s->windows) { - w = wl->window; - if (strncmp(name, w->name, strlen(name)) == 0 || - fnmatch(name, w->name, 0) == 0) { + if (strncmp(name, wl->window->name, strlen(name)) == 0 || + fnmatch(name, wl->window->name, 0) == 0) { if (wlfound != NULL) { *ambiguous = 1; return (NULL); @@ -501,6 +501,29 @@ cmd_lookup_window(struct session *s, const char *name, int *ambiguous) return (NULL); } +/* + * Find a window index - if the window doesn't exist, check if it is a + * potential index and return it anyway. + */ +int +cmd_lookup_index(struct session *s, const char *name, int *ambiguous) +{ + struct winlink *wl; + const char *errstr; + u_int idx; + + if ((wl = cmd_lookup_window(s, name, ambiguous)) != NULL) + return (wl->idx); + if (*ambiguous) + return (-1); + + idx = strtonum(name, 0, INT_MAX, &errstr); + if (errstr == NULL) + return (idx); + + return (-1); +} + /* Find the target session or report an error and return NULL. */ struct session * cmd_find_session(struct cmd_ctx *ctx, const char *arg) @@ -570,21 +593,17 @@ cmd_find_window(struct cmd_ctx *ctx, const char *arg, struct session **sp) if (*arg == '\0') goto not_found; - /* Find the separating colon. If none, assume the current session. */ + /* Find the separating colon and split into window and session. */ winptr = strchr(arg, ':'); if (winptr == NULL) - winptr = xstrdup(arg); - else { - winptr++; /* skip : */ - sessptr = xstrdup(arg); - *strchr(sessptr, ':') = '\0'; - } - - log_debug("%s: winptr=%s, sessptr=%s", __func__, winptr, sessptr); + goto no_colon; + winptr++; /* skip : */ + sessptr = xstrdup(arg); + *strchr(sessptr, ':') = '\0'; /* Try to lookup the session if present. */ - if (sessptr != NULL && *sessptr != '\0') { - if ((s = cmd_lookup_session(sessptr, &ambiguous)) == NULL) + if (*sessptr != '\0') { + if ((s = cmd_lookup_session(sessptr, &ambiguous)) == NULL) goto no_session; } if (sp != NULL) @@ -594,7 +613,7 @@ cmd_find_window(struct cmd_ctx *ctx, const char *arg, struct session **sp) * Then work out the window. An empty string is the current window, * otherwise try to look it up in the session. */ - if (winptr == NULL || *winptr == '\0') + if (*winptr == '\0') wl = s->curw; else if ((wl = cmd_lookup_window(s, winptr, &ambiguous)) == NULL) goto not_found; @@ -603,11 +622,26 @@ cmd_find_window(struct cmd_ctx *ctx, const char *arg, struct session **sp) xfree(sessptr); return (wl); +no_colon: + /* No colon in the string, first try as a window then as a session. */ + if ((wl = cmd_lookup_window(s, arg, &ambiguous)) == NULL) { + if (ambiguous) + goto not_found; + if ((s = cmd_lookup_session(arg, &ambiguous)) == NULL) + goto no_session; + wl = s->curw; + } + + if (sp != NULL) + *sp = s; + + return (wl); + no_session: if (ambiguous) - ctx->error(ctx, "multiple sessions: %s", sessptr); + ctx->error(ctx, "multiple sessions: %s", arg); else - ctx->error(ctx, "session not found: %s", sessptr); + ctx->error(ctx, "session not found: %s", arg); if (sessptr != NULL) xfree(sessptr); return (NULL); @@ -625,15 +659,14 @@ not_found: /* * Find the target session and window index, whether or not it exists in the * session. Return -2 on error or -1 if no window index is specified. This is - * used when parsing an argument for a window target that may not be exist (for - * example it is going to be created). + * used when parsing an argument for a window target that may not exist (for + * example if it is going to be created). */ int cmd_find_index(struct cmd_ctx *ctx, const char *arg, struct session **sp) { struct session *s; - struct winlink *wl; - const char *winptr, *errstr; + const char *winptr; char *sessptr = NULL; int idx, ambiguous = 0; @@ -660,53 +693,56 @@ cmd_find_index(struct cmd_ctx *ctx, const char *arg, struct session **sp) /* Find the separating colon. If none, assume the current session. */ winptr = strchr(arg, ':'); if (winptr == NULL) - winptr = xstrdup(arg); - else { - winptr++; /* skip : */ - sessptr = xstrdup(arg); - *strchr(sessptr, ':') = '\0'; - } - - log_debug("%s: winptr=%s, sessptr=%s", __func__, winptr, sessptr); + goto no_colon; + winptr++; /* skip : */ + sessptr = xstrdup(arg); + *strchr(sessptr, ':') = '\0'; /* Try to lookup the session if present. */ if (sessptr != NULL && *sessptr != '\0') { - if ((s = cmd_lookup_session(sessptr, &ambiguous)) == NULL) + if ((s = cmd_lookup_session(sessptr, &ambiguous)) == NULL) goto no_session; } if (sp != NULL) *sp = s; /* - * Then work out the window. No : means "no window" (-1), an empty - * string is the current window, otherwise try to look it up in the - * session. + * Then work out the window. An empty string is a new window otherwise + * try to look it up in the session. */ - if (winptr == NULL) - idx = -1; - else if (*winptr == '\0') - idx = s->curw->idx; - else if ((wl = cmd_lookup_window(s, winptr, &ambiguous)) == NULL) { + if (*winptr == '\0') + idx = -1; + else if ((idx = cmd_lookup_index(s, winptr, &ambiguous)) == -1) { if (ambiguous) goto not_found; - /* Don't care it doesn't exist if this is a valid index. */ - idx = strtonum(winptr, 0, INT_MAX, &errstr); - if (errstr != NULL) { - ctx->error(ctx, "index %s: %s", errstr, winptr); - idx = -2; - } - } else - idx = wl->idx; + ctx->error(ctx, "invalid index: %s", arg); + idx = -2; + } if (sessptr != NULL) xfree(sessptr); return (idx); +no_colon: + /* No colon in the string, first try as a window then as a session. */ + if ((idx = cmd_lookup_index(s, arg, &ambiguous)) == -1) { + if (ambiguous) + goto not_found; + if ((s = cmd_lookup_session(arg, &ambiguous)) == NULL) + goto no_session; + idx = -1; + } + + if (sp != NULL) + *sp = s; + + return (idx); + no_session: if (ambiguous) - ctx->error(ctx, "multiple sessions: %s", sessptr); + ctx->error(ctx, "multiple sessions: %s", arg); else - ctx->error(ctx, "session not found: %s", sessptr); + ctx->error(ctx, "session not found: %s", arg); if (sessptr != NULL) xfree(sessptr); return (-2); diff --git a/tmux.1 b/tmux.1 index 7e67e782..8146b6a1 100644 --- a/tmux.1 +++ b/tmux.1 @@ -544,36 +544,36 @@ is a prefix or for which it matches as an .Xr fnmatch 3 pattern. If a single match is found, it is used as the target session; multiple matches -produce an error +produce an error. If a session is omitted, the current session is used if available; if no current session is available, the most recently created is chosen. .Pp .Ar target-window specifies a window in the form -.Em session Ns \&: Ns Em window , -where -.Em window -is a window index, for example mysession:1, or a window name, -.Xr fnmatch 3 -pattern, or prefix, such as mysession:mywin[0-3]. -If the latter, the window is looked up in a similar fashion to session name -searches described above. -The session is in the same form as for -.Ar target-session . -.Em session , -.Em index -or both may be omitted. -If +.Em session Ns \&: Ns Em window . .Em session -is omitted, the same rules as for -.Ar target-session -are followed; if +follows the same rules as for +.Ar target-session , +and .Em window -is not present, the current window for the given session is used. +is looked for in order: as a window index, for example mysession:1; as an exact +window name, such as mysession:mywindow; then as an +.Xr fnmatch 3 +pattern or the start of a window name, such as mysession:mywin* or +mysession:mywin. +An empty window name specifies the next unused index if appropriate (for +example the +.Ic new-window +and +.Ic link-window +commands) +otherwise the current window in +.Em session +is chosen. When the argument does not contain a colon, .Nm -first attempts to parse it as window index; if that fails, an attempt is made -to match a session or client name. +first attempts to parse it as window; if that fails, an attempt is made to +match a session. .Pp Multiple commands may be specified together as part of a .Em command sequence . From 5ee84436c8bd77800fc2c04a8c5b20442078cde0 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 22 Jul 2009 21:34:36 +0000 Subject: [PATCH 0165/1180] window_add_pane cannot fail, so remove the unused cause argument and don't bother to check for a NULL return. --- cmd-split-window.c | 4 +--- tmux.h | 2 +- window.c | 7 ++----- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/cmd-split-window.c b/cmd-split-window.c index f1b21d51..f7519cb7 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -184,9 +184,7 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) if (data->flag_horizontal) type = LAYOUT_LEFTRIGHT; - wp = window_add_pane(w, hlimit, &cause); - if (wp == NULL) - goto error; + wp = window_add_pane(w, hlimit); if (window_pane_spawn(wp, cmd, cwd, env, &cause) != 0) goto error; if (layout_split_pane(w->active, type, size, wp) != 0) { diff --git a/tmux.h b/tmux.h index 70c5a4b8..4e970535 100644 --- a/tmux.h +++ b/tmux.h @@ -1469,7 +1469,7 @@ struct window *window_create(const char *, const char *, const char *, const char **, u_int, u_int, u_int, char **); void window_destroy(struct window *); void window_set_active_pane(struct window *, struct window_pane *); -struct window_pane *window_add_pane(struct window *, u_int, char **); +struct window_pane *window_add_pane(struct window *, u_int); void window_resize(struct window *, u_int, u_int); void window_remove_pane(struct window *, struct window_pane *); struct window_pane *window_pane_at_index(struct window *, u_int); diff --git a/window.c b/window.c index 5af60da3..bc6906a8 100644 --- a/window.c +++ b/window.c @@ -260,10 +260,7 @@ window_create(const char *name, const char *cmd, const char *cwd, struct window_pane *wp; w = window_create1(sx, sy); - if ((wp = window_add_pane(w, hlimit, cause)) == NULL) { - window_destroy(w); - return (NULL); - } + wp = window_add_pane(w, hlimit); layout_init(w); if (window_pane_spawn(wp, cmd, cwd, envp, cause) != 0) { window_destroy(w); @@ -322,7 +319,7 @@ window_set_active_pane(struct window *w, struct window_pane *wp) } struct window_pane * -window_add_pane(struct window *w, u_int hlimit, unused char **cause) +window_add_pane(struct window *w, u_int hlimit) { struct window_pane *wp; From bb14c36a27d308281af32dfa2e2f9b25d9755537 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 22 Jul 2009 21:58:56 +0000 Subject: [PATCH 0166/1180] Pass a set of flags into client_init rather than just a start_server variable. Only one flag now but more to come later. --- client.c | 6 +++--- tmux.c | 9 ++++----- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/client.c b/client.c index a017e7a7..5ad15321 100644 --- a/client.c +++ b/client.c @@ -36,7 +36,7 @@ void client_handle_winch(struct client_ctx *); int -client_init(char *path, struct client_ctx *cctx, int start_server, int flags) +client_init(char *path, struct client_ctx *cctx, int cmdflags, int flags) { struct sockaddr_un sa; struct stat sb; @@ -53,7 +53,7 @@ client_init(char *path, struct client_ctx *cctx, int start_server, int flags) setproctitle("client (%s)", rpathbuf); if (lstat(path, &sb) != 0) { - if (start_server && errno == ENOENT) { + if (cmdflags & CMD_STARTSERVER && errno == ENOENT) { if ((cctx->srv_fd = server_start(path)) == -1) goto start_failed; goto server_started; @@ -79,7 +79,7 @@ client_init(char *path, struct client_ctx *cctx, int start_server, int flags) if (connect( cctx->srv_fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1) { if (errno == ECONNREFUSED) { - if (unlink(path) != 0 || !start_server) + if (unlink(path) != 0 || !(cmdflags & CMD_STARTSERVER)) goto not_found; if ((cctx->srv_fd = server_start(path)) == -1) goto start_failed; diff --git a/tmux.c b/tmux.c index 9ca1783f..2a155d57 100644 --- a/tmux.c +++ b/tmux.c @@ -213,7 +213,7 @@ main(int argc, char **argv) struct passwd *pw; char *s, *path, *label, *cause, *home, *pass = NULL; char cwd[MAXPATHLEN]; - int retcode, opt, flags, unlock, start_server; + int retcode, opt, flags, unlock, cmdflags = 0; unlock = flags = 0; label = path = NULL; @@ -390,7 +390,7 @@ main(int argc, char **argv) cmdlist = NULL; if ((pass = getpass("Password: ")) == NULL) exit(1); - start_server = 0; + cmdflags &= ~CMD_STARTSERVER; } else { if (argc == 0) { cmd = xmalloc(sizeof *cmd); @@ -407,17 +407,16 @@ main(int argc, char **argv) exit(1); } } - start_server = 0; TAILQ_FOREACH(cmd, cmdlist, qentry) { if (cmd->entry->flags & CMD_STARTSERVER) { - start_server = 1; + cmdflags |= CMD_STARTSERVER; break; } } } memset(&cctx, 0, sizeof cctx); - if (client_init(path, &cctx, start_server, flags) != 0) + if (client_init(path, &cctx, cmdflags, flags) != 0) exit(1); xfree(path); From 05b511f96aeede18a6cc9b7e1e1edb4bb4f70dd7 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 22 Jul 2009 22:47:43 +0000 Subject: [PATCH 0167/1180] If there is a current session, use its default path and working directory for the initial window when creating a new session. --- cmd-new-session.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/cmd-new-session.c b/cmd-new-session.c index 53e752ac..b7dd95cb 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -112,6 +112,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) { struct cmd_new_session_data *data = self->data; struct session *s; + struct options *oo; char *cmd, *cwd, *cause; u_int sx, sy; @@ -149,6 +150,14 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) } } + /* + * If the called from inside, use the source session for the default + * path and command. + */ + oo = &global_s_options; + if (ctx->cmdclient == NULL) + oo = &ctx->curclient->session->options; + /* Find new session size and options. */ if (data->flag_detached) { sx = 80; @@ -162,7 +171,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) sy = ctx->curclient->tty.sy; } } - if (sy > 0 && options_get_number(&global_s_options, "status")) + if (sy > 0 && options_get_number(oo, "status")) sy--; if (sx == 0) sx = 1; @@ -171,11 +180,11 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) if (ctx->cmdclient != NULL && ctx->cmdclient->cwd != NULL) cwd = ctx->cmdclient->cwd; else - cwd = options_get_string(&global_s_options, "default-path"); + cwd = options_get_string(oo, "default-path"); if (data->cmd != NULL) cmd = data->cmd; else - cmd = options_get_string(&global_s_options, "default-command"); + cmd = options_get_string(oo, "default-command"); /* Create the new session. */ s = session_create(data->newname, cmd, cwd, sx, sy, &cause); From 96a7cf1e6a133979eca4d1a8bf0e3bc3887a886d Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 23 Jul 2009 12:33:48 +0000 Subject: [PATCH 0168/1180] Both of cmdclient and curclient CAN be NULL - if the command is executed from the configuration file. In this case, attach-session can't do much, and new-session should just assume -d. --- cmd-attach-session.c | 3 +++ cmd-new-session.c | 23 ++++++++++++++++------- tmux.h | 3 ++- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/cmd-attach-session.c b/cmd-attach-session.c index aae8abe7..2d930560 100644 --- a/cmd-attach-session.c +++ b/cmd-attach-session.c @@ -55,6 +55,9 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx) if ((s = cmd_find_session(ctx, data->target)) == NULL) return (-1); + if (ctx->cmdclient == NULL && ctx->curclient == NULL) + return (0); + if (ctx->cmdclient == NULL) { if (data->chflags & CMD_CHFLAG('d')) { /* diff --git a/cmd-new-session.c b/cmd-new-session.c index b7dd95cb..7e9fc936 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -114,6 +114,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) struct session *s; struct options *oo; char *cmd, *cwd, *cause; + int detached; u_int sx, sy; if (data->newname != NULL && session_find(data->newname) != NULL) { @@ -122,7 +123,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) } /* - * There are two cases: + * There are three cases: * * 1. If cmdclient is non-NULL, new-session has been called from the * command-line - cmdclient is to become a new attached, interactive @@ -132,12 +133,20 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) * 2. If cmdclient is NULL, new-session has been called from an * existing client (such as a key binding). * - * In both cases, a new additional session needs to be created and + * 3. Both are NULL, the command was in the configuration file. Treat + * this as if -d was given even if it was not. + * + * In all cases, a new additional session needs to be created and * (unless -d) set as the current session for the client. */ + /* Set -d if no client. */ + detached = data->flag_detached; + if (ctx->cmdclient == NULL && ctx->curclient == NULL) + detached = 1; + /* Open the terminal if necessary. */ - if (!data->flag_detached && ctx->cmdclient != NULL) { + if (!detached && ctx->cmdclient != NULL) { if (!(ctx->cmdclient->flags & CLIENT_TERMINAL)) { ctx->error(ctx, "not a terminal"); return (-1); @@ -155,11 +164,11 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) * path and command. */ oo = &global_s_options; - if (ctx->cmdclient == NULL) + if (ctx->cmdclient == NULL && ctx->curclient != NULL) oo = &ctx->curclient->session->options; /* Find new session size and options. */ - if (data->flag_detached) { + if (detached) { sx = 80; sy = 25; } else { @@ -207,14 +216,14 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) * to exit. */ if (ctx->cmdclient != NULL) { - if (!data->flag_detached) + if (!detached) server_write_client(ctx->cmdclient, MSG_READY, NULL, 0); else server_write_client(ctx->cmdclient, MSG_EXIT, NULL, 0); } /* Set the client to the new session. */ - if (!data->flag_detached) { + if (!detached) { if (ctx->cmdclient != NULL) { ctx->cmdclient->session = s; server_redraw_client(ctx->cmdclient); diff --git a/tmux.h b/tmux.h index 4e970535..455bb2ac 100644 --- a/tmux.h +++ b/tmux.h @@ -862,7 +862,8 @@ struct cmd_ctx { * cmdclient is the client which sent the MSG_COMMAND to the server, if * any. This is NULL unless the command came from the command-line. * - * One of curclient or cmdclient is always NULL and the other not. + * cmdclient and curclient may both be NULL if the command is in the + * configuration file. */ struct client *curclient; struct session *cursession; From e0d1954840ef3d355e12b5b6973fff7dfe44c428 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 23 Jul 2009 13:44:02 +0000 Subject: [PATCH 0169/1180] C-d is delete as well in emacs mode. --- mode-key.c | 1 + 1 file changed, 1 insertion(+) diff --git a/mode-key.c b/mode-key.c index 508760bd..9db6d86c 100644 --- a/mode-key.c +++ b/mode-key.c @@ -153,6 +153,7 @@ mode_key_lookup_emacs(struct mode_key_data *mdata, int key) case '\010': case '\177': return (MODEKEYCMD_BACKSPACE); + case '\004': case KEYC_DC: return (MODEKEYCMD_DELETE); case '\011': From 895171478f61879448351160700b44e7ade6ef4b Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 23 Jul 2009 15:47:56 +0000 Subject: [PATCH 0170/1180] Revert r1.5, I don't like it, new sessions should start off identically - with the defaults. --- cmd-new-session.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/cmd-new-session.c b/cmd-new-session.c index 7e9fc936..f988c065 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -112,7 +112,6 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) { struct cmd_new_session_data *data = self->data; struct session *s; - struct options *oo; char *cmd, *cwd, *cause; int detached; u_int sx, sy; @@ -159,14 +158,6 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) } } - /* - * If the called from inside, use the source session for the default - * path and command. - */ - oo = &global_s_options; - if (ctx->cmdclient == NULL && ctx->curclient != NULL) - oo = &ctx->curclient->session->options; - /* Find new session size and options. */ if (detached) { sx = 80; @@ -180,7 +171,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) sy = ctx->curclient->tty.sy; } } - if (sy > 0 && options_get_number(oo, "status")) + if (sy > 0 && options_get_number(&global_s_options, "status")) sy--; if (sx == 0) sx = 1; @@ -189,11 +180,11 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) if (ctx->cmdclient != NULL && ctx->cmdclient->cwd != NULL) cwd = ctx->cmdclient->cwd; else - cwd = options_get_string(oo, "default-path"); + cwd = options_get_string(&global_s_options, "default-path"); if (data->cmd != NULL) cmd = data->cmd; else - cmd = options_get_string(oo, "default-command"); + cmd = options_get_string(&global_s_options, "default-command"); /* Create the new session. */ s = session_create(data->newname, cmd, cwd, sx, sy, &cause); From ba84ddcf8e64beac0838bbc4097ef1417e85916f Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 23 Jul 2009 17:03:47 +0000 Subject: [PATCH 0171/1180] Redraw after starting selection to correctly remove any existing selection. --- window-copy.c | 1 + 1 file changed, 1 insertion(+) diff --git a/window-copy.c b/window-copy.c index 04f22a8a..aa3e670c 100644 --- a/window-copy.c +++ b/window-copy.c @@ -194,6 +194,7 @@ window_copy_key(struct window_pane *wp, struct client *c, int key) break; case MODEKEYCMD_STARTSELECTION: window_copy_start_selection(wp); + window_copy_redraw_screen(wp); break; case MODEKEYCMD_CLEARSELECTION: screen_clear_selection(&data->screen); From 16e017d5a65b68f226835cd200ae3f252b08ed15 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 23 Jul 2009 20:24:27 +0000 Subject: [PATCH 0172/1180] Tidy client message return slightly: convert flags into an enum, and merge error string into struct client_ctx as well. --- client-msg.c | 54 ++++++++++++++++++++++++---------------------------- client.c | 33 +++++++++++++++----------------- tmux.h | 13 ++++++++----- 3 files changed, 48 insertions(+), 52 deletions(-) diff --git a/client-msg.c b/client-msg.c index 7d7166ca..5a95ff62 100644 --- a/client-msg.c +++ b/client-msg.c @@ -25,16 +25,16 @@ #include "tmux.h" -int client_msg_fn_detach(struct hdr *, struct client_ctx *, char **); -int client_msg_fn_error(struct hdr *, struct client_ctx *, char **); -int client_msg_fn_shutdown(struct hdr *, struct client_ctx *, char **); -int client_msg_fn_exit(struct hdr *, struct client_ctx *, char **); -int client_msg_fn_exited(struct hdr *, struct client_ctx *, char **); -int client_msg_fn_suspend(struct hdr *, struct client_ctx *, char **); +int client_msg_fn_detach(struct hdr *, struct client_ctx *); +int client_msg_fn_error(struct hdr *, struct client_ctx *); +int client_msg_fn_shutdown(struct hdr *, struct client_ctx *); +int client_msg_fn_exit(struct hdr *, struct client_ctx *); +int client_msg_fn_exited(struct hdr *, struct client_ctx *); +int client_msg_fn_suspend(struct hdr *, struct client_ctx *); struct client_msg { enum hdrtype type; - int (*fn)(struct hdr *, struct client_ctx *, char **); + int (*fn)(struct hdr *, struct client_ctx *); }; struct client_msg client_msg_table[] = { { MSG_DETACH, client_msg_fn_detach }, @@ -46,7 +46,7 @@ struct client_msg client_msg_table[] = { }; int -client_msg_dispatch(struct client_ctx *cctx, char **error) +client_msg_dispatch(struct client_ctx *cctx) { struct hdr hdr; struct client_msg *msg; @@ -61,70 +61,67 @@ client_msg_dispatch(struct client_ctx *cctx, char **error) for (i = 0; i < nitems(client_msg_table); i++) { msg = client_msg_table + i; - if (msg->type == hdr.type) { - if (msg->fn(&hdr, cctx, error) != 0) - return (-1); - return (0); - } + if (msg->type == hdr.type) + return (msg->fn(&hdr, cctx)); } fatalx("unexpected message"); } int -client_msg_fn_error(struct hdr *hdr, struct client_ctx *cctx, char **error) +client_msg_fn_error(struct hdr *hdr, struct client_ctx *cctx) { + char *errstr; + if (hdr->size == SIZE_MAX) fatalx("bad MSG_ERROR size"); - *error = xmalloc(hdr->size + 1); - buffer_read(cctx->srv_in, *error, hdr->size); - (*error)[hdr->size] = '\0'; + errstr = xmalloc(hdr->size + 1); + buffer_read(cctx->srv_in, errstr, hdr->size); + errstr[hdr->size] = '\0'; + cctx->errstr = errstr; return (-1); } int -client_msg_fn_detach( - struct hdr *hdr, struct client_ctx *cctx, unused char **error) +client_msg_fn_detach(struct hdr *hdr, struct client_ctx *cctx) { if (hdr->size != 0) fatalx("bad MSG_DETACH size"); client_write_server(cctx, MSG_EXITING, NULL, 0); - cctx->flags |= CCTX_DETACH; + cctx->exittype = CCTX_DETACH; return (0); } int client_msg_fn_shutdown( - struct hdr *hdr, struct client_ctx *cctx, unused char **error) + struct hdr *hdr, struct client_ctx *cctx) { if (hdr->size != 0) fatalx("bad MSG_SHUTDOWN size"); client_write_server(cctx, MSG_EXITING, NULL, 0); - cctx->flags |= CCTX_SHUTDOWN; + cctx->exittype = CCTX_SHUTDOWN; return (0); } int -client_msg_fn_exit( - struct hdr *hdr, struct client_ctx *cctx, unused char **error) +client_msg_fn_exit(struct hdr *hdr, struct client_ctx *cctx) { if (hdr->size != 0) fatalx("bad MSG_EXIT size"); client_write_server(cctx, MSG_EXITING, NULL, 0); - cctx->flags |= CCTX_EXIT; + cctx->exittype = CCTX_EXIT; return (0); } int -client_msg_fn_exited( - struct hdr *hdr, unused struct client_ctx *cctx, unused char **error) +client_msg_fn_exited(struct hdr *hdr, unused struct client_ctx *cctx) { if (hdr->size != 0) fatalx("bad MSG_EXITED size"); @@ -133,8 +130,7 @@ client_msg_fn_exited( } int -client_msg_fn_suspend( - struct hdr *hdr, unused struct client_ctx *cctx, unused char **error) +client_msg_fn_suspend(struct hdr *hdr, unused struct client_ctx *cctx) { struct sigaction act; diff --git a/client.c b/client.c index 5ad15321..9bd731a8 100644 --- a/client.c +++ b/client.c @@ -155,7 +155,7 @@ client_main(struct client_ctx *cctx) sigcont = 0; } - switch (client_msg_dispatch(cctx, &error)) { + switch (client_msg_dispatch(cctx)) { case -1: goto out; case 0: @@ -179,8 +179,10 @@ client_main(struct client_ctx *cctx) fatal("poll failed"); } - if (buffer_poll(&pfd, cctx->srv_in, cctx->srv_out) != 0) - goto server_dead; + if (buffer_poll(&pfd, cctx->srv_in, cctx->srv_out) != 0) { + cctx->exittype = CCTX_DIED; + break; + } } out: @@ -188,28 +190,23 @@ out: printf("[terminated]\n"); return (1); } - - if (cctx->flags & CCTX_SHUTDOWN) { + switch (cctx->exittype) { + case CCTX_DIED: + printf("[lost server]\n"); + return (0); + case CCTX_SHUTDOWN: printf("[server exited]\n"); return (0); - } - - if (cctx->flags & CCTX_EXIT) { + case CCTX_EXIT: printf("[exited]\n"); return (0); - } - - if (cctx->flags & CCTX_DETACH) { + case CCTX_DETACH: printf("[detached]\n"); return (0); + default: + printf("[error: %s]\n", cctx->errstr); + return (1); } - - printf("[error: %s]\n", error); - return (1); - -server_dead: - printf("[lost server]\n"); - return (0); } void diff --git a/tmux.h b/tmux.h index 455bb2ac..e57b607c 100644 --- a/tmux.h +++ b/tmux.h @@ -845,10 +845,13 @@ struct client_ctx { struct buffer *srv_in; struct buffer *srv_out; -#define CCTX_DETACH 0x1 -#define CCTX_EXIT 0x2 -#define CCTX_SHUTDOWN 0x4 - int flags; + enum { + CCTX_DETACH, + CCTX_EXIT, + CCTX_DIED, + CCTX_SHUTDOWN, + } exittype; + const char *errstr; }; /* Key/command line command. */ @@ -1261,7 +1264,7 @@ int client_init(char *, struct client_ctx *, int, int); int client_main(struct client_ctx *); /* client-msg.c */ -int client_msg_dispatch(struct client_ctx *, char **); +int client_msg_dispatch(struct client_ctx *); /* client-fn.c */ void client_write_server(struct client_ctx *, enum hdrtype, void *, size_t); From 4a04b498dbc460d69a0c98fd054cfaf2708e0996 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 23 Jul 2009 21:19:11 +0000 Subject: [PATCH 0173/1180] None of the server message functions return anything but 0, so make them all void. Also remove a leftover variable in client.c. --- client.c | 2 -- server-msg.c | 45 ++++++++++++++++----------------------------- 2 files changed, 16 insertions(+), 31 deletions(-) diff --git a/client.c b/client.c index 9bd731a8..57fe1d1d 100644 --- a/client.c +++ b/client.c @@ -134,14 +134,12 @@ int client_main(struct client_ctx *cctx) { struct pollfd pfd; - char *error; int xtimeout; /* Yay for ncurses namespace! */ siginit(); logfile("client"); - error = NULL; while (!sigterm) { if (sigchld) { waitpid(WAIT_ANY, NULL, WNOHANG); diff --git a/server-msg.c b/server-msg.c index 9f33fad3..31e986f8 100644 --- a/server-msg.c +++ b/server-msg.c @@ -26,12 +26,12 @@ #include "tmux.h" -int server_msg_fn_command(struct hdr *, struct client *); -int server_msg_fn_identify(struct hdr *, struct client *); -int server_msg_fn_resize(struct hdr *, struct client *); -int server_msg_fn_exiting(struct hdr *, struct client *); -int server_msg_fn_unlock(struct hdr *, struct client *); -int server_msg_fn_wakeup(struct hdr *, struct client *); +void server_msg_fn_command(struct hdr *, struct client *); +void server_msg_fn_identify(struct hdr *, struct client *); +void server_msg_fn_resize(struct hdr *, struct client *); +void server_msg_fn_exiting(struct hdr *, struct client *); +void server_msg_fn_unlock(struct hdr *, struct client *); +void server_msg_fn_wakeup(struct hdr *, struct client *); void printflike2 server_msg_fn_command_error( struct cmd_ctx *, const char *, ...); @@ -42,7 +42,7 @@ void printflike2 server_msg_fn_command_info( struct server_msg { enum hdrtype type; - int (*fn)(struct hdr *, struct client *); + void (*fn)(struct hdr *, struct client *); }; const struct server_msg server_msg_table[] = { { MSG_IDENTIFY, server_msg_fn_identify }, @@ -59,7 +59,6 @@ server_msg_dispatch(struct client *c) struct hdr hdr; const struct server_msg *msg; u_int i; - int n; for (;;) { if (BUFFER_USED(c->in) < sizeof hdr) @@ -72,8 +71,7 @@ server_msg_dispatch(struct client *c) for (i = 0; i < nitems(server_msg_table); i++) { msg = server_msg_table + i; if (msg->type == hdr.type) { - if ((n = msg->fn(&hdr, c)) != 0) - return (n); + msg->fn(&hdr, c); break; } } @@ -127,7 +125,7 @@ server_msg_fn_command_info(struct cmd_ctx *ctx, const char *fmt, ...) xfree(msg); } -int +void server_msg_fn_command(struct hdr *hdr, struct client *c) { struct msg_command_data data; @@ -160,7 +158,7 @@ server_msg_fn_command(struct hdr *hdr, struct client *c) "unset $TMUX to force"); cmd_list_free(cmdlist); server_write_client(c, MSG_EXIT, NULL, 0); - return (0); + return; } } } @@ -168,10 +166,9 @@ server_msg_fn_command(struct hdr *hdr, struct client *c) if (cmd_list_exec(cmdlist, &ctx) != 1) server_write_client(c, MSG_EXIT, NULL, 0); cmd_list_free(cmdlist); - return (0); } -int +void server_msg_fn_identify(struct hdr *hdr, struct client *c) { struct msg_identify_data data; @@ -190,7 +187,7 @@ server_msg_fn_identify(struct hdr *hdr, struct client *c) server_write_client(c, MSG_ERROR, MSG, (sizeof MSG) - 1); #undef MSG server_write_client(c, MSG_EXIT, NULL, 0); - return (0); + return; } c->tty.sx = data.sx; @@ -216,11 +213,9 @@ server_msg_fn_identify(struct hdr *hdr, struct client *c) xfree(term); c->flags |= CLIENT_TERMINAL; - - return (0); } -int +void server_msg_fn_resize(struct hdr *hdr, struct client *c) { struct msg_resize_data data; @@ -247,11 +242,9 @@ server_msg_fn_resize(struct hdr *hdr, struct client *c) /* Always redraw this client. */ server_redraw_client(c); - - return (0); } -int +void server_msg_fn_exiting(struct hdr *hdr, struct client *c) { if (hdr->size != 0) @@ -264,11 +257,9 @@ server_msg_fn_exiting(struct hdr *hdr, struct client *c) tty_close(&c->tty, c->flags & CLIENT_SUSPENDED); server_write_client(c, MSG_EXITED, NULL, 0); - - return (0); } -int +void server_msg_fn_unlock(struct hdr *hdr, struct client *c) { char *pass; @@ -289,11 +280,9 @@ server_msg_fn_unlock(struct hdr *hdr, struct client *c) memset(pass, 0, strlen(pass)); xfree(pass); - - return (0); } -int +void server_msg_fn_wakeup(struct hdr *hdr, struct client *c) { if (hdr->size != 0) @@ -304,6 +293,4 @@ server_msg_fn_wakeup(struct hdr *hdr, struct client *c) c->flags &= ~CLIENT_SUSPENDED; tty_start_tty(&c->tty); server_redraw_client(c); - - return (0); } From ce4eb6559e1aabb67e08a367a7c5e049e800c7ed Mon Sep 17 00:00:00 2001 From: Stuart Henderson Date: Fri, 24 Jul 2009 14:50:24 +0000 Subject: [PATCH 0174/1180] up-pane and down-pane no longer auto-repeat; update the description of repeat-time accordingly. ok nicm@ if you prefer old behaviour; bind -r Up up-pane bind -r Down down-pane --- tmux.1 | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tmux.1 b/tmux.1 index 8146b6a1..1d70e88f 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1225,9 +1225,7 @@ Whether a key repeats may be set when it is bound using the flag to .Ic bind-key . Repeat is enabled for the default keys of the -.Ic up-pane , -.Ic down-pane , -.Ic resize-pane-up , +.Ic resize-pane-up and .Ic resize-pane-down commands. From 5a1a1066371328f9d53a9bc5e5c4c53acb26c2b2 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 24 Jul 2009 14:52:47 +0000 Subject: [PATCH 0175/1180] Permit commands to be bound to key presses without the prefix key first. The new -n flag to bind-key and unbind-key sets or removes these bindings, and list-key shows them in []s. --- cmd-bind-key.c | 11 ++++++++--- cmd-list-keys.c | 18 ++++++++++++------ cmd-unbind-key.c | 11 ++++++++--- key-bindings.c | 16 ++++++++++++++-- server.c | 11 ++++++++--- tmux.1 | 19 ++++++++++++++++++- tmux.h | 14 ++++++++------ 7 files changed, 76 insertions(+), 24 deletions(-) diff --git a/cmd-bind-key.c b/cmd-bind-key.c index 14a93831..82ab14b0 100644 --- a/cmd-bind-key.c +++ b/cmd-bind-key.c @@ -39,7 +39,7 @@ struct cmd_bind_key_data { const struct cmd_entry cmd_bind_key_entry = { "bind-key", "bind", - "[-r] key command [arguments]", + "[-nr] key command [arguments]", 0, 0, NULL, cmd_bind_key_parse, @@ -54,14 +54,17 @@ int cmd_bind_key_parse(struct cmd *self, int argc, char **argv, char **cause) { struct cmd_bind_key_data *data; - int opt; + int opt, no_prefix = 0; self->data = data = xmalloc(sizeof *data); data->can_repeat = 0; data->cmdlist = NULL; - while ((opt = getopt(argc, argv, "r")) != -1) { + while ((opt = getopt(argc, argv, "nr")) != -1) { switch (opt) { + case 'n': + no_prefix = 1; + break; case 'r': data->can_repeat = 1; break; @@ -78,6 +81,8 @@ cmd_bind_key_parse(struct cmd *self, int argc, char **argv, char **cause) xasprintf(cause, "unknown key: %s", argv[0]); goto error; } + if (!no_prefix) + data->key |= KEYC_PREFIX; argc--; argv++; diff --git a/cmd-list-keys.c b/cmd-list-keys.c index af3a0208..717812d9 100644 --- a/cmd-list-keys.c +++ b/cmd-list-keys.c @@ -46,27 +46,33 @@ cmd_list_keys_exec(unused struct cmd *self, struct cmd_ctx *ctx) { struct key_binding *bd; const char *key; - char tmp[BUFSIZ]; - int width, keywidth; + char tmp[BUFSIZ], keytmp[64]; + int width, keywidth; width = 0; SPLAY_FOREACH(bd, key_bindings, &key_bindings) { - if ((key = key_string_lookup_key(bd->key)) == NULL) + key = key_string_lookup_key(bd->key & ~KEYC_PREFIX); + if (key == NULL) continue; keywidth = strlen(key) + 1; + if (!(bd->key & KEYC_PREFIX)) + keywidth += 2; if (keywidth > width) width = keywidth; } - SPLAY_FOREACH(bd, key_bindings, &key_bindings) { - if ((key = key_string_lookup_key(bd->key)) == NULL) + key = key_string_lookup_key(bd->key & ~KEYC_PREFIX); + if (key == NULL) continue; *tmp = '\0'; cmd_list_print(bd->cmdlist, tmp, sizeof tmp); - + if (!(bd->key & KEYC_PREFIX)) { + xsnprintf(keytmp, sizeof keytmp, "[%s]", key); + key = keytmp; + } ctx->print(ctx, "%*s: %s", width, key, tmp); } diff --git a/cmd-unbind-key.c b/cmd-unbind-key.c index 7272bc77..0100e5a9 100644 --- a/cmd-unbind-key.c +++ b/cmd-unbind-key.c @@ -36,7 +36,7 @@ struct cmd_unbind_key_data { const struct cmd_entry cmd_unbind_key_entry = { "unbind-key", "unbind", - "key", + "[-n] key", 0, 0, NULL, cmd_unbind_key_parse, @@ -51,12 +51,15 @@ int cmd_unbind_key_parse(struct cmd *self, int argc, char **argv, char **cause) { struct cmd_unbind_key_data *data; - int opt; + int opt, no_prefix = 0; self->data = data = xmalloc(sizeof *data); - while ((opt = getopt(argc, argv, "")) != -1) { + while ((opt = getopt(argc, argv, "n")) != -1) { switch (opt) { + case 'n': + no_prefix = 1; + break; default: goto usage; } @@ -70,6 +73,8 @@ cmd_unbind_key_parse(struct cmd *self, int argc, char **argv, char **cause) xasprintf(cause, "unknown key: %s", argv[0]); goto error; } + if (!no_prefix) + data->key |= KEYC_PREFIX; return (0); diff --git a/key-bindings.c b/key-bindings.c index d37e23b3..186c1a9b 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -32,7 +32,18 @@ struct key_bindings dead_key_bindings; int key_bindings_cmp(struct key_binding *bd1, struct key_binding *bd2) { - return (bd1->key - bd2->key); + int key1, key2; + + key1 = bd1->key & ~KEYC_PREFIX; + key2 = bd2->key & ~KEYC_PREFIX; + if (key1 != key2) + return (key1 - key2); + + if (bd1->key & KEYC_PREFIX && !(bd2->key & KEYC_PREFIX)) + return (-1); + if (bd2->key & KEYC_PREFIX && !(bd1->key & KEYC_PREFIX)) + return (1); + return (0); } struct key_binding * @@ -170,7 +181,8 @@ key_bindings_init(void) cmd->entry->init(cmd, table[i].key); TAILQ_INSERT_HEAD(cmdlist, cmd, qentry); - key_bindings_add(table[i].key, table[i].can_repeat, cmdlist); + key_bindings_add( + table[i].key | KEYC_PREFIX, table[i].can_repeat, cmdlist); } } diff --git a/server.c b/server.c index 8012e900..ce793076 100644 --- a/server.c +++ b/server.c @@ -802,14 +802,19 @@ server_handle_client(struct client *c) if (!(c->flags & CLIENT_PREFIX)) { if (key == prefix) c->flags |= CLIENT_PREFIX; - else - window_pane_key(wp, c, key); + else { + /* Try as a non-prefix key binding. */ + if ((bd = key_bindings_lookup(key)) == NULL) + window_pane_key(wp, c, key); + else + key_bindings_dispatch(bd, c); + } continue; } /* Prefix key already pressed. Reset prefix and lookup key. */ c->flags &= ~CLIENT_PREFIX; - if ((bd = key_bindings_lookup(key)) == NULL) { + if ((bd = key_bindings_lookup(key | KEYC_PREFIX)) == NULL) { /* If repeating, treat this as a key, else ignore. */ if (c->flags & CLIENT_REPEAT) { c->flags &= ~CLIENT_REPEAT; diff --git a/tmux.1 b/tmux.1 index 1d70e88f..54e46a3d 100644 --- a/tmux.1 +++ b/tmux.1 @@ -617,7 +617,7 @@ If no server is started, will attempt to start it; this will fail unless sessions are created in the configuration file. .It Xo Ic bind-key -.Op Fl r +.Op Fl nr .Ar key Ar command Op Ar arguments .Xc .D1 (alias: Ic bind ) @@ -632,6 +632,13 @@ or for Ctrl keys, or .Ql M- for Alt (meta) keys. +If +.Fl n +is specified, it is not necessary to use the prefix key, +.Ar command +is bound to +.Ar key +alone. The .Fl r flag indicates this key may repeat, see the @@ -842,6 +849,10 @@ List the syntax of all commands supported by .Xc .D1 (alias: Ic lsk ) List all key bindings. +Keys bound without the prefix key (see +.Ic bind-key +.Fl n ) +are enclosed in square brackets. .It Xo Ic list-sessions .Xc .D1 (alias: Ic ls ) @@ -1613,11 +1624,17 @@ Switch the current session for client to .Ar target-session . .It Xo Ic unbind-key +.Op Fl n .Ar key .Xc .D1 (alias: Ic unbind ) Unbind the command bound to .Ar key . +If +.Fl n +is specified, the command bound to +.Ar key +without a prefix (if any) is removed. .It Xo Ic unlink-window .Op Fl k .Op Fl t Ar target-window diff --git a/tmux.h b/tmux.h index e57b607c..2eeb9f5d 100644 --- a/tmux.h +++ b/tmux.h @@ -102,10 +102,12 @@ struct buffer { #define BELL_CURRENT 2 /* Key codes. ncurses defines KEY_*. Grrr. */ -#define KEYC_NONE 0x0fff -#define KEYC_ESCAPE 0x2000 -#define KEYC_CTRL 0x4000 -#define KEYC_SHIFT 0x8000 +#define KEYC_NONE 0xfff +/* 0x1000 is base for special keys */ +#define KEYC_ESCAPE 0x2000 +#define KEYC_CTRL 0x4000 +#define KEYC_SHIFT 0x8000 +#define KEYC_PREFIX 0x10000 enum key_code { /* Mouse key. */ @@ -856,8 +858,6 @@ struct client_ctx { /* Key/command line command. */ struct cmd_ctx { - struct client *cmdclient; - /* * curclient is the client where this command was executed if inside * tmux. This is NULL if the command came from the command-line. @@ -869,6 +869,8 @@ struct cmd_ctx { * configuration file. */ struct client *curclient; + struct client *cmdclient; + struct session *cursession; struct msg_command_data *msgdata; From 1d1ea681f0b132b1dd60fc5f640a4420c76bca32 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 24 Jul 2009 14:57:22 +0000 Subject: [PATCH 0176/1180] Accept lowercase c- and m- prefix as well as C- and M-. --- key-string.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/key-string.c b/key-string.c index d70fe69b..23aa6ad7 100644 --- a/key-string.c +++ b/key-string.c @@ -108,7 +108,7 @@ key_string_lookup_string(const char *string) return (string[0]); ptr = NULL; - if (string[0] == 'C' && string[1] == '-') + if ((string[0] == 'C' || string[0] == 'c') && string[1] == '-') ptr = string + 2; else if (string[0] == '^') ptr = string + 1; @@ -129,8 +129,8 @@ key_string_lookup_string(const char *string) return (key | KEYC_CTRL); return (KEYC_NONE); } - - if (string[0] == 'M' && string[1] == '-') { + + if ((string[0] == 'M' || string[0] == 'm') && string[1] == '-') { ptr = string + 2; if (ptr[0] == '\0') return (KEYC_NONE); From 029599c02c23e5be84c21aabda1114ee0dc47c91 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 24 Jul 2009 16:21:42 +0000 Subject: [PATCH 0177/1180] Simplify screen redrawing by drawing the border and background together rather than border separately, and consolidating all the drawing characters into one string. --- screen-redraw.c | 100 +++++++++++++----------------------------------- 1 file changed, 26 insertions(+), 74 deletions(-) diff --git a/screen-redraw.c b/screen-redraw.c index e63f8725..baecb613 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -24,6 +24,13 @@ int screen_redraw_check_cell(struct client *, u_int, u_int); +#define CELL_INSIDE 0 +#define CELL_LEFT 1 +#define CELL_RIGHT 2 +#define CELL_TOP 3 +#define CELL_BOTTOM 4 +#define CELL_OUTSIDE 5 + /* Check if cell inside a pane. */ int screen_redraw_check_cell(struct client *c, u_int px, u_int py) @@ -32,7 +39,7 @@ screen_redraw_check_cell(struct client *c, u_int px, u_int py) struct window_pane *wp; if (px > w->sx || py > w->sy) - return (0); + return (CELL_OUTSIDE); TAILQ_FOREACH(wp, &w->panes, entry) { if (!window_pane_visible(wp)) @@ -41,26 +48,26 @@ screen_redraw_check_cell(struct client *c, u_int px, u_int py) /* Inside pane. */ if (px >= wp->xoff && px < wp->xoff + wp->sx && py >= wp->yoff && py < wp->yoff + wp->sy) - return (1); + return (CELL_INSIDE); /* Left/right borders. */ if (py >= wp->yoff && py < wp->yoff + wp->sy) { if (wp->xoff != 0 && px == wp->xoff - 1) - return (1); + return (CELL_LEFT); if (px == wp->xoff + wp->sx) - return (1); + return (CELL_RIGHT); } /* Top/bottom borders. */ if (px >= wp->xoff && px < wp->xoff + wp->sx) { if (wp->yoff != 0 && py == wp->yoff - 1) - return (1); + return (CELL_TOP); if (py == wp->yoff + wp->sy) - return (1); + return (CELL_BOTTOM); } } - return (0); + return (CELL_OUTSIDE); } /* Redraw entire screen. */ @@ -70,9 +77,9 @@ screen_redraw_screen(struct client *c, int status_only) struct window *w = c->session->curw->window; struct tty *tty = &c->tty; struct window_pane *wp; - u_int i, j, sx, sy; - int status, has_acs; - u_char choriz, cvert, cbackg; + u_int i, j, type; + int status; + const u_char *border; /* Get status line, er, status. */ if (c->message_string != NULL || c->prompt_string != NULL) @@ -86,85 +93,30 @@ screen_redraw_screen(struct client *c, int status_only) return; } - /* Work out ACS characters. */ - if (tty_term_has(tty->term, TTYC_ACSC)) { - has_acs = 1; - choriz = tty_get_acs(tty, 'q'); - cvert = tty_get_acs(tty, 'x'); - cbackg = tty_get_acs(tty, '~'); - } else { - has_acs = 0; - choriz = '-'; - cvert = '|'; - cbackg = '.'; - } - - /* Clear the screen. */ + /* Draw background and borders. */ tty_reset(tty); - if (has_acs) + if (tty_term_has(tty->term, TTYC_ACSC)) { + border = " xxqq~"; tty_putcode(tty, TTYC_SMACS); + } else + border = " ||--."; for (j = 0; j < tty->sy - status; j++) { if (status_only && j != tty->sy - 1) continue; for (i = 0; i < tty->sx; i++) { - if (!screen_redraw_check_cell(c, i, j)) { + type = screen_redraw_check_cell(c, i, j); + if (type != CELL_INSIDE) { tty_cursor(tty, i, j, 0, 0); - tty_putc(tty, cbackg); + tty_putc(tty, border[type]); } } } - if (has_acs) - tty_putcode(tty, TTYC_RMACS); + tty_putcode(tty, TTYC_RMACS); /* Draw the panes. */ TAILQ_FOREACH(wp, &w->panes, entry) { if (!window_pane_visible(wp)) continue; - - tty_reset(tty); - - sx = wp->sx; - sy = wp->sy; - - /* Draw left and right borders. */ - if (has_acs) - tty_putcode(tty, TTYC_SMACS); - if (wp->xoff > 0) { - for (i = wp->yoff; i < wp->yoff + sy; i++) { - if (status_only && i != tty->sy - 1) - continue; - tty_cursor(tty, wp->xoff - 1, i, 0, 0); - tty_putc(tty, cvert); - } - } - if (wp->xoff + sx < tty->sx) { - for (i = wp->yoff; i < wp->yoff + sy; i++) { - if (status_only && i != tty->sy - 1) - continue; - tty_cursor(tty, wp->xoff + sx, i, 0, 0); - tty_putc(&c->tty, cvert); - } - } - - /* Draw top and bottom borders. */ - if (wp->yoff > 0) { - if (!status_only || wp->yoff - 1 == tty->sy - 1) { - tty_cursor(tty, wp->xoff, wp->yoff - 1, 0, 0); - for (i = 0; i < sx; i++) - tty_putc(tty, choriz); - } - } - if (wp->yoff + sy < tty->sy - status) { - if (!status_only || wp->yoff + sy == tty->sy - 1) { - tty_cursor(tty, wp->xoff, wp->yoff + sy, 0, 0); - for (i = 0; i < sx; i++) - tty_putc(tty, choriz); - } - } - if (has_acs) - tty_putcode(tty, TTYC_RMACS); - - /* Draw the pane. */ for (i = 0; i < wp->sy; i++) { if (status_only && wp->yoff + i != tty->sy - 1) continue; From c6dac5c3c96ecbc43abc3de16bdcb6569141c379 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 24 Jul 2009 18:46:40 +0000 Subject: [PATCH 0178/1180] cmd_find_index should return -2 on error. --- cmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd.c b/cmd.c index 2bf4d46a..b13d0cc4 100644 --- a/cmd.c +++ b/cmd.c @@ -676,7 +676,7 @@ cmd_find_index(struct cmd_ctx *ctx, const char *arg, struct session **sp) */ if ((s = cmd_current_session(ctx)) == NULL) { ctx->error(ctx, "can't establish current session"); - return (-1); + return (-2); } /* A NULL argument means the current session and "no window" (-1). */ From 133173850c4e9986e27d5d1733b4771e209d0015 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 24 Jul 2009 19:14:38 +0000 Subject: [PATCH 0179/1180] Use the full range of ACS line drawing characters to draw pane borders, including intersections. --- screen-redraw.c | 128 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 105 insertions(+), 23 deletions(-) diff --git a/screen-redraw.c b/screen-redraw.c index baecb613..f3c718a9 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -22,14 +22,61 @@ #include "tmux.h" +int screen_redraw_cell_border(struct client *, u_int, u_int); int screen_redraw_check_cell(struct client *, u_int, u_int); #define CELL_INSIDE 0 -#define CELL_LEFT 1 -#define CELL_RIGHT 2 -#define CELL_TOP 3 -#define CELL_BOTTOM 4 -#define CELL_OUTSIDE 5 +#define CELL_LEFTRIGHT 1 +#define CELL_TOPBOTTOM 2 +#define CELL_TOPLEFT 3 +#define CELL_TOPRIGHT 4 +#define CELL_BOTTOMLEFT 5 +#define CELL_BOTTOMRIGHT 6 +#define CELL_TOPJOIN 7 +#define CELL_BOTTOMJOIN 8 +#define CELL_LEFTJOIN 9 +#define CELL_RIGHTJOIN 10 +#define CELL_JOIN 11 +#define CELL_OUTSIDE 12 + +/* Check if a cell is on the pane border. */ +int +screen_redraw_cell_border(struct client *c, u_int px, u_int py) +{ + struct window *w = c->session->curw->window; + struct window_pane *wp; + + /* Check all the panes. */ + TAILQ_FOREACH(wp, &w->panes, entry) { + if (!window_pane_visible(wp)) + continue; + + /* Inside pane. */ + if (px >= wp->xoff && px < wp->xoff + wp->sx && + py >= wp->yoff && py < wp->yoff + wp->sy) + return (0); + + /* Left/right borders. */ + if ((wp->yoff == 0 || py >= wp->yoff - 1) && + py <= wp->yoff + wp->sy) { + if (wp->xoff != 0 && px == wp->xoff - 1) + return (1); + if (px == wp->xoff + wp->sx) + return (1); + } + + /* Top/bottom borders. */ + if ((wp->xoff == 0 || px >= wp->xoff - 1) && + px <= wp->xoff + wp->sx) { + if (wp->yoff != 0 && py == wp->yoff - 1) + return (1); + if (py == wp->yoff + wp->sy) + return (1); + } + } + + return (0); +} /* Check if cell inside a pane. */ int @@ -37,6 +84,7 @@ screen_redraw_check_cell(struct client *c, u_int px, u_int py) { struct window *w = c->session->curw->window; struct window_pane *wp; + int borders; if (px > w->sx || py > w->sy) return (CELL_OUTSIDE); @@ -45,25 +93,59 @@ screen_redraw_check_cell(struct client *c, u_int px, u_int py) if (!window_pane_visible(wp)) continue; - /* Inside pane. */ - if (px >= wp->xoff && px < wp->xoff + wp->sx && - py >= wp->yoff && py < wp->yoff + wp->sy) + /* If outside the pane and its border, skip it. */ + if ((wp->xoff != 0 && px < wp->xoff - 1) || + px > wp->xoff + wp->sx || + (wp->yoff != 0 && py < wp->yoff - 1) || + py > wp->yoff + wp->sy) + continue; + + /* If definitely inside, return so. */ + if (!screen_redraw_cell_border(c, px, py)) return (CELL_INSIDE); - /* Left/right borders. */ - if (py >= wp->yoff && py < wp->yoff + wp->sy) { - if (wp->xoff != 0 && px == wp->xoff - 1) - return (CELL_LEFT); - if (px == wp->xoff + wp->sx) - return (CELL_RIGHT); - } + /* + * Construct a bitmask of whether the cells to the left (bit + * 4), right, top, and bottom (bit 1) of this cell are borders. + */ + borders = 0; + if (px == 0 || screen_redraw_cell_border(c, px - 1, py)) + borders |= 8; + if (px <= w->sx && screen_redraw_cell_border(c, px + 1, py)) + borders |= 4; + if (py == 0 || screen_redraw_cell_border(c, px, py - 1)) + borders |= 2; + if (py <= w->sy && screen_redraw_cell_border(c, px, py + 1)) + borders |= 1; - /* Top/bottom borders. */ - if (px >= wp->xoff && px < wp->xoff + wp->sx) { - if (wp->yoff != 0 && py == wp->yoff - 1) - return (CELL_TOP); - if (py == wp->yoff + wp->sy) - return (CELL_BOTTOM); + /* + * Figure out what kind of border this cell is. Only one bit + * set doesn't make sense (can't have a border cell with no + * others connected). + */ + switch (borders) { + case 15: /* 1111, left right top bottom */ + return (CELL_JOIN); + case 14: /* 1110, left right top */ + return (CELL_BOTTOMJOIN); + case 13: /* 1101, left right bottom */ + return (CELL_TOPJOIN); + case 12: /* 1100, left right */ + return (CELL_TOPBOTTOM); + case 11: /* 1011, left top bottom */ + return (CELL_RIGHTJOIN); + case 10: /* 1010, left top */ + return (CELL_BOTTOMRIGHT); + case 9: /* 1001, left bottom */ + return (CELL_TOPRIGHT); + case 7: /* 0111, right top bottom */ + return (CELL_LEFTJOIN); + case 6: /* 0110, right top */ + return (CELL_BOTTOMLEFT); + case 5: /* 0101, right bottom */ + return (CELL_TOPLEFT); + case 3: /* 0011, top bottom */ + return (CELL_LEFTRIGHT); } } @@ -96,10 +178,10 @@ screen_redraw_screen(struct client *c, int status_only) /* Draw background and borders. */ tty_reset(tty); if (tty_term_has(tty->term, TTYC_ACSC)) { - border = " xxqq~"; + border = " xqlkmjwvtun~"; tty_putcode(tty, TTYC_SMACS); } else - border = " ||--."; + border = " |-....--||+."; for (j = 0; j < tty->sy - status; j++) { if (status_only && j != tty->sy - 1) continue; From 2bb89bc5bce2f5ab59c4bec760f1151c4fb8b0a3 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 24 Jul 2009 19:35:33 +0000 Subject: [PATCH 0180/1180] Set the active pane when respawning a window - fixes problems when respawning a window with multiple panes. --- cmd-respawn-window.c | 1 + 1 file changed, 1 insertion(+) diff --git a/cmd-respawn-window.c b/cmd-respawn-window.c index 3a795461..6faf11d9 100644 --- a/cmd-respawn-window.c +++ b/cmd-respawn-window.c @@ -81,6 +81,7 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_ctx *ctx) } layout_init(w); screen_reinit(&wp->base); + window_set_active_pane(w, wp); recalculate_sizes(); server_redraw_window(w); From 34a82e7629073b8a6bb3474862d5f36b670338a3 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 26 Jul 2009 12:58:44 +0000 Subject: [PATCH 0181/1180] Make all messages sent between the client and server fixed size. This is the first of two changes to make the protocol more resilient and less sensitive to other changes in the code, particularly with commands. The client now packs argv into a buffer and sends it to the server for parsing, rather than doing it itself and sending the parsed command data. As a side-effect this also removes a lot of now-unused command marshalling code. Mixing a server without this change and a client with or vice versa will cause tmux to hang or crash, please ensure that tmux is entirely killed before upgrading. --- client-fn.c | 16 ----- client-msg.c | 13 ++-- client.c | 19 +++--- cmd-attach-session.c | 2 - cmd-bind-key.c | 23 ------- cmd-break-pane.c | 2 - cmd-choose-session.c | 2 - cmd-choose-window.c | 2 - cmd-clear-history.c | 2 - cmd-clock-mode.c | 2 - cmd-command-prompt.c | 2 - cmd-confirm-before.c | 2 - cmd-copy-buffer.c | 25 ------- cmd-copy-mode.c | 2 - cmd-delete-buffer.c | 2 - cmd-detach-client.c | 2 - cmd-display-message.c | 2 - cmd-down-pane.c | 2 - cmd-find-window.c | 2 - cmd-generic.c | 109 ----------------------------- cmd-has-session.c | 2 - cmd-if-shell.c | 25 ------- cmd-kill-pane.c | 2 - cmd-kill-server.c | 2 - cmd-kill-session.c | 2 - cmd-kill-window.c | 2 - cmd-last-window.c | 2 - cmd-link-window.c | 2 - cmd-list-buffers.c | 2 - cmd-list-clients.c | 2 - cmd-list-commands.c | 2 - cmd-list-keys.c | 2 - cmd-list-sessions.c | 2 - cmd-list-windows.c | 2 - cmd-list.c | 35 ---------- cmd-load-buffer.c | 2 - cmd-lock-server.c | 2 - cmd-move-window.c | 2 - cmd-new-session.c | 27 -------- cmd-new-window.c | 27 -------- cmd-next-layout.c | 2 - cmd-next-window.c | 2 - cmd-paste-buffer.c | 2 - cmd-previous-layout.c | 2 - cmd-previous-window.c | 2 - cmd-refresh-client.c | 2 - cmd-rename-session.c | 2 - cmd-rename-window.c | 2 - cmd-resize-pane.c | 2 - cmd-respawn-window.c | 2 - cmd-rotate-window.c | 2 - cmd-save-buffer.c | 2 - cmd-scroll-mode.c | 2 - cmd-select-layout.c | 2 - cmd-select-pane.c | 2 - cmd-select-prompt.c | 2 - cmd-select-window.c | 2 - cmd-send-keys.c | 26 ------- cmd-send-prefix.c | 2 - cmd-server-info.c | 2 - cmd-set-buffer.c | 2 - cmd-set-option.c | 2 - cmd-set-password.c | 23 ------- cmd-set-window-option.c | 2 - cmd-show-buffer.c | 2 - cmd-show-options.c | 2 - cmd-show-window-options.c | 2 - cmd-source-file.c | 23 ------- cmd-split-window.c | 25 ------- cmd-start-server.c | 2 - cmd-suspend-client.c | 2 - cmd-swap-pane.c | 23 ------- cmd-swap-window.c | 2 - cmd-switch-client.c | 25 ------- cmd-unbind-key.c | 21 ------ cmd-unlink-window.c | 2 - cmd-up-pane.c | 2 - cmd.c | 140 ++++++++++++++++---------------------- server-fn.c | 11 ++- server-msg.c | 93 ++++++++++++++----------- tmux.c | 126 ++++++++++++++++++++++------------ tmux.h | 58 +++++++++------- 82 files changed, 253 insertions(+), 780 deletions(-) diff --git a/client-fn.c b/client-fn.c index 3f42a105..b7a9b1f0 100644 --- a/client-fn.c +++ b/client-fn.c @@ -74,19 +74,3 @@ client_write_server( if (buf != NULL && len > 0) buffer_write(cctx->srv_out, buf, len); } - -void -client_write_server2(struct client_ctx *cctx, - enum hdrtype type, void *buf1, size_t len1, void *buf2, size_t len2) -{ - struct hdr hdr; - - hdr.type = type; - hdr.size = len1 + len2; - buffer_write(cctx->srv_out, &hdr, sizeof hdr); - - if (buf1 != NULL && len1 > 0) - buffer_write(cctx->srv_out, buf1, len1); - if (buf2 != NULL && len2 > 0) - buffer_write(cctx->srv_out, buf2, len2); -} diff --git a/client-msg.c b/client-msg.c index 5a95ff62..845f10b0 100644 --- a/client-msg.c +++ b/client-msg.c @@ -70,16 +70,15 @@ client_msg_dispatch(struct client_ctx *cctx) int client_msg_fn_error(struct hdr *hdr, struct client_ctx *cctx) { - char *errstr; + struct msg_print_data data; - if (hdr->size == SIZE_MAX) - fatalx("bad MSG_ERROR size"); + if (hdr->size < sizeof data) + fatalx("bad MSG_PRINT size"); + buffer_read(cctx->srv_in, &data, sizeof data); - errstr = xmalloc(hdr->size + 1); - buffer_read(cctx->srv_in, errstr, hdr->size); - errstr[hdr->size] = '\0'; + data.msg[(sizeof data.msg) - 1] = '\0'; + cctx->errstr = xstrdup(data.msg); - cctx->errstr = errstr; return (-1); } diff --git a/client.c b/client.c index 57fe1d1d..f29c2569 100644 --- a/client.c +++ b/client.c @@ -44,8 +44,7 @@ client_init(char *path, struct client_ctx *cctx, int cmdflags, int flags) struct winsize ws; size_t size; int mode; - struct buffer *b; - char *name; + char *name, *term; char rpathbuf[MAXPATHLEN]; if (realpath(path, rpathbuf) == NULL) @@ -103,20 +102,24 @@ server_started: data.flags = flags; data.sx = ws.ws_col; data.sy = ws.ws_row; - *data.tty = '\0'; + if (getcwd(data.cwd, sizeof data.cwd) == NULL) *data.cwd = '\0'; + *data.term = '\0'; + if ((term = getenv("TERM")) != NULL) { + if (strlcpy(data.term, + term, sizeof data.term) >= sizeof data.term) + *data.term = '\0'; + } + + *data.tty = '\0'; if ((name = ttyname(STDIN_FILENO)) == NULL) fatal("ttyname failed"); if (strlcpy(data.tty, name, sizeof data.tty) >= sizeof data.tty) fatalx("ttyname failed"); - b = buffer_create(BUFSIZ); - cmd_send_string(b, getenv("TERM")); - client_write_server2(cctx, MSG_IDENTIFY, - &data, sizeof data, BUFFER_OUT(b), BUFFER_USED(b)); - buffer_destroy(b); + client_write_server(cctx, MSG_IDENTIFY, &data, sizeof data); } return (0); diff --git a/cmd-attach-session.c b/cmd-attach-session.c index 2d930560..3278ea7f 100644 --- a/cmd-attach-session.c +++ b/cmd-attach-session.c @@ -33,8 +33,6 @@ const struct cmd_entry cmd_attach_session_entry = { cmd_target_init, cmd_target_parse, cmd_attach_session_exec, - cmd_target_send, - cmd_target_recv, cmd_target_free, cmd_target_print }; diff --git a/cmd-bind-key.c b/cmd-bind-key.c index 82ab14b0..41d8eeb8 100644 --- a/cmd-bind-key.c +++ b/cmd-bind-key.c @@ -26,8 +26,6 @@ int cmd_bind_key_parse(struct cmd *, int, char **, char **); int cmd_bind_key_exec(struct cmd *, struct cmd_ctx *); -void cmd_bind_key_send(struct cmd *, struct buffer *); -void cmd_bind_key_recv(struct cmd *, struct buffer *); void cmd_bind_key_free(struct cmd *); size_t cmd_bind_key_print(struct cmd *, char *, size_t); @@ -44,8 +42,6 @@ const struct cmd_entry cmd_bind_key_entry = { NULL, cmd_bind_key_parse, cmd_bind_key_exec, - cmd_bind_key_send, - cmd_bind_key_recv, cmd_bind_key_free, cmd_bind_key_print }; @@ -113,25 +109,6 @@ cmd_bind_key_exec(struct cmd *self, unused struct cmd_ctx *ctx) return (0); } -void -cmd_bind_key_send(struct cmd *self, struct buffer *b) -{ - struct cmd_bind_key_data *data = self->data; - - buffer_write(b, data, sizeof *data); - cmd_list_send(data->cmdlist, b); -} - -void -cmd_bind_key_recv(struct cmd *self, struct buffer *b) -{ - struct cmd_bind_key_data *data; - - self->data = data = xmalloc(sizeof *data); - buffer_read(b, data, sizeof *data); - data->cmdlist = cmd_list_recv(b); -} - void cmd_bind_key_free(struct cmd *self) { diff --git a/cmd-break-pane.c b/cmd-break-pane.c index 8eeb7f42..6a237c6d 100644 --- a/cmd-break-pane.c +++ b/cmd-break-pane.c @@ -35,8 +35,6 @@ const struct cmd_entry cmd_break_pane_entry = { cmd_pane_init, cmd_pane_parse, cmd_break_pane_exec, - cmd_pane_send, - cmd_pane_recv, cmd_pane_free, cmd_pane_print }; diff --git a/cmd-choose-session.c b/cmd-choose-session.c index 09c8216d..cf5e3c82 100644 --- a/cmd-choose-session.c +++ b/cmd-choose-session.c @@ -35,8 +35,6 @@ const struct cmd_entry cmd_choose_session_entry = { cmd_target_init, cmd_target_parse, cmd_choose_session_exec, - cmd_target_send, - cmd_target_recv, cmd_target_free, cmd_target_print }; diff --git a/cmd-choose-window.c b/cmd-choose-window.c index 80a2518e..9386c5fa 100644 --- a/cmd-choose-window.c +++ b/cmd-choose-window.c @@ -35,8 +35,6 @@ const struct cmd_entry cmd_choose_window_entry = { cmd_target_init, cmd_target_parse, cmd_choose_window_exec, - cmd_target_send, - cmd_target_recv, cmd_target_free, cmd_target_print }; diff --git a/cmd-clear-history.c b/cmd-clear-history.c index de24ac57..2e4c118d 100644 --- a/cmd-clear-history.c +++ b/cmd-clear-history.c @@ -33,8 +33,6 @@ const struct cmd_entry cmd_clear_history_entry = { cmd_pane_init, cmd_pane_parse, cmd_clear_history_exec, - cmd_pane_send, - cmd_pane_recv, cmd_pane_free, cmd_pane_print }; diff --git a/cmd-clock-mode.c b/cmd-clock-mode.c index 4399b7ba..0fc43a54 100644 --- a/cmd-clock-mode.c +++ b/cmd-clock-mode.c @@ -33,8 +33,6 @@ const struct cmd_entry cmd_clock_mode_entry = { cmd_target_init, cmd_target_parse, cmd_clock_mode_exec, - cmd_target_send, - cmd_target_recv, cmd_target_free, cmd_target_print }; diff --git a/cmd-command-prompt.c b/cmd-command-prompt.c index 872fa326..f729a66e 100644 --- a/cmd-command-prompt.c +++ b/cmd-command-prompt.c @@ -40,8 +40,6 @@ const struct cmd_entry cmd_command_prompt_entry = { cmd_command_prompt_init, cmd_target_parse, cmd_command_prompt_exec, - cmd_target_send, - cmd_target_recv, cmd_target_free, cmd_target_print }; diff --git a/cmd-confirm-before.c b/cmd-confirm-before.c index f1f5bfe1..db799a4b 100644 --- a/cmd-confirm-before.c +++ b/cmd-confirm-before.c @@ -38,8 +38,6 @@ const struct cmd_entry cmd_confirm_before_entry = { cmd_confirm_before_init, cmd_target_parse, cmd_confirm_before_exec, - cmd_target_send, - cmd_target_recv, cmd_target_free, cmd_target_print }; diff --git a/cmd-copy-buffer.c b/cmd-copy-buffer.c index 544cf1c6..7cef21ef 100644 --- a/cmd-copy-buffer.c +++ b/cmd-copy-buffer.c @@ -26,8 +26,6 @@ int cmd_copy_buffer_parse(struct cmd *, int, char **, char **); int cmd_copy_buffer_exec(struct cmd *, struct cmd_ctx *); -void cmd_copy_buffer_send(struct cmd *, struct buffer *); -void cmd_copy_buffer_recv(struct cmd *, struct buffer *); void cmd_copy_buffer_free(struct cmd *); void cmd_copy_buffer_init(struct cmd *, int); size_t cmd_copy_buffer_print(struct cmd *, char *, size_t); @@ -46,8 +44,6 @@ const struct cmd_entry cmd_copy_buffer_entry = { cmd_copy_buffer_init, cmd_copy_buffer_parse, cmd_copy_buffer_exec, - cmd_copy_buffer_send, - cmd_copy_buffer_recv, cmd_copy_buffer_free, cmd_copy_buffer_print }; @@ -160,27 +156,6 @@ cmd_copy_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) return (0); } -void -cmd_copy_buffer_send(struct cmd *self, struct buffer *b) -{ - struct cmd_copy_buffer_data *data = self->data; - - buffer_write(b, data, sizeof *data); - cmd_send_string(b, data->dst_session); - cmd_send_string(b, data->src_session); -} - -void -cmd_copy_buffer_recv(struct cmd *self, struct buffer *b) -{ - struct cmd_copy_buffer_data *data; - - self->data = data = xmalloc(sizeof *data); - buffer_read(b, data, sizeof *data); - data->dst_session = cmd_recv_string(b); - data->src_session = cmd_recv_string(b); -} - void cmd_copy_buffer_free(struct cmd *self) { diff --git a/cmd-copy-mode.c b/cmd-copy-mode.c index e9891179..3e6b2228 100644 --- a/cmd-copy-mode.c +++ b/cmd-copy-mode.c @@ -33,8 +33,6 @@ const struct cmd_entry cmd_copy_mode_entry = { cmd_target_init, cmd_target_parse, cmd_copy_mode_exec, - cmd_target_send, - cmd_target_recv, cmd_target_free, NULL }; diff --git a/cmd-delete-buffer.c b/cmd-delete-buffer.c index 81b69417..b193438c 100644 --- a/cmd-delete-buffer.c +++ b/cmd-delete-buffer.c @@ -35,8 +35,6 @@ const struct cmd_entry cmd_delete_buffer_entry = { cmd_buffer_init, cmd_buffer_parse, cmd_delete_buffer_exec, - cmd_buffer_send, - cmd_buffer_recv, cmd_buffer_free, cmd_buffer_print }; diff --git a/cmd-detach-client.c b/cmd-detach-client.c index 0a28cdc7..dd480226 100644 --- a/cmd-detach-client.c +++ b/cmd-detach-client.c @@ -33,8 +33,6 @@ const struct cmd_entry cmd_detach_client_entry = { cmd_target_init, cmd_target_parse, cmd_detach_client_exec, - cmd_target_send, - cmd_target_recv, cmd_target_free, cmd_target_print }; diff --git a/cmd-display-message.c b/cmd-display-message.c index 332b6e28..20758daa 100644 --- a/cmd-display-message.c +++ b/cmd-display-message.c @@ -35,8 +35,6 @@ const struct cmd_entry cmd_display_message_entry = { cmd_target_init, cmd_target_parse, cmd_display_message_exec, - cmd_target_send, - cmd_target_recv, cmd_target_free, cmd_target_print }; diff --git a/cmd-down-pane.c b/cmd-down-pane.c index c3c12dba..242c6ac3 100644 --- a/cmd-down-pane.c +++ b/cmd-down-pane.c @@ -33,8 +33,6 @@ const struct cmd_entry cmd_down_pane_entry = { cmd_target_init, cmd_target_parse, cmd_down_pane_exec, - cmd_target_send, - cmd_target_recv, cmd_target_free, cmd_target_print }; diff --git a/cmd-find-window.c b/cmd-find-window.c index 34ea75ec..0a1c38da 100644 --- a/cmd-find-window.c +++ b/cmd-find-window.c @@ -38,8 +38,6 @@ const struct cmd_entry cmd_find_window_entry = { cmd_target_init, cmd_target_parse, cmd_find_window_exec, - cmd_target_send, - cmd_target_recv, cmd_target_free, cmd_target_print }; diff --git a/cmd-generic.c b/cmd-generic.c index ea0d4d16..39c18d51 100644 --- a/cmd-generic.c +++ b/cmd-generic.c @@ -176,27 +176,6 @@ usage: return (-1); } -void -cmd_target_send(struct cmd *self, struct buffer *b) -{ - struct cmd_target_data *data = self->data; - - buffer_write(b, data, sizeof *data); - cmd_send_string(b, data->target); - cmd_send_string(b, data->arg); -} - -void -cmd_target_recv(struct cmd *self, struct buffer *b) -{ - struct cmd_target_data *data; - - self->data = data = xmalloc(sizeof *data); - buffer_read(b, data, sizeof *data); - data->target = cmd_recv_string(b); - data->arg = cmd_recv_string(b); -} - void cmd_target_free(struct cmd *self) { @@ -278,29 +257,6 @@ usage: return (-1); } -void -cmd_srcdst_send(struct cmd *self, struct buffer *b) -{ - struct cmd_srcdst_data *data = self->data; - - buffer_write(b, data, sizeof *data); - cmd_send_string(b, data->src); - cmd_send_string(b, data->dst); - cmd_send_string(b, data->arg); -} - -void -cmd_srcdst_recv(struct cmd *self, struct buffer *b) -{ - struct cmd_srcdst_data *data; - - self->data = data = xmalloc(sizeof *data); - buffer_read(b, data, sizeof *data); - data->src = cmd_recv_string(b); - data->dst = cmd_recv_string(b); - data->arg = cmd_recv_string(b); -} - void cmd_srcdst_free(struct cmd *self) { @@ -394,27 +350,6 @@ error: return (-1); } -void -cmd_buffer_send(struct cmd *self, struct buffer *b) -{ - struct cmd_buffer_data *data = self->data; - - buffer_write(b, data, sizeof *data); - cmd_send_string(b, data->target); - cmd_send_string(b, data->arg); -} - -void -cmd_buffer_recv(struct cmd *self, struct buffer *b) -{ - struct cmd_buffer_data *data; - - self->data = data = xmalloc(sizeof *data); - buffer_read(b, data, sizeof *data); - data->target = cmd_recv_string(b); - data->arg = cmd_recv_string(b); -} - void cmd_buffer_free(struct cmd *self) { @@ -500,29 +435,6 @@ usage: return (-1); } -void -cmd_option_send(struct cmd *self, struct buffer *b) -{ - struct cmd_option_data *data = self->data; - - buffer_write(b, data, sizeof *data); - cmd_send_string(b, data->target); - cmd_send_string(b, data->option); - cmd_send_string(b, data->value); -} - -void -cmd_option_recv(struct cmd *self, struct buffer *b) -{ - struct cmd_option_data *data; - - self->data = data = xmalloc(sizeof *data); - buffer_read(b, data, sizeof *data); - data->target = cmd_recv_string(b); - data->option = cmd_recv_string(b); - data->value = cmd_recv_string(b); -} - void cmd_option_free(struct cmd *self) { @@ -617,27 +529,6 @@ error: return (-1); } -void -cmd_pane_send(struct cmd *self, struct buffer *b) -{ - struct cmd_pane_data *data = self->data; - - buffer_write(b, data, sizeof *data); - cmd_send_string(b, data->target); - cmd_send_string(b, data->arg); -} - -void -cmd_pane_recv(struct cmd *self, struct buffer *b) -{ - struct cmd_pane_data *data; - - self->data = data = xmalloc(sizeof *data); - buffer_read(b, data, sizeof *data); - data->target = cmd_recv_string(b); - data->arg = cmd_recv_string(b); -} - void cmd_pane_free(struct cmd *self) { diff --git a/cmd-has-session.c b/cmd-has-session.c index 9999946b..f279a730 100644 --- a/cmd-has-session.c +++ b/cmd-has-session.c @@ -33,8 +33,6 @@ const struct cmd_entry cmd_has_session_entry = { cmd_target_init, cmd_target_parse, cmd_has_session_exec, - cmd_target_send, - cmd_target_recv, cmd_target_free, cmd_target_print }; diff --git a/cmd-if-shell.c b/cmd-if-shell.c index e73e8d5d..86502a7f 100644 --- a/cmd-if-shell.c +++ b/cmd-if-shell.c @@ -30,8 +30,6 @@ int cmd_if_shell_parse(struct cmd *, int, char **, char **); int cmd_if_shell_exec(struct cmd *, struct cmd_ctx *); -void cmd_if_shell_send(struct cmd *, struct buffer *); -void cmd_if_shell_recv(struct cmd *, struct buffer *); void cmd_if_shell_free(struct cmd *); void cmd_if_shell_init(struct cmd *, int); size_t cmd_if_shell_print(struct cmd *, char *, size_t); @@ -48,8 +46,6 @@ const struct cmd_entry cmd_if_shell_entry = { cmd_if_shell_init, cmd_if_shell_parse, cmd_if_shell_exec, - cmd_if_shell_send, - cmd_if_shell_recv, cmd_if_shell_free, cmd_if_shell_print }; @@ -126,27 +122,6 @@ cmd_if_shell_exec(struct cmd *self, struct cmd_ctx *ctx) return (0); } -void -cmd_if_shell_send(struct cmd *self, struct buffer *b) -{ - struct cmd_if_shell_data *data = self->data; - - buffer_write(b, data, sizeof *data); - cmd_send_string(b, data->cmd); - cmd_send_string(b, data->sh_cmd); -} - -void -cmd_if_shell_recv(struct cmd *self, struct buffer *b) -{ - struct cmd_if_shell_data *data; - - self->data = data = xmalloc(sizeof *data); - buffer_read(b, data, sizeof *data); - data->cmd = cmd_recv_string(b); - data->sh_cmd = cmd_recv_string(b); -} - void cmd_if_shell_free(struct cmd *self) { diff --git a/cmd-kill-pane.c b/cmd-kill-pane.c index d219f399..14b07c82 100644 --- a/cmd-kill-pane.c +++ b/cmd-kill-pane.c @@ -35,8 +35,6 @@ const struct cmd_entry cmd_kill_pane_entry = { cmd_pane_init, cmd_pane_parse, cmd_kill_pane_exec, - cmd_pane_send, - cmd_pane_recv, cmd_pane_free, cmd_pane_print }; diff --git a/cmd-kill-server.c b/cmd-kill-server.c index 0002a655..56aa47cf 100644 --- a/cmd-kill-server.c +++ b/cmd-kill-server.c @@ -37,8 +37,6 @@ const struct cmd_entry cmd_kill_server_entry = { NULL, cmd_kill_server_exec, NULL, - NULL, - NULL, NULL }; diff --git a/cmd-kill-session.c b/cmd-kill-session.c index 83eabca1..51a3edaf 100644 --- a/cmd-kill-session.c +++ b/cmd-kill-session.c @@ -36,8 +36,6 @@ const struct cmd_entry cmd_kill_session_entry = { cmd_target_init, cmd_target_parse, cmd_kill_session_exec, - cmd_target_send, - cmd_target_recv, cmd_target_free, cmd_target_print }; diff --git a/cmd-kill-window.c b/cmd-kill-window.c index 66d8be88..ed15fb33 100644 --- a/cmd-kill-window.c +++ b/cmd-kill-window.c @@ -33,8 +33,6 @@ const struct cmd_entry cmd_kill_window_entry = { cmd_target_init, cmd_target_parse, cmd_kill_window_exec, - cmd_target_send, - cmd_target_recv, cmd_target_free, cmd_target_print }; diff --git a/cmd-last-window.c b/cmd-last-window.c index 5ea2ad7e..0f7a4571 100644 --- a/cmd-last-window.c +++ b/cmd-last-window.c @@ -33,8 +33,6 @@ const struct cmd_entry cmd_last_window_entry = { cmd_target_init, cmd_target_parse, cmd_last_window_exec, - cmd_target_send, - cmd_target_recv, cmd_target_free, cmd_target_print }; diff --git a/cmd-link-window.c b/cmd-link-window.c index e4e05f11..742fb243 100644 --- a/cmd-link-window.c +++ b/cmd-link-window.c @@ -35,8 +35,6 @@ const struct cmd_entry cmd_link_window_entry = { cmd_srcdst_init, cmd_srcdst_parse, cmd_link_window_exec, - cmd_srcdst_send, - cmd_srcdst_recv, cmd_srcdst_free, cmd_srcdst_print }; diff --git a/cmd-list-buffers.c b/cmd-list-buffers.c index 6a57a723..2b5311ee 100644 --- a/cmd-list-buffers.c +++ b/cmd-list-buffers.c @@ -35,8 +35,6 @@ const struct cmd_entry cmd_list_buffers_entry = { cmd_target_init, cmd_target_parse, cmd_list_buffers_exec, - cmd_target_send, - cmd_target_recv, cmd_target_free, cmd_target_print }; diff --git a/cmd-list-clients.c b/cmd-list-clients.c index bec90530..905edf94 100644 --- a/cmd-list-clients.c +++ b/cmd-list-clients.c @@ -37,8 +37,6 @@ const struct cmd_entry cmd_list_clients_entry = { NULL, cmd_list_clients_exec, NULL, - NULL, - NULL, NULL }; diff --git a/cmd-list-commands.c b/cmd-list-commands.c index 9701a1bc..9f2942ae 100644 --- a/cmd-list-commands.c +++ b/cmd-list-commands.c @@ -34,8 +34,6 @@ const struct cmd_entry cmd_list_commands_entry = { NULL, cmd_list_commands_exec, NULL, - NULL, - NULL, NULL }; diff --git a/cmd-list-keys.c b/cmd-list-keys.c index 717812d9..9110d12a 100644 --- a/cmd-list-keys.c +++ b/cmd-list-keys.c @@ -36,8 +36,6 @@ const struct cmd_entry cmd_list_keys_entry = { NULL, cmd_list_keys_exec, NULL, - NULL, - NULL, NULL }; diff --git a/cmd-list-sessions.c b/cmd-list-sessions.c index 3dac0107..95c26567 100644 --- a/cmd-list-sessions.c +++ b/cmd-list-sessions.c @@ -36,8 +36,6 @@ const struct cmd_entry cmd_list_sessions_entry = { NULL, cmd_list_sessions_exec, NULL, - NULL, - NULL, NULL }; diff --git a/cmd-list-windows.c b/cmd-list-windows.c index 197d683f..2e4932c3 100644 --- a/cmd-list-windows.c +++ b/cmd-list-windows.c @@ -35,8 +35,6 @@ const struct cmd_entry cmd_list_windows_entry = { cmd_target_init, cmd_target_parse, cmd_list_windows_exec, - cmd_target_send, - cmd_target_recv, cmd_target_free, cmd_target_print }; diff --git a/cmd-list.c b/cmd-list.c index ffc8f1ee..16fe5921 100644 --- a/cmd-list.c +++ b/cmd-list.c @@ -86,41 +86,6 @@ cmd_list_exec(struct cmd_list *cmdlist, struct cmd_ctx *ctx) return (0); } -void -cmd_list_send(struct cmd_list *cmdlist, struct buffer *b) -{ - struct cmd *cmd; - u_int n; - - n = 0; - TAILQ_FOREACH(cmd, cmdlist, qentry) - n++; - - buffer_write(b, &n, sizeof n); - TAILQ_FOREACH(cmd, cmdlist, qentry) - cmd_send(cmd, b); -} - -struct cmd_list * -cmd_list_recv(struct buffer *b) -{ - struct cmd_list *cmdlist; - struct cmd *cmd; - u_int n; - - buffer_read(b, &n, sizeof n); - - cmdlist = xmalloc(sizeof *cmdlist); - TAILQ_INIT(cmdlist); - - while (n-- > 0) { - cmd = cmd_recv(b); - TAILQ_INSERT_TAIL(cmdlist, cmd, qentry); - } - - return (cmdlist); -} - void cmd_list_free(struct cmd_list *cmdlist) { diff --git a/cmd-load-buffer.c b/cmd-load-buffer.c index f2f2c08c..063cafa1 100644 --- a/cmd-load-buffer.c +++ b/cmd-load-buffer.c @@ -39,8 +39,6 @@ const struct cmd_entry cmd_load_buffer_entry = { cmd_buffer_init, cmd_buffer_parse, cmd_load_buffer_exec, - cmd_buffer_send, - cmd_buffer_recv, cmd_buffer_free, cmd_buffer_print }; diff --git a/cmd-lock-server.c b/cmd-lock-server.c index 5e0356e1..54f2efd2 100644 --- a/cmd-lock-server.c +++ b/cmd-lock-server.c @@ -39,8 +39,6 @@ const struct cmd_entry cmd_lock_server_entry = { cmd_lock_server_exec, NULL, NULL, - NULL, - NULL, }; int diff --git a/cmd-move-window.c b/cmd-move-window.c index 2a967cdf..f714c2cb 100644 --- a/cmd-move-window.c +++ b/cmd-move-window.c @@ -35,8 +35,6 @@ const struct cmd_entry cmd_move_window_entry = { cmd_srcdst_init, cmd_srcdst_parse, cmd_move_window_exec, - cmd_srcdst_send, - cmd_srcdst_recv, cmd_srcdst_free, cmd_srcdst_print }; diff --git a/cmd-new-session.c b/cmd-new-session.c index f988c065..ea2e5b12 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -26,8 +26,6 @@ int cmd_new_session_parse(struct cmd *, int, char **, char **); int cmd_new_session_exec(struct cmd *, struct cmd_ctx *); -void cmd_new_session_send(struct cmd *, struct buffer *); -void cmd_new_session_recv(struct cmd *, struct buffer *); void cmd_new_session_free(struct cmd *); void cmd_new_session_init(struct cmd *, int); size_t cmd_new_session_print(struct cmd *, char *, size_t); @@ -46,8 +44,6 @@ const struct cmd_entry cmd_new_session_entry = { cmd_new_session_init, cmd_new_session_parse, cmd_new_session_exec, - cmd_new_session_send, - cmd_new_session_recv, cmd_new_session_free, cmd_new_session_print }; @@ -228,29 +224,6 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) return (1); /* 1 means don't tell command client to exit */ } -void -cmd_new_session_send(struct cmd *self, struct buffer *b) -{ - struct cmd_new_session_data *data = self->data; - - buffer_write(b, data, sizeof *data); - cmd_send_string(b, data->newname); - cmd_send_string(b, data->winname); - cmd_send_string(b, data->cmd); -} - -void -cmd_new_session_recv(struct cmd *self, struct buffer *b) -{ - struct cmd_new_session_data *data; - - self->data = data = xmalloc(sizeof *data); - buffer_read(b, data, sizeof *data); - data->newname = cmd_recv_string(b); - data->winname = cmd_recv_string(b); - data->cmd = cmd_recv_string(b); -} - void cmd_new_session_free(struct cmd *self) { diff --git a/cmd-new-window.c b/cmd-new-window.c index e54bfc7d..2af6abf3 100644 --- a/cmd-new-window.c +++ b/cmd-new-window.c @@ -28,8 +28,6 @@ int cmd_new_window_parse(struct cmd *, int, char **, char **); int cmd_new_window_exec(struct cmd *, struct cmd_ctx *); -void cmd_new_window_send(struct cmd *, struct buffer *); -void cmd_new_window_recv(struct cmd *, struct buffer *); void cmd_new_window_free(struct cmd *); void cmd_new_window_init(struct cmd *, int); size_t cmd_new_window_print(struct cmd *, char *, size_t); @@ -49,8 +47,6 @@ const struct cmd_entry cmd_new_window_entry = { cmd_new_window_init, cmd_new_window_parse, cmd_new_window_exec, - cmd_new_window_send, - cmd_new_window_recv, cmd_new_window_free, cmd_new_window_print }; @@ -173,29 +169,6 @@ cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx) return (0); } -void -cmd_new_window_send(struct cmd *self, struct buffer *b) -{ - struct cmd_new_window_data *data = self->data; - - buffer_write(b, data, sizeof *data); - cmd_send_string(b, data->target); - cmd_send_string(b, data->name); - cmd_send_string(b, data->cmd); -} - -void -cmd_new_window_recv(struct cmd *self, struct buffer *b) -{ - struct cmd_new_window_data *data; - - self->data = data = xmalloc(sizeof *data); - buffer_read(b, data, sizeof *data); - data->target = cmd_recv_string(b); - data->name = cmd_recv_string(b); - data->cmd = cmd_recv_string(b); -} - void cmd_new_window_free(struct cmd *self) { diff --git a/cmd-next-layout.c b/cmd-next-layout.c index 088046fa..03459ffc 100644 --- a/cmd-next-layout.c +++ b/cmd-next-layout.c @@ -33,8 +33,6 @@ const struct cmd_entry cmd_next_layout_entry = { cmd_target_init, cmd_target_parse, cmd_next_layout_exec, - cmd_target_send, - cmd_target_recv, cmd_target_free, cmd_target_print }; diff --git a/cmd-next-window.c b/cmd-next-window.c index b7608f33..94c7b1ce 100644 --- a/cmd-next-window.c +++ b/cmd-next-window.c @@ -34,8 +34,6 @@ const struct cmd_entry cmd_next_window_entry = { cmd_next_window_init, cmd_target_parse, cmd_next_window_exec, - cmd_target_send, - cmd_target_recv, cmd_target_free, cmd_target_print }; diff --git a/cmd-paste-buffer.c b/cmd-paste-buffer.c index 76a92eaf..90deeb00 100644 --- a/cmd-paste-buffer.c +++ b/cmd-paste-buffer.c @@ -36,8 +36,6 @@ const struct cmd_entry cmd_paste_buffer_entry = { cmd_buffer_init, cmd_buffer_parse, cmd_paste_buffer_exec, - cmd_buffer_send, - cmd_buffer_recv, cmd_buffer_free, cmd_buffer_print }; diff --git a/cmd-previous-layout.c b/cmd-previous-layout.c index 44071eb5..dcdfdeae 100644 --- a/cmd-previous-layout.c +++ b/cmd-previous-layout.c @@ -33,8 +33,6 @@ const struct cmd_entry cmd_previous_layout_entry = { cmd_target_init, cmd_target_parse, cmd_previous_layout_exec, - cmd_target_send, - cmd_target_recv, cmd_target_free, cmd_target_print }; diff --git a/cmd-previous-window.c b/cmd-previous-window.c index 6b26704e..3aa1f6a3 100644 --- a/cmd-previous-window.c +++ b/cmd-previous-window.c @@ -34,8 +34,6 @@ const struct cmd_entry cmd_previous_window_entry = { cmd_previous_window_init, cmd_target_parse, cmd_previous_window_exec, - cmd_target_send, - cmd_target_recv, cmd_target_free, cmd_target_print }; diff --git a/cmd-refresh-client.c b/cmd-refresh-client.c index 9ff0ae8d..a3015f02 100644 --- a/cmd-refresh-client.c +++ b/cmd-refresh-client.c @@ -33,8 +33,6 @@ const struct cmd_entry cmd_refresh_client_entry = { cmd_target_init, cmd_target_parse, cmd_refresh_client_exec, - cmd_target_send, - cmd_target_recv, cmd_target_free, cmd_target_print }; diff --git a/cmd-rename-session.c b/cmd-rename-session.c index 7e5e81e6..ae798717 100644 --- a/cmd-rename-session.c +++ b/cmd-rename-session.c @@ -35,8 +35,6 @@ const struct cmd_entry cmd_rename_session_entry = { cmd_target_init, cmd_target_parse, cmd_rename_session_exec, - cmd_target_send, - cmd_target_recv, cmd_target_free, cmd_target_print }; diff --git a/cmd-rename-window.c b/cmd-rename-window.c index 9d314eb5..1037b25a 100644 --- a/cmd-rename-window.c +++ b/cmd-rename-window.c @@ -35,8 +35,6 @@ const struct cmd_entry cmd_rename_window_entry = { cmd_target_init, cmd_target_parse, cmd_rename_window_exec, - cmd_target_send, - cmd_target_recv, cmd_target_free, cmd_target_print }; diff --git a/cmd-resize-pane.c b/cmd-resize-pane.c index b0ea214c..f7928803 100644 --- a/cmd-resize-pane.c +++ b/cmd-resize-pane.c @@ -37,8 +37,6 @@ const struct cmd_entry cmd_resize_pane_entry = { cmd_resize_pane_init, cmd_pane_parse, cmd_resize_pane_exec, - cmd_pane_send, - cmd_pane_recv, cmd_pane_free, cmd_pane_print }; diff --git a/cmd-respawn-window.c b/cmd-respawn-window.c index 6faf11d9..70573929 100644 --- a/cmd-respawn-window.c +++ b/cmd-respawn-window.c @@ -35,8 +35,6 @@ const struct cmd_entry cmd_respawn_window_entry = { cmd_target_init, cmd_target_parse, cmd_respawn_window_exec, - cmd_target_send, - cmd_target_recv, cmd_target_free, cmd_target_print }; diff --git a/cmd-rotate-window.c b/cmd-rotate-window.c index c12345d6..71705a75 100644 --- a/cmd-rotate-window.c +++ b/cmd-rotate-window.c @@ -34,8 +34,6 @@ const struct cmd_entry cmd_rotate_window_entry = { cmd_rotate_window_init, cmd_target_parse, cmd_rotate_window_exec, - cmd_target_send, - cmd_target_recv, cmd_target_free, cmd_target_print }; diff --git a/cmd-save-buffer.c b/cmd-save-buffer.c index 1eef28c4..d48571dd 100644 --- a/cmd-save-buffer.c +++ b/cmd-save-buffer.c @@ -37,8 +37,6 @@ const struct cmd_entry cmd_save_buffer_entry = { cmd_buffer_init, cmd_buffer_parse, cmd_save_buffer_exec, - cmd_buffer_send, - cmd_buffer_recv, cmd_buffer_free, cmd_buffer_print }; diff --git a/cmd-scroll-mode.c b/cmd-scroll-mode.c index 898e3a60..935dcf03 100644 --- a/cmd-scroll-mode.c +++ b/cmd-scroll-mode.c @@ -34,8 +34,6 @@ const struct cmd_entry cmd_scroll_mode_entry = { cmd_scroll_mode_init, cmd_target_parse, cmd_scroll_mode_exec, - cmd_target_send, - cmd_target_recv, cmd_target_free, cmd_target_print }; diff --git a/cmd-select-layout.c b/cmd-select-layout.c index 6329a9b7..a2b053ac 100644 --- a/cmd-select-layout.c +++ b/cmd-select-layout.c @@ -34,8 +34,6 @@ const struct cmd_entry cmd_select_layout_entry = { cmd_select_layout_init, cmd_target_parse, cmd_select_layout_exec, - cmd_target_send, - cmd_target_recv, cmd_target_free, cmd_target_print }; diff --git a/cmd-select-pane.c b/cmd-select-pane.c index 39b89cac..055c2e3b 100644 --- a/cmd-select-pane.c +++ b/cmd-select-pane.c @@ -33,8 +33,6 @@ const struct cmd_entry cmd_select_pane_entry = { cmd_pane_init, cmd_pane_parse, cmd_select_pane_exec, - cmd_pane_send, - cmd_pane_recv, cmd_pane_free, cmd_pane_print }; diff --git a/cmd-select-prompt.c b/cmd-select-prompt.c index 67bb8ff3..a7965e29 100644 --- a/cmd-select-prompt.c +++ b/cmd-select-prompt.c @@ -37,8 +37,6 @@ const struct cmd_entry cmd_select_prompt_entry = { cmd_target_init, cmd_target_parse, cmd_select_prompt_exec, - cmd_target_send, - cmd_target_recv, cmd_target_free, cmd_target_print }; diff --git a/cmd-select-window.c b/cmd-select-window.c index 41bf78fa..dba77c30 100644 --- a/cmd-select-window.c +++ b/cmd-select-window.c @@ -36,8 +36,6 @@ const struct cmd_entry cmd_select_window_entry = { cmd_select_window_init, cmd_target_parse, cmd_select_window_exec, - cmd_target_send, - cmd_target_recv, cmd_target_free, cmd_target_print }; diff --git a/cmd-send-keys.c b/cmd-send-keys.c index df02efc5..04b21f95 100644 --- a/cmd-send-keys.c +++ b/cmd-send-keys.c @@ -28,8 +28,6 @@ int cmd_send_keys_parse(struct cmd *, int, char **, char **); int cmd_send_keys_exec(struct cmd *, struct cmd_ctx *); -void cmd_send_keys_send(struct cmd *, struct buffer *); -void cmd_send_keys_recv(struct cmd *, struct buffer *); void cmd_send_keys_free(struct cmd *); size_t cmd_send_keys_print(struct cmd *, char *, size_t); @@ -47,8 +45,6 @@ const struct cmd_entry cmd_send_keys_entry = { NULL, cmd_send_keys_parse, cmd_send_keys_exec, - cmd_send_keys_send, - cmd_send_keys_recv, cmd_send_keys_free, cmd_send_keys_print }; @@ -127,28 +123,6 @@ cmd_send_keys_exec(struct cmd *self, struct cmd_ctx *ctx) return (0); } -void -cmd_send_keys_send(struct cmd *self, struct buffer *b) -{ - struct cmd_send_keys_data *data = self->data; - - buffer_write(b, data, sizeof *data); - cmd_send_string(b, data->target); - buffer_write(b, data->keys, data->nkeys * sizeof *data->keys); -} - -void -cmd_send_keys_recv(struct cmd *self, struct buffer *b) -{ - struct cmd_send_keys_data *data; - - self->data = data = xmalloc(sizeof *data); - buffer_read(b, data, sizeof *data); - data->target = cmd_recv_string(b); - data->keys = xcalloc(data->nkeys, sizeof *data->keys); - buffer_read(b, data->keys, data->nkeys * sizeof *data->keys); -} - void cmd_send_keys_free(struct cmd *self) { diff --git a/cmd-send-prefix.c b/cmd-send-prefix.c index ca4fae6e..cc857ec3 100644 --- a/cmd-send-prefix.c +++ b/cmd-send-prefix.c @@ -33,8 +33,6 @@ const struct cmd_entry cmd_send_prefix_entry = { cmd_target_init, cmd_target_parse, cmd_send_prefix_exec, - cmd_target_send, - cmd_target_recv, cmd_target_free, cmd_target_print }; diff --git a/cmd-server-info.c b/cmd-server-info.c index 2678facd..24cd90b7 100644 --- a/cmd-server-info.c +++ b/cmd-server-info.c @@ -41,8 +41,6 @@ const struct cmd_entry cmd_server_info_entry = { NULL, cmd_server_info_exec, NULL, - NULL, - NULL, NULL }; diff --git a/cmd-set-buffer.c b/cmd-set-buffer.c index 3620dfde..8c2b8441 100644 --- a/cmd-set-buffer.c +++ b/cmd-set-buffer.c @@ -35,8 +35,6 @@ const struct cmd_entry cmd_set_buffer_entry = { cmd_buffer_init, cmd_buffer_parse, cmd_set_buffer_exec, - cmd_buffer_send, - cmd_buffer_recv, cmd_buffer_free, cmd_buffer_print }; diff --git a/cmd-set-option.c b/cmd-set-option.c index 5144418e..2e3ca734 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -36,8 +36,6 @@ const struct cmd_entry cmd_set_option_entry = { NULL, cmd_option_parse, cmd_set_option_exec, - cmd_option_send, - cmd_option_recv, cmd_option_free, cmd_option_print }; diff --git a/cmd-set-password.c b/cmd-set-password.c index 37702cde..39b48eee 100644 --- a/cmd-set-password.c +++ b/cmd-set-password.c @@ -29,8 +29,6 @@ int cmd_set_password_parse(struct cmd *, int, char **, char **); int cmd_set_password_exec(struct cmd *, struct cmd_ctx *); -void cmd_set_password_send(struct cmd *, struct buffer *); -void cmd_set_password_recv(struct cmd *, struct buffer *); void cmd_set_password_free(struct cmd *); void cmd_set_password_init(struct cmd *, int); size_t cmd_set_password_print(struct cmd *, char *, size_t); @@ -47,8 +45,6 @@ const struct cmd_entry cmd_set_password_entry = { cmd_set_password_init, cmd_set_password_parse, cmd_set_password_exec, - cmd_set_password_send, - cmd_set_password_recv, cmd_set_password_free, cmd_set_password_print }; @@ -122,25 +118,6 @@ cmd_set_password_exec(struct cmd *self, struct cmd_ctx *ctx) return (0); } -void -cmd_set_password_send(struct cmd *self, struct buffer *b) -{ - struct cmd_set_password_data *data = self->data; - - buffer_write(b, data, sizeof *data); - cmd_send_string(b, data->password); -} - -void -cmd_set_password_recv(struct cmd *self, struct buffer *b) -{ - struct cmd_set_password_data *data; - - self->data = data = xmalloc(sizeof *data); - buffer_read(b, data, sizeof *data); - data->password = cmd_recv_string(b); -} - void cmd_set_password_free(struct cmd *self) { diff --git a/cmd-set-window-option.c b/cmd-set-window-option.c index 8c0faa0d..c24f3592 100644 --- a/cmd-set-window-option.c +++ b/cmd-set-window-option.c @@ -36,8 +36,6 @@ const struct cmd_entry cmd_set_window_option_entry = { NULL, cmd_option_parse, cmd_set_window_option_exec, - cmd_option_send, - cmd_option_recv, cmd_option_free, cmd_option_print }; diff --git a/cmd-show-buffer.c b/cmd-show-buffer.c index e5a646d9..795f5b25 100644 --- a/cmd-show-buffer.c +++ b/cmd-show-buffer.c @@ -35,8 +35,6 @@ const struct cmd_entry cmd_show_buffer_entry = { cmd_buffer_init, cmd_buffer_parse, cmd_show_buffer_exec, - cmd_buffer_send, - cmd_buffer_recv, cmd_buffer_free, cmd_buffer_print }; diff --git a/cmd-show-options.c b/cmd-show-options.c index dab08917..a5ee2e4f 100644 --- a/cmd-show-options.c +++ b/cmd-show-options.c @@ -36,8 +36,6 @@ const struct cmd_entry cmd_show_options_entry = { cmd_target_init, cmd_target_parse, cmd_show_options_exec, - cmd_target_send, - cmd_target_recv, cmd_target_free, cmd_target_print }; diff --git a/cmd-show-window-options.c b/cmd-show-window-options.c index 4365b098..cfff8045 100644 --- a/cmd-show-window-options.c +++ b/cmd-show-window-options.c @@ -36,8 +36,6 @@ const struct cmd_entry cmd_show_window_options_entry = { cmd_target_init, cmd_target_parse, cmd_show_window_options_exec, - cmd_target_send, - cmd_target_recv, cmd_target_free, cmd_target_print }; diff --git a/cmd-source-file.c b/cmd-source-file.c index c9075530..b42c5785 100644 --- a/cmd-source-file.c +++ b/cmd-source-file.c @@ -26,8 +26,6 @@ int cmd_source_file_parse(struct cmd *, int, char **, char **); int cmd_source_file_exec(struct cmd *, struct cmd_ctx *); -void cmd_source_file_send(struct cmd *, struct buffer *); -void cmd_source_file_recv(struct cmd *, struct buffer *); void cmd_source_file_free(struct cmd *); void cmd_source_file_init(struct cmd *, int); size_t cmd_source_file_print(struct cmd *, char *, size_t); @@ -43,8 +41,6 @@ const struct cmd_entry cmd_source_file_entry = { cmd_source_file_init, cmd_source_file_parse, cmd_source_file_exec, - cmd_source_file_send, - cmd_source_file_recv, cmd_source_file_free, cmd_source_file_print }; @@ -103,25 +99,6 @@ cmd_source_file_exec(struct cmd *self, struct cmd_ctx *ctx) return (0); } -void -cmd_source_file_send(struct cmd *self, struct buffer *b) -{ - struct cmd_source_file_data *data = self->data; - - buffer_write(b, data, sizeof *data); - cmd_send_string(b, data->path); -} - -void -cmd_source_file_recv(struct cmd *self, struct buffer *b) -{ - struct cmd_source_file_data *data; - - self->data = data = xmalloc(sizeof *data); - buffer_read(b, data, sizeof *data); - data->path = cmd_recv_string(b); -} - void cmd_source_file_free(struct cmd *self) { diff --git a/cmd-split-window.c b/cmd-split-window.c index f7519cb7..b483cdd4 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -29,8 +29,6 @@ int cmd_split_window_parse(struct cmd *, int, char **, char **); int cmd_split_window_exec(struct cmd *, struct cmd_ctx *); -void cmd_split_window_send(struct cmd *, struct buffer *); -void cmd_split_window_recv(struct cmd *, struct buffer *); void cmd_split_window_free(struct cmd *); void cmd_split_window_init(struct cmd *, int); size_t cmd_split_window_print(struct cmd *, char *, size_t); @@ -51,8 +49,6 @@ const struct cmd_entry cmd_split_window_entry = { cmd_split_window_init, cmd_split_window_parse, cmd_split_window_exec, - cmd_split_window_send, - cmd_split_window_recv, cmd_split_window_free, cmd_split_window_print }; @@ -211,27 +207,6 @@ error: return (-1); } -void -cmd_split_window_send(struct cmd *self, struct buffer *b) -{ - struct cmd_split_window_data *data = self->data; - - buffer_write(b, data, sizeof *data); - cmd_send_string(b, data->target); - cmd_send_string(b, data->cmd); -} - -void -cmd_split_window_recv(struct cmd *self, struct buffer *b) -{ - struct cmd_split_window_data *data; - - self->data = data = xmalloc(sizeof *data); - buffer_read(b, data, sizeof *data); - data->target = cmd_recv_string(b); - data->cmd = cmd_recv_string(b); -} - void cmd_split_window_free(struct cmd *self) { diff --git a/cmd-start-server.c b/cmd-start-server.c index b8f00949..0fa5bc49 100644 --- a/cmd-start-server.c +++ b/cmd-start-server.c @@ -34,8 +34,6 @@ const struct cmd_entry cmd_start_server_entry = { NULL, cmd_start_server_exec, NULL, - NULL, - NULL, NULL }; diff --git a/cmd-suspend-client.c b/cmd-suspend-client.c index 5642bbec..f1fc6109 100644 --- a/cmd-suspend-client.c +++ b/cmd-suspend-client.c @@ -41,8 +41,6 @@ const struct cmd_entry cmd_suspend_client_entry = { cmd_target_init, cmd_target_parse, cmd_suspend_client_exec, - cmd_target_send, - cmd_target_recv, cmd_target_free, cmd_target_print }; diff --git a/cmd-swap-pane.c b/cmd-swap-pane.c index be8b2e07..7222e12c 100644 --- a/cmd-swap-pane.c +++ b/cmd-swap-pane.c @@ -28,8 +28,6 @@ int cmd_swap_pane_parse(struct cmd *, int, char **, char **); int cmd_swap_pane_exec(struct cmd *, struct cmd_ctx *); -void cmd_swap_pane_send(struct cmd *, struct buffer *); -void cmd_swap_pane_recv(struct cmd *, struct buffer *); void cmd_swap_pane_free(struct cmd *); void cmd_swap_pane_init(struct cmd *, int); size_t cmd_swap_pane_print(struct cmd *, char *, size_t); @@ -50,8 +48,6 @@ const struct cmd_entry cmd_swap_pane_entry = { cmd_swap_pane_init, cmd_swap_pane_parse, cmd_swap_pane_exec, - cmd_swap_pane_send, - cmd_swap_pane_recv, cmd_swap_pane_free, cmd_swap_pane_print }; @@ -234,25 +230,6 @@ cmd_swap_pane_exec(struct cmd *self, struct cmd_ctx *ctx) return (0); } -void -cmd_swap_pane_send(struct cmd *self, struct buffer *b) -{ - struct cmd_swap_pane_data *data = self->data; - - buffer_write(b, data, sizeof *data); - cmd_send_string(b, data->target); -} - -void -cmd_swap_pane_recv(struct cmd *self, struct buffer *b) -{ - struct cmd_swap_pane_data *data; - - self->data = data = xmalloc(sizeof *data); - buffer_read(b, data, sizeof *data); - data->target = cmd_recv_string(b); -} - void cmd_swap_pane_free(struct cmd *self) { diff --git a/cmd-swap-window.c b/cmd-swap-window.c index 61e9c423..875291f2 100644 --- a/cmd-swap-window.c +++ b/cmd-swap-window.c @@ -35,8 +35,6 @@ const struct cmd_entry cmd_swap_window_entry = { cmd_srcdst_init, cmd_srcdst_parse, cmd_swap_window_exec, - cmd_srcdst_send, - cmd_srcdst_recv, cmd_srcdst_free, cmd_srcdst_print }; diff --git a/cmd-switch-client.c b/cmd-switch-client.c index 1ad4701f..80c4dc5d 100644 --- a/cmd-switch-client.c +++ b/cmd-switch-client.c @@ -29,8 +29,6 @@ int cmd_switch_client_parse(struct cmd *, int, char **, char **); int cmd_switch_client_exec(struct cmd *, struct cmd_ctx *); -void cmd_switch_client_send(struct cmd *, struct buffer *); -void cmd_switch_client_recv(struct cmd *, struct buffer *); void cmd_switch_client_free(struct cmd *); size_t cmd_switch_client_print(struct cmd *, char *, size_t); @@ -46,8 +44,6 @@ const struct cmd_entry cmd_switch_client_entry = { NULL, cmd_switch_client_parse, cmd_switch_client_exec, - cmd_switch_client_send, - cmd_switch_client_recv, cmd_switch_client_free, cmd_switch_client_print }; @@ -111,27 +107,6 @@ cmd_switch_client_exec(struct cmd *self, struct cmd_ctx *ctx) return (0); } -void -cmd_switch_client_send(struct cmd *self, struct buffer *b) -{ - struct cmd_switch_client_data *data = self->data; - - buffer_write(b, data, sizeof *data); - cmd_send_string(b, data->name); - cmd_send_string(b, data->target); -} - -void -cmd_switch_client_recv(struct cmd *self, struct buffer *b) -{ - struct cmd_switch_client_data *data; - - self->data = data = xmalloc(sizeof *data); - buffer_read(b, data, sizeof *data); - data->name = cmd_recv_string(b); - data->target = cmd_recv_string(b); -} - void cmd_switch_client_free(struct cmd *self) { diff --git a/cmd-unbind-key.c b/cmd-unbind-key.c index 0100e5a9..35c43658 100644 --- a/cmd-unbind-key.c +++ b/cmd-unbind-key.c @@ -26,8 +26,6 @@ int cmd_unbind_key_parse(struct cmd *, int, char **, char **); int cmd_unbind_key_exec(struct cmd *, struct cmd_ctx *); -void cmd_unbind_key_send(struct cmd *, struct buffer *); -void cmd_unbind_key_recv(struct cmd *, struct buffer *); void cmd_unbind_key_free(struct cmd *); struct cmd_unbind_key_data { @@ -41,8 +39,6 @@ const struct cmd_entry cmd_unbind_key_entry = { NULL, cmd_unbind_key_parse, cmd_unbind_key_exec, - cmd_unbind_key_send, - cmd_unbind_key_recv, cmd_unbind_key_free, NULL }; @@ -99,23 +95,6 @@ cmd_unbind_key_exec(struct cmd *self, unused struct cmd_ctx *ctx) return (0); } -void -cmd_unbind_key_send(struct cmd *self, struct buffer *b) -{ - struct cmd_unbind_key_data *data = self->data; - - buffer_write(b, data, sizeof *data); -} - -void -cmd_unbind_key_recv(struct cmd *self, struct buffer *b) -{ - struct cmd_unbind_key_data *data; - - self->data = data = xmalloc(sizeof *data); - buffer_read(b, data, sizeof *data); -} - void cmd_unbind_key_free(struct cmd *self) { diff --git a/cmd-unlink-window.c b/cmd-unlink-window.c index 2ef1ca04..fd72b252 100644 --- a/cmd-unlink-window.c +++ b/cmd-unlink-window.c @@ -33,8 +33,6 @@ const struct cmd_entry cmd_unlink_window_entry = { cmd_target_init, cmd_target_parse, cmd_unlink_window_exec, - cmd_target_send, - cmd_target_recv, cmd_target_free, cmd_target_print }; diff --git a/cmd-up-pane.c b/cmd-up-pane.c index c2d063d0..966952d6 100644 --- a/cmd-up-pane.c +++ b/cmd-up-pane.c @@ -33,8 +33,6 @@ const struct cmd_entry cmd_up_pane_entry = { cmd_target_init, cmd_target_parse, cmd_up_pane_exec, - cmd_target_send, - cmd_target_recv, cmd_target_free, cmd_target_print }; diff --git a/cmd.c b/cmd.c index b13d0cc4..9fda3dcc 100644 --- a/cmd.c +++ b/cmd.c @@ -109,6 +109,64 @@ struct session *cmd_lookup_session(const char *, int *); struct winlink *cmd_lookup_window(struct session *, const char *, int *); int cmd_lookup_index(struct session *, const char *, int *); +int +cmd_pack_argv(int argc, char **argv, char *buf, size_t len) +{ + size_t arglen; + int i; + + *buf = '\0'; + for (i = 0; i < argc; i++) { + if (strlcpy(buf, argv[i], len) >= len) + return (-1); + arglen = strlen(argv[i]) + 1; + buf += arglen; + len -= arglen; + } + + return (0); +} + +int +cmd_unpack_argv(char *buf, size_t len, int argc, char ***argv) +{ + int i; + size_t arglen; + + if (argc == 0) + return (0); + *argv = xcalloc(argc, sizeof **argv); + + buf[len - 1] = '\0'; + for (i = 0; i < argc; i++) { + if (len == 0) { + cmd_free_argv(argc, *argv); + return (-1); + } + + arglen = strlen(buf) + 1; + (*argv)[i] = xstrdup(buf); + buf += arglen; + len -= arglen; + } + + return (0); +} + +void +cmd_free_argv(int argc, char **argv) +{ + int i; + + if (argc == 0) + return; + for (i = 0; i < argc; i++) { + if (argv[i] != NULL) + xfree(argv[i]); + } + xfree(argv); +} + struct cmd * cmd_parse(int argc, char **argv, char **cause) { @@ -204,53 +262,6 @@ cmd_exec(struct cmd *cmd, struct cmd_ctx *ctx) return (cmd->entry->exec(cmd, ctx)); } -void -cmd_send(struct cmd *cmd, struct buffer *b) -{ - const struct cmd_entry **entryp; - u_int n; - - n = 0; - for (entryp = cmd_table; *entryp != NULL; entryp++) { - if (*entryp == cmd->entry) - break; - n++; - } - if (*entryp == NULL) - fatalx("command not found"); - - buffer_write(b, &n, sizeof n); - - if (cmd->entry->send != NULL) - cmd->entry->send(cmd, b); -} - -struct cmd * -cmd_recv(struct buffer *b) -{ - const struct cmd_entry **entryp; - struct cmd *cmd; - u_int m, n; - - buffer_read(b, &m, sizeof m); - - n = 0; - for (entryp = cmd_table; *entryp != NULL; entryp++) { - if (n == m) - break; - n++; - } - if (*entryp == NULL) - fatalx("command not found"); - - cmd = xmalloc(sizeof *cmd); - cmd->entry = *entryp; - - if (cmd->entry->recv != NULL) - cmd->entry->recv(cmd, b); - return (cmd); -} - void cmd_free(struct cmd *cmd) { @@ -268,41 +279,6 @@ cmd_print(struct cmd *cmd, char *buf, size_t len) return (cmd->entry->print(cmd, buf, len)); } -void -cmd_send_string(struct buffer *b, const char *s) -{ - size_t n; - - if (s == NULL) { - n = 0; - buffer_write(b, &n, sizeof n); - return; - } - - n = strlen(s) + 1; - buffer_write(b, &n, sizeof n); - - buffer_write(b, s, n); -} - -char * -cmd_recv_string(struct buffer *b) -{ - char *s; - size_t n; - - buffer_read(b, &n, sizeof n); - - if (n == 0) - return (NULL); - - s = xmalloc(n); - buffer_read(b, s, n); - s[n - 1] = '\0'; - - return (s); -} - /* * Figure out the current session. Use: 1) the current session, if the command * context has one; 2) the session specified in the TMUX variable from the diff --git a/server-fn.c b/server-fn.c index 409f65bc..05f4168e 100644 --- a/server-fn.c +++ b/server-fn.c @@ -47,6 +47,15 @@ server_fill_environ(struct session *s) return (env); } +void +server_write_error(struct client *c, const char *msg) +{ + struct msg_print_data printdata; + + strlcpy(printdata.msg, msg, sizeof printdata.msg); + server_write_client(c, MSG_ERROR, &printdata, sizeof printdata); +} + void server_write_client( struct client *c, enum hdrtype type, const void *buf, size_t len) @@ -220,7 +229,7 @@ wrong: password_failures++; for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); - if (c == NULL || c->prompt_buffer == NULL) + if (c == NULL || c->prompt_buffer == NULL) continue; *c->prompt_buffer = '\0'; diff --git a/server-msg.c b/server-msg.c index 31e986f8..9d1f84f8 100644 --- a/server-msg.c +++ b/server-msg.c @@ -83,46 +83,43 @@ server_msg_dispatch(struct client *c) void printflike2 server_msg_fn_command_error(struct cmd_ctx *ctx, const char *fmt, ...) { - va_list ap; - char *msg; + struct msg_print_data data; + va_list ap; va_start(ap, fmt); - xvasprintf(&msg, fmt, ap); + xvsnprintf(data.msg, sizeof data.msg, fmt, ap); va_end(ap); - server_write_client(ctx->cmdclient, MSG_ERROR, msg, strlen(msg)); - xfree(msg); + server_write_client(ctx->cmdclient, MSG_ERROR, &data, sizeof data); } void printflike2 server_msg_fn_command_print(struct cmd_ctx *ctx, const char *fmt, ...) { - va_list ap; - char *msg; + struct msg_print_data data; + va_list ap; va_start(ap, fmt); - xvasprintf(&msg, fmt, ap); + xvsnprintf(data.msg, sizeof data.msg, fmt, ap); va_end(ap); - server_write_client(ctx->cmdclient, MSG_PRINT, msg, strlen(msg)); - xfree(msg); + server_write_client(ctx->cmdclient, MSG_PRINT, &data, sizeof data); } void printflike2 server_msg_fn_command_info(struct cmd_ctx *ctx, const char *fmt, ...) { - va_list ap; - char *msg; + struct msg_print_data data; + va_list ap; if (be_quiet) return; va_start(ap, fmt); - xvasprintf(&msg, fmt, ap); + xvsnprintf(data.msg, sizeof data.msg, fmt, ap); va_end(ap); - server_write_client(ctx->cmdclient, MSG_PRINT, msg, strlen(msg)); - xfree(msg); + server_write_client(ctx->cmdclient, MSG_PRINT, &data, sizeof data); } void @@ -130,14 +127,15 @@ server_msg_fn_command(struct hdr *hdr, struct client *c) { struct msg_command_data data; struct cmd_ctx ctx; - struct cmd_list *cmdlist; + struct cmd_list *cmdlist = NULL; struct cmd *cmd; + int argc; + char **argv, *cause; if (hdr->size < sizeof data) fatalx("bad MSG_COMMAND size"); buffer_read(c->in, &data, sizeof data); - cmdlist = cmd_list_recv(c->in); server_activity = time(NULL); ctx.error = server_msg_fn_command_error; @@ -150,15 +148,33 @@ server_msg_fn_command(struct hdr *hdr, struct client *c) ctx.cmdclient = c; + argc = data.argc; + data.argv[(sizeof data.argv) - 1] = '\0'; + if (cmd_unpack_argv(data.argv, sizeof data.argv, argc, &argv) != 0) { + server_msg_fn_command_error(&ctx, "command too long"); + goto error; + } + + if (argc == 0) { + argc = 1; + argv = xcalloc(1, sizeof *argv); + *argv = xstrdup("new-session"); + } + + if ((cmdlist = cmd_list_parse(argc, argv, &cause)) == NULL) { + server_msg_fn_command_error(&ctx, "%s", cause); + cmd_free_argv(argc, argv); + goto error; + } + cmd_free_argv(argc, argv); + if (data.pid != -1) { TAILQ_FOREACH(cmd, cmdlist, qentry) { if (cmd->entry->flags & CMD_CANTNEST) { server_msg_fn_command_error(&ctx, "sessions should be nested with care. " "unset $TMUX to force"); - cmd_list_free(cmdlist); - server_write_client(c, MSG_EXIT, NULL, 0); - return; + goto error; } } } @@ -166,27 +182,28 @@ server_msg_fn_command(struct hdr *hdr, struct client *c) if (cmd_list_exec(cmdlist, &ctx) != 1) server_write_client(c, MSG_EXIT, NULL, 0); cmd_list_free(cmdlist); + return; + +error: + if (cmdlist != NULL) + cmd_list_free(cmdlist); + server_write_client(c, MSG_EXIT, NULL, 0); } void server_msg_fn_identify(struct hdr *hdr, struct client *c) { struct msg_identify_data data; - char *term; if (hdr->size < sizeof data) fatalx("bad MSG_IDENTIFY size"); buffer_read(c->in, &data, sizeof data); - term = cmd_recv_string(c->in); log_debug("identify msg from client: %u,%u (%d)", data.sx, data.sy, data.version); if (data.version != PROTOCOL_VERSION) { -#define MSG "protocol version mismatch" - server_write_client(c, MSG_ERROR, MSG, (sizeof MSG) - 1); -#undef MSG - server_write_client(c, MSG_EXIT, NULL, 0); + server_write_error(c, "protocol version mismatch"); return; } @@ -199,7 +216,8 @@ server_msg_fn_identify(struct hdr *hdr, struct client *c) c->cwd = xstrdup(data.cwd); data.tty[(sizeof data.tty) - 1] = '\0'; - tty_init(&c->tty, data.tty, term); + data.term[(sizeof data.term) - 1] = '\0'; + tty_init(&c->tty, data.tty, data.term); if (data.flags & IDENTIFY_UTF8) c->tty.flags |= TTY_UTF8; if (data.flags & IDENTIFY_256COLOURS) @@ -209,9 +227,6 @@ server_msg_fn_identify(struct hdr *hdr, struct client *c) if (data.flags & IDENTIFY_HASDEFAULTS) c->tty.term_flags |= TERM_HASDEFAULTS; - if (term != NULL) - xfree(term); - c->flags |= CLIENT_TERMINAL; } @@ -262,24 +277,20 @@ server_msg_fn_exiting(struct hdr *hdr, struct client *c) void server_msg_fn_unlock(struct hdr *hdr, struct client *c) { - char *pass; + struct msg_unlock_data data; - if (hdr->size == 0) + if (hdr->size != sizeof data) fatalx("bad MSG_UNLOCK size"); - pass = cmd_recv_string(c->in); + buffer_read(c->in, &data, sizeof data); log_debug("unlock msg from client"); - if (server_unlock(pass) != 0) { -#define MSG "bad password" - server_write_client(c, MSG_ERROR, MSG, (sizeof MSG) - 1); -#undef MSG - } + data.pass[(sizeof data.pass) - 1] = '\0'; + if (server_unlock(data.pass) != 0) + server_write_error(c, "bad password"); + memset(&data, 0, sizeof data); server_write_client(c, MSG_EXIT, NULL, 0); - - memset(pass, 0, strlen(pass)); - xfree(pass); } void diff --git a/tmux.c b/tmux.c index 2a155d57..4f97a58a 100644 --- a/tmux.c +++ b/tmux.c @@ -57,6 +57,8 @@ char *socket_path; __dead void usage(void); char *makesockpath(const char *); +int prepare_unlock(enum hdrtype *, void **, size_t *, int); +int prepare_cmd(enum hdrtype *, void **, size_t *, int, char **); __dead void usage(void) @@ -200,19 +202,70 @@ makesockpath(const char *label) return (path); } +int +prepare_unlock(enum hdrtype *msg, void **buf, size_t *len, int argc) +{ + static struct msg_unlock_data unlockdata; + char *pass; + + if (argc != 0) { + log_warnx("can't specify a command when unlocking"); + return (-1); + } + + if ((pass = getpass("Password: ")) == NULL) + return (-1); + + if (strlen(pass) >= sizeof unlockdata.pass) { + log_warnx("password too long"); + return (-1); + } + + strlcpy(unlockdata.pass, pass, sizeof unlockdata.pass); + memset(pass, 0, strlen(pass)); + + *buf = &unlockdata; + *len = sizeof unlockdata; + + *msg = MSG_UNLOCK; + return (0); +} + +int +prepare_cmd(enum hdrtype *msg, void **buf, size_t *len, int argc, char **argv) +{ + static struct msg_command_data cmddata; + + client_fill_session(&cmddata); + + cmddata.argc = argc; + if (cmd_pack_argv(argc, argv, cmddata.argv, sizeof cmddata.argv) != 0) { + log_warnx("command too long"); + return (-1); + } + + *buf = &cmddata; + *len = sizeof cmddata; + + *msg = MSG_COMMAND; + return (0); +} + int main(int argc, char **argv) { struct client_ctx cctx; - struct msg_command_data cmddata; - struct buffer *b; struct cmd_list *cmdlist; struct cmd *cmd; struct pollfd pfd; + enum hdrtype msg; struct hdr hdr; struct passwd *pw; - char *s, *path, *label, *cause, *home, *pass = NULL; + struct msg_print_data printdata; + char *s, *path, *label, *home, *cause; char cwd[MAXPATHLEN]; + void *buf; + size_t len; int retcode, opt, flags, unlock, cmdflags = 0; unlock = flags = 0; @@ -364,7 +417,7 @@ main(int argc, char **argv) exit(1); } } - + if (label == NULL) label = xstrdup("default"); if (path == NULL && (path = makesockpath(label)) == NULL) { @@ -383,36 +436,35 @@ main(int argc, char **argv) options_set_string(&global_s_options, "default-path", "%s", cwd); if (unlock) { - if (argc != 0) { - log_warnx("can't specify a command when unlocking"); + if (prepare_unlock(&msg, &buf, &len, argc) != 0) exit(1); - } - cmdlist = NULL; - if ((pass = getpass("Password: ")) == NULL) - exit(1); - cmdflags &= ~CMD_STARTSERVER; } else { - if (argc == 0) { - cmd = xmalloc(sizeof *cmd); - cmd->entry = &cmd_new_session_entry; - cmd->entry->init(cmd, 0); + if (prepare_cmd(&msg, &buf, &len, argc, argv) != 0) + exit(1); + } - cmdlist = xmalloc(sizeof *cmdlist); - TAILQ_INIT(cmdlist); - TAILQ_INSERT_HEAD(cmdlist, cmd, qentry); - } else { - cmdlist = cmd_list_parse(argc, argv, &cause); - if (cmdlist == NULL) { - log_warnx("%s", cause); - exit(1); - } + if (unlock) + cmdflags &= ~CMD_STARTSERVER; + else if (argc == 0) + cmdflags |= CMD_STARTSERVER; + else { + /* + * It sucks parsing the command string twice (in client and + * later in server) but it is necessary to get the start server + * flag. + */ + if ((cmdlist = cmd_list_parse(argc, argv, &cause)) == NULL) { + log_warnx("%s", cause); + exit(1); } + cmdflags &= ~CMD_STARTSERVER; TAILQ_FOREACH(cmd, cmdlist, qentry) { if (cmd->entry->flags & CMD_STARTSERVER) { cmdflags |= CMD_STARTSERVER; break; } } + cmd_list_free(cmdlist); } memset(&cctx, 0, sizeof cctx); @@ -420,20 +472,8 @@ main(int argc, char **argv) exit(1); xfree(path); - b = buffer_create(BUFSIZ); - if (unlock) { - cmd_send_string(b, pass); - memset(pass, 0, strlen(pass)); - client_write_server( - &cctx, MSG_UNLOCK, BUFFER_OUT(b), BUFFER_USED(b)); - } else { - cmd_list_send(cmdlist, b); - cmd_list_free(cmdlist); - client_fill_session(&cmddata); - client_write_server2(&cctx, MSG_COMMAND, - &cmddata, sizeof cmddata, BUFFER_OUT(b), BUFFER_USED(b)); - } - buffer_destroy(b); + client_write_server(&cctx, msg, buf, len); + memset(buf, 0, len); retcode = 0; for (;;) { @@ -467,12 +507,12 @@ main(int argc, char **argv) retcode = 1; /* FALLTHROUGH */ case MSG_PRINT: - if (hdr.size > INT_MAX - 1) + if (hdr.size < sizeof printdata) fatalx("bad MSG_PRINT size"); - log_info("%.*s", - (int) hdr.size, BUFFER_OUT(cctx.srv_in)); - if (hdr.size != 0) - buffer_remove(cctx.srv_in, hdr.size); + buffer_read(cctx.srv_in, &printdata, sizeof printdata); + + printdata.msg[(sizeof printdata.msg) - 1] = '\0'; + log_info("%s", printdata.msg); goto restart; case MSG_READY: retcode = client_main(&cctx); diff --git a/tmux.h b/tmux.h index 2eeb9f5d..159711e7 100644 --- a/tmux.h +++ b/tmux.h @@ -19,7 +19,7 @@ #ifndef TMUX_H #define TMUX_H -#define PROTOCOL_VERSION -14 +#define PROTOCOL_VERSION -15 #include #include @@ -62,6 +62,14 @@ extern char *__progname; /* Maximum poll timeout (when attached). */ #define POLL_TIMEOUT 50 +/* + * Maximum sizes of strings in message data. Don't forget to bump + * PROTOCOL_VERSION if any of these change! + */ +#define COMMAND_LENGTH 2048 /* packed argv size */ +#define TERMINAL_LENGTH 128 /* length of TERM environment variable */ +#define PRINT_LENGTH 512 /* printed error/message size */ + /* Fatal errors. */ #define fatal(msg) log_fatal("%s: %s", __func__, msg); #define fatalx(msg) log_fatalx("%s: %s", __func__, msg); @@ -293,17 +301,29 @@ enum hdrtype { MSG_WAKEUP, }; -/* Message header structure. */ +/* + * Message header and data. + * + * Don't forget to bump PROTOCOL_VERSION if any of these change! + * + * Changing sizeof (struct hdr) or sizeof (struct msg_identify_data) will make + * the tmux client hang even if the protocol version is bumped. + */ struct hdr { enum hdrtype type; size_t size; }; +struct msg_print_data { + char msg[PRINT_LENGTH]; +}; + struct msg_command_data { pid_t pid; /* pid from $TMUX or -1 */ u_int idx; /* index from $TMUX */ - size_t namelen; + int argc; + char argv[COMMAND_LENGTH]; }; struct msg_identify_data { @@ -312,6 +332,8 @@ struct msg_identify_data { char cwd[MAXPATHLEN]; + char term[TERMINAL_LENGTH]; + #define IDENTIFY_UTF8 0x1 #define IDENTIFY_256COLOURS 0x2 #define IDENTIFY_88COLOURS 0x4 @@ -320,8 +342,6 @@ struct msg_identify_data { u_int sx; u_int sy; - - size_t termlen; }; struct msg_resize_data { @@ -329,6 +349,10 @@ struct msg_resize_data { u_int sy; }; +struct msg_unlock_data { + char pass[PASS_MAX]; +}; + /* Editing keys. */ enum mode_key_cmd { MODEKEYCMD_BACKSPACE = 0x1000, @@ -907,8 +931,6 @@ struct cmd_entry { void (*init)(struct cmd *, int); int (*parse)(struct cmd *, int, char **, char **); int (*exec)(struct cmd *, struct cmd_ctx *); - void (*send)(struct cmd *, struct buffer *); - void (*recv)(struct cmd *, struct buffer *); void (*free)(struct cmd *); size_t (*print)(struct cmd *, char *, size_t); }; @@ -1113,14 +1135,13 @@ int paste_replace(struct paste_stack *, u_int, char *); void clock_draw(struct screen_write_ctx *, u_int, int); /* cmd.c */ +int cmd_pack_argv(int, char **, char *, size_t); +int cmd_unpack_argv(char *, size_t, int, char ***); +void cmd_free_argv(int, char **); struct cmd *cmd_parse(int, char **, char **); int cmd_exec(struct cmd *, struct cmd_ctx *); -void cmd_send(struct cmd *, struct buffer *); -struct cmd *cmd_recv(struct buffer *); void cmd_free(struct cmd *); size_t cmd_print(struct cmd *, char *, size_t); -void cmd_send_string(struct buffer *, const char *); -char *cmd_recv_string(struct buffer *); struct session *cmd_current_session(struct cmd_ctx *); struct client *cmd_find_client(struct cmd_ctx *, const char *); struct session *cmd_find_session(struct cmd_ctx *, const char *); @@ -1205,8 +1226,6 @@ extern const struct cmd_entry cmd_up_pane_entry; /* cmd-list.c */ struct cmd_list *cmd_list_parse(int, char **, char **); int cmd_list_exec(struct cmd_list *, struct cmd_ctx *); -void cmd_list_send(struct cmd_list *, struct buffer *); -struct cmd_list *cmd_list_recv(struct buffer *); void cmd_list_free(struct cmd_list *); size_t cmd_list_print(struct cmd_list *, char *, size_t); @@ -1220,8 +1239,6 @@ size_t cmd_prarg(char *, size_t, const char *, char *); #define CMD_TARGET_CLIENT_USAGE "[-t target-client]" void cmd_target_init(struct cmd *, int); int cmd_target_parse(struct cmd *, int, char **, char **); -void cmd_target_send(struct cmd *, struct buffer *); -void cmd_target_recv(struct cmd *, struct buffer *); void cmd_target_free(struct cmd *); size_t cmd_target_print(struct cmd *, char *, size_t); #define CMD_SRCDST_WINDOW_USAGE "[-s src-window] [-t dst-window]" @@ -1229,8 +1246,6 @@ size_t cmd_target_print(struct cmd *, char *, size_t); #define CMD_SRCDST_CLIENT_USAGE "[-s src-client] [-t dst-client]" void cmd_srcdst_init(struct cmd *, int); int cmd_srcdst_parse(struct cmd *, int, char **, char **); -void cmd_srcdst_send(struct cmd *, struct buffer *); -void cmd_srcdst_recv(struct cmd *, struct buffer *); void cmd_srcdst_free(struct cmd *); size_t cmd_srcdst_print(struct cmd *, char *, size_t); #define CMD_BUFFER_WINDOW_USAGE "[-b buffer-index] [-t target-window]" @@ -1238,8 +1253,6 @@ size_t cmd_srcdst_print(struct cmd *, char *, size_t); #define CMD_BUFFER_CLIENT_USAGE "[-b buffer-index] [-t target-client]" void cmd_buffer_init(struct cmd *, int); int cmd_buffer_parse(struct cmd *, int, char **, char **); -void cmd_buffer_send(struct cmd *, struct buffer *); -void cmd_buffer_recv(struct cmd *, struct buffer *); void cmd_buffer_free(struct cmd *); size_t cmd_buffer_print(struct cmd *, char *, size_t); #define CMD_OPTION_WINDOW_USAGE "[-gu] [-t target-window] option [value]" @@ -1247,8 +1260,6 @@ size_t cmd_buffer_print(struct cmd *, char *, size_t); #define CMD_OPTION_CLIENT_USAGE "[-gu] [-t target-client] option [value]" void cmd_option_init(struct cmd *, int); int cmd_option_parse(struct cmd *, int, char **, char **); -void cmd_option_send(struct cmd *, struct buffer *); -void cmd_option_recv(struct cmd *, struct buffer *); void cmd_option_free(struct cmd *); size_t cmd_option_print(struct cmd *, char *, size_t); #define CMD_PANE_WINDOW_USAGE "[-t target-window] [-p pane-index]" @@ -1256,8 +1267,6 @@ size_t cmd_option_print(struct cmd *, char *, size_t); #define CMD_PANE_CLIENT_USAGE "[-t target-client] [-p pane-index]" void cmd_pane_init(struct cmd *, int); int cmd_pane_parse(struct cmd *, int, char **, char **); -void cmd_pane_send(struct cmd *, struct buffer *); -void cmd_pane_recv(struct cmd *, struct buffer *); void cmd_pane_free(struct cmd *); size_t cmd_pane_print(struct cmd *, char *, size_t); @@ -1270,8 +1279,6 @@ int client_msg_dispatch(struct client_ctx *); /* client-fn.c */ void client_write_server(struct client_ctx *, enum hdrtype, void *, size_t); -void client_write_server2( - struct client_ctx *, enum hdrtype, void *, size_t, void *, size_t); void client_fill_session(struct msg_command_data *); /* key-bindings.c */ @@ -1303,6 +1310,7 @@ int server_msg_dispatch(struct client *); /* server-fn.c */ const char **server_fill_environ(struct session *); +void server_write_error(struct client *, const char *); void server_write_client( struct client *, enum hdrtype, const void *, size_t); void server_write_session( From 6b3b852ebcaa61d3a03b918370939cfd6af8c191 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 26 Jul 2009 19:42:26 +0000 Subject: [PATCH 0182/1180] Go to the next if the current best process is replaced, don't keep comparing it with itself. Also fix process name comparison. --- procname.c | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/procname.c b/procname.c index e28b7535..d7644898 100644 --- a/procname.c +++ b/procname.c @@ -82,41 +82,48 @@ retry: continue; } - if (is_runnable(p) && !is_runnable(bestp)) + if (is_runnable(p) && !is_runnable(bestp)) { bestp = p; - else if (!is_runnable(p) && is_runnable(bestp)) + continue; + } else if (!is_runnable(p) && is_runnable(bestp)) continue; - if (!is_stopped(p) && is_stopped(bestp)) + if (!is_stopped(p) && is_stopped(bestp)) { bestp = p; - else if (is_stopped(p) && !is_stopped(bestp)) + continue; + } else if (is_stopped(p) && !is_stopped(bestp)) continue; - if (p->p_estcpu > bestp->p_estcpu) + if (p->p_estcpu > bestp->p_estcpu) { bestp = p; - else if (p->p_estcpu < bestp->p_estcpu) + continue; + } else if (p->p_estcpu < bestp->p_estcpu) continue; - if (p->p_slptime < bestp->p_slptime) + if (p->p_slptime < bestp->p_slptime) { bestp = p; - else if (p->p_slptime > bestp->p_slptime) + continue; + } else if (p->p_slptime > bestp->p_slptime) continue; - if (p->p_flag & P_SINTR && !(bestp->p_flag & P_SINTR)) + if (p->p_flag & P_SINTR && !(bestp->p_flag & P_SINTR)) { bestp = p; - else if (!(p->p_flag & P_SINTR) && bestp->p_flag & P_SINTR) + continue; + } else if (!(p->p_flag & P_SINTR) && bestp->p_flag & P_SINTR) continue; if (LIST_FIRST(&p->p_children) == NULL && - LIST_FIRST(&bestp->p_children) != NULL) /* XXX ugh */ + LIST_FIRST(&bestp->p_children) != NULL) { /* XXX ugh */ bestp = p; - else if (LIST_FIRST(&p->p_children) != NULL && + continue; + } else if (LIST_FIRST(&p->p_children) != NULL && LIST_FIRST(&bestp->p_children) == NULL) continue; - if (strcmp(p->p_comm, p->p_comm) < 0) + if (strcmp(p->p_comm, bestp->p_comm) < 0) { bestp = p; - else if (strcmp(p->p_comm, p->p_comm) > 0) + continue; + } else if (strcmp(p->p_comm, bestp->p_comm) > 0) continue; if (p->p_pid > bestp->p_pid) From 55d8c01c339db6dd66ed85ce3da5273632da6ca5 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 26 Jul 2009 21:13:47 +0000 Subject: [PATCH 0183/1180] Calculate the space available for the prompt buffer and the cursor position correctly, and make it work when the screen is not wide enough. Noticed by Kalle Olavi Niemitalo. --- status.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/status.c b/status.c index 46d05fd5..24d91204 100644 --- a/status.c +++ b/status.c @@ -645,7 +645,7 @@ status_prompt_redraw(struct client *c) struct screen_write_ctx ctx; struct session *s = c->session; struct screen old_status; - size_t i, size, left, len, offset, n; + size_t i, size, left, len, off, n; char ch; struct grid_cell gc; @@ -653,7 +653,7 @@ status_prompt_redraw(struct client *c) return (0); memcpy(&old_status, &c->status, sizeof old_status); screen_init(&c->status, c->tty.sx, 1, 0); - offset = 0; + off = 0; len = strlen(c->prompt_string); if (len > c->tty.sx) @@ -674,7 +674,7 @@ status_prompt_redraw(struct client *c) if (c->prompt_index < left) size = strlen(c->prompt_buffer); else { - offset = c->prompt_index - left - 1; + off = c->prompt_index - left + 1; if (c->prompt_index == strlen(c->prompt_buffer)) left--; size = left; @@ -687,27 +687,27 @@ status_prompt_redraw(struct client *c) screen_write_putc(&ctx, &gc, '*'); } else { screen_write_puts(&ctx, &gc, - "%.*s", (int) left, c->prompt_buffer + offset); + "%.*s", (int) left, c->prompt_buffer + off); } for (i = len + size; i < c->tty.sx; i++) screen_write_putc(&ctx, &gc, ' '); - } - /* Draw a fake cursor. */ - screen_write_cursormove(&ctx, len + c->prompt_index - offset, 0); - if (c->prompt_index == strlen(c->prompt_buffer)) - ch = ' '; - else { - if (c->prompt_flags & PROMPT_HIDDEN) - ch = '*'; - else - ch = c->prompt_buffer[c->prompt_index]; + /* Draw a fake cursor. */ + screen_write_cursormove(&ctx, len + c->prompt_index - off, 0); + if (c->prompt_index == strlen(c->prompt_buffer)) + ch = ' '; + else { + if (c->prompt_flags & PROMPT_HIDDEN) + ch = '*'; + else + ch = c->prompt_buffer[c->prompt_index]; + } + if (ch == '\0') + ch = ' '; + gc.attr ^= GRID_ATTR_REVERSE; + screen_write_putc(&ctx, &gc, ch); } - if (ch == '\0') - ch = ' '; - gc.attr ^= GRID_ATTR_REVERSE; - screen_write_putc(&ctx, &gc, ch); screen_write_stop(&ctx); From 639fbe03922924b70fca7860845590e8c3aa927a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 26 Jul 2009 21:42:08 +0000 Subject: [PATCH 0184/1180] Detect backspace by looking at termios VERASE and translate it into \177 (which matches screen's behaviour if not its termcap/terminfo entry). The terminfo kbs cap is often wrong or missing so it can't be used, and just assuming \177 may be wrong. --- input-keys.c | 3 +++ key-string.c | 2 +- mode-key.c | 6 +++--- tmux.h | 3 +++ tty-keys.c | 12 ++++++++++++ 5 files changed, 22 insertions(+), 4 deletions(-) diff --git a/input-keys.c b/input-keys.c index 0afe6e47..30e2be05 100644 --- a/input-keys.c +++ b/input-keys.c @@ -36,6 +36,9 @@ struct input_key_ent { }; struct input_key_ent input_keys[] = { + /* Backspace key. */ + { KEYC_BSPACE, "\177", 0 }, + /* Function keys. */ { KEYC_F1, "\033OP", INPUTKEY_CTRL|INPUTKEY_XTERM }, { KEYC_F2, "\033OQ", INPUTKEY_CTRL|INPUTKEY_XTERM }, diff --git a/key-string.c b/key-string.c index 23aa6ad7..5c8ce5b3 100644 --- a/key-string.c +++ b/key-string.c @@ -57,7 +57,7 @@ struct { { "PPage", KEYC_PPAGE }, { "Tab", '\011' }, { "BTab", KEYC_BTAB }, - { "BSpace", '\177' }, + { "BSpace", KEYC_BSPACE }, /* Arrow keys. */ { "Up", KEYC_UP }, diff --git a/mode-key.c b/mode-key.c index 9db6d86c..9e5720eb 100644 --- a/mode-key.c +++ b/mode-key.c @@ -70,7 +70,7 @@ mode_key_lookup_vi(struct mode_key_data *mdata, int key) mdata->flags &= ~MODEKEY_EDITMODE; return (MODEKEYCMD_NONE); case '\010': - case '\177': + case KEYC_BSPACE: return (MODEKEYCMD_BACKSPACE); case '\011': return (MODEKEYCMD_COMPLETE); @@ -84,7 +84,7 @@ mode_key_lookup_vi(struct mode_key_data *mdata, int key) switch (key) { case '\010': - case '\177': + case KEYC_BSPACE: return (MODEKEYCMD_LEFT); case KEYC_DC: return (MODEKEYCMD_DELETE); @@ -151,7 +151,7 @@ mode_key_lookup_emacs(struct mode_key_data *mdata, int key) { switch (key) { case '\010': - case '\177': + case KEYC_BSPACE: return (MODEKEYCMD_BACKSPACE); case '\004': case KEYC_DC: diff --git a/tmux.h b/tmux.h index 159711e7..046e6a19 100644 --- a/tmux.h +++ b/tmux.h @@ -121,6 +121,9 @@ enum key_code { /* Mouse key. */ KEYC_MOUSE = 0x1000, + /* Backspace key. */ + KEYC_BSPACE, + /* Function keys. */ KEYC_F1, KEYC_F2, diff --git a/tty-keys.c b/tty-keys.c index 5e207aa6..f25dc169 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -20,6 +20,8 @@ #include #include +#include +#include #include "tmux.h" @@ -235,6 +237,7 @@ tty_keys_next(struct tty *tty, int *key, u_char *mouse) struct timeval tv; char *buf; size_t len, size; + cc_t bspace; buf = BUFFER_OUT(tty->in); len = BUFFER_USED(tty->in); @@ -245,6 +248,15 @@ tty_keys_next(struct tty *tty, int *key, u_char *mouse) /* If a normal key, return it. */ if (*buf != '\033') { *key = buffer_read8(tty->in); + + /* + * Check for backspace key using termios VERASE - the terminfo + * kbs entry is extremely unreliable, so cannot be safely + * used. termios should have a better idea. + */ + bspace = tty->tio.c_cc[VERASE]; + if (bspace != _POSIX_VDISABLE && *key == bspace) + *key = KEYC_BSPACE; goto found; } From 584eda83397b262be01bddff31040e5cf4ff01a1 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 27 Jul 2009 07:42:45 +0000 Subject: [PATCH 0185/1180] Change previous-word behavior to move to the beginning of the word (matches emacs and vi). From Kalle Olavi Niemitalo. --- window-copy.c | 57 +++++++++++++++++++-------------------------------- 1 file changed, 21 insertions(+), 36 deletions(-) diff --git a/window-copy.c b/window-copy.c index aa3e670c..da398d8a 100644 --- a/window-copy.c +++ b/window-copy.c @@ -796,55 +796,40 @@ out: window_copy_set_cursor_x(wp, px); } +/* Move to the previous place where a word begins. */ void window_copy_cursor_previous_word(struct window_pane *wp) { struct window_copy_mode_data *data = wp->modedata; - u_int ox, px, py, skip; + u_int px, py; - ox = px = data->ox + data->cx; + px = data->ox + data->cx; py = screen_hsize(&wp->base) + data->cy - data->oy; - skip = 1; - if (px != 0) { - /* If currently on a space, skip space. */ - if (window_copy_is_space(wp, px - 1, py)) - skip = 0; - } + /* Move back to the previous word character. */ for (;;) { - if (px == 0) { - if (ox != 0) + if (px > 0) { + px--; + if (!window_copy_is_space(wp, px, py)) break; - - while (px == 0) { - if (data->cy == 0 && - (screen_hsize(&wp->base) == 0 || - data->oy >= screen_hsize(&wp->base) - 1)) - goto out; - - window_copy_cursor_up(wp); - - py = screen_hsize( - &wp->base) + data->cy - data->oy; - px = window_copy_find_length(wp, py); - } - goto out; - } - - if (skip) { - /* Currently skipping non-space (until space). */ - if (window_copy_is_space(wp, px - 1, py)) - skip = 0; } else { - /* Currently skipping space (until non-space). */ - if (!window_copy_is_space(wp, px - 1, py)) - break; + if (data->cy == 0 && + (screen_hsize(&wp->base) == 0 || + data->oy >= screen_hsize(&wp->base) - 1)) + goto out; + window_copy_cursor_up(wp); + + py = screen_hsize( + &wp->base) + data->cy - data->oy; + px = window_copy_find_length(wp, py); } - - px--; } -out: + /* Move back to the beginning of this word. */ + while (px > 0 && !window_copy_is_space(wp, px - 1, py)) + px--; + +out: window_copy_set_cursor_x(wp, px); } From fc65da1eed07708030c0ae491cb8f4a6614de390 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 27 Jul 2009 11:33:21 +0000 Subject: [PATCH 0186/1180] Draw UTF-8 characters under the selection correctly. --- screen-write.c | 22 ++++++++++++---------- tty.c | 7 +++++-- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/screen-write.c b/screen-write.c index e2fbfbf4..449c3a35 100644 --- a/screen-write.c +++ b/screen-write.c @@ -723,7 +723,7 @@ screen_write_cell( struct tty_ctx ttyctx; struct grid_utf8 gu, *tmp_gu; u_int width, xx, i; - struct grid_cell tmp_gc, *tmp_gc2; + struct grid_cell tmp_gc, tmp_gc2, *tmp_gcp; int insert = 0; /* Ignore padding. */ @@ -743,11 +743,11 @@ screen_write_cell( if (width == 0) { if (s->cx == 0) return; - tmp_gc2 = grid_view_get_cell(gd, s->cx - 1, s->cy); - if (!(tmp_gc2->flags & GRID_FLAG_UTF8)) { - tmp_gc2->flags |= GRID_FLAG_UTF8; + tmp_gcp = grid_view_get_cell(gd, s->cx - 1, s->cy); + if (!(tmp_gcp->flags & GRID_FLAG_UTF8)) { + tmp_gcp->flags |= GRID_FLAG_UTF8; memset(&gu.data, 0xff, sizeof gu.data); - *gu.data = tmp_gc2->data; + *gu.data = tmp_gcp->data; gu.width = 1; grid_view_set_utf8(gd, s->cx - 1, s->cy, &gu); } @@ -799,9 +799,9 @@ screen_write_cell( * already ensured there is enough room. */ for (xx = s->cx + 1; xx < s->cx + width; xx++) { - tmp_gc2 = grid_view_get_cell(gd, xx, s->cy); - if (tmp_gc2 != NULL) - tmp_gc2->flags |= GRID_FLAG_PADDING; + tmp_gcp = grid_view_get_cell(gd, xx, s->cy); + if (tmp_gcp != NULL) + tmp_gcp->flags |= GRID_FLAG_PADDING; } /* Set the cell. */ @@ -820,8 +820,10 @@ screen_write_cell( } ttyctx.utf8 = &gu; if (screen_check_selection(s, s->cx - width, s->cy)) { - s->sel.cell.data = gc->data; - ttyctx.cell = &s->sel.cell; + memcpy(&tmp_gc2, &s->sel.cell, sizeof tmp_gc2); + tmp_gc2.data = gc->data; + tmp_gc2.flags = gc->flags; + ttyctx.cell = &tmp_gc2; tty_write(tty_cmd_cell, &ttyctx); } else { ttyctx.cell = gc; diff --git a/tty.c b/tty.c index 05342b82..48b10f7d 100644 --- a/tty.c +++ b/tty.c @@ -480,6 +480,7 @@ void tty_draw_line(struct tty *tty, struct screen *s, u_int py, u_int ox, u_int oy) { const struct grid_cell *gc; + struct grid_cell tmpgc; const struct grid_utf8 *gu; u_int i, sx; @@ -498,8 +499,10 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int py, u_int ox, u_int oy) gu = grid_view_peek_utf8(s->grid, i, py); if (screen_check_selection(s, i, py)) { - s->sel.cell.data = gc->data; - tty_cell(tty, &s->sel.cell, gu); + memcpy(&tmpgc, &s->sel.cell, sizeof tmpgc); + tmpgc.data = gc->data; + tmpgc.flags = gc->flags; + tty_cell(tty, &tmpgc, gu); } else tty_cell(tty, gc, gu); } From ad0aad21d5dcc7d8c09a6c76e85ae1e46cf6b0da Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 27 Jul 2009 12:11:11 +0000 Subject: [PATCH 0187/1180] Add a key to delete to end of line at the prompt (^K in emacs mode, C/D in vi). From Kalle Olavi Niemitalo. --- mode-key.c | 8 ++++++++ status.c | 6 ++++++ tmux.1 | 1 + tmux.h | 1 + 4 files changed, 16 insertions(+) diff --git a/mode-key.c b/mode-key.c index 9e5720eb..b037f281 100644 --- a/mode-key.c +++ b/mode-key.c @@ -110,6 +110,12 @@ mode_key_lookup_vi(struct mode_key_data *mdata, int key) return (MODEKEYCMD_BACKTOINDENTATION); case '\033': return (MODEKEYCMD_CLEARSELECTION); + case 'C': + if (mdata->flags & MODEKEY_CANEDIT) + mdata->flags |= MODEKEY_EDITMODE; + return (MODEKEYCMD_DELETETOENDOFLINE); + case 'D': + return (MODEKEYCMD_DELETETOENDOFLINE); case 'j': case KEYC_DOWN: return (MODEKEYCMD_DOWN); @@ -169,6 +175,8 @@ mode_key_lookup_emacs(struct mode_key_data *mdata, int key) case '\027': case 'w' | KEYC_ESCAPE: return (MODEKEYCMD_COPYSELECTION); + case '\013': + return (MODEKEYCMD_DELETETOENDOFLINE); case '\016': case KEYC_DOWN: return (MODEKEYCMD_DOWN); diff --git a/status.c b/status.c index 24d91204..a7aa4a6c 100644 --- a/status.c +++ b/status.c @@ -823,6 +823,12 @@ status_prompt_key(struct client *c, int key) c->flags |= CLIENT_STATUS; } break; + case MODEKEYCMD_DELETETOENDOFLINE: + if (c->prompt_index < size) { + c->prompt_buffer[c->prompt_index] = '\0'; + c->flags |= CLIENT_STATUS; + } + break; case MODEKEYCMD_UP: if (server_locked) break; diff --git a/tmux.1 b/tmux.1 index 54e46a3d..0ba9eec9 100644 --- a/tmux.1 +++ b/tmux.1 @@ -331,6 +331,7 @@ The following keys are supported as appropriate for the mode: .It Li "Cursor right" Ta "l" Ta "Right" .It Li "Start selection" Ta "Space" Ta "C-Space" .It Li "Cursor up" Ta "k" Ta "Up" +.It Li "Delete to end of line" Ta "D or C" Ta "C-k" .It Li "Paste buffer" Ta "p" Ta "C-y" .El .Pp diff --git a/tmux.h b/tmux.h index 046e6a19..01db8690 100644 --- a/tmux.h +++ b/tmux.h @@ -365,6 +365,7 @@ enum mode_key_cmd { MODEKEYCMD_COMPLETE, MODEKEYCMD_COPYSELECTION, MODEKEYCMD_DELETE, + MODEKEYCMD_DELETETOENDOFLINE, MODEKEYCMD_DOWN, MODEKEYCMD_ENDOFLINE, MODEKEYCMD_LEFT, From 13e29dd7b5dfcefdfda6a1dd3c3f78c9cd7f1cc9 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 27 Jul 2009 18:51:46 +0000 Subject: [PATCH 0188/1180] Get rid of empty mode_key_free function. --- mode-key.c | 5 ----- status.c | 2 -- tmux.h | 1 - window-choose.c | 2 -- window-copy.c | 2 -- window-more.c | 2 -- window-scroll.c | 2 -- 7 files changed, 16 deletions(-) diff --git a/mode-key.c b/mode-key.c index b037f281..a4a534b9 100644 --- a/mode-key.c +++ b/mode-key.c @@ -33,11 +33,6 @@ mode_key_init(struct mode_key_data *mdata, int type, int flags) mdata->flags = flags; } -void -mode_key_free(unused struct mode_key_data *mdata) -{ -} - enum mode_key_cmd mode_key_lookup(struct mode_key_data *mdata, int key) { diff --git a/status.c b/status.c index a7aa4a6c..98f7967b 100644 --- a/status.c +++ b/status.c @@ -622,8 +622,6 @@ status_prompt_clear(struct client *c) if (c->prompt_freefn != NULL && c->prompt_data != NULL) c->prompt_freefn(c->prompt_data); - mode_key_free(&c->prompt_mdata); - xfree(c->prompt_string); c->prompt_string = NULL; diff --git a/tmux.h b/tmux.h index 01db8690..3dc82eca 100644 --- a/tmux.h +++ b/tmux.h @@ -1033,7 +1033,6 @@ int load_cfg(const char *, char **x); /* mode-key.c */ void mode_key_init(struct mode_key_data *, int, int); -void mode_key_free(struct mode_key_data *); enum mode_key_cmd mode_key_lookup(struct mode_key_data *, int); /* options.c */ diff --git a/window-choose.c b/window-choose.c index a1f1a069..8439c9a0 100644 --- a/window-choose.c +++ b/window-choose.c @@ -140,8 +140,6 @@ window_choose_free(struct window_pane *wp) if (data->freefn != NULL && data->data != NULL) data->freefn(data->data); - mode_key_free(&data->mdata); - for (i = 0; i < ARRAY_LENGTH(&data->list); i++) xfree(ARRAY_ITEM(&data->list, i).name); ARRAY_FREE(&data->list); diff --git a/window-copy.c b/window-copy.c index da398d8a..d87a645e 100644 --- a/window-copy.c +++ b/window-copy.c @@ -125,8 +125,6 @@ window_copy_free(struct window_pane *wp) { struct window_copy_mode_data *data = wp->modedata; - mode_key_free(&data->mdata); - screen_free(&data->screen); xfree(data); } diff --git a/window-more.c b/window-more.c index 6f75f120..d92a06a2 100644 --- a/window-more.c +++ b/window-more.c @@ -101,8 +101,6 @@ window_more_free(struct window_pane *wp) struct window_more_mode_data *data = wp->modedata; u_int i; - mode_key_free(&data->mdata); - for (i = 0; i < ARRAY_LENGTH(&data->list); i++) xfree(ARRAY_ITEM(&data->list, i)); ARRAY_FREE(&data->list); diff --git a/window-scroll.c b/window-scroll.c index 9db91ebd..ecc76306 100644 --- a/window-scroll.c +++ b/window-scroll.c @@ -88,8 +88,6 @@ window_scroll_free(struct window_pane *wp) { struct window_scroll_mode_data *data = wp->modedata; - mode_key_free(&data->mdata); - screen_free(&data->screen); xfree(data); } From d95274c5f294ddf1341f66019fee47a35b4f2561 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 27 Jul 2009 19:29:35 +0000 Subject: [PATCH 0189/1180] Change mode key bindings from big switches into a set of tables. Rather than lumping them all together, split editing keys from those used in choice/more mode and those for copy/scroll mode. Tidier and clearer, and the first step towards customisable mode keys. --- mode-key.c | 350 +++++++++++++++++++++++------------------------- status.c | 40 +++--- tmux.h | 100 +++++++++----- window-choose.c | 22 +-- window-copy.c | 38 +++--- window-more.c | 18 ++- window-scroll.c | 22 +-- 7 files changed, 316 insertions(+), 274 deletions(-) diff --git a/mode-key.c b/mode-key.c index a4a534b9..58769eda 100644 --- a/mode-key.c +++ b/mode-key.c @@ -20,198 +20,182 @@ #include "tmux.h" -enum mode_key_cmd mode_key_lookup_vi(struct mode_key_data *, int); -enum mode_key_cmd mode_key_lookup_emacs(struct mode_key_data *, int); +/* vi editing keys. */ +const struct mode_key_entry mode_key_vi_edit[] = { + { '\003' /* C-c */, 0, MODEKEYEDIT_CANCEL }, + { '\010' /* C-h */, 0, MODEKEYEDIT_BACKSPACE }, + { '\011' /* Tab */, 0, MODEKEYEDIT_COMPLETE }, + { '\033' /* Escape */, 0, MODEKEYEDIT_SWITCHMODE }, + { '\r', 0, MODEKEYEDIT_ENTER }, + { KEYC_BSPACE, 0, MODEKEYEDIT_BACKSPACE }, + { KEYC_DC, 0, MODEKEYEDIT_DELETE }, + + { '$', 1, MODEKEYEDIT_ENDOFLINE }, + { '0', 1, MODEKEYEDIT_STARTOFLINE }, + { 'D', 1, MODEKEYEDIT_DELETETOENDOFLINE }, + { '\003' /* C-c */, 1, MODEKEYEDIT_CANCEL }, + { '\010' /* C-h */, 1, MODEKEYEDIT_BACKSPACE }, + { '\r', 1, MODEKEYEDIT_ENTER }, + { '^', 1, MODEKEYEDIT_STARTOFLINE }, + { 'a', 1, MODEKEYEDIT_SWITCHMODEAPPEND }, + { 'h', 1, MODEKEYEDIT_CURSORLEFT }, + { 'i', 1, MODEKEYEDIT_SWITCHMODE }, + { 'j', 1, MODEKEYEDIT_HISTORYDOWN }, + { 'k', 1, MODEKEYEDIT_HISTORYUP }, + { 'l', 1, MODEKEYEDIT_CURSORRIGHT }, + { 'p', 1, MODEKEYEDIT_PASTE }, + { KEYC_BSPACE, 1, MODEKEYEDIT_BACKSPACE }, + { KEYC_DC, 1, MODEKEYEDIT_DELETE }, + { KEYC_DOWN, 1, MODEKEYEDIT_HISTORYDOWN }, + { KEYC_LEFT, 1, MODEKEYEDIT_CURSORLEFT }, + { KEYC_RIGHT, 1, MODEKEYEDIT_CURSORRIGHT }, + { KEYC_UP, 1, MODEKEYEDIT_HISTORYUP }, + + { 0, -1, 0 } +}; + +/* vi choice selection keys. */ +const struct mode_key_entry mode_key_vi_choice[] = { + { '\003' /* C-c */, 0, MODEKEYCHOICE_CANCEL }, + { '\r', 0, MODEKEYCHOICE_CHOOSE }, + { 'j', 0, MODEKEYCHOICE_DOWN }, + { 'k', 0, MODEKEYCHOICE_UP }, + { 'q', 0, MODEKEYCHOICE_CANCEL }, + { KEYC_DOWN, 0, MODEKEYCHOICE_DOWN }, + { KEYC_NPAGE, 0, MODEKEYCHOICE_PAGEDOWN }, + { KEYC_PPAGE, 0, MODEKEYCHOICE_PAGEUP }, + { KEYC_UP, 0, MODEKEYCHOICE_UP }, + + { 0, -1, 0 } +}; + +/* vi copy mode keys. */ +const struct mode_key_entry mode_key_vi_copy[] = { + { ' ', 0, MODEKEYCOPY_STARTSELECTION }, + { '$', 0, MODEKEYCOPY_ENDOFLINE }, + { '0', 0, MODEKEYCOPY_STARTOFLINE }, + { '\003' /* C-c */, 0, MODEKEYCOPY_QUIT }, + { '\006' /* C-f */, 0, MODEKEYCOPY_NEXTPAGE }, + { '\010' /* C-h */, 0, MODEKEYCOPY_LEFT }, + { '\025' /* C-u */, 0, MODEKEYCOPY_PREVIOUSPAGE }, + { '\033' /* Escape */, 0, MODEKEYCOPY_CLEARSELECTION }, + { '\r', 0, MODEKEYCOPY_COPYSELECTION }, + { '^', 0, MODEKEYCOPY_BACKTOINDENTATION }, + { 'b', 0, MODEKEYCOPY_PREVIOUSWORD }, + { 'h', 0, MODEKEYCOPY_LEFT }, + { 'j', 0, MODEKEYCOPY_DOWN }, + { 'k', 0, MODEKEYCOPY_UP }, + { 'l', 0, MODEKEYCOPY_RIGHT }, + { 'q', 0, MODEKEYCOPY_QUIT }, + { 'w', 0, MODEKEYCOPY_NEXTWORD }, + { KEYC_BSPACE, 0, MODEKEYCOPY_LEFT }, + { KEYC_DOWN, 0, MODEKEYCOPY_DOWN }, + { KEYC_LEFT, 0, MODEKEYCOPY_LEFT }, + { KEYC_NPAGE, 0, MODEKEYCOPY_NEXTPAGE }, + { KEYC_PPAGE, 0, MODEKEYCOPY_PREVIOUSPAGE }, + { KEYC_RIGHT, 0, MODEKEYCOPY_RIGHT }, + { KEYC_UP, 0, MODEKEYCOPY_UP }, + + { 0, -1, 0 } +}; + +/* emacs editing keys. */ +const struct mode_key_entry mode_key_emacs_edit[] = { + { '\001' /* C-a */, 0, MODEKEYEDIT_STARTOFLINE }, + { '\002' /* C-p */, 0, MODEKEYEDIT_CURSORLEFT }, + { '\004' /* C-d */, 0, MODEKEYEDIT_DELETE }, + { '\005' /* C-e */, 0, MODEKEYEDIT_ENDOFLINE }, + { '\006' /* C-f */, 0, MODEKEYEDIT_CURSORRIGHT }, + { '\010' /* C-H */, 0, MODEKEYEDIT_BACKSPACE }, + { '\011' /* Tab */, 0, MODEKEYEDIT_COMPLETE }, + { '\013' /* C-k */, 0, MODEKEYEDIT_DELETETOENDOFLINE }, + { '\016' /* C-n */, 0, MODEKEYEDIT_HISTORYDOWN }, + { '\020' /* C-p */, 0, MODEKEYEDIT_HISTORYUP }, + { '\031' /* C-y */, 0, MODEKEYEDIT_PASTE }, + { '\r', 0, MODEKEYEDIT_ENTER }, + { 'm' | KEYC_ESCAPE, 0, MODEKEYEDIT_STARTOFLINE }, + { KEYC_BSPACE, 0, MODEKEYEDIT_BACKSPACE }, + { KEYC_DC, 0, MODEKEYEDIT_DELETE }, + { KEYC_DOWN, 0, MODEKEYEDIT_HISTORYDOWN }, + { KEYC_LEFT, 0, MODEKEYEDIT_CURSORLEFT }, + { KEYC_RIGHT, 0, MODEKEYEDIT_CURSORRIGHT }, + { KEYC_UP, 0, MODEKEYEDIT_HISTORYUP }, + + { 0, -1, 0 } +}; + +/* emacs choice selection keys. */ +const struct mode_key_entry mode_key_emacs_choice[] = { + { '\003' /* C-c */, 0, MODEKEYCHOICE_CANCEL }, + { '\033' /* Escape */, 0, MODEKEYCHOICE_CANCEL }, + { '\r', 0, MODEKEYCHOICE_CHOOSE }, + { 'q', 0, MODEKEYCHOICE_CANCEL }, + { KEYC_DOWN, 0, MODEKEYCHOICE_DOWN }, + { KEYC_NPAGE, 0, MODEKEYCHOICE_PAGEDOWN }, + { KEYC_PPAGE, 0, MODEKEYCHOICE_PAGEUP }, + { KEYC_UP, 0, MODEKEYCHOICE_UP }, + + { 0, -1, 0 } +}; + +/* emacs copy mode keys. */ +const struct mode_key_entry mode_key_emacs_copy[] = { + { ' ', 0, MODEKEYCOPY_NEXTPAGE }, + { '\000' /* C-Space */, 0, MODEKEYCOPY_STARTSELECTION }, + { '\001' /* C-a */, 0, MODEKEYCOPY_STARTOFLINE }, + { '\002' /* C-b */, 0, MODEKEYCOPY_LEFT }, + { '\003' /* C-c */, 0, MODEKEYCOPY_QUIT }, + { '\005' /* C-e */, 0, MODEKEYCOPY_ENDOFLINE }, + { '\006' /* C-f */, 0, MODEKEYCOPY_RIGHT }, + { '\007' /* C-g */, 0, MODEKEYCOPY_CLEARSELECTION }, + { '\016' /* C-n */, 0, MODEKEYCOPY_DOWN }, + { '\020' /* C-p */, 0, MODEKEYCOPY_UP }, + { '\026' /* C-v */, 0, MODEKEYCOPY_NEXTPAGE }, + { '\027' /* C-w */, 0, MODEKEYCOPY_COPYSELECTION }, + { '\033' /* Escape */, 0, MODEKEYCOPY_QUIT }, + { 'b' | KEYC_ESCAPE, 0, MODEKEYCOPY_PREVIOUSWORD }, + { 'f' | KEYC_ESCAPE, 0, MODEKEYCOPY_NEXTWORD }, + { 'm' | KEYC_ESCAPE, 0, MODEKEYCOPY_BACKTOINDENTATION }, + { 'q', 0, MODEKEYCOPY_QUIT }, + { 'v' | KEYC_ESCAPE, 0, MODEKEYCOPY_PREVIOUSPAGE }, + { 'w' | KEYC_ESCAPE, 0, MODEKEYCOPY_COPYSELECTION }, + { KEYC_DOWN, 0, MODEKEYCOPY_DOWN }, + { KEYC_LEFT, 0, MODEKEYCOPY_LEFT }, + { KEYC_NPAGE, 0, MODEKEYCOPY_NEXTPAGE }, + { KEYC_PPAGE, 0, MODEKEYCOPY_PREVIOUSPAGE }, + { KEYC_RIGHT, 0, MODEKEYCOPY_RIGHT }, + { KEYC_UP, 0, MODEKEYCOPY_UP }, + + { 0, -1, 0 } +}; void -mode_key_init(struct mode_key_data *mdata, int type, int flags) +mode_key_init(struct mode_key_data *mdata, const struct mode_key_entry *table) { - mdata->type = type; - - if (flags & MODEKEY_CANEDIT) - flags |= MODEKEY_EDITMODE; - mdata->flags = flags; + mdata->table = table; + mdata->mode = 0; } enum mode_key_cmd mode_key_lookup(struct mode_key_data *mdata, int key) { - switch (mdata->type) { - case MODEKEY_VI: - return (mode_key_lookup_vi(mdata, key)); - case MODEKEY_EMACS: - return (mode_key_lookup_emacs(mdata, key)); - default: - fatalx("unknown mode key type"); - } -} + const struct mode_key_entry *ment; + int mode; -enum mode_key_cmd -mode_key_lookup_vi(struct mode_key_data *mdata, int key) -{ - if (key & KEYC_ESCAPE) { - key &= ~KEYC_ESCAPE; - if (mdata->flags & MODEKEY_CANEDIT) - mdata->flags ^= MODEKEY_EDITMODE; - } - - - if (mdata->flags & MODEKEY_EDITMODE) { - switch (key) { - case '\003': - return (MODEKEYCMD_QUIT); - case '\033': - if (mdata->flags & MODEKEY_CANEDIT) - mdata->flags &= ~MODEKEY_EDITMODE; - return (MODEKEYCMD_NONE); - case '\010': - case KEYC_BSPACE: - return (MODEKEYCMD_BACKSPACE); - case '\011': - return (MODEKEYCMD_COMPLETE); - case KEYC_DC: - return (MODEKEYCMD_DELETE); - case '\r': - return (MODEKEYCMD_CHOOSE); + mode = mdata->mode; + for (ment = mdata->table; ment->mode != -1; ment++) { + if (ment->mode == mode && key == ment->key) { + switch (ment->cmd) { + case MODEKEYEDIT_SWITCHMODE: + case MODEKEYEDIT_SWITCHMODEAPPEND: + mdata->mode = 1 - mdata->mode; + /* FALLTHROUGH */ + default: + return (ment->cmd); + } } - return (MODEKEYCMD_OTHERKEY); } - - switch (key) { - case '\010': - case KEYC_BSPACE: - return (MODEKEYCMD_LEFT); - case KEYC_DC: - return (MODEKEYCMD_DELETE); - case '\011': - return (MODEKEYCMD_COMPLETE); - case 'i': - if (mdata->flags & MODEKEY_CANEDIT) - mdata->flags |= MODEKEY_EDITMODE; - break; - case 'a': - if (mdata->flags & MODEKEY_CANEDIT) { - mdata->flags |= MODEKEY_EDITMODE; - return (MODEKEYCMD_RIGHT); - } - break; - case '\r': - if (mdata->flags & (MODEKEY_CANEDIT|MODEKEY_CHOOSEMODE)) - return (MODEKEYCMD_CHOOSE); - return (MODEKEYCMD_COPYSELECTION); - case '0': - return (MODEKEYCMD_STARTOFLINE); - case '^': - return (MODEKEYCMD_BACKTOINDENTATION); - case '\033': - return (MODEKEYCMD_CLEARSELECTION); - case 'C': - if (mdata->flags & MODEKEY_CANEDIT) - mdata->flags |= MODEKEY_EDITMODE; - return (MODEKEYCMD_DELETETOENDOFLINE); - case 'D': - return (MODEKEYCMD_DELETETOENDOFLINE); - case 'j': - case KEYC_DOWN: - return (MODEKEYCMD_DOWN); - case '$': - return (MODEKEYCMD_ENDOFLINE); - case 'h': - case KEYC_LEFT: - return (MODEKEYCMD_LEFT); - case '\006': - case KEYC_NPAGE: - return (MODEKEYCMD_NEXTPAGE); - case 'w': - return (MODEKEYCMD_NEXTWORD); - case '\025': - case KEYC_PPAGE: - return (MODEKEYCMD_PREVIOUSPAGE); - case 'b': - return (MODEKEYCMD_PREVIOUSWORD); - case 'q': - case '\003': - return (MODEKEYCMD_QUIT); - case 'l': - case KEYC_RIGHT: - return (MODEKEYCMD_RIGHT); - case ' ': - return (MODEKEYCMD_STARTSELECTION); - case 'k': - case KEYC_UP: - return (MODEKEYCMD_UP); - case 'p': - return (MODEKEYCMD_PASTE); - } - - return (MODEKEYCMD_NONE); -} - -enum mode_key_cmd -mode_key_lookup_emacs(struct mode_key_data *mdata, int key) -{ - switch (key) { - case '\010': - case KEYC_BSPACE: - return (MODEKEYCMD_BACKSPACE); - case '\004': - case KEYC_DC: - return (MODEKEYCMD_DELETE); - case '\011': - return (MODEKEYCMD_COMPLETE); - case '\r': - return (MODEKEYCMD_CHOOSE); - case '\001': - return (MODEKEYCMD_STARTOFLINE); - case 'm' | KEYC_ESCAPE: - return (MODEKEYCMD_BACKTOINDENTATION); - case '\007': - return (MODEKEYCMD_CLEARSELECTION); - case '\027': - case 'w' | KEYC_ESCAPE: - return (MODEKEYCMD_COPYSELECTION); - case '\013': - return (MODEKEYCMD_DELETETOENDOFLINE); - case '\016': - case KEYC_DOWN: - return (MODEKEYCMD_DOWN); - case '\005': - return (MODEKEYCMD_ENDOFLINE); - case '\002': - case KEYC_LEFT: - return (MODEKEYCMD_LEFT); - case ' ': - if (mdata->flags & MODEKEY_CANEDIT) - break; - /* FALLTHROUGH */ - case '\026': - case KEYC_NPAGE: - return (MODEKEYCMD_NEXTPAGE); - case 'f' | KEYC_ESCAPE: - return (MODEKEYCMD_NEXTWORD); - case '\031': - return (MODEKEYCMD_PASTE); - case 'v' | KEYC_ESCAPE: - case KEYC_PPAGE: - return (MODEKEYCMD_PREVIOUSPAGE); - case 'b' | KEYC_ESCAPE: - return (MODEKEYCMD_PREVIOUSWORD); - case '\006': - case KEYC_RIGHT: - return (MODEKEYCMD_RIGHT); - case '\000': - return (MODEKEYCMD_STARTSELECTION); - case '\020': - case KEYC_UP: - return (MODEKEYCMD_UP); - case 'q': - if (mdata->flags & MODEKEY_CANEDIT) - break; - /* FALLTHROUGH */ - case '\003': - case '\033': - return (MODEKEYCMD_QUIT); - } - - return (MODEKEYCMD_OTHERKEY); + if (mode != 0) + return (MODEKEY_NONE); + return (MODEKEY_OTHER); } diff --git a/status.c b/status.c index 98f7967b..fef440eb 100644 --- a/status.c +++ b/status.c @@ -589,6 +589,8 @@ status_prompt_set(struct client *c, const char *msg, int (*callbackfn)(void *, const char *), void (*freefn)(void *), void *data, int flags) { + int keys; + status_message_clear(c); status_prompt_clear(c); @@ -605,9 +607,11 @@ status_prompt_set(struct client *c, const char *msg, c->prompt_flags = flags; - mode_key_init(&c->prompt_mdata, - options_get_number(&c->session->options, "status-keys"), - MODEKEY_CANEDIT); + keys = options_get_number(&c->session->options, "status-keys"); + if (keys == MODEKEY_EMACS) + mode_key_init(&c->prompt_mdata, mode_key_emacs_edit); + else + mode_key_init(&c->prompt_mdata, mode_key_vi_edit); c->tty.flags |= (TTY_NOCURSOR|TTY_FREEZE); c->flags |= CLIENT_STATUS; @@ -727,32 +731,32 @@ status_prompt_key(struct client *c, int key) size = strlen(c->prompt_buffer); switch (mode_key_lookup(&c->prompt_mdata, key)) { - case MODEKEYCMD_LEFT: + case MODEKEYEDIT_CURSORLEFT: if (c->prompt_index > 0) { c->prompt_index--; c->flags |= CLIENT_STATUS; } break; - case MODEKEYCMD_RIGHT: + case MODEKEYEDIT_SWITCHMODEAPPEND: + case MODEKEYEDIT_CURSORRIGHT: if (c->prompt_index < size) { c->prompt_index++; c->flags |= CLIENT_STATUS; } break; - case MODEKEYCMD_STARTOFLINE: - case MODEKEYCMD_BACKTOINDENTATION: + case MODEKEYEDIT_STARTOFLINE: if (c->prompt_index != 0) { c->prompt_index = 0; c->flags |= CLIENT_STATUS; } break; - case MODEKEYCMD_ENDOFLINE: + case MODEKEYEDIT_ENDOFLINE: if (c->prompt_index != size) { c->prompt_index = size; c->flags |= CLIENT_STATUS; } break; - case MODEKEYCMD_COMPLETE: + case MODEKEYEDIT_COMPLETE: if (*c->prompt_buffer == '\0') break; @@ -800,7 +804,7 @@ status_prompt_key(struct client *c, int key) c->flags |= CLIENT_STATUS; break; - case MODEKEYCMD_BACKSPACE: + case MODEKEYEDIT_BACKSPACE: if (c->prompt_index != 0) { if (c->prompt_index == size) c->prompt_buffer[--c->prompt_index] = '\0'; @@ -813,7 +817,7 @@ status_prompt_key(struct client *c, int key) c->flags |= CLIENT_STATUS; } break; - case MODEKEYCMD_DELETE: + case MODEKEYEDIT_DELETE: if (c->prompt_index != size) { memmove(c->prompt_buffer + c->prompt_index, c->prompt_buffer + c->prompt_index + 1, @@ -821,13 +825,13 @@ status_prompt_key(struct client *c, int key) c->flags |= CLIENT_STATUS; } break; - case MODEKEYCMD_DELETETOENDOFLINE: + case MODEKEYEDIT_DELETETOENDOFLINE: if (c->prompt_index < size) { c->prompt_buffer[c->prompt_index] = '\0'; c->flags |= CLIENT_STATUS; } break; - case MODEKEYCMD_UP: + case MODEKEYEDIT_HISTORYUP: if (server_locked) break; @@ -845,7 +849,7 @@ status_prompt_key(struct client *c, int key) c->prompt_index = strlen(c->prompt_buffer); c->flags |= CLIENT_STATUS; break; - case MODEKEYCMD_DOWN: + case MODEKEYEDIT_HISTORYDOWN: if (server_locked) break; @@ -864,7 +868,7 @@ status_prompt_key(struct client *c, int key) c->prompt_index = strlen(c->prompt_buffer); c->flags |= CLIENT_STATUS; break; - case MODEKEYCMD_PASTE: + case MODEKEYEDIT_PASTE: if ((pb = paste_get_top(&c->session->buffers)) == NULL) break; if ((last = strchr(pb->data, '\n')) == NULL) @@ -886,7 +890,7 @@ status_prompt_key(struct client *c, int key) c->flags |= CLIENT_STATUS; break; - case MODEKEYCMD_CHOOSE: + case MODEKEYEDIT_ENTER: if (*c->prompt_buffer != '\0') { status_prompt_add_history(c); if (c->prompt_callbackfn( @@ -895,11 +899,11 @@ status_prompt_key(struct client *c, int key) break; } /* FALLTHROUGH */ - case MODEKEYCMD_QUIT: + case MODEKEYEDIT_CANCEL: if (c->prompt_callbackfn(c->prompt_data, NULL) == 0) status_prompt_clear(c); break; - case MODEKEYCMD_OTHERKEY: + case MODEKEY_OTHER: if (key < 32 || key > 126) break; c->prompt_buffer = xrealloc(c->prompt_buffer, 1, size + 2); diff --git a/tmux.h b/tmux.h index 3dc82eca..505e3d68 100644 --- a/tmux.h +++ b/tmux.h @@ -358,40 +358,71 @@ struct msg_unlock_data { /* Editing keys. */ enum mode_key_cmd { - MODEKEYCMD_BACKSPACE = 0x1000, - MODEKEYCMD_BACKTOINDENTATION, - MODEKEYCMD_CHOOSE, - MODEKEYCMD_CLEARSELECTION, - MODEKEYCMD_COMPLETE, - MODEKEYCMD_COPYSELECTION, - MODEKEYCMD_DELETE, - MODEKEYCMD_DELETETOENDOFLINE, - MODEKEYCMD_DOWN, - MODEKEYCMD_ENDOFLINE, - MODEKEYCMD_LEFT, - MODEKEYCMD_NEXTPAGE, - MODEKEYCMD_NEXTWORD, - MODEKEYCMD_NONE, - MODEKEYCMD_OTHERKEY, - MODEKEYCMD_PASTE, - MODEKEYCMD_PREVIOUSPAGE, - MODEKEYCMD_PREVIOUSWORD, - MODEKEYCMD_QUIT, - MODEKEYCMD_RIGHT, - MODEKEYCMD_STARTOFLINE, - MODEKEYCMD_STARTSELECTION, - MODEKEYCMD_UP, + MODEKEY_NONE, + MODEKEY_OTHER, + + /* Editing keys. */ + MODEKEYEDIT_BACKSPACE, + MODEKEYEDIT_CANCEL, + MODEKEYEDIT_COMPLETE, + MODEKEYEDIT_CURSORLEFT, + MODEKEYEDIT_CURSORRIGHT, + MODEKEYEDIT_DELETE, + MODEKEYEDIT_DELETETOENDOFLINE, + MODEKEYEDIT_ENDOFLINE, + MODEKEYEDIT_ENTER, + MODEKEYEDIT_HISTORYDOWN, + MODEKEYEDIT_HISTORYUP, + MODEKEYEDIT_PASTE, + MODEKEYEDIT_STARTOFLINE, + MODEKEYEDIT_SWITCHMODE, + MODEKEYEDIT_SWITCHMODEAPPEND, + + /* Menu (choice) keys. */ + MODEKEYCHOICE_CANCEL, + MODEKEYCHOICE_CHOOSE, + MODEKEYCHOICE_DOWN, + MODEKEYCHOICE_PAGEDOWN, + MODEKEYCHOICE_PAGEUP, + MODEKEYCHOICE_UP, + + /* Copy keys. */ + MODEKEYCOPY_CANCEL, + MODEKEYCOPY_BACKTOINDENTATION, + MODEKEYCOPY_CLEARSELECTION, + MODEKEYCOPY_COPYSELECTION, + MODEKEYCOPY_DOWN, + MODEKEYCOPY_ENDOFLINE, + MODEKEYCOPY_LEFT, + MODEKEYCOPY_NEXTPAGE, + MODEKEYCOPY_NEXTWORD, + MODEKEYCOPY_NONE, + MODEKEYCOPY_PREVIOUSPAGE, + MODEKEYCOPY_PREVIOUSWORD, + MODEKEYCOPY_QUIT, + MODEKEYCOPY_RIGHT, + MODEKEYCOPY_STARTOFLINE, + MODEKEYCOPY_STARTSELECTION, + MODEKEYCOPY_UP, }; +struct mode_key_entry { + int key; + + /* + * Editing mode for vi: 0 is edit mode, keys not in the table are + * returned as MODEKEY_OTHER; 1 is command mode, keys not in the table + * are returned as MODEKEY_NONE. This is also matched on, allowing some + * keys to be bound in edit mode. + */ + int mode; + + enum mode_key_cmd cmd; +}; struct mode_key_data { - int type; - - int flags; -#define MODEKEY_EDITMODE 0x1 -#define MODEKEY_CANEDIT 0x2 -#define MODEKEY_CHOOSEMODE 0x4 + const struct mode_key_entry *table; + int mode; }; - #define MODEKEY_EMACS 0 #define MODEKEY_VI 1 @@ -1032,7 +1063,14 @@ void sighandler(int); int load_cfg(const char *, char **x); /* mode-key.c */ -void mode_key_init(struct mode_key_data *, int, int); +extern const struct mode_key_entry mode_key_vi_edit[]; +extern const struct mode_key_entry mode_key_vi_choice[]; +extern const struct mode_key_entry mode_key_vi_copy[]; +extern const struct mode_key_entry mode_key_emacs_edit[]; +extern const struct mode_key_entry mode_key_emacs_choice[]; +extern const struct mode_key_entry mode_key_emacs_copy[]; +void mode_key_init( + struct mode_key_data *, const struct mode_key_entry *); enum mode_key_cmd mode_key_lookup(struct mode_key_data *, int); /* options.c */ diff --git a/window-choose.c b/window-choose.c index 8439c9a0..b1ae3bc5 100644 --- a/window-choose.c +++ b/window-choose.c @@ -109,6 +109,7 @@ window_choose_init(struct window_pane *wp) { struct window_choose_mode_data *data; struct screen *s; + int keys; wp->modedata = data = xmalloc(sizeof *data); @@ -124,9 +125,11 @@ window_choose_init(struct window_pane *wp) s->mode &= ~MODE_CURSOR; s->mode |= MODE_MOUSE; - mode_key_init(&data->mdata, - options_get_number(&wp->window->options, "mode-keys"), - MODEKEY_CHOOSEMODE); + keys = options_get_number(&wp->window->options, "mode-keys"); + if (keys == MODEKEY_EMACS) + mode_key_init(&data->mdata, mode_key_emacs_choice); + else + mode_key_init(&data->mdata, mode_key_vi_choice); return (s); } @@ -174,16 +177,16 @@ window_choose_key(struct window_pane *wp, unused struct client *c, int key) items = ARRAY_LENGTH(&data->list); switch (mode_key_lookup(&data->mdata, key)) { - case MODEKEYCMD_QUIT: + case MODEKEYCHOICE_CANCEL: data->callbackfn(data->data, -1); window_pane_reset_mode(wp); break; - case MODEKEYCMD_CHOOSE: + case MODEKEYCHOICE_CHOOSE: item = &ARRAY_ITEM(&data->list, data->selected); data->callbackfn(data->data, item->idx); window_pane_reset_mode(wp); break; - case MODEKEYCMD_UP: + case MODEKEYCHOICE_UP: if (items == 0) break; if (data->selected == 0) { @@ -205,7 +208,7 @@ window_choose_key(struct window_pane *wp, unused struct client *c, int key) screen_write_stop(&ctx); } break; - case MODEKEYCMD_DOWN: + case MODEKEYCHOICE_DOWN: if (items == 0) break; if (data->selected == items - 1) { @@ -215,6 +218,7 @@ window_choose_key(struct window_pane *wp, unused struct client *c, int key) break; } data->selected++; + if (data->selected >= data->top + screen_size_y(&data->screen)) window_choose_scroll_down(wp); else { @@ -226,7 +230,7 @@ window_choose_key(struct window_pane *wp, unused struct client *c, int key) screen_write_stop(&ctx); } break; - case MODEKEYCMD_PREVIOUSPAGE: + case MODEKEYCHOICE_PAGEUP: if (data->selected < screen_size_y(s)) { data->selected = 0; data->top = 0; @@ -239,7 +243,7 @@ window_choose_key(struct window_pane *wp, unused struct client *c, int key) } window_choose_redraw_screen(wp); break; - case MODEKEYCMD_NEXTPAGE: + case MODEKEYCHOICE_PAGEDOWN: data->selected += screen_size_y(s); if (data->selected > items - 1) data->selected = items - 1; diff --git a/window-copy.c b/window-copy.c index d87a645e..7ca4cd34 100644 --- a/window-copy.c +++ b/window-copy.c @@ -94,6 +94,7 @@ window_copy_init(struct window_pane *wp) struct screen *s; struct screen_write_ctx ctx; u_int i; + int keys; wp->modedata = data = xmalloc(sizeof *data); data->ox = 0; @@ -105,8 +106,11 @@ window_copy_init(struct window_pane *wp) screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0); s->mode |= MODE_MOUSE; - mode_key_init(&data->mdata, - options_get_number(&wp->window->options, "mode-keys"), 0); + keys = options_get_number(&wp->window->options, "mode-keys"); + if (keys == MODEKEY_EMACS) + mode_key_init(&data->mdata, mode_key_emacs_copy); + else + mode_key_init(&data->mdata, mode_key_vi_copy); s->cx = data->cx; s->cy = data->cy; @@ -164,25 +168,25 @@ window_copy_key(struct window_pane *wp, struct client *c, int key) struct screen *s = &data->screen; switch (mode_key_lookup(&data->mdata, key)) { - case MODEKEYCMD_QUIT: + case MODEKEYCOPY_QUIT: window_pane_reset_mode(wp); break; - case MODEKEYCMD_LEFT: + case MODEKEYCOPY_LEFT: window_copy_cursor_left(wp); return; - case MODEKEYCMD_RIGHT: + case MODEKEYCOPY_RIGHT: window_copy_cursor_right(wp); return; - case MODEKEYCMD_UP: + case MODEKEYCOPY_UP: window_copy_cursor_up(wp); return; - case MODEKEYCMD_DOWN: + case MODEKEYCOPY_DOWN: window_copy_cursor_down(wp); return; - case MODEKEYCMD_PREVIOUSPAGE: + case MODEKEYCOPY_PREVIOUSPAGE: window_copy_pageup(wp); break; - case MODEKEYCMD_NEXTPAGE: + case MODEKEYCOPY_NEXTPAGE: if (data->oy < screen_size_y(s)) data->oy = 0; else @@ -190,33 +194,33 @@ window_copy_key(struct window_pane *wp, struct client *c, int key) window_copy_update_selection(wp); window_copy_redraw_screen(wp); break; - case MODEKEYCMD_STARTSELECTION: + case MODEKEYCOPY_STARTSELECTION: window_copy_start_selection(wp); window_copy_redraw_screen(wp); break; - case MODEKEYCMD_CLEARSELECTION: + case MODEKEYCOPY_CLEARSELECTION: screen_clear_selection(&data->screen); window_copy_redraw_screen(wp); break; - case MODEKEYCMD_COPYSELECTION: + case MODEKEYCOPY_COPYSELECTION: if (c != NULL && c->session != NULL) { window_copy_copy_selection(wp, c); window_pane_reset_mode(wp); } break; - case MODEKEYCMD_STARTOFLINE: + case MODEKEYCOPY_STARTOFLINE: window_copy_cursor_start_of_line(wp); break; - case MODEKEYCMD_BACKTOINDENTATION: + case MODEKEYCOPY_BACKTOINDENTATION: window_copy_cursor_back_to_indentation(wp); break; - case MODEKEYCMD_ENDOFLINE: + case MODEKEYCOPY_ENDOFLINE: window_copy_cursor_end_of_line(wp); break; - case MODEKEYCMD_NEXTWORD: + case MODEKEYCOPY_NEXTWORD: window_copy_cursor_next_word(wp); break; - case MODEKEYCMD_PREVIOUSWORD: + case MODEKEYCOPY_PREVIOUSWORD: window_copy_cursor_previous_word(wp); break; default: diff --git a/window-more.c b/window-more.c index d92a06a2..a113c4ba 100644 --- a/window-more.c +++ b/window-more.c @@ -80,6 +80,7 @@ window_more_init(struct window_pane *wp) { struct window_more_mode_data *data; struct screen *s; + int keys; wp->modedata = data = xmalloc(sizeof *data); ARRAY_INIT(&data->list); @@ -89,8 +90,11 @@ window_more_init(struct window_pane *wp) screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0); s->mode &= ~MODE_CURSOR; - mode_key_init(&data->mdata, - options_get_number(&wp->window->options, "mode-keys"), 0); + keys = options_get_number(&wp->window->options, "mode-keys"); + if (keys == MODEKEY_EMACS) + mode_key_init(&data->mdata, mode_key_emacs_choice); + else + mode_key_init(&data->mdata, mode_key_vi_choice); return (s); } @@ -126,23 +130,23 @@ window_more_key(struct window_pane *wp, unused struct client *c, int key) struct screen *s = &data->screen; switch (mode_key_lookup(&data->mdata, key)) { - case MODEKEYCMD_QUIT: + case MODEKEYCHOICE_CANCEL: window_pane_reset_mode(wp); break; - case MODEKEYCMD_UP: + case MODEKEYCHOICE_UP: window_more_scroll_up(wp); break; - case MODEKEYCMD_DOWN: + case MODEKEYCHOICE_DOWN: window_more_scroll_down(wp); break; - case MODEKEYCMD_PREVIOUSPAGE: + case MODEKEYCHOICE_PAGEUP: if (data->top < screen_size_y(s)) data->top = 0; else data->top -= screen_size_y(s); window_more_redraw_screen(wp); break; - case MODEKEYCMD_NEXTPAGE: + case MODEKEYCHOICE_PAGEDOWN: if (data->top + screen_size_y(s) > ARRAY_LENGTH(&data->list)) data->top = ARRAY_LENGTH(&data->list); else diff --git a/window-scroll.c b/window-scroll.c index ecc76306..c14d1ab0 100644 --- a/window-scroll.c +++ b/window-scroll.c @@ -63,6 +63,7 @@ window_scroll_init(struct window_pane *wp) struct screen *s; struct screen_write_ctx ctx; u_int i; + int keys; wp->modedata = data = xmalloc(sizeof *data); data->ox = 0; @@ -72,8 +73,11 @@ window_scroll_init(struct window_pane *wp) screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0); s->mode &= ~MODE_CURSOR; - mode_key_init(&data->mdata, - options_get_number(&wp->window->options, "mode-keys"), 0); + keys = options_get_number(&wp->window->options, "mode-keys"); + if (keys == MODEKEY_EMACS) + mode_key_init(&data->mdata, mode_key_emacs_copy); + else + mode_key_init(&data->mdata, mode_key_vi_copy); screen_write_start(&ctx, NULL, s); for (i = 0; i < screen_size_y(s); i++) @@ -128,25 +132,25 @@ window_scroll_key(struct window_pane *wp, unused struct client *c, int key) struct screen *s = &data->screen; switch (mode_key_lookup(&data->mdata, key)) { - case MODEKEYCMD_QUIT: + case MODEKEYCOPY_QUIT: window_pane_reset_mode(wp); break; - case MODEKEYCMD_LEFT: + case MODEKEYCOPY_LEFT: window_scroll_scroll_left(wp); break; - case MODEKEYCMD_RIGHT: + case MODEKEYCOPY_RIGHT: window_scroll_scroll_right(wp); break; - case MODEKEYCMD_UP: + case MODEKEYCOPY_UP: window_scroll_scroll_up(wp); break; - case MODEKEYCMD_DOWN: + case MODEKEYCOPY_DOWN: window_scroll_scroll_down(wp); break; - case MODEKEYCMD_PREVIOUSPAGE: + case MODEKEYCOPY_PREVIOUSPAGE: window_scroll_pageup(wp); break; - case MODEKEYCMD_NEXTPAGE: + case MODEKEYCOPY_NEXTPAGE: if (data->oy < screen_size_y(s)) data->oy = 0; else From 309b76fb3255529976ff7ade7e29df8624647312 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 27 Jul 2009 20:36:13 +0000 Subject: [PATCH 0190/1180] Remove an unused entry in the mode keys command enum and rename MODEKEYCOPY_QUIT to _CANCEL to match the others. --- mode-key.c | 10 +++++----- tmux.h | 2 -- window-copy.c | 2 +- window-scroll.c | 2 +- 4 files changed, 7 insertions(+), 9 deletions(-) diff --git a/mode-key.c b/mode-key.c index 58769eda..154da684 100644 --- a/mode-key.c +++ b/mode-key.c @@ -74,7 +74,7 @@ const struct mode_key_entry mode_key_vi_copy[] = { { ' ', 0, MODEKEYCOPY_STARTSELECTION }, { '$', 0, MODEKEYCOPY_ENDOFLINE }, { '0', 0, MODEKEYCOPY_STARTOFLINE }, - { '\003' /* C-c */, 0, MODEKEYCOPY_QUIT }, + { '\003' /* C-c */, 0, MODEKEYCOPY_CANCEL }, { '\006' /* C-f */, 0, MODEKEYCOPY_NEXTPAGE }, { '\010' /* C-h */, 0, MODEKEYCOPY_LEFT }, { '\025' /* C-u */, 0, MODEKEYCOPY_PREVIOUSPAGE }, @@ -86,7 +86,7 @@ const struct mode_key_entry mode_key_vi_copy[] = { { 'j', 0, MODEKEYCOPY_DOWN }, { 'k', 0, MODEKEYCOPY_UP }, { 'l', 0, MODEKEYCOPY_RIGHT }, - { 'q', 0, MODEKEYCOPY_QUIT }, + { 'q', 0, MODEKEYCOPY_CANCEL }, { 'w', 0, MODEKEYCOPY_NEXTWORD }, { KEYC_BSPACE, 0, MODEKEYCOPY_LEFT }, { KEYC_DOWN, 0, MODEKEYCOPY_DOWN }, @@ -144,7 +144,7 @@ const struct mode_key_entry mode_key_emacs_copy[] = { { '\000' /* C-Space */, 0, MODEKEYCOPY_STARTSELECTION }, { '\001' /* C-a */, 0, MODEKEYCOPY_STARTOFLINE }, { '\002' /* C-b */, 0, MODEKEYCOPY_LEFT }, - { '\003' /* C-c */, 0, MODEKEYCOPY_QUIT }, + { '\003' /* C-c */, 0, MODEKEYCOPY_CANCEL }, { '\005' /* C-e */, 0, MODEKEYCOPY_ENDOFLINE }, { '\006' /* C-f */, 0, MODEKEYCOPY_RIGHT }, { '\007' /* C-g */, 0, MODEKEYCOPY_CLEARSELECTION }, @@ -152,11 +152,11 @@ const struct mode_key_entry mode_key_emacs_copy[] = { { '\020' /* C-p */, 0, MODEKEYCOPY_UP }, { '\026' /* C-v */, 0, MODEKEYCOPY_NEXTPAGE }, { '\027' /* C-w */, 0, MODEKEYCOPY_COPYSELECTION }, - { '\033' /* Escape */, 0, MODEKEYCOPY_QUIT }, + { '\033' /* Escape */, 0, MODEKEYCOPY_CANCEL }, { 'b' | KEYC_ESCAPE, 0, MODEKEYCOPY_PREVIOUSWORD }, { 'f' | KEYC_ESCAPE, 0, MODEKEYCOPY_NEXTWORD }, { 'm' | KEYC_ESCAPE, 0, MODEKEYCOPY_BACKTOINDENTATION }, - { 'q', 0, MODEKEYCOPY_QUIT }, + { 'q', 0, MODEKEYCOPY_CANCEL }, { 'v' | KEYC_ESCAPE, 0, MODEKEYCOPY_PREVIOUSPAGE }, { 'w' | KEYC_ESCAPE, 0, MODEKEYCOPY_COPYSELECTION }, { KEYC_DOWN, 0, MODEKEYCOPY_DOWN }, diff --git a/tmux.h b/tmux.h index 505e3d68..67623eee 100644 --- a/tmux.h +++ b/tmux.h @@ -396,10 +396,8 @@ enum mode_key_cmd { MODEKEYCOPY_LEFT, MODEKEYCOPY_NEXTPAGE, MODEKEYCOPY_NEXTWORD, - MODEKEYCOPY_NONE, MODEKEYCOPY_PREVIOUSPAGE, MODEKEYCOPY_PREVIOUSWORD, - MODEKEYCOPY_QUIT, MODEKEYCOPY_RIGHT, MODEKEYCOPY_STARTOFLINE, MODEKEYCOPY_STARTSELECTION, diff --git a/window-copy.c b/window-copy.c index 7ca4cd34..5fbfd0b8 100644 --- a/window-copy.c +++ b/window-copy.c @@ -168,7 +168,7 @@ window_copy_key(struct window_pane *wp, struct client *c, int key) struct screen *s = &data->screen; switch (mode_key_lookup(&data->mdata, key)) { - case MODEKEYCOPY_QUIT: + case MODEKEYCOPY_CANCEL: window_pane_reset_mode(wp); break; case MODEKEYCOPY_LEFT: diff --git a/window-scroll.c b/window-scroll.c index c14d1ab0..d4215338 100644 --- a/window-scroll.c +++ b/window-scroll.c @@ -132,7 +132,7 @@ window_scroll_key(struct window_pane *wp, unused struct client *c, int key) struct screen *s = &data->screen; switch (mode_key_lookup(&data->mdata, key)) { - case MODEKEYCOPY_QUIT: + case MODEKEYCOPY_CANCEL: window_pane_reset_mode(wp); break; case MODEKEYCOPY_LEFT: From 2da48644837cd51cfe5a9628140866f06e049e50 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 28 Jul 2009 06:48:44 +0000 Subject: [PATCH 0191/1180] If select-layout is not given an argument, repply the last layout used in the window, if any. --- cmd-select-layout.c | 18 +++++++++++------- cmd-server-info.c | 4 ++-- layout-set.c | 35 +++++++++++++++++++++++------------ tmux.1 | 5 ++++- tmux.h | 2 +- window.c | 2 +- 6 files changed, 42 insertions(+), 24 deletions(-) diff --git a/cmd-select-layout.c b/cmd-select-layout.c index a2b053ac..3613514e 100644 --- a/cmd-select-layout.c +++ b/cmd-select-layout.c @@ -29,8 +29,8 @@ int cmd_select_layout_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_select_layout_entry = { "select-layout", "selectl", - CMD_TARGET_WINDOW_USAGE " layout-name", - CMD_ARG1, 0, + CMD_TARGET_WINDOW_USAGE " [layout-name]", + CMD_ARG01, 0, cmd_select_layout_init, cmd_target_parse, cmd_select_layout_exec, @@ -72,11 +72,15 @@ cmd_select_layout_exec(struct cmd *self, struct cmd_ctx *ctx) if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) return (-1); - if ((layout = layout_set_lookup(data->arg)) == -1) { - ctx->error(ctx, "unknown or ambiguous layout: %s", data->arg); - return (-1); - } - + if (data->arg == NULL) { + layout = wl->window->lastlayout; + if (layout == -1) + return (0); + } else if ((layout = layout_set_lookup(data->arg)) == -1) { + ctx->error(ctx, "unknown layout or ambiguous: %s", data->arg); + return (-1); + } + layout = layout_set_select(wl->window, layout); ctx->info(ctx, "arranging in: %s", layout_set_name(layout)); diff --git a/cmd-server-info.c b/cmd-server-info.c index 24cd90b7..ce038e12 100644 --- a/cmd-server-info.c +++ b/cmd-server-info.c @@ -112,9 +112,9 @@ cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx) RB_FOREACH(wl, winlinks, &s->windows) { w = wl->window; ctx->print(ctx, "%4u: %s [%ux%u] [flags=0x%x, " - "references=%u, layout=%u]", wl->idx, w->name, + "references=%u, last layout=%d]", wl->idx, w->name, w->sx, w->sy, w->flags, w->references, - w->layout); + w->lastlayout); j = 0; TAILQ_FOREACH(wp, &w->panes, entry) { lines = ulines = size = usize = 0; diff --git a/layout-set.c b/layout-set.c index 4433d0cf..8c54a166 100644 --- a/layout-set.c +++ b/layout-set.c @@ -74,36 +74,47 @@ layout_set_select(struct window *w, u_int layout) if (layout_sets[layout].arrange != NULL) layout_sets[layout].arrange(w); - w->layout = layout; + w->lastlayout = layout; return (layout); } u_int layout_set_next(struct window *w) { - u_int layout = w->layout; + u_int layout; + + if (w->lastlayout == -1) + layout = 0; + else { + layout = w->lastlayout + 1; + if (layout > nitems(layout_sets) - 1) + layout = 0; + } if (layout_sets[layout].arrange != NULL) layout_sets[layout].arrange(w); - - w->layout++; - if (w->layout > nitems(layout_sets) - 1) - w->layout = 0; + w->lastlayout = layout; return (layout); } u_int layout_set_previous(struct window *w) { - u_int layout = w->layout; + u_int layout; + + if (w->lastlayout == -1) + layout = nitems(layout_sets) - 1; + else { + layout = w->lastlayout; + if (layout == 0) + layout = nitems(layout_sets) - 1; + else + layout--; + } if (layout_sets[layout].arrange != NULL) layout_sets[layout].arrange(w); - - if (w->layout == 0) - w->layout = nitems(layout_sets) - 1; - else - w->layout--; + w->lastlayout = layout; return (layout); } diff --git a/tmux.1 b/tmux.1 index 0ba9eec9..d3e8979d 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1064,10 +1064,13 @@ has the same meaning as in the command. .It Xo Ic select-layout .Op Fl t Ar target-window -.Ar layout-name +.Op Ar layout-name .Xc .D1 (alias: selectl ) Choose a specific layout for a window. +If +.Ar layout-name +is not given, the last layout used (if any) is reapplied. .It Xo Ic select-pane .Op Fl p Ar pane-index .Op Fl t Ar target-window diff --git a/tmux.h b/tmux.h index 67623eee..af0fed59 100644 --- a/tmux.h +++ b/tmux.h @@ -663,7 +663,7 @@ struct window { struct window_pane *active; struct window_panes panes; - u_int layout; + int lastlayout; struct layout_cell *layout_root; u_int sx; diff --git a/window.c b/window.c index bc6906a8..d1f92920 100644 --- a/window.c +++ b/window.c @@ -231,7 +231,7 @@ window_create1(u_int sx, u_int sy) TAILQ_INIT(&w->panes); w->active = NULL; - w->layout = 0; + w->lastlayout = -1; w->layout_root = NULL; w->sx = sx; From 86785004baf4086816b5d6684b9d0e4c56b58ea6 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 28 Jul 2009 07:03:32 +0000 Subject: [PATCH 0192/1180] Next step towards customisable mode keys: build each default table of keys into a named tree on start and use that for lookups. Also add command to string translation tables and modify list-keys to show the the mode key bindings (new -t argument). --- cmd-list-keys.c | 63 +++++++++++++++-- mode-key.c | 179 +++++++++++++++++++++++++++++++++++++++++++----- server.c | 2 + status.c | 4 +- tmux.1 | 39 ++++++++++- tmux.h | 56 +++++++++++---- window-choose.c | 4 +- window-copy.c | 4 +- window-more.c | 4 +- window-scroll.c | 4 +- 10 files changed, 311 insertions(+), 48 deletions(-) diff --git a/cmd-list-keys.c b/cmd-list-keys.c index 9110d12a..0a22e82c 100644 --- a/cmd-list-keys.c +++ b/cmd-list-keys.c @@ -28,25 +28,31 @@ int cmd_list_keys_exec(struct cmd *, struct cmd_ctx *); +int cmd_list_keys_table(struct cmd *, struct cmd_ctx *); + const struct cmd_entry cmd_list_keys_entry = { "list-keys", "lsk", - "", + "[-t key-table]", 0, 0, - NULL, - NULL, + cmd_target_init, + cmd_target_parse, cmd_list_keys_exec, - NULL, - NULL + cmd_target_free, + cmd_target_print }; int -cmd_list_keys_exec(unused struct cmd *self, struct cmd_ctx *ctx) +cmd_list_keys_exec(struct cmd *self, struct cmd_ctx *ctx) { + struct cmd_target_data *data = self->data; struct key_binding *bd; const char *key; char tmp[BUFSIZ], keytmp[64]; int width, keywidth; + if (data->target != NULL) + return (cmd_list_keys_table(self, ctx)); + width = 0; SPLAY_FOREACH(bd, key_bindings, &key_bindings) { key = key_string_lookup_key(bd->key & ~KEYC_PREFIX); @@ -76,3 +82,48 @@ cmd_list_keys_exec(unused struct cmd *self, struct cmd_ctx *ctx) return (0); } + +int +cmd_list_keys_table(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_target_data *data = self->data; + const struct mode_key_table *mtab; + struct mode_key_binding *mbind; + const char *key, *cmdstr, *mode; + int width, keywidth; + + for (mtab = mode_key_tables; mtab->name != NULL; mtab++) { + if (strcasecmp(data->target, mtab->name) == 0) + break; + } + if (mtab->name == NULL) { + ctx->error(ctx, "unknown key table: %s", data->target); + return (-1); + } + + width = 0; + SPLAY_FOREACH(mbind, mode_key_tree, mtab->tree) { + key = key_string_lookup_key(mbind->key); + if (key == NULL) + continue; + + keywidth = strlen(key) + 1; + if (keywidth > width) + width = keywidth; + } + + SPLAY_FOREACH(mbind, mode_key_tree, mtab->tree) { + key = key_string_lookup_key(mbind->key); + if (key == NULL) + continue; + + mode = ""; + if (mbind->mode != 0) + mode = "(command mode) "; + cmdstr = mode_key_tostring(mtab->cmdstr, mbind->cmd); + if (cmdstr != NULL) + ctx->print(ctx, "%*s: %s%s", width, key, mode, cmdstr); + } + + return (0); +} diff --git a/mode-key.c b/mode-key.c index 154da684..e0f773d5 100644 --- a/mode-key.c +++ b/mode-key.c @@ -20,6 +20,71 @@ #include "tmux.h" +/* + * Mode keys. These are the key bindings used when editing (status prompt), and + * in the modes. They are split into two sets of three tables, one set of three + * for vi and the other for emacs key bindings. The three tables are for + * editing, for menu-like modes (choice, more), and for copy modes (copy, + * scroll). + * + * The fixed tables of struct mode_key_entry below are the defaults: they are + * built into a tree of struct mode_key_binding by mode_key_init_trees, which + * can then be modified. + * + * vi command mode is handled by having a mode flag in the struct which allows + * two sets of bindings to be swapped between. A couple of editing commands + * (MODEKEYEDIT_SWITCHMODE and MODEKEYEDIT_SWITCHMODEAPPEND) are special-cased + * to do this. + */ + +/* Edit keys command strings. */ +struct mode_key_cmdstr mode_key_cmdstr_edit[] = { + { MODEKEYEDIT_BACKSPACE, "backspace" }, + { MODEKEYEDIT_CANCEL, "cancel" }, + { MODEKEYEDIT_COMPLETE, "complete" }, + { MODEKEYEDIT_CURSORLEFT, "cursor-left" }, + { MODEKEYEDIT_CURSORRIGHT, "cursor-right" }, + { MODEKEYEDIT_DELETE, "delete" }, + { MODEKEYEDIT_DELETETOENDOFLINE, "delete-end-of-line" }, + { MODEKEYEDIT_ENDOFLINE, "end-of-line" }, + { MODEKEYEDIT_ENTER, "enter" }, + { MODEKEYEDIT_HISTORYDOWN, "history-down" }, + { MODEKEYEDIT_HISTORYUP, "history-up" }, + { MODEKEYEDIT_PASTE, "paste" }, + { MODEKEYEDIT_STARTOFLINE, "start-of-line" }, + { MODEKEYEDIT_SWITCHMODE, "switch-mode" }, + { MODEKEYEDIT_SWITCHMODEAPPEND, "switch-mode-append" }, +}; + +/* Choice keys command strings. */ +struct mode_key_cmdstr mode_key_cmdstr_choice[] = { + { MODEKEYCHOICE_CANCEL, "cancel" }, + { MODEKEYCHOICE_CHOOSE, "choose" }, + { MODEKEYCHOICE_DOWN, "down" }, + { MODEKEYCHOICE_PAGEDOWN, "page-down" }, + { MODEKEYCHOICE_PAGEUP, "page-up" }, + { MODEKEYCHOICE_UP, "up" }, +}; + +/* Copy keys command strings. */ +struct mode_key_cmdstr mode_key_cmdstr_copy[] = { + { MODEKEYCOPY_CANCEL, "cancel" }, + { MODEKEYCOPY_BACKTOINDENTATION, "back-to-indentation" }, + { MODEKEYCOPY_CLEARSELECTION, "clear-selection" }, + { MODEKEYCOPY_COPYSELECTION, "copy-selection" }, + { MODEKEYCOPY_DOWN, "cursor-down" }, + { MODEKEYCOPY_ENDOFLINE, "end-of-line" }, + { MODEKEYCOPY_LEFT, "cursor-left" }, + { MODEKEYCOPY_NEXTPAGE, "page-down" }, + { MODEKEYCOPY_NEXTWORD, "next-word" }, + { MODEKEYCOPY_PREVIOUSPAGE, "page-up" }, + { MODEKEYCOPY_PREVIOUSWORD, "previous-word" }, + { MODEKEYCOPY_RIGHT, "cursor-right" }, + { MODEKEYCOPY_STARTOFLINE, "start-of-line" }, + { MODEKEYCOPY_STARTSELECTION, "begin-selection" }, + { MODEKEYCOPY_UP, "cursor-up" }, +}; + /* vi editing keys. */ const struct mode_key_entry mode_key_vi_edit[] = { { '\003' /* C-c */, 0, MODEKEYEDIT_CANCEL }, @@ -53,6 +118,7 @@ const struct mode_key_entry mode_key_vi_edit[] = { { 0, -1, 0 } }; +struct mode_key_tree mode_key_tree_vi_edit; /* vi choice selection keys. */ const struct mode_key_entry mode_key_vi_choice[] = { @@ -68,6 +134,7 @@ const struct mode_key_entry mode_key_vi_choice[] = { { 0, -1, 0 } }; +struct mode_key_tree mode_key_tree_vi_choice; /* vi copy mode keys. */ const struct mode_key_entry mode_key_vi_copy[] = { @@ -98,6 +165,7 @@ const struct mode_key_entry mode_key_vi_copy[] = { { 0, -1, 0 } }; +struct mode_key_tree mode_key_tree_vi_copy; /* emacs editing keys. */ const struct mode_key_entry mode_key_emacs_edit[] = { @@ -123,6 +191,7 @@ const struct mode_key_entry mode_key_emacs_edit[] = { { 0, -1, 0 } }; +struct mode_key_tree mode_key_tree_emacs_edit; /* emacs choice selection keys. */ const struct mode_key_entry mode_key_emacs_choice[] = { @@ -137,6 +206,7 @@ const struct mode_key_entry mode_key_emacs_choice[] = { { 0, -1, 0 } }; +struct mode_key_tree mode_key_tree_emacs_choice; /* emacs copy mode keys. */ const struct mode_key_entry mode_key_emacs_copy[] = { @@ -168,34 +238,105 @@ const struct mode_key_entry mode_key_emacs_copy[] = { { 0, -1, 0 } }; +struct mode_key_tree mode_key_tree_emacs_copy; + +/* Table mapping key table names to default settings and trees. */ +const struct mode_key_table mode_key_tables[] = { + { "vi-edit", mode_key_cmdstr_edit, + &mode_key_tree_vi_edit, mode_key_vi_edit }, + { "vi-choice", mode_key_cmdstr_choice, + &mode_key_tree_vi_choice, mode_key_vi_choice }, + { "vi-copy", mode_key_cmdstr_copy, + &mode_key_tree_vi_copy, mode_key_vi_copy }, + { "emacs-edit", mode_key_cmdstr_edit, + &mode_key_tree_emacs_edit, mode_key_emacs_edit }, + { "emacs-choice", mode_key_cmdstr_choice, + &mode_key_tree_emacs_choice, mode_key_emacs_choice }, + { "emacs-copy", mode_key_cmdstr_copy, + &mode_key_tree_emacs_copy, mode_key_emacs_copy }, + + { NULL, NULL, NULL, NULL } +}; + +SPLAY_GENERATE(mode_key_tree, mode_key_binding, entry, mode_key_cmp); + +int +mode_key_cmp(struct mode_key_binding *mbind1, struct mode_key_binding *mbind2) +{ + if (mbind1->mode != mbind2->mode) + return (mbind1->mode - mbind2->mode); + return (mbind1->key - mbind2->key); +} + +const char * +mode_key_tostring(struct mode_key_cmdstr *cmdstr, enum mode_key_cmd cmd) +{ + for (; cmdstr->name != NULL; cmdstr++) { + if (cmdstr->cmd == cmd) + return (cmdstr->name); + } + return (NULL); +} void -mode_key_init(struct mode_key_data *mdata, const struct mode_key_entry *table) +mode_key_init_trees(void) { - mdata->table = table; + const struct mode_key_table *mtab; + const struct mode_key_entry *ment; + struct mode_key_binding *mbind; + + for (mtab = mode_key_tables; mtab->name != NULL; mtab++) { + SPLAY_INIT(mtab->tree); + for (ment = mtab->table; ment->mode != -1; ment++) { + mbind = xmalloc(sizeof *mbind); + mbind->key = ment->key; + mbind->mode = ment->mode; + mbind->cmd = ment->cmd; + SPLAY_INSERT(mode_key_tree, mtab->tree, mbind); + } + } +} + +void +mode_key_free_trees(void) +{ + const struct mode_key_table *mtab; + struct mode_key_binding *mbind; + + for (mtab = mode_key_tables; mtab->name != NULL; mtab++) { + while (!SPLAY_EMPTY(mtab->tree)) { + mbind = SPLAY_ROOT(mtab->tree); + SPLAY_REMOVE(mode_key_tree, mtab->tree, mbind); + } + } +} + +void +mode_key_init(struct mode_key_data *mdata, struct mode_key_tree *mtree) +{ + mdata->tree = mtree; mdata->mode = 0; } enum mode_key_cmd mode_key_lookup(struct mode_key_data *mdata, int key) { - const struct mode_key_entry *ment; - int mode; + struct mode_key_binding *mbind, mtmp; - mode = mdata->mode; - for (ment = mdata->table; ment->mode != -1; ment++) { - if (ment->mode == mode && key == ment->key) { - switch (ment->cmd) { - case MODEKEYEDIT_SWITCHMODE: - case MODEKEYEDIT_SWITCHMODEAPPEND: - mdata->mode = 1 - mdata->mode; - /* FALLTHROUGH */ - default: - return (ment->cmd); - } - } + mtmp.key = key; + mtmp.mode = mdata->mode; + if ((mbind = SPLAY_FIND(mode_key_tree, mdata->tree, &mtmp)) == NULL) { + if (mdata->mode != 0) + return (MODEKEY_NONE); + return (MODEKEY_OTHER); + } + + switch (mbind->cmd) { + case MODEKEYEDIT_SWITCHMODE: + case MODEKEYEDIT_SWITCHMODEAPPEND: + mdata->mode = 1 - mdata->mode; + /* FALLTHROUGH */ + default: + return (mbind->cmd); } - if (mode != 0) - return (MODEKEY_NONE); - return (MODEKEY_OTHER); } diff --git a/server.c b/server.c index ce793076..668a8251 100644 --- a/server.c +++ b/server.c @@ -160,6 +160,7 @@ server_start(char *path) ARRAY_INIT(&windows); ARRAY_INIT(&clients); ARRAY_INIT(&sessions); + mode_key_init_trees(); key_bindings_init(); utf8_build(); @@ -379,6 +380,7 @@ server_main(int srv_fd) } ARRAY_FREE(&clients); + mode_key_free_trees(); key_bindings_free(); close(srv_fd); diff --git a/status.c b/status.c index fef440eb..7fcf5e9b 100644 --- a/status.c +++ b/status.c @@ -609,9 +609,9 @@ status_prompt_set(struct client *c, const char *msg, keys = options_get_number(&c->session->options, "status-keys"); if (keys == MODEKEY_EMACS) - mode_key_init(&c->prompt_mdata, mode_key_emacs_edit); + mode_key_init(&c->prompt_mdata, &mode_key_tree_emacs_edit); else - mode_key_init(&c->prompt_mdata, mode_key_vi_edit); + mode_key_init(&c->prompt_mdata, &mode_key_tree_vi_edit); c->tty.flags |= (TTY_NOCURSOR|TTY_FREEZE); c->flags |= CLIENT_STATUS; diff --git a/tmux.1 b/tmux.1 index d3e8979d..1a3b1664 100644 --- a/tmux.1 +++ b/tmux.1 @@ -331,10 +331,29 @@ The following keys are supported as appropriate for the mode: .It Li "Cursor right" Ta "l" Ta "Right" .It Li "Start selection" Ta "Space" Ta "C-Space" .It Li "Cursor up" Ta "k" Ta "Up" -.It Li "Delete to end of line" Ta "D or C" Ta "C-k" +.It Li "Delete to end of line" Ta "D" Ta "C-k" .It Li "Paste buffer" Ta "p" Ta "C-y" .El .Pp +These key bindings are defined in a set of named tables: +.Em vi-edit +and +.Em emacs-edit +for keys used when line editing at the command prompt; +.Em vi-choice +and +.Em emacs-choice +for keys used when choosing from lists (such as produced by the +.Ic window-choose +command) or in output mode; and +.Em vi-copy +and +.Em emacs-copy +used in copy and scroll modes. +The tables may be viewed with the +.Ic list-keys +command. +.Pp The paste buffer key pastes the first line from the top paste buffer on the stack. .Sh BUFFERS @@ -847,13 +866,31 @@ List all clients attached to the server. List the syntax of all commands supported by .Nm . .It Xo Ic list-keys +.Op Ar Fl t Ar key-table .Xc .D1 (alias: Ic lsk ) List all key bindings. +Without +.Fl t +the primary key bindings - those executed when preceded by the prefix key - +are printed. Keys bound without the prefix key (see .Ic bind-key .Fl n ) are enclosed in square brackets. +.Pp +With +.Fl t , +the key bindings in +.Ar key-table +are listed; this may be one of: +.Em vi-edit , +.Em emacs-edit , +.Em vi-choice , +.Em emacs-choice , +.Em vi-copy +or +.Em emacs-copy . .It Xo Ic list-sessions .Xc .D1 (alias: Ic ls ) diff --git a/tmux.h b/tmux.h index af0fed59..9d5898ae 100644 --- a/tmux.h +++ b/tmux.h @@ -356,7 +356,7 @@ struct msg_unlock_data { char pass[PASS_MAX]; }; -/* Editing keys. */ +/* Mode key commands. */ enum mode_key_cmd { MODEKEY_NONE, MODEKEY_OTHER, @@ -404,6 +404,7 @@ enum mode_key_cmd { MODEKEYCOPY_UP, }; +/* Entry in the default mode key tables. */ struct mode_key_entry { int key; @@ -414,16 +415,42 @@ struct mode_key_entry { * keys to be bound in edit mode. */ int mode; - enum mode_key_cmd cmd; }; + +/* Data required while mode keys are in use. */ struct mode_key_data { - const struct mode_key_entry *table; - int mode; + struct mode_key_tree *tree; + int mode; }; #define MODEKEY_EMACS 0 #define MODEKEY_VI 1 +/* Binding between a key and a command. */ +struct mode_key_binding { + int key; + + int mode; + enum mode_key_cmd cmd; + + SPLAY_ENTRY(mode_key_binding) entry; +}; +SPLAY_HEAD(mode_key_tree, mode_key_binding); + +/* Command to string mapping. */ +struct mode_key_cmdstr { + enum mode_key_cmd cmd; + const char *name; +}; + +/* Named mode key table description. */ +struct mode_key_table { + const char *name; + struct mode_key_cmdstr *cmdstr; + struct mode_key_tree *tree; + const struct mode_key_entry *table; /* default entries */ +}; + /* Modes. */ #define MODE_CURSOR 0x1 #define MODE_INSERT 0x2 @@ -1061,14 +1088,19 @@ void sighandler(int); int load_cfg(const char *, char **x); /* mode-key.c */ -extern const struct mode_key_entry mode_key_vi_edit[]; -extern const struct mode_key_entry mode_key_vi_choice[]; -extern const struct mode_key_entry mode_key_vi_copy[]; -extern const struct mode_key_entry mode_key_emacs_edit[]; -extern const struct mode_key_entry mode_key_emacs_choice[]; -extern const struct mode_key_entry mode_key_emacs_copy[]; -void mode_key_init( - struct mode_key_data *, const struct mode_key_entry *); +extern const struct mode_key_table mode_key_tables[]; +extern struct mode_key_tree mode_key_tree_vi_edit; +extern struct mode_key_tree mode_key_tree_vi_choice; +extern struct mode_key_tree mode_key_tree_vi_copy; +extern struct mode_key_tree mode_key_tree_emacs_edit; +extern struct mode_key_tree mode_key_tree_emacs_choice; +extern struct mode_key_tree mode_key_tree_emacs_copy; +int mode_key_cmp(struct mode_key_binding *, struct mode_key_binding *); +SPLAY_PROTOTYPE(mode_key_tree, mode_key_binding, entry, mode_key_cmp); +const char *mode_key_tostring(struct mode_key_cmdstr *r, enum mode_key_cmd); +void mode_key_init_trees(void); +void mode_key_free_trees(void); +void mode_key_init(struct mode_key_data *, struct mode_key_tree *); enum mode_key_cmd mode_key_lookup(struct mode_key_data *, int); /* options.c */ diff --git a/window-choose.c b/window-choose.c index b1ae3bc5..e7d847de 100644 --- a/window-choose.c +++ b/window-choose.c @@ -127,9 +127,9 @@ window_choose_init(struct window_pane *wp) keys = options_get_number(&wp->window->options, "mode-keys"); if (keys == MODEKEY_EMACS) - mode_key_init(&data->mdata, mode_key_emacs_choice); + mode_key_init(&data->mdata, &mode_key_tree_emacs_choice); else - mode_key_init(&data->mdata, mode_key_vi_choice); + mode_key_init(&data->mdata, &mode_key_tree_vi_choice); return (s); } diff --git a/window-copy.c b/window-copy.c index 5fbfd0b8..8ea32126 100644 --- a/window-copy.c +++ b/window-copy.c @@ -108,9 +108,9 @@ window_copy_init(struct window_pane *wp) keys = options_get_number(&wp->window->options, "mode-keys"); if (keys == MODEKEY_EMACS) - mode_key_init(&data->mdata, mode_key_emacs_copy); + mode_key_init(&data->mdata, &mode_key_tree_emacs_copy); else - mode_key_init(&data->mdata, mode_key_vi_copy); + mode_key_init(&data->mdata, &mode_key_tree_vi_copy); s->cx = data->cx; s->cy = data->cy; diff --git a/window-more.c b/window-more.c index a113c4ba..a3418eb0 100644 --- a/window-more.c +++ b/window-more.c @@ -92,9 +92,9 @@ window_more_init(struct window_pane *wp) keys = options_get_number(&wp->window->options, "mode-keys"); if (keys == MODEKEY_EMACS) - mode_key_init(&data->mdata, mode_key_emacs_choice); + mode_key_init(&data->mdata, &mode_key_tree_emacs_choice); else - mode_key_init(&data->mdata, mode_key_vi_choice); + mode_key_init(&data->mdata, &mode_key_tree_vi_choice); return (s); } diff --git a/window-scroll.c b/window-scroll.c index d4215338..12249fc1 100644 --- a/window-scroll.c +++ b/window-scroll.c @@ -75,9 +75,9 @@ window_scroll_init(struct window_pane *wp) keys = options_get_number(&wp->window->options, "mode-keys"); if (keys == MODEKEY_EMACS) - mode_key_init(&data->mdata, mode_key_emacs_copy); + mode_key_init(&data->mdata, &mode_key_tree_emacs_copy); else - mode_key_init(&data->mdata, mode_key_vi_copy); + mode_key_init(&data->mdata, &mode_key_tree_vi_copy); screen_write_start(&ctx, NULL, s); for (i = 0; i < screen_size_y(s); i++) From 9e5d585ba4b0af6badf559cc7b275a23be8947c2 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 28 Jul 2009 09:18:01 +0000 Subject: [PATCH 0193/1180] Accept and print "Enter" and "Escape" for keys rather than C-m and C-[. --- key-string.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/key-string.c b/key-string.c index 5c8ce5b3..68a57f8b 100644 --- a/key-string.c +++ b/key-string.c @@ -58,6 +58,8 @@ struct { { "Tab", '\011' }, { "BTab", KEYC_BTAB }, { "BSpace", KEYC_BSPACE }, + { "Enter", '\r' }, + { "Escape", '\033' }, /* Arrow keys. */ { "Up", KEYC_UP }, @@ -177,6 +179,11 @@ key_string_lookup_key(int key) return (tmp2); } + for (i = 0; i < nitems(key_string_table); i++) { + if (key == key_string_table[i].key) + return (key_string_table[i].string); + } + if (key >= 32 && key <= 255) { tmp[0] = key; tmp[1] = '\0'; @@ -191,9 +198,5 @@ key_string_lookup_key(int key) return (tmp); } - for (i = 0; i < nitems(key_string_table); i++) { - if (key == key_string_table[i].key) - return (key_string_table[i].string); - } return (NULL); } From f596be99505a0191cac9f314fb1b71528c5080b4 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 28 Jul 2009 17:05:10 +0000 Subject: [PATCH 0194/1180] Final pieces of mode key rebinding: bind-key and unbind-key now accept a -t argument to modify a table. --- cmd-bind-key.c | 70 +++++++++++++++++++++++++++++++++++++++++++++--- cmd-list-keys.c | 6 +---- cmd-unbind-key.c | 42 +++++++++++++++++++++++++++-- mode-key.c | 30 +++++++++++++++++++++ tmux.1 | 46 ++++++++++++++++++++++++++----- tmux.h | 2 ++ 6 files changed, 179 insertions(+), 17 deletions(-) diff --git a/cmd-bind-key.c b/cmd-bind-key.c index 41d8eeb8..041f558d 100644 --- a/cmd-bind-key.c +++ b/cmd-bind-key.c @@ -18,6 +18,8 @@ #include +#include + #include "tmux.h" /* @@ -29,15 +31,21 @@ int cmd_bind_key_exec(struct cmd *, struct cmd_ctx *); void cmd_bind_key_free(struct cmd *); size_t cmd_bind_key_print(struct cmd *, char *, size_t); +int cmd_bind_key_table(struct cmd *, struct cmd_ctx *); + struct cmd_bind_key_data { int key; int can_repeat; struct cmd_list *cmdlist; + + int command_key; + char *tablename; + char *modecmd; }; const struct cmd_entry cmd_bind_key_entry = { "bind-key", "bind", - "[-nr] key command [arguments]", + "[-cnr] [-t key-table] key command [arguments]", 0, 0, NULL, cmd_bind_key_parse, @@ -55,15 +63,24 @@ cmd_bind_key_parse(struct cmd *self, int argc, char **argv, char **cause) self->data = data = xmalloc(sizeof *data); data->can_repeat = 0; data->cmdlist = NULL; + data->command_key = 0; + data->tablename = NULL; + data->modecmd = NULL; - while ((opt = getopt(argc, argv, "nr")) != -1) { + while ((opt = getopt(argc, argv, "cnrt:")) != -1) { switch (opt) { + case 'c': + data->command_key = 1; + break; case 'n': no_prefix = 1; break; case 'r': data->can_repeat = 1; break; + case 't': + data->tablename = xstrdup(optarg); + break; default: goto usage; } @@ -82,8 +99,14 @@ cmd_bind_key_parse(struct cmd *self, int argc, char **argv, char **cause) argc--; argv++; - if ((data->cmdlist = cmd_list_parse(argc, argv, cause)) == NULL) - goto error; + if (data->tablename != NULL) { + if (argc != 1) + goto usage; + data->modecmd = xstrdup(argv[0]); + } else { + if ((data->cmdlist = cmd_list_parse(argc, argv, cause)) == NULL) + goto error; + } return (0); @@ -102,6 +125,8 @@ cmd_bind_key_exec(struct cmd *self, unused struct cmd_ctx *ctx) if (data == NULL) return (0); + if (data->tablename != NULL) + return (cmd_bind_key_table(self, ctx)); key_bindings_add(data->key, data->can_repeat, data->cmdlist); data->cmdlist = NULL; /* avoid free */ @@ -109,6 +134,39 @@ cmd_bind_key_exec(struct cmd *self, unused struct cmd_ctx *ctx) return (0); } +int +cmd_bind_key_table(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_bind_key_data *data = self->data; + const struct mode_key_table *mtab; + struct mode_key_binding *mbind, mtmp; + enum mode_key_cmd cmd; + + if ((mtab = mode_key_findtable(data->tablename)) == NULL) { + ctx->error(ctx, "unknown key table: %s", data->tablename); + return (-1); + } + + cmd = mode_key_fromstring(mtab->cmdstr, data->modecmd); + if (cmd == MODEKEY_NONE) { + ctx->error(ctx, "unknown command: %s", data->modecmd); + return (-1); + } + + mtmp.key = data->key & ~KEYC_PREFIX; + mtmp.mode = data->command_key ? 1 : 0; + if ((mbind = SPLAY_FIND(mode_key_tree, mtab->tree, &mtmp)) != NULL) { + mbind->cmd = cmd; + return (0); + } + mbind = xmalloc(sizeof *mbind); + mbind->key = mtmp.key; + mbind->mode = mtmp.mode; + mbind->cmd = cmd; + SPLAY_INSERT(mode_key_tree, mtab->tree, mbind); + return (0); +} + void cmd_bind_key_free(struct cmd *self) { @@ -116,6 +174,10 @@ cmd_bind_key_free(struct cmd *self) if (data->cmdlist != NULL) cmd_list_free(data->cmdlist); + if (data->tablename != NULL) + xfree(data->tablename); + if (data->modecmd != NULL) + xfree(data->modecmd); xfree(data); } diff --git a/cmd-list-keys.c b/cmd-list-keys.c index 0a22e82c..db64e244 100644 --- a/cmd-list-keys.c +++ b/cmd-list-keys.c @@ -92,11 +92,7 @@ cmd_list_keys_table(struct cmd *self, struct cmd_ctx *ctx) const char *key, *cmdstr, *mode; int width, keywidth; - for (mtab = mode_key_tables; mtab->name != NULL; mtab++) { - if (strcasecmp(data->target, mtab->name) == 0) - break; - } - if (mtab->name == NULL) { + if ((mtab = mode_key_findtable(data->target)) == NULL) { ctx->error(ctx, "unknown key table: %s", data->target); return (-1); } diff --git a/cmd-unbind-key.c b/cmd-unbind-key.c index 35c43658..8f5e794e 100644 --- a/cmd-unbind-key.c +++ b/cmd-unbind-key.c @@ -28,13 +28,18 @@ int cmd_unbind_key_parse(struct cmd *, int, char **, char **); int cmd_unbind_key_exec(struct cmd *, struct cmd_ctx *); void cmd_unbind_key_free(struct cmd *); +int cmd_unbind_key_table(struct cmd *, struct cmd_ctx *); + struct cmd_unbind_key_data { int key; + + int command_key; + char *tablename; }; const struct cmd_entry cmd_unbind_key_entry = { "unbind-key", "unbind", - "[-n] key", + "[-cn] [-t key-table] key", 0, 0, NULL, cmd_unbind_key_parse, @@ -50,12 +55,20 @@ cmd_unbind_key_parse(struct cmd *self, int argc, char **argv, char **cause) int opt, no_prefix = 0; self->data = data = xmalloc(sizeof *data); + data->command_key = 0; + data->tablename = NULL; - while ((opt = getopt(argc, argv, "n")) != -1) { + while ((opt = getopt(argc, argv, "cnt:")) != -1) { switch (opt) { + case 'c': + data->command_key = 1; + break; case 'n': no_prefix = 1; break; + case 't': + data->tablename = xstrdup(optarg); + break; default: goto usage; } @@ -89,16 +102,41 @@ cmd_unbind_key_exec(struct cmd *self, unused struct cmd_ctx *ctx) if (data == NULL) return (0); + if (data->tablename != NULL) + return (cmd_unbind_key_table(self, ctx)); key_bindings_remove(data->key); return (0); } +int +cmd_unbind_key_table(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_unbind_key_data *data = self->data; + const struct mode_key_table *mtab; + struct mode_key_binding *mbind, mtmp; + + if ((mtab = mode_key_findtable(data->tablename)) == NULL) { + ctx->error(ctx, "unknown key table: %s", data->tablename); + return (-1); + } + + mtmp.key = data->key & ~KEYC_PREFIX; + mtmp.mode = data->command_key ? 1 : 0; + if ((mbind = SPLAY_FIND(mode_key_tree, mtab->tree, &mtmp)) != NULL) { + SPLAY_REMOVE(mode_key_tree, mtab->tree, mbind); + xfree(mbind); + } + return (0); +} + void cmd_unbind_key_free(struct cmd *self) { struct cmd_unbind_key_data *data = self->data; + if (data->tablename != NULL) + xfree(data->tablename); xfree(data); } diff --git a/mode-key.c b/mode-key.c index e0f773d5..ccd5465c 100644 --- a/mode-key.c +++ b/mode-key.c @@ -18,6 +18,8 @@ #include +#include + #include "tmux.h" /* @@ -54,6 +56,8 @@ struct mode_key_cmdstr mode_key_cmdstr_edit[] = { { MODEKEYEDIT_STARTOFLINE, "start-of-line" }, { MODEKEYEDIT_SWITCHMODE, "switch-mode" }, { MODEKEYEDIT_SWITCHMODEAPPEND, "switch-mode-append" }, + + { 0, NULL } }; /* Choice keys command strings. */ @@ -64,6 +68,8 @@ struct mode_key_cmdstr mode_key_cmdstr_choice[] = { { MODEKEYCHOICE_PAGEDOWN, "page-down" }, { MODEKEYCHOICE_PAGEUP, "page-up" }, { MODEKEYCHOICE_UP, "up" }, + + { 0, NULL } }; /* Copy keys command strings. */ @@ -83,6 +89,8 @@ struct mode_key_cmdstr mode_key_cmdstr_copy[] = { { MODEKEYCOPY_STARTOFLINE, "start-of-line" }, { MODEKEYCOPY_STARTSELECTION, "begin-selection" }, { MODEKEYCOPY_UP, "cursor-up" }, + + { 0, NULL } }; /* vi editing keys. */ @@ -278,6 +286,28 @@ mode_key_tostring(struct mode_key_cmdstr *cmdstr, enum mode_key_cmd cmd) return (NULL); } +enum mode_key_cmd +mode_key_fromstring(struct mode_key_cmdstr *cmdstr, const char *name) +{ + for (; cmdstr->name != NULL; cmdstr++) { + if (strcasecmp(cmdstr->name, name) == 0) + return (cmdstr->cmd); + } + return (MODEKEY_NONE); +} + +const struct mode_key_table * +mode_key_findtable(const char *name) +{ + const struct mode_key_table *mtab; + + for (mtab = mode_key_tables; mtab->name != NULL; mtab++) { + if (strcasecmp(name, mtab->name) == 0) + return (mtab); + } + return (NULL); +} + void mode_key_init_trees(void) { diff --git a/tmux.1 b/tmux.1 index 1a3b1664..06bc76bd 100644 --- a/tmux.1 +++ b/tmux.1 @@ -352,7 +352,10 @@ and used in copy and scroll modes. The tables may be viewed with the .Ic list-keys -command. +command and keys modified or removed with +.Ic bind-key +and +.Ic unbind-key . .Pp The paste buffer key pastes the first line from the top paste buffer on the stack. @@ -637,7 +640,8 @@ If no server is started, will attempt to start it; this will fail unless sessions are created in the configuration file. .It Xo Ic bind-key -.Op Fl nr +.Op Fl cnr +.Op Fl t Ar key-table .Ar key Ar command Op Ar arguments .Xc .D1 (alias: Ic bind ) @@ -652,7 +656,11 @@ or for Ctrl keys, or .Ql M- for Alt (meta) keys. -If +.Pp +By default (without +.Fl t ) +the primary key bindings are modified (those normally activated with the prefix +key); in this case, if .Fl n is specified, it is not necessary to use the prefix key, .Ar command @@ -664,6 +672,19 @@ The flag indicates this key may repeat, see the .Ic repeat-time option. +.Pp +If +.Fl t +is present, +.Ar key +is bound in +.Ar key-table : +the binding for command mode with +.Fl c +or for normal mode without. +To view the default bindings and possible commands, see the +.Ic list-keys +command. .It Xo Ic break-pane .Op Fl d .Op Fl p Ar pane-index @@ -866,7 +887,7 @@ List all clients attached to the server. List the syntax of all commands supported by .Nm . .It Xo Ic list-keys -.Op Ar Fl t Ar key-table +.Op Fl t Ar key-table .Xc .D1 (alias: Ic lsk ) List all key bindings. @@ -1665,17 +1686,30 @@ Switch the current session for client to .Ar target-session . .It Xo Ic unbind-key -.Op Fl n +.Op Fl cn +.Op Fl t Ar key-table .Ar key .Xc .D1 (alias: Ic unbind ) Unbind the command bound to .Ar key . -If +Without +.Fl t +the primary key bindings are modified; in this case, if .Fl n is specified, the command bound to .Ar key without a prefix (if any) is removed. +.Pp +If +.Fl t +is present, +.Ar key +in +.Ar key-table +is unbound: the binding for command mode with +.Fl c +or for normal mode without. .It Xo Ic unlink-window .Op Fl k .Op Fl t Ar target-window diff --git a/tmux.h b/tmux.h index 9d5898ae..7fc2117c 100644 --- a/tmux.h +++ b/tmux.h @@ -1098,6 +1098,8 @@ extern struct mode_key_tree mode_key_tree_emacs_copy; int mode_key_cmp(struct mode_key_binding *, struct mode_key_binding *); SPLAY_PROTOTYPE(mode_key_tree, mode_key_binding, entry, mode_key_cmp); const char *mode_key_tostring(struct mode_key_cmdstr *r, enum mode_key_cmd); +enum mode_key_cmd mode_key_fromstring(struct mode_key_cmdstr *, const char *); +const struct mode_key_table *mode_key_findtable(const char *); void mode_key_init_trees(void); void mode_key_free_trees(void); void mode_key_init(struct mode_key_data *, struct mode_key_tree *); From d3c461097b71fa548a8b91e114d4046bdc337b4f Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 29 Jul 2009 05:36:53 +0000 Subject: [PATCH 0195/1180] Taking account of the "s, 22 not 24 is the maximum length of #T in status-right to prevent the date being cut off. --- tmux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tmux.c b/tmux.c index 4f97a58a..14ba0538 100644 --- a/tmux.c +++ b/tmux.c @@ -362,7 +362,7 @@ main(int argc, char **argv) options_set_number(&global_s_options, "status-right-length", 40); options_set_string(&global_s_options, "status-left", "[#S]"); options_set_string( - &global_s_options, "status-right", "\"#24T\" %%H:%%M %%d-%%b-%%y"); + &global_s_options, "status-right", "\"#22T\" %%H:%%M %%d-%%b-%%y"); if (flags & IDENTIFY_UTF8) options_set_number(&global_s_options, "status-utf8", 1); else From c1d6d7ac6b7eb6c3d3939d2c837281d3ce8caf1b Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 29 Jul 2009 14:17:26 +0000 Subject: [PATCH 0196/1180] Rename struct hdrtype to msgtype which is a better name and can be used even when struct hdr disappears. --- client-fn.c | 2 +- client-msg.c | 2 +- server-fn.c | 4 ++-- server-msg.c | 2 +- tmux.c | 10 +++++----- tmux.h | 10 +++++----- 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/client-fn.c b/client-fn.c index b7a9b1f0..8e5e3722 100644 --- a/client-fn.c +++ b/client-fn.c @@ -63,7 +63,7 @@ client_fill_session(struct msg_command_data *data) void client_write_server( - struct client_ctx *cctx, enum hdrtype type, void *buf, size_t len) + struct client_ctx *cctx, enum msgtype type, void *buf, size_t len) { struct hdr hdr; diff --git a/client-msg.c b/client-msg.c index 845f10b0..f282478b 100644 --- a/client-msg.c +++ b/client-msg.c @@ -33,7 +33,7 @@ int client_msg_fn_exited(struct hdr *, struct client_ctx *); int client_msg_fn_suspend(struct hdr *, struct client_ctx *); struct client_msg { - enum hdrtype type; + enum msgtype type; int (*fn)(struct hdr *, struct client_ctx *); }; struct client_msg client_msg_table[] = { diff --git a/server-fn.c b/server-fn.c index 05f4168e..8a4b1f1d 100644 --- a/server-fn.c +++ b/server-fn.c @@ -58,7 +58,7 @@ server_write_error(struct client *c, const char *msg) void server_write_client( - struct client *c, enum hdrtype type, const void *buf, size_t len) + struct client *c, enum msgtype type, const void *buf, size_t len) { struct hdr hdr; @@ -74,7 +74,7 @@ server_write_client( void server_write_session( - struct session *s, enum hdrtype type, const void *buf, size_t len) + struct session *s, enum msgtype type, const void *buf, size_t len) { struct client *c; u_int i; diff --git a/server-msg.c b/server-msg.c index 9d1f84f8..14b2d4e4 100644 --- a/server-msg.c +++ b/server-msg.c @@ -41,7 +41,7 @@ void printflike2 server_msg_fn_command_info( struct cmd_ctx *, const char *, ...); struct server_msg { - enum hdrtype type; + enum msgtype type; void (*fn)(struct hdr *, struct client *); }; const struct server_msg server_msg_table[] = { diff --git a/tmux.c b/tmux.c index 14ba0538..3845022d 100644 --- a/tmux.c +++ b/tmux.c @@ -57,8 +57,8 @@ char *socket_path; __dead void usage(void); char *makesockpath(const char *); -int prepare_unlock(enum hdrtype *, void **, size_t *, int); -int prepare_cmd(enum hdrtype *, void **, size_t *, int, char **); +int prepare_unlock(enum msgtype *, void **, size_t *, int); +int prepare_cmd(enum msgtype *, void **, size_t *, int, char **); __dead void usage(void) @@ -203,7 +203,7 @@ makesockpath(const char *label) } int -prepare_unlock(enum hdrtype *msg, void **buf, size_t *len, int argc) +prepare_unlock(enum msgtype *msg, void **buf, size_t *len, int argc) { static struct msg_unlock_data unlockdata; char *pass; @@ -232,7 +232,7 @@ prepare_unlock(enum hdrtype *msg, void **buf, size_t *len, int argc) } int -prepare_cmd(enum hdrtype *msg, void **buf, size_t *len, int argc, char **argv) +prepare_cmd(enum msgtype *msg, void **buf, size_t *len, int argc, char **argv) { static struct msg_command_data cmddata; @@ -258,7 +258,7 @@ main(int argc, char **argv) struct cmd_list *cmdlist; struct cmd *cmd; struct pollfd pfd; - enum hdrtype msg; + enum msgtype msg; struct hdr hdr; struct passwd *pw; struct msg_print_data printdata; diff --git a/tmux.h b/tmux.h index 7fc2117c..f16652a7 100644 --- a/tmux.h +++ b/tmux.h @@ -287,7 +287,7 @@ struct tty_term_code_entry { }; /* Message codes. */ -enum hdrtype { +enum msgtype { MSG_COMMAND, MSG_DETACH, MSG_ERROR, @@ -313,7 +313,7 @@ enum hdrtype { * the tmux client hang even if the protocol version is bumped. */ struct hdr { - enum hdrtype type; + enum msgtype type; size_t size; }; @@ -1351,7 +1351,7 @@ int client_main(struct client_ctx *); int client_msg_dispatch(struct client_ctx *); /* client-fn.c */ -void client_write_server(struct client_ctx *, enum hdrtype, void *, size_t); +void client_write_server(struct client_ctx *, enum msgtype, void *, size_t); void client_fill_session(struct msg_command_data *); /* key-bindings.c */ @@ -1385,9 +1385,9 @@ int server_msg_dispatch(struct client *); const char **server_fill_environ(struct session *); void server_write_error(struct client *, const char *); void server_write_client( - struct client *, enum hdrtype, const void *, size_t); + struct client *, enum msgtype, const void *, size_t); void server_write_session( - struct session *, enum hdrtype, const void *, size_t); + struct session *, enum msgtype, const void *, size_t); void server_redraw_client(struct client *); void server_status_client(struct client *); void server_redraw_session(struct session *); From 2b331084b4c69dafac6e2bb1d5b02193666cf0e0 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 29 Jul 2009 17:03:16 +0000 Subject: [PATCH 0197/1180] Add an additional heuristic to work out the current session when run from the command line. The name of all slave ptys in the server is known, so if the client was run on a tty, look for any sessions containing that tty and use the most recently created. This is more reliable than looking at $TMUX if windows have been moved or linked between sessions. --- cmd.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 46 insertions(+), 7 deletions(-) diff --git a/cmd.c b/cmd.c index 9fda3dcc..820521d0 100644 --- a/cmd.c +++ b/cmd.c @@ -103,7 +103,7 @@ const struct cmd_entry *cmd_table[] = { NULL }; -struct session *cmd_newest_session(void); +struct session *cmd_newest_session(struct sessions *); struct client *cmd_lookup_client(const char *); struct session *cmd_lookup_session(const char *, int *); struct winlink *cmd_lookup_window(struct session *, const char *, int *); @@ -281,18 +281,57 @@ cmd_print(struct cmd *cmd, char *buf, size_t len) /* * Figure out the current session. Use: 1) the current session, if the command - * context has one; 2) the session specified in the TMUX variable from the - * environment (as passed from the client); 3) the newest session. + * context has one; 2) the session containing the pty of the calling client, if + * any 3) the session specified in the TMUX variable from the environment (as + * passed from the client); 3) the newest session. */ struct session * cmd_current_session(struct cmd_ctx *ctx) { struct msg_command_data *data = ctx->msgdata; + struct client *c = ctx->cmdclient; struct session *s; + struct sessions ss; + struct winlink *wl; + struct window_pane *wp; + u_int i; + int found; if (ctx->cursession != NULL) return (ctx->cursession); + /* + * If the name of the calling client's pty is know, build a list of the + * sessions that contain it and if any choose either the first or the + * newest. + */ + if (c != NULL && c->tty.path != NULL) { + ARRAY_INIT(&ss); + for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { + if ((s = ARRAY_ITEM(&sessions, i)) == NULL) + continue; + found = 0; + RB_FOREACH(wl, winlinks, &s->windows) { + TAILQ_FOREACH(wp, &wl->window->panes, entry) { + if (strcmp(wp->tty, c->tty.path) == 0) { + found = 1; + break; + } + } + if (found) + break; + } + if (found) + ARRAY_ADD(&ss, s); + } + + s = cmd_newest_session(&ss); + ARRAY_FREE(&ss); + if (s != NULL) + return (s); + } + + /* Use the session from the TMUX environment variable. */ if (data != NULL && data->pid != -1) { if (data->pid != getpid()) return (NULL); @@ -303,20 +342,20 @@ cmd_current_session(struct cmd_ctx *ctx) return (s); } - return (cmd_newest_session()); + return (cmd_newest_session(&sessions)); } /* Find the newest session. */ struct session * -cmd_newest_session(void) +cmd_newest_session(struct sessions *ss) { struct session *s, *snewest; struct timeval *tv = NULL; u_int i; snewest = NULL; - for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { - if ((s = ARRAY_ITEM(&sessions, i)) == NULL) + for (i = 0; i < ARRAY_LENGTH(ss); i++) { + if ((s = ARRAY_ITEM(ss, i)) == NULL) continue; if (tv == NULL || timercmp(&s->tv, tv, >)) { From a419e73f7a356ef3d63f79e3b870fbd4defd74bc Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 30 Jul 2009 07:04:50 +0000 Subject: [PATCH 0198/1180] Add a mode-mouse option to prevent tmux taking over the mouse in choice or copy modes. --- cmd-set-window-option.c | 1 + tmux.1 | 10 ++++++++-- tmux.c | 3 ++- window-choose.c | 3 ++- window-copy.c | 3 ++- 5 files changed, 15 insertions(+), 5 deletions(-) diff --git a/cmd-set-window-option.c b/cmd-set-window-option.c index c24f3592..1d90425d 100644 --- a/cmd-set-window-option.c +++ b/cmd-set-window-option.c @@ -60,6 +60,7 @@ const struct set_option_entry set_window_option_table[] = { { "mode-bg", SET_OPTION_COLOUR, 0, 0, NULL }, { "mode-fg", SET_OPTION_COLOUR, 0, 0, NULL }, { "mode-keys", SET_OPTION_CHOICE, 0, 0, set_option_mode_keys_list }, + { "mode-mouse", SET_OPTION_FLAG, 0, 0, NULL }, { "monitor-activity", SET_OPTION_FLAG, 0, 0, NULL }, { "monitor-content", SET_OPTION_STRING, 0, 0, NULL }, { "remain-on-exit", SET_OPTION_FLAG, 0, 0, NULL }, diff --git a/tmux.1 b/tmux.1 index 06bc76bd..81a987c7 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1529,9 +1529,15 @@ Set window modes foreground colour. .It Xo Ic mode-keys .Op Ic vi | Ic emacs .Xc -Use vi or emacs-style -key bindings in scroll and copy modes. +Use vi or emacs-style key bindings in scroll, copy and choice modes. Key bindings default to emacs. +.It Xo Ic mode-mouse +.Op Ic on | Ic off +.Xc +Mouse state in modes. If on, +.Nm +will respond to mouse clicks by moving the cursor in copy mode or selecting an +option in choice mode. .It Xo Ic monitor-activity .Op Ic on | Ic off .Xc diff --git a/tmux.c b/tmux.c index 3845022d..dd7b83f5 100644 --- a/tmux.c +++ b/tmux.c @@ -378,12 +378,13 @@ main(int argc, char **argv) options_set_number(&global_w_options, "clock-mode-style", 1); options_set_number(&global_w_options, "force-height", 0); options_set_number(&global_w_options, "force-width", 0); - options_set_number(&global_w_options, "mode-attr", GRID_ATTR_REVERSE); options_set_number(&global_w_options, "main-pane-width", 81); options_set_number(&global_w_options, "main-pane-height", 24); + options_set_number(&global_w_options, "mode-attr", GRID_ATTR_REVERSE); options_set_number(&global_w_options, "mode-bg", 3); options_set_number(&global_w_options, "mode-fg", 0); options_set_number(&global_w_options, "mode-keys", MODEKEY_EMACS); + options_set_number(&global_w_options, "mode-mouse", 1); options_set_number(&global_w_options, "monitor-activity", 0); options_set_string(&global_w_options, "monitor-content", "%s", ""); if (flags & IDENTIFY_UTF8) diff --git a/window-choose.c b/window-choose.c index e7d847de..b1d9192a 100644 --- a/window-choose.c +++ b/window-choose.c @@ -123,7 +123,8 @@ window_choose_init(struct window_pane *wp) s = &data->screen; screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0); s->mode &= ~MODE_CURSOR; - s->mode |= MODE_MOUSE; + if (options_get_number(&wp->window->options, "mode-mouse")) + s->mode |= MODE_MOUSE; keys = options_get_number(&wp->window->options, "mode-keys"); if (keys == MODEKEY_EMACS) diff --git a/window-copy.c b/window-copy.c index 8ea32126..340c9c75 100644 --- a/window-copy.c +++ b/window-copy.c @@ -104,7 +104,8 @@ window_copy_init(struct window_pane *wp) s = &data->screen; screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0); - s->mode |= MODE_MOUSE; + if (options_get_number(&wp->window->options, "mode-mouse")) + s->mode |= MODE_MOUSE; keys = options_get_number(&wp->window->options, "mode-keys"); if (keys == MODEKEY_EMACS) From a87228b4ff85087600b0a077cb88b41506a60ff1 Mon Sep 17 00:00:00 2001 From: Jason McIntyre Date: Thu, 30 Jul 2009 13:31:22 +0000 Subject: [PATCH 0199/1180] new sentence, new line; --- tmux.1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tmux.1 b/tmux.1 index 81a987c7..e23ebaaa 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1534,7 +1534,8 @@ Key bindings default to emacs. .It Xo Ic mode-mouse .Op Ic on | Ic off .Xc -Mouse state in modes. If on, +Mouse state in modes. +If on, .Nm will respond to mouse clicks by moving the cursor in copy mode or selecting an option in choice mode. From 071494d8faff83287088bbdcc38db1414c0123b9 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 30 Jul 2009 13:45:56 +0000 Subject: [PATCH 0200/1180] Merge pane number into the target specification for pane commands. Instead of using -p index, a target pane is now addressed with the normal -t window form but suffixed with a period and a pane index, for example :0.2 or mysess:mywin.1. An unadorned number such as -t 1 is tried as a pane index in the current window, if that fails the same rules are followed as for a target window and the current pane in that window used. As a side-effect this now means that swap-pane can swap panes between different windows. Note that this changes the syntax of the break-pane, clear-history, kill-pane, resize-pane, select-pane and swap-pane commands. --- cmd-break-pane.c | 25 ++--- cmd-clear-history.c | 23 ++-- cmd-generic.c | 90 --------------- cmd-kill-pane.c | 23 ++-- cmd-resize-pane.c | 25 ++--- cmd-select-pane.c | 25 ++--- cmd-swap-pane.c | 259 ++++++++++++-------------------------------- cmd.c | 85 +++++++++++++++ tmux.1 | 69 ++++++------ tmux.h | 20 +--- 10 files changed, 233 insertions(+), 411 deletions(-) diff --git a/cmd-break-pane.c b/cmd-break-pane.c index 6a237c6d..57622119 100644 --- a/cmd-break-pane.c +++ b/cmd-break-pane.c @@ -30,39 +30,30 @@ int cmd_break_pane_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_break_pane_entry = { "break-pane", "breakp", - CMD_PANE_WINDOW_USAGE " [-d]", + CMD_TARGET_PANE_USAGE " [-d]", 0, CMD_CHFLAG('d'), - cmd_pane_init, - cmd_pane_parse, + cmd_target_init, + cmd_target_parse, cmd_break_pane_exec, - cmd_pane_free, - cmd_pane_print + cmd_target_free, + cmd_target_print }; int cmd_break_pane_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_pane_data *data = self->data; + struct cmd_target_data *data = self->data; struct winlink *wl; struct session *s; struct window_pane *wp; struct window *w; char *cause; - if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL) + if ((wl = cmd_find_pane(ctx, data->target, &s, &wp)) == NULL) return (-1); - if (data->pane == -1) - wp = wl->window->active; - else { - wp = window_pane_at_index(wl->window, data->pane); - if (wp == NULL) { - ctx->error(ctx, "no pane: %d", data->pane); - return (-1); - } - } if (window_count_panes(wl->window) == 1) { - ctx->error(ctx, "can't break pane: %d", data->pane); + ctx->error(ctx, "can't break with only one pane"); return (-1); } diff --git a/cmd-clear-history.c b/cmd-clear-history.c index 2e4c118d..0a87b9b0 100644 --- a/cmd-clear-history.c +++ b/cmd-clear-history.c @@ -28,34 +28,25 @@ int cmd_clear_history_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_clear_history_entry = { "clear-history", "clearhist", - CMD_PANE_WINDOW_USAGE, + CMD_TARGET_PANE_USAGE, 0, 0, - cmd_pane_init, - cmd_pane_parse, + cmd_target_init, + cmd_target_parse, cmd_clear_history_exec, - cmd_pane_free, - cmd_pane_print + cmd_target_free, + cmd_target_print }; int cmd_clear_history_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_pane_data *data = self->data; + struct cmd_target_data *data = self->data; struct winlink *wl; struct window_pane *wp; struct grid *gd; - if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) + if ((wl = cmd_find_pane(ctx, data->target, NULL, &wp)) == NULL) return (-1); - if (data->pane == -1) - wp = wl->window->active; - else { - wp = window_pane_at_index(wl->window, data->pane); - if (wp == NULL) { - ctx->error(ctx, "no pane: %d", data->pane); - return (-1); - } - } gd = wp->base.grid; grid_move_lines(gd, 0, gd->hsize, gd->sy); diff --git a/cmd-generic.c b/cmd-generic.c index 39c18d51..92d9a9bd 100644 --- a/cmd-generic.c +++ b/cmd-generic.c @@ -467,93 +467,3 @@ cmd_option_print(struct cmd *self, char *buf, size_t len) off += xsnprintf(buf + off, len - off, " %s", data->value); return (off); } - -void -cmd_pane_init(struct cmd *self, unused int key) -{ - struct cmd_pane_data *data; - - self->data = data = xmalloc(sizeof *data); - data->chflags = 0; - data->target = NULL; - data->arg = NULL; - data->pane = -1; -} - -int -cmd_pane_parse(struct cmd *self, int argc, char **argv, char **cause) -{ - struct cmd_pane_data *data; - const struct cmd_entry *entry = self->entry; - int opt, n; - const char *errstr; - - /* Don't use the entry version since it may be dependent on key. */ - cmd_pane_init(self, 0); - data = self->data; - - while ((opt = cmd_getopt(argc, argv, "p:t:", entry->chflags)) != -1) { - if (cmd_flags(opt, entry->chflags, &data->chflags) == 0) - continue; - switch (opt) { - case 'p': - if (data->pane == -1) { - n = strtonum(optarg, 0, INT_MAX, &errstr); - if (errstr != NULL) { - xasprintf(cause, "pane %s", errstr); - goto error; - } - data->pane = n; - } - break; - case 't': - if (data->target == NULL) - data->target = xstrdup(optarg); - break; - default: - goto usage; - } - } - argc -= optind; - argv += optind; - - if (cmd_fill_argument(self->entry->flags, &data->arg, argc, argv) != 0) - goto usage; - return (0); - -usage: - xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); - -error: - self->entry->free(self); - return (-1); -} - -void -cmd_pane_free(struct cmd *self) -{ - struct cmd_pane_data *data = self->data; - - if (data->target != NULL) - xfree(data->target); - if (data->arg != NULL) - xfree(data->arg); - xfree(data); -} - -size_t -cmd_pane_print(struct cmd *self, char *buf, size_t len) -{ - struct cmd_pane_data *data = self->data; - size_t off = 0; - - off += xsnprintf(buf, len, "%s", self->entry->name); - if (data == NULL) - return (off); - off += cmd_print_flags(buf, len, off, data->chflags); - if (off < len && data->target != NULL) - off += cmd_prarg(buf + off, len - off, " -t ", data->target); - if (off < len && data->arg != NULL) - off += cmd_prarg(buf + off, len - off, " ", data->arg); - return (off); -} diff --git a/cmd-kill-pane.c b/cmd-kill-pane.c index 14b07c82..1548a75e 100644 --- a/cmd-kill-pane.c +++ b/cmd-kill-pane.c @@ -30,33 +30,24 @@ int cmd_kill_pane_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_kill_pane_entry = { "kill-pane", "killp", - CMD_PANE_WINDOW_USAGE, + CMD_TARGET_PANE_USAGE, 0, 0, - cmd_pane_init, - cmd_pane_parse, + cmd_target_init, + cmd_target_parse, cmd_kill_pane_exec, - cmd_pane_free, - cmd_pane_print + cmd_target_free, + cmd_target_print }; int cmd_kill_pane_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_pane_data *data = self->data; + struct cmd_target_data *data = self->data; struct winlink *wl; struct window_pane *wp; - if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) + if ((wl = cmd_find_pane(ctx, data->target, NULL, &wp)) == NULL) return (-1); - if (data->pane == -1) - wp = wl->window->active; - else { - wp = window_pane_at_index(wl->window, data->pane); - if (wp == NULL) { - ctx->error(ctx, "no pane: %d", data->pane); - return (-1); - } - } if (window_count_panes(wl->window) == 1) { /* Only one pane, kill the window. */ diff --git a/cmd-resize-pane.c b/cmd-resize-pane.c index f7928803..30fbc76a 100644 --- a/cmd-resize-pane.c +++ b/cmd-resize-pane.c @@ -31,22 +31,22 @@ int cmd_resize_pane_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_resize_pane_entry = { "resize-pane", "resizep", - CMD_PANE_WINDOW_USAGE "[-DU] [adjustment]", + "[-DU] " CMD_TARGET_PANE_USAGE " [adjustment]", CMD_ARG01, CMD_CHFLAG('D')|CMD_CHFLAG('L')|CMD_CHFLAG('R')|CMD_CHFLAG('U'), cmd_resize_pane_init, - cmd_pane_parse, + cmd_target_parse, cmd_resize_pane_exec, - cmd_pane_free, - cmd_pane_print + cmd_target_free, + cmd_target_print }; void cmd_resize_pane_init(struct cmd *self, int key) { - struct cmd_pane_data *data; + struct cmd_target_data *data; - cmd_pane_init(self, key); + cmd_target_init(self, key); data = self->data; if (key == (KEYC_UP | KEYC_CTRL)) @@ -79,23 +79,14 @@ cmd_resize_pane_init(struct cmd *self, int key) int cmd_resize_pane_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_pane_data *data = self->data; + struct cmd_target_data *data = self->data; struct winlink *wl; const char *errstr; struct window_pane *wp; u_int adjust; - if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) + if ((wl = cmd_find_pane(ctx, data->target, NULL, &wp)) == NULL) return (-1); - if (data->pane == -1) - wp = wl->window->active; - else { - wp = window_pane_at_index(wl->window, data->pane); - if (wp == NULL) { - ctx->error(ctx, "no pane: %d", data->pane); - return (-1); - } - } if (data->arg == NULL) adjust = 1; diff --git a/cmd-select-pane.c b/cmd-select-pane.c index 055c2e3b..3923ea73 100644 --- a/cmd-select-pane.c +++ b/cmd-select-pane.c @@ -28,36 +28,27 @@ int cmd_select_pane_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_select_pane_entry = { "select-pane", "selectp", - CMD_PANE_WINDOW_USAGE, + CMD_TARGET_PANE_USAGE, 0, 0, - cmd_pane_init, - cmd_pane_parse, + cmd_target_init, + cmd_target_parse, cmd_select_pane_exec, - cmd_pane_free, - cmd_pane_print + cmd_target_free, + cmd_target_print }; int cmd_select_pane_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_pane_data *data = self->data; + struct cmd_target_data *data = self->data; struct winlink *wl; struct window_pane *wp; - if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) + if ((wl = cmd_find_pane(ctx, data->target, NULL, &wp)) == NULL) return (-1); - if (data->pane == -1) - wp = wl->window->active; - else { - wp = window_pane_at_index(wl->window, data->pane); - if (wp == NULL) { - ctx->error(ctx, "no pane: %d", data->pane); - return (-1); - } - } if (!window_pane_visible(wp)) { - ctx->error(ctx, "pane %d is not visible", data->pane); + ctx->error(ctx, "pane not visible: %s", data->target); return (-1); } window_set_active_pane(wl->window, wp); diff --git a/cmd-swap-pane.c b/cmd-swap-pane.c index 7222e12c..4516d2ca 100644 --- a/cmd-swap-pane.c +++ b/cmd-swap-pane.c @@ -26,191 +26,93 @@ * Swap two panes. */ -int cmd_swap_pane_parse(struct cmd *, int, char **, char **); -int cmd_swap_pane_exec(struct cmd *, struct cmd_ctx *); -void cmd_swap_pane_free(struct cmd *); void cmd_swap_pane_init(struct cmd *, int); -size_t cmd_swap_pane_print(struct cmd *, char *, size_t); - -struct cmd_swap_pane_data { - char *target; - int src; - int dst; - int flag_detached; - int flag_up; - int flag_down; -}; +int cmd_swap_pane_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_swap_pane_entry = { "swap-pane", "swapp", - "[-dDU] [-t target-window] [-p src-index] [-q dst-index]", - 0, 0, + "[-dDU] " CMD_SRCDST_PANE_USAGE, + 0, CMD_CHFLAG('d')|CMD_CHFLAG('D')|CMD_CHFLAG('U'), cmd_swap_pane_init, - cmd_swap_pane_parse, + cmd_srcdst_parse, cmd_swap_pane_exec, - cmd_swap_pane_free, - cmd_swap_pane_print + cmd_srcdst_free, + cmd_srcdst_print }; void cmd_swap_pane_init(struct cmd *self, int key) { - struct cmd_swap_pane_data *data; + struct cmd_target_data *data; - self->data = data = xmalloc(sizeof *data); - data->target = NULL; - data->src = -1; - data->dst = -1; - data->flag_detached = 0; - data->flag_up = 0; - data->flag_down = 0; - - switch (key) { - case '{': - data->flag_up = 1; - break; - case '}': - data->flag_down = 1; - break; - } -} - -int -cmd_swap_pane_parse(struct cmd *self, int argc, char **argv, char **cause) -{ - struct cmd_swap_pane_data *data; - int opt, n; - const char *errstr; - - self->entry->init(self, 0); + cmd_srcdst_init(self, key); data = self->data; - while ((opt = getopt(argc, argv, "dDt:p:q:U")) != -1) { - switch (opt) { - case 'd': - data->flag_detached = 1; - break; - case 'D': - data->flag_up = 0; - data->flag_down = 1; - data->dst = -1; - break; - case 't': - if (data->target == NULL) - data->target = xstrdup(optarg); - break; - case 'p': - if (data->src == -1) { - n = strtonum(optarg, 0, INT_MAX, &errstr); - if (errstr != NULL) { - xasprintf(cause, "src %s", errstr); - goto error; - } - data->src = n; - } - break; - case 'q': - if (data->dst == -1) { - n = strtonum(optarg, 0, INT_MAX, &errstr); - if (errstr != NULL) { - xasprintf(cause, "dst %s", errstr); - goto error; - } - data->dst = n; - } - data->flag_up = 0; - data->flag_down = 0; - break; - case 'U': - data->flag_up = 1; - data->flag_down = 0; - data->dst = -1; - break; - - default: - goto usage; - } - } - argc -= optind; - argv += optind; - if (argc != 0) - goto usage; - - return (0); - -usage: - xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); - -error: - self->entry->free(self); - return (-1); + if (key == '{') + data->chflags |= CMD_CHFLAG('U'); + else if (key == '}') + data->chflags |= CMD_CHFLAG('D'); } int cmd_swap_pane_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_swap_pane_data *data = self->data; - struct winlink *wl; - struct window *w; - struct window_pane *tmp_wp, *src_wp, *dst_wp; - struct layout_cell *lc; - u_int sx, sy, xoff, yoff; + struct cmd_srcdst_data *data = self->data; + struct winlink *src_wl, *dst_wl; + struct window *src_w, *dst_w; + struct window_pane *tmp_wp, *src_wp, *dst_wp; + struct layout_cell *src_lc, *dst_lc; + u_int sx, sy, xoff, yoff; if (data == NULL) return (0); - if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) + if ((dst_wl = cmd_find_pane(ctx, data->dst, NULL, &dst_wp)) == NULL) return (-1); - w = wl->window; + dst_w = dst_wl->window; - if (data->src == -1) - src_wp = w->active; - else { - src_wp = window_pane_at_index(w, data->src); - if (src_wp == NULL) { - ctx->error(ctx, "no pane: %d", data->src); + if (data->src == NULL) { + src_wl = dst_wl; + src_w = dst_w; + if (data->chflags & CMD_CHFLAG('D')) { + src_wp = TAILQ_NEXT(dst_wp, entry); + if (src_wp == NULL) + src_wp = TAILQ_FIRST(&dst_w->panes); + } else if (data->chflags & CMD_CHFLAG('U')) { + src_wp = TAILQ_PREV(dst_wp, window_panes, entry); + if (src_wp == NULL) + src_wp = TAILQ_LAST(&dst_w->panes, window_panes); + } else + return (0); + } else { + src_wl = cmd_find_pane(ctx, data->src, NULL, &src_wp); + if (src_wl == NULL) return (-1); - } - } - if (data->dst == -1) - dst_wp = w->active; - else { - dst_wp = window_pane_at_index(w, data->dst); - if (dst_wp == NULL) { - ctx->error(ctx, "no pane: %d", data->dst); - return (-1); - } - } - - if (data->dst == -1 && data->flag_up) { - if ((dst_wp = TAILQ_PREV(src_wp, window_panes, entry)) == NULL) - dst_wp = TAILQ_LAST(&w->panes, window_panes); - } - if (data->dst == -1 && data->flag_down) { - if ((dst_wp = TAILQ_NEXT(src_wp, entry)) == NULL) - dst_wp = TAILQ_FIRST(&w->panes); + src_w = src_wl->window; } if (src_wp == dst_wp) return (0); tmp_wp = TAILQ_PREV(dst_wp, window_panes, entry); - TAILQ_REMOVE(&w->panes, dst_wp, entry); - TAILQ_REPLACE(&w->panes, src_wp, dst_wp, entry); + TAILQ_REMOVE(&dst_w->panes, dst_wp, entry); + TAILQ_REPLACE(&src_w->panes, src_wp, dst_wp, entry); if (tmp_wp == src_wp) tmp_wp = dst_wp; if (tmp_wp == NULL) - TAILQ_INSERT_HEAD(&w->panes, src_wp, entry); + TAILQ_INSERT_HEAD(&dst_w->panes, src_wp, entry); else - TAILQ_INSERT_AFTER(&w->panes, tmp_wp, src_wp, entry); + TAILQ_INSERT_AFTER(&dst_w->panes, tmp_wp, src_wp, entry); - lc = src_wp->layout_cell; - src_wp->layout_cell = dst_wp->layout_cell; - if (src_wp->layout_cell != NULL) - src_wp->layout_cell->wp = src_wp; - dst_wp->layout_cell = lc; - if (dst_wp->layout_cell != NULL) - dst_wp->layout_cell->wp = dst_wp; + src_lc = src_wp->layout_cell; + dst_lc = dst_wp->layout_cell; + src_lc->wp = dst_wp; + dst_wp->layout_cell = src_lc; + dst_lc->wp = src_wp; + src_wp->layout_cell = dst_lc; + + src_wp->window = dst_w; + dst_wp->window = src_w; sx = src_wp->sx; sy = src_wp->sy; xoff = src_wp->xoff; yoff = src_wp->yoff; @@ -219,51 +121,24 @@ cmd_swap_pane_exec(struct cmd *self, struct cmd_ctx *ctx) dst_wp->xoff = xoff; dst_wp->yoff = yoff; window_pane_resize(dst_wp, sx, sy); - if (!data->flag_detached) { - tmp_wp = dst_wp; - if (!window_pane_visible(tmp_wp)) - tmp_wp = src_wp; - window_set_active_pane(w, tmp_wp); + if (!(data->chflags & CMD_CHFLAG('d'))) { + if (src_w != dst_w) { + window_set_active_pane(src_w, dst_wp); + window_set_active_pane(dst_w, src_wp); + } else { + tmp_wp = dst_wp; + if (!window_pane_visible(tmp_wp)) + tmp_wp = src_wp; + window_set_active_pane(src_w, tmp_wp); + } + } else { + if (src_w->active == src_wp) + window_set_active_pane(src_w, dst_wp); + if (dst_w->active == dst_wp) + window_set_active_pane(dst_w, src_wp); } - server_redraw_window(w); + server_redraw_window(src_w); + server_redraw_window(dst_w); return (0); } - -void -cmd_swap_pane_free(struct cmd *self) -{ - struct cmd_swap_pane_data *data = self->data; - - if (data->target != NULL) - xfree(data->target); - xfree(data); -} - -size_t -cmd_swap_pane_print(struct cmd *self, char *buf, size_t len) -{ - struct cmd_swap_pane_data *data = self->data; - size_t off = 0; - - off += xsnprintf(buf, len, "%s", self->entry->name); - if (data == NULL) - return (off); - if (off < len && - (data->flag_down || data->flag_up || data->flag_detached)) { - off += xsnprintf(buf + off, len - off, " -"); - if (off < len && data->flag_detached) - off += xsnprintf(buf + off, len - off, "d"); - if (off < len && data->flag_up) - off += xsnprintf(buf + off, len - off, "D"); - if (off < len && data->flag_down) - off += xsnprintf(buf + off, len - off, "U"); - } - if (off < len && data->target != NULL) - off += cmd_prarg(buf + off, len - off, " -t ", data->target); - if (off < len && data->src != -1) - off += xsnprintf(buf + off, len - off, " -p %d", data->src); - if (off < len && data->dst != -1) - off += xsnprintf(buf + off, len - off, " -q %d", data->dst); - return (off); -} diff --git a/cmd.c b/cmd.c index 820521d0..31b80b50 100644 --- a/cmd.c +++ b/cmd.c @@ -771,3 +771,88 @@ not_found: xfree(sessptr); return (-2); } + +/* + * Find the target session, window and pane number or report an error and + * return NULL. The pane number is separated from the session:window by a ., + * such as mysession:mywindow.0. + */ +struct winlink * +cmd_find_pane(struct cmd_ctx *ctx, + const char *arg, struct session **sp, struct window_pane **wpp) +{ + struct session *s; + struct winlink *wl; + const char *period; + char *winptr, *paneptr; + const char *errstr; + u_int idx; + + /* Get the current session. */ + if ((s = cmd_current_session(ctx)) == NULL) { + ctx->error(ctx, "can't establish current session"); + return (NULL); + } + if (sp != NULL) + *sp = s; + + /* A NULL argument means the current session, window and pane. */ + if (arg == NULL) { + *wpp = s->curw->window->active; + return (s->curw); + } + + /* Look for a separating period. */ + if ((period = strrchr(arg, '.')) == NULL) + goto no_period; + + /* Pull out the window part and parse it. */ + winptr = xstrdup(arg); + winptr[period - arg] = '\0'; + if (*winptr == '\0') + wl = s->curw; + else if ((wl = cmd_find_window(ctx, winptr, sp)) == NULL) + goto error; + + /* Find the pane section and look it up. */ + paneptr = winptr + (period - arg) + 1; + if (*paneptr == '\0') + *wpp = wl->window->active; + else { + idx = strtonum(paneptr, 0, INT_MAX, &errstr); + if (errstr != NULL) { + ctx->error(ctx, "pane %s: %s", errstr, paneptr); + goto error; + } + *wpp = window_pane_at_index(wl->window, idx); + if (*wpp == NULL) { + ctx->error(ctx, "no such pane: %u", idx); + goto error; + } + } + + xfree(winptr); + return (wl); + +no_period: + /* Try as a pane number alone. */ + idx = strtonum(arg, 0, INT_MAX, &errstr); + if (errstr != NULL) + goto lookup_window; + + /* Try index in the current session and window. */ + if ((*wpp = window_pane_at_index(s->curw->window, idx)) == NULL) + goto lookup_window; + + return (s->curw); + +lookup_window: + /* Try as a window and use the active pane. */ + if ((wl = cmd_find_window(ctx, arg, sp)) != NULL) + *wpp = wl->window->active; + return (wl); + +error: + xfree(winptr); + return (NULL); +} diff --git a/tmux.1 b/tmux.1 index e23ebaaa..7a2a3bf2 100644 --- a/tmux.1 +++ b/tmux.1 @@ -534,9 +534,10 @@ Most commands accept the optional argument with one of .Ar target-client , .Ar target-session +.Ar target-window , or -.Ar target-window . -These specify the client, session or window which a command should affect. +.Ar target-pane . +These specify the client, session, window or pane which a command should affect. .Ar target-client is the name of the .Xr pty 4 @@ -598,6 +599,19 @@ When the argument does not contain a colon, first attempts to parse it as window; if that fails, an attempt is made to match a session. .Pp +.Ar target-pane +takes a similar form to +.Ar target-window +but with the optional addition of a period followed by a pane index, for +example: mysession:mywindow.1. +If the pane index is omitted, the currently active pane in the specified +window is used. +If neither a colon nor period appears, +.Nm +first attempts to use the argument as a pane index; if that fails, it is looked +up as for +.Ar target-window . +.Pp Multiple commands may be specified together as part of a .Em command sequence . Each command should be separated by spaces and a semicolon; @@ -687,12 +701,12 @@ To view the default bindings and possible commands, see the command. .It Xo Ic break-pane .Op Fl d -.Op Fl p Ar pane-index -.Op Fl t Ar target-window +.Op Fl t Ar target-pane .Xc .D1 (alias: Ic breakp ) -Break the current pane off from its containing window to make it the only pane -in a new window. +Break +.Ar target-pane +off from its containing window to make it the only pane in a new window. If .Fl d is given, the new window does not become the current window. @@ -711,8 +725,7 @@ attached to the current client may be selected interactively from a list. This command works only from inside .Nm . .It Xo Ic clear-history -.Op Fl p Ar pane-index -.Op Fl t Ar target-window +.Op Fl t Ar target-pane .Xc .D1 (alias: Ic clearhist ) Remove and free the history for the specified pane. @@ -782,8 +795,7 @@ Display a message (see the option below) in the status line. .It Xo Ic down-pane -.Op Fl p Ar pane-index -.Op Fl t Ar target-window +.Op Fl t Ar target-pane .Xc .D1 (alias: Ic downp ) Move down a pane. @@ -818,8 +830,7 @@ if .Ar shell-command returns success. .It Xo Ic kill-pane -.Op Fl p Ar pane-index -.Op Fl t Ar target-window +.Op Fl t Ar target-pane .Xc .D1 (alias: Ic killp ) Destroy the given pane. @@ -1058,8 +1069,7 @@ if specified, to .Ar new-name . .It Xo Ic resize-pane .Op Fl DLRU -.Op Fl p Ar pane-index -.Op Fl t Ar target-window +.Op Fl t Ar target-pane .Op Ar adjustment .Xc .D1 (alias: Ic resizep ) @@ -1130,12 +1140,11 @@ If .Ar layout-name is not given, the last layout used (if any) is reapplied. .It Xo Ic select-pane -.Op Fl p Ar pane-index -.Op Fl t Ar target-window +.Op Fl t Ar target-pane .Xc .D1 (alias: Ic selectp ) Make pane -.Ar pane-index +.Ar target-pane the active pane in window .Ar target-window . .It Xo Ic select-prompt @@ -1297,11 +1306,9 @@ Whether a key repeats may be set when it is bound using the .Fl r flag to .Ic bind-key . -Repeat is enabled for the default keys of the -.Ic resize-pane-up -and -.Ic resize-pane-down -commands. +Repeat is enabled for the default keys bound to the +.Ic resize-pane +command. .It Xo Ic set-remain-on-exit .Op Ic on | Ic off .Xc @@ -1659,19 +1666,18 @@ Suspend a client by sending (tty stop). .It Xo Ic swap-pane .Op Fl dDU -.Op Fl p Ar src-index -.Op Fl t Ar target-window -.Op Fl q Ar dst-index +.Op Fl s Ar src-pane +.Op Fl t Ar dst-pane .Xc .D1 (alias: Ic swapp ) -Swap two panes within a window. +Swap two panes. If .Fl U -is used, the pane is swapped with the pane above (before it numerically); +is used and no source pane is specified with +.Fl s , +.Ar dst-pane is swapped with the previous pane (before it numerically); .Fl D -swaps with the pane below (the next numerically); or -.Ar dst-index -may be give to swap with a specific pane. +swaps with the next pane (after it numerically). .It Xo Ic swap-window .Op Fl d .Op Fl s Ar src-window @@ -1733,8 +1739,7 @@ if is specified and the window is linked to only one session, it is unlinked and destroyed. .It Xo Ic up-pane -.Op Fl p Ar pane-index -.Op Fl t Ar target-window +.Op Fl t Ar target-pane .Xc .D1 (alias: Ic upp ) Move up a pane. diff --git a/tmux.h b/tmux.h index f16652a7..900aa200 100644 --- a/tmux.h +++ b/tmux.h @@ -1023,13 +1023,6 @@ struct cmd_option_data { char *value; }; -struct cmd_pane_data { - uint64_t chflags; - char *target; - char *arg; - int pane; -}; - /* Key binding. */ struct key_binding { int key; @@ -1222,6 +1215,8 @@ struct winlink *cmd_find_window( struct cmd_ctx *, const char *, struct session **); int cmd_find_index( struct cmd_ctx *, const char *, struct session **); +struct winlink *cmd_find_pane(struct cmd_ctx *, + const char *, struct session **, struct window_pane **); 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; @@ -1307,6 +1302,7 @@ int cmd_string_parse(const char *, struct cmd_list **, char **); /* cmd-generic.c */ size_t cmd_prarg(char *, size_t, const char *, char *); +#define CMD_TARGET_PANE_USAGE "[-t target-pane]" #define CMD_TARGET_WINDOW_USAGE "[-t target-window]" #define CMD_TARGET_SESSION_USAGE "[-t target-session]" #define CMD_TARGET_CLIENT_USAGE "[-t target-client]" @@ -1314,6 +1310,7 @@ void cmd_target_init(struct cmd *, int); int cmd_target_parse(struct cmd *, int, char **, char **); void cmd_target_free(struct cmd *); size_t cmd_target_print(struct cmd *, char *, size_t); +#define CMD_SRCDST_PANE_USAGE "[-s src-pane] [-t dst-pane]" #define CMD_SRCDST_WINDOW_USAGE "[-s src-window] [-t dst-window]" #define CMD_SRCDST_SESSION_USAGE "[-s src-session] [-t dst-session]" #define CMD_SRCDST_CLIENT_USAGE "[-s src-client] [-t dst-client]" @@ -1321,6 +1318,7 @@ void cmd_srcdst_init(struct cmd *, int); int cmd_srcdst_parse(struct cmd *, int, char **, char **); void cmd_srcdst_free(struct cmd *); size_t cmd_srcdst_print(struct cmd *, char *, size_t); +#define CMD_BUFFER_PANE_USAGE "[-b buffer-index] [-t target-pane]" #define CMD_BUFFER_WINDOW_USAGE "[-b buffer-index] [-t target-window]" #define CMD_BUFFER_SESSION_USAGE "[-b buffer-index] [-t target-session]" #define CMD_BUFFER_CLIENT_USAGE "[-b buffer-index] [-t target-client]" @@ -1328,6 +1326,7 @@ void cmd_buffer_init(struct cmd *, int); int cmd_buffer_parse(struct cmd *, int, char **, char **); void cmd_buffer_free(struct cmd *); size_t cmd_buffer_print(struct cmd *, char *, size_t); +#define CMD_OPTION_PANE_USAGE "[-gu] [-t target-pane] option [value]" #define CMD_OPTION_WINDOW_USAGE "[-gu] [-t target-window] option [value]" #define CMD_OPTION_SESSION_USAGE "[-gu] [-t target-session] option [value]" #define CMD_OPTION_CLIENT_USAGE "[-gu] [-t target-client] option [value]" @@ -1335,13 +1334,6 @@ void cmd_option_init(struct cmd *, int); int cmd_option_parse(struct cmd *, int, char **, char **); void cmd_option_free(struct cmd *); size_t cmd_option_print(struct cmd *, char *, size_t); -#define CMD_PANE_WINDOW_USAGE "[-t target-window] [-p pane-index]" -#define CMD_PANE_SESSION_USAGE "[-t target-session] [-p pane-index]" -#define CMD_PANE_CLIENT_USAGE "[-t target-client] [-p pane-index]" -void cmd_pane_init(struct cmd *, int); -int cmd_pane_parse(struct cmd *, int, char **, char **); -void cmd_pane_free(struct cmd *); -size_t cmd_pane_print(struct cmd *, char *, size_t); /* client.c */ int client_init(char *, struct client_ctx *, int, int); From 479d614884f66e9fa11f1292a2ef36991da46c1d Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 30 Jul 2009 16:16:19 +0000 Subject: [PATCH 0201/1180] Tell the server when the client gets SIGTERM so it can clean up the terminal properly, rather than just exiting. --- client.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/client.c b/client.c index f29c2569..e8785359 100644 --- a/client.c +++ b/client.c @@ -143,7 +143,9 @@ client_main(struct client_ctx *cctx) logfile("client"); - while (!sigterm) { + for (;;) { + if (sigterm) + client_write_server(cctx, MSG_EXITING, NULL, 0); if (sigchld) { waitpid(WAIT_ANY, NULL, WNOHANG); sigchld = 0; From 5f13bb0c3ade513ec3f88af8b6c0f575fa00cc4b Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 30 Jul 2009 16:32:12 +0000 Subject: [PATCH 0202/1180] There aren't many client message types or code to handle them so get rid of the lookup table and use a switch, merge the tiny handler functions into it, and move the whole lot to client.c. Also change client_msg_dispatch to consume as many messages as possible and move the call to it to the right place so it checks for signals afterwards. Prompted by suggestions from eric@. --- Makefile | 2 +- client-fn.c | 21 +++++++ client-msg.c | 154 --------------------------------------------------- client.c | 81 +++++++++++++++++++++------ tmux.h | 3 +- 5 files changed, 88 insertions(+), 173 deletions(-) delete mode 100644 client-msg.c diff --git a/Makefile b/Makefile index b565c44b..ccd472cf 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ PROG= tmux SRCS= attributes.c buffer-poll.c buffer.c cfg.c client-fn.c \ - client-msg.c client.c clock.c cmd-attach-session.c cmd-bind-key.c \ + client.c clock.c cmd-attach-session.c cmd-bind-key.c \ cmd-break-pane.c cmd-choose-session.c cmd-choose-window.c \ cmd-clear-history.c cmd-clock-mode.c cmd-command-prompt.c \ cmd-confirm-before.c cmd-copy-buffer.c cmd-copy-mode.c \ diff --git a/client-fn.c b/client-fn.c index 8e5e3722..129c6871 100644 --- a/client-fn.c +++ b/client-fn.c @@ -20,6 +20,7 @@ #include #include +#include #include "tmux.h" @@ -74,3 +75,23 @@ client_write_server( if (buf != NULL && len > 0) buffer_write(cctx->srv_out, buf, len); } + +void +client_suspend(void) +{ + struct sigaction act; + + memset(&act, 0, sizeof act); + sigemptyset(&act.sa_mask); + act.sa_flags = SA_RESTART; + + act.sa_handler = SIG_DFL; + if (sigaction(SIGTSTP, &act, NULL) != 0) + fatal("sigaction failed"); + + act.sa_handler = sighandler; + if (sigaction(SIGCONT, &act, NULL) != 0) + fatal("sigaction failed"); + + kill(getpid(), SIGTSTP); +} diff --git a/client-msg.c b/client-msg.c deleted file mode 100644 index f282478b..00000000 --- a/client-msg.c +++ /dev/null @@ -1,154 +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 -#include -#include -#include - -#include "tmux.h" - -int client_msg_fn_detach(struct hdr *, struct client_ctx *); -int client_msg_fn_error(struct hdr *, struct client_ctx *); -int client_msg_fn_shutdown(struct hdr *, struct client_ctx *); -int client_msg_fn_exit(struct hdr *, struct client_ctx *); -int client_msg_fn_exited(struct hdr *, struct client_ctx *); -int client_msg_fn_suspend(struct hdr *, struct client_ctx *); - -struct client_msg { - enum msgtype type; - int (*fn)(struct hdr *, struct client_ctx *); -}; -struct client_msg client_msg_table[] = { - { MSG_DETACH, client_msg_fn_detach }, - { MSG_ERROR, client_msg_fn_error }, - { MSG_EXIT, client_msg_fn_exit }, - { MSG_EXITED, client_msg_fn_exited }, - { MSG_SHUTDOWN, client_msg_fn_shutdown }, - { MSG_SUSPEND, client_msg_fn_suspend }, -}; - -int -client_msg_dispatch(struct client_ctx *cctx) -{ - struct hdr hdr; - struct client_msg *msg; - u_int i; - - if (BUFFER_USED(cctx->srv_in) < sizeof hdr) - return (1); - memcpy(&hdr, BUFFER_OUT(cctx->srv_in), sizeof hdr); - if (BUFFER_USED(cctx->srv_in) < (sizeof hdr) + hdr.size) - return (1); - buffer_remove(cctx->srv_in, sizeof hdr); - - for (i = 0; i < nitems(client_msg_table); i++) { - msg = client_msg_table + i; - if (msg->type == hdr.type) - return (msg->fn(&hdr, cctx)); - } - fatalx("unexpected message"); -} - -int -client_msg_fn_error(struct hdr *hdr, struct client_ctx *cctx) -{ - struct msg_print_data data; - - if (hdr->size < sizeof data) - fatalx("bad MSG_PRINT size"); - buffer_read(cctx->srv_in, &data, sizeof data); - - data.msg[(sizeof data.msg) - 1] = '\0'; - cctx->errstr = xstrdup(data.msg); - - return (-1); -} - -int -client_msg_fn_detach(struct hdr *hdr, struct client_ctx *cctx) -{ - if (hdr->size != 0) - fatalx("bad MSG_DETACH size"); - - client_write_server(cctx, MSG_EXITING, NULL, 0); - cctx->exittype = CCTX_DETACH; - - return (0); -} - -int -client_msg_fn_shutdown( - struct hdr *hdr, struct client_ctx *cctx) -{ - if (hdr->size != 0) - fatalx("bad MSG_SHUTDOWN size"); - - client_write_server(cctx, MSG_EXITING, NULL, 0); - cctx->exittype = CCTX_SHUTDOWN; - - return (0); -} - -int -client_msg_fn_exit(struct hdr *hdr, struct client_ctx *cctx) -{ - if (hdr->size != 0) - fatalx("bad MSG_EXIT size"); - - client_write_server(cctx, MSG_EXITING, NULL, 0); - cctx->exittype = CCTX_EXIT; - - return (0); -} - -int -client_msg_fn_exited(struct hdr *hdr, unused struct client_ctx *cctx) -{ - if (hdr->size != 0) - fatalx("bad MSG_EXITED size"); - - return (-1); -} - -int -client_msg_fn_suspend(struct hdr *hdr, unused struct client_ctx *cctx) -{ - struct sigaction act; - - if (hdr->size != 0) - fatalx("bad MSG_SUSPEND size"); - - memset(&act, 0, sizeof act); - sigemptyset(&act.sa_mask); - act.sa_flags = SA_RESTART; - - act.sa_handler = SIG_DFL; - if (sigaction(SIGTSTP, &act, NULL) != 0) - fatal("sigaction failed"); - - act.sa_handler = sighandler; - if (sigaction(SIGCONT, &act, NULL) != 0) - fatal("sigaction failed"); - - kill(getpid(), SIGTSTP); - - return (0); -} diff --git a/client.c b/client.c index e8785359..cb2207dd 100644 --- a/client.c +++ b/client.c @@ -137,7 +137,6 @@ int client_main(struct client_ctx *cctx) { struct pollfd pfd; - int xtimeout; /* Yay for ncurses namespace! */ siginit(); @@ -158,25 +157,12 @@ client_main(struct client_ctx *cctx) sigcont = 0; } - switch (client_msg_dispatch(cctx)) { - case -1: - goto out; - case 0: - /* May be more in buffer, don't let poll block. */ - xtimeout = 0; - break; - default: - /* Out of data, poll may block. */ - xtimeout = INFTIM; - break; - } - pfd.fd = cctx->srv_fd; pfd.events = POLLIN; if (BUFFER_USED(cctx->srv_out) > 0) pfd.events |= POLLOUT; - if (poll(&pfd, 1, xtimeout) == -1) { + if (poll(&pfd, 1, INFTIM) == -1) { if (errno == EAGAIN || errno == EINTR) continue; fatal("poll failed"); @@ -186,9 +172,11 @@ client_main(struct client_ctx *cctx) cctx->exittype = CCTX_DIED; break; } + + if (client_msg_dispatch(cctx) != 0) + break; } -out: if (sigterm) { printf("[terminated]\n"); return (1); @@ -227,3 +215,64 @@ client_handle_winch(struct client_ctx *cctx) sigwinch = 0; } + +int +client_msg_dispatch(struct client_ctx *cctx) +{ + struct hdr hdr; + struct msg_print_data printdata; + + for (;;) { + if (BUFFER_USED(cctx->srv_in) < sizeof hdr) + return (0); + memcpy(&hdr, BUFFER_OUT(cctx->srv_in), sizeof hdr); + if (BUFFER_USED(cctx->srv_in) < (sizeof hdr) + hdr.size) + return (0); + buffer_remove(cctx->srv_in, sizeof hdr); + + switch (hdr.type) { + case MSG_DETACH: + if (hdr.size != 0) + fatalx("bad MSG_DETACH size"); + + client_write_server(cctx, MSG_EXITING, NULL, 0); + cctx->exittype = CCTX_DETACH; + break; + case MSG_ERROR: + if (hdr.size != sizeof printdata) + fatalx("bad MSG_PRINT size"); + buffer_read(cctx->srv_in, &printdata, sizeof printdata); + printdata.msg[(sizeof printdata.msg) - 1] = '\0'; + + cctx->errstr = xstrdup(printdata.msg); + return (-1); + case MSG_EXIT: + if (hdr.size != 0) + fatalx("bad MSG_EXIT size"); + + client_write_server(cctx, MSG_EXITING, NULL, 0); + cctx->exittype = CCTX_EXIT; + break; + case MSG_EXITED: + if (hdr.size != 0) + fatalx("bad MSG_EXITED size"); + + return (-1); + case MSG_SHUTDOWN: + if (hdr.size != 0) + fatalx("bad MSG_SHUTDOWN size"); + + client_write_server(cctx, MSG_EXITING, NULL, 0); + cctx->exittype = CCTX_SHUTDOWN; + break; + case MSG_SUSPEND: + if (hdr.size != 0) + fatalx("bad MSG_SUSPEND size"); + + client_suspend(); + break; + default: + fatalx("unexpected message"); + } + } +} diff --git a/tmux.h b/tmux.h index 900aa200..62a2dac0 100644 --- a/tmux.h +++ b/tmux.h @@ -1338,13 +1338,12 @@ size_t cmd_option_print(struct cmd *, char *, size_t); /* client.c */ int client_init(char *, struct client_ctx *, int, int); int client_main(struct client_ctx *); - -/* client-msg.c */ int client_msg_dispatch(struct client_ctx *); /* client-fn.c */ void client_write_server(struct client_ctx *, enum msgtype, void *, size_t); void client_fill_session(struct msg_command_data *); +void client_suspend(void); /* key-bindings.c */ extern struct key_bindings key_bindings; From 9f1dd4d0af61ccfabe5738f2c0e220767bdd769f Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 30 Jul 2009 16:40:12 +0000 Subject: [PATCH 0203/1180] Similar changes for server_msg_dispatch: use a switch instead of a lookup table and merge smaller functions inline. --- server-msg.c | 239 +++++++++++++++++++++------------------------------ 1 file changed, 98 insertions(+), 141 deletions(-) diff --git a/server-msg.c b/server-msg.c index 14b2d4e4..2ee357ed 100644 --- a/server-msg.c +++ b/server-msg.c @@ -26,39 +26,22 @@ #include "tmux.h" -void server_msg_fn_command(struct hdr *, struct client *); -void server_msg_fn_identify(struct hdr *, struct client *); -void server_msg_fn_resize(struct hdr *, struct client *); -void server_msg_fn_exiting(struct hdr *, struct client *); -void server_msg_fn_unlock(struct hdr *, struct client *); -void server_msg_fn_wakeup(struct hdr *, struct client *); +void server_msg_command(struct client *, struct msg_command_data *); +void server_msg_identify(struct client *, struct msg_identify_data *); +void server_msg_resize(struct client *, struct msg_resize_data *); -void printflike2 server_msg_fn_command_error( - struct cmd_ctx *, const char *, ...); -void printflike2 server_msg_fn_command_print( - struct cmd_ctx *, const char *, ...); -void printflike2 server_msg_fn_command_info( - struct cmd_ctx *, const char *, ...); - -struct server_msg { - enum msgtype type; - void (*fn)(struct hdr *, struct client *); -}; -const struct server_msg server_msg_table[] = { - { MSG_IDENTIFY, server_msg_fn_identify }, - { MSG_COMMAND, server_msg_fn_command }, - { MSG_RESIZE, server_msg_fn_resize }, - { MSG_EXITING, server_msg_fn_exiting }, - { MSG_UNLOCK, server_msg_fn_unlock }, - { MSG_WAKEUP, server_msg_fn_wakeup }, -}; +void printflike2 server_msg_command_error(struct cmd_ctx *, const char *, ...); +void printflike2 server_msg_command_print(struct cmd_ctx *, const char *, ...); +void printflike2 server_msg_command_info(struct cmd_ctx *, const char *, ...); int server_msg_dispatch(struct client *c) { struct hdr hdr; - const struct server_msg *msg; - u_int i; + struct msg_command_data commanddata; + struct msg_identify_data identifydata; + struct msg_resize_data resizedata; + struct msg_unlock_data unlockdata; for (;;) { if (BUFFER_USED(c->in) < sizeof hdr) @@ -68,20 +51,63 @@ server_msg_dispatch(struct client *c) return (0); buffer_remove(c->in, sizeof hdr); - for (i = 0; i < nitems(server_msg_table); i++) { - msg = server_msg_table + i; - if (msg->type == hdr.type) { - msg->fn(&hdr, c); - break; - } - } - if (i == nitems(server_msg_table)) + switch (hdr.type) { + case MSG_COMMAND: + if (hdr.size != sizeof commanddata) + fatalx("bad MSG_COMMAND size"); + buffer_read(c->in, &commanddata, sizeof commanddata); + + server_msg_command(c, &commanddata); + break; + case MSG_IDENTIFY: + if (hdr.size != sizeof identifydata) + fatalx("bad MSG_IDENTIFY size"); + buffer_read(c->in, &identifydata, sizeof identifydata); + + server_msg_identify(c, &identifydata); + break; + case MSG_RESIZE: + if (hdr.size != sizeof resizedata) + fatalx("bad MSG_RESIZE size"); + buffer_read(c->in, &resizedata, sizeof resizedata); + + server_msg_resize(c, &resizedata); + break; + case MSG_EXITING: + if (hdr.size != 0) + fatalx("bad MSG_EXITING size"); + + c->session = NULL; + tty_close(&c->tty, c->flags & CLIENT_SUSPENDED); + server_write_client(c, MSG_EXITED, NULL, 0); + break; + case MSG_UNLOCK: + if (hdr.size != sizeof unlockdata) + fatalx("bad MSG_UNLOCK size"); + buffer_read(c->in, &unlockdata, sizeof unlockdata); + + unlockdata.pass[(sizeof unlockdata.pass) - 1] = '\0'; + if (server_unlock(unlockdata.pass) != 0) + server_write_error(c, "bad password"); + memset(&unlockdata, 0, sizeof unlockdata); + server_write_client(c, MSG_EXIT, NULL, 0); + break; + case MSG_WAKEUP: + if (hdr.size != 0) + fatalx("bad MSG_WAKEUP size"); + + c->flags &= ~CLIENT_SUSPENDED; + tty_start_tty(&c->tty); + server_redraw_client(c); + break; + default: fatalx("unexpected message"); + } } } void printflike2 -server_msg_fn_command_error(struct cmd_ctx *ctx, const char *fmt, ...) +server_msg_command_error(struct cmd_ctx *ctx, const char *fmt, ...) { struct msg_print_data data; va_list ap; @@ -94,7 +120,7 @@ server_msg_fn_command_error(struct cmd_ctx *ctx, const char *fmt, ...) } void printflike2 -server_msg_fn_command_print(struct cmd_ctx *ctx, const char *fmt, ...) +server_msg_command_print(struct cmd_ctx *ctx, const char *fmt, ...) { struct msg_print_data data; va_list ap; @@ -107,7 +133,7 @@ server_msg_fn_command_print(struct cmd_ctx *ctx, const char *fmt, ...) } void printflike2 -server_msg_fn_command_info(struct cmd_ctx *ctx, const char *fmt, ...) +server_msg_command_info(struct cmd_ctx *ctx, const char *fmt, ...) { struct msg_print_data data; va_list ap; @@ -123,35 +149,30 @@ server_msg_fn_command_info(struct cmd_ctx *ctx, const char *fmt, ...) } void -server_msg_fn_command(struct hdr *hdr, struct client *c) +server_msg_command(struct client *c, struct msg_command_data *data) { - struct msg_command_data data; - struct cmd_ctx ctx; - struct cmd_list *cmdlist = NULL; - struct cmd *cmd; - int argc; - char **argv, *cause; - - if (hdr->size < sizeof data) - fatalx("bad MSG_COMMAND size"); - buffer_read(c->in, &data, sizeof data); + struct cmd_ctx ctx; + struct cmd_list *cmdlist = NULL; + struct cmd *cmd; + int argc; + char **argv, *cause; server_activity = time(NULL); - ctx.error = server_msg_fn_command_error; - ctx.print = server_msg_fn_command_print; - ctx.info = server_msg_fn_command_info; + ctx.error = server_msg_command_error; + ctx.print = server_msg_command_print; + ctx.info = server_msg_command_info; - ctx.msgdata = &data; + ctx.msgdata = data; ctx.curclient = NULL; ctx.cursession = NULL; ctx.cmdclient = c; - argc = data.argc; - data.argv[(sizeof data.argv) - 1] = '\0'; - if (cmd_unpack_argv(data.argv, sizeof data.argv, argc, &argv) != 0) { - server_msg_fn_command_error(&ctx, "command too long"); + argc = data->argc; + data->argv[(sizeof data->argv) - 1] = '\0'; + if (cmd_unpack_argv(data->argv, sizeof data->argv, argc, &argv) != 0) { + server_msg_command_error(&ctx, "command too long"); goto error; } @@ -162,16 +183,16 @@ server_msg_fn_command(struct hdr *hdr, struct client *c) } if ((cmdlist = cmd_list_parse(argc, argv, &cause)) == NULL) { - server_msg_fn_command_error(&ctx, "%s", cause); + server_msg_command_error(&ctx, "%s", cause); cmd_free_argv(argc, argv); goto error; } cmd_free_argv(argc, argv); - if (data.pid != -1) { + if (data->pid != -1) { TAILQ_FOREACH(cmd, cmdlist, qentry) { if (cmd->entry->flags & CMD_CANTNEST) { - server_msg_fn_command_error(&ctx, + server_msg_command_error(&ctx, "sessions should be nested with care. " "unset $TMUX to force"); goto error; @@ -191,60 +212,43 @@ error: } void -server_msg_fn_identify(struct hdr *hdr, struct client *c) +server_msg_identify(struct client *c, struct msg_identify_data *data) { - struct msg_identify_data data; - - if (hdr->size < sizeof data) - fatalx("bad MSG_IDENTIFY size"); - buffer_read(c->in, &data, sizeof data); - - log_debug("identify msg from client: %u,%u (%d)", - data.sx, data.sy, data.version); - - if (data.version != PROTOCOL_VERSION) { + if (data->version != PROTOCOL_VERSION) { server_write_error(c, "protocol version mismatch"); return; } - c->tty.sx = data.sx; - c->tty.sy = data.sy; + c->tty.sx = data->sx; + c->tty.sy = data->sy; c->cwd = NULL; - data.cwd[(sizeof data.cwd) - 1] = '\0'; - if (*data.cwd != '\0') - c->cwd = xstrdup(data.cwd); + data->cwd[(sizeof data->cwd) - 1] = '\0'; + if (*data->cwd != '\0') + c->cwd = xstrdup(data->cwd); - data.tty[(sizeof data.tty) - 1] = '\0'; - data.term[(sizeof data.term) - 1] = '\0'; - tty_init(&c->tty, data.tty, data.term); - if (data.flags & IDENTIFY_UTF8) + data->tty[(sizeof data->tty) - 1] = '\0'; + data->term[(sizeof data->term) - 1] = '\0'; + tty_init(&c->tty, data->tty, data->term); + if (data->flags & IDENTIFY_UTF8) c->tty.flags |= TTY_UTF8; - if (data.flags & IDENTIFY_256COLOURS) + if (data->flags & IDENTIFY_256COLOURS) c->tty.term_flags |= TERM_256COLOURS; - else if (data.flags & IDENTIFY_88COLOURS) + else if (data->flags & IDENTIFY_88COLOURS) c->tty.term_flags |= TERM_88COLOURS; - if (data.flags & IDENTIFY_HASDEFAULTS) + if (data->flags & IDENTIFY_HASDEFAULTS) c->tty.term_flags |= TERM_HASDEFAULTS; c->flags |= CLIENT_TERMINAL; } void -server_msg_fn_resize(struct hdr *hdr, struct client *c) +server_msg_resize(struct client *c, struct msg_resize_data *data) { - struct msg_resize_data data; - - if (hdr->size != sizeof data) - fatalx("bad MSG_RESIZE size"); - buffer_read(c->in, &data, sizeof data); - - log_debug("resize msg from client: %u,%u", data.sx, data.sy); - - c->tty.sx = data.sx; + c->tty.sx = data->sx; if (c->tty.sx == 0) c->tty.sx = 80; - c->tty.sy = data.sy; + c->tty.sy = data->sy; if (c->tty.sy == 0) c->tty.sy = 25; @@ -258,50 +262,3 @@ server_msg_fn_resize(struct hdr *hdr, struct client *c) /* Always redraw this client. */ server_redraw_client(c); } - -void -server_msg_fn_exiting(struct hdr *hdr, struct client *c) -{ - if (hdr->size != 0) - fatalx("bad MSG_EXITING size"); - - log_debug("exiting msg from client"); - - c->session = NULL; - - tty_close(&c->tty, c->flags & CLIENT_SUSPENDED); - - server_write_client(c, MSG_EXITED, NULL, 0); -} - -void -server_msg_fn_unlock(struct hdr *hdr, struct client *c) -{ - struct msg_unlock_data data; - - if (hdr->size != sizeof data) - fatalx("bad MSG_UNLOCK size"); - buffer_read(c->in, &data, sizeof data); - - log_debug("unlock msg from client"); - - data.pass[(sizeof data.pass) - 1] = '\0'; - if (server_unlock(data.pass) != 0) - server_write_error(c, "bad password"); - memset(&data, 0, sizeof data); - - server_write_client(c, MSG_EXIT, NULL, 0); -} - -void -server_msg_fn_wakeup(struct hdr *hdr, struct client *c) -{ - if (hdr->size != 0) - fatalx("bad MSG_WAKEUP size"); - - log_debug("wakeup msg from client"); - - c->flags &= ~CLIENT_SUSPENDED; - tty_start_tty(&c->tty); - server_redraw_client(c); -} From 6d86882ed414c6076e23eb79d9d837c74d3ee82b Mon Sep 17 00:00:00 2001 From: Jason McIntyre Date: Thu, 30 Jul 2009 16:59:24 +0000 Subject: [PATCH 0204/1180] tweak previous; --- tmux.1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tmux.1 b/tmux.1 index 7a2a3bf2..1f361d17 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1675,7 +1675,8 @@ If .Fl U is used and no source pane is specified with .Fl s , -.Ar dst-pane is swapped with the previous pane (before it numerically); +.Ar dst-pane +is swapped with the previous pane (before it numerically); .Fl D swaps with the next pane (after it numerically). .It Xo Ic swap-window From 8df30358317c2e1aeb324c1e5cef0b4a17440302 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 30 Jul 2009 17:29:12 +0000 Subject: [PATCH 0205/1180] Remove some dead code found by clang. --- cmd-clear-history.c | 3 +-- cmd-swap-pane.c | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/cmd-clear-history.c b/cmd-clear-history.c index 0a87b9b0..a9271346 100644 --- a/cmd-clear-history.c +++ b/cmd-clear-history.c @@ -41,11 +41,10 @@ int cmd_clear_history_exec(struct cmd *self, struct cmd_ctx *ctx) { struct cmd_target_data *data = self->data; - struct winlink *wl; struct window_pane *wp; struct grid *gd; - if ((wl = cmd_find_pane(ctx, data->target, NULL, &wp)) == NULL) + if (cmd_find_pane(ctx, data->target, NULL, &wp) == NULL) return (-1); gd = wp->base.grid; diff --git a/cmd-swap-pane.c b/cmd-swap-pane.c index 4516d2ca..a49e064a 100644 --- a/cmd-swap-pane.c +++ b/cmd-swap-pane.c @@ -72,7 +72,6 @@ cmd_swap_pane_exec(struct cmd *self, struct cmd_ctx *ctx) dst_w = dst_wl->window; if (data->src == NULL) { - src_wl = dst_wl; src_w = dst_w; if (data->chflags & CMD_CHFLAG('D')) { src_wp = TAILQ_NEXT(dst_wp, entry); From 61f3fc7e4dc5bdf543940f8cc7334f5f64d4b9fb Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 30 Jul 2009 17:46:12 +0000 Subject: [PATCH 0206/1180] Don't babysit people and let them try to load /dev/zero or (more useful) /dev/null if they want. --- cfg.c | 10 ---------- cmd-load-buffer.c | 4 ---- 2 files changed, 14 deletions(-) diff --git a/cfg.c b/cfg.c index fa5e1b05..6320641e 100644 --- a/cfg.c +++ b/cfg.c @@ -55,21 +55,11 @@ load_cfg(const char *path, char **cause) { FILE *f; u_int n; - struct stat sb; char *buf, *line, *ptr; size_t len; struct cmd_list *cmdlist; struct cmd_ctx ctx; - if (stat(path, &sb) != 0) { - xasprintf(cause, "%s: %s", path, strerror(errno)); - return (-1); - } - if (!S_ISREG(sb.st_mode)) { - xasprintf(cause, "%s: not a regular file", path); - return (-1); - } - if ((f = fopen(path, "rb")) == NULL) { xasprintf(cause, "%s: %s", path, strerror(errno)); return (1); diff --git a/cmd-load-buffer.c b/cmd-load-buffer.c index 063cafa1..4a7f9ffb 100644 --- a/cmd-load-buffer.c +++ b/cmd-load-buffer.c @@ -60,10 +60,6 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) ctx->error(ctx, "%s: %s", data->arg, strerror(errno)); return (-1); } - if (!S_ISREG(statbuf.st_mode)) { - ctx->error(ctx, "%s: not a regular file", data->arg); - return (-1); - } if ((f = fopen(data->arg, "rb")) == NULL) { ctx->error(ctx, "%s: %s", data->arg, strerror(errno)); From 97f105cde22c50ecf3cc1edd68df2664f3645bcc Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 30 Jul 2009 20:41:48 +0000 Subject: [PATCH 0207/1180] Plug some memory leaks. --- mode-key.c | 1 + screen-write.c | 1 + screen.c | 2 ++ status.c | 1 + 4 files changed, 5 insertions(+) diff --git a/mode-key.c b/mode-key.c index ccd5465c..26eb771e 100644 --- a/mode-key.c +++ b/mode-key.c @@ -337,6 +337,7 @@ mode_key_free_trees(void) while (!SPLAY_EMPTY(mtab->tree)) { mbind = SPLAY_ROOT(mtab->tree); SPLAY_REMOVE(mode_key_tree, mtab->tree, mbind); + xfree(mbind); } } } diff --git a/screen-write.c b/screen-write.c index 449c3a35..d9b523c4 100644 --- a/screen-write.c +++ b/screen-write.c @@ -91,6 +91,7 @@ screen_write_strlen(int utf8flag, const char *fmt, ...) } } + xfree(msg); return (size); } diff --git a/screen.c b/screen.c index 650278b2..b2bcffa3 100644 --- a/screen.c +++ b/screen.c @@ -63,6 +63,8 @@ screen_reinit(struct screen *s) void screen_free(struct screen *s) { + if (s->tabs != NULL) + xfree(s->tabs); xfree(s->title); grid_destroy(s->grid); } diff --git a/status.c b/status.c index 7fcf5e9b..e4836d34 100644 --- a/status.c +++ b/status.c @@ -801,6 +801,7 @@ status_prompt_key(struct client *c, int key) memcpy(first, s, strlen(s)); c->prompt_index = (first - c->prompt_buffer) + strlen(s); + xfree(s); c->flags |= CLIENT_STATUS; break; From 95caeaa5dc7f326a53559ea86792e488d88e2c66 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 30 Jul 2009 20:50:54 +0000 Subject: [PATCH 0208/1180] Don't leak when rollling buffers off when the paste buffer limit is reached. --- paste.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/paste.c b/paste.c index 981385e9..82fa0939 100644 --- a/paste.c +++ b/paste.c @@ -104,8 +104,12 @@ paste_add(struct paste_stack *ps, char *data, u_int limit) if (*data == '\0') return; - while (ARRAY_LENGTH(ps) >= limit) + while (ARRAY_LENGTH(ps) >= limit) { + pb = ARRAY_LAST(ps); + xfree(pb->data); + xfree(pb); ARRAY_TRUNC(ps, 1); + } pb = xmalloc(sizeof *pb); ARRAY_INSERT(ps, 0, pb); From 5db47ed53a15882e9264a059ec027bc4f5acf5b7 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 31 Jul 2009 10:12:49 +0000 Subject: [PATCH 0209/1180] Pass the ACS border characters through tty_get_acs so they appear correctly on terminals which don't use the standard set. --- screen-redraw.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/screen-redraw.c b/screen-redraw.c index f3c718a9..eee1c83c 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -161,7 +161,8 @@ screen_redraw_screen(struct client *c, int status_only) struct window_pane *wp; u_int i, j, type; int status; - const u_char *border; + const u_char *base, *ptr; + u_char ch, border[20]; /* Get status line, er, status. */ if (c->message_string != NULL || c->prompt_string != NULL) @@ -177,11 +178,15 @@ screen_redraw_screen(struct client *c, int status_only) /* Draw background and borders. */ tty_reset(tty); + strlcpy(border, " |-....--||+.", sizeof border); if (tty_term_has(tty->term, TTYC_ACSC)) { - border = " xqlkmjwvtun~"; + base = " xqlkmjwvtun~"; + for (ptr = base; *ptr != '\0'; ptr++) { + if ((ch = tty_get_acs(tty, *ptr)) != '\0') + border[ptr - base] = ch; + } tty_putcode(tty, TTYC_SMACS); - } else - border = " |-....--||+."; + } for (j = 0; j < tty->sy - status; j++) { if (status_only && j != tty->sy - 1) continue; From e4bb08e1f5ebf47620758795efcbdd61849b73e8 Mon Sep 17 00:00:00 2001 From: Matthieu Herrb Date: Sun, 2 Aug 2009 20:47:35 +0000 Subject: [PATCH 0210/1180] Fix checking of setupterm(3) error codes. While there include the name of the terminal type causing the error where relevant. ok nicm@. --- tty-term.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tty-term.c b/tty-term.c index 0f50a269..c8b47783 100644 --- a/tty-term.c +++ b/tty-term.c @@ -186,13 +186,13 @@ tty_term_find(char *name, int fd, char **cause) /* Set up curses terminal. */ if (setupterm(name, fd, &error) != OK) { switch (error) { - case 0: - xasprintf(cause, "can't use hardcopy terminal"); - break; case 1: - xasprintf(cause, "missing or unsuitable terminal"); + xasprintf(cause, "can't use hardcopy terminal: %s", name); break; - case 2: + case 0: + xasprintf(cause, "missing or unsuitable terminal: %s", name); + break; + case -1: xasprintf(cause, "can't find terminfo database"); break; default: From 1673735f0271c6f87e6ba0d85d8b4a1d0f2f3d35 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 3 Aug 2009 14:10:54 +0000 Subject: [PATCH 0211/1180] Add a terminal-overrides session option allowing individual terminfo(5) entries to be overridden. The 88col/256col checks are now moved into the default setting and out of the code. Also remove a couple of old workarounds for xterm and rxvt which are no longer necessary (tmux can emulate them if missing). --- cmd-attach-session.c | 6 ++- cmd-new-session.c | 6 ++- cmd-set-option.c | 3 +- cmd-string.c | 3 ++ tmux.1 | 38 +++++++++++++++++ tmux.c | 2 + tmux.h | 4 +- tty-term.c | 99 +++++++++++++++++++++++++++++++++++--------- tty.c | 5 ++- 9 files changed, 137 insertions(+), 29 deletions(-) diff --git a/cmd-attach-session.c b/cmd-attach-session.c index 3278ea7f..4604ee27 100644 --- a/cmd-attach-session.c +++ b/cmd-attach-session.c @@ -43,7 +43,7 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx) struct cmd_target_data *data = self->data; struct session *s; struct client *c; - char *cause; + char *overrides, *cause; u_int i; if (ARRAY_LENGTH(&sessions) == 0) { @@ -80,7 +80,9 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx) return (-1); } - if (tty_open(&ctx->cmdclient->tty, &cause) != 0) { + overrides = + options_get_string(&s->options, "terminal-overrides"); + if (tty_open(&ctx->cmdclient->tty, overrides, &cause) != 0) { ctx->error(ctx, "terminal open failed: %s", cause); xfree(cause); return (-1); diff --git a/cmd-new-session.c b/cmd-new-session.c index ea2e5b12..c1ba6e30 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -108,7 +108,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) { struct cmd_new_session_data *data = self->data; struct session *s; - char *cmd, *cwd, *cause; + char *overrides, *cmd, *cwd, *cause; int detached; u_int sx, sy; @@ -147,7 +147,9 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) return (-1); } - if (tty_open(&ctx->cmdclient->tty, &cause) != 0) { + overrides = + options_get_string(&global_s_options, "terminal-overrides"); + if (tty_open(&ctx->cmdclient->tty, overrides, &cause) != 0) { ctx->error(ctx, "open terminal failed: %s", cause); xfree(cause); return (-1); diff --git a/cmd-set-option.c b/cmd-set-option.c index 2e3ca734..5c2d5870 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -77,7 +77,8 @@ const struct set_option_entry set_option_table[] = { { "status-left-length", SET_OPTION_NUMBER, 0, SHRT_MAX, NULL }, { "status-right", SET_OPTION_STRING, 0, 0, NULL }, { "status-right-length", SET_OPTION_NUMBER, 0, SHRT_MAX, NULL }, - { "status-utf8", SET_OPTION_FLAG, 0, 0, NULL }, + { "status-utf8", SET_OPTION_FLAG, 0, 0, NULL }, + { "terminal-overrides", SET_OPTION_STRING, 0, 0, NULL }, { "visual-activity", SET_OPTION_FLAG, 0, 0, NULL }, { "visual-bell", SET_OPTION_FLAG, 0, 0, NULL }, { "visual-content", SET_OPTION_FLAG, 0, 0, NULL }, diff --git a/cmd-string.c b/cmd-string.c index 9ba399b2..c12ac1d7 100644 --- a/cmd-string.c +++ b/cmd-string.c @@ -215,6 +215,9 @@ cmd_string_string(const char *s, size_t *p, char endch, int esc) switch (ch = cmd_string_getc(s, p)) { case EOF: goto error; + case 'e': + ch = '\033'; + break; case 'r': ch = '\r'; break; diff --git a/tmux.1 b/tmux.1 index 1f361d17..e60424d3 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1418,6 +1418,44 @@ and .Ic status-right strings as UTF-8; notably, this is important for wide characters. This option defaults to off. +.It Xo Ic terminal-overrides +.Ar string +.Xc +Contains a list of entries which override terminal descriptions read using +.Xr terminfo 5 . +.Ar string +is a comma-separated list of items each a colon-separated string made up of a +terminal type pattern (matched using +.Xr fnmatch 3 ) +and a set of +.Em name=value +entries. +.Pp +For example, to set the +.Ql clear +.Xr terminfo 5 +entry to +.Ql \ee[H\ee[2J +for all terminal types and the +.Ql dch1 +entry to +.Ql \ee[P +for the +.Ql rxvt +terminal type, the option could be set to the string: +.Bd -literal -offset indent +"*:clear=\ee[H\ee[2J,rxvt:dch1=\ee[P" +.Ed +.Pp +The terminal entry value is passed through +.Xr strunvis 3 +before interpretation. +The default value forcibly corrects the +.Ql colors +entry for terminals which support 88 or 256 colours: +.Bd -literal -offset indent +"*88col*:colors=88,*256col*:colors=256" +.Ed .It Xo Ic visual-activity .Op Ic on | Ic off .Xc diff --git a/tmux.c b/tmux.c index dd7b83f5..ff1bd4c4 100644 --- a/tmux.c +++ b/tmux.c @@ -367,6 +367,8 @@ main(int argc, char **argv) options_set_number(&global_s_options, "status-utf8", 1); else options_set_number(&global_s_options, "status-utf8", 0); + options_set_string(&global_s_options, + "terminal-overrides", "*88col*:colors=88,*256col*:colors=256"); options_set_number(&global_s_options, "visual-activity", 0); options_set_number(&global_s_options, "visual-bell", 0); options_set_number(&global_s_options, "visual-content", 0); diff --git a/tmux.h b/tmux.h index 62a2dac0..37686e13 100644 --- a/tmux.h +++ b/tmux.h @@ -1130,7 +1130,7 @@ void tty_detect_utf8(struct tty *); void tty_set_title(struct tty *, const char *); void tty_update_mode(struct tty *, int); void tty_draw_line(struct tty *, struct screen *, u_int, u_int, u_int); -int tty_open(struct tty *, char **); +int tty_open(struct tty *, const char *, char **); void tty_close(struct tty *, int); void tty_free(struct tty *, int); void tty_write(void (*)(struct tty *, struct tty_ctx *), struct tty_ctx *); @@ -1153,7 +1153,7 @@ void tty_cmd_reverseindex(struct tty *, struct tty_ctx *); /* tty-term.c */ extern struct tty_terms tty_terms; extern struct tty_term_code_entry tty_term_codes[NTTYCODE]; -struct tty_term *tty_term_find(char *, int, char **); +struct tty_term *tty_term_find(char *, int, const char *, char **); void tty_term_free(struct tty_term *); int tty_term_has(struct tty_term *, enum tty_code_code); const char *tty_term_string(struct tty_term *, enum tty_code_code); diff --git a/tty-term.c b/tty-term.c index c8b47783..2813be61 100644 --- a/tty-term.c +++ b/tty-term.c @@ -19,12 +19,15 @@ #include #include +#include +#include #include #include +#include #include "tmux.h" -void tty_term_quirks(struct tty_term *); +void tty_term_override(struct tty_term *, const char *); char *tty_term_strip(const char *); struct tty_terms tty_terms = SLIST_HEAD_INITIALIZER(tty_terms); @@ -140,27 +143,87 @@ tty_term_strip(const char *s) } void -tty_term_quirks(struct tty_term *term) +tty_term_override(struct tty_term *term, const char *overrides) { - if (strncmp(term->name, "rxvt", 4) == 0) { - /* rxvt supports dch1 but some termcap files do not have it. */ - if (!tty_term_has(term, TTYC_DCH1)) { - term->codes[TTYC_DCH1].type = TTYCODE_STRING; - term->codes[TTYC_DCH1].value.string = xstrdup("\033[P"); + struct tty_term_code_entry *ent; + struct tty_code *code; + char *termnext, *termstr, *entnext, *entstr; + char *s, *ptr, *val; + const char *errstr; + u_int i; + int n, removeflag; + + s = xstrdup(overrides); + + termnext = s; + while ((termstr = strsep(&termnext, ",")) != NULL) { + entnext = termstr; + + entstr = strsep(&entnext, ":"); + if (entstr == NULL || entnext == NULL) + continue; + if (fnmatch(entstr, term->name, 0) != 0) + continue; + while ((entstr = strsep(&entnext, ":")) != NULL) { + if (*entstr == '\0') + continue; + + val = NULL; + removeflag = 0; + if ((ptr = strchr(entstr, '=')) != NULL) { + *ptr++ = '\0'; + val = xstrdup(ptr); + if (strunvis(val, ptr) == NULL) { + xfree(val); + val = xstrdup(ptr); + } + } else if (entstr[strlen(entstr) - 1] == '@') { + entstr[strlen(entstr) - 1] = '\0'; + removeflag = 1; + } + + for (i = 0; i < NTTYCODE; i++) { + ent = &tty_term_codes[i]; + if (strcmp(entstr, ent->name) != 0) + continue; + code = &term->codes[ent->code]; + + if (removeflag) { + code->type = TTYCODE_NONE; + continue; + } + switch (ent->type) { + case TTYCODE_NONE: + break; + case TTYCODE_STRING: + xfree(code->value.string); + code->value.string = xstrdup(val); + code->type = ent->type; + break; + case TTYCODE_NUMBER: + n = strtonum(val, 0, INT_MAX, &errstr); + if (errstr != NULL) + break; + code->value.number = n; + code->type = ent->type; + break; + case TTYCODE_FLAG: + code->value.flag = 1; + code->type = ent->type; + break; + } + } + + if (val != NULL) + xfree(val); } } - if (strncmp(term->name, "xterm", 5) == 0) { - /* xterm supports ich1 but some termcaps omit it. */ - if (!tty_term_has(term, TTYC_ICH1)) { - term->codes[TTYC_ICH1].type = TTYCODE_STRING; - term->codes[TTYC_ICH1].value.string = xstrdup("\033[@"); - } - } + xfree(s); } struct tty_term * -tty_term_find(char *name, int fd, char **cause) +tty_term_find(char *name, int fd, const char *overrides, char **cause) { struct tty_term *term; struct tty_term_code_entry *ent; @@ -235,7 +298,7 @@ tty_term_find(char *name, int fd, char **cause) break; } } - tty_term_quirks(term); + tty_term_override(term, overrides); /* Delete curses data. */ del_curterm(cur_term); @@ -297,12 +360,8 @@ tty_term_find(char *name, int fd, char **cause) */ if (tty_term_number(term, TTYC_COLORS) == 256) term->flags |= TERM_256COLOURS; - if (strstr(name, "256col") != NULL) /* XXX HACK */ - term->flags |= TERM_256COLOURS; if (tty_term_number(term, TTYC_COLORS) == 88) term->flags |= TERM_88COLOURS; - if (strstr(name, "88col") != NULL) /* XXX HACK */ - term->flags |= TERM_88COLOURS; /* * Terminals without xenl (eat newline glitch) wrap at at $COLUMNS - 1 diff --git a/tty.c b/tty.c index 48b10f7d..d3a4ba1d 100644 --- a/tty.c +++ b/tty.c @@ -57,7 +57,7 @@ tty_init(struct tty *tty, char *path, char *term) } int -tty_open(struct tty *tty, char **cause) +tty_open(struct tty *tty, const char *overrides, char **cause) { int mode; @@ -79,7 +79,8 @@ tty_open(struct tty *tty, char **cause) else tty->log_fd = -1; - if ((tty->term = tty_term_find(tty->termname, tty->fd, cause)) == NULL) + tty->term = tty_term_find(tty->termname, tty->fd, overrides, cause); + if (tty->term == NULL) goto error; tty->in = buffer_create(BUFSIZ); From 9a391b33202fbab9a76812a763ac6252187bafdd Mon Sep 17 00:00:00 2001 From: Jason McIntyre Date: Mon, 3 Aug 2009 14:34:47 +0000 Subject: [PATCH 0212/1180] tweak previous; --- tmux.1 | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tmux.1 b/tmux.1 index e60424d3..e907b4ca 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1418,9 +1418,7 @@ and .Ic status-right strings as UTF-8; notably, this is important for wide characters. This option defaults to off. -.It Xo Ic terminal-overrides -.Ar string -.Xc +.It Ic terminal-overrides Ar string Contains a list of entries which override terminal descriptions read using .Xr terminfo 5 . .Ar string @@ -1440,7 +1438,7 @@ for all terminal types and the .Ql dch1 entry to .Ql \ee[P -for the +for the .Ql rxvt terminal type, the option could be set to the string: .Bd -literal -offset indent From ac54dee9bbd33e71910fed8d5f8ddb1cde9b9a35 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 3 Aug 2009 15:30:16 +0000 Subject: [PATCH 0213/1180] Don't try to free old string values (and crash) when they are overridden unless they were actually found in the source terminal description. Reported by jmc. --- tty-term.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tty-term.c b/tty-term.c index 2813be61..c96bdb12 100644 --- a/tty-term.c +++ b/tty-term.c @@ -196,7 +196,8 @@ tty_term_override(struct tty_term *term, const char *overrides) case TTYCODE_NONE: break; case TTYCODE_STRING: - xfree(code->value.string); + if (code->type == TTYCODE_STRING) + xfree(code->value.string); code->value.string = xstrdup(val); code->type = ent->type; break; From 189fb08e13984cc2a8b28379ee9defe4156e1878 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 3 Aug 2009 17:12:07 +0000 Subject: [PATCH 0214/1180] Split the comparison into a function to make this code smaller and more understandable. --- procname.c | 118 +++++++++++++++++++++++++++-------------------------- 1 file changed, 60 insertions(+), 58 deletions(-) diff --git a/procname.c b/procname.c index d7644898..61f3a46f 100644 --- a/procname.c +++ b/procname.c @@ -34,7 +34,55 @@ #define is_stopped(p) \ ((p)->p_stat == SSTOP || (p)->p_stat == SZOMB || (p)->p_stat == SDEAD) -char *get_proc_name(int, char *); +struct proc *cmp_procs(struct proc *, struct proc *); +char *get_proc_name(int, char *); + +struct proc * +cmp_procs(struct proc *p1, struct proc *p2) +{ + void *ptr1, *ptr2; + + if (is_runnable(p1) && !is_runnable(p2)) + return (p1); + if (!is_runnable(p1) && is_runnable(p2)) + return (p2); + + if (is_stopped(p1) && !is_stopped(p2)) + return (p1); + if (!is_stopped(p1) && is_stopped(p2)) + return (p2); + + if (p1->p_estcpu > p2->p_estcpu) + return (p1); + if (p1->p_estcpu < p2->p_estcpu) + return (p2); + + if (p1->p_slptime < p2->p_slptime) + return (p1); + if (p1->p_slptime > p2->p_slptime) + return (p2); + + if ((p1->p_flag & P_SINTR) && !(p2->p_flag & P_SINTR)) + return (p1); + if (!(p1->p_flag & P_SINTR) && (p2->p_flag & P_SINTR)) + return (p2); + + ptr1 = LIST_FIRST(&p1->p_children); + ptr2 = LIST_FIRST(&p2->p_children); + if (ptr1 == NULL && ptr2 != NULL) + return (p1); + if (ptr1 != NULL && ptr2 == NULL) + return (p2); + + if (strcmp(p1->p_comm, p2->p_comm) < 0) + return (p1); + if (strcmp(p1->p_comm, p2->p_comm) > 0) + return (p2); + + if (p1->p_pid > p2->p_pid) + return (p1); + return (p2); +} char * get_proc_name(int fd, char *tty) @@ -59,17 +107,14 @@ retry: return (NULL); len = (len * 5) / 4; - if ((newbuf = realloc(buf, len)) == NULL) { - free(buf); - return (NULL); - } + if ((newbuf = realloc(buf, len)) == NULL) + goto error; buf = newbuf; if (sysctl(mib, nitems(mib), buf, &len, NULL, 0) == -1) { if (errno == ENOMEM) goto retry; - free(buf); - return (NULL); + goto error; } bestp = NULL; @@ -77,57 +122,10 @@ retry: if (buf[i].kp_eproc.e_tdev != sb.st_rdev) continue; p = &buf[i].kp_proc; - if (bestp == NULL) { - bestp = p; - continue; - } - - if (is_runnable(p) && !is_runnable(bestp)) { - bestp = p; - continue; - } else if (!is_runnable(p) && is_runnable(bestp)) - continue; - - if (!is_stopped(p) && is_stopped(bestp)) { - bestp = p; - continue; - } else if (is_stopped(p) && !is_stopped(bestp)) - continue; - - if (p->p_estcpu > bestp->p_estcpu) { - bestp = p; - continue; - } else if (p->p_estcpu < bestp->p_estcpu) - continue; - - if (p->p_slptime < bestp->p_slptime) { - bestp = p; - continue; - } else if (p->p_slptime > bestp->p_slptime) - continue; - - if (p->p_flag & P_SINTR && !(bestp->p_flag & P_SINTR)) { - bestp = p; - continue; - } else if (!(p->p_flag & P_SINTR) && bestp->p_flag & P_SINTR) - continue; - - if (LIST_FIRST(&p->p_children) == NULL && - LIST_FIRST(&bestp->p_children) != NULL) { /* XXX ugh */ - bestp = p; - continue; - } else if (LIST_FIRST(&p->p_children) != NULL && - LIST_FIRST(&bestp->p_children) == NULL) - continue; - - if (strcmp(p->p_comm, bestp->p_comm) < 0) { - bestp = p; - continue; - } else if (strcmp(p->p_comm, bestp->p_comm) > 0) - continue; - - if (p->p_pid > bestp->p_pid) - bestp = p; + if (bestp == NULL) + bestp = &buf[i].kp_proc; + else + bestp = cmp_procs(&buf[i].kp_proc, bestp); } name = NULL; @@ -136,4 +134,8 @@ retry: free(buf); return (name); + +error: + free(buf); + return (NULL); } From 6b69b93b53681632c501d0e9ce19e78736c68cce Mon Sep 17 00:00:00 2001 From: Jason McIntyre Date: Tue, 4 Aug 2009 07:56:38 +0000 Subject: [PATCH 0215/1180] clean up some macro abuse in the commands section; --- tmux.1 | 181 +++++++++++++++++++++++---------------------------------- 1 file changed, 74 insertions(+), 107 deletions(-) diff --git a/tmux.1 b/tmux.1 index e907b4ca..97c4c6b6 100644 --- a/tmux.1 +++ b/tmux.1 @@ -710,28 +710,20 @@ off from its containing window to make it the only pane in a new window. If .Fl d is given, the new window does not become the current window. -.It Xo Ic choose-session -.Op Fl t Ar target-window -.Xc +.It Ic choose-session Op Fl t Ar target-window Put a window into session choice mode, where the session for the current client may be selected interactively from a list. This command works only from inside .Nm . -.It Xo Ic choose-window -.Op Fl t Ar target-window -.Xc +.It Ic choose-window Op Fl t Ar target-window Put a window into window choice mode, where the window for the session attached to the current client may be selected interactively from a list. This command works only from inside .Nm . -.It Xo Ic clear-history -.Op Fl t Ar target-pane -.Xc +.It Ic clear-history Op Fl t Ar target-pane .D1 (alias: Ic clearhist ) Remove and free the history for the specified pane. -.It Xo Ic clock-mode -.Op Fl t Ar target-window -.Xc +.It Ic clock-mode Op Fl t Ar target-window Display a large clock. .It Xo Ic command-prompt .Op Fl t Ar target-client @@ -779,9 +771,7 @@ option scrolls one page up. Delete the buffer at .Ar buffer-index , or the top buffer if not specified. -.It Xo Ic detach-client -.Op Fl t Ar target-client -.Xc +.It Ic detach-client Op Fl t Ar target-client .D1 (alias: Ic detach ) Detach the current client if bound to a key, or the specified client with .Fl t . @@ -794,9 +784,7 @@ Display a message (see the .Ic status-left option below) in the status line. -.It Xo Ic down-pane -.Op Fl t Ar target-pane -.Xc +.It Ic down-pane Op Fl t Ar target-pane .D1 (alias: Ic downp ) Move down a pane. .It Xo Ic find-window @@ -813,48 +801,34 @@ If only one window is matched, it'll be automatically selected, otherwise a choice list is shown. This command only works from inside .Nm . -.It Xo Ic has-session -.Op Fl t Ar target-session -.Xc +.It Ic has-session Op Fl t Ar target-session .D1 (alias: Ic has ) Report an error and exit with 1 if the specified session does not exist. If it does exist, exit with 0. -.It Xo Ic if-shell -.Ar shell-command -.Ar command -.Xc +.It Ic if-shell Ar shell-command command .D1 (alias: Ic if ) Execute .Ar command if .Ar shell-command returns success. -.It Xo Ic kill-pane -.Op Fl t Ar target-pane -.Xc +.It Ic kill-pane Op Fl t Ar target-pane .D1 (alias: Ic killp ) Destroy the given pane. If no panes remain in the containing window, it is also destroyed. -.It Xo Ic kill-server -.Xc +.It Ic kill-server Kill the .Nm server and clients and destroy all sessions. -.It Xo Ic kill-session -.Op Fl t Ar target-session -.Xc +.It Ic kill-session Op Fl t Ar target-session Destroy the given session, closing any windows linked to it and no other sessions, and detaching all clients attached to it. -.It Xo Ic kill-window -.Op Fl t Ar target-window -.Xc +.It Ic kill-window Op Fl t Ar target-window .D1 (alias: Ic killw ) Kill the current window or the window at .Ar target-window , removing it from any sessions to which it is linked. -.It Xo Ic last-window -.Op Fl t Ar target-session -.Xc +.It Ic last-window Op Fl t Ar target-session .D1 (alias: Ic last ) Select the last (previously selected) window. If no @@ -883,23 +857,17 @@ exists, it is killed, otherwise an error is generated. If .Fl d is given, the newly linked window is not selected. -.It Xo Ic list-buffers -.Op Fl t Ar target-session -.Xc +.It Ic list-buffers Op Fl t Ar target-session .D1 (alias: Ic lsb ) List the buffers in the given session. -.It Xo Ic list-clients -.Xc +.It Ic list-clients .D1 (alias: Ic lsc ) List all clients attached to the server. -.It Xo Ic list-commands -.Xc +.It Ic list-commands .D1 (alias: Ic lscm ) List the syntax of all commands supported by .Nm . -.It Xo Ic list-keys -.Op Fl t Ar key-table -.Xc +.It Ic list-keys Op Fl t Ar key-table .D1 (alias: Ic lsk ) List all key bindings. Without @@ -923,13 +891,10 @@ are listed; this may be one of: .Em vi-copy or .Em emacs-copy . -.It Xo Ic list-sessions -.Xc +.It Ic list-sessions .D1 (alias: Ic ls ) List all sessions managed by the server. -.It Xo Ic list-windows -.Op Fl t Ar target-session -.Xc +.It Ic list-windows Op Fl t Ar target-session .D1 (alias: Ic lsw ) List windows in the current session or in .Ar target-session . @@ -941,8 +906,7 @@ List windows in the current session or in .D1 (alias: Ic loadb ) Load the contents of the specified paste buffer from .Ar path . -.It Xo Ic lock-server -.Xc +.It Ic lock-server .D1 (alias: Ic lock ) Lock the server until a password is entered. .It Xo Ic move-window @@ -1006,9 +970,7 @@ New windows will automatically have .Dq TERM=screen added to their environment, but care must be taken not to reset this in shell start-up files. -.It Xo Ic next-layout -.Op Fl t Ar target-window -.Xc +.It Ic next-layout Op Fl t Ar target-window .D1 (alias: Ic nextl ) Move a window to the next layout and rearrange the panes to fit. .It Xo Ic next-window @@ -1044,9 +1006,7 @@ Move to the previous window in the session. With .Fl a , move to the previous window with a bell, activity or content alert. -.It Xo Ic refresh-client -.Op Fl t Ar target-client -.Xc +.It Ic refresh-client Op Fl t Ar target-client .D1 (alias: Ic refresh ) Refresh the current client if bound to a key, or a single client if one is given with @@ -1139,23 +1099,17 @@ Choose a specific layout for a window. If .Ar layout-name is not given, the last layout used (if any) is reapplied. -.It Xo Ic select-pane -.Op Fl t Ar target-pane -.Xc +.It Ic select-pane Op Fl t Ar target-pane .D1 (alias: Ic selectp ) Make pane .Ar target-pane the active pane in window .Ar target-window . -.It Xo Ic select-prompt -.Op Fl t Ar target-client -.Xc +.It Ic select-prompt Op Fl t Ar target-client Open a prompt inside .Ar target-client allowing a window index to be entered interactively. -.It Xo Ic select-window -.Op Fl t Ar target-window -.Xc +.It Ic select-window Op Fl t Ar target-window .D1 (alias: Ic selectw ) Select the window at .Ar target-window . @@ -1174,12 +1128,9 @@ or ) to send; if the string is not recognised as a key, it is sent as a series of characters. All arguments are sent sequentially from first to last. -.It Xo Ic send-prefix -.Op Fl t Ar target-window -.Xc +.It Ic send-prefix Op Fl t Ar target-window Send the prefix key to a window as if it was pressed. -.It Xo Ic server-info -.Xc +.It Ic server-info .D1 (alias: Ic info ) Show server information and terminal details. .It Xo Ic set-buffer @@ -1208,7 +1159,7 @@ options - it is not possible to unset a global option. Available session options are: .Bl -tag -width Ds .It Xo Ic bell-action -.Op Ic any | Ic none | Ic current +.Op Ic any | none | current .Xc Set action on window bell. .Ic any @@ -1310,13 +1261,13 @@ Repeat is enabled for the default keys bound to the .Ic resize-pane command. .It Xo Ic set-remain-on-exit -.Op Ic on | Ic off +.Op Ic on | off .Xc Set the .Ic remain-on-exit window option for any windows first created in this session. .It Xo Ic set-titles -.Op Ic on | Ic off +.Op Ic on | off .Xc Attempt to set the window title using the \ee]2;...\e007 xterm code and the terminal appears to be an xterm. @@ -1325,7 +1276,7 @@ Note that elinks will only attempt to set the window title if the STY environment variable is set. .It Xo Ic status -.Op Ic on | Ic off +.Op Ic on | off .Xc Show or hide the status line. .It Ic status-attr Ar attributes @@ -1341,12 +1292,12 @@ seconds. By default, updates will occur every 15 seconds. A setting of zero disables redrawing at interval. .It Xo Ic status-justify -.Op Ic left | Ic centre | Ic right +.Op Ic left | centre | right .Xc Set the position of the window list component of the status line: left, centre or right justified. .It Xo Ic status-keys -.Op Ic vi | Ic emacs +.Op Ic vi | emacs .Xc Use vi or emacs-style key bindings in the status line, for example at the command prompt. @@ -1408,7 +1359,7 @@ of the right component of the status bar. The default is 40. .Pp .It Xo Ic status-utf8 -.Op Ic on | Ic off +.Op Ic on | off .Xc Instruct .Nm @@ -1455,14 +1406,14 @@ entry for terminals which support 88 or 256 colours: "*88col*:colors=88,*256col*:colors=256" .Ed .It Xo Ic visual-activity -.Op Ic on | Ic off +.Op Ic on | off .Xc If on, display a status line message when activity occurs in a window for which the .Ic monitor-activity window option is enabled. .It Xo Ic visual-bell -.Op Ic on | Ic off +.Op Ic on | off .Xc If this option is on, a message is shown on a bell instead of it being passed through to the terminal (which normally makes a sound). @@ -1470,7 +1421,7 @@ Also see the .Ic bell-action option. .It Xo Ic visual-content -.Op Ic on | Ic off +.Op Ic on | off .Xc Like .Ic visual-activity , @@ -1510,9 +1461,10 @@ flags work similarly to the command. .Pp Supported window options are: -.Bl -tag -width Ds +.Pp +.Bl -tag -width Ds -compact .It Xo Ic aggressive-resize -.Op Ic on | Ic off +.Op Ic on | off .Xc Aggressively resize the chosen window. This means that @@ -1523,8 +1475,9 @@ The window may resize when the current window is changed on another sessions; this option is good for full-screen programs which support .Dv SIGWINCH and poor for interactive programs such as shells. +.Pp .It Xo Ic automatic-rename -.Op Ic on | Ic off +.Op Ic on | off .Xc Control automatic window renaming. When this setting is enabled, @@ -1541,12 +1494,15 @@ It may be switched off globally with: .Bd -literal -offset indent set-window-option -g automatic-rename off .Ed +.Pp .It Ic clock-mode-colour Ar colour Set clock colour. +.Pp .It Xo Ic clock-mode-style -.Op Ic 12 | Ic 24 +.Op Ic 12 | 24 .Xc Set clock hour format. +.Pp .It Ic force-height Ar height .It Ic force-width Ar width Prevent @@ -1556,6 +1512,7 @@ from resizing a window to greater than or .Ar height . A value of zero restores the default unlimited setting. +.Pp .It Ic main-pane-width Ar width .It Ic main-pane-height Ar height Set the width or height of the main (left or top) pane in the @@ -1563,66 +1520,81 @@ Set the width or height of the main (left or top) pane in the 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 | Ic emacs +.Op Ic vi | emacs .Xc Use vi or emacs-style key bindings in scroll, copy and choice modes. Key bindings default to emacs. +.Pp .It Xo Ic mode-mouse -.Op Ic on | Ic off +.Op Ic on | off .Xc Mouse state in modes. If on, .Nm will respond to mouse clicks by moving the cursor in copy mode or selecting an option in choice mode. +.Pp .It Xo Ic monitor-activity -.Op Ic on | Ic off +.Op Ic on | off .Xc Monitor for activity in the window. Windows with activity are highlighted in the status line. -.It Xo Ic monitor-content Ar match-string -.Xc +.Pp +.It Ic monitor-content Ar match-string Monitor content in the window. When .Xr fnmatch 3 pattern .Ar match-string appears in the window, it is highlighted in the status line. +.Pp .It Xo Ic remain-on-exit -.Op Ic on | Ic off +.Op Ic on | off .Xc A window with this flag set is not destroyed when the program running in it exits. The window may be reactivated with the .Ic respawn-window command. +.Pp .It Xo Ic utf8 -.Op Ic on | Ic off +.Op Ic on | off .Xc Instructs .Nm to expect UTF-8 sequences to appear in this window. +.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-fg Ar colour Set status line foreground 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. +.Pp .It Xo Ic xterm-keys -.Op Ic on | Ic off +.Op Ic on | off .Xc If this option is set, .Nm @@ -1656,9 +1628,7 @@ List the window options for or the global window options if .Fl g is used. -.It Xo Ic source-file -.Ar path -.Xc +.It Ic source-file Ar path .D1 (alias: Ic source ) Execute commands from .Ar path . @@ -1687,14 +1657,13 @@ cells (for horizontal split), or as a percentage, respectively. All other options have the same meaning as in the .Ic new-window command. -.It Xo Ic start-server -.Xc +.It Ic start-server .D1 (alias: Ic start ) Start the .Nm server, if not already running, without creating any sessions. .It Xo Ic suspend-client -.Op Fl c target-client +.Op Fl c Ar target-client .Xc .D1 (alias: Ic suspendc ) Suspend a client by sending @@ -1775,9 +1744,7 @@ if .Fl k is specified and the window is linked to only one session, it is unlinked and destroyed. -.It Xo Ic up-pane -.Op Fl t Ar target-pane -.Xc +.It Ic up-pane Op Fl t Ar target-pane .D1 (alias: Ic upp ) Move up a pane. .El From 93bf2a1d726c5f98a8460efcd199a8d202ecb3cc Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 4 Aug 2009 10:31:28 +0000 Subject: [PATCH 0216/1180] Check for "UTF8" as well as "UTF-8" in LANG etc as it seems this may also appear. --- tmux.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tmux.c b/tmux.c index ff1bd4c4..792969b3 100644 --- a/tmux.c +++ b/tmux.c @@ -332,7 +332,8 @@ main(int argc, char **argv) if ((s = getenv("LC_CTYPE")) == NULL) s = getenv("LANG"); } - if (s != NULL && strcasestr(s, "UTF-8") != NULL) + if (s != NULL && (strcasestr(s, "UTF-8") != NULL || + strcasestr(s, "UTF8") != NULL)) flags |= IDENTIFY_UTF8; } From 9e3bb986d59a930e409ee5a11b2fad72abe3dd68 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 4 Aug 2009 14:28:23 +0000 Subject: [PATCH 0217/1180] Show the bell/activity/current status and the window title in the choice list. --- cmd-choose-window.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/cmd-choose-window.c b/cmd-choose-window.c index 9386c5fa..efca9f80 100644 --- a/cmd-choose-window.c +++ b/cmd-choose-window.c @@ -52,6 +52,8 @@ cmd_choose_window_exec(struct cmd *self, struct cmd_ctx *ctx) struct winlink *wl, *wm; struct window *w; u_int idx, cur; + char flag, *title; + const char *left, *right; if (ctx->curclient == NULL) { ctx->error(ctx, "must be run interactively"); @@ -73,9 +75,30 @@ cmd_choose_window_exec(struct cmd *self, struct cmd_ctx *ctx) cur = idx; idx++; + flag = ' '; + if (session_alert_has(s, wm, WINDOW_ACTIVITY)) + flag = '#'; + else if (session_alert_has(s, wm, WINDOW_BELL)) + flag = '!'; + else if (session_alert_has(s, wm, WINDOW_CONTENT)) + flag = '+'; + else if (wm == s->curw) + flag = '*'; + else if (wm == SLIST_FIRST(&s->lastw)) + flag = '-'; + + title = w->active->screen->title; + if (wm == wl) + title = w->active->base.title; + left = " \""; + right = "\""; + if (*title == '\0') + left = right = ""; + window_choose_add(wl->window->active, - wm->idx, "%3d: %s [%ux%u] (%u panes)", - wm->idx, w->name, w->sx, w->sy, window_count_panes(w)); + wm->idx, "%3d: %s%c [%ux%u] (%u panes)%s%s%s", + wm->idx, w->name, flag, w->sx, w->sy, window_count_panes(w), + left, title, right); } cdata = xmalloc(sizeof *cdata); From a0647f1616da3a2b5fc7ce831ea83519832a196e Mon Sep 17 00:00:00 2001 From: Jason McIntyre Date: Tue, 4 Aug 2009 18:41:28 +0000 Subject: [PATCH 0218/1180] restructure the layout of this page, moving the commands into various subsections; lots of tweaks to come on the text from nicm and myself --- tmux.1 | 1597 +++++++++++++++++++++++++++++--------------------------- 1 file changed, 825 insertions(+), 772 deletions(-) diff --git a/tmux.1 b/tmux.1 index 97c4c6b6..15c21486 100644 --- a/tmux.1 +++ b/tmux.1 @@ -34,26 +34,6 @@ is a terminal multiplexer: it enables a number of terminals to be accessed and controlled from a single terminal. .Pp -.Nm -runs as a server-client system. -A server holds a number of -.Em sessions , -each of which may have a number of -.Em windows -linked to it. -A server is started automatically when the first session is created and exits -when all the sessions it contains are destroyed. -A window may be split on screen into one or more -.Em panes , -each of which is a separate terminal. -Any number of -.Em clients -may connect to a session, or the server -may be controlled by issuing commands with -.Nm . -Communication takes place through a socket, by default placed in -.Pa /tmp . -.Pp The options are as follows: .Bl -tag -width "XXXXXXXXXXXX" .It Fl 2 @@ -151,381 +131,51 @@ If no command and flags are specified, the .Ic new-session command is assumed. .El -.Sh QUICK START -To create a new +.Sh INTRODUCTION .Nm -session running -.Xr vi 1 : +runs as a server-client system. +A server holds a number of +.Em sessions , +each of which may have a number of +.Em windows +linked to it. +A server is started automatically when the first session is created and exits +when all the sessions it contains are destroyed. +A window may be split on screen into one or more +.Em panes , +each of which is a separate terminal. +Any number of +.Em clients +may connect to a session, or the server +may be controlled by issuing commands with +.Nm . +Communication takes place through a socket, by default placed in +.Pa /tmp . .Pp -.Dl $ tmux new-session vi -.Pp -Most commands have a shorter form, known as an alias. -For new-session, this is -.Ic new : -.Pp -.Dl $ tmux new vi -.Pp -Alternatively, the shortest unambiguous form of a command is accepted. -If there are several options, they are listed: -.Bd -literal -offset indent -$ tmux n -ambiguous command: n, could be: new-session, new-window, next-window -.Ed -.Pp -Within an active session, a new window may be created by typing -.Ql C-b c -(Ctrl -followed by the -.Ql b -key -followed by the -.Ql c -key). -.Pp -Windows may be navigated with: -.Ql C-b 0 -(to select window 0), -.Ql C-b 1 -(to select window 1), and so on; -.Ql C-b n -to select the next window; and -.Ql C-b p -to select the previous window. -.Pp -A session may be detached using -.Ql C-b d -and reattached with: -.Pp -.Dl $ tmux attach-session -.Pp -Typing -.Ql C-b \&? -lists the current key bindings in the current window; up and down may be used -to navigate the list or -.Ql q -to exit from it. -.Pp -Commands to be run when the +This is an overview of the sections in this manual page: +.Bl -ohang +.It Sy Commands +An overview of how .Nm -server is started may be placed in the -.Pa ~/.tmux.conf -configuration file. -Common examples include: -.Pp -Changing the default prefix key: -.Bd -literal -offset indent -set-option -g prefix C-a -unbind-key C-b -bind-key C-a send-prefix -.Ed -.Pp -Turning the status line off, or changing its colour: -.Bd -literal -offset indent -set-option -g status off -set-option -g status-bg blue -.Ed -.Pp -Setting other options, such as the default command, -or locking after 30 minutes of inactivity: -.Bd -literal -offset indent -set-option -g default-command "exec /bin/ksh" -set-option -g lock-after-time 1800 -.Ed -.Pp -Creating new key bindings: -.Bd -literal -offset indent -bind-key b set-option status -bind-key / command-prompt "split-window 'exec man %%'" -.Ed -.Sh KEY BINDINGS -.Nm -may be controlled from an attached client by using a key combination of a -prefix key, -.Ql C-b -(Ctrl-b) by default, followed by a command key. -.Pp -Some of the default key bindings include: -.Pp -.Bl -tag -width Ds -offset 3n -compact -.It c -Create new window. -.It d -Detach current client. -.It l -Move to last (previously selected) window in the current session. -.It n -Change to next window in the current session. -.It p -Change to previous window in the current session. -.It t -Display a large clock. -.It \&? -List current key bindings. +commands work. +.It Sy Clients and sessions +Commands for managing clients and sessions. +.It Sy Windows and panes +Commands for managing windows and panes. +.It Sy Key bindings +How key bindings work. +.It Sy Options +Configuration options for +.Nm . +.It Sy Status line +Commands pertinent to the status line. +.It Sy Buffers +Copy and paste operations. +.It Sy Miscellaneous +Miscellaneous commands. +.It Sy Examples +A quick start guide. .El -.Pp -A complete list may be obtained with the -.Ic list-keys -command (bound to -.Ql \&? -by default). -Key bindings may be changed with the -.Ic bind-key -and -.Ic unbind-key -commands. -.Sh HISTORY -.Nm -maintains a configurable history buffer for each window. -By default, up to 2000 lines are kept; this can be altered with the -.Ic history-limit -option (see the -.Ic set-option -command below). -.Sh MODES -A -.Nm -window may be in one of several modes. -The default permits direct access to the terminal attached to the window. -The others are: -.Bl -tag -width Ds -.It Em output mode -This is entered when a command which produces output, such as -.Ic list-keys , -is executed from a key binding. -.It Em scroll mode -This is entered with the -.Ic scroll-mode -command (bound to -.Ql = -by default) and permits the window history buffer to be inspected. -.It Em copy mode -This permits a section of a window or its history to be copied to a -.Em paste buffer -for later insertion into another window. -This mode is entered with the -.Ic copy-mode -command, bound to -.Ql [ -by default. -.El -.Pp -The keys available depend on whether emacs or vi mode is selected -(see the -.Ic mode-keys -option). -The following keys are supported as appropriate for the mode: -.Bl -column "FunctionXXXXXXXXXXXX" "viXXXXXX" "emacs" -offset indent -.It Sy "Function" Ta Sy "vi" Ta Sy "emacs" -.It Li "Start of line" Ta "0" Ta "C-a" -.It Li "Back to indentation" Ta "^" Ta "M-m" -.It Li "Clear selection" Ta "Escape" Ta "C-g" -.It Li "Copy selection" Ta "Enter" Ta "M-w" -.It Li "Cursor down" Ta "j" Ta "Down" -.It Li "End of line" Ta "$" Ta "C-e" -.It Li "Cursor left" Ta "h" Ta "Left" -.It Li "Next page" Ta "C-f" Ta "Page down" -.It Li "Next word" Ta "w" Ta "M-f" -.It Li "Previous page" Ta "C-u" Ta "Page up" -.It Li "Previous word" Ta "b" Ta "M-b" -.It Li "Quit mode" Ta "q" Ta "Escape" -.It Li "Cursor right" Ta "l" Ta "Right" -.It Li "Start selection" Ta "Space" Ta "C-Space" -.It Li "Cursor up" Ta "k" Ta "Up" -.It Li "Delete to end of line" Ta "D" Ta "C-k" -.It Li "Paste buffer" Ta "p" Ta "C-y" -.El -.Pp -These key bindings are defined in a set of named tables: -.Em vi-edit -and -.Em emacs-edit -for keys used when line editing at the command prompt; -.Em vi-choice -and -.Em emacs-choice -for keys used when choosing from lists (such as produced by the -.Ic window-choose -command) or in output mode; and -.Em vi-copy -and -.Em emacs-copy -used in copy and scroll modes. -The tables may be viewed with the -.Ic list-keys -command and keys modified or removed with -.Ic bind-key -and -.Ic unbind-key . -.Pp -The paste buffer key pastes the first line from the top paste buffer on the -stack. -.Sh BUFFERS -.Nm -maintains a stack of -.Em paste buffers -for each session. -Up to the value of the -.Ic buffer-limit -option are kept; when a new buffer is added, the buffer at the bottom of the -stack is removed. -Buffers may be added using -.Ic copy-mode -or the -.Ic set-buffer -command, and pasted into a window using the -.Ic paste-buffer -command. -.Sh OPTIONS -The appearance and behaviour of -.Nm -may be modified by changing the value of various options. -There are two types of option: -.Em session options -and -.Em window options . -.Pp -Each individual session may have a set of session options, and there is a -separate set of global session options. -Sessions which do not have a particular option configured inherit the value -from the global session options. -Session options are set or unset with the -.Ic set-option -command and may be listed with the -.Ic show-options -command. -The available session options are listed under the -.Ic set-option -command. -.Pp -Similarly, a set of window options is attached to each window, and there is -a set of global window options from which any unset options are inherited. -Window options are altered with the -.Ic set-window-option -command and can be listed with the -.Ic show-window-options -command. -All window options are documented with the -.Ic set-window-option -command. -.Sh PANES AND LAYOUTS -Each window displayed by -.Nm -may be split into one or more -.Em panes ; -each pane takes up a certain area of the display and is a separate terminal. -A window may be split into panes using the -.Ic split-window -command. -Windows may be split horizontally (with the -.Fl h -flag) or vertically. -Panes may be resized with the -.Ic resize-pane -command (bound to -.Ql C-up , -.Ql C-down -.Ql C-left -and -.Ql C-right -by default), the current pane may be changed with the -.Ic up-pane -and -.Ic down-pane -commands and the -.Ic rotate-window -and -.Ic swap-pane -commands may be used to swap panes without changing their position. -Panes are numbered beginning from zero in the order they are created. -.Pp -A number of preset -.Em layouts -are available. -These may be selected with the -.Ic select-layout -command or cycled with -.Ic next-layout -(bound to -.Ql C-space -by default); once a layout is chosen, panes within it may be moved and resized as normal. -.Pp -The following layouts are supported: -.Bl -tag -width Ds -.It Ic even-horizontal -Panes are spread out evenly from left to right across the window. -.It Ic even-vertical -Panes are spread evenly from top to bottom. -.It Ic main-horizontal -A large (main) pane is shown at the top of the window and the remaining panes are -spread from left to right in the leftover space at the bottom. -Use the -.Em main-pane-height -window option to specify the height of the top pane. -.It Ic main-vertical -Similar to -.Ic main-horizontal -but the large pane is placed on the left and the others spread from top to -bottom along the right. -See the -.Em main-pane-width -window option. -.El -.Sh STATUS LINE -.Nm -includes an optional status line which is displayed in the bottom line of each -terminal. -By default, the status line is enabled (it may be disabled with the -.Ic status -session option) and contains, from left-to-right: the name of the current -session in square brackets; the window list; the current window title in double -quotes; and the time and date. -.Pp -The status line is made of three parts: configurable left and right sections -(which may contain dynamic content such as the time or output from a shell -command, see the -.Ic status-left , -.Ic status-left-length , -.Ic status-right , -and -.Ic status-right-length -options below), and a central window list. -The window list shows the index, name and (if any) flag of the windows -present in the current session in ascending numerical order. -The flag is one of the following symbols appended to the window name: -.Bl -column "Symbol" "Meaning" -offset indent -.It Sy "Symbol" Ta Sy "Meaning" -.It Li "*" Ta "Denotes the current window." -.It Li "-" Ta "Marks the last window (previously selected)." -.It Li "#" Ta "Window is monitored and activity has been detected." -.It Li "!" Ta "A bell has occurred in the window." -.It Li "+" Ta "Window is monitored for content and it has appeared." -.El -.Pp -The # symbol relates to the -.Ic monitor-activity -and + to the -.Ic monitor-content -window options. -The window name is printed in inverted colours if an alert (bell, activity or -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. -.Pp -The status line is automatically refreshed at interval if it has changed, the interval may be -controlled with the -.Ic status-interval -session option. .Sh COMMANDS This section contains a list of the commands supported by .Nm . @@ -632,7 +282,7 @@ new-window ; split-window -d bind-key D detach-client \e\; lock-server .Ed -.Pp +.Sh CLIENTS AND SESSIONS The following commands are available: .Bl -tag -width Ds .It Xo Ic attach-session @@ -653,52 +303,251 @@ If no server is started, .Ic attach-session will attempt to start it; this will fail unless sessions are created in the configuration file. -.It Xo Ic bind-key -.Op Fl cnr -.Op Fl t Ar key-table -.Ar key Ar command Op Ar arguments +.It Ic detach-client Op Fl t Ar target-client +.D1 (alias: Ic detach ) +Detach the current client if bound to a key, or the specified client with +.Fl t . +.It Ic has-session Op Fl t Ar target-session +.D1 (alias: Ic has ) +Report an error and exit with 1 if the specified session does not exist. +If it does exist, exit with 0. +.It Ic kill-server +Kill the +.Nm +server and clients and destroy all sessions. +.It Ic kill-session Op Fl t Ar target-session +Destroy the given session, closing any windows linked to it and no other +sessions, and detaching all clients attached to it. +.It Ic list-clients +.D1 (alias: Ic lsc ) +List all clients attached to the server. +.It Ic list-commands +.D1 (alias: Ic lscm ) +List the syntax of all commands supported by +.Nm . +.It Ic list-sessions +.D1 (alias: Ic ls ) +List all sessions managed by the server. +.It Xo Ic new-session +.Op Fl d +.Op Fl n Ar window-name +.Op Fl s Ar session-name +.Op Ar command .Xc -.D1 (alias: Ic bind ) -Bind key -.Ar key -to -.Ar command . -Keys may be specified prefixed with -.Ql C- -or -.Ql ^ -for Ctrl keys, or -.Ql M- -for Alt (meta) keys. -.Pp -By default (without -.Fl t ) -the primary key bindings are modified (those normally activated with the prefix -key); in this case, if -.Fl n -is specified, it is not necessary to use the prefix key, +.D1 (alias: Ic new ) +Create a new session with name +.Ar session-name . +The new session is attached to the current terminal unless +.Fl d +is given. +.Ar window-name +and .Ar command -is bound to -.Ar key -alone. -The -.Fl r -flag indicates this key may repeat, see the -.Ic repeat-time -option. +are the name of and command to execute in the initial window. +.It Ic refresh-client Op Fl t Ar target-client +.D1 (alias: Ic refresh ) +Refresh the current client if bound to a key, or a single client if one is given +with +.Fl t . +.It Xo Ic rename-session +.Op Fl t Ar target-session +.Ar new-name +.Xc +.D1 (alias: Ic rename ) +Rename the session to +.Ar new-name . +.It Ic source-file Ar path +.D1 (alias: Ic source ) +Execute commands from +.Ar path . +.It Ic start-server +.D1 (alias: Ic start ) +Start the +.Nm +server, if not already running, without creating any sessions. +.It Xo Ic suspend-client +.Op Fl c Ar target-client +.Xc +.D1 (alias: Ic suspendc ) +Suspend a client by sending +.Dv SIGTSTP +(tty stop). +.It Xo Ic switch-client +.Op Fl c Ar target-client +.Op Fl t Ar target-session +.Xc +.D1 (alias: Ic switchc ) +Switch the current session for client +.Ar target-client +to +.Ar target-session . +.El +.Sh WINDOWS AND PANES +A +.Nm +window may be in one of several modes. +The default permits direct access to the terminal attached to the window. +The others are: +.Bl -tag -width Ds +.It Em output mode +This is entered when a command which produces output, such as +.Ic list-keys , +is executed from a key binding. +.It Em scroll mode +This is entered with the +.Ic scroll-mode +command (bound to +.Ql = +by default) and permits the window history buffer to be inspected. +.It Em copy mode +This permits a section of a window or its history to be copied to a +.Em paste buffer +for later insertion into another window. +This mode is entered with the +.Ic copy-mode +command, bound to +.Ql [ +by default. +.El .Pp -If -.Fl t -is present, -.Ar key -is bound in -.Ar key-table : -the binding for command mode with -.Fl c -or for normal mode without. -To view the default bindings and possible commands, see the +The keys available depend on whether emacs or vi mode is selected +(see the +.Ic mode-keys +option). +The following keys are supported as appropriate for the mode: +.Bl -column "FunctionXXXXXXXXXXXX" "viXXXXXX" "emacs" -offset indent +.It Sy "Function" Ta Sy "vi" Ta Sy "emacs" +.It Li "Start of line" Ta "0" Ta "C-a" +.It Li "Back to indentation" Ta "^" Ta "M-m" +.It Li "Clear selection" Ta "Escape" Ta "C-g" +.It Li "Copy selection" Ta "Enter" Ta "M-w" +.It Li "Cursor down" Ta "j" Ta "Down" +.It Li "End of line" Ta "$" Ta "C-e" +.It Li "Cursor left" Ta "h" Ta "Left" +.It Li "Next page" Ta "C-f" Ta "Page down" +.It Li "Next word" Ta "w" Ta "M-f" +.It Li "Previous page" Ta "C-u" Ta "Page up" +.It Li "Previous word" Ta "b" Ta "M-b" +.It Li "Quit mode" Ta "q" Ta "Escape" +.It Li "Cursor right" Ta "l" Ta "Right" +.It Li "Start selection" Ta "Space" Ta "C-Space" +.It Li "Cursor up" Ta "k" Ta "Up" +.It Li "Delete to end of line" Ta "D" Ta "C-k" +.It Li "Paste buffer" Ta "p" Ta "C-y" +.El +.Pp +These key bindings are defined in a set of named tables: +.Em vi-edit +and +.Em emacs-edit +for keys used when line editing at the command prompt; +.Em vi-choice +and +.Em emacs-choice +for keys used when choosing from lists (such as produced by the +.Ic window-choose +command) or in output mode; and +.Em vi-copy +and +.Em emacs-copy +used in copy and scroll modes. +The tables may be viewed with the .Ic list-keys +command and keys modified or removed with +.Ic bind-key +and +.Ic unbind-key . +.Pp +The paste buffer key pastes the first line from the top paste buffer on the +stack. +.Pp +The mode commands are as follows: +.Bl -tag -width Ds +.It Xo Ic copy-mode +.Op Fl u +.Op Fl t Ar target-window +.Xc +Enter copy mode. +The +.Fl u +option scrolls one page up. +.It Xo Ic scroll-mode +.Op Fl u +.Op Fl t Ar target-window +.Xc +Enter scroll mode. +The +.Fl u +has the same meaning as in the +.Ic copy-mode command. +.El +.Pp +Each window displayed by +.Nm +may be split into one or more +.Em panes ; +each pane takes up a certain area of the display and is a separate terminal. +A window may be split into panes using the +.Ic split-window +command. +Windows may be split horizontally (with the +.Fl h +flag) or vertically. +Panes may be resized with the +.Ic resize-pane +command (bound to +.Ql C-up , +.Ql C-down +.Ql C-left +and +.Ql C-right +by default), the current pane may be changed with the +.Ic up-pane +and +.Ic down-pane +commands and the +.Ic rotate-window +and +.Ic swap-pane +commands may be used to swap panes without changing their position. +Panes are numbered beginning from zero in the order they are created. +.Pp +A number of preset +.Em layouts +are available. +These may be selected with the +.Ic select-layout +command or cycled with +.Ic next-layout +(bound to +.Ql C-space +by default); once a layout is chosen, panes within it may be moved and resized as normal. +.Pp +The following layouts are supported: +.Bl -tag -width Ds +.It Ic even-horizontal +Panes are spread out evenly from left to right across the window. +.It Ic even-vertical +Panes are spread evenly from top to bottom. +.It Ic main-horizontal +A large (main) pane is shown at the top of the window and the remaining panes are +spread from left to right in the leftover space at the bottom. +Use the +.Em main-pane-height +window option to specify the height of the top pane. +.It Ic main-vertical +Similar to +.Ic main-horizontal +but the large pane is placed on the left and the others spread from top to +bottom along the right. +See the +.Em main-pane-width +window option. +.El +.Pp +Commands related to windows and panes are as follows: +.Bl -tag -width Ds .It Xo Ic break-pane .Op Fl d .Op Fl t Ar target-pane @@ -720,70 +569,6 @@ Put a window into window choice mode, where the window for the session attached to the current client may be selected interactively from a list. This command works only from inside .Nm . -.It Ic clear-history Op Fl t Ar target-pane -.D1 (alias: Ic clearhist ) -Remove and free the history for the specified pane. -.It Ic clock-mode Op Fl t Ar target-window -Display a large clock. -.It Xo Ic command-prompt -.Op Fl t Ar target-client -.Op Ar template -.Xc -Open the command prompt in a client. -This may be used from inside -.Nm -to execute commands interactively. -If -.Ar template -is specified, it is used as the command; any %% in the template will be -replaced by what is entered at the prompt. -.It Xo Ic confirm-before -.Op Fl t Ar target-client -.Ar command -.Xc -.D1 (alias: Ic confirm ) -Ask for confirmation before executing -.Ar command . -This command works only from inside -.Nm . -.It Xo Ic copy-buffer -.Op Fl a Ar src-index -.Op Fl b Ar dst-index -.Op Fl s Ar src-session -.Op Fl t Ar dst-session -.Xc -.D1 (alias: Ic copyb ) -Copy a session paste buffer to another session. -If no sessions are specified, the current one is used instead. -.It Xo Ic copy-mode -.Op Fl u -.Op Fl t Ar target-window -.Xc -Enter copy mode. -The -.Fl u -option scrolls one page up. -.It Xo Ic delete-buffer -.Op Fl b Ar buffer-index -.Op Fl t Ar target-session -.Xc -.D1 (alias: Ic deleteb ) -Delete the buffer at -.Ar buffer-index , -or the top buffer if not specified. -.It Ic detach-client Op Fl t Ar target-client -.D1 (alias: Ic detach ) -Detach the current client if bound to a key, or the specified client with -.Fl t . -.It Xo Ic display-message -.Op Fl t Ar target-client -.Op Ar message -.Xc -.D1 (alias: Ic display ) -Display a message (see the -.Ic status-left -option below) -in the status line. .It Ic down-pane Op Fl t Ar target-pane .D1 (alias: Ic downp ) Move down a pane. @@ -801,28 +586,10 @@ If only one window is matched, it'll be automatically selected, otherwise a choice list is shown. This command only works from inside .Nm . -.It Ic has-session Op Fl t Ar target-session -.D1 (alias: Ic has ) -Report an error and exit with 1 if the specified session does not exist. -If it does exist, exit with 0. -.It Ic if-shell Ar shell-command command -.D1 (alias: Ic if ) -Execute -.Ar command -if -.Ar shell-command -returns success. .It Ic kill-pane Op Fl t Ar target-pane .D1 (alias: Ic killp ) Destroy the given pane. If no panes remain in the containing window, it is also destroyed. -.It Ic kill-server -Kill the -.Nm -server and clients and destroy all sessions. -.It Ic kill-session Op Fl t Ar target-session -Destroy the given session, closing any windows linked to it and no other -sessions, and detaching all clients attached to it. .It Ic kill-window Op Fl t Ar target-window .D1 (alias: Ic killw ) Kill the current window or the window at @@ -857,58 +624,10 @@ exists, it is killed, otherwise an error is generated. If .Fl d is given, the newly linked window is not selected. -.It Ic list-buffers Op Fl t Ar target-session -.D1 (alias: Ic lsb ) -List the buffers in the given session. -.It Ic list-clients -.D1 (alias: Ic lsc ) -List all clients attached to the server. -.It Ic list-commands -.D1 (alias: Ic lscm ) -List the syntax of all commands supported by -.Nm . -.It Ic list-keys Op Fl t Ar key-table -.D1 (alias: Ic lsk ) -List all key bindings. -Without -.Fl t -the primary key bindings - those executed when preceded by the prefix key - -are printed. -Keys bound without the prefix key (see -.Ic bind-key -.Fl n ) -are enclosed in square brackets. -.Pp -With -.Fl t , -the key bindings in -.Ar key-table -are listed; this may be one of: -.Em vi-edit , -.Em emacs-edit , -.Em vi-choice , -.Em emacs-choice , -.Em vi-copy -or -.Em emacs-copy . -.It Ic list-sessions -.D1 (alias: Ic ls ) -List all sessions managed by the server. .It Ic list-windows Op Fl t Ar target-session .D1 (alias: Ic lsw ) List windows in the current session or in .Ar target-session . -.It Xo Ic load-buffer -.Op Fl b Ar buffer-index -.Op Fl t Ar target-session -.Ar path -.Xc -.D1 (alias: Ic loadb ) -Load the contents of the specified paste buffer from -.Ar path . -.It Ic lock-server -.D1 (alias: Ic lock ) -Lock the server until a password is entered. .It Xo Ic move-window .Op Fl d .Op Fl s Ar src-window @@ -921,22 +640,6 @@ except the window at .Ar src-window is moved to .Ar dst-window . -.It Xo Ic new-session -.Op Fl d -.Op Fl n Ar window-name -.Op Fl s Ar session-name -.Op Ar command -.Xc -.D1 (alias: Ic new ) -Create a new session with name -.Ar session-name . -The new session is attached to the current terminal unless -.Fl d -is given. -.Ar window-name -and -.Ar command -are the name of and command to execute in the initial window. .It Xo Ic new-window .Op Fl dk .Op Fl n Ar window-name @@ -982,21 +685,6 @@ Move to the next window in the session. If .Fl a is used, move to the next window with a bell, activity or content alert. -.It Xo Ic paste-buffer -.Op Fl dr -.Op Fl b Ar buffer-index -.Op Fl t Ar target-window -.Xc -.D1 (alias: Ic pasteb ) -Insert the contents of a paste buffer into the current window. -With -.Fl d , -also delete the paste buffer from the stack. -When output, any linefeed (LF) characters in the paste buffer are replaced with -carriage returns (CR). -This translation may be disabled with the -.Fl r -flag. .It Xo Ic previous-window .Op Fl a .Op Fl t Ar target-session @@ -1006,18 +694,6 @@ Move to the previous window in the session. With .Fl a , move to the previous window with a bell, activity or content alert. -.It Ic refresh-client Op Fl t Ar target-client -.D1 (alias: Ic refresh ) -Refresh the current client if bound to a key, or a single client if one is given -with -.Fl t . -.It Xo Ic rename-session -.Op Fl t Ar target-session -.Ar new-name -.Xc -.D1 (alias: Ic rename ) -Rename the session to -.Ar new-name . .It Xo Ic rename-window .Op Fl t Ar target-window .Ar new-name @@ -1068,28 +744,6 @@ Rotate the positions of the panes within a window, either upward (numerically lower) with .Fl U or downward (numerically higher). -.It Xo Ic save-buffer -.Op Fl a -.Op Fl b Ar buffer-index -.Op Fl t Ar target-session -.Ar path -.Xc -.D1 (alias: Ic saveb ) -Save the contents of the specified paste buffer to -.Ar path . -The -.Fl a -option appends to rather than overwriting the file. -.It Xo Ic scroll-mode -.Op Fl u -.Op Fl t Ar target-window -.Xc -Enter scroll mode. -The -.Fl u -has the same meaning as in the -.Ic copy-mode -command. .It Xo Ic select-layout .Op Fl t Ar target-window .Op Ar layout-name @@ -1105,14 +759,189 @@ Make pane .Ar target-pane the active pane in window .Ar target-window . -.It Ic select-prompt Op Fl t Ar target-client -Open a prompt inside -.Ar target-client -allowing a window index to be entered interactively. .It Ic select-window Op Fl t Ar target-window .D1 (alias: Ic selectw ) Select the window at .Ar target-window . +.It Xo Ic split-window +.Op Fl dhv +.Oo Fl l +.Ar size | +.Fl p Ar percentage Oc +.Op Fl t Ar target-window +.Op Ar command +.Xc +.D1 (alias: splitw ) +Creates a new pane by splitting the active pane: +.Fl h +does a horizontal split and +.Fl v +a vertical split; if neither is specified, +.Fl v +is assumed. +The +.Fl l +and +.Fl p +options specify the size of the new window in lines (for vertical split) or in +cells (for horizontal split), or as a percentage, respectively. +All other options have the same meaning as in the +.Ic new-window +command. +.It Xo Ic swap-pane +.Op Fl dDU +.Op Fl s Ar src-pane +.Op Fl t Ar dst-pane +.Xc +.D1 (alias: Ic swapp ) +Swap two panes. +If +.Fl U +is used and no source pane is specified with +.Fl s , +.Ar dst-pane +is swapped with the previous pane (before it numerically); +.Fl D +swaps with the next pane (after it numerically). +.It Xo Ic swap-window +.Op Fl d +.Op Fl s Ar src-window +.Op Fl t Ar dst-window +.Xc +.D1 (alias: Ic swapw ) +This is similar to +.Ic link-window , +except the source and destination windows are swapped. +It is an error if no window exists at +.Ar src-window . +.It Xo Ic unlink-window +.Op Fl k +.Op Fl t Ar target-window +.Xc +.D1 (alias: Ic unlinkw ) +Unlink +.Ar target-window . +Unless +.Fl k +is given, a window may be unlinked only if it is linked to multiple sessions - +windows may not be linked to no sessions; +if +.Fl k +is specified and the window is linked to only one session, it is unlinked and +destroyed. +.It Ic up-pane Op Fl t Ar target-pane +.D1 (alias: Ic upp ) +Move up a pane. +.El +.Sh KEY BINDINGS +.Nm +may be controlled from an attached client by using a key combination of a +prefix key, +.Ql C-b +(Ctrl-b) by default, followed by a command key. +.Pp +Some of the default key bindings include: +.Pp +.Bl -tag -width Ds -offset 3n -compact +.It c +Create new window. +.It d +Detach current client. +.It l +Move to last (previously selected) window in the current session. +.It n +Change to next window in the current session. +.It p +Change to previous window in the current session. +.It t +Display a large clock. +.It \&? +List current key bindings. +.El +.Pp +A complete list may be obtained with the +.Ic list-keys +command (bound to +.Ql \&? +by default). +Key bindings may be changed with the +.Ic bind-key +and +.Ic unbind-key +commands. +.Pp +Commands related to key bindings are as follows: +.Bl -tag -width Ds +.It Xo Ic bind-key +.Op Fl cnr +.Op Fl t Ar key-table +.Ar key Ar command Op Ar arguments +.Xc +.D1 (alias: Ic bind ) +Bind key +.Ar key +to +.Ar command . +Keys may be specified prefixed with +.Ql C- +or +.Ql ^ +for Ctrl keys, or +.Ql M- +for Alt (meta) keys. +.Pp +By default (without +.Fl t ) +the primary key bindings are modified (those normally activated with the prefix +key); in this case, if +.Fl n +is specified, it is not necessary to use the prefix key, +.Ar command +is bound to +.Ar key +alone. +The +.Fl r +flag indicates this key may repeat, see the +.Ic repeat-time +option. +.Pp +If +.Fl t +is present, +.Ar key +is bound in +.Ar key-table : +the binding for command mode with +.Fl c +or for normal mode without. +To view the default bindings and possible commands, see the +.Ic list-keys +command. +.It Ic list-keys Op Fl t Ar key-table +.D1 (alias: Ic lsk ) +List all key bindings. +Without +.Fl t +the primary key bindings - those executed when preceded by the prefix key - +are printed. +Keys bound without the prefix key (see +.Ic bind-key +.Fl n ) +are enclosed in square brackets. +.Pp +With +.Fl t , +the key bindings in +.Ar key-table +are listed; this may be one of: +.Em vi-edit , +.Em emacs-edit , +.Em vi-choice , +.Em emacs-choice , +.Em vi-copy +or +.Em emacs-copy . .It Xo Ic send-keys .Op Fl t Ar target-window .Ar key Ar ... @@ -1130,17 +959,67 @@ characters. All arguments are sent sequentially from first to last. .It Ic send-prefix Op Fl t Ar target-window Send the prefix key to a window as if it was pressed. -.It Ic server-info -.D1 (alias: Ic info ) -Show server information and terminal details. -.It Xo Ic set-buffer -.Op Fl b Ar buffer-index -.Op Fl t Ar target-session -.Ar data +.It Xo Ic unbind-key +.Op Fl cn +.Op Fl t Ar key-table +.Ar key .Xc -.D1 (alias: Ic setb ) -Set the contents of the specified buffer to -.Ar data . +.D1 (alias: Ic unbind ) +Unbind the command bound to +.Ar key . +Without +.Fl t +the primary key bindings are modified; in this case, if +.Fl n +is specified, the command bound to +.Ar key +without a prefix (if any) is removed. +.Pp +If +.Fl t +is present, +.Ar key +in +.Ar key-table +is unbound: the binding for command mode with +.Fl c +or for normal mode without. +.El +.Sh OPTIONS +The appearance and behaviour of +.Nm +may be modified by changing the value of various options. +There are two types of option: +.Em session options +and +.Em window options . +.Pp +Each individual session may have a set of session options, and there is a +separate set of global session options. +Sessions which do not have a particular option configured inherit the value +from the global session options. +Session options are set or unset with the +.Ic set-option +command and may be listed with the +.Ic show-options +command. +The available session options are listed under the +.Ic set-option +command. +.Pp +Similarly, a set of window options is attached to each window, and there is +a set of global window options from which any unset options are inherited. +Window options are altered with the +.Ic set-window-option +command and can be listed with the +.Ic show-window-options +command. +All window options are documented with the +.Ic set-window-option +command. +.Pp +Commands which set options are as follows: +.Bl -tag -width Ds .It Xo Ic set-option .Op Fl gu .Op Fl t Ar target-session @@ -1430,21 +1309,6 @@ for which the .Ic monitor-content window option is enabled. .El -.It Xo Ic set-password -.Op Fl c -.Ar password -.Xc -.D1 (alias: Ic pass ) -Set the server password. -If the -.Fl c -option is given, a pre-encrypted password may be specified. -By default, the password is blank, thus any entered password will be accepted -when unlocking the server (see the -.Ic lock-server -command). -To prevent variable expansion when an encrypted password is read from a -configuration file, enclose it in single quotes ('). .It Xo Ic set-window-option .Op Fl gu .Op Fl t Ar target-window @@ -1603,12 +1467,6 @@ will generate function key sequences; these have a number included to indicate modifiers such as Shift, Alt or Ctrl. .El -.It Xo Ic show-buffer -.Op Fl b Ar buffer-index -.Op Fl t Ar target-session -.Xc -.D1 (alias: Ic showb ) -Display the contents of the specified buffer. .It Xo Ic show-options .Op Fl g .Op Fl t Ar target-session @@ -1628,125 +1486,234 @@ List the window options for or the global window options if .Fl g is used. -.It Ic source-file Ar path -.D1 (alias: Ic source ) -Execute commands from -.Ar path . -.It Xo Ic split-window -.Op Fl dhv -.Oo Fl l -.Ar size | -.Fl p Ar percentage Oc -.Op Fl t Ar target-window -.Op Ar command -.Xc -.D1 (alias: splitw ) -Creates a new pane by splitting the active pane: -.Fl h -does a horizontal split and -.Fl v -a vertical split; if neither is specified, -.Fl v -is assumed. -The -.Fl l -and -.Fl p -options specify the size of the new window in lines (for vertical split) or in -cells (for horizontal split), or as a percentage, respectively. -All other options have the same meaning as in the -.Ic new-window -command. -.It Ic start-server -.D1 (alias: Ic start ) -Start the +.El +.Sh STATUS LINE .Nm -server, if not already running, without creating any sessions. -.It Xo Ic suspend-client -.Op Fl c Ar target-client +includes an optional status line which is displayed in the bottom line of each +terminal. +By default, the status line is enabled (it may be disabled with the +.Ic status +session option) and contains, from left-to-right: the name of the current +session in square brackets; the window list; the current window title in double +quotes; and the time and date. +.Pp +The status line is made of three parts: configurable left and right sections +(which may contain dynamic content such as the time or output from a shell +command, see the +.Ic status-left , +.Ic status-left-length , +.Ic status-right , +and +.Ic status-right-length +options below), and a central window list. +The window list shows the index, name and (if any) flag of the windows +present in the current session in ascending numerical order. +The flag is one of the following symbols appended to the window name: +.Bl -column "Symbol" "Meaning" -offset indent +.It Sy "Symbol" Ta Sy "Meaning" +.It Li "*" Ta "Denotes the current window." +.It Li "-" Ta "Marks the last window (previously selected)." +.It Li "#" Ta "Window is monitored and activity has been detected." +.It Li "!" Ta "A bell has occurred in the window." +.It Li "+" Ta "Window is monitored for content and it has appeared." +.El +.Pp +The # symbol relates to the +.Ic monitor-activity +and + to the +.Ic monitor-content +window options. +The window name is printed in inverted colours if an alert (bell, activity or +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. +.Pp +The status line is automatically refreshed at interval if it has changed, the interval may be +controlled with the +.Ic status-interval +session option. +.Pp +Commands related to the status line are as follows: +.Bl -tag -width Ds +.It Xo Ic command-prompt +.Op Fl t Ar target-client +.Op Ar template .Xc -.D1 (alias: Ic suspendc ) -Suspend a client by sending -.Dv SIGTSTP -(tty stop). -.It Xo Ic swap-pane -.Op Fl dDU -.Op Fl s Ar src-pane -.Op Fl t Ar dst-pane -.Xc -.D1 (alias: Ic swapp ) -Swap two panes. +Open the command prompt in a client. +This may be used from inside +.Nm +to execute commands interactively. If -.Fl U -is used and no source pane is specified with -.Fl s , -.Ar dst-pane -is swapped with the previous pane (before it numerically); -.Fl D -swaps with the next pane (after it numerically). -.It Xo Ic swap-window -.Op Fl d -.Op Fl s Ar src-window -.Op Fl t Ar dst-window +.Ar template +is specified, it is used as the command; any %% in the template will be +replaced by what is entered at the prompt. +.It Xo Ic confirm-before +.Op Fl t Ar target-client +.Ar command .Xc -.D1 (alias: Ic swapw ) -This is similar to -.Ic link-window , -except the source and destination windows are swapped. -It is an error if no window exists at -.Ar src-window . -.It Xo Ic switch-client -.Op Fl c Ar target-client +.D1 (alias: Ic confirm ) +Ask for confirmation before executing +.Ar command . +This command works only from inside +.Nm . +.It Xo Ic display-message +.Op Fl t Ar target-client +.Op Ar message +.Xc +.D1 (alias: Ic display ) +Display a message (see the +.Ic status-left +option below) +in the status line. +.It Ic select-prompt Op Fl t Ar target-client +Open a prompt inside +.Ar target-client +allowing a window index to be entered interactively. +.El +.Sh BUFFERS +.Nm +maintains a stack of +.Em paste buffers +for each session. +Up to the value of the +.Ic buffer-limit +option are kept; when a new buffer is added, the buffer at the bottom of the +stack is removed. +Buffers may be added using +.Ic copy-mode +or the +.Ic set-buffer +command, and pasted into a window using the +.Ic paste-buffer +command. +.Pp +A configurable history buffer is also maintained for each window. +By default, up to 2000 lines are kept; this can be altered with the +.Ic history-limit +option (see the +.Ic set-option +command above). +.Pp +The buffer commands are as follows: +.Bl -tag -width Ds +.It Ic clear-history Op Fl t Ar target-pane +.D1 (alias: Ic clearhist ) +Remove and free the history for the specified pane. +.It Xo Ic copy-buffer +.Op Fl a Ar src-index +.Op Fl b Ar dst-index +.Op Fl s Ar src-session +.Op Fl t Ar dst-session +.Xc +.D1 (alias: Ic copyb ) +Copy a session paste buffer to another session. +If no sessions are specified, the current one is used instead. +.It Xo Ic delete-buffer +.Op Fl b Ar buffer-index .Op Fl t Ar target-session .Xc -.D1 (alias: Ic switchc ) -Switch the current session for client -.Ar target-client -to -.Ar target-session . -.It Xo Ic unbind-key -.Op Fl cn -.Op Fl t Ar key-table -.Ar key +.D1 (alias: Ic deleteb ) +Delete the buffer at +.Ar buffer-index , +or the top buffer if not specified. +.It Ic list-buffers Op Fl t Ar target-session +.D1 (alias: Ic lsb ) +List the buffers in the given session. +.It Xo Ic load-buffer +.Op Fl b Ar buffer-index +.Op Fl t Ar target-session +.Ar path .Xc -.D1 (alias: Ic unbind ) -Unbind the command bound to -.Ar key . -Without -.Fl t -the primary key bindings are modified; in this case, if -.Fl n -is specified, the command bound to -.Ar key -without a prefix (if any) is removed. -.Pp -If -.Fl t -is present, -.Ar key -in -.Ar key-table -is unbound: the binding for command mode with -.Fl c -or for normal mode without. -.It Xo Ic unlink-window -.Op Fl k +.D1 (alias: Ic loadb ) +Load the contents of the specified paste buffer from +.Ar path . +.It Xo Ic paste-buffer +.Op Fl dr +.Op Fl b Ar buffer-index .Op Fl t Ar target-window .Xc -.D1 (alias: Ic unlinkw ) -Unlink -.Ar target-window . -Unless -.Fl k -is given, a window may be unlinked only if it is linked to multiple sessions - -windows may not be linked to no sessions; +.D1 (alias: Ic pasteb ) +Insert the contents of a paste buffer into the current window. +With +.Fl d , +also delete the paste buffer from the stack. +When output, any linefeed (LF) characters in the paste buffer are replaced with +carriage returns (CR). +This translation may be disabled with the +.Fl r +flag. +.It Xo Ic save-buffer +.Op Fl a +.Op Fl b Ar buffer-index +.Op Fl t Ar target-session +.Ar path +.Xc +.D1 (alias: Ic saveb ) +Save the contents of the specified paste buffer to +.Ar path . +The +.Fl a +option appends to rather than overwriting the file. +.It Xo Ic set-buffer +.Op Fl b Ar buffer-index +.Op Fl t Ar target-session +.Ar data +.Xc +.D1 (alias: Ic setb ) +Set the contents of the specified buffer to +.Ar data . +.It Xo Ic show-buffer +.Op Fl b Ar buffer-index +.Op Fl t Ar target-session +.Xc +.D1 (alias: Ic showb ) +Display the contents of the specified buffer. +.El +.Sh MISCELLANEOUS +.Pp +Miscellaneous commands are as follows: +.Bl -tag -width Ds +.It Ic clock-mode Op Fl t Ar target-window +Display a large clock. +.It Ic if-shell Ar shell-command command +.D1 (alias: Ic if ) +Execute +.Ar command if -.Fl k -is specified and the window is linked to only one session, it is unlinked and -destroyed. -.It Ic up-pane Op Fl t Ar target-pane -.D1 (alias: Ic upp ) -Move up a pane. +.Ar shell-command +returns success. +.It Ic lock-server +.D1 (alias: Ic lock ) +Lock the server until a password is entered. +.It Ic server-info +.D1 (alias: Ic info ) +Show server information and terminal details. +.It Xo Ic set-password +.Op Fl c +.Ar password +.Xc +.D1 (alias: Ic pass ) +Set the server password. +If the +.Fl c +option is given, a pre-encrypted password may be specified. +By default, the password is blank, thus any entered password will be accepted +when unlocking the server (see the +.Ic lock-server +command). +To prevent variable expansion when an encrypted password is read from a +configuration file, enclose it in single quotes ('). .El .Sh FILES .Bl -tag -width "/etc/tmux.confXXX" -compact @@ -1757,6 +1724,92 @@ configuration file. .It Pa /etc/tmux.conf System-wide configuration file. .El +.Sh EXAMPLES +To create a new +.Nm +session running +.Xr vi 1 : +.Pp +.Dl $ tmux new-session vi +.Pp +Most commands have a shorter form, known as an alias. +For new-session, this is +.Ic new : +.Pp +.Dl $ tmux new vi +.Pp +Alternatively, the shortest unambiguous form of a command is accepted. +If there are several options, they are listed: +.Bd -literal -offset indent +$ tmux n +ambiguous command: n, could be: new-session, new-window, next-window +.Ed +.Pp +Within an active session, a new window may be created by typing +.Ql C-b c +(Ctrl +followed by the +.Ql b +key +followed by the +.Ql c +key). +.Pp +Windows may be navigated with: +.Ql C-b 0 +(to select window 0), +.Ql C-b 1 +(to select window 1), and so on; +.Ql C-b n +to select the next window; and +.Ql C-b p +to select the previous window. +.Pp +A session may be detached using +.Ql C-b d +and reattached with: +.Pp +.Dl $ tmux attach-session +.Pp +Typing +.Ql C-b \&? +lists the current key bindings in the current window; up and down may be used +to navigate the list or +.Ql q +to exit from it. +.Pp +Commands to be run when the +.Nm +server is started may be placed in the +.Pa ~/.tmux.conf +configuration file. +Common examples include: +.Pp +Changing the default prefix key: +.Bd -literal -offset indent +set-option -g prefix C-a +unbind-key C-b +bind-key C-a send-prefix +.Ed +.Pp +Turning the status line off, or changing its colour: +.Bd -literal -offset indent +set-option -g status off +set-option -g status-bg blue +.Ed +.Pp +Setting other options, such as the default command, +or locking after 30 minutes of inactivity: +.Bd -literal -offset indent +set-option -g default-command "exec /bin/ksh" +set-option -g lock-after-time 1800 +.Ed +.Pp +Creating new key bindings: +.Bd -literal -offset indent +bind-key b set-option status +bind-key / command-prompt "split-window 'exec man %%'" +.Ed .Sh SEE ALSO .Xr pty 4 .Sh AUTHORS From 12ef3ceda13f9ae4c77384f98e6f145322971e69 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 4 Aug 2009 18:45:57 +0000 Subject: [PATCH 0219/1180] Add a -a flag to set-option and set-window-option to append to an existing string value, useful for terminal-overrides. --- cmd-set-option.c | 7 ++++--- cmd-set-window-option.c | 7 ++++--- options-cmd.c | 17 ++++++++++++++--- tmux.1 | 10 ++++++++-- tmux.h | 10 +++++----- 5 files changed, 35 insertions(+), 16 deletions(-) diff --git a/cmd-set-option.c b/cmd-set-option.c index 5c2d5870..de6141a1 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -31,8 +31,8 @@ int cmd_set_option_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_set_option_entry = { "set-option", "set", - CMD_OPTION_SESSION_USAGE, - 0, CMD_CHFLAG('g')|CMD_CHFLAG('u'), + "[-agu] " CMD_OPTION_SESSION_USAGE, + 0, CMD_CHFLAG('a')|CMD_CHFLAG('g')|CMD_CHFLAG('u'), NULL, cmd_option_parse, cmd_set_option_exec, @@ -144,7 +144,8 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) } else { switch (entry->type) { case SET_OPTION_STRING: - set_option_string(ctx, oo, entry, data->value); + set_option_string(ctx, oo, entry, + data->value, data->chflags & CMD_CHFLAG('a')); break; case SET_OPTION_NUMBER: set_option_number(ctx, oo, entry, data->value); diff --git a/cmd-set-window-option.c b/cmd-set-window-option.c index 1d90425d..beeb26e2 100644 --- a/cmd-set-window-option.c +++ b/cmd-set-window-option.c @@ -31,8 +31,8 @@ int cmd_set_window_option_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_set_window_option_entry = { "set-window-option", "setw", - CMD_OPTION_WINDOW_USAGE, - 0, CMD_CHFLAG('g')|CMD_CHFLAG('u'), + "[-agu] " CMD_OPTION_WINDOW_USAGE, + 0, CMD_CHFLAG('a')|CMD_CHFLAG('g')|CMD_CHFLAG('u'), NULL, cmd_option_parse, cmd_set_window_option_exec, @@ -134,7 +134,8 @@ cmd_set_window_option_exec(struct cmd *self, struct cmd_ctx *ctx) } else { switch (entry->type) { case SET_OPTION_STRING: - set_option_string(ctx, oo, entry, data->value); + set_option_string(ctx, oo, entry, + data->value, data->chflags & CMD_CHFLAG('a')); break; case SET_OPTION_NUMBER: set_option_number(ctx, oo, entry, data->value); diff --git a/options-cmd.c b/options-cmd.c index 6b7090bd..4cdd75d0 100644 --- a/options-cmd.c +++ b/options-cmd.c @@ -25,15 +25,26 @@ void set_option_string(struct cmd_ctx *ctx, struct options *oo, - const struct set_option_entry *entry, char *value) + const struct set_option_entry *entry, char *value, int append) { + char *oldvalue, *newvalue; + if (value == NULL) { ctx->error(ctx, "empty value"); return; } - options_set_string(oo, entry->name, "%s", value); - ctx->info(ctx, "set option: %s -> %s", entry->name, value); + if (append) { + oldvalue = options_get_string(oo, entry->name); + xasprintf(&newvalue, "%s%s", oldvalue, value); + } else + newvalue = value; + + options_set_string(oo, entry->name, "%s", newvalue); + ctx->info(ctx, "set option: %s -> %s", entry->name, newvalue); + + if (newvalue != value) + xfree(newvalue); } void diff --git a/tmux.1 b/tmux.1 index 15c21486..8264c73f 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1021,12 +1021,17 @@ command. Commands which set options are as follows: .Bl -tag -width Ds .It Xo Ic set-option -.Op Fl gu +.Op Fl agu .Op Fl t Ar target-session .Ar option Ar value .Xc .D1 (alias: Ic set ) Set a session option. +With +.Fl a , +and if the option expects a string, +.Ar value +is appended to the existing setting. If .Fl g is specified, the global session option is set. @@ -1310,13 +1315,14 @@ for which the window option is enabled. .El .It Xo Ic set-window-option -.Op Fl gu +.Op Fl agu .Op Fl t Ar target-window .Ar option Ar value .Xc .D1 (alias: Ic setw ) Set a window option. The +.Fl a , .Fl g and .Fl u diff --git a/tmux.h b/tmux.h index 37686e13..97ac7040 100644 --- a/tmux.h +++ b/tmux.h @@ -1172,7 +1172,7 @@ int tty_keys_next(struct tty *, int *, u_char *); /* options-cmd.c */ void set_option_string(struct cmd_ctx *, - struct options *, const struct set_option_entry *, char *); + struct options *, const struct set_option_entry *, char *, int); void set_option_number(struct cmd_ctx *, struct options *, const struct set_option_entry *, char *); void set_option_key(struct cmd_ctx *, @@ -1326,10 +1326,10 @@ void cmd_buffer_init(struct cmd *, int); int cmd_buffer_parse(struct cmd *, int, char **, char **); void cmd_buffer_free(struct cmd *); size_t cmd_buffer_print(struct cmd *, char *, size_t); -#define CMD_OPTION_PANE_USAGE "[-gu] [-t target-pane] option [value]" -#define CMD_OPTION_WINDOW_USAGE "[-gu] [-t target-window] option [value]" -#define CMD_OPTION_SESSION_USAGE "[-gu] [-t target-session] option [value]" -#define CMD_OPTION_CLIENT_USAGE "[-gu] [-t target-client] option [value]" +#define CMD_OPTION_PANE_USAGE "[-t target-pane] option [value]" +#define CMD_OPTION_WINDOW_USAGE "[-t target-window] option [value]" +#define CMD_OPTION_SESSION_USAGE "[-t target-session] option [value]" +#define CMD_OPTION_CLIENT_USAGE "[-t target-client] option [value]" void cmd_option_init(struct cmd *, int); int cmd_option_parse(struct cmd *, int, char **, char **); void cmd_option_free(struct cmd *); From bcddddf98d46bb9aef919d8e93b7328a7b040140 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 5 Aug 2009 16:26:38 +0000 Subject: [PATCH 0220/1180] If colours are not supported by the terminal, try to emulate a coloured background by setting or clearing the reverse attribute. This makes a few applications which don't use the reverse attribute themselves a little happier, and allows the status, message and mode options to have default attributes and fg/bg options that work as expected when set as reverse. --- status.c | 12 ++++++------ tmux.c | 6 +++--- tty.c | 26 ++++++++++++++++++++------ window-choose.c | 4 ++-- window-copy.c | 8 ++++---- window-more.c | 4 ++-- window-scroll.c | 4 ++-- 7 files changed, 39 insertions(+), 25 deletions(-) diff --git a/status.c b/status.c index e4836d34..5b625471 100644 --- a/status.c +++ b/status.c @@ -64,8 +64,8 @@ status_redraw(struct client *c) if (gettimeofday(&c->status_timer, NULL) != 0) fatal("gettimeofday"); memcpy(&stdgc, &grid_default_cell, sizeof gc); - stdgc.bg = options_get_number(&s->options, "status-fg"); - stdgc.fg = options_get_number(&s->options, "status-bg"); + stdgc.fg = options_get_number(&s->options, "status-fg"); + stdgc.bg = options_get_number(&s->options, "status-bg"); stdgc.attr |= options_get_number(&s->options, "status-attr"); yy = c->tty.sy - 1; @@ -563,8 +563,8 @@ status_message_redraw(struct client *c) len = c->tty.sx; memcpy(&gc, &grid_default_cell, sizeof gc); - gc.bg = options_get_number(&s->options, "message-fg"); - gc.fg = options_get_number(&s->options, "message-bg"); + gc.fg = options_get_number(&s->options, "message-fg"); + gc.bg = options_get_number(&s->options, "message-bg"); gc.attr |= options_get_number(&s->options, "message-attr"); screen_write_start(&ctx, NULL, &c->status); @@ -662,8 +662,8 @@ status_prompt_redraw(struct client *c) len = c->tty.sx; memcpy(&gc, &grid_default_cell, sizeof gc); - gc.bg = options_get_number(&s->options, "message-fg"); - gc.fg = options_get_number(&s->options, "message-bg"); + gc.fg = options_get_number(&s->options, "message-fg"); + gc.bg = options_get_number(&s->options, "message-bg"); gc.attr |= options_get_number(&s->options, "message-attr"); screen_write_start(&ctx, NULL, &c->status); diff --git a/tmux.c b/tmux.c index 792969b3..00a9e8f0 100644 --- a/tmux.c +++ b/tmux.c @@ -345,7 +345,7 @@ main(int argc, char **argv) options_set_number(&global_s_options, "display-time", 750); options_set_number(&global_s_options, "history-limit", 2000); options_set_number(&global_s_options, "lock-after-time", 0); - options_set_number(&global_s_options, "message-attr", GRID_ATTR_REVERSE); + options_set_number(&global_s_options, "message-attr", 0); options_set_number(&global_s_options, "message-bg", 3); options_set_number(&global_s_options, "message-fg", 0); options_set_number(&global_s_options, "prefix", '\002'); @@ -353,7 +353,7 @@ main(int argc, char **argv) options_set_number(&global_s_options, "set-remain-on-exit", 0); options_set_number(&global_s_options, "set-titles", 0); options_set_number(&global_s_options, "status", 1); - options_set_number(&global_s_options, "status-attr", GRID_ATTR_REVERSE); + options_set_number(&global_s_options, "status-attr", 0); options_set_number(&global_s_options, "status-bg", 2); options_set_number(&global_s_options, "status-fg", 0); options_set_number(&global_s_options, "status-interval", 15); @@ -383,7 +383,7 @@ main(int argc, char **argv) options_set_number(&global_w_options, "force-width", 0); options_set_number(&global_w_options, "main-pane-width", 81); options_set_number(&global_w_options, "main-pane-height", 24); - options_set_number(&global_w_options, "mode-attr", GRID_ATTR_REVERSE); + options_set_number(&global_w_options, "mode-attr", 0); options_set_number(&global_w_options, "mode-bg", 3); options_set_number(&global_w_options, "mode-fg", 0); options_set_number(&global_w_options, "mode-keys", MODEKEY_EMACS); diff --git a/tty.c b/tty.c index d3a4ba1d..cbdbec8d 100644 --- a/tty.c +++ b/tty.c @@ -951,19 +951,33 @@ tty_attributes(struct tty *tty, const struct grid_cell *gc) { struct grid_cell *tc = &tty->cell; u_char changed; - u_int fg, bg; + u_int fg, bg, attr; + + /* + * If no setab, try to use the reverse attribute as a best-effort for a + * non-default background. This is a bit of a hack but it doesn't do + * any serious harm and makes a couple of applications happier. + */ + fg = gc->fg; bg = gc->bg; attr = gc->attr; + if (!tty_term_has(tty->term, TTYC_SETAB)) { + if (attr & GRID_ATTR_REVERSE) { + if (fg != 7 && fg != 8) + attr &= ~GRID_ATTR_REVERSE; + } else { + if (bg != 0 && bg != 8) + attr |= GRID_ATTR_REVERSE; + } + } /* If any bits are being cleared, reset everything. */ - if (tc->attr & ~gc->attr) + if (tc->attr & ~attr) tty_reset(tty); /* Filter out attribute bits already set. */ - changed = gc->attr & ~tc->attr; - tc->attr = gc->attr; + changed = attr & ~tc->attr; + tc->attr = attr; /* Set the attributes. */ - fg = gc->fg; - bg = gc->bg; if (changed & GRID_ATTR_BRIGHT) tty_putcode(tty, TTYC_BOLD); if (changed & GRID_ATTR_DIM) diff --git a/window-choose.c b/window-choose.c index b1d9192a..4ef003df 100644 --- a/window-choose.c +++ b/window-choose.c @@ -305,8 +305,8 @@ 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) { - gc.fg = options_get_number(&wp->window->options, "mode-bg"); - gc.bg = options_get_number(&wp->window->options, "mode-fg"); + gc.fg = options_get_number(&wp->window->options, "mode-fg"); + gc.bg = options_get_number(&wp->window->options, "mode-bg"); gc.attr |= options_get_number(&wp->window->options, "mode-attr"); } diff --git a/window-copy.c b/window-copy.c index 340c9c75..7996359d 100644 --- a/window-copy.c +++ b/window-copy.c @@ -264,8 +264,8 @@ window_copy_write_line(struct window_pane *wp, struct screen_write_ctx *ctx, u_i memcpy(&gc, &grid_default_cell, sizeof gc); size = xsnprintf(hdr, sizeof hdr, "[%u,%u/%u]", data->ox, data->oy, screen_hsize(&wp->base)); - gc.bg = options_get_number(&wp->window->options, "mode-fg"); - gc.fg = options_get_number(&wp->window->options, "mode-bg"); + gc.fg = options_get_number(&wp->window->options, "mode-fg"); + gc.bg = options_get_number(&wp->window->options, "mode-bg"); gc.attr |= options_get_number(&wp->window->options, "mode-attr"); screen_write_cursormove(ctx, screen_size_x(s) - size, 0); screen_write_puts(ctx, &gc, "%s", hdr); @@ -368,8 +368,8 @@ window_copy_update_selection(struct window_pane *wp) /* Set colours. */ memcpy(&gc, &grid_default_cell, sizeof gc); - gc.bg = options_get_number(&wp->window->options, "mode-fg"); - gc.fg = options_get_number(&wp->window->options, "mode-bg"); + gc.fg = options_get_number(&wp->window->options, "mode-fg"); + gc.bg = options_get_number(&wp->window->options, "mode-bg"); gc.attr |= options_get_number(&wp->window->options, "mode-attr"); /* Find top-left of screen. */ diff --git a/window-more.c b/window-more.c index a3418eb0..9eefd79f 100644 --- a/window-more.c +++ b/window-more.c @@ -176,8 +176,8 @@ window_more_write_line( size = xsnprintf(hdr, sizeof hdr, "[%u/%u]", data->top, ARRAY_LENGTH(&data->list)); screen_write_cursormove(ctx, screen_size_x(s) - size, 0); - gc.bg = options_get_number(&wp->window->options, "mode-fg"); - gc.fg = options_get_number(&wp->window->options, "mode-bg"); + gc.fg = options_get_number(&wp->window->options, "mode-fg"); + gc.bg = options_get_number(&wp->window->options, "mode-bg"); gc.attr |= options_get_number(&wp->window->options, "mode-attr"); screen_write_puts(ctx, &gc, "%s", hdr); memcpy(&gc, &grid_default_cell, sizeof gc); diff --git a/window-scroll.c b/window-scroll.c index 12249fc1..bdb7d559 100644 --- a/window-scroll.c +++ b/window-scroll.c @@ -176,8 +176,8 @@ window_scroll_write_line( memcpy(&gc, &grid_default_cell, sizeof gc); size = xsnprintf(hdr, sizeof hdr, "[%u,%u/%u]", data->ox, data->oy, screen_hsize(&wp->base)); - gc.bg = options_get_number(&wp->window->options, "mode-fg"); - gc.fg = options_get_number(&wp->window->options, "mode-bg"); + gc.fg = options_get_number(&wp->window->options, "mode-fg"); + gc.bg = options_get_number(&wp->window->options, "mode-bg"); gc.attr |= options_get_number(&wp->window->options, "mode-attr"); screen_write_cursormove(ctx, screen_size_x(s) - size, 0); screen_write_puts(ctx, &gc, "%s", hdr); From 4027335fa9dd6f6bdce9191695a39529581bfe2a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 5 Aug 2009 19:05:02 +0000 Subject: [PATCH 0221/1180] Clear the codes array earlier as tty_term_free could be called on error. --- tty-term.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tty-term.c b/tty-term.c index c96bdb12..37826dab 100644 --- a/tty-term.c +++ b/tty-term.c @@ -245,6 +245,7 @@ tty_term_find(char *name, int fd, const char *overrides, char **cause) term->name = xstrdup(name); term->references = 1; term->flags = 0; + memset(&term->codes, 0, sizeof term->codes); SLIST_INSERT_HEAD(&tty_terms, term, entry); /* Set up curses terminal. */ @@ -267,7 +268,6 @@ tty_term_find(char *name, int fd, const char *overrides, char **cause) } /* Fill in codes. */ - memset(&term->codes, 0, sizeof term->codes); for (i = 0; i < NTTYCODE; i++) { ent = &tty_term_codes[i]; From 746fe5832a428ac8d74f17c1d463805e51bee0c3 Mon Sep 17 00:00:00 2001 From: Jason McIntyre Date: Thu, 6 Aug 2009 21:06:35 +0000 Subject: [PATCH 0222/1180] tweak INTRODUCTION; from nicm and myself --- tmux.1 | 52 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 20 deletions(-) diff --git a/tmux.1 b/tmux.1 index 8264c73f..6f73688f 100644 --- a/tmux.1 +++ b/tmux.1 @@ -31,8 +31,9 @@ .Ek .Sh DESCRIPTION .Nm -is a terminal multiplexer: it enables a number of terminals to be accessed and -controlled from a single terminal. +is a terminal multiplexer: +it enables a number of terminals to be created, accessed, and +controlled from a single screen. .Pp The options are as follows: .Bl -tag -width "XXXXXXXXXXXX" @@ -127,30 +128,41 @@ is the PID of the server or client process. This specifies one of a set of commands used to control .Nm , as described in the following sections. -If no command and flags are specified, the +If no commands are specified, the .Ic new-session command is assumed. .El .Sh INTRODUCTION +When .Nm -runs as a server-client system. -A server holds a number of -.Em sessions , -each of which may have a number of -.Em windows -linked to it. -A server is started automatically when the first session is created and exits -when all the sessions it contains are destroyed. -A window may be split on screen into one or more -.Em panes , -each of which is a separate terminal. -Any number of -.Em clients -may connect to a session, or the server -may be controlled by issuing commands with +is started it creates a new +.Em session +with a single +.Em window +and displays it on screen. +A status line at the bottom of the screen +shows information on the current session +and is used to enter interactive commands. +.Pp +A session is a single collection of +.Em pseudo terminals +under the management of .Nm . -Communication takes place through a socket, by default placed in -.Pa /tmp . +Each session has one or more +windows linked to it. +A window occupies the entire screen +and may be split into rectangular panes, +each of which is a separate pseudo terminal +(the +.Xr pty 4 +manual page documents the technical details of pseudo terminals). +Any number of +.Nm +instances may connect to the same session, +and any number of windows may be present in the same session. +Once all sessions are killed, +.Nm +exits. .Pp This is an overview of the sections in this manual page: .Bl -ohang From 04e97e8aefa722b7a0941a70889afc7e50c24035 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 7 Aug 2009 00:12:13 +0000 Subject: [PATCH 0223/1180] Using the alternative screen (smcup/rmcup) should also preserve the current colours and attributes. Found thanks to a report from Taylor Venable. While here also nuke a couple of extra blank lines. --- input.c | 8 +++++--- tmux.h | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/input.c b/input.c index e3bba5d3..4cba6e06 100644 --- a/input.c +++ b/input.c @@ -1189,7 +1189,9 @@ input_handle_sequence_sm(struct input_ctx *ictx) wp->saved_grid, 0, s->grid, screen_hsize(s), sy); wp->saved_cx = s->cx; wp->saved_cy = s->cy; - + memcpy(&wp->saved_cell, + &ictx->cell, sizeof wp->saved_cell); + grid_view_clear(s->grid, 0, 0, sx, sy); wp->base.grid->flags &= ~GRID_HISTORY; @@ -1261,7 +1263,7 @@ input_handle_sequence_rm(struct input_ctx *ictx) if (sy > wp->saved_grid->sy) screen_resize(s, sx, wp->saved_grid->sy); - /* Restore the grid and cursor position. */ + /* Restore the grid, cursor position and cell. */ grid_duplicate_lines( s->grid, screen_hsize(s), wp->saved_grid, 0, sy); s->cx = wp->saved_cx; @@ -1270,6 +1272,7 @@ input_handle_sequence_rm(struct input_ctx *ictx) s->cy = wp->saved_cy; if (s->cy > screen_size_y(s) - 1) s->cy = screen_size_y(s) - 1; + memcpy(&ictx->cell, &wp->saved_cell, sizeof ictx->cell); /* * Turn history back on (so resize can use it) and then @@ -1326,7 +1329,6 @@ input_handle_sequence_dsr(struct input_ctx *ictx) break; } } - } void diff --git a/tmux.h b/tmux.h index 97ac7040..a35e44a4 100644 --- a/tmux.h +++ b/tmux.h @@ -602,7 +602,6 @@ struct input_ctx { struct grid_cell cell; - struct grid_cell saved_cell; u_int saved_cx; u_int saved_cy; @@ -674,6 +673,7 @@ struct window_pane { u_int saved_cx; u_int saved_cy; struct grid *saved_grid; + struct grid_cell saved_cell; const struct window_mode *mode; void *modedata; From ccaf8724e4c5f1909c8eaf62963ded1265a271b2 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 7 Aug 2009 12:24:16 +0000 Subject: [PATCH 0224/1180] Move introduction section up into description. From jmc. --- tmux.1 | 116 +++++++++++++++++++++++++++++---------------------------- 1 file changed, 60 insertions(+), 56 deletions(-) diff --git a/tmux.1 b/tmux.1 index 6f73688f..d8bbcd8c 100644 --- a/tmux.1 +++ b/tmux.1 @@ -35,6 +35,66 @@ is a terminal multiplexer: it enables a number of terminals to be created, accessed, and controlled from a single screen. .Pp +When +.Nm +is started it creates a new +.Em session +with a single +.Em window +and displays it on screen. +A status line at the bottom of the screen +shows information on the current session +and is used to enter interactive commands. +.Pp +A session is a single collection of +.Em pseudo terminals +under the management of +.Nm . +Each session has one or more +windows linked to it. +A window occupies the entire screen +and may be split into rectangular panes, +each of which is a separate pseudo terminal +(the +.Xr pty 4 +manual page documents the technical details of pseudo terminals). +Any number of +.Nm +instances may connect to the same session, +and any number of windows may be present in the same session. +Once all sessions are killed, +.Nm +exits. +.Pp +For a quick start guide, +see the +.Sx EXAMPLES +section at the bottom of the page. +An overview of the sections in this manual page: +.Bl -ohang +.It Sy Commands +An overview of how +.Nm +commands work. +.It Sy Clients and sessions +Commands for managing clients and sessions. +.It Sy Windows and panes +Commands for managing windows and panes. +.It Sy Key bindings +How key bindings work. +.It Sy Options +Configuration options for +.Nm . +.It Sy Status line +Commands pertinent to the status line. +.It Sy Buffers +Copy and paste operations. +.It Sy Miscellaneous +Miscellaneous commands. +.It Sy Examples +A quick start guide. +.El +.Pp The options are as follows: .Bl -tag -width "XXXXXXXXXXXX" .It Fl 2 @@ -132,62 +192,6 @@ If no commands are specified, the .Ic new-session command is assumed. .El -.Sh INTRODUCTION -When -.Nm -is started it creates a new -.Em session -with a single -.Em window -and displays it on screen. -A status line at the bottom of the screen -shows information on the current session -and is used to enter interactive commands. -.Pp -A session is a single collection of -.Em pseudo terminals -under the management of -.Nm . -Each session has one or more -windows linked to it. -A window occupies the entire screen -and may be split into rectangular panes, -each of which is a separate pseudo terminal -(the -.Xr pty 4 -manual page documents the technical details of pseudo terminals). -Any number of -.Nm -instances may connect to the same session, -and any number of windows may be present in the same session. -Once all sessions are killed, -.Nm -exits. -.Pp -This is an overview of the sections in this manual page: -.Bl -ohang -.It Sy Commands -An overview of how -.Nm -commands work. -.It Sy Clients and sessions -Commands for managing clients and sessions. -.It Sy Windows and panes -Commands for managing windows and panes. -.It Sy Key bindings -How key bindings work. -.It Sy Options -Configuration options for -.Nm . -.It Sy Status line -Commands pertinent to the status line. -.It Sy Buffers -Copy and paste operations. -.It Sy Miscellaneous -Miscellaneous commands. -.It Sy Examples -A quick start guide. -.El .Sh COMMANDS This section contains a list of the commands supported by .Nm . From e89e70e71575417195285a3ea55c430654f9fc21 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 7 Aug 2009 15:39:10 +0000 Subject: [PATCH 0225/1180] If there is an error in the configuration file, don't just exit(1) as this can cause the client to hang. Instead, send the error message, then mark the client as bad and start a normal shutdown so the server exits once the error is written. This also allows some code duplicating daemon(3) to be trimmed and logging to begin earlier. Prompted by Theo noticing the behaviour on error wasn't documented. --- server-fn.c | 2 ++ server.c | 85 +++++++++++++++++++++++++++++------------------------ tmux.1 | 4 +++ tmux.h | 1 + 4 files changed, 53 insertions(+), 39 deletions(-) diff --git a/server-fn.c b/server-fn.c index 8a4b1f1d..83ef6ca8 100644 --- a/server-fn.c +++ b/server-fn.c @@ -62,6 +62,8 @@ server_write_client( { struct hdr hdr; + if (c->flags & CLIENT_BAD) + return; log_debug("writing %d to client %d", type, c->fd); hdr.type = type; diff --git a/server.c b/server.c index 668a8251..927cfeb6 100644 --- a/server.c +++ b/server.c @@ -131,9 +131,10 @@ server_client_index(struct client *c) int server_start(char *path) { - int pair[2], srv_fd, null_fd; - char *cause; - char rpathbuf[MAXPATHLEN]; + struct client *c; + int pair[2], srv_fd; + char *cause; + char rpathbuf[MAXPATHLEN]; /* The first client is special and gets a socketpair; create it. */ if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) != 0) @@ -154,9 +155,12 @@ server_start(char *path) * Must daemonise before loading configuration as the PID changes so * $TMUX would be wrong for sessions created in the config file. */ - if (daemon(1, 1) != 0) + if (daemon(1, 0) != 0) fatal("daemon failed"); + logfile("server"); + log_debug("server started, pid %ld", (long) getpid()); + ARRAY_INIT(&windows); ARRAY_INIT(&clients); ARRAY_INIT(&sessions); @@ -171,45 +175,37 @@ server_start(char *path) start_time = time(NULL); socket_path = path; - if (access(SYSTEM_CFG, R_OK) != 0) { - if (errno != ENOENT) { - log_warn("%s", SYSTEM_CFG); - exit(1); - } - } else { - if (load_cfg(SYSTEM_CFG, &cause) != 0) { - log_warnx("%s", cause); - exit(1); - } - } - if (cfg_file != NULL && load_cfg(cfg_file, &cause) != 0) { - log_warnx("%s", cause); - exit(1); - } - logfile("server"); - - /* - * Close stdin/stdout/stderr. Can't let daemon() do this as they are - * needed until now to print configuration file errors. - */ - if ((null_fd = open(_PATH_DEVNULL, O_RDWR)) != -1) { - dup2(null_fd, STDIN_FILENO); - dup2(null_fd, STDOUT_FILENO); - dup2(null_fd, STDERR_FILENO); - if (null_fd > 2) - close(null_fd); - } - - log_debug("server started, pid %ld", (long) getpid()); - log_debug("socket path %s", socket_path); - if (realpath(socket_path, rpathbuf) == NULL) strlcpy(rpathbuf, socket_path, sizeof rpathbuf); + log_debug("socket path %s", socket_path); setproctitle("server (%s)", rpathbuf); srv_fd = server_create_socket(); server_create_client(pair[1]); + if (access(SYSTEM_CFG, R_OK) != 0) { + if (errno != ENOENT) { + xasprintf( + &cause, "%s: %s", strerror(errno), SYSTEM_CFG); + goto error; + } + } else if (load_cfg(SYSTEM_CFG, &cause) != 0) + goto error; + if (cfg_file != NULL && load_cfg(cfg_file, &cause) != 0) + goto error; + + exit(server_main(srv_fd)); + +error: + /* Write the error and shutdown the server. */ + c = ARRAY_FIRST(&clients); + + server_write_error(c, cause); + xfree(cause); + + server_shutdown(); + c->flags |= CLIENT_BAD; + exit(server_main(srv_fd)); } @@ -419,8 +415,13 @@ server_shutdown(void) for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); - if (c != NULL) - server_write_client(c, MSG_SHUTDOWN, NULL, 0); + if (c != NULL) { + if (c->flags & CLIENT_BAD) + server_lost_client(c); + else + server_write_client(c, MSG_SHUTDOWN, NULL, 0); + c->flags |= CLIENT_BAD; + } } } @@ -672,7 +673,8 @@ server_fill_clients(struct pollfd **pfd) (*pfd)->fd = -1; else { (*pfd)->fd = c->fd; - (*pfd)->events = POLLIN; + if (!(c->flags & CLIENT_BAD)) + (*pfd)->events = POLLIN; if (BUFFER_USED(c->out) > 0) (*pfd)->events |= POLLOUT; } @@ -720,6 +722,11 @@ server_handle_clients(struct pollfd **pfd) server_lost_client(c); (*pfd) += 2; continue; + } else if (c->flags & CLIENT_BAD) { + if (BUFFER_USED(c->out) == 0) + server_lost_client(c); + (*pfd) += 2; + continue; } else server_msg_dispatch(c); } diff --git a/tmux.1 b/tmux.1 index d8bbcd8c..48b361ca 100644 --- a/tmux.1 +++ b/tmux.1 @@ -120,6 +120,10 @@ if present, then looks for a user configuration file at The configuration file is a set of .Nm commands which are executed in sequence when the server is first started. +.Pp +If a command in the configuration file fails, +.Nm +will report an error and exit without executing further commands. .It Fl L Ar socket-name .Nm stores the server socket in a directory under diff --git a/tmux.h b/tmux.h index a35e44a4..c2568907 100644 --- a/tmux.h +++ b/tmux.h @@ -900,6 +900,7 @@ struct client { #define CLIENT_STATUS 0x10 #define CLIENT_REPEAT 0x20 /* allow command to repeat within repeat time */ #define CLIENT_SUSPENDED 0x40 +#define CLIENT_BAD 0x80 int flags; char *message_string; From 5e01b6d663abc086847c9bec145edeb9cd91530a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 8 Aug 2009 13:29:27 +0000 Subject: [PATCH 0226/1180] Change the way the grid is stored, previously it was: - a two-dimensional array of cells; - a two-dimensional array of utf8 data; - an array of line lengths. Now it is a single array of a new struct grid_line each of which represents a line and containts the length and an array of cells and an array of utf8 data. This will make it easier to add additional per-line members, such as flags. --- cmd-list-windows.c | 9 +-- cmd-server-info.c | 14 ++-- grid.c | 176 +++++++++++++++++++++------------------------ screen.c | 14 ++-- tmux.h | 15 ++-- tty.c | 4 +- window-copy.c | 2 +- 7 files changed, 111 insertions(+), 123 deletions(-) diff --git a/cmd-list-windows.c b/cmd-list-windows.c index 2e4932c3..e5a45be2 100644 --- a/cmd-list-windows.c +++ b/cmd-list-windows.c @@ -48,6 +48,7 @@ cmd_list_windows_exec(struct cmd *self, struct cmd_ctx *ctx) struct window *w; struct window_pane *wp; struct grid *gd; + struct grid_line *gl; u_int i; unsigned long long size; const char *name; @@ -65,11 +66,11 @@ cmd_list_windows_exec(struct cmd *self, struct cmd_ctx *ctx) size = 0; for (i = 0; i < gd->hsize; i++) { - size += gd->size[i] * sizeof **gd->data; - size += gd->usize[i] * sizeof **gd->udata; + gl = &gd->linedata[i]; + size += gl->cellsize * sizeof *gl->celldata; + size += gl->utf8size * sizeof *gl->utf8data; } - size += gd->hsize * (sizeof *gd->data); - size += gd->hsize * (sizeof *gd->size); + size += gd->hsize * sizeof *gd->linedata; if (wp->fd != -1) name = ttyname(wp->fd); diff --git a/cmd-server-info.c b/cmd-server-info.c index ce038e12..a79f2520 100644 --- a/cmd-server-info.c +++ b/cmd-server-info.c @@ -57,6 +57,7 @@ cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx) struct tty_term_code_entry *ent; struct utsname un; struct grid *gd; + struct grid_line *gl; u_int i, j, k; char out[80]; char *tim; @@ -120,15 +121,16 @@ cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx) lines = ulines = size = usize = 0; gd = wp->base.grid; for (k = 0; k < gd->hsize + gd->sy; k++) { - if (gd->data[k] != NULL) { + gl = &gd->linedata[k]; + if (gl->celldata != NULL) { lines++; - size += gd->size[k] * - sizeof (**gd->data); + size += gl->cellsize * + sizeof *gl->celldata; } - if (gd->udata[k] != NULL) { + if (gl->utf8data != NULL) { ulines++; - usize += gd->usize[k] * - sizeof (**gd->udata); + usize += gl->utf8size * + sizeof *gl->utf8data; } } ctx->print(ctx, "%6u: %s %lu %d %u/%u, %zu " diff --git a/grid.c b/grid.c index 8842371a..abe62fd6 100644 --- a/grid.c +++ b/grid.c @@ -38,10 +38,12 @@ const struct grid_cell grid_default_cell = { 0, 0, 8, 8, ' ' }; #define grid_put_cell(gd, px, py, gc) do { \ - memcpy(&gd->data[py][px], gc, sizeof gd->data[py][px]); \ + memcpy(&gd->linedata[py].celldata[px], \ + gc, sizeof gd->linedata[py].celldata[px]); \ } while (0) #define grid_put_utf8(gd, px, py, gc) do { \ - memcpy(&gd->udata[py][px], gc, sizeof gd->udata[py][px]); \ + memcpy(&gd->linedata[py].utf8data[px], \ + gc, sizeof gd->linedata[py].utf8data[px]); \ } while (0) int grid_check_x(struct grid *, u_int); @@ -100,11 +102,7 @@ grid_create(u_int sx, u_int sy, u_int hlimit) gd->hsize = 0; gd->hlimit = hlimit; - gd->size = xcalloc(gd->sy, sizeof *gd->size); - gd->data = xcalloc(gd->sy, sizeof *gd->data); - - gd->usize = xcalloc(gd->sy, sizeof *gd->usize); - gd->udata = xcalloc(gd->sy, sizeof *gd->udata); + gd->linedata = xcalloc(gd->sy, sizeof *gd->linedata); return (gd); } @@ -113,24 +111,18 @@ grid_create(u_int sx, u_int sy, u_int hlimit) void grid_destroy(struct grid *gd) { - u_int yy; + struct grid_line *gl; + u_int yy; for (yy = 0; yy < gd->hsize + gd->sy; yy++) { - if (gd->udata[yy] != NULL) - xfree(gd->udata[yy]); - if (gd->data[yy] != NULL) - xfree(gd->data[yy]); + gl = &gd->linedata[yy]; + if (gl->celldata != NULL) + xfree(gl->celldata); + if (gl->utf8data != NULL) + xfree(gl->utf8data); } - if (gd->udata != NULL) - xfree(gd->udata); - if (gd->usize != NULL) - xfree(gd->usize); - - if (gd->data != NULL) - xfree(gd->data); - if (gd->size != NULL) - xfree(gd->size); + xfree(gd->linedata); xfree(gd); } @@ -139,6 +131,7 @@ grid_destroy(struct grid *gd) int grid_compare(struct grid *ga, struct grid *gb) { + struct grid_line *gla, *glb; struct grid_cell *gca, *gcb; struct grid_utf8 *gua, *gub; u_int xx, yy; @@ -147,17 +140,19 @@ grid_compare(struct grid *ga, struct grid *gb) return (1); for (yy = 0; yy < ga->sy; yy++) { - if (ga->size[yy] != gb->size[yy]) + gla = &ga->linedata[yy]; + glb = &gb->linedata[yy]; + if (gla->cellsize != glb->cellsize) return (1); for (xx = 0; xx < ga->sx; xx++) { - gca = &ga->data[yy][xx]; - gcb = &gb->data[yy][xx]; + gca = &gla->celldata[xx]; + gcb = &glb->celldata[xx]; if (memcmp(gca, gcb, sizeof (struct grid_cell)) != 0) return (1); if (!(gca->flags & GRID_FLAG_UTF8)) continue; - gua = &ga->udata[yy][xx]; - gub = &gb->udata[yy][xx]; + gua = &gla->utf8data[xx]; + gub = &glb->utf8data[xx]; if (memcmp(gua, gub, sizeof (struct grid_utf8)) != 0) return (1); } @@ -186,15 +181,8 @@ grid_scroll_line(struct grid *gd) yy = gd->hsize + gd->sy; - gd->size = xrealloc(gd->size, yy + 1, sizeof *gd->size); - gd->size[yy] = 0; - gd->data = xrealloc(gd->data, yy + 1, sizeof *gd->data); - gd->data[yy] = NULL; - - gd->usize = xrealloc(gd->usize, yy + 1, sizeof *gd->usize); - gd->usize[yy] = 0; - gd->udata = xrealloc(gd->udata, yy + 1, sizeof *gd->udata); - gd->udata[yy] = NULL; + gd->linedata = xrealloc(gd->linedata, yy + 1, sizeof *gd->linedata); + memset(&gd->linedata[yy], 0, sizeof gd->linedata[yy]); gd->hsize++; } @@ -203,26 +191,31 @@ grid_scroll_line(struct grid *gd) void grid_expand_line(struct grid *gd, u_int py, u_int sx) { - u_int xx; + struct grid_line *gl; + u_int xx; - if (sx <= gd->size[py]) + gl = &gd->linedata[py]; + if (sx <= gl->cellsize) return; - gd->data[py] = xrealloc(gd->data[py], sx, sizeof **gd->data); - for (xx = gd->size[py]; xx < sx; xx++) + gl->celldata = xrealloc(gl->celldata, sx, sizeof *gl->celldata); + for (xx = gl->cellsize; xx < sx; xx++) grid_put_cell(gd, xx, py, &grid_default_cell); - gd->size[py] = sx; + gl->cellsize = sx; } /* Expand line to fit to cell for UTF-8. */ void grid_expand_line_utf8(struct grid *gd, u_int py, u_int sx) { - if (sx <= gd->usize[py]) + struct grid_line *gl; + + gl = &gd->linedata[py]; + if (sx <= gl->utf8size) return; - gd->udata[py] = xrealloc(gd->udata[py], sx, sizeof **gd->udata); - gd->usize[py] = sx; + gl->utf8data = xrealloc(gl->utf8data, sx, sizeof *gl->utf8data); + gl->utf8size = sx; } /* Get cell for reading. */ @@ -234,9 +227,9 @@ grid_peek_cell(struct grid *gd, u_int px, u_int py) if (grid_check_y(gd, py) != 0) return (&grid_default_cell); - if (px >= gd->size[py]) + if (px >= gd->linedata[py].cellsize) return (&grid_default_cell); - return (&gd->data[py][px]); + return (&gd->linedata[py].celldata[px]); } /* Get cell at relative position (for writing). */ @@ -249,7 +242,7 @@ grid_get_cell(struct grid *gd, u_int px, u_int py) return (NULL); grid_expand_line(gd, py, px + 1); - return (&gd->data[py][px]); + return (&gd->linedata[py].celldata[px]); } /* Set cell at relative position. */ @@ -275,9 +268,9 @@ grid_peek_utf8(struct grid *gd, u_int px, u_int py) if (grid_check_y(gd, py) != 0) return (NULL); - if (px >= gd->usize[py]) + if (px >= gd->linedata[py].utf8size) return (NULL); - return (&gd->udata[py][px]); + return (&gd->linedata[py].utf8data[px]); } /* Get utf8 at relative position (for writing). */ @@ -290,7 +283,7 @@ grid_get_utf8(struct grid *gd, u_int px, u_int py) return (NULL); grid_expand_line_utf8(gd, py, px + 1); - return (&gd->udata[py][px]); + return (&gd->linedata[py].utf8data[px]); } /* Set utf8 at relative position. */ @@ -337,7 +330,7 @@ grid_clear(struct grid *gd, u_int px, u_int py, u_int nx, u_int ny) for (yy = py; yy < py + ny; yy++) { for (xx = px; xx < px + nx; xx++) { - if (xx >= gd->size[yy]) + if (xx >= gd->linedata[yy].cellsize) break; grid_put_cell(gd, xx, yy, &grid_default_cell); } @@ -348,7 +341,8 @@ grid_clear(struct grid *gd, u_int px, u_int py, u_int nx, u_int ny) void grid_clear_lines(struct grid *gd, u_int py, u_int ny) { - u_int yy; + struct grid_line *gl; + u_int yy; GRID_DEBUG(gd, "py=%u, ny=%u", py, ny); @@ -361,16 +355,12 @@ grid_clear_lines(struct grid *gd, u_int py, u_int ny) return; for (yy = py; yy < py + ny; yy++) { - if (gd->data[yy] != NULL) { - xfree(gd->data[yy]); - gd->data[yy] = NULL; - gd->size[yy] = 0; - } - if (gd->udata[yy] != NULL) { - xfree(gd->udata[yy]); - gd->udata[yy] = NULL; - gd->usize[yy] = 0; - } + gl = &gd->linedata[yy]; + if (gl->celldata != NULL) + xfree(gl->celldata); + if (gl->utf8data != NULL) + xfree(gl->utf8data); + memset(gl, 0, sizeof *gl); } } @@ -401,20 +391,14 @@ grid_move_lines(struct grid *gd, u_int dy, u_int py, u_int ny) grid_clear_lines(gd, yy, 1); } - memmove(&gd->data[dy], &gd->data[py], ny * (sizeof *gd->data)); - memmove(&gd->size[dy], &gd->size[py], ny * (sizeof *gd->size)); - - memmove(&gd->udata[dy], &gd->udata[py], ny * (sizeof *gd->udata)); - memmove(&gd->usize[dy], &gd->usize[py], ny * (sizeof *gd->usize)); + memmove( + &gd->linedata[dy], &gd->linedata[py], ny * (sizeof *gd->linedata)); /* Wipe any lines that have been moved (without freeing them). */ for (yy = py; yy < py + ny; yy++) { if (yy >= dy && yy < dy + ny) continue; - gd->data[yy] = NULL; - gd->size[yy] = 0; - gd->udata[yy] = NULL; - gd->usize[yy] = 0; + memset(&gd->linedata[yy], 0, sizeof gd->linedata[yy]); } } @@ -422,7 +406,8 @@ grid_move_lines(struct grid *gd, u_int dy, u_int py, u_int ny) void grid_move_cells(struct grid *gd, u_int dx, u_int px, u_int py, u_int nx) { - u_int xx; + struct grid_line *gl; + u_int xx; GRID_DEBUG(gd, "dx=%u, px=%u, py=%u, nx=%u", dx, px, py, nx); @@ -437,16 +422,18 @@ grid_move_cells(struct grid *gd, u_int dx, u_int px, u_int py, u_int nx) return; if (grid_check_y(gd, py) != 0) return; + gl = &gd->linedata[py]; grid_expand_line(gd, py, px + nx); grid_expand_line(gd, py, dx + nx); - memmove(&gd->data[py][dx], &gd->data[py][px], nx * (sizeof **gd->data)); + memmove( + &gl->celldata[dx], &gl->celldata[px], nx * sizeof *gl->celldata); - if (gd->udata[py] != NULL) { + if (gl->utf8data != NULL) { grid_expand_line_utf8(gd, py, px + nx); grid_expand_line_utf8(gd, py, dx + nx); - memmove(&gd->udata[py][dx], - &gd->udata[py][px], nx * (sizeof **gd->udata)); + memmove(&gl->utf8data[dx], + &gl->utf8data[px], nx * sizeof *gl->utf8data); } /* Wipe any cells that have been moved. */ @@ -515,7 +502,8 @@ void grid_duplicate_lines( struct grid *dst, u_int dy, struct grid *src, u_int sy, u_int ny) { - u_int yy; + struct grid_line *dstl, *srcl; + u_int yy; GRID_DEBUG(src, "dy=%u, sy=%u, ny=%u", dy, sy, ny); @@ -526,26 +514,24 @@ grid_duplicate_lines( grid_clear_lines(dst, dy, ny); for (yy = 0; yy < ny; yy++) { - dst->size[dy] = src->size[sy]; - if (src->size[sy] == 0) - dst->data[dy] = NULL; - else { - dst->data[dy] = xcalloc( - src->size[sy], sizeof **dst->data); - memcpy(dst->data[dy], src->data[sy], - src->size[sy] * (sizeof **dst->data)); + srcl = &src->linedata[yy]; + dstl = &dst->linedata[yy]; + + memcpy(dstl, srcl, sizeof *dstl); + if (srcl->cellsize != 0) { + dstl->celldata = xcalloc( + srcl->cellsize, sizeof *dstl->celldata); + memcpy(dstl->celldata, srcl->celldata, + srcl->cellsize * sizeof *dstl->celldata); + } + if (srcl->utf8size != 0) { + dstl->utf8data = xcalloc( + srcl->utf8size, sizeof *dstl->utf8data); + memcpy(dstl->utf8data, srcl->utf8data, + srcl->utf8size * sizeof *dstl->utf8data); } - dst->usize[dy] = src->usize[sy]; - if (src->usize[sy] == 0) - dst->udata[dy] = NULL; - else { - dst->udata[dy] = xcalloc( - src->usize[sy], sizeof **dst->udata); - memcpy(dst->udata[dy], src->udata[sy], - src->usize[sy] * (sizeof **dst->udata)); - } - - sy++; dy++; + sy++; + dy++; } } diff --git a/screen.c b/screen.c index b2bcffa3..bcf52099 100644 --- a/screen.c +++ b/screen.c @@ -194,10 +194,8 @@ screen_resize_y(struct screen *s, u_int sy) } /* Resize line arrays. */ - gd->size = xrealloc(gd->size, gd->hsize + sy, sizeof *gd->size); - gd->data = xrealloc(gd->data, gd->hsize + sy, sizeof *gd->data); - gd->usize = xrealloc(gd->usize, gd->hsize + sy, sizeof *gd->usize); - gd->udata = xrealloc(gd->udata, gd->hsize + sy, sizeof *gd->udata); + gd->linedata = xrealloc( + gd->linedata, gd->hsize + sy, sizeof *gd->linedata); /* Size increasing. */ if (sy > oldy) { @@ -218,12 +216,8 @@ screen_resize_y(struct screen *s, u_int sy) needed -= available; /* Then fill the rest in with blanks. */ - for (i = gd->hsize + sy - needed; i < gd->hsize + sy; i++) { - gd->size[i] = 0; - gd->data[i] = NULL; - gd->usize[i] = 0; - gd->udata[i] = NULL; - } + for (i = gd->hsize + sy - needed; i < gd->hsize + sy; i++) + memset(&gd->linedata[i], 0, sizeof gd->linedata[i]); } /* Set the new size, and reset the scroll region. */ diff --git a/tmux.h b/tmux.h index c2568907..82099e8e 100644 --- a/tmux.h +++ b/tmux.h @@ -500,6 +500,15 @@ struct grid_utf8 { u_char data[UTF8_SIZE]; } __packed; +/* Grid line. */ +struct grid_line { + u_int cellsize; + struct grid_cell *celldata; + + u_int utf8size; + struct grid_utf8 *utf8data; +} __packed; + /* Entire grid of cells. */ struct grid { int flags; @@ -511,11 +520,7 @@ struct grid { u_int hsize; u_int hlimit; - u_int *size; - struct grid_cell **data; - - u_int *usize; - struct grid_utf8 **udata; + struct grid_line *linedata; }; /* Option data structures. */ diff --git a/tty.c b/tty.c index cbdbec8d..33acb99d 100644 --- a/tty.c +++ b/tty.c @@ -486,8 +486,8 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int py, u_int ox, u_int oy) u_int i, sx; sx = screen_size_x(s); - if (sx > s->grid->size[s->grid->hsize + py]) - sx = s->grid->size[s->grid->hsize + py]; + if (sx > s->grid->linedata[s->grid->hsize + py].cellsize) + sx = s->grid->linedata[s->grid->hsize + py].cellsize; if (sx > tty->sx) sx = tty->sx; diff --git a/window-copy.c b/window-copy.c index 7996359d..db1c3506 100644 --- a/window-copy.c +++ b/window-copy.c @@ -537,7 +537,7 @@ window_copy_find_length(struct window_pane *wp, u_int py) * width of the grid, and screen_write_copy treats them as spaces, so * ignore them here too. */ - px = wp->base.grid->size[py]; + px = wp->base.grid->linedata[py].cellsize; if (px > screen_size_x(&wp->base)) px = screen_size_x(&wp->base); while (px > 0) { From 06ddd3dcf8ad5685e7120be93681ee666e4689fc Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 8 Aug 2009 15:57:49 +0000 Subject: [PATCH 0227/1180] Add a flags member to the grid_line struct and use it to differentiate lines wrapped at the screen edge from those terminated by a newline. Then use this when copying to combine wrapped lines together into one. --- input.c | 8 ++++---- screen-write.c | 17 ++++++++++++----- tmux.h | 7 ++++++- window-copy.c | 36 +++++++++++++++++++++++++----------- 4 files changed, 47 insertions(+), 21 deletions(-) diff --git a/input.c b/input.c index 4cba6e06..4cfd3522 100644 --- a/input.c +++ b/input.c @@ -635,7 +635,7 @@ input_handle_c0_control(u_char ch, struct input_ctx *ictx) case '\0': /* NUL */ break; case '\n': /* LF */ - screen_write_linefeed(&ictx->ctx); + screen_write_linefeed(&ictx->ctx, 0); break; case '\r': /* CR */ screen_write_carriagereturn(&ictx->ctx); @@ -659,7 +659,7 @@ input_handle_c0_control(u_char ch, struct input_ctx *ictx) } while (s->cx < screen_size_x(s) - 1); break; case '\013': /* VT */ - screen_write_linefeed(&ictx->ctx); + screen_write_linefeed(&ictx->ctx, 0); break; case '\016': /* SO */ ictx->cell.attr |= GRID_ATTR_CHARSET; @@ -682,11 +682,11 @@ input_handle_c1_control(u_char ch, struct input_ctx *ictx) switch (ch) { case 'D': /* IND */ - screen_write_linefeed(&ictx->ctx); + screen_write_linefeed(&ictx->ctx, 0); break; case 'E': /* NEL */ screen_write_carriagereturn(&ictx->ctx); - screen_write_linefeed(&ictx->ctx); + screen_write_linefeed(&ictx->ctx, 0); break; case 'H': /* HTS */ if (s->cx < screen_size_x(s)) diff --git a/screen-write.c b/screen-write.c index d9b523c4..4e66b076 100644 --- a/screen-write.c +++ b/screen-write.c @@ -610,13 +610,20 @@ screen_write_mousemode(struct screen_write_ctx *ctx, int state) /* Line feed (down with scroll). */ void -screen_write_linefeed(struct screen_write_ctx *ctx) +screen_write_linefeed(struct screen_write_ctx *ctx, int wrapped) { - struct screen *s = ctx->s; - struct tty_ctx ttyctx; + struct screen *s = ctx->s; + struct grid_line *gl; + struct tty_ctx ttyctx; screen_write_initctx(ctx, &ttyctx); + gl = &s->grid->linedata[s->grid->hsize + s->cy]; + if (wrapped) + gl->flags |= GRID_LINE_WRAPPED; + else + gl->flags &= ~GRID_LINE_WRAPPED; + if (s->cy == s->rlower) grid_view_scroll_region_up(s->grid, s->rupper, s->rlower); else if (s->cy < screen_size_y(s) - 1) @@ -782,10 +789,10 @@ screen_write_cell( insert = 1; } - /* Check this will fit on the current line; scroll if not. */ + /* Check this will fit on the current line and wrap if not. */ if (s->cx > screen_size_x(s) - width) { screen_write_carriagereturn(ctx); - screen_write_linefeed(ctx); + screen_write_linefeed(ctx, 1); } /* Sanity checks. */ diff --git a/tmux.h b/tmux.h index 82099e8e..44c169ef 100644 --- a/tmux.h +++ b/tmux.h @@ -484,6 +484,9 @@ struct mode_key_table { #define GRID_FLAG_PADDING 0x4 #define GRID_FLAG_UTF8 0x8 +/* Grid line flags. */ +#define GRID_LINE_WRAPPED 0x1 + /* Grid cell data. */ struct grid_cell { u_char attr; @@ -507,6 +510,8 @@ struct grid_line { u_int utf8size; struct grid_utf8 *utf8data; + + int flags; } __packed; /* Entire grid of cells. */ @@ -1504,7 +1509,7 @@ void screen_write_reverseindex(struct screen_write_ctx *); void screen_write_scrollregion(struct screen_write_ctx *, u_int, u_int); void screen_write_insertmode(struct screen_write_ctx *, int); void screen_write_mousemode(struct screen_write_ctx *, int); -void screen_write_linefeed(struct screen_write_ctx *); +void screen_write_linefeed(struct screen_write_ctx *, int); void screen_write_carriagereturn(struct screen_write_ctx *); void screen_write_kcursormode(struct screen_write_ctx *, int); void screen_write_kkeypadmode(struct screen_write_ctx *, int); diff --git a/window-copy.c b/window-copy.c index db1c3506..06c10d9c 100644 --- a/window-copy.c +++ b/window-copy.c @@ -449,13 +449,11 @@ window_copy_copy_selection(struct window_pane *wp, struct client *c) if (sy == ey) window_copy_copy_line(wp, &buf, &off, sy, sx, ex); else { - xx = window_copy_find_length(wp, sy); + xx = screen_size_x(s); window_copy_copy_line(wp, &buf, &off, sy, sx, xx); if (ey - sy > 1) { - for (i = sy + 1; i < ey; i++) { - xx = window_copy_find_length(wp, i); + for (i = sy + 1; i < ey; i++) window_copy_copy_line(wp, &buf, &off, i, 0, xx); - } } window_copy_copy_line(wp, &buf, &off, ey, 0, ex); } @@ -473,14 +471,28 @@ void window_copy_copy_line(struct window_pane *wp, char **buf, size_t *off, u_int sy, u_int sx, u_int ex) { + struct grid *gd = wp->base.grid; const struct grid_cell *gc; const struct grid_utf8 *gu; - u_int i, j, xx; + struct grid_line *gl; + u_int i, j, xx, wrapped = 0; if (sx > ex) return; - xx = window_copy_find_length(wp, sy); + /* + * Work out if the line was wrapped at the screen edge and all of it is + * on screen. + */ + gl = &gd->linedata[sy]; + if (gl->flags & GRID_LINE_WRAPPED && gl->cellsize <= gd->sx) + wrapped = 1; + + /* If the line was wrapped, don't strip spaces (use the full length). */ + if (wrapped) + xx = gl->cellsize; + else + xx = window_copy_find_length(wp, sy); if (ex > xx) ex = xx; if (sx > xx) @@ -488,14 +500,14 @@ window_copy_copy_line(struct window_pane *wp, if (sx < ex) { for (i = sx; i < ex; i++) { - gc = grid_peek_cell(wp->base.grid, i, sy); + gc = grid_peek_cell(gd, i, sy); if (gc->flags & GRID_FLAG_PADDING) continue; if (!(gc->flags & GRID_FLAG_UTF8)) { *buf = xrealloc(*buf, 1, (*off) + 1); (*buf)[(*off)++] = gc->data; } else { - gu = grid_peek_utf8(wp->base.grid, i, sy); + gu = grid_peek_utf8(gd, i, sy); *buf = xrealloc(*buf, 1, (*off) + UTF8_SIZE); for (j = 0; j < UTF8_SIZE; j++) { if (gu->data[j] == 0xff) @@ -506,9 +518,11 @@ window_copy_copy_line(struct window_pane *wp, } } - *buf = xrealloc(*buf, 1, (*off) + 1); - (*buf)[*off] = '\n'; - (*off)++; + /* Only add a newline if the line wasn't wrapped. */ + if (!wrapped) { + *buf = xrealloc(*buf, 1, (*off) + 1); + (*buf)[(*off)++] = '\n'; + } } int From 92cc3a691499e3c5cc056bb9bf1a543fc09d32aa Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 8 Aug 2009 16:05:01 +0000 Subject: [PATCH 0228/1180] Handle ttyname(3) failure better. --- cmd-list-windows.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmd-list-windows.c b/cmd-list-windows.c index e5a45be2..c2f8bbd1 100644 --- a/cmd-list-windows.c +++ b/cmd-list-windows.c @@ -72,9 +72,10 @@ cmd_list_windows_exec(struct cmd *self, struct cmd_ctx *ctx) } size += gd->hsize * sizeof *gd->linedata; + name = NULL; if (wp->fd != -1) name = ttyname(wp->fd); - else + if (name == NULL) name = "unknown"; ctx->print(ctx, " %s [%ux%u] [history %u/%u, %llu bytes]", From 90f8151ffd21f273be62f364ff841f738a10cee0 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 8 Aug 2009 20:36:42 +0000 Subject: [PATCH 0229/1180] Options to set the colours and attributes for status-left/-right. From Thomas Adam, thanks. --- cmd-set-option.c | 6 ++++++ status.c | 34 +++++++++++++++++++++++++++++++--- tmux.1 | 12 ++++++++++++ tmux.c | 10 ++++++++-- 4 files changed, 57 insertions(+), 5 deletions(-) diff --git a/cmd-set-option.c b/cmd-set-option.c index de6141a1..3f2a2ed2 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -74,8 +74,14 @@ const struct set_option_entry set_option_table[] = { SET_OPTION_CHOICE, 0, 0, set_option_status_justify_list }, { "status-keys", SET_OPTION_CHOICE, 0, 0, set_option_status_keys_list }, { "status-left", SET_OPTION_STRING, 0, 0, NULL }, + { "status-left-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL }, + { "status-left-bg", SET_OPTION_COLOUR, 0, 0, NULL }, + { "status-left-fg", SET_OPTION_COLOUR, 0, 0, NULL }, { "status-left-length", SET_OPTION_NUMBER, 0, SHRT_MAX, NULL }, { "status-right", SET_OPTION_STRING, 0, 0, NULL }, + { "status-right-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL }, + { "status-right-bg", SET_OPTION_COLOUR, 0, 0, NULL }, + { "status-right-fg", SET_OPTION_COLOUR, 0, 0, NULL }, { "status-right-length", SET_OPTION_NUMBER, 0, SHRT_MAX, NULL }, { "status-utf8", SET_OPTION_FLAG, 0, 0, NULL }, { "terminal-overrides", SET_OPTION_STRING, 0, 0, NULL }, diff --git a/status.c b/status.c index 5b625471..47a5d8e4 100644 --- a/status.c +++ b/status.c @@ -47,8 +47,10 @@ status_redraw(struct client *c) char *left, *right, *text, *ptr; size_t llen, llen2, rlen, rlen2, offset; size_t ox, xx, yy, size, start, width; - struct grid_cell stdgc, gc; + struct grid_cell stdgc, sl_stdgc, sr_stdgc, gc; int larrow, rarrow, utf8flag; + int sl_fg, sl_bg, sr_fg, sr_bg; + int sl_attr, sr_attr; left = right = NULL; @@ -68,6 +70,32 @@ status_redraw(struct client *c) stdgc.bg = options_get_number(&s->options, "status-bg"); stdgc.attr |= options_get_number(&s->options, "status-attr"); + /* + * Set the status-left and status-right parts to the default status + * line options and only change them where they differ from the + * defaults. + */ + memcpy(&sl_stdgc, &stdgc, sizeof sl_stdgc); + memcpy(&sr_stdgc, &stdgc, sizeof sr_stdgc); + sl_fg = options_get_number(&s->options, "status-left-fg"); + if (sl_fg != 8) + sl_stdgc.fg = sl_fg; + sl_bg = options_get_number(&s->options, "status-left-bg"); + if (sl_bg != 8) + sl_stdgc.bg = sl_bg; + sl_attr = options_get_number(&s->options, "status-left-attr"); + if (sl_attr != 0) + sl_stdgc.attr = sl_attr; + sr_fg = options_get_number(&s->options, "status-right-fg"); + if (sr_fg != 8) + sr_stdgc.fg = sr_fg; + sr_bg = options_get_number(&s->options, "status-right-bg"); + if (sr_bg != 8) + sr_stdgc.bg = sr_bg; + sr_attr = options_get_number(&s->options, "status-right-attr"); + if (sr_attr != 0) + sr_stdgc.attr = sr_attr; + yy = c->tty.sy - 1; if (yy == 0) goto blank; @@ -164,7 +192,7 @@ draw: screen_write_start(&ctx, NULL, &c->status); if (llen != 0) { screen_write_cursormove(&ctx, 0, yy); - screen_write_nputs(&ctx, llen, &stdgc, utf8flag, "%s", left); + screen_write_nputs(&ctx, llen, &sl_stdgc, utf8flag, "%s", left); screen_write_putc(&ctx, &stdgc, ' '); if (larrow) screen_write_putc(&ctx, &stdgc, ' '); @@ -238,7 +266,7 @@ draw: if (rlen != 0) { screen_write_cursormove(&ctx, c->tty.sx - rlen - 1, yy); screen_write_putc(&ctx, &stdgc, ' '); - screen_write_nputs(&ctx, rlen, &stdgc, utf8flag, "%s", right); + screen_write_nputs(&ctx, rlen, &sr_stdgc, utf8flag, "%s", right); } /* Draw the arrows. */ diff --git a/tmux.1 b/tmux.1 index 48b361ca..58609e12 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1238,6 +1238,12 @@ 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-fg Ar colour +Set the foreground colour 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-length Ar length Set the maximum .Ar length @@ -1256,6 +1262,12 @@ 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-fg Ar colour +Set the foreground colour 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-length Ar length Set the maximum .Ar length diff --git a/tmux.c b/tmux.c index 00a9e8f0..ec2c4d3e 100644 --- a/tmux.c +++ b/tmux.c @@ -359,11 +359,17 @@ main(int argc, char **argv) options_set_number(&global_s_options, "status-interval", 15); options_set_number(&global_s_options, "status-keys", MODEKEY_EMACS); options_set_number(&global_s_options, "status-justify", 0); - options_set_number(&global_s_options, "status-left-length", 10); - options_set_number(&global_s_options, "status-right-length", 40); options_set_string(&global_s_options, "status-left", "[#S]"); + options_set_number(&global_s_options, "status-left-attr", 0); + options_set_number(&global_s_options, "status-left-fg", 8); + options_set_number(&global_s_options, "status-left-bg", 8); + options_set_number(&global_s_options, "status-left-length", 10); options_set_string( &global_s_options, "status-right", "\"#22T\" %%H:%%M %%d-%%b-%%y"); + options_set_number(&global_s_options, "status-right-attr", 0); + options_set_number(&global_s_options, "status-right-fg", 8); + options_set_number(&global_s_options, "status-right-bg", 8); + options_set_number(&global_s_options, "status-right-length", 40); if (flags & IDENTIFY_UTF8) options_set_number(&global_s_options, "status-utf8", 1); else From e9856294408c76f374547d9e74d4292f1b0c1163 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 8 Aug 2009 21:18:23 +0000 Subject: [PATCH 0230/1180] Tidy function a little by using a temporary variable. --- client.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/client.c b/client.c index cb2207dd..829b3d3c 100644 --- a/client.c +++ b/client.c @@ -43,7 +43,7 @@ client_init(char *path, struct client_ctx *cctx, int cmdflags, int flags) struct msg_identify_data data; struct winsize ws; size_t size; - int mode; + int fd, mode; char *name, *term; char rpathbuf[MAXPATHLEN]; @@ -53,7 +53,7 @@ client_init(char *path, struct client_ctx *cctx, int cmdflags, int flags) if (lstat(path, &sb) != 0) { if (cmdflags & CMD_STARTSERVER && errno == ENOENT) { - if ((cctx->srv_fd = server_start(path)) == -1) + if ((fd = server_start(path)) == -1) goto start_failed; goto server_started; } @@ -72,15 +72,14 @@ client_init(char *path, struct client_ctx *cctx, int cmdflags, int flags) goto not_found; } - if ((cctx->srv_fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) + if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) fatal("socket"); - if (connect( - cctx->srv_fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1) { + if (connect(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1) { if (errno == ECONNREFUSED) { if (unlink(path) != 0 || !(cmdflags & CMD_STARTSERVER)) goto not_found; - if ((cctx->srv_fd = server_start(path)) == -1) + if ((fd = server_start(path)) == -1) goto start_failed; goto server_started; } @@ -88,10 +87,11 @@ client_init(char *path, struct client_ctx *cctx, int cmdflags, int flags) } server_started: - if ((mode = fcntl(cctx->srv_fd, F_GETFL)) == -1) + if ((mode = fcntl(fd, F_GETFL)) == -1) fatal("fcntl failed"); - if (fcntl(cctx->srv_fd, F_SETFL, mode|O_NONBLOCK) == -1) + if (fcntl(fd, F_SETFL, mode|O_NONBLOCK) == -1) fatal("fcntl failed"); + cctx->srv_fd = fd; cctx->srv_in = buffer_create(BUFSIZ); cctx->srv_out = buffer_create(BUFSIZ); From 6491274f60c175b89b02b6e4cd0c59b13717e2ec Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 8 Aug 2009 21:52:43 +0000 Subject: [PATCH 0231/1180] Infrastructure and commands to manage the environment for processes started within tmux. There is a global environment, copied from the external environment when the server is started and each sesssion has an (initially empty) session environment which overrides it. New commands set-environment and show-environment manipulate or display the environments. A new session option, update-environment, is a space-separated list of variables which are updated from the external environment into the session environment every time a new session is created - the default is DISPLAY. --- Makefile | 3 +- client.c | 18 ++++- cmd-attach-session.c | 7 +- cmd-new-session.c | 13 +++- cmd-respawn-window.c | 11 ++- cmd-set-environment.c | 88 ++++++++++++++++++++++++ cmd-set-option.c | 1 + cmd-show-environment.c | 67 +++++++++++++++++++ cmd-split-window.c | 11 ++- cmd-string.c | 28 ++++---- cmd.c | 2 + environ.c | 147 +++++++++++++++++++++++++++++++++++++++++ server-fn.c | 21 +++--- server-msg.c | 10 +++ session.c | 22 ++++-- tmux.1 | 66 ++++++++++++++++++ tmux.c | 14 ++-- tmux.h | 46 +++++++++++-- window.c | 37 ++++++++--- 19 files changed, 549 insertions(+), 63 deletions(-) create mode 100644 cmd-set-environment.c create mode 100644 cmd-show-environment.c create mode 100644 environ.c diff --git a/Makefile b/Makefile index ccd472cf..bec2a8bb 100644 --- a/Makefile +++ b/Makefile @@ -25,8 +25,9 @@ SRCS= attributes.c buffer-poll.c buffer.c cfg.c client-fn.c \ cmd-split-window.c cmd-start-server.c cmd-string.c cmd-if-shell.c \ cmd-suspend-client.c cmd-swap-pane.c cmd-swap-window.c \ cmd-switch-client.c cmd-unbind-key.c cmd-unlink-window.c \ + cmd-set-environment.c cmd-show-environment.c \ cmd-up-pane.c cmd-display-message.c cmd.c \ - colour.c grid-view.c grid.c input-keys.c \ + colour.c environ.c grid-view.c grid.c input-keys.c \ input.c key-bindings.c key-string.c layout-set.c layout.c log.c \ mode-key.c names.c options-cmd.c options.c paste.c procname.c \ resize.c screen-redraw.c screen-write.c screen.c server-fn.c \ diff --git a/client.c b/client.c index 829b3d3c..4e756981 100644 --- a/client.c +++ b/client.c @@ -33,6 +33,7 @@ #include "tmux.h" +void client_send_environ(struct client_ctx *); void client_handle_winch(struct client_ctx *); int @@ -95,6 +96,8 @@ server_started: cctx->srv_in = buffer_create(BUFSIZ); cctx->srv_out = buffer_create(BUFSIZ); + if (cmdflags & CMD_SENDENVIRON) + client_send_environ(cctx); if (isatty(STDIN_FILENO)) { if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1) fatal("ioctl(TIOCGWINSZ)"); @@ -133,6 +136,19 @@ not_found: return (1); } +void +client_send_environ(struct client_ctx *cctx) +{ + char **var; + struct msg_environ_data data; + + for (var = environ; *var != NULL; var++) { + if (strlcpy(data.var, *var, sizeof data.var) >= sizeof data.var) + continue; + client_write_server(cctx, MSG_ENVIRON, &data, sizeof data); + } +} + int client_main(struct client_ctx *cctx) { @@ -242,8 +258,8 @@ client_msg_dispatch(struct client_ctx *cctx) if (hdr.size != sizeof printdata) fatalx("bad MSG_PRINT size"); buffer_read(cctx->srv_in, &printdata, sizeof printdata); - printdata.msg[(sizeof printdata.msg) - 1] = '\0'; + printdata.msg[(sizeof printdata.msg) - 1] = '\0'; cctx->errstr = xstrdup(printdata.msg); return (-1); case MSG_EXIT: diff --git a/cmd-attach-session.c b/cmd-attach-session.c index 4604ee27..92be3085 100644 --- a/cmd-attach-session.c +++ b/cmd-attach-session.c @@ -29,7 +29,7 @@ int cmd_attach_session_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_attach_session_entry = { "attach-session", "attach", "[-d] " CMD_TARGET_SESSION_USAGE, - CMD_CANTNEST|CMD_STARTSERVER, CMD_CHFLAG('d'), + CMD_CANTNEST|CMD_STARTSERVER|CMD_SENDENVIRON, CMD_CHFLAG('d'), cmd_target_init, cmd_target_parse, cmd_attach_session_exec, @@ -43,6 +43,7 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx) struct cmd_target_data *data = self->data; struct session *s; struct client *c; + const char *update; char *overrides, *cause; u_int i; @@ -93,6 +94,10 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx) ctx->cmdclient->session = s; server_write_client(ctx->cmdclient, MSG_READY, NULL, 0); + + update = options_get_string(&s->options, "update-environment"); + environ_update(update, &ctx->cmdclient->environ, &s->environ); + server_redraw_client(ctx->cmdclient); } recalculate_sizes(); diff --git a/cmd-new-session.c b/cmd-new-session.c index c1ba6e30..61f18c8f 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -40,7 +40,7 @@ struct cmd_new_session_data { const struct cmd_entry cmd_new_session_entry = { "new-session", "new", "[-d] [-n window-name] [-s session-name] [command]", - CMD_STARTSERVER|CMD_CANTNEST, 0, + CMD_STARTSERVER|CMD_CANTNEST|CMD_SENDENVIRON, 0, cmd_new_session_init, cmd_new_session_parse, cmd_new_session_exec, @@ -108,6 +108,8 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) { struct cmd_new_session_data *data = self->data; struct session *s; + struct environ env; + const char *update; char *overrides, *cmd, *cwd, *cause; int detached; u_int sx, sy; @@ -184,13 +186,20 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) else cmd = options_get_string(&global_s_options, "default-command"); + /* Construct the environment. */ + environ_init(&env); + update = options_get_string(&global_s_options, "update-environment"); + if (ctx->cmdclient != NULL) + environ_update(update, &ctx->cmdclient->environ, &env); + /* Create the new session. */ - s = session_create(data->newname, cmd, cwd, sx, sy, &cause); + s = session_create(data->newname, cmd, cwd, &env, sx, sy, &cause); if (s == NULL) { ctx->error(ctx, "create session failed: %s", cause); xfree(cause); return (-1); } + environ_free(&env); if (data->winname != NULL) { xfree(s->curw->window->name); diff --git a/cmd-respawn-window.c b/cmd-respawn-window.c index 70573929..735c637b 100644 --- a/cmd-respawn-window.c +++ b/cmd-respawn-window.c @@ -47,7 +47,7 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_ctx *ctx) struct window *w; struct window_pane *wp; struct session *s; - const char **env; + struct environ env; char *cause; if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL) @@ -64,7 +64,10 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_ctx *ctx) } } - env = server_fill_environ(s); + environ_init(&env); + environ_copy(&global_environ, &env); + environ_copy(&s->environ, &env); + server_fill_environ(s, &env); wp = TAILQ_FIRST(&w->panes); TAILQ_REMOVE(&w->panes, wp, entry); @@ -72,9 +75,10 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_ctx *ctx) window_destroy_panes(w); TAILQ_INSERT_HEAD(&w->panes, wp, entry); window_pane_resize(wp, w->sx, w->sy); - if (window_pane_spawn(wp, data->arg, NULL, env, &cause) != 0) { + if (window_pane_spawn(wp, data->arg, NULL, &env, &cause) != 0) { ctx->error(ctx, "respawn window failed: %s", cause); xfree(cause); + environ_free(&env); return (-1); } layout_init(w); @@ -84,5 +88,6 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_ctx *ctx) recalculate_sizes(); server_redraw_window(w); + environ_free(&env); return (0); } diff --git a/cmd-set-environment.c b/cmd-set-environment.c new file mode 100644 index 00000000..85399a94 --- /dev/null +++ b/cmd-set-environment.c @@ -0,0 +1,88 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2009 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 "tmux.h" + +/* + * Set an environment variable. + */ + +int cmd_set_environment_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_set_environment_entry = { + "set-environment", "setenv", + "[-gru] " CMD_OPTION_SESSION_USAGE, + 0, CMD_CHFLAG('g')|CMD_CHFLAG('r')|CMD_CHFLAG('u'), + NULL, + cmd_option_parse, + cmd_set_environment_exec, + cmd_option_free, + cmd_option_print +}; + +int +cmd_set_environment_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_option_data *data = self->data; + struct session *s; + struct environ *env; + + if (*data->option == '\0') { + ctx->error(ctx, "empty variable name"); + return (-1); + } + if (strchr(data->option, '=') != NULL) { + ctx->error(ctx, "variable name contains ="); + return (-1); + } + + if (data->chflags & CMD_CHFLAG('g')) + env = &global_environ; + else { + if ((s = cmd_find_session(ctx, data->target)) == NULL) + return (-1); + env = &s->environ; + } + + if (data->chflags & CMD_CHFLAG('u')) { + if (data->value != NULL) { + ctx->error(ctx, "can't specify a value with -u"); + return (-1); + } + environ_unset(env, data->option); + } else if (data->chflags & CMD_CHFLAG('r')) { + if (data->value != NULL) { + ctx->error(ctx, "can't specify a value with -r"); + return (-1); + } + environ_set(env, data->option, NULL); + } else { + if (data->value == NULL) { + ctx->error(ctx, "no value specified"); + return (-1); + } + environ_set(env, data->option, data->value); + } + + return (0); +} diff --git a/cmd-set-option.c b/cmd-set-option.c index 3f2a2ed2..7dad54a6 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -85,6 +85,7 @@ const struct set_option_entry set_option_table[] = { { "status-right-length", SET_OPTION_NUMBER, 0, SHRT_MAX, NULL }, { "status-utf8", SET_OPTION_FLAG, 0, 0, NULL }, { "terminal-overrides", SET_OPTION_STRING, 0, 0, NULL }, + { "update-environment", SET_OPTION_STRING, 0, 0, NULL }, { "visual-activity", SET_OPTION_FLAG, 0, 0, NULL }, { "visual-bell", SET_OPTION_FLAG, 0, 0, NULL }, { "visual-content", SET_OPTION_FLAG, 0, 0, NULL }, diff --git a/cmd-show-environment.c b/cmd-show-environment.c new file mode 100644 index 00000000..6a86ec67 --- /dev/null +++ b/cmd-show-environment.c @@ -0,0 +1,67 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2009 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 "tmux.h" + +/* + * Show environment. + */ + +int cmd_show_environment_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_show_environment_entry = { + "show-environment", "showenv", + "[-g] " CMD_TARGET_SESSION_USAGE, + 0, CMD_CHFLAG('g'), + cmd_target_init, + cmd_target_parse, + cmd_show_environment_exec, + cmd_target_free, + cmd_target_print +}; + +int +cmd_show_environment_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_target_data *data = self->data; + struct session *s; + struct environ *env; + struct environ_entry *envent; + + if (data->chflags & CMD_CHFLAG('g')) + env = &global_environ; + else { + if ((s = cmd_find_session(ctx, data->target)) == NULL) + return (-1); + env = &s->environ; + } + + RB_FOREACH(envent, environ, env) { + if (envent->value != NULL) + ctx->print(ctx, "%s=%s", envent->name, envent->value); + else + ctx->print(ctx, "-%s", envent->name); + } + + return (0); +} diff --git a/cmd-split-window.c b/cmd-split-window.c index b483cdd4..70004a14 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -149,7 +149,7 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) struct winlink *wl; struct window *w; struct window_pane *wp; - const char **env; + struct environ env; char *cmd, *cwd, *cause; u_int hlimit; int size; @@ -159,7 +159,10 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) return (-1); w = wl->window; - env = server_fill_environ(s); + environ_init(&env); + environ_copy(&global_environ, &env); + environ_copy(&s->environ, &env); + server_fill_environ(s, &env); cmd = data->cmd; if (cmd == NULL) @@ -181,7 +184,7 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) type = LAYOUT_LEFTRIGHT; wp = window_add_pane(w, hlimit); - if (window_pane_spawn(wp, cmd, cwd, env, &cause) != 0) + if (window_pane_spawn(wp, cmd, cwd, &env, &cause) != 0) goto error; if (layout_split_pane(w->active, type, size, wp) != 0) { cause = xstrdup("pane too small"); @@ -197,9 +200,11 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) } else server_status_session(s); + environ_free(&env); return (0); error: + environ_free(&env); if (wp != NULL) window_remove_pane(w, wp); ctx->error(ctx, "create pane failed: %s", cause); diff --git a/cmd-string.c b/cmd-string.c index c12ac1d7..41b20948 100644 --- a/cmd-string.c +++ b/cmd-string.c @@ -59,21 +59,11 @@ int cmd_string_parse(const char *s, struct cmd_list **cmdlist, char **cause) { size_t p; - int ch, argc, rval, have_arg; - char **argv, *buf, *t, *u; + int ch, i, argc, rval, have_arg; + char **argv, *buf, *t; + const char *whitespace, *equals; size_t len; - if ((t = strchr(s, ' ')) == NULL && (t = strchr(s, '\t')) == NULL) - t = strchr(s, '\0'); - if ((u = strchr(s, '=')) != NULL && u < t) { - if (putenv(xstrdup(s)) != 0) { - xasprintf(cause, "assignment failed: %s", s); - return (-1); - } - *cmdlist = NULL; - return (0); - } - argv = NULL; argc = 0; @@ -147,6 +137,18 @@ cmd_string_parse(const char *s, struct cmd_list **cmdlist, char **cause) if (argc == 0) goto out; + for (i = 0; i < argc; i++) { + equals = strchr(argv[i], '='); + whitespace = argv[i] + strcspn(argv[i], " \t"); + if (equals == NULL || equals > whitespace) + break; + environ_put(&global_environ, argv[i]); + memmove(&argv[i], &argv[i + 1], argc - i - 1); + argc--; + } + if (argc == 0) + goto out; + *cmdlist = cmd_list_parse(argc, argv, cause); if (*cmdlist == NULL) goto out; diff --git a/cmd.c b/cmd.c index 31b80b50..b0f785f9 100644 --- a/cmd.c +++ b/cmd.c @@ -84,10 +84,12 @@ const struct cmd_entry *cmd_table[] = { &cmd_send_prefix_entry, &cmd_server_info_entry, &cmd_set_buffer_entry, + &cmd_set_environment_entry, &cmd_set_option_entry, &cmd_set_password_entry, &cmd_set_window_option_entry, &cmd_show_buffer_entry, + &cmd_show_environment_entry, &cmd_show_options_entry, &cmd_show_window_options_entry, &cmd_source_file_entry, diff --git a/environ.c b/environ.c new file mode 100644 index 00000000..e9f95742 --- /dev/null +++ b/environ.c @@ -0,0 +1,147 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2009 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 "tmux.h" + +/* + * Environment - manipulate a set of environment variables. + */ + +RB_GENERATE(environ, environ_entry, entry, environ_cmp); + +void environ_set1(struct environ *, char *, char *); + +int +environ_cmp(struct environ_entry *envent1, struct environ_entry *envent2) +{ + return (strcmp(envent1->name, envent2->name)); +} + +void +environ_init(struct environ *env) +{ + RB_INIT(env); +} + +void +environ_free(struct environ *env) +{ + struct environ_entry *envent; + + while (!RB_EMPTY(env)) { + envent = RB_ROOT(env); + RB_REMOVE(environ, env, envent); + xfree(envent->name); + if (envent->value != NULL) + xfree(envent->value); + xfree(envent); + } +} + +void +environ_copy(struct environ *srcenv, struct environ *dstenv) +{ + struct environ_entry *envent; + + RB_FOREACH(envent, environ, srcenv) + environ_set(dstenv, envent->name, envent->value); +} + +struct environ_entry * +environ_find(struct environ *env, const char *name) +{ + struct environ_entry envent; + + envent.name = (char *) name; + return (RB_FIND(environ, env, &envent)); +} + +void +environ_set(struct environ *env, const char *name, const char *value) +{ + struct environ_entry *envent; + + if ((envent = environ_find(env, name)) != NULL) { + if (envent->value != NULL) + xfree(envent->value); + if (value != NULL) + envent->value = xstrdup(value); + else + envent->value = NULL; + } else { + envent = xmalloc(sizeof *envent); + envent->name = xstrdup(name); + if (value != NULL) + envent->value = xstrdup(value); + else + envent->value = NULL; + RB_INSERT(environ, env, envent); + } +} + +void +environ_put(struct environ *env, const char *var) +{ + char *name, *value; + + value = strchr(var, '='); + if (value == NULL) + return; + value++; + + name = xstrdup(var); + name[strcspn(name, "=")] = '\0'; + + environ_set(env, name, value); + xfree(name); +} + +void +environ_unset(struct environ *env, const char *name) +{ + struct environ_entry *envent; + + if ((envent = environ_find(env, name)) == NULL) + return; + RB_REMOVE(environ, env, envent); + xfree(envent->name); + if (envent->value != NULL) + xfree(envent->value); + xfree(envent); +} + +void +environ_update(const char *vars, struct environ *srcenv, struct environ *dstenv) +{ + struct environ_entry *envent; + char *var, *next; + + vars = next = xstrdup(vars); + while ((var = strsep(&next, " ")) != NULL) { + if ((envent = environ_find(srcenv, var)) == NULL) + environ_set(dstenv, var, NULL); + else + environ_set(dstenv, envent->name, envent->value); + } + xfree(vars); +} diff --git a/server-fn.c b/server-fn.c index 83ef6ca8..6f6ed2c8 100644 --- a/server-fn.c +++ b/server-fn.c @@ -26,25 +26,20 @@ int server_lock_callback(void *, const char *); -const char ** -server_fill_environ(struct session *s) +void +server_fill_environ(struct session *s, struct environ *env) { - static const char *env[] = { NULL /* TMUX= */, NULL /* TERM */, NULL }; - static char tmuxvar[MAXPATHLEN + 256], termvar[256]; - u_int idx; + char tmuxvar[MAXPATHLEN], *term; + u_int idx; if (session_index(s, &idx) != 0) fatalx("session not found"); - xsnprintf(tmuxvar, sizeof tmuxvar, - "TMUX=%s,%ld,%u", socket_path, (long) getpid(), idx); - env[0] = tmuxvar; + "%s,%ld,%u", socket_path, (long) getpid(), idx); + environ_set(env, "TMUX", tmuxvar); - xsnprintf(termvar, sizeof termvar, - "TERM=%s", options_get_string(&s->options, "default-terminal")); - env[1] = termvar; - - return (env); + term = options_get_string(&s->options, "default-terminal"); + environ_set(env, "TERM", term); } void diff --git a/server-msg.c b/server-msg.c index 2ee357ed..b23ec4c4 100644 --- a/server-msg.c +++ b/server-msg.c @@ -42,6 +42,7 @@ server_msg_dispatch(struct client *c) struct msg_identify_data identifydata; struct msg_resize_data resizedata; struct msg_unlock_data unlockdata; + struct msg_environ_data environdata; for (;;) { if (BUFFER_USED(c->in) < sizeof hdr) @@ -100,6 +101,15 @@ server_msg_dispatch(struct client *c) tty_start_tty(&c->tty); server_redraw_client(c); break; + case MSG_ENVIRON: + if (hdr.size != sizeof environdata) + fatalx("bad MSG_ENVIRON size"); + buffer_read(c->in, &environdata, sizeof environdata); + + environdata.var[(sizeof environdata.var) - 1] = '\0'; + if (strchr(environdata.var, '=') != NULL) + environ_put(&c->environ, environdata.var); + break; default: fatalx("unexpected message"); } diff --git a/session.c b/session.c index 6bf2a3ea..f53e14da 100644 --- a/session.c +++ b/session.c @@ -112,8 +112,8 @@ session_find(const char *name) /* Create a new session. */ struct session * -session_create(const char *name, - const char *cmd, const char *cwd, u_int sx, u_int sy, char **cause) +session_create(const char *name, const char *cmd, const char *cwd, + struct environ *env, u_int sx, u_int sy, char **cause) { struct session *s; u_int i; @@ -128,6 +128,9 @@ session_create(const char *name, SLIST_INIT(&s->alerts); paste_init_stack(&s->buffers); options_init(&s->options, &global_s_options); + environ_init(&s->environ); + if (env != NULL) + environ_copy(env, &s->environ); s->sx = sx; s->sy = sy; @@ -171,6 +174,7 @@ session_destroy(struct session *s) ARRAY_TRUNC(&sessions, 1); session_alert_cancel(s, NULL); + environ_free(&s->environ); options_free(&s->options); paste_free_stack(&s->buffers); @@ -200,15 +204,21 @@ session_new(struct session *s, const char *name, const char *cmd, const char *cwd, int idx, char **cause) { struct window *w; - const char **env; + struct environ env; u_int hlimit; - env = server_fill_environ(s); + environ_init(&env); + environ_copy(&global_environ, &env); + environ_copy(&s->environ, &env); + server_fill_environ(s, &env); hlimit = options_get_number(&s->options, "history-limit"); - w = window_create(name, cmd, cwd, env, s->sx, s->sy, hlimit, cause); - if (w == NULL) + w = window_create(name, cmd, cwd, &env, s->sx, s->sy, hlimit, cause); + if (w == NULL) { + environ_free(&env); return (NULL); + } + environ_free(&env); if (options_get_number(&s->options, "set-remain-on-exit")) options_set_number(&w->options, "remain-on-exit", 1); diff --git a/tmux.1 b/tmux.1 index 58609e12..1aebdbaf 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1321,6 +1321,18 @@ entry for terminals which support 88 or 256 colours: .Bd -literal -offset indent "*88col*:colors=88,*256col*:colors=256" .Ed +.It Ic update-environment Ar variables +Set a space-separated string containing a list of environment variables to be +copied into the session environment when a new session is created or an +existing session is attached. +Any variables that do not exist in the source environment are set to be +removed from the session environment (as if +.Fl r +was given to the +.Ic set-environment +command). +The default is +.Ev DISPLAY . .It Xo Ic visual-activity .Op Ic on | off .Xc @@ -1525,6 +1537,60 @@ or the global window options if .Fl g is used. .El +.Sh ENVIRONMENT +When the server is started, +.Nm +copies the environment into the +.Em global environment ; +in addition, each session has a +.Em session environment . +When a window is created, the session and global environments are merged with +the session environment overriding any variable present in both. +This is the initial environment passed to the new process. +.Pp +The +.Ic update-environment +session option may be used to update the session environment from the client +when a new session is created or an old reattached. +.Nm +also initialises the +.Ev TMUX +variable with some internal information to allow commands to be executed +from inside, and the +.Ev TERM +variable with the correct terminal setting of +.Ql screen . +.Pp +Commands to alter and view the environment are: +.Bl -tag -width Ds +.It Xo Ic set-environment +.Op Fl gru +.Op Fl t Ar target-session +.Ar name Op Ar value +.Xc +Set or unset an environment variable. +If +.Fl g +is used, the change is made in the global environment; otherwise, it is applied +to the session environment for +.Ar target-session . +The +.Fl u +flag unsets a variable. +.Fl r +indicates the variable is to be removed from the environment before starting a +new process. +.It Xo Ic show-environment +.Op Fl g +.Op Fl t Ar target-session +.Xc +Display the environment for +.Ar target-session +or the global environment with +.Fl g . +Variables removed from the environment are prefixed with +.Ql - . +.El .Sh STATUS LINE .Nm includes an optional status line which is displayed in the bottom line of each diff --git a/tmux.c b/tmux.c index ec2c4d3e..72ea52b3 100644 --- a/tmux.c +++ b/tmux.c @@ -44,6 +44,7 @@ volatile sig_atomic_t sigusr2; char *cfg_file; struct options global_s_options; /* session options */ struct options global_w_options; /* window options */ +struct environ global_environ; int server_locked; u_int password_failures; @@ -262,7 +263,7 @@ main(int argc, char **argv) struct hdr hdr; struct passwd *pw; struct msg_print_data printdata; - char *s, *path, *label, *home, *cause; + char *s, *path, *label, *home, *cause, **var; char cwd[MAXPATHLEN]; void *buf; size_t len; @@ -320,6 +321,10 @@ main(int argc, char **argv) log_open_tty(debug_level); siginit(); + environ_init(&global_environ); + for (var = environ; *var != NULL; var++) + environ_put(&global_environ, *var); + if (!(flags & IDENTIFY_UTF8)) { /* * If the user has set whichever of LC_ALL, LC_CTYPE or LANG @@ -376,6 +381,7 @@ main(int argc, char **argv) options_set_number(&global_s_options, "status-utf8", 0); options_set_string(&global_s_options, "terminal-overrides", "*88col*:colors=88,*256col*:colors=256"); + options_set_string(&global_s_options, "update-environment", "DISPLAY"); options_set_number(&global_s_options, "visual-activity", 0); options_set_number(&global_s_options, "visual-bell", 0); options_set_number(&global_s_options, "visual-content", 0); @@ -469,10 +475,10 @@ main(int argc, char **argv) } cmdflags &= ~CMD_STARTSERVER; TAILQ_FOREACH(cmd, cmdlist, qentry) { - if (cmd->entry->flags & CMD_STARTSERVER) { + if (cmd->entry->flags & CMD_STARTSERVER) cmdflags |= CMD_STARTSERVER; - break; - } + if (cmd->entry->flags & CMD_SENDENVIRON) + cmdflags |= CMD_SENDENVIRON; } cmd_list_free(cmdlist); } diff --git a/tmux.h b/tmux.h index 44c169ef..96e2bf76 100644 --- a/tmux.h +++ b/tmux.h @@ -39,6 +39,7 @@ #include "array.h" extern char *__progname; +extern char **environ; /* Default configuration files. */ #define DEFAULT_CFG ".tmux.conf" @@ -69,6 +70,7 @@ extern char *__progname; #define COMMAND_LENGTH 2048 /* packed argv size */ #define TERMINAL_LENGTH 128 /* length of TERM environment variable */ #define PRINT_LENGTH 512 /* printed error/message size */ +#define ENVIRON_LENGTH 1024 /* environment variable length */ /* Fatal errors. */ #define fatal(msg) log_fatal("%s: %s", __func__, msg); @@ -302,6 +304,7 @@ enum msgtype { MSG_SUSPEND, MSG_UNLOCK, MSG_WAKEUP, + MSG_ENVIRON }; /* @@ -356,6 +359,10 @@ struct msg_unlock_data { char pass[PASS_MAX]; }; +struct msg_environ_data { + char var[ENVIRON_LENGTH]; +}; + /* Mode key commands. */ enum mode_key_cmd { MODEKEY_NONE, @@ -765,6 +772,15 @@ struct paste_buffer { }; ARRAY_DECL(paste_stack, struct paste_buffer *); +/* Environment variable. */ +struct environ_entry { + char *name; + char *value; + + RB_ENTRY(environ_entry) entry; +}; +RB_HEAD(environ, environ_entry); + /* Client session. */ struct session_alert { struct winlink *wl; @@ -792,6 +808,8 @@ struct session { #define SESSION_UNATTACHED 0x1 /* not attached to any clients */ int flags; + + struct environ environ; }; ARRAY_DECL(sessions, struct session *); @@ -894,6 +912,8 @@ struct client { struct buffer *in; struct buffer *out; + struct environ environ; + char *title; char *cwd; @@ -992,6 +1012,7 @@ struct cmd_entry { #define CMD_CANTNEST 0x2 #define CMD_ARG1 0x4 #define CMD_ARG01 0x8 +#define CMD_SENDENVIRON 0x10 int flags; #define CMD_CHFLAG(flag) \ @@ -1074,6 +1095,7 @@ extern volatile sig_atomic_t sigusr1; extern volatile sig_atomic_t sigusr2; extern struct options global_s_options; extern struct options global_w_options; +extern struct environ global_environ; extern char *cfg_file; extern int server_locked; extern u_int password_failures; @@ -1123,6 +1145,18 @@ char *options_get_string(struct options *, const char *); void options_set_number(struct options *, const char *, long long); long long options_get_number(struct options *, const char *); +/* environ.c */ +int environ_cmp(struct environ_entry *, struct environ_entry *); +RB_PROTOTYPE(environ, environ_entry, entry, environ_cmp); +void environ_init(struct environ *); +void environ_free(struct environ *); +void environ_copy(struct environ *, struct environ *); +struct environ_entry *environ_find(struct environ *, const char *); +void environ_set(struct environ *, const char *, const char *); +void environ_put(struct environ *, const char *); +void environ_unset(struct environ *, const char *); +void environ_update(const char *, struct environ *, struct environ *); + /* tty.c */ u_char tty_get_acs(struct tty *, u_char); void tty_reset(struct tty *); @@ -1285,10 +1319,12 @@ extern const struct cmd_entry cmd_send_keys_entry; extern const struct cmd_entry cmd_send_prefix_entry; extern const struct cmd_entry cmd_server_info_entry; extern const struct cmd_entry cmd_set_buffer_entry; +extern const struct cmd_entry cmd_set_environment_entry; extern const struct cmd_entry cmd_set_option_entry; extern const struct cmd_entry cmd_set_password_entry; extern const struct cmd_entry cmd_set_window_option_entry; extern const struct cmd_entry cmd_show_buffer_entry; +extern const struct cmd_entry cmd_show_environment_entry; extern const struct cmd_entry cmd_show_options_entry; extern const struct cmd_entry cmd_show_window_options_entry; extern const struct cmd_entry cmd_source_file_entry; @@ -1384,7 +1420,7 @@ int server_start(char *); int server_msg_dispatch(struct client *); /* server-fn.c */ -const char **server_fill_environ(struct session *); +void server_fill_environ(struct session *, struct environ *); void server_write_error(struct client *, const char *); void server_write_client( struct client *, enum msgtype, const void *, size_t); @@ -1554,8 +1590,8 @@ void winlink_stack_push(struct winlink_stack *, struct winlink *); void winlink_stack_remove(struct winlink_stack *, struct winlink *); int window_index(struct window *, u_int *); struct window *window_create1(u_int, u_int); -struct window *window_create(const char *, const char *, - const char *, const char **, u_int, u_int, u_int, char **); +struct window *window_create(const char *, const char *, const char *, + struct environ *, u_int, u_int, u_int, char **); void window_destroy(struct window *); void window_set_active_pane(struct window *, struct window_pane *); struct window_pane *window_add_pane(struct window *, u_int); @@ -1568,7 +1604,7 @@ void window_destroy_panes(struct window *); struct window_pane *window_pane_create(struct window *, u_int, u_int, u_int); void window_pane_destroy(struct window_pane *); int window_pane_spawn(struct window_pane *, - const char *, const char *, const char **, char **); + const char *, const char *, struct environ *, char **); void window_pane_resize(struct window_pane *, u_int, u_int); int window_pane_set_mode( struct window_pane *, const struct window_mode *); @@ -1648,7 +1684,7 @@ int session_alert_has(struct session *, struct winlink *, int); int session_alert_has_window(struct session *, struct window *, int); struct session *session_find(const char *); struct session *session_create(const char *, const char *, - const char *, u_int, u_int, char **); + const char *, struct environ *, u_int, u_int, char **); void session_destroy(struct session *); int session_index(struct session *, u_int *); struct winlink *session_new(struct session *, diff --git a/window.c b/window.c index d1f92920..3976d7cc 100644 --- a/window.c +++ b/window.c @@ -254,7 +254,7 @@ window_create1(u_int sx, u_int sy) struct window * window_create(const char *name, const char *cmd, const char *cwd, - const char **envp, u_int sx, u_int sy, u_int hlimit, char **cause) + struct environ *env, u_int sx, u_int sy, u_int hlimit, char **cause) { struct window *w; struct window_pane *wp; @@ -262,7 +262,7 @@ window_create(const char *name, const char *cmd, const char *cwd, w = window_create1(sx, sy); wp = window_add_pane(w, hlimit); layout_init(w); - if (window_pane_spawn(wp, cmd, cwd, envp, cause) != 0) { + if (window_pane_spawn(wp, cmd, cwd, env, cause) != 0) { window_destroy(w); return (NULL); } @@ -456,13 +456,16 @@ window_pane_destroy(struct window_pane *wp) int window_pane_spawn(struct window_pane *wp, - const char *cmd, const char *cwd, const char **envp, char **cause) + const char *cmd, const char *cwd, struct environ *env, char **cause) { - struct winsize ws; - int mode; - const char **envq, *ptr; - char *argv0; - struct timeval tv; + struct winsize ws; + int mode; + char *argv0, **varp, *var; + ARRAY_DECL(, char *) varlist; + struct environ_entry *envent; + const char *ptr; + struct timeval tv; + u_int i; if (wp->fd != -1) close(wp->fd); @@ -495,10 +498,22 @@ window_pane_spawn(struct window_pane *wp, case 0: if (chdir(wp->cwd) != 0) chdir("/"); - for (envq = envp; *envq != NULL; envq++) { - if (putenv(xstrdup(*envq)) != 0) - fatal("putenv failed"); + + ARRAY_INIT(&varlist); + for (varp = environ; *varp != NULL; varp++) { + var = xstrdup(*varp); + var[strcspn(var, "=")] = '\0'; + ARRAY_ADD(&varlist, var); } + for (i = 0; i < ARRAY_LENGTH(&varlist); i++) { + var = ARRAY_ITEM(&varlist, i); + unsetenv(var); + } + RB_FOREACH(envent, environ, env) { + if (envent->value != NULL) + setenv(envent->name, envent->value, 1); + } + sigreset(); log_close(); From 05f1680efaae84222a88f8fdeed34e72a5085b42 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 8 Aug 2009 21:54:26 +0000 Subject: [PATCH 0232/1180] Use a temporary variable for strdup of const char *. --- environ.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/environ.c b/environ.c index e9f95742..10a66340 100644 --- a/environ.c +++ b/environ.c @@ -134,14 +134,14 @@ void environ_update(const char *vars, struct environ *srcenv, struct environ *dstenv) { struct environ_entry *envent; - char *var, *next; + char *copyvars, *var, *next; - vars = next = xstrdup(vars); + copyvars = next = xstrdup(vars); while ((var = strsep(&next, " ")) != NULL) { if ((envent = environ_find(srcenv, var)) == NULL) environ_set(dstenv, var, NULL); else environ_set(dstenv, envent->name, envent->value); } - xfree(vars); + xfree(copyvars); } From b3107d26dfdabaeaffa558db40e69962e7c697f6 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 9 Aug 2009 08:34:17 +0000 Subject: [PATCH 0233/1180] Don't leak in the (rare) case of an invalid command at the end of a file not terminated by a \n. --- cfg.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cfg.c b/cfg.c index 6320641e..75390165 100644 --- a/cfg.c +++ b/cfg.c @@ -112,6 +112,8 @@ load_cfg(const char *path, char **cause) return (0); error: + if (line != NULL) + xfree(line); fclose(f); xasprintf(&ptr, "%s: %s at line %u", path, *cause, n); From 57381aa5608f7e70a8c7ef4fa0dda557aa433b18 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 9 Aug 2009 14:35:15 +0000 Subject: [PATCH 0234/1180] Move the key bindings section to near the start, mention attach/detach in the first section, and another couple of tweaks. Based on a diff from Theo. --- tmux.1 | 124 ++++++++++++++++++++++++++++----------------------------- 1 file changed, 60 insertions(+), 64 deletions(-) diff --git a/tmux.1 b/tmux.1 index 1aebdbaf..15b8600c 100644 --- a/tmux.1 +++ b/tmux.1 @@ -34,6 +34,8 @@ is a terminal multiplexer: it enables a number of terminals to be created, accessed, and controlled from a single screen. +Programs may be detached from the screen, continue running in the background, +and be reattached to the same or a different screen. .Pp When .Nm @@ -66,35 +68,26 @@ Once all sessions are killed, .Nm exits. .Pp -For a quick start guide, -see the -.Sx EXAMPLES -section at the bottom of the page. -An overview of the sections in this manual page: -.Bl -ohang -.It Sy Commands -An overview of how +Each session is persistent and will survive accidental disconnection +(such as +.Xr ssh 1 +connection timeout) or intentional detachment (with the +.Ql C-b d +key strokes). .Nm -commands work. -.It Sy Clients and sessions -Commands for managing clients and sessions. -.It Sy Windows and panes -Commands for managing windows and panes. -.It Sy Key bindings -How key bindings work. -.It Sy Options -Configuration options for -.Nm . -.It Sy Status line -Commands pertinent to the status line. -.It Sy Buffers -Copy and paste operations. -.It Sy Miscellaneous -Miscellaneous commands. -.It Sy Examples -A quick start guide. -.El +may be reattached using: .Pp +.Dl $ tmux attach +.Pp +In +.Nm , +a session is displayed on screen by a +.Em client +and all sessions are managed by a single +.Em server . +The server and each client are separate processes which communicate through a +socket in +.Pa /tmp . The options are as follows: .Bl -tag -width "XXXXXXXXXXXX" .It Fl 2 @@ -196,6 +189,43 @@ If no commands are specified, the .Ic new-session command is assumed. .El +.Sh KEY BINDINGS +.Nm +may be controlled from an attached client by using a key combination of a +prefix key, +.Ql C-b +(Ctrl-b) by default, followed by a command key. +.Pp +Some of the default key bindings are: +.Pp +.Bl -tag -width Ds -offset 3n -compact +.It c +Create new window. +.It d +Detach current client. +.It l +Move to last (previously selected) window in the current session. +.It n +Change to next window in the current session. +.It p +Change to previous window in the current session. +.It t +Display a large clock. +.It \&? +List current key bindings. +.El +.Pp +A complete list may be obtained with the +.Ic list-keys +command (bound to +.Ql \&? +by default). +Key bindings may be changed with the +.Ic bind-key +and +.Ic unbind-key +commands. +.Pp .Sh COMMANDS This section contains a list of the commands supported by .Nm . @@ -854,42 +884,6 @@ destroyed. Move up a pane. .El .Sh KEY BINDINGS -.Nm -may be controlled from an attached client by using a key combination of a -prefix key, -.Ql C-b -(Ctrl-b) by default, followed by a command key. -.Pp -Some of the default key bindings include: -.Pp -.Bl -tag -width Ds -offset 3n -compact -.It c -Create new window. -.It d -Detach current client. -.It l -Move to last (previously selected) window in the current session. -.It n -Change to next window in the current session. -.It p -Change to previous window in the current session. -.It t -Display a large clock. -.It \&? -List current key bindings. -.El -.Pp -A complete list may be obtained with the -.Ic list-keys -command (bound to -.Ql \&? -by default). -Key bindings may be changed with the -.Ic bind-key -and -.Ic unbind-key -commands. -.Pp Commands related to key bindings are as follows: .Bl -tag -width Ds .It Xo Ic bind-key @@ -1871,7 +1865,9 @@ to select the previous window. .Pp A session may be detached using .Ql C-b d -and reattached with: +(or by an external event such as +.Xr ssh 1 +disconnection) and reattached with: .Pp .Dl $ tmux attach-session .Pp From ad18e45206ad897cb331a971d39c1b78fdcb11e7 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 9 Aug 2009 15:17:50 +0000 Subject: [PATCH 0235/1180] Nuke a dead variable found with clang and an unused declaration with lint. --- environ.c | 2 -- procname.c | 3 +-- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/environ.c b/environ.c index 10a66340..353b84fa 100644 --- a/environ.c +++ b/environ.c @@ -29,8 +29,6 @@ RB_GENERATE(environ, environ_entry, entry, environ_cmp); -void environ_set1(struct environ *, char *, char *); - int environ_cmp(struct environ_entry *envent1, struct environ_entry *envent2) { diff --git a/procname.c b/procname.c index 61f3a46f..85d5212e 100644 --- a/procname.c +++ b/procname.c @@ -91,7 +91,7 @@ get_proc_name(int fd, char *tty) struct stat sb; size_t len; struct kinfo_proc *buf, *newbuf; - struct proc *p, *bestp; + struct proc *bestp; u_int i; char *name; @@ -121,7 +121,6 @@ retry: for (i = 0; i < len / sizeof (struct kinfo_proc); i++) { if (buf[i].kp_eproc.e_tdev != sb.st_rdev) continue; - p = &buf[i].kp_proc; if (bestp == NULL) bestp = &buf[i].kp_proc; else From d7de29e1e5fe24fde203e2ef8e507dc6b3cb00e8 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 9 Aug 2009 15:25:56 +0000 Subject: [PATCH 0236/1180] Minor language tweaks, change which key bindings are summarised. --- tmux.1 | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/tmux.1 b/tmux.1 index 15b8600c..2d16f6e0 100644 --- a/tmux.1 +++ b/tmux.1 @@ -88,6 +88,7 @@ and all sessions are managed by a single The server and each client are separate processes which communicate through a socket in .Pa /tmp . +.Pp The options are as follows: .Bl -tag -width "XXXXXXXXXXXX" .It Fl 2 @@ -200,19 +201,21 @@ Some of the default key bindings are: .Pp .Bl -tag -width Ds -offset 3n -compact .It c -Create new window. +Create a new window. .It d -Detach current client. +Detach the current client. .It l -Move to last (previously selected) window in the current session. +Move to the previously selected window. .It n -Change to next window in the current session. +Change to the next window. .It p -Change to previous window in the current session. -.It t -Display a large clock. +Change to the previous window. +.It & +Kill the current window. +.It , +Rename the current window. .It \&? -List current key bindings. +List all key bindings. .El .Pp A complete list may be obtained with the From de73fed73d050edd142971a8639cf0c195ad7ea7 Mon Sep 17 00:00:00 2001 From: Jason McIntyre Date: Sun, 9 Aug 2009 16:03:05 +0000 Subject: [PATCH 0237/1180] zap trailing whitespace; --- tmux.1 | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tmux.1 b/tmux.1 index 2d16f6e0..f03b6173 100644 --- a/tmux.1 +++ b/tmux.1 @@ -69,7 +69,7 @@ Once all sessions are killed, exits. .Pp Each session is persistent and will survive accidental disconnection -(such as +(such as .Xr ssh 1 connection timeout) or intentional detachment (with the .Ql C-b d @@ -228,7 +228,6 @@ Key bindings may be changed with the and .Ic unbind-key commands. -.Pp .Sh COMMANDS This section contains a list of the commands supported by .Nm . @@ -1236,7 +1235,7 @@ 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. +Set the attribute 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-bg Ar colour @@ -1260,7 +1259,7 @@ 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. +Set the attribute 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-bg Ar colour From ec0c33b8449269859c825d72a8c3c82bbe0c3164 Mon Sep 17 00:00:00 2001 From: Jason McIntyre Date: Mon, 10 Aug 2009 17:14:55 +0000 Subject: [PATCH 0238/1180] some minor tweaks; ok nicm --- tmux.1 | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tmux.1 b/tmux.1 index f03b6173..8621c3f4 100644 --- a/tmux.1 +++ b/tmux.1 @@ -34,8 +34,10 @@ is a terminal multiplexer: it enables a number of terminals to be created, accessed, and controlled from a single screen. -Programs may be detached from the screen, continue running in the background, -and be reattached to the same or a different screen. +.Nm +may be detached from a screen +and continue running in the background, +then later reattached. .Pp When .Nm @@ -71,7 +73,7 @@ exits. Each session is persistent and will survive accidental disconnection (such as .Xr ssh 1 -connection timeout) or intentional detachment (with the +connection timeout) or intentional detaching (with the .Ql C-b d key strokes). .Nm @@ -199,7 +201,7 @@ prefix key, .Pp Some of the default key bindings are: .Pp -.Bl -tag -width Ds -offset 3n -compact +.Bl -tag -width Ds -offset indent -compact .It c Create a new window. .It d From fa64c1235e0870e2beea98d090c1a8bcb77588a0 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 10 Aug 2009 17:59:59 +0000 Subject: [PATCH 0239/1180] Use the right source and destination lines in grid_duplicate_lines. --- grid.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/grid.c b/grid.c index abe62fd6..50b3569a 100644 --- a/grid.c +++ b/grid.c @@ -514,8 +514,8 @@ grid_duplicate_lines( grid_clear_lines(dst, dy, ny); for (yy = 0; yy < ny; yy++) { - srcl = &src->linedata[yy]; - dstl = &dst->linedata[yy]; + srcl = &src->linedata[sy]; + dstl = &dst->linedata[dy]; memcpy(dstl, srcl, sizeof *dstl); if (srcl->cellsize != 0) { From 181e1bcffd1f728d0ec32f66b027507857daa598 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 10 Aug 2009 19:42:03 +0000 Subject: [PATCH 0240/1180] Reset the attributes after drawing all or part of the screen, and reset the region before poll(2). This reduces (but does not eliminate) the chance of the attributes not being normal if tmux is disconnected without warning (ssh ~., reboot from inside, etc). --- screen-redraw.c | 3 +++ server.c | 1 + 2 files changed, 4 insertions(+) diff --git a/screen-redraw.c b/screen-redraw.c index eee1c83c..5ee273a5 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -173,6 +173,7 @@ screen_redraw_screen(struct client *c, int status_only) /* If only drawing status and it is present, don't need the rest. */ if (status_only && status) { tty_draw_line(tty, &c->status, 0, 0, tty->sy - 1); + tty_reset(tty); return; } @@ -214,6 +215,7 @@ screen_redraw_screen(struct client *c, int status_only) /* Draw the status line. */ if (status) tty_draw_line(tty, &c->status, 0, 0, tty->sy - 1); + tty_reset(tty); } /* Draw a single pane. */ @@ -224,4 +226,5 @@ screen_redraw_pane(struct client *c, struct window_pane *wp) for (i = 0; i < wp->sy; i++) tty_draw_line(&c->tty, wp->screen, i, wp->xoff, wp->yoff); + tty_reset(&c->tty); } diff --git a/server.c b/server.c index 927cfeb6..ab407a04 100644 --- a/server.c +++ b/server.c @@ -866,6 +866,7 @@ server_handle_client(struct client *c) /* Ensure cursor position and mode settings. */ status = options_get_number(&c->session->options, "status"); + tty_region(&c->tty, 0, c->tty.sy - 1, 0); if (!window_pane_visible(wp) || wp->yoff + s->cy >= c->tty.sy - status) tty_cursor(&c->tty, 0, 0, 0, 0); else From edcb22a6fb51f7862ffe694df8c0bdaffdaa8895 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 10 Aug 2009 20:51:29 +0000 Subject: [PATCH 0241/1180] No arguments are the same as new-session and this requires the environment to be sent, so set that flag too when argc == 0. --- tmux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tmux.c b/tmux.c index 72ea52b3..af099e3f 100644 --- a/tmux.c +++ b/tmux.c @@ -462,7 +462,7 @@ main(int argc, char **argv) if (unlock) cmdflags &= ~CMD_STARTSERVER; else if (argc == 0) - cmdflags |= CMD_STARTSERVER; + cmdflags |= CMD_STARTSERVER|CMD_SENDENVIRON; else { /* * It sucks parsing the command string twice (in client and From 60db6e3df471142e4ee7773b9b4e9b0135d61dfc Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 11 Aug 2009 12:53:37 +0000 Subject: [PATCH 0242/1180] Add flags for 1+2 and 2 arguments to the generic target code, use it for cmd-set-environment/option/window-option and remove the generic options parsing. --- cmd-generic.c | 124 +++++++++++----------------------------- cmd-set-environment.c | 28 ++++----- cmd-set-option.c | 38 ++++++------ cmd-set-window-option.c | 38 ++++++------ tmux.h | 26 +++------ 5 files changed, 92 insertions(+), 162 deletions(-) diff --git a/cmd-generic.c b/cmd-generic.c index 92d9a9bd..7962a87a 100644 --- a/cmd-generic.c +++ b/cmd-generic.c @@ -26,7 +26,7 @@ int cmd_getopt(int, char **, const char *, uint64_t); int cmd_flags(int, uint64_t, uint64_t *); size_t cmd_print_flags(char *, size_t, size_t, uint64_t); -int cmd_fill_argument(int, char **, int, char **); +int cmd_fill_argument(int, char **, char **, int, char **); size_t cmd_prarg(char *buf, size_t len, const char *prefix, char *arg) @@ -104,9 +104,10 @@ cmd_print_flags(char *buf, size_t len, size_t off, uint64_t chflags) } int -cmd_fill_argument(int flags, char **arg, int argc, char **argv) +cmd_fill_argument(int flags, char **arg, char **arg2, int argc, char **argv) { *arg = NULL; + *arg2 = NULL; if (flags & CMD_ARG1) { if (argc != 1) @@ -123,6 +124,23 @@ cmd_fill_argument(int flags, char **arg, int argc, char **argv) return (0); } + if (flags & CMD_ARG2) { + if (argc != 2) + return (-1); + *arg = xstrdup(argv[0]); + *arg2 = xstrdup(argv[1]); + return (0); + } + + if (flags & CMD_ARG12) { + if (argc != 1 && argc != 2) + return (-1); + *arg = xstrdup(argv[0]); + if (argc == 2) + *arg2 = xstrdup(argv[1]); + return (0); + } + if (argc != 0) return (-1); return (0); @@ -165,7 +183,8 @@ cmd_target_parse(struct cmd *self, int argc, char **argv, char **cause) argc -= optind; argv += optind; - if (cmd_fill_argument(self->entry->flags, &data->arg, argc, argv) != 0) + if (cmd_fill_argument( + self->entry->flags, &data->arg, &data->arg2, argc, argv) != 0) goto usage; return (0); @@ -202,6 +221,8 @@ cmd_target_print(struct cmd *self, char *buf, size_t len) off += cmd_prarg(buf + off, len - off, " -t ", data->target); if (off < len && data->arg != NULL) off += cmd_prarg(buf + off, len - off, " ", data->arg); + if (off < len && data->arg2 != NULL) + off += cmd_prarg(buf + off, len - off, " ", data->arg2); return (off); } @@ -246,7 +267,8 @@ cmd_srcdst_parse(struct cmd *self, int argc, char **argv, char **cause) argc -= optind; argv += optind; - if (cmd_fill_argument(self->entry->flags, &data->arg, argc, argv) != 0) + if (cmd_fill_argument( + self->entry->flags, &data->arg, &data->arg2, argc, argv) != 0) goto usage; return (0); @@ -287,6 +309,8 @@ cmd_srcdst_print(struct cmd *self, char *buf, size_t len) off += xsnprintf(buf + off, len - off, " -t %s", data->dst); if (off < len && data->arg != NULL) off += cmd_prarg(buf + off, len - off, " ", data->arg); + if (off < len && data->arg2 != NULL) + off += cmd_prarg(buf + off, len - off, " ", data->arg2); return (off); } @@ -338,7 +362,8 @@ cmd_buffer_parse(struct cmd *self, int argc, char **argv, char **cause) argc -= optind; argv += optind; - if (cmd_fill_argument(self->entry->flags, &data->arg, argc, argv) != 0) + if (cmd_fill_argument( + self->entry->flags, &data->arg, &data->arg2, argc, argv) != 0) goto usage; return (0); @@ -378,92 +403,7 @@ cmd_buffer_print(struct cmd *self, char *buf, size_t len) off += cmd_prarg(buf + off, len - off, " -t ", data->target); if (off < len && data->arg != NULL) off += cmd_prarg(buf + off, len - off, " ", data->arg); - return (off); -} - -void -cmd_option_init(struct cmd *self, unused int key) -{ - struct cmd_option_data *data; - - self->data = data = xmalloc(sizeof *data); - data->chflags = 0; - data->target = NULL; - data->option = NULL; - data->value = NULL; -} - -int -cmd_option_parse(struct cmd *self, int argc, char **argv, char **cause) -{ - struct cmd_option_data *data; - const struct cmd_entry *entry = self->entry; - int opt; - - /* Don't use the entry version since it may be dependent on key. */ - cmd_option_init(self, 0); - data = self->data; - - while ((opt = cmd_getopt(argc, argv, "t:", entry->chflags)) != -1) { - if (cmd_flags(opt, entry->chflags, &data->chflags) == 0) - continue; - switch (opt) { - case 't': - if (data->target == NULL) - data->target = xstrdup(optarg); - break; - default: - goto usage; - } - } - argc -= optind; - argv += optind; - - if (argc == 2) { - data->option = xstrdup(argv[0]); - data->value = xstrdup(argv[1]); - } else if (argc == 1) - data->option = xstrdup(argv[0]); - else - goto usage; - return (0); - -usage: - xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); - - self->entry->free(self); - return (-1); -} - -void -cmd_option_free(struct cmd *self) -{ - struct cmd_option_data *data = self->data; - - if (data->target != NULL) - xfree(data->target); - if (data->option != NULL) - xfree(data->option); - if (data->value != NULL) - xfree(data->value); - xfree(data); -} - -size_t -cmd_option_print(struct cmd *self, char *buf, size_t len) -{ - struct cmd_option_data *data = self->data; - size_t off = 0; - - off += xsnprintf(buf, len, "%s", self->entry->name); - if (data == NULL) - return (off); - off += cmd_print_flags(buf, len, off, data->chflags); - if (off < len && data->target != NULL) - off += cmd_prarg(buf + off, len - off, " -t ", data->target); - if (off < len && data->option != NULL) - off += xsnprintf(buf + off, len - off, " %s", data->option); - if (off < len && data->value != NULL) - off += xsnprintf(buf + off, len - off, " %s", data->value); + if (off < len && data->arg2 != NULL) + off += cmd_prarg(buf + off, len - off, " ", data->arg2); return (off); } diff --git a/cmd-set-environment.c b/cmd-set-environment.c index 85399a94..4ba66a07 100644 --- a/cmd-set-environment.c +++ b/cmd-set-environment.c @@ -31,27 +31,27 @@ int cmd_set_environment_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_set_environment_entry = { "set-environment", "setenv", - "[-gru] " CMD_OPTION_SESSION_USAGE, - 0, CMD_CHFLAG('g')|CMD_CHFLAG('r')|CMD_CHFLAG('u'), + "[-gru] " CMD_TARGET_SESSION_USAGE " name [value]", + CMD_ARG12, CMD_CHFLAG('g')|CMD_CHFLAG('r')|CMD_CHFLAG('u'), NULL, - cmd_option_parse, + cmd_target_parse, cmd_set_environment_exec, - cmd_option_free, - cmd_option_print + cmd_target_free, + cmd_target_print }; int cmd_set_environment_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_option_data *data = self->data; + struct cmd_target_data *data = self->data; struct session *s; struct environ *env; - if (*data->option == '\0') { + if (*data->arg == '\0') { ctx->error(ctx, "empty variable name"); return (-1); } - if (strchr(data->option, '=') != NULL) { + if (strchr(data->arg, '=') != NULL) { ctx->error(ctx, "variable name contains ="); return (-1); } @@ -65,23 +65,23 @@ cmd_set_environment_exec(struct cmd *self, struct cmd_ctx *ctx) } if (data->chflags & CMD_CHFLAG('u')) { - if (data->value != NULL) { + if (data->arg2 != NULL) { ctx->error(ctx, "can't specify a value with -u"); return (-1); } - environ_unset(env, data->option); + environ_unset(env, data->arg); } else if (data->chflags & CMD_CHFLAG('r')) { - if (data->value != NULL) { + if (data->arg2 != NULL) { ctx->error(ctx, "can't specify a value with -r"); return (-1); } - environ_set(env, data->option, NULL); + environ_set(env, data->arg, NULL); } else { - if (data->value == NULL) { + if (data->arg2 == NULL) { ctx->error(ctx, "no value specified"); return (-1); } - environ_set(env, data->option, data->value); + environ_set(env, data->arg, data->arg2); } return (0); diff --git a/cmd-set-option.c b/cmd-set-option.c index 7dad54a6..87b0b5a3 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -31,13 +31,13 @@ int cmd_set_option_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_set_option_entry = { "set-option", "set", - "[-agu] " CMD_OPTION_SESSION_USAGE, - 0, CMD_CHFLAG('a')|CMD_CHFLAG('g')|CMD_CHFLAG('u'), + "[-agu] " CMD_TARGET_SESSION_USAGE " option [value]", + CMD_ARG12, CMD_CHFLAG('a')|CMD_CHFLAG('g')|CMD_CHFLAG('u'), NULL, - cmd_option_parse, + cmd_target_parse, cmd_set_option_exec, - cmd_option_free, - cmd_option_print + cmd_target_free, + cmd_target_print }; const char *set_option_status_keys_list[] = { @@ -95,7 +95,7 @@ const struct set_option_entry set_option_table[] = { int cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_option_data *data = self->data; + struct cmd_target_data *data = self->data; struct session *s; struct client *c; struct options *oo; @@ -110,27 +110,27 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) oo = &s->options; } - if (*data->option == '\0') { + if (*data->arg == '\0') { ctx->error(ctx, "invalid option"); return (-1); } entry = NULL; for (opt = set_option_table; opt->name != NULL; opt++) { - if (strncmp(opt->name, data->option, strlen(data->option)) != 0) + if (strncmp(opt->name, data->arg, strlen(data->arg)) != 0) continue; if (entry != NULL) { - ctx->error(ctx, "ambiguous option: %s", data->option); + ctx->error(ctx, "ambiguous option: %s", data->arg); return (-1); } entry = opt; /* Bail now if an exact match. */ - if (strcmp(entry->name, data->option) == 0) + if (strcmp(entry->name, data->arg) == 0) break; } if (entry == NULL) { - ctx->error(ctx, "unknown option: %s", data->option); + ctx->error(ctx, "unknown option: %s", data->arg); return (-1); } @@ -140,7 +140,7 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) "can't unset global option: %s", entry->name); return (-1); } - if (data->value != NULL) { + if (data->arg2 != NULL) { ctx->error(ctx, "value passed to unset option: %s", entry->name); return (-1); @@ -152,25 +152,25 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) switch (entry->type) { case SET_OPTION_STRING: set_option_string(ctx, oo, entry, - data->value, data->chflags & CMD_CHFLAG('a')); + data->arg2, data->chflags & CMD_CHFLAG('a')); break; case SET_OPTION_NUMBER: - set_option_number(ctx, oo, entry, data->value); + set_option_number(ctx, oo, entry, data->arg2); break; case SET_OPTION_KEY: - set_option_key(ctx, oo, entry, data->value); + set_option_key(ctx, oo, entry, data->arg2); break; case SET_OPTION_COLOUR: - set_option_colour(ctx, oo, entry, data->value); + set_option_colour(ctx, oo, entry, data->arg2); break; case SET_OPTION_ATTRIBUTES: - set_option_attributes(ctx, oo, entry, data->value); + set_option_attributes(ctx, oo, entry, data->arg2); break; case SET_OPTION_FLAG: - set_option_flag(ctx, oo, entry, data->value); + set_option_flag(ctx, oo, entry, data->arg2); break; case SET_OPTION_CHOICE: - set_option_choice(ctx, oo, entry, data->value); + set_option_choice(ctx, oo, entry, data->arg2); break; } } diff --git a/cmd-set-window-option.c b/cmd-set-window-option.c index beeb26e2..01e10a35 100644 --- a/cmd-set-window-option.c +++ b/cmd-set-window-option.c @@ -31,13 +31,13 @@ int cmd_set_window_option_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_set_window_option_entry = { "set-window-option", "setw", - "[-agu] " CMD_OPTION_WINDOW_USAGE, - 0, CMD_CHFLAG('a')|CMD_CHFLAG('g')|CMD_CHFLAG('u'), + "[-agu] " CMD_TARGET_WINDOW_USAGE " option [value]", + CMD_ARG12, CMD_CHFLAG('a')|CMD_CHFLAG('g')|CMD_CHFLAG('u'), NULL, - cmd_option_parse, + cmd_target_parse, cmd_set_window_option_exec, - cmd_option_free, - cmd_option_print + cmd_target_free, + cmd_target_print }; const char *set_option_mode_keys_list[] = { @@ -78,7 +78,7 @@ const struct set_option_entry set_window_option_table[] = { int cmd_set_window_option_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_option_data *data = self->data; + struct cmd_target_data *data = self->data; struct winlink *wl; struct client *c; struct options *oo; @@ -93,27 +93,27 @@ cmd_set_window_option_exec(struct cmd *self, struct cmd_ctx *ctx) oo = &wl->window->options; } - if (*data->option == '\0') { + if (*data->arg == '\0') { ctx->error(ctx, "invalid option"); return (-1); } entry = NULL; for (opt = set_window_option_table; opt->name != NULL; opt++) { - if (strncmp(opt->name, data->option, strlen(data->option)) != 0) + if (strncmp(opt->name, data->arg, strlen(data->arg)) != 0) continue; if (entry != NULL) { - ctx->error(ctx, "ambiguous option: %s", data->option); + ctx->error(ctx, "ambiguous option: %s", data->arg); return (-1); } entry = opt; /* Bail now if an exact match. */ - if (strcmp(entry->name, data->option) == 0) + if (strcmp(entry->name, data->arg) == 0) break; } if (entry == NULL) { - ctx->error(ctx, "unknown option: %s", data->option); + ctx->error(ctx, "unknown option: %s", data->arg); return (-1); } @@ -123,7 +123,7 @@ cmd_set_window_option_exec(struct cmd *self, struct cmd_ctx *ctx) "can't unset global option: %s", entry->name); return (-1); } - if (data->value != NULL) { + if (data->arg2 != NULL) { ctx->error(ctx, "value passed to unset option: %s", entry->name); return (-1); @@ -135,25 +135,25 @@ cmd_set_window_option_exec(struct cmd *self, struct cmd_ctx *ctx) switch (entry->type) { case SET_OPTION_STRING: set_option_string(ctx, oo, entry, - data->value, data->chflags & CMD_CHFLAG('a')); + data->arg2, data->chflags & CMD_CHFLAG('a')); break; case SET_OPTION_NUMBER: - set_option_number(ctx, oo, entry, data->value); + set_option_number(ctx, oo, entry, data->arg2); break; case SET_OPTION_KEY: - set_option_key(ctx, oo, entry, data->value); + set_option_key(ctx, oo, entry, data->arg2); break; case SET_OPTION_COLOUR: - set_option_colour(ctx, oo, entry, data->value); + set_option_colour(ctx, oo, entry, data->arg2); break; case SET_OPTION_ATTRIBUTES: - set_option_attributes(ctx, oo, entry, data->value); + set_option_attributes(ctx, oo, entry, data->arg2); break; case SET_OPTION_FLAG: - set_option_flag(ctx, oo, entry, data->value); + set_option_flag(ctx, oo, entry, data->arg2); break; case SET_OPTION_CHOICE: - set_option_choice(ctx, oo, entry, data->value); + set_option_choice(ctx, oo, entry, data->arg2); break; } } diff --git a/tmux.h b/tmux.h index 96e2bf76..26ca824d 100644 --- a/tmux.h +++ b/tmux.h @@ -1010,9 +1010,11 @@ struct cmd_entry { #define CMD_STARTSERVER 0x1 #define CMD_CANTNEST 0x2 -#define CMD_ARG1 0x4 -#define CMD_ARG01 0x8 -#define CMD_SENDENVIRON 0x10 +#define CMD_SENDENVIRON 0x4 +#define CMD_ARG1 0x8 +#define CMD_ARG01 0x10 +#define CMD_ARG2 0x20 +#define CMD_ARG12 0x40 int flags; #define CMD_CHFLAG(flag) \ @@ -1032,6 +1034,7 @@ struct cmd_target_data { uint64_t chflags; char *target; char *arg; + char *arg2; }; struct cmd_srcdst_data { @@ -1039,6 +1042,7 @@ struct cmd_srcdst_data { char *src; char *dst; char *arg; + char *arg2; }; struct cmd_buffer_data { @@ -1046,13 +1050,7 @@ struct cmd_buffer_data { char *target; int buffer; char *arg; -}; - -struct cmd_option_data { - uint64_t chflags; - char *target; - char *option; - char *value; + char *arg2; }; /* Key binding. */ @@ -1373,14 +1371,6 @@ void cmd_buffer_init(struct cmd *, int); int cmd_buffer_parse(struct cmd *, int, char **, char **); void cmd_buffer_free(struct cmd *); size_t cmd_buffer_print(struct cmd *, char *, size_t); -#define CMD_OPTION_PANE_USAGE "[-t target-pane] option [value]" -#define CMD_OPTION_WINDOW_USAGE "[-t target-window] option [value]" -#define CMD_OPTION_SESSION_USAGE "[-t target-session] option [value]" -#define CMD_OPTION_CLIENT_USAGE "[-t target-client] option [value]" -void cmd_option_init(struct cmd *, int); -int cmd_option_parse(struct cmd *, int, char **, char **); -void cmd_option_free(struct cmd *); -size_t cmd_option_print(struct cmd *, char *, size_t); /* client.c */ int client_init(char *, struct client_ctx *, int, int); From f0635717b3e840a72a962a2014b18d84fac4c83a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 11 Aug 2009 17:18:35 +0000 Subject: [PATCH 0243/1180] Switch tmux to use imsg. This is the last major change to make the client-server protocol more resilient and make the protocol versioning work properly. In future, the only things requiring a protocol version bump will be changes in the message structs, and (when both client and server have this change) mixing different versions should nicely report an error message. As a side effect this also makes the code tidier, fixes a problem with the way errors reported during server startup were handled, and supports fd passing (which will be used in future). Looked over by eric@, thanks. Please note that mixing a client with this change with an older server or vice versa may cause tmux to crash or hang - tmux should be completely exited before upgrading. --- Makefile | 3 +- client-fn.c | 9 +- client.c | 72 ++++++----- cmd-server-info.c | 2 +- imsg-buffer.c | 305 ++++++++++++++++++++++++++++++++++++++++++++++ imsg.c | 271 ++++++++++++++++++++++++++++++++++++++++ imsg.h | 108 ++++++++++++++++ server-fn.c | 12 +- server-msg.c | 56 +++++---- server.c | 42 ++++--- tmux.c | 112 +++++++++++------ tmux.h | 24 ++-- 12 files changed, 874 insertions(+), 142 deletions(-) create mode 100644 imsg-buffer.c create mode 100644 imsg.c create mode 100644 imsg.h diff --git a/Makefile b/Makefile index bec2a8bb..97d39afa 100644 --- a/Makefile +++ b/Makefile @@ -28,7 +28,8 @@ SRCS= attributes.c buffer-poll.c buffer.c cfg.c client-fn.c \ cmd-set-environment.c cmd-show-environment.c \ cmd-up-pane.c cmd-display-message.c cmd.c \ colour.c environ.c grid-view.c grid.c input-keys.c \ - input.c key-bindings.c key-string.c layout-set.c layout.c log.c \ + imsg.c imsg-buffer.c input.c key-bindings.c key-string.c \ + layout-set.c layout.c log.c \ mode-key.c names.c options-cmd.c options.c paste.c procname.c \ resize.c screen-redraw.c screen-write.c screen.c server-fn.c \ server-msg.c server.c session.c status.c tmux.c tty-keys.c tty-term.c \ diff --git a/client-fn.c b/client-fn.c index 129c6871..789ac427 100644 --- a/client-fn.c +++ b/client-fn.c @@ -66,14 +66,7 @@ void client_write_server( struct client_ctx *cctx, enum msgtype type, void *buf, size_t len) { - struct hdr hdr; - - hdr.type = type; - hdr.size = len; - buffer_write(cctx->srv_out, &hdr, sizeof hdr); - - if (buf != NULL && len > 0) - buffer_write(cctx->srv_out, buf, len); + imsg_compose(&cctx->ibuf, type, PROTOCOL_VERSION, -1, -1, buf, len); } void diff --git a/client.c b/client.c index 4e756981..a56af84e 100644 --- a/client.c +++ b/client.c @@ -92,16 +92,13 @@ server_started: fatal("fcntl failed"); if (fcntl(fd, F_SETFL, mode|O_NONBLOCK) == -1) fatal("fcntl failed"); - cctx->srv_fd = fd; - cctx->srv_in = buffer_create(BUFSIZ); - cctx->srv_out = buffer_create(BUFSIZ); + imsg_init(&cctx->ibuf, fd); if (cmdflags & CMD_SENDENVIRON) client_send_environ(cctx); if (isatty(STDIN_FILENO)) { if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1) fatal("ioctl(TIOCGWINSZ)"); - data.version = PROTOCOL_VERSION; data.flags = flags; data.sx = ws.ws_col; data.sy = ws.ws_row; @@ -153,6 +150,7 @@ int client_main(struct client_ctx *cctx) { struct pollfd pfd; + int nfds; siginit(); @@ -173,24 +171,33 @@ client_main(struct client_ctx *cctx) sigcont = 0; } - pfd.fd = cctx->srv_fd; + pfd.fd = cctx->ibuf.fd; pfd.events = POLLIN; - if (BUFFER_USED(cctx->srv_out) > 0) + if (cctx->ibuf.w.queued > 0) pfd.events |= POLLOUT; - if (poll(&pfd, 1, INFTIM) == -1) { + if ((nfds = poll(&pfd, 1, INFTIM)) == -1) { if (errno == EAGAIN || errno == EINTR) continue; fatal("poll failed"); } + if (nfds == 0) + continue; - if (buffer_poll(&pfd, cctx->srv_in, cctx->srv_out) != 0) { - cctx->exittype = CCTX_DIED; - break; + if (pfd.revents & (POLLERR|POLLHUP|POLLNVAL)) + fatalx("socket error"); + + if (pfd.revents & POLLIN) { + if (client_msg_dispatch(cctx) != 0) + break; } - if (client_msg_dispatch(cctx) != 0) - break; + if (pfd.revents & POLLOUT) { + if (msgbuf_write(&cctx->ibuf.w) < 0) { + cctx->exittype = CCTX_DIED; + break; + } + } } if (sigterm) { @@ -235,54 +242,61 @@ client_handle_winch(struct client_ctx *cctx) int client_msg_dispatch(struct client_ctx *cctx) { - struct hdr hdr; + struct imsg imsg; struct msg_print_data printdata; + ssize_t n, datalen; + + if ((n = imsg_read(&cctx->ibuf)) == -1 || n == 0) { + cctx->exittype = CCTX_DIED; + return (-1); + } for (;;) { - if (BUFFER_USED(cctx->srv_in) < sizeof hdr) + if ((n = imsg_get(&cctx->ibuf, &imsg)) == -1) + fatalx("imsg_get failed"); + if (n == 0) return (0); - memcpy(&hdr, BUFFER_OUT(cctx->srv_in), sizeof hdr); - if (BUFFER_USED(cctx->srv_in) < (sizeof hdr) + hdr.size) - return (0); - buffer_remove(cctx->srv_in, sizeof hdr); + datalen = imsg.hdr.len - IMSG_HEADER_SIZE; - switch (hdr.type) { + switch (imsg.hdr.type) { case MSG_DETACH: - if (hdr.size != 0) + if (datalen != 0) fatalx("bad MSG_DETACH size"); client_write_server(cctx, MSG_EXITING, NULL, 0); cctx->exittype = CCTX_DETACH; break; case MSG_ERROR: - if (hdr.size != sizeof printdata) - fatalx("bad MSG_PRINT size"); - buffer_read(cctx->srv_in, &printdata, sizeof printdata); + if (datalen != sizeof printdata) + fatalx("bad MSG_ERROR size"); + memcpy(&printdata, imsg.data, sizeof printdata); printdata.msg[(sizeof printdata.msg) - 1] = '\0'; cctx->errstr = xstrdup(printdata.msg); + imsg_free(&imsg); return (-1); case MSG_EXIT: - if (hdr.size != 0) + if (datalen != 0) fatalx("bad MSG_EXIT size"); - + client_write_server(cctx, MSG_EXITING, NULL, 0); cctx->exittype = CCTX_EXIT; break; case MSG_EXITED: - if (hdr.size != 0) + if (datalen != 0) fatalx("bad MSG_EXITED size"); + imsg_free(&imsg); return (-1); case MSG_SHUTDOWN: - if (hdr.size != 0) + if (datalen != 0) fatalx("bad MSG_SHUTDOWN size"); client_write_server(cctx, MSG_EXITING, NULL, 0); cctx->exittype = CCTX_SHUTDOWN; break; case MSG_SUSPEND: - if (hdr.size != 0) + if (datalen != 0) fatalx("bad MSG_SUSPEND size"); client_suspend(); @@ -290,5 +304,7 @@ client_msg_dispatch(struct client_ctx *cctx) default: fatalx("unexpected message"); } + + imsg_free(&imsg); } } diff --git a/cmd-server-info.c b/cmd-server-info.c index a79f2520..396d15b0 100644 --- a/cmd-server-info.c +++ b/cmd-server-info.c @@ -90,7 +90,7 @@ cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx) continue; ctx->print(ctx, "%2d: %s (%d, %d): %s [%ux%u %s] " - "[flags=0x%x/0x%x]", i, c->tty.path, c->fd, c->tty.fd, + "[flags=0x%x/0x%x]", i, c->tty.path, c->ibuf.fd, c->tty.fd, c->session->name, c->tty.sx, c->tty.sy, c->tty.termname, c->flags, c->tty.flags); } diff --git a/imsg-buffer.c b/imsg-buffer.c new file mode 100644 index 00000000..06fe0b1a --- /dev/null +++ b/imsg-buffer.c @@ -0,0 +1,305 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2003, 2004 Henning Brauer + * + * 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 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 + +#include "imsg.h" + +int buf_realloc(struct buf *, size_t); +void buf_enqueue(struct msgbuf *, struct buf *); +void buf_dequeue(struct msgbuf *, struct buf *); + +struct buf * +buf_open(size_t len) +{ + struct buf *buf; + + if ((buf = calloc(1, sizeof(struct buf))) == NULL) + return (NULL); + if ((buf->buf = malloc(len)) == NULL) { + free(buf); + return (NULL); + } + buf->size = buf->max = len; + buf->fd = -1; + + return (buf); +} + +struct buf * +buf_dynamic(size_t len, size_t max) +{ + struct buf *buf; + + if (max < len) + return (NULL); + + if ((buf = buf_open(len)) == NULL) + return (NULL); + + if (max > 0) + buf->max = max; + + return (buf); +} + +int +buf_realloc(struct buf *buf, size_t len) +{ + u_char *b; + + /* on static buffers max is eq size and so the following fails */ + if (buf->wpos + len > buf->max) { + errno = ENOMEM; + return (-1); + } + + b = realloc(buf->buf, buf->wpos + len); + if (b == NULL) + return (-1); + buf->buf = b; + buf->size = buf->wpos + len; + + return (0); +} + +int +buf_add(struct buf *buf, const void *data, size_t len) +{ + if (buf->wpos + len > buf->size) + if (buf_realloc(buf, len) == -1) + return (-1); + + memcpy(buf->buf + buf->wpos, data, len); + buf->wpos += len; + return (0); +} + +void * +buf_reserve(struct buf *buf, size_t len) +{ + void *b; + + if (buf->wpos + len > buf->size) + if (buf_realloc(buf, len) == -1) + return (NULL); + + b = buf->buf + buf->wpos; + buf->wpos += len; + return (b); +} + +void * +buf_seek(struct buf *buf, size_t pos, size_t len) +{ + /* only allowed to seek in already written parts */ + if (pos + len > buf->wpos) + return (NULL); + + return (buf->buf + pos); +} + +size_t +buf_size(struct buf *buf) +{ + return (buf->wpos); +} + +size_t +buf_left(struct buf *buf) +{ + return (buf->max - buf->wpos); +} + +void +buf_close(struct msgbuf *msgbuf, struct buf *buf) +{ + buf_enqueue(msgbuf, buf); +} + +int +buf_write(struct msgbuf *msgbuf) +{ + struct iovec iov[IOV_MAX]; + struct buf *buf, *next; + unsigned int i = 0; + ssize_t n; + + bzero(&iov, sizeof(iov)); + TAILQ_FOREACH(buf, &msgbuf->bufs, entry) { + if (i >= IOV_MAX) + break; + iov[i].iov_base = buf->buf + buf->rpos; + iov[i].iov_len = buf->wpos - buf->rpos; + i++; + } + + if ((n = writev(msgbuf->fd, iov, i)) == -1) { + if (errno == EAGAIN || errno == ENOBUFS || + errno == EINTR) /* try later */ + return (0); + else + return (-1); + } + + if (n == 0) { /* connection closed */ + errno = 0; + return (-2); + } + + for (buf = TAILQ_FIRST(&msgbuf->bufs); buf != NULL && n > 0; + buf = next) { + next = TAILQ_NEXT(buf, entry); + if (buf->rpos + n >= buf->wpos) { + n -= buf->wpos - buf->rpos; + buf_dequeue(msgbuf, buf); + } else { + buf->rpos += n; + n = 0; + } + } + + return (0); +} + +void +buf_free(struct buf *buf) +{ + free(buf->buf); + free(buf); +} + +void +msgbuf_init(struct msgbuf *msgbuf) +{ + msgbuf->queued = 0; + msgbuf->fd = -1; + TAILQ_INIT(&msgbuf->bufs); +} + +void +msgbuf_clear(struct msgbuf *msgbuf) +{ + struct buf *buf; + + while ((buf = TAILQ_FIRST(&msgbuf->bufs)) != NULL) + buf_dequeue(msgbuf, buf); +} + +int +msgbuf_write(struct msgbuf *msgbuf) +{ + struct iovec iov[IOV_MAX]; + struct buf *buf, *next; + unsigned int i = 0; + ssize_t n; + struct msghdr msg; + struct cmsghdr *cmsg; + union { + struct cmsghdr hdr; + char buf[CMSG_SPACE(sizeof(int))]; + } cmsgbuf; + + bzero(&iov, sizeof(iov)); + bzero(&msg, sizeof(msg)); + TAILQ_FOREACH(buf, &msgbuf->bufs, entry) { + if (i >= IOV_MAX) + break; + iov[i].iov_base = buf->buf + buf->rpos; + iov[i].iov_len = buf->wpos - buf->rpos; + i++; + if (buf->fd != -1) + break; + } + + msg.msg_iov = iov; + msg.msg_iovlen = i; + + if (buf != NULL && buf->fd != -1) { + msg.msg_control = (caddr_t)&cmsgbuf.buf; + msg.msg_controllen = sizeof(cmsgbuf.buf); + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_len = CMSG_LEN(sizeof(int)); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + *(int *)CMSG_DATA(cmsg) = buf->fd; + } + + if ((n = sendmsg(msgbuf->fd, &msg, 0)) == -1) { + if (errno == EAGAIN || errno == ENOBUFS || + errno == EINTR) /* try later */ + return (0); + else + return (-1); + } + + if (n == 0) { /* connection closed */ + errno = 0; + return (-2); + } + + /* + * assumption: fd got sent if sendmsg sent anything + * this works because fds are passed one at a time + */ + if (buf != NULL && buf->fd != -1) { + close(buf->fd); + buf->fd = -1; + } + + for (buf = TAILQ_FIRST(&msgbuf->bufs); buf != NULL && n > 0; + buf = next) { + next = TAILQ_NEXT(buf, entry); + if (buf->rpos + n >= buf->wpos) { + n -= buf->wpos - buf->rpos; + buf_dequeue(msgbuf, buf); + } else { + buf->rpos += n; + n = 0; + } + } + + return (0); +} + +void +buf_enqueue(struct msgbuf *msgbuf, struct buf *buf) +{ + TAILQ_INSERT_TAIL(&msgbuf->bufs, buf, entry); + msgbuf->queued++; +} + +void +buf_dequeue(struct msgbuf *msgbuf, struct buf *buf) +{ + TAILQ_REMOVE(&msgbuf->bufs, buf, entry); + + if (buf->fd != -1) + close(buf->fd); + + msgbuf->queued--; + buf_free(buf); +} diff --git a/imsg.c b/imsg.c new file mode 100644 index 00000000..263c7c8c --- /dev/null +++ b/imsg.c @@ -0,0 +1,271 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2003, 2004 Henning Brauer + * + * 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 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 + +#include "imsg.h" + +int imsg_get_fd(struct imsgbuf *); + +void +imsg_init(struct imsgbuf *ibuf, int fd) +{ + msgbuf_init(&ibuf->w); + bzero(&ibuf->r, sizeof(ibuf->r)); + ibuf->fd = fd; + ibuf->w.fd = fd; + ibuf->pid = getpid(); + TAILQ_INIT(&ibuf->fds); +} + +ssize_t +imsg_read(struct imsgbuf *ibuf) +{ + struct msghdr msg; + struct cmsghdr *cmsg; + union { + struct cmsghdr hdr; + char buf[CMSG_SPACE(sizeof(int) * 16)]; + } cmsgbuf; + struct iovec iov; + ssize_t n; + int fd; + struct imsg_fd *ifd; + + bzero(&msg, sizeof(msg)); + + iov.iov_base = ibuf->r.buf + ibuf->r.wpos; + iov.iov_len = sizeof(ibuf->r.buf) - ibuf->r.wpos; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = &cmsgbuf.buf; + msg.msg_controllen = sizeof(cmsgbuf.buf); + + if ((n = recvmsg(ibuf->fd, &msg, 0)) == -1) { + if (errno != EINTR && errno != EAGAIN) { + return (-1); + } + return (-2); + } + + ibuf->r.wpos += n; + + for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; + cmsg = CMSG_NXTHDR(&msg, cmsg)) { + if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_RIGHTS) { + fd = (*(int *)CMSG_DATA(cmsg)); + if ((ifd = calloc(1, sizeof(struct imsg_fd))) == NULL) { + /* XXX: this return can leak */ + return (-1); + } + ifd->fd = fd; + TAILQ_INSERT_TAIL(&ibuf->fds, ifd, entry); + } + /* we do not handle other ctl data level */ + } + + return (n); +} + +ssize_t +imsg_get(struct imsgbuf *ibuf, struct imsg *imsg) +{ + size_t av, left, datalen; + + av = ibuf->r.wpos; + + if (IMSG_HEADER_SIZE > av) + return (0); + + memcpy(&imsg->hdr, ibuf->r.buf, sizeof(imsg->hdr)); + if (imsg->hdr.len < IMSG_HEADER_SIZE || + imsg->hdr.len > MAX_IMSGSIZE) { + errno = ERANGE; + return (-1); + } + if (imsg->hdr.len > av) + return (0); + datalen = imsg->hdr.len - IMSG_HEADER_SIZE; + ibuf->r.rptr = ibuf->r.buf + IMSG_HEADER_SIZE; + if ((imsg->data = malloc(datalen)) == NULL) + return (-1); + + if (imsg->hdr.flags & IMSGF_HASFD) + imsg->fd = imsg_get_fd(ibuf); + else + imsg->fd = -1; + + memcpy(imsg->data, ibuf->r.rptr, datalen); + + if (imsg->hdr.len < av) { + left = av - imsg->hdr.len; + memmove(&ibuf->r.buf, ibuf->r.buf + imsg->hdr.len, left); + ibuf->r.wpos = left; + } else + ibuf->r.wpos = 0; + + return (datalen + IMSG_HEADER_SIZE); +} + +int +imsg_compose(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid, + pid_t pid, int fd, void *data, u_int16_t datalen) +{ + struct buf *wbuf; + + if ((wbuf = imsg_create(ibuf, type, peerid, pid, datalen)) == NULL) + return (-1); + + if (imsg_add(wbuf, data, datalen) == -1) + return (-1); + + wbuf->fd = fd; + + imsg_close(ibuf, wbuf); + + return (1); +} + +int +imsg_composev(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid, + pid_t pid, int fd, const struct iovec *iov, int iovcnt) +{ + struct buf *wbuf; + int i, datalen = 0; + + for (i = 0; i < iovcnt; i++) + datalen += iov[i].iov_len; + + if ((wbuf = imsg_create(ibuf, type, peerid, pid, datalen)) == NULL) + return (-1); + + for (i = 0; i < iovcnt; i++) + if (imsg_add(wbuf, iov[i].iov_base, iov[i].iov_len) == -1) + return (-1); + + wbuf->fd = fd; + + imsg_close(ibuf, wbuf); + + return (1); +} + +/* ARGSUSED */ +struct buf * +imsg_create(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid, + pid_t pid, u_int16_t datalen) +{ + struct buf *wbuf; + struct imsg_hdr hdr; + + datalen += IMSG_HEADER_SIZE; + if (datalen > MAX_IMSGSIZE) { + errno = ERANGE; + return (NULL); + } + + hdr.type = type; + hdr.flags = 0; + hdr.peerid = peerid; + if ((hdr.pid = pid) == 0) + hdr.pid = ibuf->pid; + if ((wbuf = buf_dynamic(datalen, MAX_IMSGSIZE)) == NULL) { + return (NULL); + } + if (imsg_add(wbuf, &hdr, sizeof(hdr)) == -1) + return (NULL); + + return (wbuf); +} + +int +imsg_add(struct buf *msg, void *data, u_int16_t datalen) +{ + if (datalen) + if (buf_add(msg, data, datalen) == -1) { + buf_free(msg); + return (-1); + } + return (datalen); +} + +void +imsg_close(struct imsgbuf *ibuf, struct buf *msg) +{ + struct imsg_hdr *hdr; + + hdr = (struct imsg_hdr *)msg->buf; + + hdr->flags &= ~IMSGF_HASFD; + if (msg->fd != -1) + hdr->flags |= IMSGF_HASFD; + + hdr->len = (u_int16_t)msg->wpos; + + buf_close(&ibuf->w, msg); +} + +void +imsg_free(struct imsg *imsg) +{ + free(imsg->data); +} + +int +imsg_get_fd(struct imsgbuf *ibuf) +{ + int fd; + struct imsg_fd *ifd; + + if ((ifd = TAILQ_FIRST(&ibuf->fds)) == NULL) + return (-1); + + fd = ifd->fd; + TAILQ_REMOVE(&ibuf->fds, ifd, entry); + free(ifd); + + return (fd); +} + +int +imsg_flush(struct imsgbuf *ibuf) +{ + while (ibuf->w.queued) + if (msgbuf_write(&ibuf->w) < 0) + return (-1); + return (0); +} + +void +imsg_clear(struct imsgbuf *ibuf) +{ + int fd; + + msgbuf_clear(&ibuf->w); + while ((fd = imsg_get_fd(ibuf)) != -1) + close(fd); +} diff --git a/imsg.h b/imsg.h new file mode 100644 index 00000000..5de73f0c --- /dev/null +++ b/imsg.h @@ -0,0 +1,108 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2006, 2007 Pierre-Yves Ritschard + * Copyright (c) 2006, 2007, 2008 Reyk Floeter + * Copyright (c) 2003, 2004 Henning Brauer + * + * 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 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 + +#define READ_BUF_SIZE 65535 +#define IMSG_HEADER_SIZE sizeof(struct imsg_hdr) +#define MAX_IMSGSIZE 16384 + +struct buf { + TAILQ_ENTRY(buf) entry; + u_char *buf; + size_t size; + size_t max; + size_t wpos; + size_t rpos; + int fd; +}; + +struct msgbuf { + TAILQ_HEAD(, buf) bufs; + u_int32_t queued; + int fd; +}; + +struct buf_read { + u_char buf[READ_BUF_SIZE]; + u_char *rptr; + size_t wpos; +}; + +struct imsg_fd { + TAILQ_ENTRY(imsg_fd) entry; + int fd; +}; + +struct imsgbuf { + TAILQ_HEAD(, imsg_fd) fds; + struct buf_read r; + struct msgbuf w; + int fd; + pid_t pid; +}; + +#define IMSGF_HASFD 1 + +struct imsg_hdr { + u_int32_t type; + u_int16_t len; + u_int16_t flags; + u_int32_t peerid; + u_int32_t pid; +}; + +struct imsg { + struct imsg_hdr hdr; + int fd; + void *data; +}; + + +/* buffer.c */ +struct buf *buf_open(size_t); +struct buf *buf_dynamic(size_t, size_t); +int buf_add(struct buf *, const void *, size_t); +void *buf_reserve(struct buf *, size_t); +void *buf_seek(struct buf *, size_t, size_t); +size_t buf_size(struct buf *); +size_t buf_left(struct buf *); +void buf_close(struct msgbuf *, struct buf *); +int buf_write(struct msgbuf *); +void buf_free(struct buf *); +void msgbuf_init(struct msgbuf *); +void msgbuf_clear(struct msgbuf *); +int msgbuf_write(struct msgbuf *); + +/* imsg.c */ +void imsg_init(struct imsgbuf *, int); +ssize_t imsg_read(struct imsgbuf *); +ssize_t imsg_get(struct imsgbuf *, struct imsg *); +int imsg_compose(struct imsgbuf *, u_int32_t, u_int32_t, pid_t, + int, void *, u_int16_t); +int imsg_composev(struct imsgbuf *, u_int32_t, u_int32_t, pid_t, + int, const struct iovec *, int); +struct buf *imsg_create(struct imsgbuf *, u_int32_t, u_int32_t, pid_t, + u_int16_t); +int imsg_add(struct buf *, void *, u_int16_t); +void imsg_close(struct imsgbuf *, struct buf *); +void imsg_free(struct imsg *); +int imsg_flush(struct imsgbuf *); +void imsg_clear(struct imsgbuf *); diff --git a/server-fn.c b/server-fn.c index 6f6ed2c8..8d5d06bd 100644 --- a/server-fn.c +++ b/server-fn.c @@ -55,18 +55,12 @@ void server_write_client( struct client *c, enum msgtype type, const void *buf, size_t len) { - struct hdr hdr; + struct imsgbuf *ibuf = &c->ibuf; if (c->flags & CLIENT_BAD) return; - log_debug("writing %d to client %d", type, c->fd); - - hdr.type = type; - hdr.size = len; - - buffer_write(c->out, &hdr, sizeof hdr); - if (buf != NULL && len > 0) - buffer_write(c->out, buf, len); + log_debug("writing %d to client %d", type, c->ibuf.fd); + imsg_compose(ibuf, type, PROTOCOL_VERSION, -1, -1, (void *) buf, len); } void diff --git a/server-msg.c b/server-msg.c index b23ec4c4..6cc69a0a 100644 --- a/server-msg.c +++ b/server-msg.c @@ -37,45 +37,56 @@ void printflike2 server_msg_command_info(struct cmd_ctx *, const char *, ...); int server_msg_dispatch(struct client *c) { - struct hdr hdr; + struct imsg imsg; struct msg_command_data commanddata; struct msg_identify_data identifydata; struct msg_resize_data resizedata; struct msg_unlock_data unlockdata; struct msg_environ_data environdata; + ssize_t n, datalen; + + if ((n = imsg_read(&c->ibuf)) == -1 || n == 0) + return (-1); for (;;) { - if (BUFFER_USED(c->in) < sizeof hdr) + if ((n = imsg_get(&c->ibuf, &imsg)) == -1) + return (-1); + if (n == 0) return (0); - memcpy(&hdr, BUFFER_OUT(c->in), sizeof hdr); - if (BUFFER_USED(c->in) < (sizeof hdr) + hdr.size) - return (0); - buffer_remove(c->in, sizeof hdr); + datalen = imsg.hdr.len - IMSG_HEADER_SIZE; - switch (hdr.type) { + if (imsg.hdr.peerid != PROTOCOL_VERSION) { + server_write_client(c, MSG_VERSION, NULL, 0); + c->flags |= CLIENT_BAD; + imsg_free(&imsg); + continue; + } + + log_debug("got %d from client %d", imsg.hdr.type, c->ibuf.fd); + switch (imsg.hdr.type) { case MSG_COMMAND: - if (hdr.size != sizeof commanddata) + if (datalen != sizeof commanddata) fatalx("bad MSG_COMMAND size"); - buffer_read(c->in, &commanddata, sizeof commanddata); + memcpy(&commanddata, imsg.data, sizeof commanddata); server_msg_command(c, &commanddata); break; case MSG_IDENTIFY: - if (hdr.size != sizeof identifydata) + if (datalen != sizeof identifydata) fatalx("bad MSG_IDENTIFY size"); - buffer_read(c->in, &identifydata, sizeof identifydata); + memcpy(&identifydata, imsg.data, sizeof identifydata); server_msg_identify(c, &identifydata); break; case MSG_RESIZE: - if (hdr.size != sizeof resizedata) + if (datalen != sizeof resizedata) fatalx("bad MSG_RESIZE size"); - buffer_read(c->in, &resizedata, sizeof resizedata); + memcpy(&resizedata, imsg.data, sizeof resizedata); server_msg_resize(c, &resizedata); break; case MSG_EXITING: - if (hdr.size != 0) + if (datalen != 0) fatalx("bad MSG_EXITING size"); c->session = NULL; @@ -83,9 +94,9 @@ server_msg_dispatch(struct client *c) server_write_client(c, MSG_EXITED, NULL, 0); break; case MSG_UNLOCK: - if (hdr.size != sizeof unlockdata) + if (datalen != sizeof unlockdata) fatalx("bad MSG_UNLOCK size"); - buffer_read(c->in, &unlockdata, sizeof unlockdata); + memcpy(&unlockdata, imsg.data, sizeof unlockdata); unlockdata.pass[(sizeof unlockdata.pass) - 1] = '\0'; if (server_unlock(unlockdata.pass) != 0) @@ -94,7 +105,7 @@ server_msg_dispatch(struct client *c) server_write_client(c, MSG_EXIT, NULL, 0); break; case MSG_WAKEUP: - if (hdr.size != 0) + if (datalen != 0) fatalx("bad MSG_WAKEUP size"); c->flags &= ~CLIENT_SUSPENDED; @@ -102,9 +113,9 @@ server_msg_dispatch(struct client *c) server_redraw_client(c); break; case MSG_ENVIRON: - if (hdr.size != sizeof environdata) + if (datalen != sizeof environdata) fatalx("bad MSG_ENVIRON size"); - buffer_read(c->in, &environdata, sizeof environdata); + memcpy(&environdata, imsg.data, sizeof environdata); environdata.var[(sizeof environdata.var) - 1] = '\0'; if (strchr(environdata.var, '=') != NULL) @@ -113,6 +124,8 @@ server_msg_dispatch(struct client *c) default: fatalx("unexpected message"); } + + imsg_free(&imsg); } } @@ -224,11 +237,6 @@ error: void server_msg_identify(struct client *c, struct msg_identify_data *data) { - if (data->version != PROTOCOL_VERSION) { - server_write_error(c, "protocol version mismatch"); - return; - } - c->tty.sx = data->sx; c->tty.sy = data->sy; diff --git a/server.c b/server.c index ab407a04..acaf5207 100644 --- a/server.c +++ b/server.c @@ -85,9 +85,7 @@ server_create_client(int fd) fatal("fcntl failed"); c = xcalloc(1, sizeof *c); - c->fd = fd; - c->in = buffer_create(BUFSIZ); - c->out = buffer_create(BUFSIZ); + imsg_init(&c->ibuf, fd); ARRAY_INIT(&c->prompt_hdata); @@ -672,10 +670,10 @@ server_fill_clients(struct pollfd **pfd) if (c == NULL) (*pfd)->fd = -1; else { - (*pfd)->fd = c->fd; + (*pfd)->fd = c->ibuf.fd; if (!(c->flags & CLIENT_BAD)) - (*pfd)->events = POLLIN; - if (BUFFER_USED(c->out) > 0) + (*pfd)->events |= POLLIN; + if (c->ibuf.w.queued > 0) (*pfd)->events |= POLLOUT; } (*pfd)++; @@ -718,17 +716,32 @@ server_handle_clients(struct pollfd **pfd) c = ARRAY_ITEM(&clients, i); if (c != NULL) { - if (buffer_poll(*pfd, c->in, c->out) != 0) { + if ((*pfd)->revents & (POLLERR|POLLNVAL|POLLHUP)) { server_lost_client(c); (*pfd) += 2; continue; - } else if (c->flags & CLIENT_BAD) { - if (BUFFER_USED(c->out) == 0) + } + + if ((*pfd)->revents & POLLOUT) { + if (msgbuf_write(&c->ibuf.w) < 0) { + server_lost_client(c); + (*pfd) += 2; + continue; + } + } + + if (c->flags & CLIENT_BAD) { + if (c->ibuf.w.queued == 0) server_lost_client(c); (*pfd) += 2; - continue; - } else - server_msg_dispatch(c); + continue; + } else if ((*pfd)->revents & POLLIN) { + if (server_msg_dispatch(c) != 0) { + server_lost_client(c); + (*pfd) += 2; + continue; + } + } } (*pfd)++; @@ -910,9 +923,8 @@ server_lost_client(struct client *c) if (c->cwd != NULL) xfree(c->cwd); - close(c->fd); - buffer_destroy(c->in); - buffer_destroy(c->out); + close(c->ibuf.fd); + imsg_clear(&c->ibuf); xfree(c); recalculate_sizes(); diff --git a/tmux.c b/tmux.c index af099e3f..34416e30 100644 --- a/tmux.c +++ b/tmux.c @@ -60,6 +60,7 @@ __dead void usage(void); char *makesockpath(const char *); int prepare_unlock(enum msgtype *, void **, size_t *, int); int prepare_cmd(enum msgtype *, void **, size_t *, int, char **); +int dispatch_imsg(struct client_ctx *, int *); __dead void usage(void) @@ -260,14 +261,13 @@ main(int argc, char **argv) struct cmd *cmd; struct pollfd pfd; enum msgtype msg; - struct hdr hdr; struct passwd *pw; - struct msg_print_data printdata; char *s, *path, *label, *home, *cause, **var; char cwd[MAXPATHLEN]; void *buf; size_t len; int retcode, opt, flags, unlock, cmdflags = 0; + int nfds; unlock = flags = 0; label = path = NULL; @@ -493,58 +493,92 @@ main(int argc, char **argv) retcode = 0; for (;;) { - pfd.fd = cctx.srv_fd; + pfd.fd = cctx.ibuf.fd; pfd.events = POLLIN; - if (BUFFER_USED(cctx.srv_out) > 0) + if (cctx.ibuf.w.queued != 0) pfd.events |= POLLOUT; - if (poll(&pfd, 1, INFTIM) == -1) { + if ((nfds = poll(&pfd, 1, INFTIM)) == -1) { if (errno == EAGAIN || errno == EINTR) continue; fatal("poll failed"); } - - if (buffer_poll(&pfd, cctx.srv_in, cctx.srv_out) != 0) - goto out; - - restart: - if (BUFFER_USED(cctx.srv_in) < sizeof hdr) + if (nfds == 0) continue; - memcpy(&hdr, BUFFER_OUT(cctx.srv_in), sizeof hdr); - if (BUFFER_USED(cctx.srv_in) < (sizeof hdr) + hdr.size) - continue; - buffer_remove(cctx.srv_in, sizeof hdr); - switch (hdr.type) { - case MSG_EXIT: - case MSG_SHUTDOWN: - goto out; - case MSG_ERROR: - retcode = 1; - /* FALLTHROUGH */ - case MSG_PRINT: - if (hdr.size < sizeof printdata) - fatalx("bad MSG_PRINT size"); - buffer_read(cctx.srv_in, &printdata, sizeof printdata); + if (pfd.revents & (POLLERR|POLLHUP|POLLNVAL)) + fatalx("socket error"); - printdata.msg[(sizeof printdata.msg) - 1] = '\0'; - log_info("%s", printdata.msg); - goto restart; - case MSG_READY: - retcode = client_main(&cctx); - goto out; - default: - fatalx("unexpected command"); + if (pfd.revents & POLLIN) { + if (dispatch_imsg(&cctx, &retcode) != 0) + break; + } + + if (pfd.revents & POLLOUT) { + if (msgbuf_write(&cctx.ibuf.w) < 0) + fatalx("msgbuf_write failed"); } } -out: options_free(&global_s_options); options_free(&global_w_options); - close(cctx.srv_fd); - buffer_destroy(cctx.srv_in); - buffer_destroy(cctx.srv_out); - return (retcode); } + +int +dispatch_imsg(struct client_ctx *cctx, int *retcode) +{ + struct imsg imsg; + ssize_t n, datalen; + struct msg_print_data printdata; + + if ((n = imsg_read(&cctx->ibuf)) == -1 || n == 0) + fatalx("imsg_read failed"); + + for (;;) { + if ((n = imsg_get(&cctx->ibuf, &imsg)) == -1) + fatalx("imsg_get failed"); + if (n == 0) + return (0); + datalen = imsg.hdr.len - IMSG_HEADER_SIZE; + + switch (imsg.hdr.type) { + case MSG_EXIT: + case MSG_SHUTDOWN: + if (datalen != 0) + fatalx("bad MSG_EXIT size"); + + return (-1); + case MSG_ERROR: + *retcode = 1; + /* FALLTHROUGH */ + case MSG_PRINT: + if (datalen != sizeof printdata) + fatalx("bad MSG_PRINT size"); + memcpy(&printdata, imsg.data, sizeof printdata); + printdata.msg[(sizeof printdata.msg) - 1] = '\0'; + + log_info("%s", printdata.msg); + break; + case MSG_READY: + if (datalen != 0) + fatalx("bad MSG_READY size"); + + *retcode = client_main(cctx); + return (-1); + case MSG_VERSION: + if (datalen != 0) + fatalx("bad MSG_VERSION size"); + + log_warnx("protocol version mismatch (client %u, " + "server %u)", PROTOCOL_VERSION, imsg.hdr.peerid); + *retcode = 1; + return (-1); + default: + fatalx("unexpected message"); + } + + imsg_free(&imsg); + } +} diff --git a/tmux.h b/tmux.h index 26ca824d..cdd8d6ad 100644 --- a/tmux.h +++ b/tmux.h @@ -19,12 +19,13 @@ #ifndef TMUX_H #define TMUX_H -#define PROTOCOL_VERSION -15 +#define PROTOCOL_VERSION 1 #include #include #include #include +#include #include #include @@ -37,6 +38,7 @@ #include #include "array.h" +#include "imsg.h" extern char *__progname; extern char **environ; @@ -303,23 +305,16 @@ enum msgtype { MSG_SHUTDOWN, MSG_SUSPEND, MSG_UNLOCK, + MSG_VERSION, MSG_WAKEUP, MSG_ENVIRON }; /* - * Message header and data. + * Message data. * * Don't forget to bump PROTOCOL_VERSION if any of these change! - * - * Changing sizeof (struct hdr) or sizeof (struct msg_identify_data) will make - * the tmux client hang even if the protocol version is bumped. */ -struct hdr { - enum msgtype type; - size_t size; -}; - struct msg_print_data { char msg[PRINT_LENGTH]; }; @@ -334,7 +329,6 @@ struct msg_command_data { struct msg_identify_data { char tty[TTY_NAME_MAX]; - int version; char cwd[MAXPATHLEN]; @@ -908,9 +902,7 @@ struct tty_ctx { /* Client connection. */ struct client { - int fd; - struct buffer *in; - struct buffer *out; + struct imsgbuf ibuf; struct environ environ; @@ -958,9 +950,7 @@ ARRAY_DECL(clients, struct client *); /* Client context. */ struct client_ctx { - int srv_fd; - struct buffer *srv_in; - struct buffer *srv_out; + struct imsgbuf ibuf; enum { CCTX_DETACH, From ff65e3754565f1d878c70257e96f6aea09c1c90e Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 11 Aug 2009 19:32:25 +0000 Subject: [PATCH 0244/1180] Drop the no_stop argument to tty_close and tty_free in favour of a flag in the tty struct. --- server-msg.c | 2 +- server.c | 2 +- tmux.h | 5 +++-- tty.c | 15 ++++++++++----- 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/server-msg.c b/server-msg.c index 6cc69a0a..3e82f90a 100644 --- a/server-msg.c +++ b/server-msg.c @@ -90,7 +90,7 @@ server_msg_dispatch(struct client *c) fatalx("bad MSG_EXITING size"); c->session = NULL; - tty_close(&c->tty, c->flags & CLIENT_SUSPENDED); + tty_close(&c->tty); server_write_client(c, MSG_EXITED, NULL, 0); break; case MSG_UNLOCK: diff --git a/server.c b/server.c index acaf5207..15a5fc94 100644 --- a/server.c +++ b/server.c @@ -902,7 +902,7 @@ server_lost_client(struct client *c) ARRAY_SET(&clients, i, NULL); } - tty_free(&c->tty, c->flags & CLIENT_SUSPENDED); + tty_free(&c->tty); screen_free(&c->status); diff --git a/tmux.h b/tmux.h index cdd8d6ad..060d2bd1 100644 --- a/tmux.h +++ b/tmux.h @@ -868,6 +868,7 @@ struct tty { #define TTY_FREEZE 0x2 #define TTY_ESCAPE 0x4 #define TTY_UTF8 0x8 +#define TTY_STARTED 0x10 int flags; int term_flags; @@ -1164,8 +1165,8 @@ void tty_set_title(struct tty *, const char *); void tty_update_mode(struct tty *, int); void tty_draw_line(struct tty *, struct screen *, u_int, u_int, u_int); int tty_open(struct tty *, const char *, char **); -void tty_close(struct tty *, int); -void tty_free(struct tty *, int); +void tty_close(struct tty *); +void tty_free(struct tty *); void tty_write(void (*)(struct tty *, struct tty_ctx *), struct tty_ctx *); void tty_cmd_alignmenttest(struct tty *, struct tty_ctx *); void tty_cmd_cell(struct tty *, struct tty_ctx *); diff --git a/tty.c b/tty.c index 33acb99d..1584444e 100644 --- a/tty.c +++ b/tty.c @@ -149,6 +149,8 @@ tty_start_tty(struct tty *tty) tty->rupper = UINT_MAX; tty->mode = MODE_CURSOR; + + tty->flags |= TTY_STARTED; } void @@ -156,6 +158,10 @@ tty_stop_tty(struct tty *tty) { struct winsize ws; + if (!(tty->flags & TTY_STARTED)) + return; + tty->flags &= ~TTY_STARTED; + /* * Be flexible about error handling and try not kill the server just * because the fd is invalid. Things like ssh -t can easily leave us @@ -281,7 +287,7 @@ tty_get_acs(struct tty *tty, u_char ch) } void -tty_close(struct tty *tty, int no_stop) +tty_close(struct tty *tty) { if (tty->fd == -1) return; @@ -291,8 +297,7 @@ tty_close(struct tty *tty, int no_stop) tty->log_fd = -1; } - if (!no_stop) - tty_stop_tty(tty); + tty_stop_tty(tty); tty_term_free(tty->term); tty_keys_free(tty); @@ -305,9 +310,9 @@ tty_close(struct tty *tty, int no_stop) } void -tty_free(struct tty *tty, int no_stop) +tty_free(struct tty *tty) { - tty_close(tty, no_stop); + tty_close(tty); if (tty->path != NULL) xfree(tty->path); From 4ec8ade11c23eec4b652cdd7ea47ddf346b7be93 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 11 Aug 2009 20:29:04 +0000 Subject: [PATCH 0245/1180] Add a TTY_OPENED flag and tidy a little. --- tmux.h | 1 + tty.c | 34 +++++++++++++++++----------------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/tmux.h b/tmux.h index 060d2bd1..53590eaf 100644 --- a/tmux.h +++ b/tmux.h @@ -869,6 +869,7 @@ struct tty { #define TTY_ESCAPE 0x4 #define TTY_UTF8 0x8 #define TTY_STARTED 0x10 +#define TTY_OPENED 0x20 int flags; int term_flags; diff --git a/tty.c b/tty.c index 1584444e..1da0c2ff 100644 --- a/tty.c +++ b/tty.c @@ -80,8 +80,11 @@ tty_open(struct tty *tty, const char *overrides, char **cause) tty->log_fd = -1; tty->term = tty_term_find(tty->termname, tty->fd, overrides, cause); - if (tty->term == NULL) - goto error; + if (tty->term == NULL) { + tty_close(tty); + return (-1); + } + tty->flags |= TTY_OPENED; tty->in = buffer_create(BUFSIZ); tty->out = buffer_create(BUFSIZ); @@ -95,12 +98,6 @@ tty_open(struct tty *tty, const char *overrides, char **cause) tty_fill_acs(tty); return (0); - -error: - close(tty->fd); - tty->fd = -1; - - return (-1); } void @@ -289,9 +286,6 @@ tty_get_acs(struct tty *tty, u_char ch) void tty_close(struct tty *tty) { - if (tty->fd == -1) - return; - if (tty->log_fd != -1) { close(tty->log_fd); tty->log_fd = -1; @@ -299,14 +293,20 @@ tty_close(struct tty *tty) tty_stop_tty(tty); - tty_term_free(tty->term); - tty_keys_free(tty); + if (tty->flags & TTY_OPENED) { + tty_term_free(tty->term); + tty_keys_free(tty); - close(tty->fd); - tty->fd = -1; + buffer_destroy(tty->in); + buffer_destroy(tty->out); - buffer_destroy(tty->in); - buffer_destroy(tty->out); + tty->flags &= ~TTY_OPENED; + } + + if (tty->fd != -1) { + close(tty->fd); + tty->fd = -1; + } } void From 4310282a4c52f1885ae2eb80b106c9c03564a0b8 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 11 Aug 2009 21:28:11 +0000 Subject: [PATCH 0246/1180] Have the client pass its stdin fd to the server when identifying itself and have the server use that rather than reopening the tty. If the fd isn't given, use the old behaviour (so no need for a version change). This allows tmux to be used as the shell, so also change so that when working out the command to execute if default-command is empty (the default), tmux will try not execute itself. --- client.c | 3 ++- server-msg.c | 8 ++++---- tmux.h | 2 +- tty.c | 14 +++++++++----- window.c | 19 +++++++++++++++---- 5 files changed, 31 insertions(+), 15 deletions(-) diff --git a/client.c b/client.c index a56af84e..0bbe6056 100644 --- a/client.c +++ b/client.c @@ -119,7 +119,8 @@ server_started: if (strlcpy(data.tty, name, sizeof data.tty) >= sizeof data.tty) fatalx("ttyname failed"); - client_write_server(cctx, MSG_IDENTIFY, &data, sizeof data); + imsg_compose(&cctx->ibuf, MSG_IDENTIFY, + PROTOCOL_VERSION, -1, STDIN_FILENO, &data, sizeof data); } return (0); diff --git a/server-msg.c b/server-msg.c index 3e82f90a..286e8bdc 100644 --- a/server-msg.c +++ b/server-msg.c @@ -27,7 +27,7 @@ #include "tmux.h" void server_msg_command(struct client *, struct msg_command_data *); -void server_msg_identify(struct client *, struct msg_identify_data *); +void server_msg_identify(struct client *, struct msg_identify_data *, int); void server_msg_resize(struct client *, struct msg_resize_data *); void printflike2 server_msg_command_error(struct cmd_ctx *, const char *, ...); @@ -76,7 +76,7 @@ server_msg_dispatch(struct client *c) fatalx("bad MSG_IDENTIFY size"); memcpy(&identifydata, imsg.data, sizeof identifydata); - server_msg_identify(c, &identifydata); + server_msg_identify(c, &identifydata, imsg.fd); break; case MSG_RESIZE: if (datalen != sizeof resizedata) @@ -235,7 +235,7 @@ error: } void -server_msg_identify(struct client *c, struct msg_identify_data *data) +server_msg_identify(struct client *c, struct msg_identify_data *data, int fd) { c->tty.sx = data->sx; c->tty.sy = data->sy; @@ -247,7 +247,7 @@ server_msg_identify(struct client *c, struct msg_identify_data *data) data->tty[(sizeof data->tty) - 1] = '\0'; data->term[(sizeof data->term) - 1] = '\0'; - tty_init(&c->tty, data->tty, data->term); + tty_init(&c->tty, fd, data->tty, data->term); if (data->flags & IDENTIFY_UTF8) c->tty.flags |= TTY_UTF8; if (data->flags & IDENTIFY_256COLOURS) diff --git a/tmux.h b/tmux.h index 53590eaf..9b2e6642 100644 --- a/tmux.h +++ b/tmux.h @@ -1158,7 +1158,7 @@ void tty_putcode2(struct tty *, enum tty_code_code, int, int); void tty_puts(struct tty *, const char *); void tty_putc(struct tty *, u_char); void tty_pututf8(struct tty *, const struct grid_utf8 *); -void tty_init(struct tty *, char *, char *); +void tty_init(struct tty *, int, char *, char *); void tty_start_tty(struct tty *); void tty_stop_tty(struct tty *); void tty_detect_utf8(struct tty *); diff --git a/tty.c b/tty.c index 1da0c2ff..d850347a 100644 --- a/tty.c +++ b/tty.c @@ -45,9 +45,11 @@ void tty_cell(struct tty *, const struct grid_cell *, const struct grid_utf8 *); void -tty_init(struct tty *tty, char *path, char *term) +tty_init(struct tty *tty, int fd, char *path, char *term) { tty->path = xstrdup(path); + tty->fd = fd; + if (term == NULL || *term == '\0') tty->termname = xstrdup("unknown"); else @@ -59,12 +61,14 @@ tty_init(struct tty *tty, char *path, char *term) int tty_open(struct tty *tty, const char *overrides, char **cause) { - int mode; + int mode; - tty->fd = open(tty->path, O_RDWR|O_NONBLOCK); if (tty->fd == -1) { - xasprintf(cause, "%s: %s", tty->path, strerror(errno)); - return (-1); + tty->fd = open(tty->path, O_RDWR|O_NONBLOCK); + if (tty->fd == -1) { + xasprintf(cause, "%s: %s", tty->path, strerror(errno)); + return (-1); + } } if ((mode = fcntl(tty->fd, F_GETFL)) == -1) diff --git a/window.c b/window.c index 3976d7cc..d24d789b 100644 --- a/window.c +++ b/window.c @@ -61,18 +61,29 @@ RB_GENERATE(winlinks, winlink, entry, winlink_cmp); const char * window_default_command(void) { - const char *shell; + const char *shell, *ptr; struct passwd *pw; shell = getenv("SHELL"); if (shell != NULL && *shell != '\0') - return (shell); + goto found; pw = getpwuid(getuid()); - if (pw != NULL && pw->pw_shell != NULL && *pw->pw_shell != '\0') - return (pw->pw_shell); + if (pw != NULL && pw->pw_shell != NULL && *pw->pw_shell != '\0') { + shell = pw->pw_shell; + goto found; + } return (_PATH_BSHELL); + +found: + if ((ptr = strrchr(shell, '/')) != NULL) + ptr++; + else + ptr = shell; + if (strcmp(ptr, __progname) == 0) + return (_PATH_BSHELL); + return (shell); } int From e0a19abb99aebcee544c451ff5e99f6a59d42d0c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 11 Aug 2009 22:34:17 +0000 Subject: [PATCH 0247/1180] Initialise log_fd to -1, prevents spurious disconnection of the client when it ends up as fd 0 (likely if the server is started with "tmux start"). Also add some extra debugging messages to server.c. --- server.c | 3 +++ tty.c | 1 + 2 files changed, 4 insertions(+) diff --git a/server.c b/server.c index 15a5fc94..eb8843f5 100644 --- a/server.c +++ b/server.c @@ -110,6 +110,7 @@ server_create_client(int fd) } } ARRAY_ADD(&clients, c); + log_debug("new client %d", fd); } /* Find client index. */ @@ -257,6 +258,7 @@ server_main(int srv_fd) time_t now, last; siginit(); + log_debug("server socket is %d", srv_fd); last = time(NULL); @@ -901,6 +903,7 @@ server_lost_client(struct client *c) if (ARRAY_ITEM(&clients, i) == c) ARRAY_SET(&clients, i, NULL); } + log_debug("lost client %d", c->ibuf.fd); tty_free(&c->tty); diff --git a/tty.c b/tty.c index d850347a..c6904409 100644 --- a/tty.c +++ b/tty.c @@ -49,6 +49,7 @@ tty_init(struct tty *tty, int fd, char *path, char *term) { tty->path = xstrdup(path); tty->fd = fd; + tty->log_fd = -1; if (term == NULL || *term == '\0') tty->termname = xstrdup("unknown"); From 85e8b70625c415e25b332e59152f6383a49afa5d Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 12 Aug 2009 06:04:28 +0000 Subject: [PATCH 0248/1180] imsg closes the fd after sending, so dup() STDIN_FILENO before passing it to the parent, otherwise TIOCGWINSZ will fail when the window is resized (that could actually be moved into the server but this is more future-proof and avoids breaking the protocol). --- client.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/client.c b/client.c index 0bbe6056..359d9482 100644 --- a/client.c +++ b/client.c @@ -44,7 +44,7 @@ client_init(char *path, struct client_ctx *cctx, int cmdflags, int flags) struct msg_identify_data data; struct winsize ws; size_t size; - int fd, mode; + int fd, fd2, mode; char *name, *term; char rpathbuf[MAXPATHLEN]; @@ -119,8 +119,9 @@ server_started: if (strlcpy(data.tty, name, sizeof data.tty) >= sizeof data.tty) fatalx("ttyname failed"); + fd2 = dup(STDIN_FILENO); imsg_compose(&cctx->ibuf, MSG_IDENTIFY, - PROTOCOL_VERSION, -1, STDIN_FILENO, &data, sizeof data); + PROTOCOL_VERSION, -1, fd2, &data, sizeof data); } return (0); From 9a52ef099a28eb1c80f265d122567a4ccf31ba3a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 12 Aug 2009 09:14:25 +0000 Subject: [PATCH 0249/1180] When started as the shell, __progname contains a leading -, so hardcode "tmux" for socket path and log files, and strip it when working out the shell. --- tmux.c | 5 ++--- window.c | 6 +++++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/tmux.c b/tmux.c index 34416e30..65772f92 100644 --- a/tmux.c +++ b/tmux.c @@ -79,8 +79,7 @@ logfile(const char *name) log_close(); if (debug_level > 0) { - xasprintf( - &path, "%s-%s-%ld.log", __progname, name, (long) getpid()); + xasprintf(&path, "tmux-%s-%ld.log", name, (long) getpid()); log_open_file(debug_level, path); xfree(path); } @@ -184,7 +183,7 @@ makesockpath(const char *label) u_int uid; uid = getuid(); - xsnprintf(base, MAXPATHLEN, "%s/%s-%d", _PATH_TMP, __progname, uid); + xsnprintf(base, MAXPATHLEN, "%s/tmux-%d", _PATH_TMP, uid); if (mkdir(base, S_IRWXU) != 0 && errno != EEXIST) return (NULL); diff --git a/window.c b/window.c index d24d789b..cfef2b24 100644 --- a/window.c +++ b/window.c @@ -62,6 +62,7 @@ const char * window_default_command(void) { const char *shell, *ptr; + char *progname; struct passwd *pw; shell = getenv("SHELL"); @@ -81,7 +82,10 @@ found: ptr++; else ptr = shell; - if (strcmp(ptr, __progname) == 0) + progname = __progname; + if (*progname == '-') + progname++; + if (strcmp(ptr, progname) == 0) return (_PATH_BSHELL); return (shell); } From bc497dbb92268004e33c4f1deb09d3cbbeaa48a0 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 12 Aug 2009 09:41:59 +0000 Subject: [PATCH 0250/1180] A tty context must not be modified as it may be reused to update multiple clients, so make it const. Also fix an actual modification which caused a hang when a session was connected to multiple terminals at least one of which was missing ich/ich1. --- tmux.h | 33 +++++++++++++++++---------------- tty.c | 40 +++++++++++++++++++++------------------- 2 files changed, 38 insertions(+), 35 deletions(-) diff --git a/tmux.h b/tmux.h index 9b2e6642..af59eba1 100644 --- a/tmux.h +++ b/tmux.h @@ -1168,22 +1168,23 @@ void tty_draw_line(struct tty *, struct screen *, u_int, u_int, u_int); int tty_open(struct tty *, const char *, char **); void tty_close(struct tty *); void tty_free(struct tty *); -void tty_write(void (*)(struct tty *, struct tty_ctx *), struct tty_ctx *); -void tty_cmd_alignmenttest(struct tty *, struct tty_ctx *); -void tty_cmd_cell(struct tty *, struct tty_ctx *); -void tty_cmd_clearendofline(struct tty *, struct tty_ctx *); -void tty_cmd_clearendofscreen(struct tty *, struct tty_ctx *); -void tty_cmd_clearline(struct tty *, struct tty_ctx *); -void tty_cmd_clearscreen(struct tty *, struct tty_ctx *); -void tty_cmd_clearstartofline(struct tty *, struct tty_ctx *); -void tty_cmd_clearstartofscreen(struct tty *, struct tty_ctx *); -void tty_cmd_deletecharacter(struct tty *, struct tty_ctx *); -void tty_cmd_deleteline(struct tty *, struct tty_ctx *); -void tty_cmd_insertcharacter(struct tty *, struct tty_ctx *); -void tty_cmd_insertline(struct tty *, struct tty_ctx *); -void tty_cmd_linefeed(struct tty *, struct tty_ctx *); -void tty_cmd_utf8character(struct tty *, struct tty_ctx *); -void tty_cmd_reverseindex(struct tty *, struct tty_ctx *); +void tty_write(void (*)( + struct tty *, const struct tty_ctx *), const struct tty_ctx *); +void tty_cmd_alignmenttest(struct tty *, const struct tty_ctx *); +void tty_cmd_cell(struct tty *, const struct tty_ctx *); +void tty_cmd_clearendofline(struct tty *, const struct tty_ctx *); +void tty_cmd_clearendofscreen(struct tty *, const struct tty_ctx *); +void tty_cmd_clearline(struct tty *, const struct tty_ctx *); +void tty_cmd_clearscreen(struct tty *, const struct tty_ctx *); +void tty_cmd_clearstartofline(struct tty *, const struct tty_ctx *); +void tty_cmd_clearstartofscreen(struct tty *, const struct tty_ctx *); +void tty_cmd_deletecharacter(struct tty *, const struct tty_ctx *); +void tty_cmd_deleteline(struct tty *, const struct tty_ctx *); +void tty_cmd_insertcharacter(struct tty *, const struct tty_ctx *); +void tty_cmd_insertline(struct tty *, const struct tty_ctx *); +void tty_cmd_linefeed(struct tty *, const struct tty_ctx *); +void tty_cmd_utf8character(struct tty *, const struct tty_ctx *); +void tty_cmd_reverseindex(struct tty *, const struct tty_ctx *); /* tty-term.c */ extern struct tty_terms tty_terms; diff --git a/tty.c b/tty.c index c6904409..1c985dcc 100644 --- a/tty.c +++ b/tty.c @@ -38,7 +38,7 @@ void tty_attributes(struct tty *, const struct grid_cell *); void tty_attributes_fg(struct tty *, const struct grid_cell *); void tty_attributes_bg(struct tty *, const struct grid_cell *); -void tty_redraw_region(struct tty *, struct tty_ctx *); +void tty_redraw_region(struct tty *, const struct tty_ctx *); void tty_emulate_repeat( struct tty *, enum tty_code_code, enum tty_code_code, u_int); void tty_cell(struct tty *, @@ -461,7 +461,7 @@ tty_emulate_repeat( * width of the terminal. */ void -tty_redraw_region(struct tty *tty, struct tty_ctx *ctx) +tty_redraw_region(struct tty *tty, const struct tty_ctx *ctx) { struct window_pane *wp = ctx->wp; struct screen *s = wp->screen; @@ -532,7 +532,8 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int py, u_int ox, u_int oy) } void -tty_write(void (*cmdfn)(struct tty *, struct tty_ctx *), struct tty_ctx *ctx) +tty_write(void (*cmdfn)( + struct tty *, const struct tty_ctx *), const struct tty_ctx *ctx) { struct window_pane *wp = ctx->wp; struct client *c; @@ -563,10 +564,11 @@ tty_write(void (*cmdfn)(struct tty *, struct tty_ctx *), struct tty_ctx *ctx) } void -tty_cmd_insertcharacter(struct tty *tty, struct tty_ctx *ctx) +tty_cmd_insertcharacter(struct tty *tty, const struct tty_ctx *ctx) { struct window_pane *wp = ctx->wp; struct screen *s = wp->screen; + u_int i; if (wp->xoff != 0 || screen_size_x(s) < tty->sx) { tty_draw_line(tty, wp->screen, ctx->ocy, wp->xoff, wp->yoff); @@ -581,14 +583,14 @@ tty_cmd_insertcharacter(struct tty *tty, struct tty_ctx *ctx) tty_emulate_repeat(tty, TTYC_ICH, TTYC_ICH1, ctx->num); else { tty_putcode(tty, TTYC_SMIR); - while (ctx->num-- > 0) + for (i = 0; i < ctx->num; i++) tty_putc(tty, ' '); tty_putcode(tty, TTYC_RMIR); } } void -tty_cmd_deletecharacter(struct tty *tty, struct tty_ctx *ctx) +tty_cmd_deletecharacter(struct tty *tty, const struct tty_ctx *ctx) { struct window_pane *wp = ctx->wp; struct screen *s = wp->screen; @@ -605,7 +607,7 @@ tty_cmd_deletecharacter(struct tty *tty, struct tty_ctx *ctx) } void -tty_cmd_insertline(struct tty *tty, struct tty_ctx *ctx) +tty_cmd_insertline(struct tty *tty, const struct tty_ctx *ctx) { struct window_pane *wp = ctx->wp; struct screen *s = wp->screen; @@ -625,7 +627,7 @@ tty_cmd_insertline(struct tty *tty, struct tty_ctx *ctx) } void -tty_cmd_deleteline(struct tty *tty, struct tty_ctx *ctx) +tty_cmd_deleteline(struct tty *tty, const struct tty_ctx *ctx) { struct window_pane *wp = ctx->wp; struct screen *s = wp->screen; @@ -645,7 +647,7 @@ tty_cmd_deleteline(struct tty *tty, struct tty_ctx *ctx) } void -tty_cmd_clearline(struct tty *tty, struct tty_ctx *ctx) +tty_cmd_clearline(struct tty *tty, const struct tty_ctx *ctx) { struct window_pane *wp = ctx->wp; struct screen *s = wp->screen; @@ -664,7 +666,7 @@ tty_cmd_clearline(struct tty *tty, struct tty_ctx *ctx) } void -tty_cmd_clearendofline(struct tty *tty, struct tty_ctx *ctx) +tty_cmd_clearendofline(struct tty *tty, const struct tty_ctx *ctx) { struct window_pane *wp = ctx->wp; struct screen *s = wp->screen; @@ -683,7 +685,7 @@ tty_cmd_clearendofline(struct tty *tty, struct tty_ctx *ctx) } void -tty_cmd_clearstartofline(struct tty *tty, struct tty_ctx *ctx) +tty_cmd_clearstartofline(struct tty *tty, const struct tty_ctx *ctx) { struct window_pane *wp = ctx->wp; u_int i; @@ -701,7 +703,7 @@ tty_cmd_clearstartofline(struct tty *tty, struct tty_ctx *ctx) } void -tty_cmd_reverseindex(struct tty *tty, struct tty_ctx *ctx) +tty_cmd_reverseindex(struct tty *tty, const struct tty_ctx *ctx) { struct window_pane *wp = ctx->wp; struct screen *s = wp->screen; @@ -723,7 +725,7 @@ tty_cmd_reverseindex(struct tty *tty, struct tty_ctx *ctx) } void -tty_cmd_linefeed(struct tty *tty, struct tty_ctx *ctx) +tty_cmd_linefeed(struct tty *tty, const struct tty_ctx *ctx) { struct window_pane *wp = ctx->wp; struct screen *s = wp->screen; @@ -745,7 +747,7 @@ tty_cmd_linefeed(struct tty *tty, struct tty_ctx *ctx) } void -tty_cmd_clearendofscreen(struct tty *tty, struct tty_ctx *ctx) +tty_cmd_clearendofscreen(struct tty *tty, const struct tty_ctx *ctx) { struct window_pane *wp = ctx->wp; struct screen *s = wp->screen; @@ -780,7 +782,7 @@ tty_cmd_clearendofscreen(struct tty *tty, struct tty_ctx *ctx) } void -tty_cmd_clearstartofscreen(struct tty *tty, struct tty_ctx *ctx) +tty_cmd_clearstartofscreen(struct tty *tty, const struct tty_ctx *ctx) { struct window_pane *wp = ctx->wp; struct screen *s = wp->screen; @@ -809,7 +811,7 @@ tty_cmd_clearstartofscreen(struct tty *tty, struct tty_ctx *ctx) } void -tty_cmd_clearscreen(struct tty *tty, struct tty_ctx *ctx) +tty_cmd_clearscreen(struct tty *tty, const struct tty_ctx *ctx) { struct window_pane *wp = ctx->wp; struct screen *s = wp->screen; @@ -838,7 +840,7 @@ tty_cmd_clearscreen(struct tty *tty, struct tty_ctx *ctx) } void -tty_cmd_alignmenttest(struct tty *tty, struct tty_ctx *ctx) +tty_cmd_alignmenttest(struct tty *tty, const struct tty_ctx *ctx) { struct window_pane *wp = ctx->wp; struct screen *s = wp->screen; @@ -856,7 +858,7 @@ tty_cmd_alignmenttest(struct tty *tty, struct tty_ctx *ctx) } void -tty_cmd_cell(struct tty *tty, struct tty_ctx *ctx) +tty_cmd_cell(struct tty *tty, const struct tty_ctx *ctx) { struct window_pane *wp = ctx->wp; @@ -866,7 +868,7 @@ tty_cmd_cell(struct tty *tty, struct tty_ctx *ctx) } void -tty_cmd_utf8character(struct tty *tty, struct tty_ctx *ctx) +tty_cmd_utf8character(struct tty *tty, const struct tty_ctx *ctx) { u_char *ptr = ctx->ptr; size_t i; From 7a005b91b373aad3cfa877081b1df9c8d52f1d58 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 13 Aug 2009 12:15:45 +0000 Subject: [PATCH 0251/1180] If the client passes zero for the window size in the identify message (which it can, for example on serial terminals), reset it to 80x25, same as for resize messages. Problem reported by kettenis@. --- server-msg.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/server-msg.c b/server-msg.c index 286e8bdc..e8aea526 100644 --- a/server-msg.c +++ b/server-msg.c @@ -238,7 +238,11 @@ void server_msg_identify(struct client *c, struct msg_identify_data *data, int fd) { c->tty.sx = data->sx; + if (c->tty.sx == 0) + c->tty.sx = 80; c->tty.sy = data->sy; + if (c->tty.sy == 0) + c->tty.sy = 25; c->cwd = NULL; data->cwd[(sizeof data->cwd) - 1] = '\0'; From b02e429788af45110a09139069023e164f0a23be Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 13 Aug 2009 16:24:33 +0000 Subject: [PATCH 0252/1180] It was originally intended that scroll mode would show content that was currently off-screen due to resize, but somewhere along the way this got lost. Restore this behaviour to scroll mode by fixing screen_write_copy to read up to the saved line length rather than the current screen width. Copy mode remains unaltered for now. --- screen-write.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/screen-write.c b/screen-write.c index 4e66b076..d735d450 100644 --- a/screen-write.c +++ b/screen-write.c @@ -184,24 +184,24 @@ screen_write_copy(struct screen_write_ctx *ctx, { struct screen *s = ctx->s; struct grid *gd = src->grid; + struct grid_line *gl; const struct grid_cell *gc; - struct grid_utf8 *gu; u_char *udata; u_int xx, yy, cx, cy; cx = s->cx; cy = s->cy; for (yy = py; yy < py + ny; yy++) { + gl = &gd->linedata[yy]; for (xx = px; xx < px + nx; xx++) { - if (xx >= gd->sx || yy >= gd->hsize + gd->sy) - gc = &grid_default_cell; - else - gc = grid_peek_cell(gd, xx, yy); + udata = NULL; - udata = NULL; - if (gc->flags & GRID_FLAG_UTF8) { - gu = grid_get_utf8(gd, xx, yy); - udata = gu->data; + if (xx >= gl->cellsize || yy >= gd->hsize + gd->sy) + gc = &grid_default_cell; + else { + gc = &gl->celldata[xx]; + if (gc->flags & GRID_FLAG_UTF8) + udata = gl->utf8data[xx].data; } screen_write_cell(ctx, gc, udata); From 2e3bb5a51193269305eca3d689b6c66d08b2530a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 13 Aug 2009 16:48:43 +0000 Subject: [PATCH 0253/1180] Redraw the screen after resizing. --- window-copy.c | 1 + 1 file changed, 1 insertion(+) diff --git a/window-copy.c b/window-copy.c index 06c10d9c..e945ac19 100644 --- a/window-copy.c +++ b/window-copy.c @@ -160,6 +160,7 @@ window_copy_resize(struct window_pane *wp, u_int sx, u_int sy) window_copy_write_lines(wp, &ctx, 0, screen_size_y(s) - 1); screen_write_stop(&ctx); window_copy_update_selection(wp); + window_copy_redraw_screen(wp); } void From 52793e7a3fc7f53b173ee887c221ff4ed38499e8 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 13 Aug 2009 19:03:59 +0000 Subject: [PATCH 0254/1180] When creating a new session from the command-line where there is an external terminal, copy the termios(4) special characters and use them for new windows created in the new session. Suggested by Theo. --- cmd-new-session.c | 25 ++++++++++++++++++++++++- cmd-respawn-window.c | 2 +- cmd-split-window.c | 2 +- session.c | 8 +++++--- tmux.1 | 4 ++++ tmux.h | 13 ++++++++----- window.c | 11 ++++++----- 7 files changed, 49 insertions(+), 16 deletions(-) diff --git a/cmd-new-session.c b/cmd-new-session.c index 61f18c8f..5dc27879 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -18,6 +18,12 @@ #include +#include +#include + +#define TTYDEFCHARS +#include + #include "tmux.h" /* @@ -109,6 +115,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) struct cmd_new_session_data *data = self->data; struct session *s; struct environ env; + struct termios tio; const char *update; char *overrides, *cmd, *cwd, *cause; int detached; @@ -192,8 +199,24 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) if (ctx->cmdclient != NULL) environ_update(update, &ctx->cmdclient->environ, &env); + /* + * Fill in the termios settings used for new windows in this session; + * if there is a command client, use the control characters from it. + */ + if (ctx->cmdclient != NULL && ctx->cmdclient->tty.fd != -1) { + if (tcgetattr(ctx->cmdclient->tty.fd, &tio) != 0) + fatal("tcgetattr failed"); + } else + memcpy(tio.c_cc, ttydefchars, sizeof tio.c_cc); + tio.c_iflag = TTYDEF_IFLAG; + tio.c_oflag = TTYDEF_OFLAG; + tio.c_lflag = TTYDEF_LFLAG; + tio.c_cflag = TTYDEF_CFLAG; + tio.c_ispeed = TTYDEF_SPEED; + tio.c_ospeed = TTYDEF_SPEED; + /* Create the new session. */ - s = session_create(data->newname, cmd, cwd, &env, sx, sy, &cause); + s = session_create(data->newname, cmd, cwd, &env, &tio, sx, sy, &cause); if (s == NULL) { ctx->error(ctx, "create session failed: %s", cause); xfree(cause); diff --git a/cmd-respawn-window.c b/cmd-respawn-window.c index 735c637b..8ed678b1 100644 --- a/cmd-respawn-window.c +++ b/cmd-respawn-window.c @@ -75,7 +75,7 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_ctx *ctx) window_destroy_panes(w); TAILQ_INSERT_HEAD(&w->panes, wp, entry); window_pane_resize(wp, w->sx, w->sy); - if (window_pane_spawn(wp, data->arg, NULL, &env, &cause) != 0) { + if (window_pane_spawn(wp, data->arg, NULL, &env, &s->tio, &cause) != 0) { ctx->error(ctx, "respawn window failed: %s", cause); xfree(cause); environ_free(&env); diff --git a/cmd-split-window.c b/cmd-split-window.c index 70004a14..09bd214e 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -184,7 +184,7 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) type = LAYOUT_LEFTRIGHT; wp = window_add_pane(w, hlimit); - if (window_pane_spawn(wp, cmd, cwd, &env, &cause) != 0) + if (window_pane_spawn(wp, cmd, cwd, &env, &s->tio, &cause) != 0) goto error; if (layout_split_pane(w->active, type, size, wp) != 0) { cause = xstrdup("pane too small"); diff --git a/session.c b/session.c index f53e14da..9b7beeb5 100644 --- a/session.c +++ b/session.c @@ -113,7 +113,7 @@ session_find(const char *name) /* Create a new session. */ struct session * session_create(const char *name, const char *cmd, const char *cwd, - struct environ *env, u_int sx, u_int sy, char **cause) + struct environ *env, struct termios *tio, u_int sx, u_int sy, char **cause) { struct session *s; u_int i; @@ -131,6 +131,7 @@ session_create(const char *name, const char *cmd, const char *cwd, environ_init(&s->environ); if (env != NULL) environ_copy(env, &s->environ); + memcpy(&s->tio, tio, sizeof s->tio); s->sx = sx; s->sy = sy; @@ -200,7 +201,7 @@ session_index(struct session *s, u_int *i) /* Create a new window on a session. */ struct winlink * -session_new(struct session *s, +session_new(struct session *s, const char *name, const char *cmd, const char *cwd, int idx, char **cause) { struct window *w; @@ -213,7 +214,8 @@ session_new(struct session *s, server_fill_environ(s, &env); hlimit = options_get_number(&s->options, "history-limit"); - w = window_create(name, cmd, cwd, &env, s->sx, s->sy, hlimit, cause); + w = window_create( + name, cmd, cwd, &env, &s->tio, s->sx, s->sy, hlimit, cause); if (w == NULL) { environ_free(&env); return (NULL); diff --git a/tmux.1 b/tmux.1 index 8621c3f4..faa44ad6 100644 --- a/tmux.1 +++ b/tmux.1 @@ -398,6 +398,10 @@ is given. and .Ar command are the name of and command to execute in the initial window. +.Pp +If run from a terminal, any +.Xr termios 4 +special characters are saved and used for new windows in the new session. .It Ic refresh-client Op Fl t Ar target-client .D1 (alias: Ic refresh ) Refresh the current client if bound to a key, or a single client if one is given diff --git a/tmux.h b/tmux.h index af59eba1..b15d02bf 100644 --- a/tmux.h +++ b/tmux.h @@ -803,6 +803,8 @@ struct session { #define SESSION_UNATTACHED 0x1 /* not attached to any clients */ int flags; + struct termios tio; + struct environ environ; }; ARRAY_DECL(sessions, struct session *); @@ -1574,7 +1576,8 @@ void winlink_stack_remove(struct winlink_stack *, struct winlink *); int window_index(struct window *, u_int *); struct window *window_create1(u_int, u_int); struct window *window_create(const char *, const char *, const char *, - struct environ *, u_int, u_int, u_int, char **); + struct environ *, struct termios *, u_int, u_int, u_int, + char **); void window_destroy(struct window *); void window_set_active_pane(struct window *, struct window_pane *); struct window_pane *window_add_pane(struct window *, u_int); @@ -1586,8 +1589,8 @@ u_int window_count_panes(struct window *); void window_destroy_panes(struct window *); struct window_pane *window_pane_create(struct window *, u_int, u_int, u_int); void window_pane_destroy(struct window_pane *); -int window_pane_spawn(struct window_pane *, - const char *, const char *, struct environ *, char **); +int window_pane_spawn(struct window_pane *, const char *, + const char *, struct environ *, struct termios *, char **); void window_pane_resize(struct window_pane *, u_int, u_int); int window_pane_set_mode( struct window_pane *, const struct window_mode *); @@ -1666,8 +1669,8 @@ void session_alert_cancel(struct session *, struct winlink *); int session_alert_has(struct session *, struct winlink *, int); int session_alert_has_window(struct session *, struct window *, int); struct session *session_find(const char *); -struct session *session_create(const char *, const char *, - const char *, struct environ *, u_int, u_int, char **); +struct session *session_create(const char *, const char *, const char *, + struct environ *, struct termios *, u_int, u_int, char **); void session_destroy(struct session *); int session_index(struct session *, u_int *); struct winlink *session_new(struct session *, diff --git a/window.c b/window.c index cfef2b24..eccaa4e5 100644 --- a/window.c +++ b/window.c @@ -269,7 +269,8 @@ window_create1(u_int sx, u_int sy) struct window * window_create(const char *name, const char *cmd, const char *cwd, - struct environ *env, u_int sx, u_int sy, u_int hlimit, char **cause) + struct environ *env, struct termios *tio, u_int sx, u_int sy, u_int hlimit, + char **cause) { struct window *w; struct window_pane *wp; @@ -277,7 +278,7 @@ window_create(const char *name, const char *cmd, const char *cwd, w = window_create1(sx, sy); wp = window_add_pane(w, hlimit); layout_init(w); - if (window_pane_spawn(wp, cmd, cwd, env, cause) != 0) { + if (window_pane_spawn(wp, cmd, cwd, env, tio, cause) != 0) { window_destroy(w); return (NULL); } @@ -470,8 +471,8 @@ window_pane_destroy(struct window_pane *wp) } int -window_pane_spawn(struct window_pane *wp, - const char *cmd, const char *cwd, struct environ *env, char **cause) +window_pane_spawn(struct window_pane *wp, const char *cmd, + const char *cwd, struct environ *env, struct termios *tio, char **cause) { struct winsize ws; int mode; @@ -505,7 +506,7 @@ window_pane_spawn(struct window_pane *wp, tv.tv_usec = NAME_INTERVAL * 1000L; timeradd(&wp->window->name_timer, &tv, &wp->window->name_timer); - switch (wp->pid = forkpty(&wp->fd, wp->tty, NULL, &ws)) { + switch (wp->pid = forkpty(&wp->fd, wp->tty, tio, &ws)) { case -1: wp->fd = -1; xasprintf(cause, "%s: %s", cmd, strerror(errno)); From e2ff51f93f934c8e5317dbafe95a1783b16287a0 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 13 Aug 2009 19:16:14 +0000 Subject: [PATCH 0255/1180] Rather than telling the client to exit in the function when creating a new session detached, let the caller do it. Allows "tmux new -d \; attach" to work. --- cmd-new-session.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cmd-new-session.c b/cmd-new-session.c index 5dc27879..64337e6d 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -239,8 +239,6 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) if (ctx->cmdclient != NULL) { if (!detached) server_write_client(ctx->cmdclient, MSG_READY, NULL, 0); - else - server_write_client(ctx->cmdclient, MSG_EXIT, NULL, 0); } /* Set the client to the new session. */ @@ -255,7 +253,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) } recalculate_sizes(); - return (1); /* 1 means don't tell command client to exit */ + return (!detached); /* 1 means don't tell command client to exit */ } void From 3026118c702fc0f17b860197b5242816927bbadb Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 13 Aug 2009 19:35:20 +0000 Subject: [PATCH 0256/1180] Allowing copy mode to scroll left and right is annoying, so limit it to the real screen width. To indicate the cursor is at the end of the line rather than the cell before, put a '$' in the last cell. Also clear the selection when the terminal is resized to avoid tmux getting confused. --- window-copy.c | 267 +++++++++++++------------------------------------- 1 file changed, 68 insertions(+), 199 deletions(-) diff --git a/window-copy.c b/window-copy.c index e945ac19..be810ee3 100644 --- a/window-copy.c +++ b/window-copy.c @@ -35,12 +35,8 @@ void window_copy_write_line( struct window_pane *, struct screen_write_ctx *, u_int); void window_copy_write_lines( struct window_pane *, struct screen_write_ctx *, u_int, u_int); -void window_copy_write_column( - struct window_pane *, struct screen_write_ctx *, u_int); -void window_copy_write_columns( - struct window_pane *, struct screen_write_ctx *, u_int, u_int); -void window_copy_update_cursor(struct window_pane *); +void window_copy_update_cursor(struct window_pane *, u_int, u_int); void window_copy_start_selection(struct window_pane *); int window_copy_update_selection(struct window_pane *); void window_copy_copy_selection(struct window_pane *, struct client *); @@ -48,7 +44,6 @@ void window_copy_copy_line( struct window_pane *, char **, size_t *, u_int, u_int, u_int); int window_copy_is_space(struct window_pane *, u_int, u_int); u_int window_copy_find_length(struct window_pane *, u_int); -void window_copy_set_cursor_x(struct window_pane *, u_int); void window_copy_cursor_start_of_line(struct window_pane *); void window_copy_cursor_back_to_indentation(struct window_pane *); void window_copy_cursor_end_of_line(struct window_pane *); @@ -58,8 +53,6 @@ void window_copy_cursor_up(struct window_pane *); void window_copy_cursor_down(struct window_pane *); void window_copy_cursor_next_word(struct window_pane *); void window_copy_cursor_previous_word(struct window_pane *); -void window_copy_scroll_left(struct window_pane *, u_int); -void window_copy_scroll_right(struct window_pane *, u_int); void window_copy_scroll_up(struct window_pane *, u_int); void window_copy_scroll_down(struct window_pane *, u_int); @@ -77,7 +70,6 @@ struct window_copy_mode_data { struct mode_key_data mdata; - u_int ox; u_int oy; u_int selx; @@ -97,7 +89,6 @@ window_copy_init(struct window_pane *wp) int keys; wp->modedata = data = xmalloc(sizeof *data); - data->ox = 0; data->oy = 0; data->cx = wp->base.cx; data->cy = wp->base.cy; @@ -156,10 +147,18 @@ window_copy_resize(struct window_pane *wp, u_int sx, u_int sy) struct screen_write_ctx ctx; screen_resize(s, sx, sy); + + if (data->cy > sy - 1) + data->cy = sy - 1; + if (data->cx > sx) + data->cx = sx; + + screen_clear_selection(&data->screen); + screen_write_start(&ctx, NULL, s); window_copy_write_lines(wp, &ctx, 0, screen_size_y(s) - 1); screen_write_stop(&ctx); - window_copy_update_selection(wp); + window_copy_redraw_screen(wp); } @@ -244,16 +243,14 @@ window_copy_mouse(struct window_pane *wp, if (y >= screen_size_y(s)) return; - data->cx = x; - data->cy = y; - + window_copy_update_cursor(wp, x, y); if (window_copy_update_selection(wp)) window_copy_redraw_screen(wp); - window_copy_update_cursor(wp); } void -window_copy_write_line(struct window_pane *wp, struct screen_write_ctx *ctx, u_int py) +window_copy_write_line( + struct window_pane *wp, struct screen_write_ctx *ctx, u_int py) { struct window_copy_mode_data *data = wp->modedata; struct screen *s = &data->screen; @@ -264,18 +261,25 @@ window_copy_write_line(struct window_pane *wp, struct screen_write_ctx *ctx, u_i if (py == 0) { memcpy(&gc, &grid_default_cell, sizeof gc); size = xsnprintf(hdr, sizeof hdr, - "[%u,%u/%u]", data->ox, data->oy, screen_hsize(&wp->base)); + "[%u/%u]", data->oy, screen_hsize(&wp->base)); gc.fg = options_get_number(&wp->window->options, "mode-fg"); gc.bg = options_get_number(&wp->window->options, "mode-bg"); - gc.attr |= options_get_number(&wp->window->options, "mode-attr"); + gc.attr |= options_get_number( + &wp->window->options, "mode-attr"); screen_write_cursormove(ctx, screen_size_x(s) - size, 0); screen_write_puts(ctx, &gc, "%s", hdr); } else size = 0; screen_write_cursormove(ctx, 0, py); - screen_write_copy(ctx, &wp->base, data->ox, (screen_hsize(&wp->base) - + screen_write_copy(ctx, &wp->base, 0, (screen_hsize(&wp->base) - data->oy) + py, screen_size_x(s) - size, 1); + + if (py == data->cy && data->cx == screen_size_x(s)) { + memcpy(&gc, &grid_default_cell, sizeof gc); + screen_write_cursormove(ctx, screen_size_x(s) - 1, py); + screen_write_putc(ctx, &gc, '$'); + } } void @@ -288,28 +292,6 @@ window_copy_write_lines( window_copy_write_line(wp, ctx, py); } -void -window_copy_write_column( - struct window_pane *wp, struct screen_write_ctx *ctx, u_int px) -{ - struct window_copy_mode_data *data = wp->modedata; - struct screen *s = &data->screen; - - screen_write_cursormove(ctx, px, 0); - screen_write_copy(ctx, &wp->base, - data->ox + px, screen_hsize(&wp->base) - data->oy, 1, screen_size_y(s)); -} - -void -window_copy_write_columns( - struct window_pane *wp, struct screen_write_ctx *ctx, u_int px, u_int nx) -{ - u_int xx; - - for (xx = px; xx < px + nx; xx++) - window_copy_write_column(wp, ctx, xx); -} - void window_copy_redraw_lines(struct window_pane *wp, u_int py, u_int ny) { @@ -333,14 +315,24 @@ window_copy_redraw_screen(struct window_pane *wp) } void -window_copy_update_cursor(struct window_pane *wp) +window_copy_update_cursor(struct window_pane *wp, u_int cx, u_int cy) { struct window_copy_mode_data *data = wp->modedata; + struct screen *s = &data->screen; struct screen_write_ctx ctx; + u_int old_cx, old_cy; - screen_write_start(&ctx, wp, NULL); - screen_write_cursormove(&ctx, data->cx, data->cy); - screen_write_stop(&ctx); + old_cx = data->cx; old_cy = data->cy; + data->cx = cx; data->cy = cy; + if (old_cx == screen_size_x(s)) + window_copy_redraw_lines(wp, old_cy, 1); + if (data->cx == screen_size_x(s)) + window_copy_redraw_lines(wp, data->cy, 1); + else { + screen_write_start(&ctx, wp, NULL); + screen_write_cursormove(&ctx, data->cx, data->cy); + screen_write_stop(&ctx); + } } void @@ -349,7 +341,7 @@ window_copy_start_selection(struct window_pane *wp) struct window_copy_mode_data *data = wp->modedata; struct screen *s = &data->screen; - data->selx = data->cx + data->ox; + data->selx = data->cx; data->sely = screen_hsize(&wp->base) + data->cy - data->oy; s->sel.flag = 1; @@ -362,7 +354,7 @@ window_copy_update_selection(struct window_pane *wp) struct window_copy_mode_data *data = wp->modedata; struct screen *s = &data->screen; struct grid_cell gc; - u_int sx, sy, tx, ty; + u_int sx, sy, ty; if (!s->sel.flag) return (0); @@ -373,34 +365,20 @@ window_copy_update_selection(struct window_pane *wp) gc.bg = options_get_number(&wp->window->options, "mode-bg"); gc.attr |= options_get_number(&wp->window->options, "mode-attr"); - /* Find top-left of screen. */ - tx = data->ox; + /* Find top of screen. */ ty = screen_hsize(&wp->base) - data->oy; /* Adjust the selection. */ sx = data->selx; sy = data->sely; - if (sy < ty) { - /* Above it. */ + if (sy < ty) { /* above screen */ sx = 0; sy = 0; - } else if (sy > ty + screen_size_y(s) - 1) { - /* Below it. */ + } else if (sy > ty + screen_size_y(s) - 1) { /* below screen */ sx = screen_size_x(s) - 1; sy = screen_size_y(s) - 1; - } else if (sx < tx) { - /* To the left. */ - sx = 0; - } else if (sx > tx + screen_size_x(s) - 1) { - /* To the right. */ - sx = 0; - sy++; - if (sy > screen_size_y(s) - 1) - sy = screen_size_y(s) - 1; - } else { - sx -= tx; + } else sy -= ty; - } sy = screen_hsize(s) + sy; screen_set_selection( @@ -431,7 +409,7 @@ window_copy_copy_selection(struct window_pane *wp, struct client *c) */ /* Find start and end. */ - xx = data->cx + data->ox; + xx = data->cx; yy = screen_hsize(&wp->base) + data->cy - data->oy; if (yy < data->sely || (yy == data->sely && xx < data->selx)) { sx = xx; sy = yy; @@ -566,61 +544,14 @@ window_copy_find_length(struct window_pane *wp, u_int py) return (px); } -/* - * Set the cursor X coordinate and scroll horizontally to make it visible. - * Also redraw the selection or the cursor, as needed. - */ -void -window_copy_set_cursor_x(struct window_pane *wp, u_int px) -{ - struct window_copy_mode_data *data = wp->modedata; - struct screen *s = &data->screen; - - /* On screen. */ - if (px > data->ox && px <= data->ox + screen_size_x(s) - 1) - data->cx = px - data->ox; - - /* Off right of screen. */ - if (px > data->ox + screen_size_x(s) - 1) { - /* Move cursor to last and scroll screen. */ - window_copy_scroll_left( - wp, px - data->ox - (screen_size_x(s) - 1)); - data->cx = screen_size_x(s) - 1; - } - - /* Off left of screen. */ - if (px <= data->ox) { - if (px < screen_size_x(s) - 1) { - /* Short enough to fit on screen. */ - window_copy_scroll_right(wp, data->ox); - data->cx = px; - } else { - /* Too long to fit on screen. */ - window_copy_scroll_right( - wp, data->ox - (px - (screen_size_x(s) - 1))); - data->cx = screen_size_x(s) - 1; - } - } - - if (window_copy_update_selection(wp)) - window_copy_redraw_lines(wp, data->cy, 1); - else - window_copy_update_cursor(wp); -} - void window_copy_cursor_start_of_line(struct window_pane *wp) { struct window_copy_mode_data *data = wp->modedata; - if (data->ox != 0) - window_copy_scroll_right(wp, data->ox); - data->cx = 0; - + window_copy_update_cursor(wp, 0, data->cy); if (window_copy_update_selection(wp)) window_copy_redraw_lines(wp, data->cy, 1); - else - window_copy_update_cursor(wp); } void @@ -647,7 +578,9 @@ window_copy_cursor_back_to_indentation(struct window_pane *wp) px++; } - window_copy_set_cursor_x(wp, px); + window_copy_update_cursor(wp, px, data->cy); + if (window_copy_update_selection(wp)) + window_copy_redraw_lines(wp, data->cy, 1); } void @@ -659,7 +592,9 @@ window_copy_cursor_end_of_line(struct window_pane *wp) py = screen_hsize(&wp->base) + data->cy - data->oy; px = window_copy_find_length(wp, py); - window_copy_set_cursor_x(wp, px); + window_copy_update_cursor(wp, px, data->cy); + if (window_copy_update_selection(wp)) + window_copy_redraw_lines(wp, data->cy, 1); } void @@ -668,18 +603,12 @@ window_copy_cursor_left(struct window_pane *wp) struct window_copy_mode_data *data = wp->modedata; if (data->cx == 0) { - if (data->ox > 0) - window_copy_scroll_right(wp, 1); - else { - window_copy_cursor_up(wp); - window_copy_cursor_end_of_line(wp); - } + window_copy_cursor_up(wp); + window_copy_cursor_end_of_line(wp); } else { - data->cx--; + window_copy_update_cursor(wp, data->cx - 1, data->cy); if (window_copy_update_selection(wp)) window_copy_redraw_lines(wp, data->cy, 1); - else - window_copy_update_cursor(wp); } } @@ -696,11 +625,9 @@ window_copy_cursor_right(struct window_pane *wp) window_copy_cursor_start_of_line(wp); window_copy_cursor_down(wp); } else { - data->cx++; + window_copy_update_cursor(wp, data->cx + 1, data->cy); if (window_copy_update_selection(wp)) window_copy_redraw_lines(wp, data->cy, 1); - else - window_copy_update_cursor(wp); } } @@ -716,17 +643,15 @@ window_copy_cursor_up(struct window_pane *wp) if (data->cy == 0) window_copy_scroll_down(wp, 1); else { - data->cy--; + window_copy_update_cursor(wp, data->cx, data->cy - 1); if (window_copy_update_selection(wp)) window_copy_redraw_lines(wp, data->cy, 2); - else - window_copy_update_cursor(wp); } py = screen_hsize(&wp->base) + data->cy - data->oy; px = window_copy_find_length(wp, py); - if (data->cx + data->ox >= px || data->cx + data->ox >= ox) + if (data->cx >= px || data->cx >= ox) window_copy_cursor_end_of_line(wp); } @@ -743,17 +668,15 @@ window_copy_cursor_down(struct window_pane *wp) if (data->cy == screen_size_y(s) - 1) window_copy_scroll_up(wp, 1); else { - data->cy++; + window_copy_update_cursor(wp, data->cx, data->cy + 1); if (window_copy_update_selection(wp)) window_copy_redraw_lines(wp, data->cy - 1, 2); - else - window_copy_update_cursor(wp); } py = screen_hsize(&wp->base) + data->cy - data->oy; px = window_copy_find_length(wp, py); - if (data->cx + data->ox >= px || data->cx + data->ox >= ox) + if (data->cx >= px || data->cx >= ox) window_copy_cursor_end_of_line(wp); } @@ -764,7 +687,7 @@ window_copy_cursor_next_word(struct window_pane *wp) struct screen *s = &data->screen; u_int px, py, xx, skip; - px = data->ox + data->cx; + px = data->cx; py = screen_hsize(&wp->base) + data->cy - data->oy; xx = window_copy_find_length(wp, py); @@ -809,9 +732,11 @@ window_copy_cursor_next_word(struct window_pane *wp) px++; } -out: - window_copy_set_cursor_x(wp, px); +out: + window_copy_update_cursor(wp, px, data->cy); + if (window_copy_update_selection(wp)) + window_copy_redraw_lines(wp, data->cy, 1); } /* Move to the previous place where a word begins. */ @@ -821,7 +746,7 @@ window_copy_cursor_previous_word(struct window_pane *wp) struct window_copy_mode_data *data = wp->modedata; u_int px, py; - px = data->ox + data->cx; + px = data->cx; py = screen_hsize(&wp->base) + data->cy - data->oy; /* Move back to the previous word character. */ @@ -848,65 +773,9 @@ window_copy_cursor_previous_word(struct window_pane *wp) px--; out: - window_copy_set_cursor_x(wp, px); -} - -void -window_copy_scroll_left(struct window_pane *wp, u_int nx) -{ - struct window_copy_mode_data *data = wp->modedata; - struct screen *s = &data->screen; - struct screen_write_ctx ctx; - u_int i; - - if (data->ox > SHRT_MAX - nx) - nx = SHRT_MAX - data->ox; - if (nx == 0) - return; - data->ox += nx; - window_copy_update_selection(wp); - - screen_write_start(&ctx, wp, NULL); - for (i = 1; i < screen_size_y(s); i++) { - screen_write_cursormove(&ctx, 0, i); - screen_write_deletecharacter(&ctx, nx); - } - window_copy_write_columns(wp, &ctx, screen_size_x(s) - nx, nx); - window_copy_write_line(wp, &ctx, 0); - if (s->sel.flag) { - window_copy_update_selection(wp); - window_copy_write_lines(wp, &ctx, data->cy, 1); - } - screen_write_cursormove(&ctx, data->cx, data->cy); - screen_write_stop(&ctx); -} - -void -window_copy_scroll_right(struct window_pane *wp, u_int nx) -{ - struct window_copy_mode_data *data = wp->modedata; - struct screen *s = &data->screen; - struct screen_write_ctx ctx; - u_int i; - - if (data->ox < nx) - nx = data->ox; - if (nx == 0) - return; - data->ox -= nx; - window_copy_update_selection(wp); - - screen_write_start(&ctx, wp, NULL); - for (i = 1; i < screen_size_y(s); i++) { - screen_write_cursormove(&ctx, 0, i); - screen_write_insertcharacter(&ctx, nx); - } - window_copy_write_columns(wp, &ctx, 0, nx); - window_copy_write_line(wp, &ctx, 0); - if (s->sel.flag) - window_copy_write_line(wp, &ctx, data->cy); - screen_write_cursormove(&ctx, data->cx, data->cy); - screen_write_stop(&ctx); + window_copy_update_cursor(wp, px, data->cy); + if (window_copy_update_selection(wp)) + window_copy_redraw_lines(wp, data->cy, 1); } void From 3ad4de6c8cbdc767c6ac40b99764cc7bd8db066a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 13 Aug 2009 20:11:58 +0000 Subject: [PATCH 0257/1180] Add a base-index session option to specify the first index checked when looking for an index for a new window. --- cmd-break-pane.c | 4 +++- cmd-link-window.c | 2 ++ cmd-move-window.c | 2 ++ cmd-new-session.c | 6 ++++-- cmd-new-window.c | 2 ++ cmd-set-option.c | 1 + session.c | 7 ++++--- tmux.1 | 4 ++++ tmux.c | 1 + tmux.h | 5 +++-- window.c | 26 ++++++++++++++------------ 11 files changed, 40 insertions(+), 20 deletions(-) diff --git a/cmd-break-pane.c b/cmd-break-pane.c index 57622119..b8d489de 100644 --- a/cmd-break-pane.c +++ b/cmd-break-pane.c @@ -48,6 +48,7 @@ cmd_break_pane_exec(struct cmd *self, struct cmd_ctx *ctx) struct window_pane *wp; struct window *w; char *cause; + int base_idx; if ((wl = cmd_find_pane(ctx, data->target, &s, &wp)) == NULL) return (-1); @@ -71,7 +72,8 @@ cmd_break_pane_exec(struct cmd *self, struct cmd_ctx *ctx) w->name = default_window_name(w); layout_init(w); - wl = session_attach(s, w, -1, &cause); /* can't fail */ + base_idx = options_get_number(&s->options, "base-index"); + wl = session_attach(s, w, -1 - base_idx, &cause); /* can't fail */ if (!(data->chflags & CMD_CHFLAG('d'))) session_select(s, wl->idx); diff --git a/cmd-link-window.c b/cmd-link-window.c index 742fb243..c13dbc90 100644 --- a/cmd-link-window.c +++ b/cmd-link-window.c @@ -77,6 +77,8 @@ cmd_link_window_exec(struct cmd *self, struct cmd_ctx *ctx) } } + if (idx == -1) + idx = -1 - options_get_number(&dst->options, "base-index"); wl_dst = session_attach(dst, wl_src->window, idx, &cause); if (wl_dst == NULL) { ctx->error(ctx, "create session failed: %s", cause); diff --git a/cmd-move-window.c b/cmd-move-window.c index f714c2cb..1cf72f94 100644 --- a/cmd-move-window.c +++ b/cmd-move-window.c @@ -79,6 +79,8 @@ cmd_move_window_exec(struct cmd *self, struct cmd_ctx *ctx) } } + if (idx == -1) + idx = -1 - options_get_number(&dst->options, "base-index"); wl_dst = session_attach(dst, wl_src->window, idx, &cause); if (wl_dst == NULL) { ctx->error(ctx, "attach window failed: %s", cause); diff --git a/cmd-new-session.c b/cmd-new-session.c index 64337e6d..ff90e3be 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -118,7 +118,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) struct termios tio; const char *update; char *overrides, *cmd, *cwd, *cause; - int detached; + int detached, idx; u_int sx, sy; if (data->newname != NULL && session_find(data->newname) != NULL) { @@ -216,7 +216,9 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) tio.c_ospeed = TTYDEF_SPEED; /* Create the new session. */ - s = session_create(data->newname, cmd, cwd, &env, &tio, sx, sy, &cause); + idx = -1 - options_get_number(&global_s_options, "base-index"); + s = session_create( + data->newname, cmd, cwd, &env, &tio, idx, sx, sy, &cause); if (s == NULL) { ctx->error(ctx, "create session failed: %s", cause); xfree(cause); diff --git a/cmd-new-window.c b/cmd-new-window.c index 2af6abf3..b3ec4379 100644 --- a/cmd-new-window.c +++ b/cmd-new-window.c @@ -154,6 +154,8 @@ cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx) else cwd = ctx->cmdclient->cwd; + if (idx == -1) + idx = -1 - options_get_number(&s->options, "base-index"); wl = session_new(s, data->name, cmd, cwd, idx, &cause); if (wl == NULL) { ctx->error(ctx, "create window failed: %s", cause); diff --git a/cmd-set-option.c b/cmd-set-option.c index 87b0b5a3..e764f4c5 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -50,6 +50,7 @@ const char *set_option_bell_action_list[] = { "none", "any", "current", NULL }; const struct set_option_entry set_option_table[] = { + { "base-index", SET_OPTION_NUMBER, 0, INT_MAX, NULL }, { "bell-action", SET_OPTION_CHOICE, 0, 0, set_option_bell_action_list }, { "buffer-limit", SET_OPTION_NUMBER, 1, INT_MAX, NULL }, { "default-command", SET_OPTION_STRING, 0, 0, NULL }, diff --git a/session.c b/session.c index 9b7beeb5..2e1aae3d 100644 --- a/session.c +++ b/session.c @@ -113,7 +113,8 @@ session_find(const char *name) /* Create a new session. */ struct session * session_create(const char *name, const char *cmd, const char *cwd, - struct environ *env, struct termios *tio, u_int sx, u_int sy, char **cause) + struct environ *env, struct termios *tio, int idx, u_int sx, u_int sy, + char **cause) { struct session *s; u_int i; @@ -149,11 +150,11 @@ session_create(const char *name, const char *cmd, const char *cwd, s->name = xstrdup(name); else xasprintf(&s->name, "%u", i); - if (session_new(s, NULL, cmd, cwd, -1, cause) == NULL) { + if (session_new(s, NULL, cmd, cwd, idx, cause) == NULL) { session_destroy(s); return (NULL); } - session_select(s, 0); + session_select(s, RB_ROOT(&s->windows)->idx); log_debug("session %s created", s->name); diff --git a/tmux.1 b/tmux.1 index faa44ad6..138366e2 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1064,6 +1064,10 @@ options - it is not possible to unset a global option. .Pp Available session options are: .Bl -tag -width Ds +.It Ic base-index Ar index +Set the base index from which an unused index should be searched when a new +window is created. +The default is zero. .It Xo Ic bell-action .Op Ic any | none | current .Xc diff --git a/tmux.c b/tmux.c index 65772f92..9ad48863 100644 --- a/tmux.c +++ b/tmux.c @@ -342,6 +342,7 @@ main(int argc, char **argv) } options_init(&global_s_options, NULL); + options_set_number(&global_s_options, "base-index", 0); options_set_number(&global_s_options, "bell-action", BELL_ANY); options_set_number(&global_s_options, "buffer-limit", 9); options_set_string(&global_s_options, "default-command", "%s", ""); diff --git a/tmux.h b/tmux.h index b15d02bf..2e182660 100644 --- a/tmux.h +++ b/tmux.h @@ -1565,7 +1565,7 @@ RB_PROTOTYPE(windows, window, entry, window_cmp); RB_PROTOTYPE(winlinks, winlink, entry, winlink_cmp); struct winlink *winlink_find_by_index(struct winlinks *, int); struct winlink *winlink_find_by_window(struct winlinks *, struct window *); -int winlink_next_index(struct winlinks *); +int winlink_next_index(struct winlinks *, int); u_int winlink_count(struct winlinks *); struct winlink *winlink_add(struct winlinks *, struct window *, int); void winlink_remove(struct winlinks *, struct winlink *); @@ -1670,7 +1670,8 @@ int session_alert_has(struct session *, struct winlink *, int); int session_alert_has_window(struct session *, struct window *, int); struct session *session_find(const char *); struct session *session_create(const char *, const char *, const char *, - struct environ *, struct termios *, u_int, u_int, char **); + struct environ *, struct termios *, int, u_int, u_int, + char **); void session_destroy(struct session *); int session_index(struct session *, u_int *); struct winlink *session_new(struct session *, diff --git a/window.c b/window.c index eccaa4e5..630533ee 100644 --- a/window.c +++ b/window.c @@ -122,16 +122,20 @@ winlink_find_by_index(struct winlinks *wwl, int idx) } int -winlink_next_index(struct winlinks *wwl) +winlink_next_index(struct winlinks *wwl, int idx) { - u_int i; + int i; - for (i = 0; i < INT_MAX; i++) { + i = idx; + do { if (winlink_find_by_index(wwl, i) == NULL) return (i); - } - - fatalx("no free indexes"); + if (i == INT_MAX) + i = 0; + else + i++; + } while (i != idx); + return (-1); } u_int @@ -152,14 +156,12 @@ winlink_add(struct winlinks *wwl, struct window *w, int idx) { struct winlink *wl; - if (idx == -1) - idx = winlink_next_index(wwl); - else if (winlink_find_by_index(wwl, idx) != NULL) + if (idx < 0) { + if ((idx = winlink_next_index(wwl, -idx - 1)) == -1) + return (NULL); + } else if (winlink_find_by_index(wwl, idx) != NULL) return (NULL); - if (idx < 0) - fatalx("bad index"); - wl = xcalloc(1, sizeof *wl); wl->idx = idx; wl->window = w; From 375be90fd1cd137f84496c8919f3cceff839b33b Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 13 Aug 2009 21:56:14 +0000 Subject: [PATCH 0258/1180] Disable mode-mouse (mouse in copy/choice mode) by default as it isn't very useful at the moment and causes confusion. --- tmux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tmux.c b/tmux.c index 9ad48863..4437f07b 100644 --- a/tmux.c +++ b/tmux.c @@ -399,7 +399,7 @@ main(int argc, char **argv) options_set_number(&global_w_options, "mode-bg", 3); options_set_number(&global_w_options, "mode-fg", 0); options_set_number(&global_w_options, "mode-keys", MODEKEY_EMACS); - options_set_number(&global_w_options, "mode-mouse", 1); + options_set_number(&global_w_options, "mode-mouse", 0); options_set_number(&global_w_options, "monitor-activity", 0); options_set_string(&global_w_options, "monitor-content", "%s", ""); if (flags & IDENTIFY_UTF8) From 39154402e5907887c7c49095d60577932afd99ee Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 13 Aug 2009 22:11:43 +0000 Subject: [PATCH 0259/1180] Scroll by two less than the number of lines in the screen, like emacs, rather than by the entire screen, to make it easier to pull things out from under the line indicator. Suggested by claudio. --- window-copy.c | 16 ++++++++++++---- window-scroll.c | 16 ++++++++++++---- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/window-copy.c b/window-copy.c index be810ee3..f99c969b 100644 --- a/window-copy.c +++ b/window-copy.c @@ -130,11 +130,15 @@ window_copy_pageup(struct window_pane *wp) { struct window_copy_mode_data *data = wp->modedata; struct screen *s = &data->screen; + u_int n; - if (data->oy + screen_size_y(s) > screen_hsize(&wp->base)) + n = 1; + if (screen_size_y(s) > 2) + n = screen_size_y(s) - 2; + if (data->oy + n > screen_hsize(&wp->base)) data->oy = screen_hsize(&wp->base); else - data->oy += screen_size_y(s); + data->oy += n; window_copy_update_selection(wp); window_copy_redraw_screen(wp); } @@ -167,6 +171,7 @@ window_copy_key(struct window_pane *wp, struct client *c, int key) { struct window_copy_mode_data *data = wp->modedata; struct screen *s = &data->screen; + u_int n; switch (mode_key_lookup(&data->mdata, key)) { case MODEKEYCOPY_CANCEL: @@ -188,10 +193,13 @@ window_copy_key(struct window_pane *wp, struct client *c, int key) window_copy_pageup(wp); break; case MODEKEYCOPY_NEXTPAGE: - if (data->oy < screen_size_y(s)) + n = 1; + if (screen_size_y(s) > 2) + n = screen_size_y(s) - 2; + if (data->oy < n) data->oy = 0; else - data->oy -= screen_size_y(s); + data->oy -= n; window_copy_update_selection(wp); window_copy_redraw_screen(wp); break; diff --git a/window-scroll.c b/window-scroll.c index bdb7d559..b3c0941d 100644 --- a/window-scroll.c +++ b/window-scroll.c @@ -101,11 +101,15 @@ window_scroll_pageup(struct window_pane *wp) { struct window_scroll_mode_data *data = wp->modedata; struct screen *s = &data->screen; + u_int n; - if (data->oy + screen_size_y(s) > screen_hsize(&wp->base)) + n = 1; + if (screen_size_y(s) > 2) + n = screen_size_y(s) - 2; + if (data->oy + n > screen_hsize(&wp->base)) data->oy = screen_hsize(&wp->base); else - data->oy += screen_size_y(s); + data->oy += n; window_scroll_redraw_screen(wp); } @@ -130,6 +134,7 @@ window_scroll_key(struct window_pane *wp, unused struct client *c, int key) { struct window_scroll_mode_data *data = wp->modedata; struct screen *s = &data->screen; + u_int n; switch (mode_key_lookup(&data->mdata, key)) { case MODEKEYCOPY_CANCEL: @@ -151,10 +156,13 @@ window_scroll_key(struct window_pane *wp, unused struct client *c, int key) window_scroll_pageup(wp); break; case MODEKEYCOPY_NEXTPAGE: - if (data->oy < screen_size_y(s)) + n = 1; + if (screen_size_y(s) > 2) + n = screen_size_y(s) - 2; + if (data->oy < n) data->oy = 0; else - data->oy -= screen_size_y(s); + data->oy -= n; window_scroll_redraw_screen(wp); break; default: From 7a359c00aca2e35dc26c2239f4261f0fa53f0caf Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 13 Aug 2009 22:32:18 +0000 Subject: [PATCH 0260/1180] vi(1)-style half page scroll in copy and scroll modes. Move the vi full page scroll key to C-b instead of C-u and use C-u/C-d for half page scrolling with vi keys. In emacs mode, half page scrolling is bound to M-Up and M-Down. Suggested by merdely (about a year ago :-)). --- mode-key.c | 6 +++++- tmux.h | 4 +++- window-copy.c | 18 ++++++++++++++++++ window-scroll.c | 16 ++++++++++++++++ 4 files changed, 42 insertions(+), 2 deletions(-) diff --git a/mode-key.c b/mode-key.c index 26eb771e..6ceb01b6 100644 --- a/mode-key.c +++ b/mode-key.c @@ -149,10 +149,12 @@ const struct mode_key_entry mode_key_vi_copy[] = { { ' ', 0, MODEKEYCOPY_STARTSELECTION }, { '$', 0, MODEKEYCOPY_ENDOFLINE }, { '0', 0, MODEKEYCOPY_STARTOFLINE }, + { '\002' /* C-b */, 0, MODEKEYCOPY_PREVIOUSPAGE }, { '\003' /* C-c */, 0, MODEKEYCOPY_CANCEL }, + { '\004' /* C-d */, 0, MODEKEYCOPY_HALFPAGEDOWN }, { '\006' /* C-f */, 0, MODEKEYCOPY_NEXTPAGE }, { '\010' /* C-h */, 0, MODEKEYCOPY_LEFT }, - { '\025' /* C-u */, 0, MODEKEYCOPY_PREVIOUSPAGE }, + { '\025' /* C-u */, 0, MODEKEYCOPY_HALFPAGEUP }, { '\033' /* Escape */, 0, MODEKEYCOPY_CLEARSELECTION }, { '\r', 0, MODEKEYCOPY_COPYSELECTION }, { '^', 0, MODEKEYCOPY_BACKTOINDENTATION }, @@ -237,11 +239,13 @@ const struct mode_key_entry mode_key_emacs_copy[] = { { 'q', 0, MODEKEYCOPY_CANCEL }, { 'v' | KEYC_ESCAPE, 0, MODEKEYCOPY_PREVIOUSPAGE }, { 'w' | KEYC_ESCAPE, 0, MODEKEYCOPY_COPYSELECTION }, + { KEYC_DOWN | KEYC_ESCAPE, 0, MODEKEYCOPY_HALFPAGEDOWN }, { KEYC_DOWN, 0, MODEKEYCOPY_DOWN }, { KEYC_LEFT, 0, MODEKEYCOPY_LEFT }, { KEYC_NPAGE, 0, MODEKEYCOPY_NEXTPAGE }, { KEYC_PPAGE, 0, MODEKEYCOPY_PREVIOUSPAGE }, { KEYC_RIGHT, 0, MODEKEYCOPY_RIGHT }, + { KEYC_UP | KEYC_ESCAPE, 0, MODEKEYCOPY_HALFPAGEUP }, { KEYC_UP, 0, MODEKEYCOPY_UP }, { 0, -1, 0 } diff --git a/tmux.h b/tmux.h index 2e182660..2f58ce4b 100644 --- a/tmux.h +++ b/tmux.h @@ -388,12 +388,14 @@ enum mode_key_cmd { MODEKEYCHOICE_UP, /* Copy keys. */ - MODEKEYCOPY_CANCEL, MODEKEYCOPY_BACKTOINDENTATION, + MODEKEYCOPY_CANCEL, MODEKEYCOPY_CLEARSELECTION, MODEKEYCOPY_COPYSELECTION, MODEKEYCOPY_DOWN, MODEKEYCOPY_ENDOFLINE, + MODEKEYCOPY_HALFPAGEDOWN, + MODEKEYCOPY_HALFPAGEUP, MODEKEYCOPY_LEFT, MODEKEYCOPY_NEXTPAGE, MODEKEYCOPY_NEXTWORD, diff --git a/window-copy.c b/window-copy.c index f99c969b..5bbb88a1 100644 --- a/window-copy.c +++ b/window-copy.c @@ -203,6 +203,24 @@ window_copy_key(struct window_pane *wp, struct client *c, int key) window_copy_update_selection(wp); window_copy_redraw_screen(wp); break; + case MODEKEYCOPY_HALFPAGEUP: + n = screen_size_y(s) / 2; + if (data->oy + n > screen_hsize(&wp->base)) + data->oy = screen_hsize(&wp->base); + else + data->oy += n; + window_copy_update_selection(wp); + window_copy_redraw_screen(wp); + break; + case MODEKEYCOPY_HALFPAGEDOWN: + n = screen_size_y(s) / 2; + if (data->oy < n) + data->oy = 0; + else + data->oy -= n; + window_copy_update_selection(wp); + window_copy_redraw_screen(wp); + break; case MODEKEYCOPY_STARTSELECTION: window_copy_start_selection(wp); window_copy_redraw_screen(wp); diff --git a/window-scroll.c b/window-scroll.c index b3c0941d..711976bb 100644 --- a/window-scroll.c +++ b/window-scroll.c @@ -165,6 +165,22 @@ window_scroll_key(struct window_pane *wp, unused struct client *c, int key) data->oy -= n; window_scroll_redraw_screen(wp); break; + case MODEKEYCOPY_HALFPAGEUP: + n = screen_size_y(s) / 2; + if (data->oy + n > screen_hsize(&wp->base)) + data->oy = screen_hsize(&wp->base); + else + data->oy += n; + window_scroll_redraw_screen(wp); + break; + case MODEKEYCOPY_HALFPAGEDOWN: + n = screen_size_y(s) / 2; + if (data->oy < n) + data->oy = 0; + else + data->oy -= n; + window_scroll_redraw_screen(wp); + break; default: break; } From 09cbd0c695cdd953834a46d161f6d3b0bf385c1c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 13 Aug 2009 23:44:18 +0000 Subject: [PATCH 0261/1180] Switch the prompt code to return an empty string when the user enters no response and reserve NULL for an explicit cancel. Change all callbacks to treat them the same so no functional change. Also add cancel key bindings to emacs mode which were missing. --- cmd-command-prompt.c | 2 +- cmd-confirm-before.c | 4 +++- cmd-select-prompt.c | 2 +- mode-key.c | 2 ++ status.c | 11 ++++------- 5 files changed, 11 insertions(+), 10 deletions(-) diff --git a/cmd-command-prompt.c b/cmd-command-prompt.c index f729a66e..dac334b2 100644 --- a/cmd-command-prompt.c +++ b/cmd-command-prompt.c @@ -112,7 +112,7 @@ cmd_command_prompt_callback(void *data, const char *s) char *cause, *ptr, *buf, ch; size_t len, slen; - if (s == NULL) + if (s == NULL || *s == '\0') return (0); slen = strlen(s); diff --git a/cmd-confirm-before.c b/cmd-confirm-before.c index db799a4b..fd366b9b 100644 --- a/cmd-confirm-before.c +++ b/cmd-confirm-before.c @@ -107,7 +107,9 @@ cmd_confirm_before_callback(void *data, const char *s) struct cmd_ctx ctx; char *cause; - if (s == NULL || tolower((u_char) s[0]) != 'y' || s[1] != '\0') + if (s == NULL || *s == '\0') + return (0); + if (tolower((u_char) s[0]) != 'y' || s[1] != '\0') return (0); if (cmd_string_parse(cdata->cmd, &cmdlist, &cause) != 0) { diff --git a/cmd-select-prompt.c b/cmd-select-prompt.c index a7965e29..bead0619 100644 --- a/cmd-select-prompt.c +++ b/cmd-select-prompt.c @@ -66,7 +66,7 @@ cmd_select_prompt_callback(void *data, const char *s) char msg[128]; u_int idx; - if (s == NULL) + if (s == NULL || *s == '\0') return (0); idx = strtonum(s, 0, UINT_MAX, &errstr); diff --git a/mode-key.c b/mode-key.c index 6ceb01b6..d36504fd 100644 --- a/mode-key.c +++ b/mode-key.c @@ -181,6 +181,7 @@ struct mode_key_tree mode_key_tree_vi_copy; const struct mode_key_entry mode_key_emacs_edit[] = { { '\001' /* C-a */, 0, MODEKEYEDIT_STARTOFLINE }, { '\002' /* C-p */, 0, MODEKEYEDIT_CURSORLEFT }, + { '\003' /* C-c */, 0, MODEKEYEDIT_CANCEL }, { '\004' /* C-d */, 0, MODEKEYEDIT_DELETE }, { '\005' /* C-e */, 0, MODEKEYEDIT_ENDOFLINE }, { '\006' /* C-f */, 0, MODEKEYEDIT_CURSORRIGHT }, @@ -190,6 +191,7 @@ const struct mode_key_entry mode_key_emacs_edit[] = { { '\016' /* C-n */, 0, MODEKEYEDIT_HISTORYDOWN }, { '\020' /* C-p */, 0, MODEKEYEDIT_HISTORYUP }, { '\031' /* C-y */, 0, MODEKEYEDIT_PASTE }, + { '\033' /* Escape */, 0, MODEKEYEDIT_CANCEL }, { '\r', 0, MODEKEYEDIT_ENTER }, { 'm' | KEYC_ESCAPE, 0, MODEKEYEDIT_STARTOFLINE }, { KEYC_BSPACE, 0, MODEKEYEDIT_BACKSPACE }, diff --git a/status.c b/status.c index 47a5d8e4..c42dc896 100644 --- a/status.c +++ b/status.c @@ -920,14 +920,11 @@ status_prompt_key(struct client *c, int key) c->flags |= CLIENT_STATUS; break; case MODEKEYEDIT_ENTER: - if (*c->prompt_buffer != '\0') { + if (*c->prompt_buffer != '\0') status_prompt_add_history(c); - if (c->prompt_callbackfn( - c->prompt_data, c->prompt_buffer) == 0) - status_prompt_clear(c); - break; - } - /* FALLTHROUGH */ + if (c->prompt_callbackfn(c->prompt_data, c->prompt_buffer) == 0) + status_prompt_clear(c); + break; case MODEKEYEDIT_CANCEL: if (c->prompt_callbackfn(c->prompt_data, NULL) == 0) status_prompt_clear(c); From 5cf994856ffcbd95b1821e687dc271c6f81b6e35 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 14 Aug 2009 08:53:52 +0000 Subject: [PATCH 0262/1180] Send SGR0 when initialising the screen. Fixes problems on terminals with BCE (like putty) if the background colours is non-default when tmux starts. May also fix problems when resuming a suspended tmux. --- tty.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tty.c b/tty.c index 1c985dcc..0428a0cc 100644 --- a/tty.c +++ b/tty.c @@ -134,6 +134,9 @@ tty_start_tty(struct tty *tty) tty_putcode(tty, TTYC_SMCUP); + tty_putcode(tty, TTYC_SGR0); + memcpy(&tty->cell, &grid_default_cell, sizeof tty->cell); + tty_putcode(tty, TTYC_SMKX); tty_putcode(tty, TTYC_ENACS); tty_putcode(tty, TTYC_CLEAR); @@ -142,8 +145,6 @@ tty_start_tty(struct tty *tty) if (tty_term_has(tty->term, TTYC_KMOUS)) tty_puts(tty, "\033[?1000l"); - memcpy(&tty->cell, &grid_default_cell, sizeof tty->cell); - tty->cx = UINT_MAX; tty->cy = UINT_MAX; From e7cd547457e40dce8c05c37c358c414d36bac54d Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 14 Aug 2009 11:23:34 +0000 Subject: [PATCH 0263/1180] Reset attributes as well as scroll region before poll(2) and add a big comment explaining why. --- server.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/server.c b/server.c index eb8843f5..059e1b9d 100644 --- a/server.c +++ b/server.c @@ -879,7 +879,16 @@ server_handle_client(struct client *c) wp = c->session->curw->window->active; /* could die - do each loop */ s = wp->screen; - /* Ensure cursor position and mode settings. */ + /* + * Update cursor position and mode settings. The scroll region and + * attributes are cleared across poll(2) as this is the most likely + * time a user may interrupt tmux, for example with ~^Z in ssh(1). This + * is a compromise between excessive resets and likelihood of an + * interrupt. + * + * tty_region/tty_reset/tty_update_mode already take care of not + * resetting things that are already in their default state. + */ status = options_get_number(&c->session->options, "status"); tty_region(&c->tty, 0, c->tty.sy - 1, 0); if (!window_pane_visible(wp) || wp->yoff + s->cy >= c->tty.sy - status) @@ -891,6 +900,7 @@ server_handle_client(struct client *c) if (server_locked) mode &= ~TTY_NOCURSOR; tty_update_mode(&c->tty, mode); + tty_reset(&c->tty); } /* Lost a client. */ From c828c2f3665d1caed443816a066e3ac81b08ea83 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 18 Aug 2009 07:08:26 +0000 Subject: [PATCH 0264/1180] Add (naive) searching and goto line in copy mode. Searching is C-r and C-s with emacs keys, / and ? with vi; n repeats the search again with either key set. All searching wraps the top/bottom. Goto line is g for both emacs and vi. The search prompts don't have full line editing, just simple append and delete characters. Also sort the mode keys list in tmux.1. --- mode-key.c | 14 +- tmux.1 | 16 +- tmux.h | 4 + window-copy.c | 404 ++++++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 417 insertions(+), 21 deletions(-) diff --git a/mode-key.c b/mode-key.c index d36504fd..64f31a49 100644 --- a/mode-key.c +++ b/mode-key.c @@ -74,18 +74,22 @@ struct mode_key_cmdstr mode_key_cmdstr_choice[] = { /* Copy keys command strings. */ struct mode_key_cmdstr mode_key_cmdstr_copy[] = { - { MODEKEYCOPY_CANCEL, "cancel" }, { MODEKEYCOPY_BACKTOINDENTATION, "back-to-indentation" }, + { MODEKEYCOPY_CANCEL, "cancel" }, { MODEKEYCOPY_CLEARSELECTION, "clear-selection" }, { MODEKEYCOPY_COPYSELECTION, "copy-selection" }, { MODEKEYCOPY_DOWN, "cursor-down" }, { MODEKEYCOPY_ENDOFLINE, "end-of-line" }, + { MODEKEYCOPY_GOTOLINE, "goto-line" }, { MODEKEYCOPY_LEFT, "cursor-left" }, { MODEKEYCOPY_NEXTPAGE, "page-down" }, { MODEKEYCOPY_NEXTWORD, "next-word" }, { MODEKEYCOPY_PREVIOUSPAGE, "page-up" }, { MODEKEYCOPY_PREVIOUSWORD, "previous-word" }, { MODEKEYCOPY_RIGHT, "cursor-right" }, + { MODEKEYCOPY_SEARCHAGAIN, "search-again" }, + { MODEKEYCOPY_SEARCHDOWN, "search-forward" }, + { MODEKEYCOPY_SEARCHUP, "search-backward" }, { MODEKEYCOPY_STARTOFLINE, "start-of-line" }, { MODEKEYCOPY_STARTSELECTION, "begin-selection" }, { MODEKEYCOPY_UP, "cursor-up" }, @@ -148,7 +152,9 @@ struct mode_key_tree mode_key_tree_vi_choice; const struct mode_key_entry mode_key_vi_copy[] = { { ' ', 0, MODEKEYCOPY_STARTSELECTION }, { '$', 0, MODEKEYCOPY_ENDOFLINE }, + { '/', 0, MODEKEYCOPY_SEARCHUP }, { '0', 0, MODEKEYCOPY_STARTOFLINE }, + { '?', 0, MODEKEYCOPY_SEARCHDOWN }, { '\002' /* C-b */, 0, MODEKEYCOPY_PREVIOUSPAGE }, { '\003' /* C-c */, 0, MODEKEYCOPY_CANCEL }, { '\004' /* C-d */, 0, MODEKEYCOPY_HALFPAGEDOWN }, @@ -159,10 +165,12 @@ const struct mode_key_entry mode_key_vi_copy[] = { { '\r', 0, MODEKEYCOPY_COPYSELECTION }, { '^', 0, MODEKEYCOPY_BACKTOINDENTATION }, { 'b', 0, MODEKEYCOPY_PREVIOUSWORD }, + { 'g', 0, MODEKEYCOPY_GOTOLINE }, { 'h', 0, MODEKEYCOPY_LEFT }, { 'j', 0, MODEKEYCOPY_DOWN }, { 'k', 0, MODEKEYCOPY_UP }, { 'l', 0, MODEKEYCOPY_RIGHT }, + { 'n', 0, MODEKEYCOPY_SEARCHAGAIN }, { 'q', 0, MODEKEYCOPY_CANCEL }, { 'w', 0, MODEKEYCOPY_NEXTWORD }, { KEYC_BSPACE, 0, MODEKEYCOPY_LEFT }, @@ -232,12 +240,16 @@ const struct mode_key_entry mode_key_emacs_copy[] = { { '\007' /* C-g */, 0, MODEKEYCOPY_CLEARSELECTION }, { '\016' /* C-n */, 0, MODEKEYCOPY_DOWN }, { '\020' /* C-p */, 0, MODEKEYCOPY_UP }, + { '\022' /* C-r */, 0, MODEKEYCOPY_SEARCHUP }, + { '\023' /* C-s */, 0, MODEKEYCOPY_SEARCHDOWN }, { '\026' /* C-v */, 0, MODEKEYCOPY_NEXTPAGE }, { '\027' /* C-w */, 0, MODEKEYCOPY_COPYSELECTION }, { '\033' /* Escape */, 0, MODEKEYCOPY_CANCEL }, { 'b' | KEYC_ESCAPE, 0, MODEKEYCOPY_PREVIOUSWORD }, { 'f' | KEYC_ESCAPE, 0, MODEKEYCOPY_NEXTWORD }, + { 'g', 0, MODEKEYCOPY_GOTOLINE }, { 'm' | KEYC_ESCAPE, 0, MODEKEYCOPY_BACKTOINDENTATION }, + { 'n', 0, MODEKEYCOPY_SEARCHAGAIN }, { 'q', 0, MODEKEYCOPY_CANCEL }, { 'v' | KEYC_ESCAPE, 0, MODEKEYCOPY_PREVIOUSPAGE }, { 'w' | KEYC_ESCAPE, 0, MODEKEYCOPY_COPYSELECTION }, diff --git a/tmux.1 b/tmux.1 index 138366e2..1347ee8a 100644 --- a/tmux.1 +++ b/tmux.1 @@ -475,23 +475,27 @@ option). The following keys are supported as appropriate for the mode: .Bl -column "FunctionXXXXXXXXXXXX" "viXXXXXX" "emacs" -offset indent .It Sy "Function" Ta Sy "vi" Ta Sy "emacs" -.It Li "Start of line" Ta "0" Ta "C-a" .It Li "Back to indentation" Ta "^" Ta "M-m" .It Li "Clear selection" Ta "Escape" Ta "C-g" .It Li "Copy selection" Ta "Enter" Ta "M-w" .It Li "Cursor down" Ta "j" Ta "Down" -.It Li "End of line" Ta "$" Ta "C-e" .It Li "Cursor left" Ta "h" Ta "Left" +.It Li "Cursor right" Ta "l" Ta "Right" +.It Li "Cursor up" Ta "k" Ta "Up" +.It Li "Delete to end of line" Ta "D" Ta "C-k" +.It Li "End of line" Ta "$" Ta "C-e" +.It Li "Goto line" Ta "g" Ta "g" .It Li "Next page" Ta "C-f" Ta "Page down" .It Li "Next word" Ta "w" Ta "M-f" +.It Li "Paste buffer" Ta "p" Ta "C-y" .It Li "Previous page" Ta "C-u" Ta "Page up" .It Li "Previous word" Ta "b" Ta "M-b" .It Li "Quit mode" Ta "q" Ta "Escape" -.It Li "Cursor right" Ta "l" Ta "Right" +.It Li "Search again" Ta "n" Ta "n" +.It Li "Search backward" Ta "?" Ta "C-r" +.It Li "Search forward" Ta "/" Ta "C-s" +.It Li "Start of line" Ta "0" Ta "C-a" .It Li "Start selection" Ta "Space" Ta "C-Space" -.It Li "Cursor up" Ta "k" Ta "Up" -.It Li "Delete to end of line" Ta "D" Ta "C-k" -.It Li "Paste buffer" Ta "p" Ta "C-y" .El .Pp These key bindings are defined in a set of named tables: diff --git a/tmux.h b/tmux.h index 2f58ce4b..220826c6 100644 --- a/tmux.h +++ b/tmux.h @@ -394,6 +394,7 @@ enum mode_key_cmd { MODEKEYCOPY_COPYSELECTION, MODEKEYCOPY_DOWN, MODEKEYCOPY_ENDOFLINE, + MODEKEYCOPY_GOTOLINE, MODEKEYCOPY_HALFPAGEDOWN, MODEKEYCOPY_HALFPAGEUP, MODEKEYCOPY_LEFT, @@ -402,6 +403,9 @@ enum mode_key_cmd { MODEKEYCOPY_PREVIOUSPAGE, MODEKEYCOPY_PREVIOUSWORD, MODEKEYCOPY_RIGHT, + MODEKEYCOPY_SEARCHAGAIN, + MODEKEYCOPY_SEARCHDOWN, + MODEKEYCOPY_SEARCHUP, MODEKEYCOPY_STARTOFLINE, MODEKEYCOPY_STARTSELECTION, MODEKEYCOPY_UP, diff --git a/window-copy.c b/window-copy.c index 5bbb88a1..238508b8 100644 --- a/window-copy.c +++ b/window-copy.c @@ -18,6 +18,7 @@ #include +#include #include #include "tmux.h" @@ -26,6 +27,7 @@ struct screen *window_copy_init(struct window_pane *); void window_copy_free(struct window_pane *); void window_copy_resize(struct window_pane *, u_int, u_int); void window_copy_key(struct window_pane *, struct client *, int); +int window_copy_key_input(struct window_pane *, int); void window_copy_mouse( struct window_pane *, struct client *, u_char, u_char, u_char); @@ -36,6 +38,16 @@ void window_copy_write_line( void window_copy_write_lines( struct window_pane *, struct screen_write_ctx *, u_int, u_int); +void window_copy_scroll_to(struct window_pane *, u_int, u_int); +int window_copy_search_compare( + struct grid *, u_int, u_int, struct grid *, u_int); +int window_copy_search_lr( + struct grid *, struct grid *, u_int *, u_int, u_int, u_int); +int window_copy_search_rl( + struct grid *, struct grid *, u_int *, u_int, u_int, u_int); +void window_copy_search_up(struct window_pane *, const char *); +void window_copy_search_down(struct window_pane *, const char *); +void window_copy_goto_line(struct window_pane *, const char *); void window_copy_update_cursor(struct window_pane *, u_int, u_int); void window_copy_start_selection(struct window_pane *); int window_copy_update_selection(struct window_pane *); @@ -65,18 +77,32 @@ const struct window_mode window_copy_mode = { NULL, }; +enum window_copy_input_type { + WINDOW_COPY_OFF, + WINDOW_COPY_SEARCHUP, + WINDOW_COPY_SEARCHDOWN, + WINDOW_COPY_GOTOLINE, +}; + struct window_copy_mode_data { struct screen screen; - struct mode_key_data mdata; + struct mode_key_data mdata; - u_int oy; + u_int oy; - u_int selx; - u_int sely; + u_int selx; + u_int sely; - u_int cx; - u_int cy; + u_int cx; + u_int cy; + + enum window_copy_input_type inputtype; + const char *inputprompt; + char *inputstr; + + enum window_copy_input_type searchtype; + char *searchstr; }; struct screen * @@ -93,6 +119,13 @@ window_copy_init(struct window_pane *wp) data->cx = wp->base.cx; data->cy = wp->base.cy; + data->inputtype = WINDOW_COPY_OFF; + data->inputprompt = NULL; + data->inputstr = xstrdup(""); + + data->searchtype = WINDOW_COPY_OFF; + data->searchstr = NULL; + s = &data->screen; screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0); if (options_get_number(&wp->window->options, "mode-mouse")) @@ -121,7 +154,12 @@ window_copy_free(struct window_pane *wp) { struct window_copy_mode_data *data = wp->modedata; + if (data->searchstr != NULL) + xfree(data->searchstr); + xfree(data->inputstr); + screen_free(&data->screen); + xfree(data); } @@ -172,6 +210,13 @@ window_copy_key(struct window_pane *wp, struct client *c, int key) struct window_copy_mode_data *data = wp->modedata; struct screen *s = &data->screen; u_int n; + int keys; + + if (data->inputtype != WINDOW_COPY_OFF) { + if (window_copy_key_input(wp, key) != 0) + goto input_off; + return; + } switch (mode_key_lookup(&data->mdata, key)) { case MODEKEYCOPY_CANCEL: @@ -250,9 +295,111 @@ window_copy_key(struct window_pane *wp, struct client *c, int key) case MODEKEYCOPY_PREVIOUSWORD: window_copy_cursor_previous_word(wp); break; + case MODEKEYCOPY_SEARCHUP: + data->inputtype = WINDOW_COPY_SEARCHUP; + data->inputprompt = "Search Up"; + goto input_on; + case MODEKEYCOPY_SEARCHDOWN: + data->inputtype = WINDOW_COPY_SEARCHDOWN; + data->inputprompt = "Search Down"; + goto input_on; + case MODEKEYCOPY_SEARCHAGAIN: + switch (data->searchtype) { + case WINDOW_COPY_OFF: + case WINDOW_COPY_GOTOLINE: + break; + case WINDOW_COPY_SEARCHUP: + window_copy_search_up(wp, data->searchstr); + break; + case WINDOW_COPY_SEARCHDOWN: + window_copy_search_down(wp, data->searchstr); + break; + } + break; + case MODEKEYCOPY_GOTOLINE: + data->inputtype = WINDOW_COPY_GOTOLINE; + data->inputprompt = "Goto Line"; + *data->inputstr = '\0'; + goto input_on; default: break; } + + return; + +input_on: + keys = options_get_number(&wp->window->options, "mode-keys"); + if (keys == MODEKEY_EMACS) + mode_key_init(&data->mdata, &mode_key_tree_emacs_edit); + else + mode_key_init(&data->mdata, &mode_key_tree_vi_edit); + + window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1); + return; + +input_off: + keys = options_get_number(&wp->window->options, "mode-keys"); + if (keys == MODEKEY_EMACS) + mode_key_init(&data->mdata, &mode_key_tree_emacs_copy); + else + mode_key_init(&data->mdata, &mode_key_tree_vi_copy); + + data->inputtype = WINDOW_COPY_OFF; + data->inputprompt = NULL; + + window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1); +} + +int +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; + + switch (mode_key_lookup(&data->mdata, key)) { + case MODEKEYEDIT_CANCEL: + return (-1); + case MODEKEYEDIT_BACKSPACE: + inputlen = strlen(data->inputstr); + if (inputlen > 0) + data->inputstr[inputlen - 1] = '\0'; + break; + case MODEKEYEDIT_ENTER: + switch (data->inputtype) { + case WINDOW_COPY_OFF: + break; + case WINDOW_COPY_SEARCHUP: + window_copy_search_up(wp, data->inputstr); + data->searchtype = data->inputtype; + data->searchstr = xstrdup(data->inputstr); + break; + case WINDOW_COPY_SEARCHDOWN: + window_copy_search_down(wp, data->inputstr); + data->searchtype = data->inputtype; + data->searchstr = xstrdup(data->inputstr); + break; + case WINDOW_COPY_GOTOLINE: + window_copy_goto_line(wp, data->inputstr); + *data->inputstr = '\0'; + break; + } + return (1); + case MODEKEY_OTHER: + if (key < 32 || key > 126) + break; + inputlen = strlen(data->inputstr) + 2; + + data->inputstr = xrealloc(data->inputstr, 1, inputlen); + data->inputstr[inputlen - 2] = key; + data->inputstr[inputlen - 1] = '\0'; + break; + default: + break; + } + + window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1); + return (0); } void @@ -274,6 +421,229 @@ window_copy_mouse(struct window_pane *wp, window_copy_redraw_screen(wp); } +void +window_copy_scroll_to(struct window_pane *wp, u_int px, u_int py) +{ + struct window_copy_mode_data *data = wp->modedata; + struct screen *s = &wp->base; + struct grid *gd = s->grid; + u_int offset, gap; + + data->cx = px; + + gap = gd->sy / 4; + if (py < gd->sy) { + offset = 0; + data->cy = py; + } else if (py > gd->hsize + gd->sy - gap) { + offset = gd->hsize; + data->cy = py - gd->hsize; + } else { + offset = py + gap - gd->sy; + data->cy = py - offset; + } + data->oy = gd->hsize - offset; + + window_copy_redraw_screen(wp); +} + +int +window_copy_search_compare( + struct grid *gd, u_int px, u_int py, struct grid *sgd, u_int spx) +{ + const struct grid_cell *gc, *sgc; + const struct grid_utf8 *gu, *sgu; + + gc = grid_peek_cell(gd, px, py); + sgc = grid_peek_cell(sgd, spx, 0); + + if ((gc->flags & GRID_FLAG_UTF8) != (sgc->flags & GRID_FLAG_UTF8)) + return (0); + + if (gc->flags & GRID_FLAG_UTF8) { + gu = grid_peek_utf8(gd, px, py); + sgu = grid_peek_utf8(sgd, spx, 0); + if (memcmp(gu->data, sgu->data, UTF8_SIZE) == 0) + return (1); + } else { + if (gc->data == sgc->data) + return (1); + } + return (0); +} + +int +window_copy_search_lr(struct grid *gd, + struct grid *sgd, u_int *ppx, u_int py, u_int first, u_int last) +{ + u_int ax, bx, px; + + for (ax = first; ax < last; ax++) { + if (ax + sgd->sx >= gd->sx) + break; + for (bx = 0; bx < sgd->sx; bx++) { + px = ax + bx; + if (!window_copy_search_compare(gd, px, py, sgd, bx)) + break; + } + if (bx == sgd->sx) { + *ppx = ax; + return (1); + } + } + return (0); +} + +int +window_copy_search_rl(struct grid *gd, + struct grid *sgd, u_int *ppx, u_int py, u_int first, u_int last) +{ + u_int ax, bx, px; + + for (ax = last + 1; ax > first; ax--) { + for (bx = 0; bx < sgd->sx; bx++) { + px = ax - 1 + bx; + if (!window_copy_search_compare(gd, px, py, sgd, bx)) + break; + } + if (bx == sgd->sx) { + *ppx = ax - 1; + return (1); + } + } + return (0); +} + +void +window_copy_search_up(struct window_pane *wp, const char *searchstr) +{ + struct window_copy_mode_data *data = wp->modedata; + struct screen *s = &wp->base, ss; + struct screen_write_ctx ctx; + struct grid *gd = s->grid, *sgd; + struct grid_cell gc; + size_t searchlen; + u_int i, last, fx, fy, px; + int utf8flag, n, wrapped; + + if (*searchstr == '\0') + return; + utf8flag = options_get_number(&wp->window->options, "utf8"); + searchlen = screen_write_strlen(utf8flag, "%s", searchstr); + + screen_init(&ss, searchlen, 1, 0); + screen_write_start(&ctx, NULL, &ss); + memcpy(&gc, &grid_default_cell, sizeof gc); + screen_write_nputs(&ctx, -1, &gc, utf8flag, "%s", searchstr); + screen_write_stop(&ctx); + + fx = data->cx; + fy = gd->hsize - data->oy + data->cy; + + if (fx == 0) { + if (fy == 0) + return; + fx = gd->sx - 1; + fy--; + } else + fx--; + n = wrapped = 0; + +retry: + sgd = ss.grid; + for (i = fy + 1; i > 0; i--) { + last = screen_size_x(s); + if (i == fy + 1) + last = fx; + n = window_copy_search_rl(gd, sgd, &px, i - 1, 0, last); + if (n) { + window_copy_scroll_to(wp, px, i - 1); + break; + } + } + if (!n && !wrapped) { + fx = gd->sx - 1; + fy = gd->hsize + gd->sy - 1; + wrapped = 1; + goto retry; + } + + screen_free(&ss); +} + +void +window_copy_search_down(struct window_pane *wp, const char *searchstr) +{ + struct window_copy_mode_data *data = wp->modedata; + struct screen *s = &wp->base, ss; + struct screen_write_ctx ctx; + struct grid *gd = s->grid, *sgd; + struct grid_cell gc; + size_t searchlen; + u_int i, first, fx, fy, px; + int utf8flag, n, wrapped; + + if (*searchstr == '\0') + return; + utf8flag = options_get_number(&wp->window->options, "utf8"); + searchlen = screen_write_strlen(utf8flag, "%s", searchstr); + + screen_init(&ss, searchlen, 1, 0); + screen_write_start(&ctx, NULL, &ss); + memcpy(&gc, &grid_default_cell, sizeof gc); + screen_write_nputs(&ctx, -1, &gc, utf8flag, "%s", searchstr); + screen_write_stop(&ctx); + searchlen = strlen(searchstr); + + fx = data->cx; + fy = gd->hsize - data->oy + data->cy; + + if (fx == gd->sx - 1) { + if (fy == gd->hsize + gd->sy) + return; + fx = 0; + fy++; + } else + fx++; + n = wrapped = 0; + +retry: + sgd = ss.grid; + for (i = fy + 1; i < gd->hsize + gd->sy; i++) { + first = 0; + if (i == fy + 1) + first = fx; + n = window_copy_search_lr(gd, sgd, &px, i - 1, first, gd->sx); + if (n) { + window_copy_scroll_to(wp, px, i - 1); + break; + } + } + if (!n && !wrapped) { + fx = 0; + fy = 0; + wrapped = 1; + goto retry; + } + + screen_free(&ss); +} + +void +window_copy_goto_line(struct window_pane *wp, const char *linestr) +{ + struct window_copy_mode_data *data = wp->modedata; + const char *errstr; + u_int lineno; + + lineno = strtonum(linestr, 0, screen_hsize(&wp->base), &errstr); + if (errstr != NULL) + return; + + data->oy = lineno; + window_copy_redraw_screen(wp); +} + void window_copy_write_line( struct window_pane *wp, struct screen_write_ctx *ctx, u_int py) @@ -282,23 +652,29 @@ window_copy_write_line( struct screen *s = &data->screen; struct grid_cell gc; char hdr[32]; - size_t size; + size_t last, xoff = 0, size = 0; + memcpy(&gc, &grid_default_cell, sizeof gc); + gc.fg = options_get_number(&wp->window->options, "mode-fg"); + gc.bg = options_get_number(&wp->window->options, "mode-bg"); + gc.attr |= options_get_number(&wp->window->options, "mode-attr"); + + last = screen_size_y(s) - 1; if (py == 0) { - memcpy(&gc, &grid_default_cell, sizeof gc); size = xsnprintf(hdr, sizeof hdr, "[%u/%u]", data->oy, screen_hsize(&wp->base)); - gc.fg = options_get_number(&wp->window->options, "mode-fg"); - gc.bg = options_get_number(&wp->window->options, "mode-bg"); - gc.attr |= options_get_number( - &wp->window->options, "mode-attr"); 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) { + xoff = size = xsnprintf(hdr, sizeof hdr, + "%s: %s", data->inputprompt, data->inputstr); + screen_write_cursormove(ctx, 0, last); + screen_write_puts(ctx, &gc, "%s", hdr); } else size = 0; - screen_write_cursormove(ctx, 0, py); - screen_write_copy(ctx, &wp->base, 0, (screen_hsize(&wp->base) - + screen_write_cursormove(ctx, xoff, py); + screen_write_copy(ctx, &wp->base, xoff, (screen_hsize(&wp->base) - data->oy) + py, screen_size_x(s) - size, 1); if (py == data->cy && data->cx == screen_size_x(s)) { From feaf91ab939837a6397799a741b2258ed623f88a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 18 Aug 2009 07:23:43 +0000 Subject: [PATCH 0265/1180] Add a "delete line" key when editing in the status line or the search up/down prompt. C-u with emacs keys, d with vi. --- mode-key.c | 5 ++++- status.c | 5 +++++ tmux.1 | 1 + tmux.h | 1 + window-copy.c | 3 +++ 5 files changed, 14 insertions(+), 1 deletion(-) diff --git a/mode-key.c b/mode-key.c index 64f31a49..599de5ce 100644 --- a/mode-key.c +++ b/mode-key.c @@ -47,6 +47,7 @@ struct mode_key_cmdstr mode_key_cmdstr_edit[] = { { MODEKEYEDIT_CURSORLEFT, "cursor-left" }, { MODEKEYEDIT_CURSORRIGHT, "cursor-right" }, { MODEKEYEDIT_DELETE, "delete" }, + { MODEKEYEDIT_DELETELINE, "delete-line" }, { MODEKEYEDIT_DELETETOENDOFLINE, "delete-end-of-line" }, { MODEKEYEDIT_ENDOFLINE, "end-of-line" }, { MODEKEYEDIT_ENTER, "enter" }, @@ -109,6 +110,7 @@ const struct mode_key_entry mode_key_vi_edit[] = { { '$', 1, MODEKEYEDIT_ENDOFLINE }, { '0', 1, MODEKEYEDIT_STARTOFLINE }, + { 'd', 1, MODEKEYEDIT_DELETELINE }, { 'D', 1, MODEKEYEDIT_DELETETOENDOFLINE }, { '\003' /* C-c */, 1, MODEKEYEDIT_CANCEL }, { '\010' /* C-h */, 1, MODEKEYEDIT_BACKSPACE }, @@ -194,10 +196,11 @@ const struct mode_key_entry mode_key_emacs_edit[] = { { '\005' /* C-e */, 0, MODEKEYEDIT_ENDOFLINE }, { '\006' /* C-f */, 0, MODEKEYEDIT_CURSORRIGHT }, { '\010' /* C-H */, 0, MODEKEYEDIT_BACKSPACE }, - { '\011' /* Tab */, 0, MODEKEYEDIT_COMPLETE }, + { '\011' /* Tab */, 0, MODEKEYEDIT_COMPLETE }, { '\013' /* C-k */, 0, MODEKEYEDIT_DELETETOENDOFLINE }, { '\016' /* C-n */, 0, MODEKEYEDIT_HISTORYDOWN }, { '\020' /* C-p */, 0, MODEKEYEDIT_HISTORYUP }, + { '\025' /* C-u */, 0, MODEKEYEDIT_DELETELINE }, { '\031' /* C-y */, 0, MODEKEYEDIT_PASTE }, { '\033' /* Escape */, 0, MODEKEYEDIT_CANCEL }, { '\r', 0, MODEKEYEDIT_ENTER }, diff --git a/status.c b/status.c index c42dc896..d700f2c7 100644 --- a/status.c +++ b/status.c @@ -854,6 +854,11 @@ status_prompt_key(struct client *c, int key) c->flags |= CLIENT_STATUS; } break; + case MODEKEYEDIT_DELETELINE: + *c->prompt_buffer = '\0'; + c->prompt_index = 0; + c->flags |= CLIENT_STATUS; + break; case MODEKEYEDIT_DELETETOENDOFLINE: if (c->prompt_index < size) { c->prompt_buffer[c->prompt_index] = '\0'; diff --git a/tmux.1 b/tmux.1 index 1347ee8a..3213b32b 100644 --- a/tmux.1 +++ b/tmux.1 @@ -482,6 +482,7 @@ The following keys are supported as appropriate for the mode: .It Li "Cursor left" Ta "h" Ta "Left" .It Li "Cursor right" Ta "l" Ta "Right" .It Li "Cursor up" Ta "k" Ta "Up" +.It Li "Delete entire line" Ta "d" Ta "C-u" .It Li "Delete to end of line" Ta "D" Ta "C-k" .It Li "End of line" Ta "$" Ta "C-e" .It Li "Goto line" Ta "g" Ta "g" diff --git a/tmux.h b/tmux.h index 220826c6..4ba1cec4 100644 --- a/tmux.h +++ b/tmux.h @@ -369,6 +369,7 @@ enum mode_key_cmd { MODEKEYEDIT_CURSORLEFT, MODEKEYEDIT_CURSORRIGHT, MODEKEYEDIT_DELETE, + MODEKEYEDIT_DELETELINE, MODEKEYEDIT_DELETETOENDOFLINE, MODEKEYEDIT_ENDOFLINE, MODEKEYEDIT_ENTER, diff --git a/window-copy.c b/window-copy.c index 238508b8..dff7f479 100644 --- a/window-copy.c +++ b/window-copy.c @@ -365,6 +365,9 @@ window_copy_key_input(struct window_pane *wp, int key) if (inputlen > 0) data->inputstr[inputlen - 1] = '\0'; break; + case MODEKEYEDIT_DELETELINE: + *data->inputstr = '\0'; + break; case MODEKEYEDIT_ENTER: switch (data->inputtype) { case WINDOW_COPY_OFF: From 406fc209acd3ef784108363cd2bed2b54f70454c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 18 Aug 2009 09:51:51 +0000 Subject: [PATCH 0266/1180] Nuke unnecessary assignment. --- window-copy.c | 1 - 1 file changed, 1 deletion(-) diff --git a/window-copy.c b/window-copy.c index dff7f479..4ee3d4e3 100644 --- a/window-copy.c +++ b/window-copy.c @@ -596,7 +596,6 @@ window_copy_search_down(struct window_pane *wp, const char *searchstr) memcpy(&gc, &grid_default_cell, sizeof gc); screen_write_nputs(&ctx, -1, &gc, utf8flag, "%s", searchstr); screen_write_stop(&ctx); - searchlen = strlen(searchstr); fx = data->cx; fy = gd->hsize - data->oy + data->cy; From 1c58b941412ffb24ee46d6852802a6b453a3c9a3 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 18 Aug 2009 11:53:03 +0000 Subject: [PATCH 0267/1180] Use the full screen width when printing output rather than one less. --- window-more.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/window-more.c b/window-more.c index 9eefd79f..1ac453cc 100644 --- a/window-more.c +++ b/window-more.c @@ -188,7 +188,7 @@ window_more_write_line( if (data->top + py < ARRAY_LENGTH(&data->list)) { msg = ARRAY_ITEM(&data->list, data->top + py); screen_write_nputs( - ctx, screen_size_x(s) - 1 - size, &gc, utf8flag, "%s", msg); + ctx, screen_size_x(s) - size, &gc, utf8flag, "%s", msg); } while (s->cx < screen_size_x(s) - size) screen_write_putc(ctx, &gc, ' '); From 840fff5e5e3b841ced7fe78a4f783f7618cf8e15 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 18 Aug 2009 12:26:37 +0000 Subject: [PATCH 0268/1180] Change list-buffers to run the preview of the buffer through vis(1). --- cmd-list-buffers.c | 50 +++++++++++++++++++--------------------------- 1 file changed, 20 insertions(+), 30 deletions(-) diff --git a/cmd-list-buffers.c b/cmd-list-buffers.c index 2b5311ee..f32d32f5 100644 --- a/cmd-list-buffers.c +++ b/cmd-list-buffers.c @@ -19,6 +19,7 @@ #include #include +#include #include "tmux.h" @@ -46,44 +47,33 @@ cmd_list_buffers_exec(struct cmd *self, struct cmd_ctx *ctx) struct session *s; struct paste_buffer *pb; u_int idx; - char *tmp; - size_t size, in, out; + char tmp[51 * 4 + 1]; + size_t size, len; if ((s = cmd_find_session(ctx, data->target)) == NULL) return (-1); - if (s->sx > 35) { /* leave three for ... */ - size = s->sx - 32; - tmp = xmalloc(size + 1); - } else { - size = 0; - tmp = NULL; - } - idx = 0; while ((pb = paste_walk_stack(&s->buffers, &idx)) != NULL) { - if (tmp != NULL) { - in = out = 0; - while (out < size && pb->data[in] != '\0') { - if (pb->data[in] > 31 && pb->data[in] != 127) - tmp[out++] = pb->data[in]; - in++; - } - tmp[out] = '\0'; - if (out == size) { - tmp[out - 1] = '.'; - tmp[out - 2] = '.'; - tmp[out - 3] = '.'; - } + size = strlen(pb->data); - ctx->print(ctx, "%d: %zu bytes: \"%s\"", - idx - 1, strlen(pb->data), tmp); - } else - ctx->print(ctx, "%d: %zu bytes", idx, strlen(pb->data)); + /* Translate the first 50 characters. */ + len = size; + if (len > 50) + len = 50; + strvisx(tmp, pb->data, len, VIS_OCTAL|VIS_TAB|VIS_NL); + + /* + * If the first 50 characterswere encoded as a longer string, + * or there is definitely more data, add "...". + */ + if (size > 50 || strlen(tmp) > 50) { + tmp[50 - 3] = '\0'; + strlcat(tmp, "...", sizeof tmp); + } + + ctx->print(ctx, "%u: %zu bytes: \"%s\"", idx - 1, size, tmp); } - if (tmp != NULL) - xfree(tmp); - return (0); } From 003a2e6479a89320b89611bd05f74797b5533890 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 18 Aug 2009 13:08:43 +0000 Subject: [PATCH 0269/1180] Pass show-buffer output through vis(3) as well, and wrap it to the edge of the terminal when used from the command line. --- cmd-show-buffer.c | 55 +++++++++++++++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 19 deletions(-) diff --git a/cmd-show-buffer.c b/cmd-show-buffer.c index 795f5b25..0b525695 100644 --- a/cmd-show-buffer.c +++ b/cmd-show-buffer.c @@ -18,7 +18,8 @@ #include -#include +#include +#include #include "tmux.h" @@ -45,9 +46,9 @@ cmd_show_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) struct cmd_buffer_data *data = self->data; struct session *s; struct paste_buffer *pb; - u_int size; - char *buf, *ptr; - size_t len; + char *in, *buf, *ptr; + size_t size, len; + u_int width; if ((s = cmd_find_session(ctx, data->target)) == NULL) return (-1); @@ -61,27 +62,43 @@ cmd_show_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) ctx->error(ctx, "no buffer %d", data->buffer); return (-1); } + if (pb == NULL) + return (0); - if (pb != NULL) { - size = s->sx; + size = strlen(pb->data); + if (size > SIZE_MAX / 4 - 1) + size = SIZE_MAX / 4 - 1; + in = xmalloc(size * 4 + 1); + strvisx(in, pb->data, size, VIS_OCTAL|VIS_TAB); - buf = xmalloc(size + 1); - len = 0; + width = s->sx; + if (ctx->cmdclient != NULL) + width = ctx->cmdclient->tty.sx; + + buf = xmalloc(width + 1); + len = 0; + + ptr = in; + do { + buf[len++] = *ptr++; + + if (len == width || buf[len - 1] == '\n') { + if (buf[len - 1] == '\n') + len--; + buf[len] = '\0'; - ptr = pb->data; - do { - buf[len++] = *ptr++; - - if (len == size) { - buf[len] = '\0'; - ctx->print(ctx, buf); - - len = 0; - } - } while (*ptr != '\0'); + ctx->print(ctx, "%s", buf); + len = 0; + } + } while (*ptr != '\0'); + + if (len != 0) { buf[len] = '\0'; ctx->print(ctx, buf); } + xfree(buf); + + xfree(in); return (0); } From dc6271cd79947c020fc21a9d5641de6d576f61f2 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 18 Aug 2009 14:48:42 +0000 Subject: [PATCH 0270/1180] Tag a few missed printf-like functions and fix a missing "%s". --- cmd-server-info.c | 8 ++++---- cmd-show-buffer.c | 2 +- tmux.h | 10 +++++----- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/cmd-server-info.c b/cmd-server-info.c index 396d15b0..daa08572 100644 --- a/cmd-server-info.c +++ b/cmd-server-info.c @@ -81,7 +81,7 @@ cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx) ctx->print(ctx, "protocol version is %d", PROTOCOL_VERSION); ctx->print(ctx, "%u clients, %u sessions", ARRAY_LENGTH(&clients), ARRAY_LENGTH(&sessions)); - ctx->print(ctx, ""); + ctx->print(ctx, "%s", ""); ctx->print(ctx, "Clients:"); for (i = 0; i < ARRAY_LENGTH(&clients); i++) { @@ -94,7 +94,7 @@ cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx) c->session->name, c->tty.sx, c->tty.sy, c->tty.termname, c->flags, c->tty.flags); } - ctx->print(ctx, ""); + ctx->print(ctx, "%s", ""); ctx->print(ctx, "Sessions: [%zu/%zu]", sizeof (struct grid_cell), sizeof (struct grid_utf8)); @@ -142,7 +142,7 @@ cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx) } } } - ctx->print(ctx, ""); + ctx->print(ctx, "%s", ""); ctx->print(ctx, "Terminals:"); SLIST_FOREACH(term, &tty_terms, entry) { @@ -174,7 +174,7 @@ cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx) } } } - ctx->print(ctx, ""); + ctx->print(ctx, "%s", ""); return (0); } diff --git a/cmd-show-buffer.c b/cmd-show-buffer.c index 0b525695..8972f098 100644 --- a/cmd-show-buffer.c +++ b/cmd-show-buffer.c @@ -94,7 +94,7 @@ cmd_show_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) if (len != 0) { buf[len] = '\0'; - ctx->print(ctx, buf); + ctx->print(ctx, "%s", buf); } xfree(buf); diff --git a/tmux.h b/tmux.h index 4ba1cec4..4aa844b8 100644 --- a/tmux.h +++ b/tmux.h @@ -991,9 +991,9 @@ struct cmd_ctx { struct msg_command_data *msgdata; - void (*print)(struct cmd_ctx *, const char *, ...); - void (*info)(struct cmd_ctx *, const char *, ...); - void (*error)(struct cmd_ctx *, const char *, ...); + void printflike2 (*print)(struct cmd_ctx *, const char *, ...); + void printflike2 (*info)(struct cmd_ctx *, const char *, ...); + void printflike2 (*error)(struct cmd_ctx *, const char *, ...); }; struct cmd { @@ -1722,8 +1722,8 @@ void printflike1 log_warnx(const char *, ...); void printflike1 log_info(const char *, ...); void printflike1 log_debug(const char *, ...); void printflike1 log_debug2(const char *, ...); -__dead void log_fatal(const char *, ...); -__dead void log_fatalx(const char *, ...); +__dead void printflike1 log_fatal(const char *, ...); +__dead void printflike1 log_fatalx(const char *, ...); /* xmalloc.c */ char *xstrdup(const char *); From 145ba777e8ad6cca977e6b310de15145e4f1c321 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 18 Aug 2009 16:21:04 +0000 Subject: [PATCH 0271/1180] Now that pane targets (-t) are supported, switch some commands to use them where it makes sense: clock-mode, copy-mode, scroll-mode, send-keys, send-prefix. --- cmd-clock-mode.c | 8 ++++---- cmd-copy-mode.c | 6 ++---- cmd-scroll-mode.c | 6 ++---- cmd-send-keys.c | 12 +++++------- cmd-send-prefix.c | 8 ++++---- tmux.1 | 10 +++++----- 6 files changed, 22 insertions(+), 28 deletions(-) diff --git a/cmd-clock-mode.c b/cmd-clock-mode.c index 0fc43a54..b1f135a6 100644 --- a/cmd-clock-mode.c +++ b/cmd-clock-mode.c @@ -28,7 +28,7 @@ int cmd_clock_mode_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_clock_mode_entry = { "clock-mode", NULL, - CMD_TARGET_WINDOW_USAGE, + CMD_TARGET_PANE_USAGE, 0, 0, cmd_target_init, cmd_target_parse, @@ -41,12 +41,12 @@ int cmd_clock_mode_exec(struct cmd *self, struct cmd_ctx *ctx) { struct cmd_target_data *data = self->data; - struct winlink *wl; + struct window_pane *wp; - if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) + if (cmd_find_pane(ctx, data->target, NULL, &wp) == NULL) return (-1); - window_pane_set_mode(wl->window->active, &window_clock_mode); + window_pane_set_mode(wp, &window_clock_mode); return (0); } diff --git a/cmd-copy-mode.c b/cmd-copy-mode.c index 3e6b2228..f72f1c1b 100644 --- a/cmd-copy-mode.c +++ b/cmd-copy-mode.c @@ -28,7 +28,7 @@ int cmd_copy_mode_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_copy_mode_entry = { "copy-mode", NULL, - "[-u] " CMD_TARGET_WINDOW_USAGE, + "[-u] " CMD_TARGET_PANE_USAGE, 0, CMD_CHFLAG('u'), cmd_target_init, cmd_target_parse, @@ -41,12 +41,10 @@ int cmd_copy_mode_exec(struct cmd *self, struct cmd_ctx *ctx) { struct cmd_target_data *data = self->data; - struct winlink *wl; struct window_pane *wp; - if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) + if (cmd_find_pane(ctx, data->target, NULL, &wp) == NULL) return (-1); - wp = wl->window->active; window_pane_set_mode(wp, &window_copy_mode); if (wp->mode == &window_copy_mode && data->chflags & CMD_CHFLAG('u')) diff --git a/cmd-scroll-mode.c b/cmd-scroll-mode.c index 935dcf03..b5e4d7c9 100644 --- a/cmd-scroll-mode.c +++ b/cmd-scroll-mode.c @@ -29,7 +29,7 @@ int cmd_scroll_mode_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_scroll_mode_entry = { "scroll-mode", NULL, - "[-u] " CMD_TARGET_WINDOW_USAGE, + "[-u] " CMD_TARGET_PANE_USAGE, 0, CMD_CHFLAG('u'), cmd_scroll_mode_init, cmd_target_parse, @@ -57,12 +57,10 @@ int cmd_scroll_mode_exec(struct cmd *self, struct cmd_ctx *ctx) { struct cmd_target_data *data = self->data; - struct winlink *wl; struct window_pane *wp; - if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) + if (cmd_find_pane(ctx, data->target, NULL, &wp) == NULL) return (-1); - wp = wl->window->active; window_pane_set_mode(wp, &window_scroll_mode); if (wp->mode == &window_scroll_mode && data->chflags & CMD_CHFLAG('u')) diff --git a/cmd-send-keys.c b/cmd-send-keys.c index 04b21f95..037cbf33 100644 --- a/cmd-send-keys.c +++ b/cmd-send-keys.c @@ -40,7 +40,7 @@ struct cmd_send_keys_data { const struct cmd_entry cmd_send_keys_entry = { "send-keys", "send", - "[-t target-window] key ...", + "[-t target-pane] key ...", 0, 0, NULL, cmd_send_keys_parse, @@ -106,19 +106,17 @@ int cmd_send_keys_exec(struct cmd *self, struct cmd_ctx *ctx) { struct cmd_send_keys_data *data = self->data; - struct winlink *wl; + struct window_pane *wp; u_int i; if (data == NULL) return (-1); - if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) + if (cmd_find_pane(ctx, data->target, NULL, &wp) == NULL) return (-1); - for (i = 0; i < data->nkeys; i++) { - window_pane_key( - wl->window->active, ctx->curclient, data->keys[i]); - } + for (i = 0; i < data->nkeys; i++) + window_pane_key(wp, ctx->curclient, data->keys[i]); return (0); } diff --git a/cmd-send-prefix.c b/cmd-send-prefix.c index cc857ec3..aeefc701 100644 --- a/cmd-send-prefix.c +++ b/cmd-send-prefix.c @@ -28,7 +28,7 @@ int cmd_send_prefix_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_send_prefix_entry = { "send-prefix", NULL, - CMD_TARGET_WINDOW_USAGE, + CMD_TARGET_PANE_USAGE, 0, 0, cmd_target_init, cmd_target_parse, @@ -42,14 +42,14 @@ cmd_send_prefix_exec(struct cmd *self, struct cmd_ctx *ctx) { struct cmd_target_data *data = self->data; struct session *s; - struct winlink *wl; + struct window_pane *wp; int key; - if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL) + if (cmd_find_pane(ctx, data->target, &s, &wp) == NULL) return (-1); key = options_get_number(&s->options, "prefix"); - window_pane_key(wl->window->active, ctx->curclient, key); + window_pane_key(wp, ctx->curclient, key); return (0); } diff --git a/tmux.1 b/tmux.1 index 3213b32b..b811c81e 100644 --- a/tmux.1 +++ b/tmux.1 @@ -528,7 +528,7 @@ The mode commands are as follows: .Bl -tag -width Ds .It Xo Ic copy-mode .Op Fl u -.Op Fl t Ar target-window +.Op Fl t Ar target-pane .Xc Enter copy mode. The @@ -536,7 +536,7 @@ The option scrolls one page up. .It Xo Ic scroll-mode .Op Fl u -.Op Fl t Ar target-window +.Op Fl t Ar target-pane .Xc Enter scroll mode. The @@ -970,7 +970,7 @@ are listed; this may be one of: or .Em emacs-copy . .It Xo Ic send-keys -.Op Fl t Ar target-window +.Op Fl t Ar target-pane .Ar key Ar ... .Xc .D1 (alias: Ic send ) @@ -984,7 +984,7 @@ or ) to send; if the string is not recognised as a key, it is sent as a series of characters. All arguments are sent sequentially from first to last. -.It Ic send-prefix Op Fl t Ar target-window +.It Ic send-prefix Op Fl t Ar target-pane Send the prefix key to a window as if it was pressed. .It Xo Ic unbind-key .Op Fl cn @@ -1799,7 +1799,7 @@ Display the contents of the specified buffer. .Pp Miscellaneous commands are as follows: .Bl -tag -width Ds -.It Ic clock-mode Op Fl t Ar target-window +.It Ic clock-mode Op Fl t Ar target-pane Display a large clock. .It Ic if-shell Ar shell-command command .D1 (alias: Ic if ) From fa617467b12ca519b58878343c604026058d388d Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 18 Aug 2009 21:14:24 +0000 Subject: [PATCH 0272/1180] options_get_number() is relatively expensive and a check for dead panes happens a lot more often than actually finding one, so instead of getting the option for every check, get it for every dead window found. --- server.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/server.c b/server.c index 059e1b9d..18b11999 100644 --- a/server.c +++ b/server.c @@ -1106,13 +1106,12 @@ void server_check_window(struct window *w) { struct window_pane *wp, *wq; + struct options *oo = &w->options; struct client *c; struct session *s; struct winlink *wl; u_int i, j; - int destroyed, flag; - - flag = options_get_number(&w->options, "remain-on-exit"); + int destroyed; destroyed = 1; @@ -1125,7 +1124,7 @@ server_check_window(struct window *w) * the window to be destroyed (or it'll close when the last * pane dies). */ - if (wp->fd == -1 && !flag) { + if (wp->fd == -1 && options_get_number(oo, "remain-on-exit")) { layout_close_pane(wp); window_remove_pane(w, wp); server_redraw_window(w); From 8b7be5861e193212d0a98aa1decdcf827e9882f8 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 18 Aug 2009 21:18:20 +0000 Subject: [PATCH 0273/1180] Move another expensive options test to after a cheaper timer check/update. --- names.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/names.c b/names.c index 172dc496..915d06bf 100644 --- a/names.c +++ b/names.c @@ -42,8 +42,6 @@ set_window_names(void) w = ARRAY_ITEM(&windows, i); if (w == NULL || w->active == NULL) continue; - if (!options_get_number(&w->options, "automatic-rename")) - continue; if (timercmp(&tv, &w->name_timer, <)) continue; @@ -52,6 +50,9 @@ set_window_names(void) tv2.tv_usec = NAME_INTERVAL * 1000L; timeradd(&w->name_timer, &tv2, &w->name_timer); + if (!options_get_number(&w->options, "automatic-rename")) + continue; + if (w->active->screen != &w->active->base) name = NULL; else From c488e5e40d37d441cd0d19cec0663015457a1337 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 18 Aug 2009 21:37:04 +0000 Subject: [PATCH 0274/1180] Whoops, getting the comparison the right way round is usually recommended. --- server.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server.c b/server.c index 18b11999..707b4e49 100644 --- a/server.c +++ b/server.c @@ -1124,7 +1124,7 @@ server_check_window(struct window *w) * the window to be destroyed (or it'll close when the last * pane dies). */ - if (wp->fd == -1 && options_get_number(oo, "remain-on-exit")) { + if (wp->fd == -1 && !options_get_number(oo, "remain-on-exit")) { layout_close_pane(wp); window_remove_pane(w, wp); server_redraw_window(w); From 036de0c5e44ba374707e86b313e4f848488ebdea Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 18 Aug 2009 21:41:13 +0000 Subject: [PATCH 0275/1180] Instead of just checking for an empty buffer, which may not be the case if there is unconsumed data, save the previous size and use it instead. This means that activity monitoring should work in this (unlikely) event. Also remove a debugging statement that no longer seems necessary. --- input.c | 10 +++++----- tmux.h | 1 + 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/input.c b/input.c index 4cfd3522..7b43f261 100644 --- a/input.c +++ b/input.c @@ -235,6 +235,8 @@ input_init(struct window_pane *wp) ictx->saved_cy = 0; input_state(ictx, input_state_first); + + ictx->was = 0; } void @@ -252,8 +254,9 @@ input_parse(struct window_pane *wp) struct input_ctx *ictx = &wp->ictx; u_char ch; - if (BUFFER_USED(wp->in) == 0) + if (BUFFER_USED(wp->in) == ictx->was) return; + wp->window->flags |= WINDOW_ACTIVITY; ictx->buf = BUFFER_OUT(wp->in); ictx->len = BUFFER_USED(wp->in); @@ -261,15 +264,11 @@ input_parse(struct window_pane *wp) ictx->wp = wp; - log_debug2("entry; buffer=%zu", ictx->len); - if (wp->mode == NULL) screen_write_start(&ictx->ctx, wp, &wp->base); else screen_write_start(&ictx->ctx, NULL, &wp->base); - if (ictx->off != ictx->len) - wp->window->flags |= WINDOW_ACTIVITY; while (ictx->off < ictx->len) { ch = ictx->buf[ictx->off++]; ictx->state(ch, ictx); @@ -278,6 +277,7 @@ input_parse(struct window_pane *wp) screen_write_stop(&ictx->ctx); buffer_remove(wp->in, ictx->len); + ictx->was = BUFFER_USED(wp->in); } void diff --git a/tmux.h b/tmux.h index 4aa844b8..f70d1f5c 100644 --- a/tmux.h +++ b/tmux.h @@ -617,6 +617,7 @@ struct input_ctx { u_char *buf; size_t len; size_t off; + size_t was; struct grid_cell cell; From 3f4418d84dd8865f1bba410fc796acb53277abbf Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 19 Aug 2009 10:39:50 +0000 Subject: [PATCH 0276/1180] Extend command-prompt with a -p option which is a comma-separated list of one or more prompts to present in order. The responses to the prompt are replaced in the template string: %% are replaced in order, so the first prompt replaces the first %%, the second replaces the second, and so on. In addition, %1 up to %9 are replaced with the responses to the first the ninth prompts The default template is "%1" so the response to the first prompt is processed as a command. Note that this changes the behaviour for %% so if there is only one prompt, only the first %% will be replaced. Templates such as "neww -n '%%' 'ssh %%'" should be changed to "neww -n '%1' 'ssh %1'". From Tiago Cunha. --- cmd-command-prompt.c | 272 +++++++++++++++++++++++++++++++------------ status.c | 14 +++ tmux.1 | 28 ++++- tmux.h | 1 + 4 files changed, 238 insertions(+), 77 deletions(-) diff --git a/cmd-command-prompt.c b/cmd-command-prompt.c index dac334b2..e4954ddd 100644 --- a/cmd-command-prompt.c +++ b/cmd-command-prompt.c @@ -27,56 +27,112 @@ * Prompt for command in client. */ -void cmd_command_prompt_init(struct cmd *, int); -int cmd_command_prompt_exec(struct cmd *, struct cmd_ctx *); +void cmd_command_prompt_init(struct cmd *, int); +int cmd_command_prompt_parse(struct cmd *, int, char **, char **); +int cmd_command_prompt_exec(struct cmd *, struct cmd_ctx *); +void cmd_command_prompt_free(struct cmd *); +size_t cmd_command_prompt_print(struct cmd *, char *, size_t); -int cmd_command_prompt_callback(void *, const char *); -void cmd_command_prompt_free(void *); +int cmd_command_prompt_callback(void *, const char *); +void cmd_command_prompt_cfree(void *); +char *cmd_command_prompt_replace(char *, const char *, int); const struct cmd_entry cmd_command_prompt_entry = { "command-prompt", NULL, - CMD_TARGET_CLIENT_USAGE " [template]", - CMD_ARG01, 0, + CMD_TARGET_CLIENT_USAGE " [-p prompts] [template]", + 0, 0, cmd_command_prompt_init, - cmd_target_parse, + cmd_command_prompt_parse, cmd_command_prompt_exec, - cmd_target_free, - cmd_target_print + cmd_command_prompt_free, + cmd_command_prompt_print }; struct cmd_command_prompt_data { + char *prompts; + char *target; + char *template; +}; + +struct cmd_command_prompt_cdata { struct client *c; + char *next_prompt; + char *prompts; char *template; + int idx; }; void cmd_command_prompt_init(struct cmd *self, int key) { - struct cmd_target_data *data; + struct cmd_command_prompt_data *data; - cmd_target_init(self, key); - data = self->data; + self->data = data = xmalloc(sizeof *data); + data->prompts = NULL; + data->target = NULL; + data->template = NULL; switch (key) { case ',': - data->arg = xstrdup("rename-window '%%'"); + data->template = xstrdup("rename-window '%%'"); break; case '.': - data->arg = xstrdup("move-window -t '%%'"); + data->template = xstrdup("move-window -t '%%'"); break; case 'f': - data->arg = xstrdup("find-window '%%'"); + data->template = xstrdup("find-window '%%'"); break; } } +int +cmd_command_prompt_parse(struct cmd *self, int argc, char **argv, char **cause) +{ + struct cmd_command_prompt_data *data; + int opt; + + self->entry->init(self, 0); + data = self->data; + + while ((opt = getopt(argc, argv, "p:t:")) != -1) { + switch (opt) { + case 'p': + if (data->prompts == NULL) + data->prompts = xstrdup(optarg); + break; + case 't': + if (data->target == NULL) + data->target = xstrdup(optarg); + break; + default: + goto usage; + } + } + argc -= optind; + argv += optind; + if (argc != 0 && argc != 1) + goto usage; + + if (argc == 1) + data->template = xstrdup(argv[0]); + + return (0); + +usage: + xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); + + self->entry->free(self); + return (-1); +} + int cmd_command_prompt_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; - struct cmd_command_prompt_data *cdata; + struct cmd_command_prompt_data *data = self->data; + struct cmd_command_prompt_cdata *cdata; struct client *c; - char *hdr, *ptr; + char *prompt, *ptr; + size_t n; if ((c = cmd_find_client(ctx, data->target)) == NULL) return (-1); @@ -86,76 +142,100 @@ cmd_command_prompt_exec(struct cmd *self, struct cmd_ctx *ctx) cdata = xmalloc(sizeof *cdata); cdata->c = c; - if (data->arg != NULL) { - cdata->template = xstrdup(data->arg); - if ((ptr = strchr(data->arg, ' ')) == NULL) - ptr = strchr(data->arg, '\0'); - xasprintf(&hdr, "(%.*s) ", (int) (ptr - data->arg), data->arg); - } else { - cdata->template = NULL; - hdr = xstrdup(":"); - } - status_prompt_set(c, hdr, - cmd_command_prompt_callback, cmd_command_prompt_free, cdata, 0); - xfree(hdr); + cdata->idx = 1; + cdata->next_prompt = NULL; + cdata->prompts = NULL; + cdata->template = NULL; + + if (data->template != NULL) + cdata->template = xstrdup(data->template); + else + cdata->template = xstrdup("%1"); + if (data->prompts != NULL) + cdata->prompts = xstrdup(data->prompts); + else if (data->template != NULL) { + n = strcspn(data->template, " ,"); + xasprintf(&cdata->prompts, "(%.*s) ", (int) n, data->template); + } else + cdata->prompts = xstrdup(":"); + + cdata->next_prompt = cdata->prompts; + ptr = strsep(&cdata->next_prompt, ","); + if (data->prompts == NULL) + prompt = xstrdup(ptr); + else + xasprintf(&prompt, "%s ", ptr); + status_prompt_set(c, prompt, cmd_command_prompt_callback, + cmd_command_prompt_cfree, cdata, 0); + xfree(prompt); return (0); } +void +cmd_command_prompt_free(struct cmd *self) +{ + struct cmd_command_prompt_data *data = self->data; + + if (data->prompts != NULL) + xfree(data->prompts); + if (data->target != NULL) + xfree(data->target); + if (data->template != NULL) + xfree(data->template); + xfree(data); +} + +size_t +cmd_command_prompt_print(struct cmd *self, char *buf, size_t len) +{ + struct cmd_command_prompt_data *data = self->data; + size_t off = 0; + + off += xsnprintf(buf, len, "%s", self->entry->name); + if (data == NULL) + return (off); + if (off < len && data->prompts != NULL) + off += cmd_prarg(buf + off, len - off, " -p ", data->prompts); + if (off < len && data->target != NULL) + off += cmd_prarg(buf + off, len - off, " -t ", data->target); + if (off < len && data->template != NULL) + off += cmd_prarg(buf + off, len - off, " ", data->template); + return (off); +} + int cmd_command_prompt_callback(void *data, const char *s) { - struct cmd_command_prompt_data *cdata = data; + struct cmd_command_prompt_cdata *cdata = data; struct client *c = cdata->c; struct cmd_list *cmdlist; - struct cmd_ctx ctx; - char *cause, *ptr, *buf, ch; - size_t len, slen; + struct cmd_ctx ctx; + char *cause, *newtempl, *prompt, *ptr; - if (s == NULL || *s == '\0') + if (s == NULL) return (0); - slen = strlen(s); - len = 0; - buf = NULL; - if (cdata->template != NULL) { - ptr = cdata->template; - while (*ptr != '\0') { - switch (ch = *ptr++) { - case '%': - if (*ptr != '%') - break; - ptr++; + newtempl = cmd_command_prompt_replace(cdata->template, s, cdata->idx); + xfree(cdata->template); + cdata->template = newtempl; - buf = xrealloc(buf, 1, len + slen + 1); - memcpy(buf + len, s, slen); - len += slen; - break; - default: - buf = xrealloc(buf, 1, len + 2); - buf[len++] = ch; - break; - } + if ((ptr = strsep(&cdata->next_prompt, ",")) != NULL) { + xasprintf(&prompt, "%s ", ptr); + status_prompt_update(c, prompt); + xfree(prompt); + cdata->idx++; + return (1); + } + + if (cmd_string_parse(newtempl, &cmdlist, &cause) != 0) { + if (cause != NULL) { + *cause = toupper((u_char) *cause); + status_message_set(c, "%s", cause); + xfree(cause); } - - if (buf == NULL) - return (0); - buf[len] = '\0'; - s = buf; - } - - if (cmd_string_parse(s, &cmdlist, &cause) != 0) { - if (cause == NULL) - return (0); - *cause = toupper((u_char) *cause); - status_message_set(c, "%s", cause); - xfree(cause); - cmdlist = NULL; - } - if (buf != NULL) - xfree(buf); - if (cmdlist == NULL) return (0); + } ctx.msgdata = NULL; ctx.cursession = c->session; @@ -176,11 +256,53 @@ cmd_command_prompt_callback(void *data, const char *s) } void -cmd_command_prompt_free(void *data) +cmd_command_prompt_cfree(void *data) { - struct cmd_command_prompt_data *cdata = data; + struct cmd_command_prompt_cdata *cdata = data; + if (cdata->prompts != NULL) + xfree(cdata->prompts); if (cdata->template != NULL) xfree(cdata->template); xfree(cdata); } + +char * +cmd_command_prompt_replace(char *template, const char *s, int idx) +{ + char ch; + char *buf, *ptr; + int replaced; + size_t len; + + if (strstr(template, "%") == NULL) + return (xstrdup(template)); + + buf = xmalloc(1); + *buf = '\0'; + len = 0; + replaced = 0; + + ptr = template; + while (*ptr != '\0') { + switch (ch = *ptr++) { + case '%': + if (*ptr < '1' || *ptr > '9' || *ptr - '0' != idx) { + if (*ptr != '%' || replaced) + break; + replaced = 1; + } + ptr++; + + len += strlen(s); + buf = xrealloc(buf, 1, len + 1); + strlcat(buf, s, len + 1); + continue; + } + buf = xrealloc(buf, 1, len + 2); + buf[len++] = ch; + buf[len] = '\0'; + } + + return (buf); +} diff --git a/status.c b/status.c index d700f2c7..b4f23702 100644 --- a/status.c +++ b/status.c @@ -668,6 +668,20 @@ status_prompt_clear(struct client *c) screen_reinit(&c->status); } +void +status_prompt_update(struct client *c, const char *msg) +{ + xfree(c->prompt_string); + c->prompt_string = xstrdup(msg); + + *c->prompt_buffer = '\0'; + c->prompt_index = 0; + + c->prompt_hindex = 0; + + c->flags |= CLIENT_STATUS; +} + /* Draw client prompt on status line of present else on last line. */ int status_prompt_redraw(struct client *c) diff --git a/tmux.1 b/tmux.1 index b811c81e..f5f05f06 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1662,6 +1662,7 @@ session option. Commands related to the status line are as follows: .Bl -tag -width Ds .It Xo Ic command-prompt +.Op Fl p Ar prompts .Op Fl t Ar target-client .Op Ar template .Xc @@ -1671,8 +1672,30 @@ This may be used from inside to execute commands interactively. If .Ar template -is specified, it is used as the command; any %% in the template will be -replaced by what is entered at the prompt. +is specified, it is used as the command. +If +.Fl p +is given, +.Ar prompts +is a comma-separated list of prompts which are displayed in order; otherwise +a single prompt is displayed, constructed from +.Ar template +if it is present, or +.Ql \&: +if not. +Before the command is executed, the first occurrence of the string +.Ql %% +and all occurences of +.Ql %1 +are replaced by the response to the first prompt, the second +.Ql %% +and all +.Ql %2 +are replaced with the response to the second prompt, and so on for further +prompts. Up to nine prompt responses may be replaced +.Ns ( Ql %1 +to +.Ns Ql %9 ) . .It Xo Ic confirm-before .Op Fl t Ar target-client .Ar command @@ -1926,6 +1949,7 @@ Creating new key bindings: .Bd -literal -offset indent bind-key b set-option status bind-key / command-prompt "split-window 'exec man %%'" +bind-key S command-prompt "new-window -n %1 'ssh %1'" .Ed .Sh SEE ALSO .Xr pty 4 diff --git a/tmux.h b/tmux.h index f70d1f5c..4b388360 100644 --- a/tmux.h +++ b/tmux.h @@ -1440,6 +1440,7 @@ void status_prompt_set(struct client *, const char *, void status_prompt_clear(struct client *); int status_prompt_redraw(struct client *); void status_prompt_key(struct client *, int); +void status_prompt_update(struct client *, const char *); /* resize.c */ void recalculate_sizes(void); From c41aa49059a3c5d475a55c174aa0f7b509f67534 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 19 Aug 2009 14:32:15 +0000 Subject: [PATCH 0277/1180] Use cfsetispeed/cfsetospeed to set termios speed members. --- cmd-new-session.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd-new-session.c b/cmd-new-session.c index ff90e3be..bffdb2b8 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -212,8 +212,8 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) tio.c_oflag = TTYDEF_OFLAG; tio.c_lflag = TTYDEF_LFLAG; tio.c_cflag = TTYDEF_CFLAG; - tio.c_ispeed = TTYDEF_SPEED; - tio.c_ospeed = TTYDEF_SPEED; + cfsetispeed(&tio, TTYDEF_SPEED); + cfsetospeed(&tio, TTYDEF_SPEED); /* Create the new session. */ idx = -1 - options_get_number(&global_s_options, "base-index"); From 55336657d45196221203cbaa162128755243bb0c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 19 Aug 2009 14:46:56 +0000 Subject: [PATCH 0278/1180] Don't read beyond the edge of the screen when searching (dies with debug enabled). --- window-copy.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/window-copy.c b/window-copy.c index 4ee3d4e3..63c31829 100644 --- a/window-copy.c +++ b/window-copy.c @@ -504,6 +504,8 @@ window_copy_search_rl(struct grid *gd, u_int ax, bx, px; for (ax = last + 1; ax > first; ax--) { + if (gd->sx - (ax - 1) < sgd->sx) + continue; for (bx = 0; bx < sgd->sx; bx++) { px = ax - 1 + bx; if (!window_copy_search_compare(gd, px, py, sgd, bx)) From c741f2f4a6f49675fad6344c8540c2054f7ea2c9 Mon Sep 17 00:00:00 2001 From: Jason McIntyre Date: Wed, 19 Aug 2009 16:10:26 +0000 Subject: [PATCH 0279/1180] tweak previous; --- tmux.1 | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tmux.1 b/tmux.1 index f5f05f06..11282404 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1685,17 +1685,20 @@ if it is present, or if not. Before the command is executed, the first occurrence of the string .Ql %% -and all occurences of +and all occurrences of .Ql %1 are replaced by the response to the first prompt, the second .Ql %% and all .Ql %2 are replaced with the response to the second prompt, and so on for further -prompts. Up to nine prompt responses may be replaced -.Ns ( Ql %1 +prompts. +Up to nine prompt responses may be replaced +.Po +.Ql %1 to -.Ns Ql %9 ) . +.Ql %9 +.Pc . .It Xo Ic confirm-before .Op Fl t Ar target-client .Ar command From bf121f7c6011a219f316745e2a4182830fc0a85a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 19 Aug 2009 17:00:31 +0000 Subject: [PATCH 0280/1180] Handle the device attributes (DA) escape sequence. --- input.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/input.c b/input.c index 7b43f261..15104faf 100644 --- a/input.c +++ b/input.c @@ -68,6 +68,7 @@ void input_handle_sequence_cuf(struct input_ctx *); void input_handle_sequence_cub(struct input_ctx *); void input_handle_sequence_dch(struct input_ctx *); void input_handle_sequence_cbt(struct input_ctx *); +void input_handle_sequence_da(struct input_ctx *); void input_handle_sequence_dl(struct input_ctx *); void input_handle_sequence_ich(struct input_ctx *); void input_handle_sequence_il(struct input_ctx *); @@ -104,6 +105,7 @@ const struct input_sequence_entry input_sequence_table[] = { { 'M', input_handle_sequence_dl }, { 'P', input_handle_sequence_dch }, { 'Z', input_handle_sequence_cbt }, + { 'c', input_handle_sequence_da }, { 'd', input_handle_sequence_vpa }, { 'f', input_handle_sequence_cup }, { 'g', input_handle_sequence_tbc }, @@ -951,6 +953,25 @@ input_handle_sequence_cbt(struct input_ctx *ictx) } } +void +input_handle_sequence_da(struct input_ctx *ictx) +{ + struct screen *s = ictx->ctx.s; + uint16_t n; + + if (ictx->private != '\0') + return; + + if (ARRAY_LENGTH(&ictx->args) > 1) + return; + if (input_get_argument(ictx, 0, &n, 0) != 0) + return; + if (n != 0) + return; + + buffer_write(ictx->wp->out, "\033[?1;2c", (sizeof "\033[?1;2c") - 1); +} + void input_handle_sequence_dl(struct input_ctx *ictx) { From 234ad54b2c7b1b1b9a78d3ecc20d29c12dd2f107 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 20 Aug 2009 10:48:25 +0000 Subject: [PATCH 0281/1180] Nuke unused variable. --- input.c | 1 - 1 file changed, 1 deletion(-) diff --git a/input.c b/input.c index 15104faf..ba3d9223 100644 --- a/input.c +++ b/input.c @@ -956,7 +956,6 @@ input_handle_sequence_cbt(struct input_ctx *ictx) void input_handle_sequence_da(struct input_ctx *ictx) { - struct screen *s = ictx->ctx.s; uint16_t n; if (ictx->private != '\0') From 1501b3fbbdf405aae7dc996a60bd22a49c884110 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 20 Aug 2009 19:14:42 +0000 Subject: [PATCH 0282/1180] A few trivial optimisations: no need to check for zero size if calling buffer_ensure in buffer.c; expand grid lines by a greater increase than one each time; and don't read UTF-8 data unless it actually needs to be checked when overwriting a cell. --- buffer.c | 5 +---- grid.c | 4 ++++ screen-write.c | 26 +++++++++++++++----------- 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/buffer.c b/buffer.c index f52d6352..5505bf74 100644 --- a/buffer.c +++ b/buffer.c @@ -100,9 +100,6 @@ buffer_remove(struct buffer *b, size_t size) void buffer_write(struct buffer *b, const void *data, size_t size) { - if (size == 0) - fatalx("zero size"); - buffer_ensure(b, size); memcpy(BUFFER_IN(b), data, size); buffer_add(b, size); @@ -127,7 +124,7 @@ buffer_write8(struct buffer *b, uint8_t n) { buffer_ensure(b, 1); BUFFER_IN(b)[0] = n; - buffer_add(b, 1); + b->size++; } /* Extract an 8-bit value. */ diff --git a/grid.c b/grid.c index 50b3569a..31cc430b 100644 --- a/grid.c +++ b/grid.c @@ -198,6 +198,10 @@ grid_expand_line(struct grid *gd, u_int py, u_int sx) if (sx <= gl->cellsize) return; + if (gl->cellsize > gd->sx / 2) + sx = gd->sx; + else + sx = 1 + gl->cellsize * 2; gl->celldata = xrealloc(gl->celldata, sx, sizeof *gl->celldata); for (xx = gl->cellsize; xx < sx; xx++) grid_put_cell(gd, xx, py, &grid_default_cell); diff --git a/screen-write.c b/screen-write.c index d735d450..dd553f17 100644 --- a/screen-write.c +++ b/screen-write.c @@ -858,7 +858,8 @@ screen_write_overwrite(struct screen_write_ctx *ctx) u_int xx; gc = grid_view_peek_cell(gd, s->cx, s->cy); - gu = grid_view_peek_utf8(gd, s->cx, s->cy); + if (gc->flags & GRID_FLAG_UTF8) + gu = grid_view_peek_utf8(gd, s->cx, s->cy); if (gc->flags & GRID_FLAG_PADDING) { /* @@ -885,16 +886,19 @@ screen_write_overwrite(struct screen_write_ctx *ctx) break; grid_view_set_cell(gd, xx, s->cy, &grid_default_cell); } - } else if (gc->flags & GRID_FLAG_UTF8 && gu->width > 1) { - /* - * An UTF-8 wide cell; overwrite following padding cells only. - */ - xx = s->cx; - while (++xx < screen_size_x(s)) { - gc = grid_view_peek_cell(gd, xx, s->cy); - if (!(gc->flags & GRID_FLAG_PADDING)) - break; - grid_view_set_cell(gd, xx, s->cy, &grid_default_cell); + } else if (gc->flags & GRID_FLAG_UTF8) { + gu = grid_view_peek_utf8(gd, s->cx, s->cy); + if (gu->width > 1) { + /* + * An UTF-8 wide cell; overwrite following padding cells only. + */ + xx = s->cx; + while (++xx < screen_size_x(s)) { + gc = grid_view_peek_cell(gd, xx, s->cy); + if (!(gc->flags & GRID_FLAG_PADDING)) + break; + grid_view_set_cell(gd, xx, s->cy, &grid_default_cell); + } } } } From 0198bb6bf3f1b3877ca8def6d198642a2a41d342 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 21 Aug 2009 07:29:37 +0000 Subject: [PATCH 0283/1180] Fix grid_expand_line so it actually works when the required size is bigger than 2 * the current size. --- grid.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/grid.c b/grid.c index 31cc430b..b79e8843 100644 --- a/grid.c +++ b/grid.c @@ -189,19 +189,22 @@ grid_scroll_line(struct grid *gd) /* Expand line to fit to cell. */ void -grid_expand_line(struct grid *gd, u_int py, u_int sx) +grid_expand_line(struct grid *gd, u_int py, u_int wantx) { struct grid_line *gl; - u_int xx; + u_int xx, sx; gl = &gd->linedata[py]; - if (sx <= gl->cellsize) + if (wantx <= gl->cellsize) return; if (gl->cellsize > gd->sx / 2) sx = gd->sx; - else - sx = 1 + gl->cellsize * 2; + else { + sx = gl->cellsize + 1; + while (sx < wantx) + sx *= 2; + } gl->celldata = xrealloc(gl->celldata, sx, sizeof *gl->celldata); for (xx = gl->cellsize; xx < sx; xx++) grid_put_cell(gd, xx, py, &grid_default_cell); From f817a338d035d96cec8ceeaaa60a79ac01421563 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 21 Aug 2009 07:33:58 +0000 Subject: [PATCH 0284/1180] When moving up or down in copy mode, save the cursor position and size of the last line with content (width != 0) and use it to determine if the cursor should be at the end of the line. Fixes problem of the cursor always jumping to the end of the line when scrolling past a blank line. --- window-copy.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/window-copy.c b/window-copy.c index 63c31829..f102092c 100644 --- a/window-copy.c +++ b/window-copy.c @@ -97,6 +97,9 @@ struct window_copy_mode_data { u_int cx; u_int cy; + u_int lastcx; /* position in last line with content */ + u_int lastsx; /* size of last line with content */ + enum window_copy_input_type inputtype; const char *inputprompt; char *inputstr; @@ -119,6 +122,9 @@ window_copy_init(struct window_pane *wp) data->cx = wp->base.cx; data->cy = wp->base.cy; + data->lastcx = 0; + data->lastsx = 0; + data->inputtype = WINDOW_COPY_OFF; data->inputprompt = NULL; data->inputstr = xstrdup(""); @@ -1045,7 +1051,12 @@ window_copy_cursor_up(struct window_pane *wp) oy = screen_hsize(&wp->base) + data->cy - data->oy; ox = window_copy_find_length(wp, oy); + if (ox != 0) { + data->lastcx = data->cx; + data->lastsx = ox; + } + data->cx = data->lastcx; if (data->cy == 0) window_copy_scroll_down(wp, 1); else { @@ -1056,8 +1067,7 @@ window_copy_cursor_up(struct window_pane *wp) py = screen_hsize(&wp->base) + data->cy - data->oy; px = window_copy_find_length(wp, py); - - if (data->cx >= px || data->cx >= ox) + if (data->cx >= data->lastsx || data->cx > px) window_copy_cursor_end_of_line(wp); } @@ -1070,7 +1080,12 @@ window_copy_cursor_down(struct window_pane *wp) oy = screen_hsize(&wp->base) + data->cy - data->oy; ox = window_copy_find_length(wp, oy); + if (ox != 0) { + data->lastcx = data->cx; + data->lastsx = ox; + } + data->cx = data->lastcx; if (data->cy == screen_size_y(s) - 1) window_copy_scroll_up(wp, 1); else { @@ -1081,8 +1096,7 @@ window_copy_cursor_down(struct window_pane *wp) py = screen_hsize(&wp->base) + data->cy - data->oy; px = window_copy_find_length(wp, py); - - if (data->cx >= px || data->cx >= ox) + if (data->cx >= data->lastsx || data->cx > px) window_copy_cursor_end_of_line(wp); } From 65ac8e9f0c852cbf436243258c0c1878b20c3c87 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 21 Aug 2009 08:12:05 +0000 Subject: [PATCH 0285/1180] Ugh, committed the wrong version of this change and got both solutions rather than just the second. Remove unused assignment. --- screen-write.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/screen-write.c b/screen-write.c index dd553f17..bfb4e7f2 100644 --- a/screen-write.c +++ b/screen-write.c @@ -858,9 +858,6 @@ screen_write_overwrite(struct screen_write_ctx *ctx) u_int xx; gc = grid_view_peek_cell(gd, s->cx, s->cy); - if (gc->flags & GRID_FLAG_UTF8) - gu = grid_view_peek_utf8(gd, s->cx, s->cy); - if (gc->flags & GRID_FLAG_PADDING) { /* * A padding cell, so clear any following and leading padding From 915a1913e19dd254689f51bc228686f83f2d77ee Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 21 Aug 2009 11:36:08 +0000 Subject: [PATCH 0286/1180] Move reading termios settings to before tty_open alters them, and expand the comment. --- cmd-new-session.c | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/cmd-new-session.c b/cmd-new-session.c index bffdb2b8..73698d24 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -149,6 +149,27 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) if (ctx->cmdclient == NULL && ctx->curclient == NULL) detached = 1; + /* + * Fill in the termios settings used for new windows in this session; + * if there is a command client, use the control characters from it. + * + * This is read again with tcgetattr() rather than using tty.tio as if + * detached, tty_open won't be called. Because of this, it must be done + * before opening the terminal as that calls tcsetattr() to prepare for + * tmux taking over. + */ + if (ctx->cmdclient != NULL && ctx->cmdclient->tty.fd != -1) { + if (tcgetattr(ctx->cmdclient->tty.fd, &tio) != 0) + fatal("tcgetattr failed"); + } else + memcpy(tio.c_cc, ttydefchars, sizeof tio.c_cc); + tio.c_iflag = TTYDEF_IFLAG; + tio.c_oflag = TTYDEF_OFLAG; + tio.c_lflag = TTYDEF_LFLAG; + tio.c_cflag = TTYDEF_CFLAG; + cfsetispeed(&tio, TTYDEF_SPEED); + cfsetospeed(&tio, TTYDEF_SPEED); + /* Open the terminal if necessary. */ if (!detached && ctx->cmdclient != NULL) { if (!(ctx->cmdclient->flags & CLIENT_TERMINAL)) { @@ -199,22 +220,6 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) if (ctx->cmdclient != NULL) environ_update(update, &ctx->cmdclient->environ, &env); - /* - * Fill in the termios settings used for new windows in this session; - * if there is a command client, use the control characters from it. - */ - if (ctx->cmdclient != NULL && ctx->cmdclient->tty.fd != -1) { - if (tcgetattr(ctx->cmdclient->tty.fd, &tio) != 0) - fatal("tcgetattr failed"); - } else - memcpy(tio.c_cc, ttydefchars, sizeof tio.c_cc); - tio.c_iflag = TTYDEF_IFLAG; - tio.c_oflag = TTYDEF_OFLAG; - tio.c_lflag = TTYDEF_LFLAG; - tio.c_cflag = TTYDEF_CFLAG; - cfsetispeed(&tio, TTYDEF_SPEED); - cfsetospeed(&tio, TTYDEF_SPEED); - /* Create the new session. */ idx = -1 - options_get_number(&global_s_options, "base-index"); s = session_create( From 926b52b6002164b4bc82624674d488e7fe1e42c2 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 21 Aug 2009 12:29:59 +0000 Subject: [PATCH 0287/1180] Emulate dch/dch1 if missing by redrawing the entire line. --- tty-term.c | 4 ---- tty.c | 8 ++++++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tty-term.c b/tty-term.c index 37826dab..50b2520a 100644 --- a/tty-term.c +++ b/tty-term.c @@ -338,10 +338,6 @@ tty_term_find(char *name, int fd, const char *overrides, char **cause) "terminal does not support ich1 or ich or smir and rmir"); goto error; } - if (!tty_term_has(term, TTYC_DCH1) && !tty_term_has(term, TTYC_DCH)) { - xasprintf(cause, "terminal does not support dch1 or dch"); - goto error; - } /* * Figure out if terminal support default colours. AX is a screen diff --git a/tty.c b/tty.c index 0428a0cc..158bd527 100644 --- a/tty.c +++ b/tty.c @@ -596,7 +596,9 @@ tty_cmd_deletecharacter(struct tty *tty, const struct tty_ctx *ctx) struct window_pane *wp = ctx->wp; struct screen *s = wp->screen; - if (wp->xoff != 0 || screen_size_x(s) < tty->sx) { + if (wp->xoff != 0 || screen_size_x(s) < tty->sx || + (!tty_term_has(tty->term, TTYC_DCH) && + !tty_term_has(tty->term, TTYC_DCH1))) { tty_draw_line(tty, wp->screen, ctx->ocy, wp->xoff, wp->yoff); return; } @@ -604,7 +606,9 @@ tty_cmd_deletecharacter(struct tty *tty, const struct tty_ctx *ctx) tty_reset(tty); tty_cursor(tty, ctx->ocx, ctx->ocy, wp->xoff, wp->yoff); - tty_emulate_repeat(tty, TTYC_DCH, TTYC_DCH1, ctx->num); + if (tty_term_has(tty->term, TTYC_DCH) || + tty_term_has(tty->term, TTYC_DCH1)) + tty_emulate_repeat(tty, TTYC_DCH, TTYC_DCH1, ctx->num); } void From 1eb303e6d401c1ef2992933532eb2d7eab36cecf Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 23 Aug 2009 11:40:05 +0000 Subject: [PATCH 0288/1180] Check the return value of strunvis against -1 not NULL. --- tty-term.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tty-term.c b/tty-term.c index 50b2520a..dd3e8e00 100644 --- a/tty-term.c +++ b/tty-term.c @@ -173,7 +173,7 @@ tty_term_override(struct tty_term *term, const char *overrides) if ((ptr = strchr(entstr, '=')) != NULL) { *ptr++ = '\0'; val = xstrdup(ptr); - if (strunvis(val, ptr) == NULL) { + if (strunvis(val, ptr) == -1) { xfree(val); val = xstrdup(ptr); } From 43cd40e87a41d9504dcac99419c96e3cdbb81029 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 23 Aug 2009 16:45:00 +0000 Subject: [PATCH 0289/1180] The cursession member in struct cmd_ctx is always either curclient->session or NULL when curclient is also NULL, so just eliminate it. --- cfg.c | 1 - cmd-command-prompt.c | 1 - cmd-confirm-before.c | 1 - cmd.c | 4 ++-- key-bindings.c | 3 +-- server-msg.c | 1 - tmux.h | 2 -- 7 files changed, 3 insertions(+), 10 deletions(-) diff --git a/cfg.c b/cfg.c index 75390165..ec2d906d 100644 --- a/cfg.c +++ b/cfg.c @@ -88,7 +88,6 @@ load_cfg(const char *path, char **cause) cfg_cause = NULL; ctx.msgdata = NULL; - ctx.cursession = NULL; ctx.curclient = NULL; ctx.error = cfg_error; diff --git a/cmd-command-prompt.c b/cmd-command-prompt.c index e4954ddd..cd417a61 100644 --- a/cmd-command-prompt.c +++ b/cmd-command-prompt.c @@ -238,7 +238,6 @@ cmd_command_prompt_callback(void *data, const char *s) } ctx.msgdata = NULL; - ctx.cursession = c->session; ctx.curclient = c; ctx.error = key_bindings_error; diff --git a/cmd-confirm-before.c b/cmd-confirm-before.c index fd366b9b..d0a2196a 100644 --- a/cmd-confirm-before.c +++ b/cmd-confirm-before.c @@ -122,7 +122,6 @@ cmd_confirm_before_callback(void *data, const char *s) } ctx.msgdata = NULL; - ctx.cursession = c->session; ctx.curclient = c; ctx.error = key_bindings_error; diff --git a/cmd.c b/cmd.c index b0f785f9..21f2052f 100644 --- a/cmd.c +++ b/cmd.c @@ -299,8 +299,8 @@ cmd_current_session(struct cmd_ctx *ctx) u_int i; int found; - if (ctx->cursession != NULL) - return (ctx->cursession); + if (ctx->curclient != NULL && ctx->curclient->session != NULL) + return (ctx->curclient->session); /* * If the name of the calling client's pty is know, build a list of the diff --git a/key-bindings.c b/key-bindings.c index 186c1a9b..b2ccc4aa 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -218,7 +218,7 @@ key_bindings_error(struct cmd_ctx *ctx, const char *fmt, ...) void printflike2 key_bindings_print(struct cmd_ctx *ctx, const char *fmt, ...) { - struct winlink *wl = ctx->cursession->curw; + struct winlink *wl = ctx->curclient->session->curw; va_list ap; if (wl->window->active->mode != &window_more_mode) @@ -254,7 +254,6 @@ key_bindings_dispatch(struct key_binding *bd, struct client *c) struct cmd_ctx ctx; ctx.msgdata = NULL; - ctx.cursession = c->session; ctx.curclient = c; ctx.error = key_bindings_error; diff --git a/server-msg.c b/server-msg.c index e8aea526..54bd2439 100644 --- a/server-msg.c +++ b/server-msg.c @@ -188,7 +188,6 @@ server_msg_command(struct client *c, struct msg_command_data *data) ctx.msgdata = data; ctx.curclient = NULL; - ctx.cursession = NULL; ctx.cmdclient = c; diff --git a/tmux.h b/tmux.h index 4b388360..4cc659d6 100644 --- a/tmux.h +++ b/tmux.h @@ -988,8 +988,6 @@ struct cmd_ctx { struct client *curclient; struct client *cmdclient; - struct session *cursession; - struct msg_command_data *msgdata; void printflike2 (*print)(struct cmd_ctx *, const char *, ...); From c7394ac4e0f7e6e034fbb4b050de6f713bb9f6e0 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 23 Aug 2009 17:29:51 +0000 Subject: [PATCH 0290/1180] When using source-file, run the commands in the context of the source-file command rather than with no context. This makes things like attach work from a file. --- cfg.c | 15 ++++++++++----- cmd-source-file.c | 2 +- server.c | 4 ++-- tmux.h | 2 +- 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/cfg.c b/cfg.c index ec2d906d..d50eaae7 100644 --- a/cfg.c +++ b/cfg.c @@ -51,7 +51,7 @@ cfg_error(unused struct cmd_ctx *ctx, const char *fmt, ...) } int -load_cfg(const char *path, char **cause) +load_cfg(const char *path, struct cmd_ctx *ctxin, char **cause) { FILE *f; u_int n; @@ -87,15 +87,20 @@ load_cfg(const char *path, char **cause) continue; cfg_cause = NULL; - ctx.msgdata = NULL; - ctx.curclient = NULL; + if (ctxin == NULL) { + ctx.msgdata = NULL; + ctx.curclient = NULL; + ctx.cmdclient = NULL; + } else { + ctx.msgdata = ctxin->msgdata; + ctx.curclient = ctxin->curclient; + ctx.cmdclient = ctxin->cmdclient; + } ctx.error = cfg_error; ctx.print = cfg_print; ctx.info = cfg_print; - ctx.cmdclient = NULL; - cfg_cause = NULL; cmd_list_exec(cmdlist, &ctx); cmd_list_free(cmdlist); diff --git a/cmd-source-file.c b/cmd-source-file.c index b42c5785..247b06ec 100644 --- a/cmd-source-file.c +++ b/cmd-source-file.c @@ -90,7 +90,7 @@ cmd_source_file_exec(struct cmd *self, struct cmd_ctx *ctx) struct cmd_source_file_data *data = self->data; char *cause; - if (load_cfg(data->path, &cause) != 0) { + if (load_cfg(data->path, ctx, &cause) != 0) { ctx->error(ctx, "%s", cause); xfree(cause); return (-1); diff --git a/server.c b/server.c index 707b4e49..3f15ca41 100644 --- a/server.c +++ b/server.c @@ -188,9 +188,9 @@ server_start(char *path) &cause, "%s: %s", strerror(errno), SYSTEM_CFG); goto error; } - } else if (load_cfg(SYSTEM_CFG, &cause) != 0) + } else if (load_cfg(SYSTEM_CFG, NULL, &cause) != 0) goto error; - if (cfg_file != NULL && load_cfg(cfg_file, &cause) != 0) + if (cfg_file != NULL && load_cfg(cfg_file, NULL, &cause) != 0) goto error; exit(server_main(srv_fd)); diff --git a/tmux.h b/tmux.h index 4cc659d6..a2d01ea0 100644 --- a/tmux.h +++ b/tmux.h @@ -1109,7 +1109,7 @@ void sigreset(void); void sighandler(int); /* cfg.c */ -int load_cfg(const char *, char **x); +int load_cfg(const char *, struct cmd_ctx *, char **); /* mode-key.c */ extern const struct mode_key_table mode_key_tables[]; From a910b38a353d73bf581900a6b117406020dbf2d9 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 23 Aug 2009 17:37:48 +0000 Subject: [PATCH 0291/1180] Some code tidying. --- cmd-new-session.c | 52 +++++++++++++++++++++++------------------------ 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/cmd-new-session.c b/cmd-new-session.c index 73698d24..8cf30bc3 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -114,6 +114,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) { struct cmd_new_session_data *data = self->data; struct session *s; + struct window *w; struct environ env; struct termios tio; const char *update; @@ -186,18 +187,22 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) } } - /* Find new session size and options. */ + /* Get the new session working directory. */ + if (ctx->cmdclient != NULL && ctx->cmdclient->cwd != NULL) + cwd = ctx->cmdclient->cwd; + else + cwd = options_get_string(&global_s_options, "default-path"); + + /* Find new session size. */ if (detached) { sx = 80; sy = 25; + } else if (ctx->cmdclient != NULL) { + sx = ctx->cmdclient->tty.sx; + sy = ctx->cmdclient->tty.sy; } else { - if (ctx->cmdclient != NULL) { - sx = ctx->cmdclient->tty.sx; - sy = ctx->cmdclient->tty.sy; - } else { - sx = ctx->curclient->tty.sx; - sy = ctx->curclient->tty.sy; - } + sx = ctx->curclient->tty.sx; + sy = ctx->curclient->tty.sy; } if (sy > 0 && options_get_number(&global_s_options, "status")) sy--; @@ -205,10 +210,8 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) sx = 1; if (sy == 0) sy = 1; - if (ctx->cmdclient != NULL && ctx->cmdclient->cwd != NULL) - cwd = ctx->cmdclient->cwd; - else - cwd = options_get_string(&global_s_options, "default-path"); + + /* Figure out the command for the new window. */ if (data->cmd != NULL) cmd = data->cmd; else @@ -231,26 +234,23 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) } environ_free(&env); + /* Set the initial window name if one given. */ if (data->winname != NULL) { - xfree(s->curw->window->name); - s->curw->window->name = xstrdup(data->winname); - options_set_number( - &s->curw->window->options, "automatic-rename", 0); + w = s->curw->window; + + xfree(w->name); + w->name = xstrdup(data->winname); + + options_set_number(&w->options, "automatic-rename", 0); } - /* - * If a command client exists, it is either taking this session (and - * needs to get MSG_READY and stay around), or -d is given and it needs - * to exit. + /* + * Set the client to the new session. If a command client exists, it is + * taking this session and needs to get MSG_READY and stay around. */ - if (ctx->cmdclient != NULL) { - if (!detached) - server_write_client(ctx->cmdclient, MSG_READY, NULL, 0); - } - - /* Set the client to the new session. */ if (!detached) { if (ctx->cmdclient != NULL) { + server_write_client(ctx->cmdclient, MSG_READY, NULL, 0); ctx->cmdclient->session = s; server_redraw_client(ctx->cmdclient); } else { From 90400ae96ab433a915d9e1a8b6df6a640c6fd7cd Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 23 Aug 2009 18:21:02 +0000 Subject: [PATCH 0292/1180] Add some other obvious variables to update-environment (WINDOWID SSH_ASKPASS SSH_AUTH_SOCK SSH_AGENT_PID SSH_CONNECTION) so they are updated in the session environment on new/attach. --- tmux.1 | 2 +- tmux.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/tmux.1 b/tmux.1 index 11282404..bedf404b 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1343,7 +1343,7 @@ was given to the .Ic set-environment command). The default is -.Ev DISPLAY . +"DISPLAY WINDOWID SSH_ASKPASS SSH_AUTH_SOCK SSH_AGENT_PID SSH_CONNECTION". .It Xo Ic visual-activity .Op Ic on | off .Xc diff --git a/tmux.c b/tmux.c index 4437f07b..eab2c2aa 100644 --- a/tmux.c +++ b/tmux.c @@ -381,7 +381,8 @@ main(int argc, char **argv) options_set_number(&global_s_options, "status-utf8", 0); options_set_string(&global_s_options, "terminal-overrides", "*88col*:colors=88,*256col*:colors=256"); - options_set_string(&global_s_options, "update-environment", "DISPLAY"); + options_set_string(&global_s_options, "update-environment", "DISPLAY " + "WINDOWID SSH_ASKPASS SSH_AUTH_SOCK SSH_AGENT_PID SSH_CONNECTION"); options_set_number(&global_s_options, "visual-activity", 0); options_set_number(&global_s_options, "visual-bell", 0); options_set_number(&global_s_options, "visual-content", 0); From 4f1d81c4ce89440bd2f155cbb8002b622f13ce0b Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 24 Aug 2009 08:03:11 +0000 Subject: [PATCH 0293/1180] gcc2 doesn't understand attributes on function pointers. --- tmux.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tmux.h b/tmux.h index a2d01ea0..1f3cf74d 100644 --- a/tmux.h +++ b/tmux.h @@ -990,9 +990,16 @@ struct cmd_ctx { struct msg_command_data *msgdata; + /* gcc2 doesn't understand attributes on function pointers... */ +#if defined(__GNUC__) && __GNUC__ >= 3 void printflike2 (*print)(struct cmd_ctx *, const char *, ...); void printflike2 (*info)(struct cmd_ctx *, const char *, ...); void printflike2 (*error)(struct cmd_ctx *, const char *, ...); +#else + void (*print)(struct cmd_ctx *, const char *, ...); + void (*info)(struct cmd_ctx *, const char *, ...); + void (*error)(struct cmd_ctx *, const char *, ...); +#endif }; struct cmd { From 7b847ced4af09b7da66a7b0b59fbab68f07bcb50 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 25 Aug 2009 12:18:51 +0000 Subject: [PATCH 0294/1180] Add a choose-client command and extend choose-{session,window} to accept a template. After a choice is made, %% (or %1) in the template is replaced by the name of the session, window or client suitable for -t and the result executed as a command. So, for example, "choose-window "killw -t '%%'"" will kill the selected window. The defaults if no template is given are (as now) select-window for choose-window, switch-client for choose-session, and detach-client for choose-client (now bound to D). --- Makefile | 2 +- cmd-choose-client.c | 149 +++++++++++++++++++++++++++++++++++++++++++ cmd-choose-session.c | 68 ++++++++++++++++---- cmd-choose-window.c | 72 ++++++++++++++++++--- cmd-command-prompt.c | 43 +------------ cmd.c | 42 ++++++++++++ key-bindings.c | 5 +- tmux.1 | 55 ++++++++++++++-- tmux.h | 2 + 9 files changed, 366 insertions(+), 72 deletions(-) create mode 100644 cmd-choose-client.c diff --git a/Makefile b/Makefile index 97d39afa..82003be2 100644 --- a/Makefile +++ b/Makefile @@ -25,7 +25,7 @@ SRCS= attributes.c buffer-poll.c buffer.c cfg.c client-fn.c \ cmd-split-window.c cmd-start-server.c cmd-string.c cmd-if-shell.c \ cmd-suspend-client.c cmd-swap-pane.c cmd-swap-window.c \ cmd-switch-client.c cmd-unbind-key.c cmd-unlink-window.c \ - cmd-set-environment.c cmd-show-environment.c \ + cmd-set-environment.c cmd-show-environment.c cmd-choose-client.c \ cmd-up-pane.c cmd-display-message.c cmd.c \ colour.c environ.c grid-view.c grid.c input-keys.c \ imsg.c imsg-buffer.c input.c key-bindings.c key-string.c \ diff --git a/cmd-choose-client.c b/cmd-choose-client.c new file mode 100644 index 00000000..59a5bd27 --- /dev/null +++ b/cmd-choose-client.c @@ -0,0 +1,149 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2009 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" + +/* + * Enter choice mode to choose a client. + */ + +int cmd_choose_client_exec(struct cmd *, struct cmd_ctx *); + +void cmd_choose_client_callback(void *, int); +void cmd_choose_client_free(void *); + +const struct cmd_entry cmd_choose_client_entry = { + "choose-client", NULL, + CMD_TARGET_WINDOW_USAGE " [template]", + CMD_ARG01, 0, + cmd_target_init, + cmd_target_parse, + cmd_choose_client_exec, + cmd_target_free, + cmd_target_print +}; + +struct cmd_choose_client_data { + u_int client; + char *template; +}; + +int +cmd_choose_client_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_target_data *data = self->data; + struct cmd_choose_client_data *cdata; + struct winlink *wl; + struct client *c; + u_int i, idx, cur; + + if (ctx->curclient == NULL) { + ctx->error(ctx, "must be run interactively"); + return (-1); + } + + if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) + return (-1); + + if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0) + return (0); + + cur = idx = 0; + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c == NULL || c->session == NULL) + continue; + if (c == ctx->curclient) + cur = idx; + idx++; + + window_choose_add(wl->window->active, i, + "%s: %s [%ux%u %s]%s", c->tty.path, + c->session->name, c->tty.sx, c->tty.sy, + c->tty.termname, c->tty.flags & TTY_UTF8 ? " (utf8)" : ""); + } + + cdata = xmalloc(sizeof *cdata); + if (data->arg != NULL) + cdata->template = xstrdup(data->arg); + else + cdata->template = xstrdup("detach-client -t '%%'"); + cdata->client = server_client_index(ctx->curclient); + + window_choose_ready(wl->window->active, + cur, cmd_choose_client_callback, cmd_choose_client_free, cdata); + + return (0); +} + +void +cmd_choose_client_callback(void *data, int idx) +{ + struct cmd_choose_client_data *cdata = data; + struct client *c, *c2; + struct cmd_list *cmdlist; + struct cmd_ctx ctx; + char *template, *cause; + + if (idx == -1) + return; + if (cdata->client > ARRAY_LENGTH(&clients) - 1) + return; + c = ARRAY_ITEM(&clients, cdata->client); + + if ((u_int) idx > ARRAY_LENGTH(&clients) - 1) + return; + c2 = ARRAY_ITEM(&clients, idx); + if (c2 == NULL || c2->session == NULL) + return; + template = cmd_template_replace(cdata->template, c2->tty.path, 1); + + if (cmd_string_parse(template, &cmdlist, &cause) != 0) { + if (cause != NULL) { + *cause = toupper((u_char) *cause); + status_message_set(c, "%s", cause); + xfree(cause); + } + xfree(template); + return; + } + xfree(template); + + ctx.msgdata = NULL; + ctx.curclient = c; + + ctx.error = key_bindings_error; + ctx.print = key_bindings_print; + ctx.info = key_bindings_info; + + ctx.cmdclient = NULL; + + cmd_list_exec(cmdlist, &ctx); + cmd_list_free(cmdlist); +} + +void +cmd_choose_client_free(void *data) +{ + struct cmd_choose_client_data *cdata = data; + + xfree(cdata->template); + xfree(cdata); +} diff --git a/cmd-choose-session.c b/cmd-choose-session.c index cf5e3c82..3028df22 100644 --- a/cmd-choose-session.c +++ b/cmd-choose-session.c @@ -27,11 +27,12 @@ int cmd_choose_session_exec(struct cmd *, struct cmd_ctx *); void cmd_choose_session_callback(void *, int); +void cmd_choose_session_free(void *); const struct cmd_entry cmd_choose_session_entry = { "choose-session", NULL, - CMD_TARGET_WINDOW_USAGE, - 0, 0, + CMD_TARGET_WINDOW_USAGE " [template]", + CMD_ARG01, 0, cmd_target_init, cmd_target_parse, cmd_choose_session_exec, @@ -40,7 +41,8 @@ const struct cmd_entry cmd_choose_session_entry = { }; struct cmd_choose_session_data { - u_int client; + u_int client; + char *template; }; int @@ -79,10 +81,14 @@ cmd_choose_session_exec(struct cmd *self, struct cmd_ctx *ctx) } cdata = xmalloc(sizeof *cdata); + if (data->arg != NULL) + cdata->template = xstrdup(data->arg); + else + cdata->template = xstrdup("switch-client -t '%%'"); cdata->client = server_client_index(ctx->curclient); - window_choose_ready( - wl->window->active, cur, cmd_choose_session_callback, xfree, cdata); + window_choose_ready(wl->window->active, + cur, cmd_choose_session_callback, cmd_choose_session_free, cdata); return (0); } @@ -92,13 +98,53 @@ cmd_choose_session_callback(void *data, int idx) { struct cmd_choose_session_data *cdata = data; struct client *c; + struct session *s; + struct cmd_list *cmdlist; + struct cmd_ctx ctx; + char *template, *cause; - if (idx != -1 && cdata->client <= ARRAY_LENGTH(&clients) - 1) { - c = ARRAY_ITEM(&clients, cdata->client); - if (c != NULL && (u_int) idx <= ARRAY_LENGTH(&sessions) - 1) { - c->session = ARRAY_ITEM(&sessions, idx); - recalculate_sizes(); - server_redraw_client(c); + if (idx == -1) + return; + if (cdata->client > ARRAY_LENGTH(&clients) - 1) + return; + c = ARRAY_ITEM(&clients, cdata->client); + + if ((u_int) idx > ARRAY_LENGTH(&sessions) - 1) + return; + s = ARRAY_ITEM(&sessions, idx); + if (s == NULL) + return; + template = cmd_template_replace(cdata->template, s->name, 1); + + if (cmd_string_parse(template, &cmdlist, &cause) != 0) { + if (cause != NULL) { + *cause = toupper((u_char) *cause); + status_message_set(c, "%s", cause); + xfree(cause); } + xfree(template); + return; } + xfree(template); + + ctx.msgdata = NULL; + ctx.curclient = c; + + ctx.error = key_bindings_error; + ctx.print = key_bindings_print; + ctx.info = key_bindings_info; + + ctx.cmdclient = NULL; + + cmd_list_exec(cmdlist, &ctx); + cmd_list_free(cmdlist); +} + +void +cmd_choose_session_free(void *data) +{ + struct cmd_choose_session_data *cdata = data; + + xfree(cdata->template); + xfree(cdata); } diff --git a/cmd-choose-window.c b/cmd-choose-window.c index efca9f80..ec6b2499 100644 --- a/cmd-choose-window.c +++ b/cmd-choose-window.c @@ -27,11 +27,12 @@ int cmd_choose_window_exec(struct cmd *, struct cmd_ctx *); void cmd_choose_window_callback(void *, int); +void cmd_choose_window_free(void *); const struct cmd_entry cmd_choose_window_entry = { "choose-window", NULL, - CMD_TARGET_WINDOW_USAGE, - 0, 0, + CMD_TARGET_WINDOW_USAGE " [template]", + CMD_ARG01, 0, cmd_target_init, cmd_target_parse, cmd_choose_window_exec, @@ -40,7 +41,9 @@ const struct cmd_entry cmd_choose_window_entry = { }; struct cmd_choose_window_data { - u_int session; + u_int client; + u_int session; + char *template; }; int @@ -104,9 +107,14 @@ cmd_choose_window_exec(struct cmd *self, struct cmd_ctx *ctx) cdata = xmalloc(sizeof *cdata); if (session_index(s, &cdata->session) != 0) fatalx("session not found"); + if (data->arg != NULL) + cdata->template = xstrdup(data->arg); + else + cdata->template = xstrdup("select-window -t '%%'"); + cdata->client = server_client_index(ctx->curclient); - window_choose_ready( - wl->window->active, cur, cmd_choose_window_callback, xfree, cdata); + window_choose_ready(wl->window->active, + cur, cmd_choose_window_callback, cmd_choose_window_free, cdata); return (0); } @@ -115,12 +123,56 @@ void cmd_choose_window_callback(void *data, int idx) { struct cmd_choose_window_data *cdata = data; + struct client *c; struct session *s; + struct cmd_list *cmdlist; + struct cmd_ctx ctx; + char *target, *template, *cause; - if (idx != -1 && cdata->session <= ARRAY_LENGTH(&sessions) - 1) { - s = ARRAY_ITEM(&sessions, cdata->session); - if (s != NULL && session_select(s, idx) == 0) - server_redraw_session(s); - recalculate_sizes(); + if (idx == -1) + return; + if (cdata->client > ARRAY_LENGTH(&clients) - 1) + return; + c = ARRAY_ITEM(&clients, cdata->client); + if (cdata->session > ARRAY_LENGTH(&sessions) - 1) + return; + s = ARRAY_ITEM(&sessions, cdata->session); + if (c->session != s) + return; + + xasprintf(&target, "%s:%d", s->name, idx); + template = cmd_template_replace(cdata->template, target, 1); + xfree(target); + + if (cmd_string_parse(template, &cmdlist, &cause) != 0) { + if (cause != NULL) { + *cause = toupper((u_char) *cause); + status_message_set(c, "%s", cause); + xfree(cause); + } + xfree(template); + return; } + xfree(template); + + ctx.msgdata = NULL; + ctx.curclient = c; + + ctx.error = key_bindings_error; + ctx.print = key_bindings_print; + ctx.info = key_bindings_info; + + ctx.cmdclient = NULL; + + cmd_list_exec(cmdlist, &ctx); + cmd_list_free(cmdlist); +} + +void +cmd_choose_window_free(void *data) +{ + struct cmd_choose_window_data *cdata = data; + + xfree(cdata->template); + xfree(cdata); } diff --git a/cmd-command-prompt.c b/cmd-command-prompt.c index cd417a61..6aee2ec0 100644 --- a/cmd-command-prompt.c +++ b/cmd-command-prompt.c @@ -35,7 +35,6 @@ size_t cmd_command_prompt_print(struct cmd *, char *, size_t); int cmd_command_prompt_callback(void *, const char *); void cmd_command_prompt_cfree(void *); -char *cmd_command_prompt_replace(char *, const char *, int); const struct cmd_entry cmd_command_prompt_entry = { "command-prompt", NULL, @@ -216,7 +215,7 @@ cmd_command_prompt_callback(void *data, const char *s) if (s == NULL) return (0); - newtempl = cmd_command_prompt_replace(cdata->template, s, cdata->idx); + newtempl = cmd_template_replace(cdata->template, s, cdata->idx); xfree(cdata->template); cdata->template = newtempl; @@ -265,43 +264,3 @@ cmd_command_prompt_cfree(void *data) xfree(cdata->template); xfree(cdata); } - -char * -cmd_command_prompt_replace(char *template, const char *s, int idx) -{ - char ch; - char *buf, *ptr; - int replaced; - size_t len; - - if (strstr(template, "%") == NULL) - return (xstrdup(template)); - - buf = xmalloc(1); - *buf = '\0'; - len = 0; - replaced = 0; - - ptr = template; - while (*ptr != '\0') { - switch (ch = *ptr++) { - case '%': - if (*ptr < '1' || *ptr > '9' || *ptr - '0' != idx) { - if (*ptr != '%' || replaced) - break; - replaced = 1; - } - ptr++; - - len += strlen(s); - buf = xrealloc(buf, 1, len + 1); - strlcat(buf, s, len + 1); - continue; - } - buf = xrealloc(buf, 1, len + 2); - buf[len++] = ch; - buf[len] = '\0'; - } - - return (buf); -} diff --git a/cmd.c b/cmd.c index 21f2052f..8712fe90 100644 --- a/cmd.c +++ b/cmd.c @@ -31,6 +31,7 @@ const struct cmd_entry *cmd_table[] = { &cmd_attach_session_entry, &cmd_bind_key_entry, &cmd_break_pane_entry, + &cmd_choose_client_entry, &cmd_choose_session_entry, &cmd_choose_window_entry, &cmd_clear_history_entry, @@ -858,3 +859,44 @@ error: xfree(winptr); return (NULL); } + +/* Replace the first %% or %idx in template by s. */ +char * +cmd_template_replace(char *template, const char *s, int idx) +{ + char ch; + char *buf, *ptr; + int replaced; + size_t len; + + if (strstr(template, "%") == NULL) + return (xstrdup(template)); + + buf = xmalloc(1); + *buf = '\0'; + len = 0; + replaced = 0; + + ptr = template; + while (*ptr != '\0') { + switch (ch = *ptr++) { + case '%': + if (*ptr < '1' || *ptr > '9' || *ptr - '0' != idx) { + if (*ptr != '%' || replaced) + break; + replaced = 1; + } + ptr++; + + len += strlen(s); + buf = xrealloc(buf, 1, len + 1); + strlcat(buf, s, len + 1); + continue; + } + buf = xrealloc(buf, 1, len + 2); + buf[len++] = ch; + buf[len] = '\0'; + } + + return (buf); +} diff --git a/key-bindings.c b/key-bindings.c index b2ccc4aa..907163f0 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -130,6 +130,7 @@ key_bindings_init(void) { ']', 0, &cmd_paste_buffer_entry }, { 'c', 0, &cmd_new_window_entry }, { 'd', 0, &cmd_detach_client_entry }, + { 'D', 0, &cmd_choose_client_entry }, { 'f', 0, &cmd_command_prompt_entry }, { 'i', 0, &cmd_display_message_entry }, { 'l', 0, &cmd_last_window_entry }, @@ -143,7 +144,7 @@ key_bindings_init(void) { 'x', 0, &cmd_confirm_before_entry }, { '{', 0, &cmd_swap_pane_entry }, { '}', 0, &cmd_swap_pane_entry }, - { '\002', 0, &cmd_send_prefix_entry }, + { '\002', /* C-b */ 0, &cmd_send_prefix_entry }, { '1' | KEYC_ESCAPE, 0, &cmd_select_layout_entry }, { '2' | KEYC_ESCAPE, 0, &cmd_select_layout_entry }, { '3' | KEYC_ESCAPE, 0, &cmd_select_layout_entry }, @@ -162,7 +163,7 @@ key_bindings_init(void) { KEYC_LEFT | KEYC_CTRL, 1, &cmd_resize_pane_entry }, { KEYC_RIGHT | KEYC_CTRL, 1, &cmd_resize_pane_entry }, { 'o' | KEYC_ESCAPE, 0, &cmd_rotate_window_entry }, - { '\017', 0, &cmd_rotate_window_entry }, + { '\017', /* C-o */ 0, &cmd_rotate_window_entry }, }; u_int i; struct cmd *cmd; diff --git a/tmux.1 b/tmux.1 index bedf404b..fa97cf3b 100644 --- a/tmux.1 +++ b/tmux.1 @@ -622,14 +622,57 @@ off from its containing window to make it the only pane in a new window. If .Fl d is given, the new window does not become the current window. -.It Ic choose-session Op Fl t Ar target-window -Put a window into session choice mode, where the session for the current -client may be selected interactively from a list. +.It Xo +.Ic choose-client +.Op Fl t Ar target-window +.Op Ar template +.Xc +Put a window into client choice mode, allowing a client to be selected +interactively from a list. +After a client is chosen, +.Ql %% +is replaced by the client +.Xr pty 4 +path in +.Ar template +and the result executed as a command. +If +.Ar template +is not given, "detach-client -t '%%'" is used. This command works only from inside .Nm . -.It Ic choose-window Op Fl t Ar target-window -Put a window into window choice mode, where the window for the session -attached to the current client may be selected interactively from a list. +.It Xo +.Ic choose-session +.Op Fl t Ar target-window +.Op Ar template +.Xc +Put a window into session choice mode, where a session may be selected +interactively from a list. +When one is chosen, +.Ql %% +is replaced by the session name in +.Ar template +and the result executed as a command. +If +.Ar template +is not given, "switch-client -t '%%'" is used. +This command works only from inside +.Nm . +.It Xo +.Ic choose-window +.Op Fl t Ar target-window +.Op Ar template +.Xc +Put a window into window choice mode, where a window may be chosen +interactively from a list. +After a window is selected, +.Ql %% +is replaced by the session name and window index in +.Ar template +and the result executed as a command. +If +.Ar template +is not given, "select-window -t '%%'" is used. This command works only from inside .Nm . .It Ic down-pane Op Fl t Ar target-pane diff --git a/tmux.h b/tmux.h index 1f3cf74d..aaa1190c 100644 --- a/tmux.h +++ b/tmux.h @@ -1268,10 +1268,12 @@ int cmd_find_index( struct cmd_ctx *, const char *, struct session **); struct winlink *cmd_find_pane(struct cmd_ctx *, const char *, struct session **, struct window_pane **); +char *cmd_template_replace(char *, const char *, int); 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; extern const struct cmd_entry cmd_break_pane_entry; +extern const struct cmd_entry cmd_choose_client_entry; extern const struct cmd_entry cmd_choose_session_entry; extern const struct cmd_entry cmd_choose_window_entry; extern const struct cmd_entry cmd_clear_history_entry; From be16f79438111231c4b126879aa1820381a6a600 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 25 Aug 2009 13:32:14 +0000 Subject: [PATCH 0295/1180] These should #include . --- cmd-choose-client.c | 2 ++ cmd-choose-session.c | 2 ++ cmd-choose-window.c | 2 ++ 3 files changed, 6 insertions(+) diff --git a/cmd-choose-client.c b/cmd-choose-client.c index 59a5bd27..dd09fe51 100644 --- a/cmd-choose-client.c +++ b/cmd-choose-client.c @@ -18,6 +18,8 @@ #include +#include + #include "tmux.h" /* diff --git a/cmd-choose-session.c b/cmd-choose-session.c index 3028df22..87b3437b 100644 --- a/cmd-choose-session.c +++ b/cmd-choose-session.c @@ -18,6 +18,8 @@ #include +#include + #include "tmux.h" /* diff --git a/cmd-choose-window.c b/cmd-choose-window.c index ec6b2499..ddc8ecb6 100644 --- a/cmd-choose-window.c +++ b/cmd-choose-window.c @@ -18,6 +18,8 @@ #include +#include + #include "tmux.h" /* From f949107a32fed3f1bab6ac4227a7c6b03b233643 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 25 Aug 2009 14:53:22 +0000 Subject: [PATCH 0296/1180] Print -l and -p when showing command, pointed out by Tiago Cunha. --- cmd-split-window.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cmd-split-window.c b/cmd-split-window.c index 09bd214e..d5f0ba6c 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -237,6 +237,12 @@ cmd_split_window_print(struct cmd *self, char *buf, size_t len) off += xsnprintf(buf + off, len - off, " -d"); if (off < len && data->flag_horizontal) off += xsnprintf(buf + off, len - off, " -h"); + if (off < len && data->size > 0) + off += xsnprintf(buf + off, len - off, " -l %d", data->size); + if (off < len && data->percentage > 0) { + off += xsnprintf( + buf + off, len - off, " -p %d", data->percentage); + } if (off < len && data->target != NULL) off += cmd_prarg(buf + off, len - off, " -t ", data->target); if (off < len && data->cmd != NULL) From 1ba5ce9cb3992f3a5f7ff41975c370540678e815 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 26 Aug 2009 16:16:06 +0000 Subject: [PATCH 0297/1180] Fix clock mode in black and white terminals now that tty.c tries to fix reverse. --- clock.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/clock.c b/clock.c index 60248f47..275861a9 100644 --- a/clock.c +++ b/clock.c @@ -113,7 +113,7 @@ clock_draw(struct screen_write_ctx *ctx, u_int colour, int style) screen_write_clearscreen(ctx); memcpy(&gc, &grid_default_cell, sizeof gc); - gc.fg = colour; + gc.bg = colour; if (screen_size_x(s) < 6 * strlen(tim) || screen_size_y(s) < 6) { if (screen_size_x(s) >= strlen(tim) && screen_size_y(s) != 0) { @@ -147,13 +147,10 @@ clock_draw(struct screen_write_ctx *ctx, u_int colour, int style) } for (j = 0; j < 5; j++) { - screen_write_cursormove(ctx, x, y + j); for (i = 0; i < 5; i++) { + screen_write_cursormove(ctx, x + i, y + j); if (clock_table[idx][j][i]) - gc.attr |= GRID_ATTR_REVERSE; - else - gc.attr &= ~GRID_ATTR_REVERSE; - screen_write_putc(ctx, &gc, ' '); + screen_write_putc(ctx, &gc, ' '); } } x += 6; From ddf97f8289df9c7973e7dad6dae8949e29792a16 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 26 Aug 2009 16:23:30 +0000 Subject: [PATCH 0298/1180] Make this work when the clock is in small characters as well. Doh. --- clock.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/clock.c b/clock.c index 275861a9..4cd8a8a7 100644 --- a/clock.c +++ b/clock.c @@ -112,8 +112,6 @@ clock_draw(struct screen_write_ctx *ctx, u_int colour, int style) strftime(tim, sizeof tim, "%H:%M", localtime(&t)); screen_write_clearscreen(ctx); - memcpy(&gc, &grid_default_cell, sizeof gc); - gc.bg = colour; if (screen_size_x(s) < 6 * strlen(tim) || screen_size_y(s) < 6) { if (screen_size_x(s) >= strlen(tim) && screen_size_y(s) != 0) { @@ -121,6 +119,7 @@ clock_draw(struct screen_write_ctx *ctx, u_int colour, int style) y = screen_size_y(s) / 2; screen_write_cursormove(ctx, x, y); + memcpy(&gc, &grid_default_cell, sizeof gc); gc.fg = colour; screen_write_puts(ctx, &gc, "%s", tim); } @@ -130,6 +129,8 @@ clock_draw(struct screen_write_ctx *ctx, u_int colour, int style) x = (screen_size_x(s) / 2) - 3 * strlen(tim); y = (screen_size_y(s) / 2) - 3; + memcpy(&gc, &grid_default_cell, sizeof gc); + gc.bg = colour; for (ptr = tim; *ptr != '\0'; ptr++) { if (*ptr >= '0' && *ptr <= '9') idx = *ptr - '0'; From 2e5b3ab8bc0e0f7a36f7a901263fa720654d60ca Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 26 Aug 2009 18:09:52 +0000 Subject: [PATCH 0299/1180] Initialise the arg2 pointer properly (also free it when freeing the others). Fixes crashes with J in malloc_options reported by oga. --- cmd-generic.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/cmd-generic.c b/cmd-generic.c index 7962a87a..89dc2e25 100644 --- a/cmd-generic.c +++ b/cmd-generic.c @@ -155,6 +155,7 @@ cmd_target_init(struct cmd *self, unused int key) data->chflags = 0; data->target = NULL; data->arg = NULL; + data->arg2 = NULL; } int @@ -204,6 +205,8 @@ cmd_target_free(struct cmd *self) xfree(data->target); if (data->arg != NULL) xfree(data->arg); + if (data->arg2 != NULL) + xfree(data->arg2); xfree(data); } @@ -236,6 +239,7 @@ cmd_srcdst_init(struct cmd *self, unused int key) data->src = NULL; data->dst = NULL; data->arg = NULL; + data->arg2 = NULL; } int @@ -290,6 +294,8 @@ cmd_srcdst_free(struct cmd *self) xfree(data->dst); if (data->arg != NULL) xfree(data->arg); + if (data->arg2 != NULL) + xfree(data->arg2); xfree(data); } @@ -324,6 +330,7 @@ cmd_buffer_init(struct cmd *self, unused int key) data->target = NULL; data->buffer = -1; data->arg = NULL; + data->arg2 = NULL; } int @@ -384,6 +391,8 @@ cmd_buffer_free(struct cmd *self) xfree(data->target); if (data->arg != NULL) xfree(data->arg); + if (data->arg2 != NULL) + xfree(data->arg2); xfree(data); } From 71ede76c68104c43a9f6980564fb6283a7f19473 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 31 Aug 2009 11:37:27 +0000 Subject: [PATCH 0300/1180] Don't call tty_free unless the client is a terminal, otherwise tty_init hasn't been called and it may end up doing close(0). From Kalle Olavi Niemitalo. --- server.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/server.c b/server.c index 3f15ca41..0780e6b1 100644 --- a/server.c +++ b/server.c @@ -915,7 +915,12 @@ server_lost_client(struct client *c) } log_debug("lost client %d", c->ibuf.fd); - tty_free(&c->tty); + /* + * If CLIENT_TERMINAL hasn't been set, then tty_init hasn't been called + * and tty_free might close an unrelated fd. + */ + if (c->flags & CLIENT_TERMINAL) + tty_free(&c->tty); screen_free(&c->status); From 8102ec3be55e9800837eeb2f1f9135a433452794 Mon Sep 17 00:00:00 2001 From: Stefan Sperling Date: Mon, 31 Aug 2009 11:52:32 +0000 Subject: [PATCH 0301/1180] squash typo ok nicm@ --- tmux.1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tmux.1 b/tmux.1 index fa97cf3b..281d1566 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1227,7 +1227,7 @@ window option for any windows first created in this session. .It Xo Ic set-titles .Op Ic on | off .Xc -Attempt to set the window title using the \ee]2;...\e007 xterm code and +Attempt to set the window title using the \ee]2;...\e007 xterm code if the terminal appears to be an xterm. This option is off by default. Note that elinks From 04319964b95304138dbe5cbce0b97222769d0c17 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 31 Aug 2009 20:46:19 +0000 Subject: [PATCH 0302/1180] Add a new display-panes command, with two options (display-panes-colour and display-panes-time), which displays a visual indication of the number of each pane. --- Makefile | 2 +- cmd-display-panes.c | 52 +++++++++++++++++++++++++++++++++++++++++ cmd-set-option.c | 2 ++ cmd.c | 1 + key-bindings.c | 1 + screen-redraw.c | 56 +++++++++++++++++++++++++++++++++++++++++++++ server-fn.c | 29 +++++++++++++++++++++++ server.c | 4 ++++ status.c | 7 +++--- tmux.1 | 20 +++++++++++++++- tmux.c | 2 ++ tmux.h | 8 +++++++ tty.c | 1 - 13 files changed, 179 insertions(+), 6 deletions(-) create mode 100644 cmd-display-panes.c diff --git a/Makefile b/Makefile index 82003be2..fcb1d43b 100644 --- a/Makefile +++ b/Makefile @@ -26,7 +26,7 @@ SRCS= attributes.c buffer-poll.c buffer.c cfg.c client-fn.c \ cmd-suspend-client.c cmd-swap-pane.c cmd-swap-window.c \ cmd-switch-client.c cmd-unbind-key.c cmd-unlink-window.c \ cmd-set-environment.c cmd-show-environment.c cmd-choose-client.c \ - cmd-up-pane.c cmd-display-message.c cmd.c \ + cmd-up-pane.c cmd-display-message.c cmd-display-panes.c cmd.c \ colour.c environ.c grid-view.c grid.c input-keys.c \ imsg.c imsg-buffer.c input.c key-bindings.c key-string.c \ layout-set.c layout.c log.c \ diff --git a/cmd-display-panes.c b/cmd-display-panes.c new file mode 100644 index 00000000..141e3436 --- /dev/null +++ b/cmd-display-panes.c @@ -0,0 +1,52 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2009 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" + +/* + * Display panes on a client. + */ + +int cmd_display_panes_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_display_panes_entry = { + "display-panes", "displayp", + CMD_TARGET_CLIENT_USAGE, + 0, 0, + cmd_target_init, + cmd_target_parse, + cmd_display_panes_exec, + cmd_target_free, + cmd_target_print +}; + +int +cmd_display_panes_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_target_data *data = self->data; + struct client *c; + + if ((c = cmd_find_client(ctx, data->target)) == NULL) + return (-1); + + server_set_identify(c); + + return (0); +} diff --git a/cmd-set-option.c b/cmd-set-option.c index e764f4c5..b69ffe0d 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -56,6 +56,8 @@ const struct set_option_entry set_option_table[] = { { "default-command", SET_OPTION_STRING, 0, 0, NULL }, { "default-path", SET_OPTION_STRING, 0, 0, NULL }, { "default-terminal", SET_OPTION_STRING, 0, 0, NULL }, + { "display-panes-colour", SET_OPTION_COLOUR, 0, 0, NULL }, + { "display-panes-time", SET_OPTION_NUMBER, 1, INT_MAX, NULL }, { "display-time", SET_OPTION_NUMBER, 1, INT_MAX, NULL }, { "history-limit", SET_OPTION_NUMBER, 0, INT_MAX, NULL }, { "lock-after-time", SET_OPTION_NUMBER, 0, INT_MAX, NULL }, diff --git a/cmd.c b/cmd.c index 8712fe90..08aea7cb 100644 --- a/cmd.c +++ b/cmd.c @@ -43,6 +43,7 @@ const struct cmd_entry *cmd_table[] = { &cmd_delete_buffer_entry, &cmd_detach_client_entry, &cmd_display_message_entry, + &cmd_display_panes_entry, &cmd_down_pane_entry, &cmd_find_window_entry, &cmd_has_session_entry, diff --git a/key-bindings.c b/key-bindings.c index 907163f0..31c7e5e9 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -137,6 +137,7 @@ key_bindings_init(void) { 'n', 0, &cmd_next_window_entry }, { 'o', 0, &cmd_down_pane_entry }, { 'p', 0, &cmd_previous_window_entry }, + { 'q', 0, &cmd_display_panes_entry }, { 'r', 0, &cmd_refresh_client_entry }, { 's', 0, &cmd_choose_session_entry }, { 't', 0, &cmd_clock_mode_entry }, diff --git a/screen-redraw.c b/screen-redraw.c index 5ee273a5..ce26c47d 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -24,6 +24,7 @@ int screen_redraw_cell_border(struct client *, u_int, u_int); int screen_redraw_check_cell(struct client *, u_int, u_int); +void screen_redraw_draw_number(struct client *, struct window_pane *); #define CELL_INSIDE 0 #define CELL_LEFTRIGHT 1 @@ -210,6 +211,8 @@ screen_redraw_screen(struct client *c, int status_only) continue; tty_draw_line(tty, wp->screen, i, wp->xoff, wp->yoff); } + if (c->flags & CLIENT_IDENTIFY) + screen_redraw_draw_number(c, wp); } /* Draw the status line. */ @@ -228,3 +231,56 @@ screen_redraw_pane(struct client *c, struct window_pane *wp) tty_draw_line(&c->tty, wp->screen, i, wp->xoff, wp->yoff); tty_reset(&c->tty); } + +/* Draw number on a pane. */ +void +screen_redraw_draw_number(struct client *c, struct window_pane *wp) +{ + struct tty *tty = &c->tty; + struct session *s = c->session; + struct grid_cell gc; + u_int idx, px, py, i, j; + u_char colour; + char buf[16], *ptr; + size_t len; + + idx = window_pane_index(wp->window, wp); + len = xsnprintf(buf, sizeof buf, "%u", idx); + + if (wp->sx < len) + return; + colour = options_get_number(&s->options, "display-panes-colour"); + + px = wp->sx / 2; + py = wp->sy / 2; + if (wp->sx < len * 6 || wp->sy < 5) { + tty_cursor(tty, px - len / 2, py, wp->xoff, wp->yoff); + memcpy(&gc, &grid_default_cell, sizeof gc); + gc.fg = colour; + tty_attributes(tty, &gc); + tty_puts(tty, buf); + return; + } + + px -= len * 3; + py -= 2; + + memcpy(&gc, &grid_default_cell, sizeof gc); + gc.bg = colour; + tty_attributes(tty, &gc); + for (ptr = buf; *ptr != '\0'; ptr++) { + if (*ptr < '0' || *ptr > '9') + continue; + idx = *ptr - '0'; + + for (j = 0; j < 5; j++) { + for (i = px; i < px + 5; i++) { + tty_cursor(tty, i, py + j, wp->xoff, wp->yoff); + if (!clock_table[idx][j][i - px]) + continue; + tty_putc(tty, ' '); + } + } + px += 6; + } +} diff --git a/server-fn.c b/server-fn.c index 8d5d06bd..37bf98a4 100644 --- a/server-fn.c +++ b/server-fn.c @@ -263,3 +263,32 @@ server_kill_window(struct window *w) } recalculate_sizes(); } + +void +server_set_identify(struct client *c) +{ + struct timeval tv; + int delay; + + delay = options_get_number(&c->session->options, "display-panes-time"); + tv.tv_sec = delay / 1000; + tv.tv_usec = (delay % 1000) * 1000L; + + if (gettimeofday(&c->identify_timer, NULL) != 0) + fatal("gettimeofday"); + timeradd(&c->identify_timer, &tv, &c->identify_timer); + + c->flags |= CLIENT_IDENTIFY; + c->tty.flags |= (TTY_FREEZE|TTY_NOCURSOR); + server_redraw_client(c); +} + +void +server_clear_identify(struct client *c) +{ + if (c->flags & CLIENT_IDENTIFY) { + c->flags &= ~CLIENT_IDENTIFY; + c->tty.flags &= ~(TTY_FREEZE|TTY_NOCURSOR); + server_redraw_client(c); + } +} diff --git a/server.c b/server.c index 0780e6b1..3bb93d95 100644 --- a/server.c +++ b/server.c @@ -632,6 +632,9 @@ server_check_timers(struct client *c) if (gettimeofday(&tv, NULL) != 0) fatal("gettimeofday"); + if (c->flags & CLIENT_IDENTIFY && timercmp(&tv, &c->identify_timer, >)) + server_clear_identify(c); + if (c->message_string != NULL && timercmp(&tv, &c->message_timer, >)) status_message_clear(c); @@ -809,6 +812,7 @@ server_handle_client(struct client *c) wp = c->session->curw->window->active; /* could die */ status_message_clear(c); + server_clear_identify(c); if (c->prompt_string != NULL) { status_prompt_key(c, key); continue; diff --git a/status.c b/status.c index b4f23702..51c9c64f 100644 --- a/status.c +++ b/status.c @@ -541,13 +541,14 @@ status_message_set(struct client *c, const char *fmt, ...) status_prompt_clear(c); status_message_clear(c); + va_start(ap, fmt); + xvasprintf(&c->message_string, fmt, ap); + va_end(ap); + delay = options_get_number(&c->session->options, "display-time"); tv.tv_sec = delay / 1000; tv.tv_usec = (delay % 1000) * 1000L; - va_start(ap, fmt); - xvasprintf(&c->message_string, fmt, ap); - va_end(ap); if (gettimeofday(&c->message_timer, NULL) != 0) fatal("gettimeofday"); timeradd(&c->message_timer, &tv, &c->message_timer); diff --git a/tmux.1 b/tmux.1 index 281d1566..8b92fa69 100644 --- a/tmux.1 +++ b/tmux.1 @@ -675,6 +675,15 @@ If is not given, "select-window -t '%%'" is used. This command works only from inside .Nm . +.It Ic display-panes Op Fl t Ar target-client +.D1 (alias: Ic displayp) +Display a visible indicator of each pane shown by +.Ar target-client . +See the +.Ic display-panes-time +and +.Ic display-panes-colour +session options. .It Ic down-pane Op Fl t Ar target-pane .D1 (alias: Ic downp ) Move down a pane. @@ -1157,8 +1166,17 @@ to work correctly, this be set to .Ql screen or a derivative of it. +.It Ic display-panes-colour Ar colour +Set the colour used for the +.Ic display-panes +command. +.It Ic display-panes-time Ar time +Set the time in milliseconds for which the indicators shown by the +.Ic display-panes +command appear. .It Ic display-time Ar time -Set the amount of time for which status line messages are displayed. +Set the amount of time for which status line messages and other on-screen +indicators are displayed. .Ar time is in milliseconds. .It Ic history-limit Ar lines diff --git a/tmux.c b/tmux.c index eab2c2aa..e98d1d9c 100644 --- a/tmux.c +++ b/tmux.c @@ -347,6 +347,8 @@ main(int argc, char **argv) options_set_number(&global_s_options, "buffer-limit", 9); options_set_string(&global_s_options, "default-command", "%s", ""); options_set_string(&global_s_options, "default-terminal", "screen"); + options_set_number(&global_s_options, "display-panes-colour", 4); + options_set_number(&global_s_options, "display-panes-time", 1000); options_set_number(&global_s_options, "display-time", 750); options_set_number(&global_s_options, "history-limit", 2000); options_set_number(&global_s_options, "lock-after-time", 0); diff --git a/tmux.h b/tmux.h index aaa1190c..36e660df 100644 --- a/tmux.h +++ b/tmux.h @@ -935,8 +935,11 @@ struct client { #define CLIENT_REPEAT 0x20 /* allow command to repeat within repeat time */ #define CLIENT_SUSPENDED 0x40 #define CLIENT_BAD 0x80 +#define CLIENT_IDENTIFY 0x100 int flags; + struct timeval identify_timer; + char *message_string; struct timeval message_timer; @@ -1164,6 +1167,7 @@ void environ_update(const char *, struct environ *, struct environ *); /* tty.c */ u_char tty_get_acs(struct tty *, u_char); +void tty_attributes(struct tty *, const struct grid_cell *); void tty_reset(struct tty *); void tty_region(struct tty *, u_int, u_int, u_int); void tty_cursor(struct tty *, u_int, u_int, u_int, u_int); @@ -1249,6 +1253,7 @@ void paste_add(struct paste_stack *, char *, u_int); int paste_replace(struct paste_stack *, u_int, char *); /* clock.c */ +extern const char clock_table[14][5][5]; void clock_draw(struct screen_write_ctx *, u_int, int); /* cmd.c */ @@ -1285,6 +1290,7 @@ extern const struct cmd_entry cmd_copy_mode_entry; extern const struct cmd_entry cmd_delete_buffer_entry; extern const struct cmd_entry cmd_detach_client_entry; extern const struct cmd_entry cmd_display_message_entry; +extern const struct cmd_entry cmd_display_panes_entry; extern const struct cmd_entry cmd_down_pane_entry; extern const struct cmd_entry cmd_find_window_entry; extern const struct cmd_entry cmd_has_session_entry; @@ -1435,6 +1441,8 @@ void server_status_window(struct window *); void server_lock(void); int server_unlock(const char *); void server_kill_window(struct window *); +void server_set_identify(struct client *); +void server_clear_identify(struct client *); /* status.c */ int status_redraw(struct client *); diff --git a/tty.c b/tty.c index 158bd527..de6b4d0b 100644 --- a/tty.c +++ b/tty.c @@ -34,7 +34,6 @@ void tty_raw(struct tty *, const char *); int tty_try_256(struct tty *, u_char, const char *); int tty_try_88(struct tty *, u_char, const char *); -void tty_attributes(struct tty *, const struct grid_cell *); void tty_attributes_fg(struct tty *, const struct grid_cell *); void tty_attributes_bg(struct tty *, const struct grid_cell *); From 34bb735a65674816c90212f58c71e3adb6bf2696 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 1 Sep 2009 09:00:54 +0000 Subject: [PATCH 0303/1180] Sort cases same as getopt argument, from martynas. --- tmux.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tmux.c b/tmux.c index e98d1d9c..103a6bc6 100644 --- a/tmux.c +++ b/tmux.c @@ -280,6 +280,9 @@ main(int argc, char **argv) flags |= IDENTIFY_88COLOURS; flags &= ~IDENTIFY_256COLOURS; break; + case 'd': + flags |= IDENTIFY_HASDEFAULTS; + break; case 'f': if (cfg_file) xfree(cfg_file); @@ -290,23 +293,20 @@ main(int argc, char **argv) xfree(label); label = xstrdup(optarg); break; + case 'q': + be_quiet = 1; + break; case 'S': if (path != NULL) xfree(path); path = xstrdup(optarg); break; - case 'q': - be_quiet = 1; - break; case 'u': flags |= IDENTIFY_UTF8; break; case 'U': unlock = 1; break; - case 'd': - flags |= IDENTIFY_HASDEFAULTS; - break; case 'v': debug_level++; break; From f8aa5821be6bb802785c5ca7c23c91465cfba4a3 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 1 Sep 2009 09:11:05 +0000 Subject: [PATCH 0304/1180] Use "Password:" with no space for password prompts and don't display a *s for the password, like pretty much everything else. From martynas@ with minor tweaks by me. --- server-fn.c | 2 +- status.c | 26 ++++++++++---------------- tmux.c | 2 +- 3 files changed, 12 insertions(+), 18 deletions(-) diff --git a/server-fn.c b/server-fn.c index 37bf98a4..568751df 100644 --- a/server-fn.c +++ b/server-fn.c @@ -172,7 +172,7 @@ server_lock(void) status_prompt_clear(c); status_prompt_set(c, - "Password: ", server_lock_callback, NULL, c, PROMPT_HIDDEN); + "Password:", server_lock_callback, NULL, c, PROMPT_HIDDEN); server_redraw_client(c); } server_locked = 1; diff --git a/status.c b/status.c index 51c9c64f..e1fede15 100644 --- a/status.c +++ b/status.c @@ -690,7 +690,7 @@ status_prompt_redraw(struct client *c) struct screen_write_ctx ctx; struct session *s = c->session; struct screen old_status; - size_t i, size, left, len, off, n; + size_t i, size, left, len, off; char ch; struct grid_cell gc; @@ -724,13 +724,9 @@ status_prompt_redraw(struct client *c) left--; size = left; } - if (c->prompt_flags & PROMPT_HIDDEN) { - n = strlen(c->prompt_buffer); - if (n > left) - n = left; - for (i = 0; i < n; i++) - screen_write_putc(&ctx, &gc, '*'); - } else { + if (c->prompt_flags & PROMPT_HIDDEN) + size = 0; + else { screen_write_puts(&ctx, &gc, "%.*s", (int) left, c->prompt_buffer + off); } @@ -739,17 +735,15 @@ status_prompt_redraw(struct client *c) screen_write_putc(&ctx, &gc, ' '); /* Draw a fake cursor. */ - screen_write_cursormove(&ctx, len + c->prompt_index - off, 0); - if (c->prompt_index == strlen(c->prompt_buffer)) - ch = ' '; + ch = ' '; + if (c->prompt_flags & PROMPT_HIDDEN) + screen_write_cursormove(&ctx, len, 0); else { - if (c->prompt_flags & PROMPT_HIDDEN) - ch = '*'; - else + screen_write_cursormove(&ctx, + len + c->prompt_index - off, 0); + if (c->prompt_index < strlen(c->prompt_buffer)) ch = c->prompt_buffer[c->prompt_index]; } - if (ch == '\0') - ch = ' '; gc.attr ^= GRID_ATTR_REVERSE; screen_write_putc(&ctx, &gc, ch); } diff --git a/tmux.c b/tmux.c index 103a6bc6..7053201c 100644 --- a/tmux.c +++ b/tmux.c @@ -214,7 +214,7 @@ prepare_unlock(enum msgtype *msg, void **buf, size_t *len, int argc) return (-1); } - if ((pass = getpass("Password: ")) == NULL) + if ((pass = getpass("Password:")) == NULL) return (-1); if (strlen(pass) >= sizeof unlockdata.pass) { From 7d5e4947160d9355353c29a983e373b66c05abef Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 1 Sep 2009 13:09:49 +0000 Subject: [PATCH 0305/1180] When using tmux as a login shell, there is currently no way to specify a shell to be used as a login shell inside tmux, so add a default-shell session option. This sets the shell invoked as a login shell when the default-command option is empty. The default option value is whichever of $SHELL, getpwuid(getuid())'s pw_shell or /bin/sh is valid first. Based on a diff from martynas@, changed by me to be a session option rather than a window option. --- cmd-respawn-window.c | 3 ++- cmd-set-option.c | 1 + cmd-split-window.c | 8 +++++- names.c | 2 +- session.c | 8 +++++- tmux.1 | 26 +++++++++++++++++--- tmux.c | 46 +++++++++++++++++++++++++++++++++++ tmux.h | 12 ++++++--- window.c | 58 +++++++++++++------------------------------- 9 files changed, 111 insertions(+), 53 deletions(-) diff --git a/cmd-respawn-window.c b/cmd-respawn-window.c index 8ed678b1..cd96f50b 100644 --- a/cmd-respawn-window.c +++ b/cmd-respawn-window.c @@ -75,7 +75,8 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_ctx *ctx) window_destroy_panes(w); TAILQ_INSERT_HEAD(&w->panes, wp, entry); window_pane_resize(wp, w->sx, w->sy); - if (window_pane_spawn(wp, data->arg, NULL, &env, &s->tio, &cause) != 0) { + if (window_pane_spawn( + wp, data->arg, NULL, NULL, &env, &s->tio, &cause) != 0) { ctx->error(ctx, "respawn window failed: %s", cause); xfree(cause); environ_free(&env); diff --git a/cmd-set-option.c b/cmd-set-option.c index b69ffe0d..90cb6e0b 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -55,6 +55,7 @@ const struct set_option_entry set_option_table[] = { { "buffer-limit", SET_OPTION_NUMBER, 1, INT_MAX, NULL }, { "default-command", SET_OPTION_STRING, 0, 0, NULL }, { "default-path", SET_OPTION_STRING, 0, 0, NULL }, + { "default-shell", SET_OPTION_STRING, 0, 0, NULL }, { "default-terminal", SET_OPTION_STRING, 0, 0, NULL }, { "display-panes-colour", SET_OPTION_COLOUR, 0, 0, NULL }, { "display-panes-time", SET_OPTION_NUMBER, 1, INT_MAX, NULL }, diff --git a/cmd-split-window.c b/cmd-split-window.c index d5f0ba6c..d6fc3f78 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -18,6 +18,7 @@ #include +#include #include #include @@ -151,6 +152,7 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) struct window_pane *wp; struct environ env; char *cmd, *cwd, *cause; + const char *shell; u_int hlimit; int size; enum layout_type type; @@ -183,8 +185,12 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) if (data->flag_horizontal) type = LAYOUT_LEFTRIGHT; + shell = options_get_string(&s->options, "default-shell"); + if (*shell == '\0' || areshell(shell)) + shell = _PATH_BSHELL; + wp = window_add_pane(w, hlimit); - if (window_pane_spawn(wp, cmd, cwd, &env, &s->tio, &cause) != 0) + if (window_pane_spawn(wp, cmd, shell, cwd, &env, &s->tio, &cause) != 0) goto error; if (layout_split_pane(w->active, type, size, wp) != 0) { cause = xstrdup("pane too small"); diff --git a/names.c b/names.c index 915d06bf..75f6c7b8 100644 --- a/names.c +++ b/names.c @@ -90,7 +90,7 @@ default_window_name(struct window *w) return (xstrdup("[tmux]")); if (w->active->cmd != NULL && *w->active->cmd != '\0') return (parse_window_name(w->active->cmd)); - return (parse_window_name(window_default_command())); + return (parse_window_name(w->active->shell)); } char * diff --git a/session.c b/session.c index 2e1aae3d..55d38c80 100644 --- a/session.c +++ b/session.c @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -207,6 +208,7 @@ session_new(struct session *s, { struct window *w; struct environ env; + const char *shell; u_int hlimit; environ_init(&env); @@ -214,9 +216,13 @@ session_new(struct session *s, environ_copy(&s->environ, &env); server_fill_environ(s, &env); + shell = options_get_string(&s->options, "default-shell"); + if (*shell == '\0' || areshell(shell)) + shell = _PATH_BSHELL; + hlimit = options_get_number(&s->options, "history-limit"); w = window_create( - name, cmd, cwd, &env, &s->tio, s->sx, s->sy, hlimit, cause); + name, cmd, shell, cwd, &env, &s->tio, s->sx, s->sy, hlimit, cause); if (w == NULL) { environ_free(&env); return (NULL); diff --git a/tmux.1 b/tmux.1 index 8b92fa69..a524c025 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1143,13 +1143,31 @@ maintain this maximum length. .It Ic default-command Ar command Set the command used for new windows (if not specified when the window is created) to -.Ar command . +.Ar command , +which may be any +.Xr sh 1 +command. The default is an empty string, which instructs .Nm -to create a login shell using the +to create a login shell using the value of the +.Ic default-shell +option. +.It Ic default-shell Ar path +Specify the default shell. +This is used as the login shell for new windows when the +.Ic default-command +option is set to empty, and must be the full path of the executable. +When started +.Nm +tries to set a default value from the first suitable of the .Ev SHELL -environment variable or, if it is unset, the user's shell returned by -.Xr getpwuid 3 . +environment variable, the shell returned by +.Xr getpwuid 3 , +or +.Pa /bin/sh . +This option should be configured when +.Nm +is used as a login shell. .It Ic default-path Ar path Set the default working directory for processes created from keys, or interactively from the prompt. diff --git a/tmux.c b/tmux.c index 7053201c..f77b1d6c 100644 --- a/tmux.c +++ b/tmux.c @@ -175,6 +175,50 @@ sigreset(void) fatal("sigaction failed"); } +const char * +getshell(void) +{ + struct passwd *pw; + const char *shell; + + shell = getenv("SHELL"); + if (checkshell(shell)) + return (shell); + + pw = getpwuid(getuid()); + if (pw != NULL && checkshell(pw->pw_shell)) + return (pw->pw_shell); + + return (_PATH_BSHELL); +} + +int +checkshell(const char *shell) +{ + if (shell == NULL || *shell == '\0' || areshell(shell)) + return (0); + if (access(shell, X_OK) != 0) + return (0); + return (1); +} + +int +areshell(const char *shell) +{ + const char *progname, *ptr; + + if ((ptr = strrchr(shell, '/')) != NULL) + ptr++; + else + ptr = shell; + progname = __progname; + if (*progname == '-') + progname++; + if (strcmp(ptr, progname) == 0) + return (1); + return (0); +} + char * makesockpath(const char *label) { @@ -346,6 +390,8 @@ main(int argc, char **argv) options_set_number(&global_s_options, "bell-action", BELL_ANY); options_set_number(&global_s_options, "buffer-limit", 9); options_set_string(&global_s_options, "default-command", "%s", ""); + options_set_string( + &global_s_options, "default-shell", "%s", getshell()); options_set_string(&global_s_options, "default-terminal", "screen"); options_set_number(&global_s_options, "display-panes-colour", 4); options_set_number(&global_s_options, "display-panes-time", 1000); diff --git a/tmux.h b/tmux.h index 36e660df..20f316dd 100644 --- a/tmux.h +++ b/tmux.h @@ -675,6 +675,7 @@ struct window_pane { #define PANE_REDRAW 0x1 char *cmd; + char *shell; char *cwd; pid_t pid; @@ -1117,6 +1118,9 @@ void logfile(const char *); void siginit(void); void sigreset(void); void sighandler(int); +const char *getshell(void); +int checkshell(const char *); +int areshell(const char *); /* cfg.c */ int load_cfg(const char *, struct cmd_ctx *, char **); @@ -1582,7 +1586,6 @@ int screen_check_selection(struct screen *, u_int, u_int); /* window.c */ extern struct windows windows; -const char *window_default_command(void); int window_cmp(struct window *, struct window *); int winlink_cmp(struct winlink *, struct winlink *); RB_PROTOTYPE(windows, window, entry, window_cmp); @@ -1600,8 +1603,8 @@ void winlink_stack_remove(struct winlink_stack *, struct winlink *); int window_index(struct window *, u_int *); struct window *window_create1(u_int, u_int); struct window *window_create(const char *, const char *, const char *, - struct environ *, struct termios *, u_int, u_int, u_int, - char **); + const char *, struct environ *, struct termios *, + u_int, u_int, u_int, char **); void window_destroy(struct window *); void window_set_active_pane(struct window *, struct window_pane *); struct window_pane *window_add_pane(struct window *, u_int); @@ -1614,7 +1617,8 @@ void window_destroy_panes(struct window *); struct window_pane *window_pane_create(struct window *, u_int, u_int, u_int); void window_pane_destroy(struct window_pane *); int window_pane_spawn(struct window_pane *, const char *, - const char *, struct environ *, struct termios *, char **); + const char *, const char *, struct environ *, + struct termios *, char **); void window_pane_resize(struct window_pane *, u_int, u_int); int window_pane_set_mode( struct window_pane *, const struct window_mode *); diff --git a/window.c b/window.c index 630533ee..97381785 100644 --- a/window.c +++ b/window.c @@ -58,38 +58,6 @@ struct windows windows; RB_GENERATE(winlinks, winlink, entry, winlink_cmp); -const char * -window_default_command(void) -{ - const char *shell, *ptr; - char *progname; - struct passwd *pw; - - shell = getenv("SHELL"); - if (shell != NULL && *shell != '\0') - goto found; - - pw = getpwuid(getuid()); - if (pw != NULL && pw->pw_shell != NULL && *pw->pw_shell != '\0') { - shell = pw->pw_shell; - goto found; - } - - return (_PATH_BSHELL); - -found: - if ((ptr = strrchr(shell, '/')) != NULL) - ptr++; - else - ptr = shell; - progname = __progname; - if (*progname == '-') - progname++; - if (strcmp(ptr, progname) == 0) - return (_PATH_BSHELL); - return (shell); -} - int winlink_cmp(struct winlink *wl1, struct winlink *wl2) { @@ -270,9 +238,9 @@ window_create1(u_int sx, u_int sy) } struct window * -window_create(const char *name, const char *cmd, const char *cwd, - struct environ *env, struct termios *tio, u_int sx, u_int sy, u_int hlimit, - char **cause) +window_create(const char *name, const char *cmd, const char *shell, + const char *cwd, struct environ *env, struct termios *tio, + u_int sx, u_int sy, u_int hlimit,char **cause) { struct window *w; struct window_pane *wp; @@ -280,7 +248,7 @@ window_create(const char *name, const char *cmd, const char *cwd, w = window_create1(sx, sy); wp = window_add_pane(w, hlimit); layout_init(w); - if (window_pane_spawn(wp, cmd, cwd, env, tio, cause) != 0) { + if (window_pane_spawn(wp, cmd, shell, cwd, env, tio, cause) != 0) { window_destroy(w); return (NULL); } @@ -423,6 +391,7 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit) wp->window = w; wp->cmd = NULL; + wp->shell = NULL; wp->cwd = NULL; wp->fd = -1; @@ -467,13 +436,15 @@ window_pane_destroy(struct window_pane *wp) if (wp->cwd != NULL) xfree(wp->cwd); + if (wp->shell != NULL) + xfree(wp->shell); if (wp->cmd != NULL) xfree(wp->cmd); xfree(wp); } int -window_pane_spawn(struct window_pane *wp, const char *cmd, +window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell, const char *cwd, struct environ *env, struct termios *tio, char **cause) { struct winsize ws; @@ -492,6 +463,11 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, xfree(wp->cmd); wp->cmd = xstrdup(cmd); } + if (shell != NULL) { + if (wp->shell != NULL) + xfree(wp->shell); + wp->shell = xstrdup(shell); + } if (cwd != NULL) { if (wp->cwd != NULL) xfree(wp->cwd); @@ -541,12 +517,12 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, } /* No command; fork a login shell. */ - cmd = window_default_command(); - if ((ptr = strrchr(cmd, '/')) != NULL && *(ptr + 1) != '\0') + ptr = strrchr(wp->shell, '/'); + if (ptr != NULL && *(ptr + 1) != '\0') xasprintf(&argv0, "-%s", ptr + 1); else - xasprintf(&argv0, "-%s", cmd); - execl(cmd, argv0, (char *) NULL); + xasprintf(&argv0, "-%s", wp->shell); + execl(wp->shell, argv0, (char *) NULL); fatal("execl failed"); } From c089e19020a55d5df5887821dda30cb8281dcc75 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 1 Sep 2009 14:40:33 +0000 Subject: [PATCH 0306/1180] If forking a login shell or if SHELL is otherwise not useful, set it to the default shell. Based on a diff from martynas@. --- window.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/window.c b/window.c index 97381785..62b1f487 100644 --- a/window.c +++ b/window.c @@ -512,6 +512,11 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell, log_close(); if (*wp->cmd != '\0') { + /* Set SHELL but only if it is currently not useful. */ + shell = getenv("SHELL"); + if (shell == NULL || *shell == '\0' || areshell(shell)) + setenv("SHELL", wp->shell, 1); + execl(_PATH_BSHELL, "sh", "-c", wp->cmd, (char *) NULL); fatal("execl failed"); } @@ -522,6 +527,7 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell, xasprintf(&argv0, "-%s", ptr + 1); else xasprintf(&argv0, "-%s", wp->shell); + setenv("SHELL", wp->shell, 1); execl(wp->shell, argv0, (char *) NULL); fatal("execl failed"); } From 61b7dc522d175c5f2a8b38d177adcf7282820380 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 2 Sep 2009 06:33:20 +0000 Subject: [PATCH 0307/1180] Add a transpose-chars command in edit mode (C-t in emacs mode only). From Kalle Olavi Niemitalo. --- mode-key.c | 2 ++ status.c | 14 +++++++++++++- tmux.1 | 1 + tmux.h | 1 + 4 files changed, 17 insertions(+), 1 deletion(-) diff --git a/mode-key.c b/mode-key.c index 599de5ce..ce711e0f 100644 --- a/mode-key.c +++ b/mode-key.c @@ -57,6 +57,7 @@ struct mode_key_cmdstr mode_key_cmdstr_edit[] = { { MODEKEYEDIT_STARTOFLINE, "start-of-line" }, { MODEKEYEDIT_SWITCHMODE, "switch-mode" }, { MODEKEYEDIT_SWITCHMODEAPPEND, "switch-mode-append" }, + { MODEKEYEDIT_TRANSPOSECHARS, "transpose-chars" }, { 0, NULL } }; @@ -200,6 +201,7 @@ const struct mode_key_entry mode_key_emacs_edit[] = { { '\013' /* C-k */, 0, MODEKEYEDIT_DELETETOENDOFLINE }, { '\016' /* C-n */, 0, MODEKEYEDIT_HISTORYDOWN }, { '\020' /* C-p */, 0, MODEKEYEDIT_HISTORYUP }, + { '\024' /* C-t */, 0, MODEKEYEDIT_TRANSPOSECHARS }, { '\025' /* C-u */, 0, MODEKEYEDIT_DELETELINE }, { '\031' /* C-y */, 0, MODEKEYEDIT_PASTE }, { '\033' /* Escape */, 0, MODEKEYEDIT_CANCEL }, diff --git a/status.c b/status.c index e1fede15..f0e7ce62 100644 --- a/status.c +++ b/status.c @@ -763,7 +763,7 @@ void status_prompt_key(struct client *c, int key) { struct paste_buffer *pb; - char *s, *first, *last, word[64]; + char *s, *first, *last, word[64], swapc; size_t size, n, off, idx; size = strlen(c->prompt_buffer); @@ -933,6 +933,18 @@ status_prompt_key(struct client *c, int key) c->flags |= CLIENT_STATUS; break; + case MODEKEYEDIT_TRANSPOSECHARS: + idx = c->prompt_index; + if (idx < size) + idx++; + if (idx >= 2) { + swapc = c->prompt_buffer[idx - 2]; + c->prompt_buffer[idx - 2] = c->prompt_buffer[idx - 1]; + c->prompt_buffer[idx - 1] = swapc; + c->prompt_index = idx; + c->flags |= CLIENT_STATUS; + } + break; case MODEKEYEDIT_ENTER: if (*c->prompt_buffer != '\0') status_prompt_add_history(c); diff --git a/tmux.1 b/tmux.1 index a524c025..07e9b74c 100644 --- a/tmux.1 +++ b/tmux.1 @@ -497,6 +497,7 @@ The following keys are supported as appropriate for the mode: .It Li "Search forward" Ta "/" Ta "C-s" .It Li "Start of line" Ta "0" Ta "C-a" .It Li "Start selection" Ta "Space" Ta "C-Space" +.It Li "Transpose chars" Ta "" Ta "C-t" .El .Pp These key bindings are defined in a set of named tables: diff --git a/tmux.h b/tmux.h index 20f316dd..e301b1d9 100644 --- a/tmux.h +++ b/tmux.h @@ -379,6 +379,7 @@ enum mode_key_cmd { MODEKEYEDIT_STARTOFLINE, MODEKEYEDIT_SWITCHMODE, MODEKEYEDIT_SWITCHMODEAPPEND, + MODEKEYEDIT_TRANSPOSECHARS, /* Menu (choice) keys. */ MODEKEYCHOICE_CANCEL, From c5ac2579bac08f46f68ee7b9b9e47b6123e83bd2 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 2 Sep 2009 16:38:35 +0000 Subject: [PATCH 0308/1180] When incorrect passwords are entered, behave similarly to login(1) and backoff for a bit. Based on a diff from martynas@. --- server-fn.c | 41 ++++++++++++++++++++++++++++++++++++++--- server-msg.c | 9 ++++++++- tmux.1 | 5 +++++ tmux.c | 2 ++ tmux.h | 2 ++ 5 files changed, 55 insertions(+), 4 deletions(-) diff --git a/server-fn.c b/server-fn.c index 568751df..8486b6c9 100644 --- a/server-fn.c +++ b/server-fn.c @@ -18,6 +18,8 @@ #include +#include +#include #include #include #include @@ -159,12 +161,20 @@ server_status_window(struct window *w) void server_lock(void) { - struct client *c; - u_int i; + struct client *c; + static struct passwd *pw, pwstore; + static char pwbuf[_PW_BUF_LEN]; + u_int i; if (server_locked) return; + if (getpwuid_r(getuid(), &pwstore, pwbuf, sizeof pwbuf, &pw) != 0) { + server_locked_pw = NULL; + return; + } + server_locked_pw = pw; + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); if (c == NULL || c->session == NULL) @@ -175,6 +185,7 @@ server_lock(void) "Password:", server_lock_callback, NULL, c, PROMPT_HIDDEN); server_redraw_client(c); } + server_locked = 1; } @@ -188,12 +199,16 @@ int server_unlock(const char *s) { struct client *c; + login_cap_t *lc; u_int i; char *out; + u_int failures, tries, backoff; - if (!server_locked) + if (!server_locked || server_locked_pw == NULL) return (0); server_activity = time(NULL); + if (server_activity < password_backoff) + return (-2); if (server_password != NULL) { if (s == NULL) @@ -214,10 +229,13 @@ server_unlock(const char *s) server_locked = 0; password_failures = 0; + password_backoff = 0; return (0); wrong: + password_backoff = server_activity; password_failures++; + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); if (c == NULL || c->prompt_buffer == NULL) @@ -228,6 +246,23 @@ wrong: server_redraw_client(c); } + /* + * Start slowing down after "login-backoff" attempts and reset every + * "login-tries" attempts. + */ + lc = login_getclass(server_locked_pw->pw_class); + if (lc != NULL) { + tries = login_getcapnum(lc, (char *) "login-tries", 10, 10); + backoff = login_getcapnum(lc, (char *) "login-backoff", 3, 3); + } else { + tries = 10; + backoff = 3; + } + failures = password_failures % tries; + if (failures > backoff) { + password_backoff += ((failures - backoff) * tries / 2); + return (-2); + } return (-1); } diff --git a/server-msg.c b/server-msg.c index 54bd2439..8c50339d 100644 --- a/server-msg.c +++ b/server-msg.c @@ -99,8 +99,15 @@ server_msg_dispatch(struct client *c) memcpy(&unlockdata, imsg.data, sizeof unlockdata); unlockdata.pass[(sizeof unlockdata.pass) - 1] = '\0'; - if (server_unlock(unlockdata.pass) != 0) + switch (server_unlock(unlockdata.pass)) { + case -1: server_write_error(c, "bad password"); + break; + case -2: + server_write_error(c, + "too many bad passwords, sleeping"); + break; + } memset(&unlockdata, 0, sizeof unlockdata); server_write_client(c, MSG_EXIT, NULL, 0); break; diff --git a/tmux.1 b/tmux.1 index 07e9b74c..61d77b75 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1209,6 +1209,11 @@ seconds of inactivity. The default is off (set to 0). This has no effect as a session option; it must be set as a global option using .Fl g . +When passwords are entered incorrectly, +.Nm +follows the behaviour of +.Xr login 1 +and ignores further password attempts for an increasing timeout. .It Ic message-attr Ar attributes Set status line message attributes, where .Ar attributes diff --git a/tmux.c b/tmux.c index f77b1d6c..01f7d6c3 100644 --- a/tmux.c +++ b/tmux.c @@ -47,7 +47,9 @@ struct options global_w_options; /* window options */ struct environ global_environ; int server_locked; +struct passwd *server_locked_pw; u_int password_failures; +time_t password_backoff; char *server_password; time_t server_activity; diff --git a/tmux.h b/tmux.h index e301b1d9..57d5bf4b 100644 --- a/tmux.h +++ b/tmux.h @@ -1108,7 +1108,9 @@ extern struct options global_w_options; extern struct environ global_environ; extern char *cfg_file; extern int server_locked; +extern struct passwd *server_locked_pw; extern u_int password_failures; +extern time_t password_backoff; extern char *server_password; extern time_t server_activity; extern int debug_level; From 74c35c513efc616cd56aa9bd1d7b2561fd6df132 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 2 Sep 2009 17:34:57 +0000 Subject: [PATCH 0309/1180] Accept -l to make it easier for people who use tmux as a login shell to use $SHELL. Originally from martynas@, tweaked by me. --- cmd-server-info.c | 5 +++-- tmux.1 | 6 +++++- tmux.c | 13 +++++++++---- tmux.h | 1 + 4 files changed, 18 insertions(+), 7 deletions(-) diff --git a/cmd-server-info.c b/cmd-server-info.c index daa08572..14212478 100644 --- a/cmd-server-info.c +++ b/cmd-server-info.c @@ -68,8 +68,9 @@ cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx) tim = ctime(&start_time); *strchr(tim, '\n') = '\0'; ctx->print(ctx, "pid %ld, started %s", (long) getpid(), tim); - ctx->print(ctx, "socket path %s, debug level %d%s", - socket_path, debug_level, be_quiet ? ", quiet" : ""); + ctx->print(ctx, "socket path %s, debug level %d%s%s", + socket_path, debug_level, be_quiet ? ", quiet" : "", + login_shell ? ", login shell" : ""); if (uname(&un) == 0) { ctx->print(ctx, "system is %s %s %s %s", un.sysname, un.release, un.version, un.machine); diff --git a/tmux.1 b/tmux.1 index 61d77b75..f3a36fe8 100644 --- a/tmux.1 +++ b/tmux.1 @@ -23,7 +23,7 @@ .Sh SYNOPSIS .Nm tmux .Bk -words -.Op Fl 28dqUuv +.Op Fl 28dlqUuv .Op Fl f Ar file .Op Fl L Ar socket-name .Op Fl S Ar socket-path @@ -120,6 +120,10 @@ commands which are executed in sequence when the server is first started. If a command in the configuration file fails, .Nm will report an error and exit without executing further commands. +.It Fl l +Behave as a login shell. +This flag currently has no effect and is for compatibility with other shells +when using tmux as a login shell. .It Fl L Ar socket-name .Nm stores the server socket in a directory under diff --git a/tmux.c b/tmux.c index 01f7d6c3..fce1e4d9 100644 --- a/tmux.c +++ b/tmux.c @@ -57,6 +57,7 @@ int debug_level; int be_quiet; time_t start_time; char *socket_path; +int login_shell; __dead void usage(void); char *makesockpath(const char *); @@ -68,8 +69,8 @@ __dead void usage(void) { fprintf(stderr, - "usage: %s [-28dqUuv] [-f file] [-L socket-name] [-S socket-path]\n" - " [command [flags]]\n", + "usage: %s [-28dlqUuv] [-f file] [-L socket-name]\n" + " [-S socket-path] [command [flags]]\n", __progname); exit(1); } @@ -316,8 +317,9 @@ main(int argc, char **argv) unlock = flags = 0; label = path = NULL; - while ((opt = getopt(argc, argv, "28df:L:qS:uUv")) != -1) { - switch (opt) { + login_shell = (**argv == '-'); + while ((opt = getopt(argc, argv, "28df:lL:qS:uUv")) != -1) { + switch (opt) { case '2': flags |= IDENTIFY_256COLOURS; flags &= ~IDENTIFY_88COLOURS; @@ -334,6 +336,9 @@ main(int argc, char **argv) xfree(cfg_file); cfg_file = xstrdup(optarg); break; + case 'l': + login_shell = 1; + break; case 'L': if (label != NULL) xfree(label); diff --git a/tmux.h b/tmux.h index 57d5bf4b..778346fa 100644 --- a/tmux.h +++ b/tmux.h @@ -1117,6 +1117,7 @@ extern int debug_level; extern int be_quiet; extern time_t start_time; extern char *socket_path; +extern int login_shell; void logfile(const char *); void siginit(void); void sigreset(void); From 7a4bac82d7d3cc355c92b312fda00fa9523e79f9 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 2 Sep 2009 20:00:10 +0000 Subject: [PATCH 0310/1180] Set exittype for error exit as well as the error string. --- client.c | 8 ++++++-- tmux.h | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/client.c b/client.c index 359d9482..bd062c69 100644 --- a/client.c +++ b/client.c @@ -201,7 +201,7 @@ client_main(struct client_ctx *cctx) } } } - + if (sigterm) { printf("[terminated]\n"); return (1); @@ -219,9 +219,12 @@ client_main(struct client_ctx *cctx) case CCTX_DETACH: printf("[detached]\n"); return (0); - default: + case CCTX_ERROR: printf("[error: %s]\n", cctx->errstr); return (1); + default: + printf("[error: unknown error]\n"); + return (1); } } @@ -275,6 +278,7 @@ client_msg_dispatch(struct client_ctx *cctx) printdata.msg[(sizeof printdata.msg) - 1] = '\0'; cctx->errstr = xstrdup(printdata.msg); + cctx->exittype = CCTX_ERROR; imsg_free(&imsg); return (-1); case MSG_EXIT: diff --git a/tmux.h b/tmux.h index 778346fa..6707f3ff 100644 --- a/tmux.h +++ b/tmux.h @@ -974,6 +974,7 @@ struct client_ctx { CCTX_EXIT, CCTX_DIED, CCTX_SHUTDOWN, + CCTX_ERROR } exittype; const char *errstr; }; From 459abafcea844ebb2de8cc58761edb84ffa8dec8 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 2 Sep 2009 20:15:49 +0000 Subject: [PATCH 0311/1180] That was the wrong fix. MSG_ERROR should set the error and the client should use the error and exit on MSG_EXIT (it was being handled in the default case). Undo the last change, move the errstr check into the MSG_EXIT case, and add a comment. --- client.c | 11 ++++++----- tmux.h | 3 +-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/client.c b/client.c index bd062c69..8724c35e 100644 --- a/client.c +++ b/client.c @@ -214,16 +214,17 @@ client_main(struct client_ctx *cctx) printf("[server exited]\n"); return (0); case CCTX_EXIT: + if (cctx->errstr != NULL) { + printf("[error: %s]\n", cctx->errstr); + return (1); + } printf("[exited]\n"); return (0); case CCTX_DETACH: printf("[detached]\n"); return (0); - case CCTX_ERROR: - printf("[error: %s]\n", cctx->errstr); - return (1); default: - printf("[error: unknown error]\n"); + printf("[unknown error]\n"); return (1); } } @@ -277,8 +278,8 @@ client_msg_dispatch(struct client_ctx *cctx) memcpy(&printdata, imsg.data, sizeof printdata); printdata.msg[(sizeof printdata.msg) - 1] = '\0'; + /* Error string used after exit message from server. */ cctx->errstr = xstrdup(printdata.msg); - cctx->exittype = CCTX_ERROR; imsg_free(&imsg); return (-1); case MSG_EXIT: diff --git a/tmux.h b/tmux.h index 6707f3ff..49851ddf 100644 --- a/tmux.h +++ b/tmux.h @@ -973,8 +973,7 @@ struct client_ctx { CCTX_DETACH, CCTX_EXIT, CCTX_DIED, - CCTX_SHUTDOWN, - CCTX_ERROR + CCTX_SHUTDOWN } exittype; const char *errstr; }; From 81a457e6fb169141fe567feb7bf70f98a8ad6c2a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 2 Sep 2009 21:25:57 +0000 Subject: [PATCH 0312/1180] When shutting down the server, expect clients to be polite and exit when asked with the right message. --- server.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/server.c b/server.c index 3bb93d95..970a5ca0 100644 --- a/server.c +++ b/server.c @@ -202,8 +202,8 @@ error: server_write_error(c, cause); xfree(cause); + sigterm = 1; server_shutdown(); - c->flags |= CLIENT_BAD; exit(server_main(srv_fd)); } @@ -304,7 +304,7 @@ server_main(int srv_fd) /* Update socket permissions. */ xtimeout = INFTIM; - if (sigterm || server_update_socket() != 0) + if (server_update_socket() != 0) xtimeout = POLL_TIMEOUT; /* Do the poll. */ @@ -420,7 +420,6 @@ server_shutdown(void) server_lost_client(c); else server_write_client(c, MSG_SHUTDOWN, NULL, 0); - c->flags |= CLIENT_BAD; } } } From 751a2fa915bc73e45e4914a26ddb3d1cb3e6a653 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 2 Sep 2009 23:49:25 +0000 Subject: [PATCH 0313/1180] Fix a race condition when asking a client to take over the terminal (switching to a different poll loop): If a MSG_READY was followed very quickly by a MSG_EXIT (for example if doing "tmux new 'exit'"), both messages could be read as part of the same imsg_read in the first client poll loop. The MSG_READY would then cause a switch to the second client loop, which would immediately call poll(2) again, causing the client to hang forever waiting for an exit message that it already had. Change to call imsg_get to process any existing messages before polling. --- client.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/client.c b/client.c index 8724c35e..abf2f782 100644 --- a/client.c +++ b/client.c @@ -152,12 +152,21 @@ int client_main(struct client_ctx *cctx) { struct pollfd pfd; - int nfds; + int n, nfds; siginit(); logfile("client"); + /* + * imsg_read in the first client poll loop (before the terminal has + * been initialiased) may have read messages into the buffer after the + * MSG_READY switched to here. Process anything outstanding now so poll + * doesn't hang waiting for messages that have already arrived. + */ + if (client_msg_dispatch(cctx) != 0) + goto out; + for (;;) { if (sigterm) client_write_server(cctx, MSG_EXITING, NULL, 0); @@ -190,6 +199,10 @@ client_main(struct client_ctx *cctx) fatalx("socket error"); if (pfd.revents & POLLIN) { + if ((n = imsg_read(&cctx->ibuf)) == -1 || n == 0) { + cctx->exittype = CCTX_DIED; + break; + } if (client_msg_dispatch(cctx) != 0) break; } @@ -201,7 +214,8 @@ client_main(struct client_ctx *cctx) } } } - + +out: if (sigterm) { printf("[terminated]\n"); return (1); @@ -252,11 +266,6 @@ client_msg_dispatch(struct client_ctx *cctx) struct msg_print_data printdata; ssize_t n, datalen; - if ((n = imsg_read(&cctx->ibuf)) == -1 || n == 0) { - cctx->exittype = CCTX_DIED; - return (-1); - } - for (;;) { if ((n = imsg_get(&cctx->ibuf, &imsg)) == -1) fatalx("imsg_get failed"); From be0d6faa158fd45a1444246e8532ad61bcce11f0 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 4 Sep 2009 13:29:10 +0000 Subject: [PATCH 0314/1180] Tell the user when sleeping due to password backoff. --- server.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/server.c b/server.c index 970a5ca0..82396b2e 100644 --- a/server.c +++ b/server.c @@ -605,6 +605,8 @@ server_redraw_locked(struct client *c) screen_write_cursormove(&ctx, 0, 0); screen_write_puts( &ctx, &gc, "%u failed attempts", password_failures); + if (time(NULL) < password_backoff) + screen_write_puts(&ctx, &gc, "; sleeping"); } screen_write_stop(&ctx); @@ -1183,6 +1185,7 @@ void server_second_timers(void) { struct window *w; + struct client *c; struct window_pane *wp; u_int i; int xtimeout; @@ -1191,6 +1194,7 @@ server_second_timers(void) time_t t; t = time(NULL); + xtimeout = options_get_number(&global_s_options, "lock-after-time"); if (xtimeout > 0 && t > server_activity + xtimeout) server_lock(); @@ -1206,6 +1210,13 @@ server_second_timers(void) } } + if (t > password_backoff) { + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + if ((c = ARRAY_ITEM(&clients, i)) != NULL) + server_redraw_client(c); + } + } + /* Check for a minute having passed. */ gmtime_r(&t, &now); gmtime_r(&last_t, &then); From 83af55bed4d4bcdb709a4b7db4543c6b5b489442 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 4 Sep 2009 15:15:24 +0000 Subject: [PATCH 0315/1180] Tidy main and make it a bit easier to read. --- tmux.c | 179 +++++++++++++++++++++++++++++---------------------------- 1 file changed, 90 insertions(+), 89 deletions(-) diff --git a/tmux.c b/tmux.c index fce1e4d9..66ba8767 100644 --- a/tmux.c +++ b/tmux.c @@ -308,6 +308,7 @@ main(int argc, char **argv) struct pollfd pfd; enum msgtype msg; struct passwd *pw; + struct options *so, *wo; char *s, *path, *label, *home, *cause, **var; char cwd[MAXPATHLEN]; void *buf; @@ -332,7 +333,7 @@ main(int argc, char **argv) flags |= IDENTIFY_HASDEFAULTS; break; case 'f': - if (cfg_file) + if (cfg_file != NULL) xfree(cfg_file); cfg_file = xstrdup(optarg); break; @@ -371,10 +372,6 @@ main(int argc, char **argv) log_open_tty(debug_level); siginit(); - environ_init(&global_environ); - for (var = environ; *var != NULL; var++) - environ_put(&global_environ, *var); - if (!(flags & IDENTIFY_UTF8)) { /* * If the user has set whichever of LC_ALL, LC_CTYPE or LANG @@ -392,84 +389,97 @@ main(int argc, char **argv) flags |= IDENTIFY_UTF8; } + environ_init(&global_environ); + for (var = environ; *var != NULL; var++) + environ_put(&global_environ, *var); + options_init(&global_s_options, NULL); - options_set_number(&global_s_options, "base-index", 0); - options_set_number(&global_s_options, "bell-action", BELL_ANY); - options_set_number(&global_s_options, "buffer-limit", 9); - options_set_string(&global_s_options, "default-command", "%s", ""); - options_set_string( - &global_s_options, "default-shell", "%s", getshell()); - options_set_string(&global_s_options, "default-terminal", "screen"); - options_set_number(&global_s_options, "display-panes-colour", 4); - options_set_number(&global_s_options, "display-panes-time", 1000); - options_set_number(&global_s_options, "display-time", 750); - options_set_number(&global_s_options, "history-limit", 2000); - options_set_number(&global_s_options, "lock-after-time", 0); - options_set_number(&global_s_options, "message-attr", 0); - options_set_number(&global_s_options, "message-bg", 3); - options_set_number(&global_s_options, "message-fg", 0); - options_set_number(&global_s_options, "prefix", '\002'); - options_set_number(&global_s_options, "repeat-time", 500); - options_set_number(&global_s_options, "set-remain-on-exit", 0); - options_set_number(&global_s_options, "set-titles", 0); - options_set_number(&global_s_options, "status", 1); - options_set_number(&global_s_options, "status-attr", 0); - options_set_number(&global_s_options, "status-bg", 2); - options_set_number(&global_s_options, "status-fg", 0); - options_set_number(&global_s_options, "status-interval", 15); - options_set_number(&global_s_options, "status-keys", MODEKEY_EMACS); - options_set_number(&global_s_options, "status-justify", 0); - options_set_string(&global_s_options, "status-left", "[#S]"); - options_set_number(&global_s_options, "status-left-attr", 0); - options_set_number(&global_s_options, "status-left-fg", 8); - options_set_number(&global_s_options, "status-left-bg", 8); - options_set_number(&global_s_options, "status-left-length", 10); - options_set_string( - &global_s_options, "status-right", "\"#22T\" %%H:%%M %%d-%%b-%%y"); - options_set_number(&global_s_options, "status-right-attr", 0); - options_set_number(&global_s_options, "status-right-fg", 8); - options_set_number(&global_s_options, "status-right-bg", 8); - options_set_number(&global_s_options, "status-right-length", 40); - if (flags & IDENTIFY_UTF8) - options_set_number(&global_s_options, "status-utf8", 1); - else - options_set_number(&global_s_options, "status-utf8", 0); - options_set_string(&global_s_options, - "terminal-overrides", "*88col*:colors=88,*256col*:colors=256"); - options_set_string(&global_s_options, "update-environment", "DISPLAY " + so = &global_s_options; + options_set_number(so, "base-index", 0); + options_set_number(so, "bell-action", BELL_ANY); + options_set_number(so, "buffer-limit", 9); + options_set_string(so, "default-command", "%s", ""); + options_set_string(so, "default-shell", "%s", getshell()); + options_set_string(so, "default-terminal", "screen"); + options_set_number(so, "display-panes-colour", 4); + options_set_number(so, "display-panes-time", 1000); + options_set_number(so, "display-time", 750); + options_set_number(so, "history-limit", 2000); + options_set_number(so, "lock-after-time", 0); + options_set_number(so, "message-attr", 0); + options_set_number(so, "message-bg", 3); + options_set_number(so, "message-fg", 0); + options_set_number(so, "prefix", '\002'); + options_set_number(so, "repeat-time", 500); + options_set_number(so, "set-remain-on-exit", 0); + options_set_number(so, "set-titles", 0); + options_set_number(so, "status", 1); + options_set_number(so, "status-attr", 0); + options_set_number(so, "status-bg", 2); + options_set_number(so, "status-fg", 0); + options_set_number(so, "status-interval", 15); + options_set_number(so, "status-justify", 0); + options_set_number(so, "status-keys", MODEKEY_EMACS); + options_set_string(so, "status-left", "[#S]"); + options_set_number(so, "status-left-attr", 0); + options_set_number(so, "status-left-bg", 8); + options_set_number(so, "status-left-fg", 8); + options_set_number(so, "status-left-length", 10); + options_set_string(so, "status-right", "\"#22T\" %%H:%%M %%d-%%b-%%y"); + options_set_number(so, "status-right-attr", 0); + options_set_number(so, "status-right-bg", 8); + options_set_number(so, "status-right-fg", 8); + options_set_number(so, "status-right-length", 40); + options_set_string(so, "terminal-overrides", + "*88col*:colors=88,*256col*:colors=256"); + options_set_string(so, "update-environment", "DISPLAY " "WINDOWID SSH_ASKPASS SSH_AUTH_SOCK SSH_AGENT_PID SSH_CONNECTION"); - options_set_number(&global_s_options, "visual-activity", 0); - options_set_number(&global_s_options, "visual-bell", 0); - options_set_number(&global_s_options, "visual-content", 0); + options_set_number(so, "visual-activity", 0); + options_set_number(so, "visual-bell", 0); + options_set_number(so, "visual-content", 0); options_init(&global_w_options, NULL); - options_set_number(&global_w_options, "aggressive-resize", 0); - options_set_number(&global_w_options, "automatic-rename", 1); - options_set_number(&global_w_options, "clock-mode-colour", 4); - options_set_number(&global_w_options, "clock-mode-style", 1); - options_set_number(&global_w_options, "force-height", 0); - options_set_number(&global_w_options, "force-width", 0); - options_set_number(&global_w_options, "main-pane-width", 81); - options_set_number(&global_w_options, "main-pane-height", 24); - options_set_number(&global_w_options, "mode-attr", 0); - options_set_number(&global_w_options, "mode-bg", 3); - options_set_number(&global_w_options, "mode-fg", 0); - options_set_number(&global_w_options, "mode-keys", MODEKEY_EMACS); - options_set_number(&global_w_options, "mode-mouse", 0); - options_set_number(&global_w_options, "monitor-activity", 0); - options_set_string(&global_w_options, "monitor-content", "%s", ""); - if (flags & IDENTIFY_UTF8) - options_set_number(&global_w_options, "utf8", 1); - else - options_set_number(&global_w_options, "utf8", 0); - options_set_number(&global_w_options, "window-status-attr", 0); - options_set_number(&global_w_options, "window-status-bg", 8); - options_set_number(&global_w_options, "window-status-fg", 8); - options_set_number(&global_w_options, "window-status-current-attr", 0); - options_set_number(&global_w_options, "window-status-current-bg", 8); - options_set_number(&global_w_options, "window-status-current-fg", 8); - options_set_number(&global_w_options, "xterm-keys", 0); - options_set_number(&global_w_options, "remain-on-exit", 0); + wo = &global_w_options; + options_set_number(wo, "aggressive-resize", 0); + options_set_number(wo, "automatic-rename", 1); + options_set_number(wo, "clock-mode-colour", 4); + options_set_number(wo, "clock-mode-style", 1); + options_set_number(wo, "force-height", 0); + options_set_number(wo, "force-width", 0); + options_set_number(wo, "main-pane-height", 24); + options_set_number(wo, "main-pane-width", 81); + options_set_number(wo, "mode-attr", 0); + options_set_number(wo, "mode-bg", 3); + options_set_number(wo, "mode-fg", 0); + options_set_number(wo, "mode-keys", MODEKEY_EMACS); + options_set_number(wo, "mode-mouse", 0); + options_set_number(wo, "monitor-activity", 0); + options_set_string(wo, "monitor-content", "%s", ""); + options_set_number(wo, "window-status-attr", 0); + options_set_number(wo, "window-status-bg", 8); + options_set_number(wo, "window-status-current-attr", 0); + options_set_number(wo, "window-status-current-bg", 8); + options_set_number(wo, "window-status-current-fg", 8); + options_set_number(wo, "window-status-fg", 8); + options_set_number(wo, "xterm-keys", 0); + options_set_number(wo, "remain-on-exit", 0); + + if (flags & IDENTIFY_UTF8) { + options_set_number(so, "status-utf8", 1); + options_set_number(wo, "utf8", 1); + } else { + options_set_number(so, "status-utf8", 0); + options_set_number(wo, "utf8", 0); + } + + if (getcwd(cwd, sizeof cwd) == NULL) { + pw = getpwuid(getuid()); + if (pw->pw_dir != NULL && *pw->pw_dir != '\0') + strlcpy(cwd, pw->pw_dir, sizeof cwd); + else + strlcpy(cwd, "/", sizeof cwd); + } + options_set_string(so, "default-path", "%s", cwd); if (cfg_file == NULL) { home = getenv("HOME"); @@ -498,15 +508,6 @@ main(int argc, char **argv) } xfree(label); - if (getcwd(cwd, sizeof cwd) == NULL) { - pw = getpwuid(getuid()); - if (pw->pw_dir != NULL && *pw->pw_dir != '\0') - strlcpy(cwd, pw->pw_dir, sizeof cwd); - else - strlcpy(cwd, "/", sizeof cwd); - } - options_set_string(&global_s_options, "default-path", "%s", cwd); - if (unlock) { if (prepare_unlock(&msg, &buf, &len, argc) != 0) exit(1); @@ -517,7 +518,7 @@ main(int argc, char **argv) if (unlock) cmdflags &= ~CMD_STARTSERVER; - else if (argc == 0) + else if (argc == 0) /* new-session is the default */ cmdflags |= CMD_STARTSERVER|CMD_SENDENVIRON; else { /* From ffab22bb35a990a72f3a13c9729680c01e23a727 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 5 Sep 2009 17:42:16 +0000 Subject: [PATCH 0316/1180] Only redraw all clients once when the backoff timer expires rather than every second all the time. Reported by Simon Nicolussi. --- server-fn.c | 5 +++-- server.c | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/server-fn.c b/server-fn.c index 8486b6c9..d3cdbd60 100644 --- a/server-fn.c +++ b/server-fn.c @@ -233,8 +233,8 @@ server_unlock(const char *s) return (0); wrong: - password_backoff = server_activity; password_failures++; + password_backoff = 0; for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); @@ -260,7 +260,8 @@ wrong: } failures = password_failures % tries; if (failures > backoff) { - password_backoff += ((failures - backoff) * tries / 2); + password_backoff = + server_activity + ((failures - backoff) * tries / 2); return (-2); } return (-1); diff --git a/server.c b/server.c index 82396b2e..9841816b 100644 --- a/server.c +++ b/server.c @@ -1210,11 +1210,12 @@ server_second_timers(void) } } - if (t > password_backoff) { + if (password_backoff != 0 && t >= password_backoff) { for (i = 0; i < ARRAY_LENGTH(&clients); i++) { if ((c = ARRAY_ITEM(&clients, i)) != NULL) server_redraw_client(c); } + password_backoff = 0; } /* Check for a minute having passed. */ From e97006b102dd274dd8cc70c2aee13f6b09f69a41 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 7 Sep 2009 10:49:32 +0000 Subject: [PATCH 0317/1180] Permit embedded colour and attributes in status-left and status-right using new #[] special characters, for example #[fg=red,bg=blue,blink]. --- screen-write.c | 172 +++++++++++++++++++++++++++++++++++++++++++++++++ status.c | 22 +++++-- tmux.1 | 20 +++++- tmux.h | 5 ++ 4 files changed, 214 insertions(+), 5 deletions(-) diff --git a/screen-write.c b/screen-write.c index bfb4e7f2..62acadd2 100644 --- a/screen-write.c +++ b/screen-write.c @@ -52,6 +52,41 @@ screen_write_putc( screen_write_cell(ctx, gc, NULL); } +/* Calculate string length, with embedded formatting. */ +size_t printflike2 +screen_write_cstrlen(int utf8flag, const char *fmt, ...) +{ + va_list ap; + char *msg, *msg2, *ptr, *ptr2; + size_t size; + + va_start(ap, fmt); + xvasprintf(&msg, fmt, ap); + va_end(ap); + msg2 = xmalloc(strlen(msg) + 1); + + ptr = msg; + ptr2 = msg2; + while (*ptr != '\0') { + if (ptr[0] == '#' && ptr[1] == '[') { + while (*ptr != ']' && *ptr != '\0') + ptr++; + if (*ptr == ']') + ptr++; + continue; + } + *ptr2++ = *ptr++; + } + *ptr2 = '\0'; + + size = screen_write_strlen(utf8flag, "%s", msg2); + + xfree(msg); + xfree(msg2); + + return (size); +} + /* Calculate string length. */ size_t printflike2 screen_write_strlen(int utf8flag, const char *fmt, ...) @@ -177,6 +212,143 @@ screen_write_vnputs(struct screen_write_ctx *ctx, ssize_t maxlen, xfree(msg); } +/* Write string, similar to nputs, but with embedded formatting (#[]). */ +void printflike5 +screen_write_cnputs(struct screen_write_ctx *ctx, + ssize_t maxlen, struct grid_cell *gc, int utf8flag, const char *fmt, ...) +{ + struct grid_cell lgc; + va_list ap; + char *msg; + u_char *ptr, *last, utf8buf[4]; + size_t left, size = 0; + int width; + + va_start(ap, fmt); + xvasprintf(&msg, fmt, ap); + va_end(ap); + + memcpy(&lgc, gc, sizeof lgc); + + ptr = msg; + while (*ptr != '\0') { + if (ptr[0] == '#' && ptr[1] == '[') { + ptr += 2; + last = ptr + strcspn(ptr, "]"); + if (*last == '\0') { + /* No ]. Not much point in doing anything. */ + break; + } + *last = '\0'; + + screen_write_parsestyle(gc, &lgc, ptr); + ptr = last + 1; + continue; + } + + if (utf8flag && *ptr > 0x7f) { + memset(utf8buf, 0xff, sizeof utf8buf); + + left = strlen(ptr); + if (*ptr >= 0xc2 && *ptr <= 0xdf && left >= 2) { + memcpy(utf8buf, ptr, 2); + ptr += 2; + } else if (*ptr >= 0xe0 && *ptr <= 0xef && left >= 3) { + memcpy(utf8buf, ptr, 3); + ptr += 3; + } else if (*ptr >= 0xf0 && *ptr <= 0xf4 && left >= 4) { + memcpy(utf8buf, ptr, 4); + ptr += 4; + } else { + *utf8buf = *ptr; + ptr++; + } + + width = utf8_width(utf8buf); + if (maxlen > 0 && size + width > (size_t) maxlen) { + while (size < (size_t) maxlen) { + screen_write_putc(ctx, gc, ' '); + size++; + } + break; + } + size += width; + + lgc.flags |= GRID_FLAG_UTF8; + screen_write_cell(ctx, &lgc, utf8buf); + lgc.flags &= ~GRID_FLAG_UTF8; + + } else { + if (maxlen > 0 && size + 1 > (size_t) maxlen) + break; + + size++; + screen_write_putc(ctx, &lgc, *ptr); + ptr++; + } + } + + xfree(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; + + if (*in == '\0') + return; + if (strchr(delimiters, in[strlen(in) - 1]) != NULL) + return; + + fg = gc->fg; + bg = gc->bg; + attr = 0; + 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; + } 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) + fg = val; + else + fg = defgc->fg; + } else if (*in == 'b' || *in == 'B') { + if (val != 8) + bg = val; + else + bg = defgc->bg; + } else + return; + } 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; +} + /* Copy from another screen. */ void screen_write_copy(struct screen_write_ctx *ctx, diff --git a/status.c b/status.c index f0e7ce62..5e696afb 100644 --- a/status.c +++ b/status.c @@ -107,14 +107,14 @@ status_redraw(struct client *c) left = status_replace(s, options_get_string( &s->options, "status-left"), c->status_timer.tv_sec); llen = options_get_number(&s->options, "status-left-length"); - llen2 = screen_write_strlen(utf8flag, "%s", left); + llen2 = screen_write_cstrlen(utf8flag, "%s", left); if (llen2 < llen) llen = llen2; right = status_replace(s, options_get_string( &s->options, "status-right"), c->status_timer.tv_sec); rlen = options_get_number(&s->options, "status-right-length"); - rlen2 = screen_write_strlen(utf8flag, "%s", right); + rlen2 = screen_write_cstrlen(utf8flag, "%s", right); if (rlen2 < rlen) rlen = rlen2; @@ -192,7 +192,7 @@ draw: screen_write_start(&ctx, NULL, &c->status); if (llen != 0) { screen_write_cursormove(&ctx, 0, yy); - screen_write_nputs(&ctx, llen, &sl_stdgc, utf8flag, "%s", left); + screen_write_cnputs(&ctx, llen, &sl_stdgc, utf8flag, "%s", left); screen_write_putc(&ctx, &stdgc, ' '); if (larrow) screen_write_putc(&ctx, &stdgc, ' '); @@ -266,7 +266,7 @@ draw: if (rlen != 0) { screen_write_cursormove(&ctx, c->tty.sx - rlen - 1, yy); screen_write_putc(&ctx, &stdgc, ' '); - screen_write_nputs(&ctx, rlen, &sr_stdgc, utf8flag, "%s", right); + screen_write_cnputs(&ctx, rlen, &sr_stdgc, utf8flag, "%s", right); } /* Draw the arrows. */ @@ -400,6 +400,20 @@ status_replace(struct session *s, const char *fmt, time_t t) len--; } break; + case '[': + /* + * Embedded style, handled at display time. + * Leave present and skip input until ]. + */ + *optr++ = '#'; + + iptr--; /* include [ */ + while (*iptr != ']' && *iptr != '\0') { + if (optr >= out + (sizeof out) - 1) + break; + *optr++ = *iptr++; + } + break; case '#': *optr++ = '#'; break; diff --git a/tmux.1 b/tmux.1 index f3a36fe8..757005d9 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1316,10 +1316,11 @@ will be passed through before being used. By default, the session name is shown. .Ar string -may contain any of the following special character pairs: +may contain any of the following special character sequences: .Bl -column "Character pair" "Replaced with" -offset indent .It Sy "Character pair" Ta Sy "Replaced with" .It Li "#(command)" Ta "First line of command's output" +.It Li "#[attributes]" Ta "Colour or attribute change" .It Li "#H" Ta "Hostname of local host" .It Li "#I" Ta "Current window index" .It Li "#P" Ta "Current pane index" @@ -1329,6 +1330,23 @@ may contain any of the following special character pairs: .It Li "##" Ta "A literal" Ql # .El .Pp +The #(command) form executes +.Ql command +as a shell command and inserts the first line of its output. +#[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, or one of the attributes described under the +.Ic message-attr +option. +Examples are: +.Bd -literal -offset indent +#(sysctl vm.loadavg) +#[fg=yellow,bold]#(apm -l)%%#[default] [#S] +.Ed +.Pp Where appropriate, these may be prefixed with a number to specify the maximum length, for example .Ql #24T . diff --git a/tmux.h b/tmux.h index 49851ddf..d2004bdd 100644 --- a/tmux.h +++ b/tmux.h @@ -1533,6 +1533,9 @@ char *grid_view_string_cells(struct grid *, u_int, u_int, u_int); void screen_write_start( struct screen_write_ctx *, struct window_pane *, struct screen *); void screen_write_stop(struct screen_write_ctx *); +size_t printflike2 screen_write_cstrlen(int, const char *, ...); +void printflike5 screen_write_cnputs(struct screen_write_ctx *, + ssize_t, struct grid_cell *, int, const char *, ...); size_t printflike2 screen_write_strlen(int, const char *, ...); void printflike3 screen_write_puts(struct screen_write_ctx *, struct grid_cell *, const char *, ...); @@ -1540,6 +1543,8 @@ 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 *, From ccba613e5b277e70e8261c04ecc37ff3ef14a217 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 7 Sep 2009 18:50:45 +0000 Subject: [PATCH 0318/1180] Give each paste buffer a size member instead of requiring them to be zero-terminated. --- cmd-copy-buffer.c | 27 +++++++++++++++++---------- cmd-list-buffers.c | 2 +- cmd-load-buffer.c | 17 ++++++++--------- cmd-paste-buffer.c | 15 ++++++--------- cmd-save-buffer.c | 2 +- cmd-set-buffer.c | 14 ++++++++++---- cmd-show-buffer.c | 3 +-- paste.c | 6 ++++-- status.c | 7 ++++--- tmux.h | 5 +++-- window-copy.c | 11 +++++++---- 11 files changed, 62 insertions(+), 47 deletions(-) diff --git a/cmd-copy-buffer.c b/cmd-copy-buffer.c index 7cef21ef..695c909c 100644 --- a/cmd-copy-buffer.c +++ b/cmd-copy-buffer.c @@ -16,7 +16,10 @@ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include + #include +#include #include "tmux.h" @@ -122,34 +125,38 @@ cmd_copy_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) { struct cmd_copy_buffer_data *data = self->data; struct paste_buffer *pb; + struct paste_stack *dst_ps, *src_ps; + u_char *pdata; struct session *dst_session, *src_session; u_int limit; if ((dst_session = cmd_find_session(ctx, data->dst_session)) == NULL || (src_session = cmd_find_session(ctx, data->src_session)) == NULL) return (-1); + dst_ps = &dst_session->buffers; + src_ps = &src_session->buffers; if (data->src_idx == -1) { - if ((pb = paste_get_top(&src_session->buffers)) == NULL) { + if ((pb = paste_get_top(src_ps)) == NULL) { ctx->error(ctx, "no buffers"); return (-1); } } else { - if ((pb = paste_get_index(&src_session->buffers, - data->src_idx)) == NULL) { + if ((pb = paste_get_index(src_ps, data->src_idx)) == NULL) { ctx->error(ctx, "no buffer %d", data->src_idx); return (-1); } } - limit = options_get_number(&dst_session->options, "buffer-limit"); - if (data->dst_idx == -1) { - paste_add(&dst_session->buffers, xstrdup(pb->data), limit); - return (0); - } - if (paste_replace(&dst_session->buffers, data->dst_idx, - xstrdup(pb->data)) != 0) { + + pdata = xmalloc(pb->size); + memcpy(pdata, pb->data, pb->size); + + if (data->dst_idx == -1) + paste_add(dst_ps, pdata, pb->size, limit); + else if (paste_replace(dst_ps, data->dst_idx, pdata, pb->size) != 0) { ctx->error(ctx, "no buffer %d", data->dst_idx); + xfree(pdata); return (-1); } diff --git a/cmd-list-buffers.c b/cmd-list-buffers.c index f32d32f5..bb0e6a64 100644 --- a/cmd-list-buffers.c +++ b/cmd-list-buffers.c @@ -55,7 +55,7 @@ cmd_list_buffers_exec(struct cmd *self, struct cmd_ctx *ctx) idx = 0; while ((pb = paste_walk_stack(&s->buffers, &idx)) != NULL) { - size = strlen(pb->data); + size = pb->size; /* Translate the first 50 characters. */ len = size; diff --git a/cmd-load-buffer.c b/cmd-load-buffer.c index 4a7f9ffb..1f8e75cd 100644 --- a/cmd-load-buffer.c +++ b/cmd-load-buffer.c @@ -48,15 +48,15 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) { struct cmd_buffer_data *data = self->data; struct session *s; - struct stat statbuf; + struct stat sb; FILE *f; - char *buf; - u_int limit; + u_char *buf; + u_int limit; if ((s = cmd_find_session(ctx, data->target)) == NULL) return (-1); - if (stat(data->arg, &statbuf) < 0) { + if (stat(data->arg, &sb) < 0) { ctx->error(ctx, "%s: %s", data->arg, strerror(errno)); return (-1); } @@ -70,28 +70,27 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) * We don't want to die due to memory exhaustion, hence xmalloc can't * be used here. */ - if ((buf = malloc(statbuf.st_size + 1)) == NULL) { + if ((buf = malloc(sb.st_size + 1)) == NULL) { ctx->error(ctx, "malloc error: %s", strerror(errno)); fclose(f); return (-1); } - if (fread(buf, 1, statbuf.st_size, f) != (size_t) statbuf.st_size) { + if (fread(buf, 1, sb.st_size, f) != (size_t) sb.st_size) { ctx->error(ctx, "%s: fread error", data->arg); xfree(buf); fclose(f); return (-1); } - buf[statbuf.st_size] = '\0'; fclose(f); limit = options_get_number(&s->options, "buffer-limit"); if (data->buffer == -1) { - paste_add(&s->buffers, buf, limit); + paste_add(&s->buffers, buf, sb.st_size, limit); return (0); } - if (paste_replace(&s->buffers, data->buffer, buf) != 0) { + if (paste_replace(&s->buffers, data->buffer, buf, sb.st_size) != 0) { ctx->error(ctx, "no buffer %d", data->buffer); xfree(buf); return (-1); diff --git a/cmd-paste-buffer.c b/cmd-paste-buffer.c index 90deeb00..1d92557f 100644 --- a/cmd-paste-buffer.c +++ b/cmd-paste-buffer.c @@ -45,13 +45,13 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) { struct cmd_buffer_data *data = self->data; struct winlink *wl; - struct window *w; + struct window_pane *wp; struct session *s; struct paste_buffer *pb; if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL) return (-1); - w = wl->window; + wp = wl->window->active; if (data->buffer == -1) pb = paste_get_top(&s->buffers); @@ -64,13 +64,10 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) if (pb != NULL && *pb->data != '\0') { /* -r means raw data without LF->CR conversion. */ - if (data->chflags & CMD_CHFLAG('r')) { - buffer_write( - w->active->out, pb->data, strlen(pb->data)); - } else { - cmd_paste_buffer_lf2cr( - w->active->out, pb->data, strlen(pb->data)); - } + if (data->chflags & CMD_CHFLAG('r')) + buffer_write(wp->out, pb->data, pb->size); + else + cmd_paste_buffer_lf2cr(wp->out, pb->data, pb->size); } /* Delete the buffer if -d. */ diff --git a/cmd-save-buffer.c b/cmd-save-buffer.c index d48571dd..5a779dc1 100644 --- a/cmd-save-buffer.c +++ b/cmd-save-buffer.c @@ -75,7 +75,7 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) return (-1); } - if (fwrite(pb->data, 1, strlen(pb->data), f) != strlen(pb->data)) { + if (fwrite(pb->data, 1, pb->size, f) != pb->size) { ctx->error(ctx, "%s: fwrite error", data->arg); fclose(f); return (-1); diff --git a/cmd-set-buffer.c b/cmd-set-buffer.c index 8c2b8441..2f624040 100644 --- a/cmd-set-buffer.c +++ b/cmd-set-buffer.c @@ -18,7 +18,7 @@ #include -#include +#include #include "tmux.h" @@ -45,17 +45,23 @@ cmd_set_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) struct cmd_buffer_data *data = self->data; struct session *s; u_int limit; + u_char *pdata; + size_t psize; if ((s = cmd_find_session(ctx, data->target)) == NULL) return (-1); - limit = options_get_number(&s->options, "buffer-limit"); + + pdata = xstrdup(data->arg); + psize = strlen(pdata); + if (data->buffer == -1) { - paste_add(&s->buffers, xstrdup(data->arg), limit); + paste_add(&s->buffers, pdata, psize, limit); return (0); } - if (paste_replace(&s->buffers, data->buffer, xstrdup(data->arg)) != 0) { + if (paste_replace(&s->buffers, data->buffer, pdata, psize) != 0) { ctx->error(ctx, "no buffer %d", data->buffer); + xfree(pdata); return (-1); } return (0); diff --git a/cmd-show-buffer.c b/cmd-show-buffer.c index 8972f098..151fc2ae 100644 --- a/cmd-show-buffer.c +++ b/cmd-show-buffer.c @@ -18,7 +18,6 @@ #include -#include #include #include "tmux.h" @@ -65,7 +64,7 @@ cmd_show_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) if (pb == NULL) return (0); - size = strlen(pb->data); + size = pb->size; if (size > SIZE_MAX / 4 - 1) size = SIZE_MAX / 4 - 1; in = xmalloc(size * 4 + 1); diff --git a/paste.c b/paste.c index 82fa0939..f78c0241 100644 --- a/paste.c +++ b/paste.c @@ -97,7 +97,7 @@ paste_free_index(struct paste_stack *ps, u_int idx) } void -paste_add(struct paste_stack *ps, char *data, u_int limit) +paste_add(struct paste_stack *ps, u_char *data, size_t size, u_int limit) { struct paste_buffer *pb; @@ -115,12 +115,13 @@ paste_add(struct paste_stack *ps, char *data, u_int limit) ARRAY_INSERT(ps, 0, pb); pb->data = data; + pb->size = size; if (gettimeofday(&pb->tv, NULL) != 0) fatal("gettimeofday"); } int -paste_replace(struct paste_stack *ps, u_int idx, char *data) +paste_replace(struct paste_stack *ps, u_int idx, u_char *data, size_t size) { struct paste_buffer *pb; @@ -131,6 +132,7 @@ paste_replace(struct paste_stack *ps, u_int idx, char *data) xfree(pb->data); pb->data = data; + pb->size = size; if (gettimeofday(&pb->tv, NULL) != 0) fatal("gettimeofday"); diff --git a/status.c b/status.c index 5e696afb..877ee846 100644 --- a/status.c +++ b/status.c @@ -928,9 +928,10 @@ status_prompt_key(struct client *c, int key) case MODEKEYEDIT_PASTE: if ((pb = paste_get_top(&c->session->buffers)) == NULL) break; - if ((last = strchr(pb->data, '\n')) == NULL) - last = strchr(pb->data, '\0'); - n = last - pb->data; + for (n = 0; n < pb->size; n++) { + if (pb->data[n] < 32 || pb->data[n] == 127) + break; + } c->prompt_buffer = xrealloc(c->prompt_buffer, 1, size + n + 1); if (c->prompt_index == size) { diff --git a/tmux.h b/tmux.h index d2004bdd..4057fe8b 100644 --- a/tmux.h +++ b/tmux.h @@ -772,6 +772,7 @@ struct layout_cell { /* Paste buffer. */ struct paste_buffer { char *data; + size_t size; struct timeval tv; }; ARRAY_DECL(paste_stack, struct paste_buffer *); @@ -1257,8 +1258,8 @@ struct paste_buffer *paste_get_top(struct paste_stack *); struct paste_buffer *paste_get_index(struct paste_stack *, u_int); int paste_free_top(struct paste_stack *); int paste_free_index(struct paste_stack *, u_int); -void paste_add(struct paste_stack *, char *, u_int); -int paste_replace(struct paste_stack *, u_int, char *); +void paste_add(struct paste_stack *, u_char *, size_t, u_int); +int paste_replace(struct paste_stack *, u_int, u_char *, size_t); /* clock.c */ extern const char clock_table[14][5][5]; diff --git a/window-copy.c b/window-copy.c index f102092c..bacd6ad9 100644 --- a/window-copy.c +++ b/window-copy.c @@ -849,13 +849,16 @@ window_copy_copy_selection(struct window_pane *wp, struct client *c) window_copy_copy_line(wp, &buf, &off, ey, 0, ex); } - /* Terminate buffer, overwriting final \n. */ - if (off != 0) - buf[off - 1] = '\0'; + /* Don't bother if no data. */ + if (off == 0) { + xfree(buf); + return; + } + off--; /* remove final \n */ /* Add the buffer to the stack. */ limit = options_get_number(&c->session->options, "buffer-limit"); - paste_add(&c->session->buffers, buf, limit); + paste_add(&c->session->buffers, buf, off, limit); } void From e323f6620d6d64da7c9337fa2e5f8f9f0deb4394 Mon Sep 17 00:00:00 2001 From: Matthias Kilian Date: Mon, 7 Sep 2009 19:08:45 +0000 Subject: [PATCH 0319/1180] Tiny cleanup. ok nicm@ --- server.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server.c b/server.c index 9841816b..09c412d5 100644 --- a/server.c +++ b/server.c @@ -1228,8 +1228,8 @@ server_second_timers(void) /* If locked, redraw all clients. */ if (server_locked) { for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - if (ARRAY_ITEM(&clients, i) != NULL) - server_redraw_client(ARRAY_ITEM(&clients, i)); + if ((c = ARRAY_ITEM(&clients, i)) != NULL) + server_redraw_client(c); } } } From 51c95747d878405bcbe2077c5c27c6b1a87c48a8 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 7 Sep 2009 21:01:50 +0000 Subject: [PATCH 0320/1180] Reference count clients and sessions rather than relying on a saved index for cmd-choose-*. --- cmd-choose-client.c | 19 ++++++++++--------- cmd-choose-session.c | 14 +++++++------- cmd-choose-window.c | 31 +++++++++++++++---------------- cmd-server-info.c | 12 +++++++----- server.c | 44 +++++++++++++++++++++++++++++++++++++++++++- session.c | 17 ++++++++++++++++- tmux.h | 8 ++++++++ 7 files changed, 106 insertions(+), 39 deletions(-) diff --git a/cmd-choose-client.c b/cmd-choose-client.c index dd09fe51..0aa66622 100644 --- a/cmd-choose-client.c +++ b/cmd-choose-client.c @@ -43,7 +43,7 @@ const struct cmd_entry cmd_choose_client_entry = { }; struct cmd_choose_client_data { - u_int client; + struct client *client; char *template; }; @@ -87,7 +87,8 @@ cmd_choose_client_exec(struct cmd *self, struct cmd_ctx *ctx) cdata->template = xstrdup(data->arg); else cdata->template = xstrdup("detach-client -t '%%'"); - cdata->client = server_client_index(ctx->curclient); + cdata->client = ctx->curclient; + cdata->client->references++; window_choose_ready(wl->window->active, cur, cmd_choose_client_callback, cmd_choose_client_free, cdata); @@ -99,23 +100,22 @@ void cmd_choose_client_callback(void *data, int idx) { struct cmd_choose_client_data *cdata = data; - struct client *c, *c2; + struct client *c; struct cmd_list *cmdlist; struct cmd_ctx ctx; char *template, *cause; if (idx == -1) return; - if (cdata->client > ARRAY_LENGTH(&clients) - 1) + if (cdata->client->flags & CLIENT_DEAD) return; - c = ARRAY_ITEM(&clients, cdata->client); if ((u_int) idx > ARRAY_LENGTH(&clients) - 1) return; - c2 = ARRAY_ITEM(&clients, idx); - if (c2 == NULL || c2->session == NULL) + c = ARRAY_ITEM(&clients, idx); + if (c == NULL || c->session == NULL) return; - template = cmd_template_replace(cdata->template, c2->tty.path, 1); + template = cmd_template_replace(cdata->template, c->tty.path, 1); if (cmd_string_parse(template, &cmdlist, &cause) != 0) { if (cause != NULL) { @@ -129,7 +129,7 @@ cmd_choose_client_callback(void *data, int idx) xfree(template); ctx.msgdata = NULL; - ctx.curclient = c; + ctx.curclient = cdata->client; ctx.error = key_bindings_error; ctx.print = key_bindings_print; @@ -146,6 +146,7 @@ cmd_choose_client_free(void *data) { struct cmd_choose_client_data *cdata = data; + cdata->client->references--; xfree(cdata->template); xfree(cdata); } diff --git a/cmd-choose-session.c b/cmd-choose-session.c index 87b3437b..7bc34853 100644 --- a/cmd-choose-session.c +++ b/cmd-choose-session.c @@ -43,7 +43,7 @@ const struct cmd_entry cmd_choose_session_entry = { }; struct cmd_choose_session_data { - u_int client; + struct client *client; char *template; }; @@ -87,7 +87,8 @@ cmd_choose_session_exec(struct cmd *self, struct cmd_ctx *ctx) cdata->template = xstrdup(data->arg); else cdata->template = xstrdup("switch-client -t '%%'"); - cdata->client = server_client_index(ctx->curclient); + cdata->client = ctx->curclient; + cdata->client->references++; window_choose_ready(wl->window->active, cur, cmd_choose_session_callback, cmd_choose_session_free, cdata); @@ -99,7 +100,6 @@ void cmd_choose_session_callback(void *data, int idx) { struct cmd_choose_session_data *cdata = data; - struct client *c; struct session *s; struct cmd_list *cmdlist; struct cmd_ctx ctx; @@ -107,9 +107,8 @@ cmd_choose_session_callback(void *data, int idx) if (idx == -1) return; - if (cdata->client > ARRAY_LENGTH(&clients) - 1) + if (cdata->client->flags & CLIENT_DEAD) return; - c = ARRAY_ITEM(&clients, cdata->client); if ((u_int) idx > ARRAY_LENGTH(&sessions) - 1) return; @@ -121,7 +120,7 @@ cmd_choose_session_callback(void *data, int idx) if (cmd_string_parse(template, &cmdlist, &cause) != 0) { if (cause != NULL) { *cause = toupper((u_char) *cause); - status_message_set(c, "%s", cause); + status_message_set(cdata->client, "%s", cause); xfree(cause); } xfree(template); @@ -130,7 +129,7 @@ cmd_choose_session_callback(void *data, int idx) xfree(template); ctx.msgdata = NULL; - ctx.curclient = c; + ctx.curclient = cdata->client; ctx.error = key_bindings_error; ctx.print = key_bindings_print; @@ -147,6 +146,7 @@ cmd_choose_session_free(void *data) { struct cmd_choose_session_data *cdata = data; + cdata->client->references--; xfree(cdata->template); xfree(cdata); } diff --git a/cmd-choose-window.c b/cmd-choose-window.c index ddc8ecb6..43a24585 100644 --- a/cmd-choose-window.c +++ b/cmd-choose-window.c @@ -43,8 +43,8 @@ const struct cmd_entry cmd_choose_window_entry = { }; struct cmd_choose_window_data { - u_int client; - u_int session; + struct client *client; + struct session *session; char *template; }; @@ -107,13 +107,14 @@ cmd_choose_window_exec(struct cmd *self, struct cmd_ctx *ctx) } cdata = xmalloc(sizeof *cdata); - if (session_index(s, &cdata->session) != 0) - fatalx("session not found"); if (data->arg != NULL) cdata->template = xstrdup(data->arg); else cdata->template = xstrdup("select-window -t '%%'"); - cdata->client = server_client_index(ctx->curclient); + cdata->session = s; + cdata->session->references++; + cdata->client = ctx->curclient; + cdata->client->references++; window_choose_ready(wl->window->active, cur, cmd_choose_window_callback, cmd_choose_window_free, cdata); @@ -125,31 +126,27 @@ void cmd_choose_window_callback(void *data, int idx) { struct cmd_choose_window_data *cdata = data; - struct client *c; - struct session *s; struct cmd_list *cmdlist; struct cmd_ctx ctx; char *target, *template, *cause; if (idx == -1) return; - if (cdata->client > ARRAY_LENGTH(&clients) - 1) + if (cdata->client->flags & CLIENT_DEAD) + return; + if (cdata->session->flags & SESSION_DEAD) return; - c = ARRAY_ITEM(&clients, cdata->client); - if (cdata->session > ARRAY_LENGTH(&sessions) - 1) - return; - s = ARRAY_ITEM(&sessions, cdata->session); - if (c->session != s) + if (cdata->client->session != cdata->session) return; - xasprintf(&target, "%s:%d", s->name, idx); + xasprintf(&target, "%s:%d", cdata->session->name, idx); template = cmd_template_replace(cdata->template, target, 1); xfree(target); if (cmd_string_parse(template, &cmdlist, &cause) != 0) { if (cause != NULL) { *cause = toupper((u_char) *cause); - status_message_set(c, "%s", cause); + status_message_set(cdata->client, "%s", cause); xfree(cause); } xfree(template); @@ -158,7 +155,7 @@ cmd_choose_window_callback(void *data, int idx) xfree(template); ctx.msgdata = NULL; - ctx.curclient = c; + ctx.curclient = cdata->client; ctx.error = key_bindings_error; ctx.print = key_bindings_print; @@ -175,6 +172,8 @@ cmd_choose_window_free(void *data) { struct cmd_choose_window_data *cdata = data; + cdata->session->references--; + cdata->client->references--; xfree(cdata->template); xfree(cdata); } diff --git a/cmd-server-info.c b/cmd-server-info.c index 14212478..48ea3707 100644 --- a/cmd-server-info.c +++ b/cmd-server-info.c @@ -91,9 +91,10 @@ cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx) continue; ctx->print(ctx, "%2d: %s (%d, %d): %s [%ux%u %s] " - "[flags=0x%x/0x%x]", i, c->tty.path, c->ibuf.fd, c->tty.fd, - c->session->name, c->tty.sx, c->tty.sy, c->tty.termname, - c->flags, c->tty.flags); + "[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->flags, + c->tty.flags, c->references); } ctx->print(ctx, "%s", ""); @@ -109,8 +110,9 @@ cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx) *strchr(tim, '\n') = '\0'; ctx->print(ctx, "%2u: %s: %u windows (created %s) [%ux%u] " - "[flags=0x%x]", i, s->name, winlink_count(&s->windows), - tim, s->sx, s->sy, s->flags); + "[flags=0x%x, references=%u]", i, s->name, + winlink_count(&s->windows), tim, s->sx, s->sy, s->flags, + s->references); RB_FOREACH(wl, winlinks, &s->windows) { w = wl->window; ctx->print(ctx, "%4u: %s [%ux%u] [flags=0x%x, " diff --git a/server.c b/server.c index 09c412d5..c8b96368 100644 --- a/server.c +++ b/server.c @@ -43,6 +43,7 @@ /* Client list. */ struct clients clients; +struct clients dead_clients; void server_create_client(int); int server_create_socket(void); @@ -61,6 +62,7 @@ int server_check_window_activity(struct session *, struct window *); int server_check_window_content(struct session *, struct window *, struct window_pane *); +void server_clean_dead(void); void server_lost_client(struct client *); void server_check_window(struct window *); void server_check_redraw(struct client *); @@ -85,6 +87,7 @@ server_create_client(int fd) fatal("fcntl failed"); c = xcalloc(1, sizeof *c); + c->references = 0; imsg_init(&c->ibuf, fd); ARRAY_INIT(&c->prompt_hdata); @@ -162,7 +165,9 @@ server_start(char *path) ARRAY_INIT(&windows); ARRAY_INIT(&clients); + ARRAY_INIT(&dead_clients); ARRAY_INIT(&sessions); + ARRAY_INIT(&dead_sessions); mode_key_init_trees(); key_bindings_init(); utf8_build(); @@ -344,6 +349,9 @@ server_main(int srv_fd) /* Collect any unset key bindings. */ key_bindings_clean(); + + /* Collect dead clients and sessions. */ + server_clean_dead(); /* * If we have no sessions and clients left, let's get out @@ -948,11 +956,45 @@ server_lost_client(struct client *c) close(c->ibuf.fd); imsg_clear(&c->ibuf); - xfree(c); + + for (i = 0; i < ARRAY_LENGTH(&dead_clients); i++) { + if (ARRAY_ITEM(&dead_clients, i) == NULL) { + ARRAY_SET(&dead_clients, i, c); + break; + } + } + if (i == ARRAY_LENGTH(&dead_clients)) + ARRAY_ADD(&dead_clients, c); + c->flags |= CLIENT_DEAD; recalculate_sizes(); } +/* Free dead, unreferenced clients and sessions. */ +void +server_clean_dead(void) +{ + struct session *s; + struct client *c; + u_int i; + + for (i = 0; i < ARRAY_LENGTH(&dead_sessions); i++) { + s = ARRAY_ITEM(&dead_sessions, i); + if (s == NULL || s->references != 0) + continue; + ARRAY_SET(&dead_sessions, i, NULL); + xfree(s); + } + + for (i = 0; i < ARRAY_LENGTH(&dead_clients); i++) { + c = ARRAY_ITEM(&dead_clients, i); + if (c == NULL || c->references != 0) + continue; + ARRAY_SET(&dead_clients, i, NULL); + xfree(c); + } +} + /* Handle window data. */ void server_handle_window(struct window *w, struct window_pane *wp) diff --git a/session.c b/session.c index 55d38c80..4e5ac83e 100644 --- a/session.c +++ b/session.c @@ -28,6 +28,7 @@ /* Global session list. */ struct sessions sessions; +struct sessions dead_sessions; struct winlink *session_next_activity(struct session *, struct winlink *); struct winlink *session_previous_activity(struct session *, struct winlink *); @@ -121,14 +122,19 @@ session_create(const char *name, const char *cmd, const char *cwd, u_int i; s = xmalloc(sizeof *s); + s->references = 0; s->flags = 0; + if (gettimeofday(&s->tv, NULL) != 0) fatal("gettimeofday"); + s->curw = NULL; SLIST_INIT(&s->lastw); RB_INIT(&s->windows); SLIST_INIT(&s->alerts); + paste_init_stack(&s->buffers); + options_init(&s->options, &global_s_options); environ_init(&s->environ); if (env != NULL) @@ -187,7 +193,16 @@ session_destroy(struct session *s) winlink_remove(&s->windows, RB_ROOT(&s->windows)); xfree(s->name); - xfree(s); + + for (i = 0; i < ARRAY_LENGTH(&dead_sessions); i++) { + if (ARRAY_ITEM(&dead_sessions, i) == NULL) { + ARRAY_SET(&dead_sessions, i, s); + break; + } + } + if (i == ARRAY_LENGTH(&dead_sessions)) + ARRAY_ADD(&dead_sessions, s); + s->flags |= SESSION_DEAD; } /* Find session index. */ diff --git a/tmux.h b/tmux.h index 4057fe8b..7b725b00 100644 --- a/tmux.h +++ b/tmux.h @@ -812,11 +812,14 @@ struct session { SLIST_HEAD(, session_alert) alerts; #define SESSION_UNATTACHED 0x1 /* not attached to any clients */ +#define SESSION_DEAD 0x2 int flags; struct termios tio; struct environ environ; + + int references; }; ARRAY_DECL(sessions, struct session *); @@ -939,6 +942,7 @@ struct client { #define CLIENT_SUSPENDED 0x40 #define CLIENT_BAD 0x80 #define CLIENT_IDENTIFY 0x100 +#define CLIENT_DEAD 0x200 int flags; struct timeval identify_timer; @@ -963,6 +967,8 @@ struct client { struct mode_key_data prompt_mdata; struct session *session; + + int references; }; ARRAY_DECL(clients, struct client *); @@ -1428,6 +1434,7 @@ const char *key_string_lookup_key(int); /* server.c */ extern struct clients clients; +extern struct clients dead_clients; int server_client_index(struct client *); int server_start(char *); @@ -1702,6 +1709,7 @@ char *default_window_name(struct window *); /* session.c */ extern struct sessions sessions; +extern struct sessions dead_sessions; void session_alert_add(struct session *, struct window *, int); void session_alert_cancel(struct session *, struct winlink *); int session_alert_has(struct session *, struct winlink *, int); From 3f3b01c7ce503d98ab649fa4aecde741ce63cec0 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 7 Sep 2009 21:12:12 +0000 Subject: [PATCH 0321/1180] While the display-panes indicator is on screen, make the number keys select the pane with that index. --- server.c | 13 ++++++++++++- tmux.1 | 5 +++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/server.c b/server.c index c8b96368..a4ef2008 100644 --- a/server.c +++ b/server.c @@ -795,6 +795,7 @@ server_accept_client(int srv_fd) void server_handle_client(struct client *c) { + struct window *w; struct window_pane *wp; struct screen *s; struct timeval tv; @@ -818,8 +819,18 @@ server_handle_client(struct client *c) if (c->session == NULL) return; - wp = c->session->curw->window->active; /* could die */ + w = c->session->curw->window; + wp = w->active; /* could die */ + /* Special case: number keys jump to pane in identify mode. */ + if (c->flags & CLIENT_IDENTIFY && key >= '0' && key <= '9') { + wp = window_pane_at_index(w, key - '0'); + if (wp != NULL && window_pane_visible(wp)) + window_set_active_pane(w, wp); + server_clear_identify(c); + continue; + } + status_message_clear(c); server_clear_identify(c); if (c->prompt_string != NULL) { diff --git a/tmux.1 b/tmux.1 index 757005d9..c630c179 100644 --- a/tmux.1 +++ b/tmux.1 @@ -689,6 +689,11 @@ See the and .Ic display-panes-colour session options. +While the indicator is on screen, a pane may be selected with the +.Ql 0 +to +.Ql 9 +keys. .It Ic down-pane Op Fl t Ar target-pane .D1 (alias: Ic downp ) Move down a pane. From 372a8cb1d9c4306f74b592660b4ce394dff3e31d Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 10 Sep 2009 17:16:24 +0000 Subject: [PATCH 0322/1180] Permit options such as status-bg to be configured using the entire 256 colour palette by setting "colour0" to "colour255". --- clock.c | 4 ++-- colour.c | 43 +++++++++++++++++++++++++++++++++++++++++-- screen-redraw.c | 11 +++++------ screen-write.c | 27 ++++++++++++++++++++------- server.c | 2 +- status.c | 45 +++++++++++++++++++++++---------------------- tmux.1 | 7 +++++-- tmux.h | 4 +++- tty.c | 3 ++- window-choose.c | 7 ++++--- window-copy.c | 14 ++++++++------ window-more.c | 7 ++++--- window-scroll.c | 7 ++++--- 13 files changed, 122 insertions(+), 59 deletions(-) diff --git a/clock.c b/clock.c index 4cd8a8a7..5711b441 100644 --- a/clock.c +++ b/clock.c @@ -120,7 +120,7 @@ clock_draw(struct screen_write_ctx *ctx, u_int colour, int style) screen_write_cursormove(ctx, x, y); memcpy(&gc, &grid_default_cell, sizeof gc); - gc.fg = colour; + colour_set_fg(&gc, colour); screen_write_puts(ctx, &gc, "%s", tim); } return; @@ -130,7 +130,7 @@ clock_draw(struct screen_write_ctx *ctx, u_int colour, int style) y = (screen_size_y(s) / 2) - 3; memcpy(&gc, &grid_default_cell, sizeof gc); - gc.bg = colour; + colour_set_bg(&gc, colour); for (ptr = tim; *ptr != '\0'; ptr++) { if (*ptr >= '0' && *ptr <= '9') idx = *ptr - '0'; diff --git a/colour.c b/colour.c index 2067d0dd..5e31f815 100644 --- a/colour.c +++ b/colour.c @@ -18,13 +18,42 @@ #include +#include #include #include "tmux.h" -const char * -colour_tostring(u_char c) +/* + * Colour to string conversion functions. Bit 8 of the colour means it is one + * of the 256 colour palette. + */ + +void +colour_set_fg(struct grid_cell *gc, int c) { + if (c & 0x100) + gc->flags |= GRID_FLAG_FG256; + gc->fg = c; +} + +void +colour_set_bg(struct grid_cell *gc, int c) +{ + if (c & 0x100) + gc->flags |= GRID_FLAG_BG256; + gc->bg = c; +} + +const char * +colour_tostring(int c) +{ + static char s[32]; + + if (c & 0x100) { + xsnprintf(s, sizeof s, "colour%u", c & ~0x100); + return (s); + } + switch (c) { case 0: return ("black"); @@ -51,6 +80,16 @@ colour_tostring(u_char c) int colour_fromstring(const char *s) { + const char *errstr; + int n; + + if (strncasecmp(s, "colour", (sizeof "colour") - 1) == 0) { + n = strtonum(s + (sizeof "colour") - 1, 0, 255, &errstr); + if (errstr != NULL) + return (-1); + return (n | 0x100); + } + if (strcasecmp(s, "black") == 0 || (s[0] == '0' && s[1] == '\0')) return (0); if (strcasecmp(s, "red") == 0 || (s[0] == '1' && s[1] == '\0')) diff --git a/screen-redraw.c b/screen-redraw.c index ce26c47d..d22591f0 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -240,7 +240,7 @@ screen_redraw_draw_number(struct client *c, struct window_pane *wp) struct session *s = c->session; struct grid_cell gc; u_int idx, px, py, i, j; - u_char colour; + int colour; char buf[16], *ptr; size_t len; @@ -256,7 +256,7 @@ screen_redraw_draw_number(struct client *c, struct window_pane *wp) if (wp->sx < len * 6 || wp->sy < 5) { tty_cursor(tty, px - len / 2, py, wp->xoff, wp->yoff); memcpy(&gc, &grid_default_cell, sizeof gc); - gc.fg = colour; + colour_set_fg(&gc, colour); tty_attributes(tty, &gc); tty_puts(tty, buf); return; @@ -266,7 +266,7 @@ screen_redraw_draw_number(struct client *c, struct window_pane *wp) py -= 2; memcpy(&gc, &grid_default_cell, sizeof gc); - gc.bg = colour; + colour_set_bg(&gc, colour); tty_attributes(tty, &gc); for (ptr = buf; *ptr != '\0'; ptr++) { if (*ptr < '0' || *ptr > '9') @@ -276,9 +276,8 @@ screen_redraw_draw_number(struct client *c, struct window_pane *wp) for (j = 0; j < 5; j++) { for (i = px; i < px + 5; i++) { tty_cursor(tty, i, py + j, wp->xoff, wp->yoff); - if (!clock_table[idx][j][i - px]) - continue; - tty_putc(tty, ' '); + if (clock_table[idx][j][i - px]) + tty_putc(tty, ' '); } } px += 6; diff --git a/screen-write.c b/screen-write.c index 62acadd2..dba5f708 100644 --- a/screen-write.c +++ b/screen-write.c @@ -300,7 +300,7 @@ screen_write_parsestyle( char tmp[32]; int val; size_t end; - u_char fg, bg, attr; + u_char fg, bg, attr, flags; if (*in == '\0') return; @@ -309,7 +309,8 @@ screen_write_parsestyle( fg = gc->fg; bg = gc->bg; - attr = 0; + attr = gc->attr; + flags = gc->flags; do { end = strcspn(in, delimiters); if (end > (sizeof tmp) - 1) @@ -325,14 +326,24 @@ screen_write_parsestyle( if ((val = colour_fromstring(tmp + 3)) == -1) return; if (*in == 'f' || *in == 'F') { - if (val != 8) + if (val != 8) { + if (val & 0x100) { + flags |= GRID_FLAG_FG256; + val &= ~0x100; + } else + flags &= ~GRID_FLAG_FG256; fg = val; - else + } else fg = defgc->fg; } else if (*in == 'b' || *in == 'B') { - if (val != 8) + if (val != 8) { + if (val & 0x100) { + flags |= GRID_FLAG_BG256; + val &= ~0x100; + } else + flags &= ~GRID_FLAG_BG256; bg = val; - else + } else bg = defgc->bg; } else return; @@ -347,6 +358,7 @@ screen_write_parsestyle( gc->fg = fg; gc->bg = bg; gc->attr = attr; + gc->flags = flags; } /* Copy from another screen. */ @@ -1002,7 +1014,8 @@ screen_write_cell( if (screen_check_selection(s, s->cx - width, s->cy)) { memcpy(&tmp_gc2, &s->sel.cell, sizeof tmp_gc2); tmp_gc2.data = gc->data; - tmp_gc2.flags = gc->flags; + tmp_gc2.flags = gc->flags & ~(GRID_FLAG_FG256|GRID_FLAG_BG256); + tmp_gc2.flags |= s->sel.cell.flags & (GRID_FLAG_FG256|GRID_FLAG_BG256); ttyctx.cell = &tmp_gc2; tty_write(tty_cmd_cell, &ttyctx); } else { diff --git a/server.c b/server.c index a4ef2008..ce2d984a 100644 --- a/server.c +++ b/server.c @@ -601,7 +601,7 @@ server_redraw_locked(struct client *c) style = options_get_number(&global_w_options, "clock-mode-style"); memcpy(&gc, &grid_default_cell, sizeof gc); - gc.fg = colour; + colour_set_fg(&gc, colour); gc.attr |= GRID_ATTR_BRIGHT; screen_init(&screen, xx, yy, 0); diff --git a/status.c b/status.c index 877ee846..7e25f235 100644 --- a/status.c +++ b/status.c @@ -66,8 +66,8 @@ status_redraw(struct client *c) if (gettimeofday(&c->status_timer, NULL) != 0) fatal("gettimeofday"); memcpy(&stdgc, &grid_default_cell, sizeof gc); - stdgc.fg = options_get_number(&s->options, "status-fg"); - stdgc.bg = options_get_number(&s->options, "status-bg"); + 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"); /* @@ -79,19 +79,19 @@ status_redraw(struct client *c) memcpy(&sr_stdgc, &stdgc, sizeof sr_stdgc); sl_fg = options_get_number(&s->options, "status-left-fg"); if (sl_fg != 8) - sl_stdgc.fg = sl_fg; + colour_set_fg(&sl_stdgc, sl_fg); sl_bg = options_get_number(&s->options, "status-left-bg"); if (sl_bg != 8) - sl_stdgc.bg = sl_bg; + colour_set_bg(&sl_stdgc, sl_bg); sl_attr = options_get_number(&s->options, "status-left-attr"); if (sl_attr != 0) sl_stdgc.attr = sl_attr; sr_fg = options_get_number(&s->options, "status-right-fg"); if (sr_fg != 8) - sr_stdgc.fg = sr_fg; + colour_set_fg(&sr_stdgc, sr_fg); sr_bg = options_get_number(&s->options, "status-right-bg"); if (sr_bg != 8) - sr_stdgc.bg = sr_bg; + colour_set_bg(&sr_stdgc, sr_bg); sr_attr = options_get_number(&s->options, "status-right-attr"); if (sr_attr != 0) sr_stdgc.attr = sr_attr; @@ -501,16 +501,17 @@ status_width(struct winlink *wl) char * status_print(struct session *s, struct winlink *wl, struct grid_cell *gc) { - char *text, flag; - u_char fg, bg, attr; + struct options *oo = &wl->window->options; + char *text, flag; + u_char fg, bg, attr; - fg = options_get_number(&wl->window->options, "window-status-fg"); + fg = options_get_number(oo, "window-status-fg"); if (fg != 8) - gc->fg = fg; - bg = options_get_number(&wl->window->options, "window-status-bg"); + colour_set_fg(gc, fg); + bg = options_get_number(oo, "window-status-bg"); if (bg != 8) - gc->bg = bg; - attr = options_get_number(&wl->window->options, "window-status-attr"); + colour_set_bg(gc, bg); + attr = options_get_number(oo, "window-status-attr"); if (attr != 0) gc->attr = attr; @@ -518,13 +519,13 @@ status_print(struct session *s, struct winlink *wl, struct grid_cell *gc) if (wl == SLIST_FIRST(&s->lastw)) flag = '-'; if (wl == s->curw) { - fg = options_get_number(&wl->window->options, "window-status-current-fg"); + fg = options_get_number(oo, "window-status-current-fg"); if (fg != 8) - gc->fg = fg; - bg = options_get_number(&wl->window->options, "window-status-current-bg"); + colour_set_fg(gc, fg); + bg = options_get_number(oo, "window-status-current-bg"); if (bg != 8) - gc->bg = bg; - attr = options_get_number(&wl->window->options, "window-status-current-attr"); + colour_set_bg(gc, bg); + attr = options_get_number(oo, "window-status-current-attr"); if (attr != 0) gc->attr = attr; flag = '*'; @@ -606,8 +607,8 @@ status_message_redraw(struct client *c) len = c->tty.sx; memcpy(&gc, &grid_default_cell, sizeof gc); - gc.fg = options_get_number(&s->options, "message-fg"); - gc.bg = options_get_number(&s->options, "message-bg"); + 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"); screen_write_start(&ctx, NULL, &c->status); @@ -719,8 +720,8 @@ status_prompt_redraw(struct client *c) len = c->tty.sx; memcpy(&gc, &grid_default_cell, sizeof gc); - gc.fg = options_get_number(&s->options, "message-fg"); - gc.bg = options_get_number(&s->options, "message-bg"); + 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"); screen_write_start(&ctx, NULL, &c->status); diff --git a/tmux.1 b/tmux.1 index c630c179..fb733bd5 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1250,8 +1250,11 @@ is one of: .Ic blue , .Ic magenta , .Ic cyan , -.Ic white -or +.Ic white , +.Ic colour0 +to +.Ic colour255 +from the 256-colour palette, or .Ic default . .It Ic message-fg Ar colour Set status line message foreground colour. diff --git a/tmux.h b/tmux.h index 7b725b00..a1b7fea2 100644 --- a/tmux.h +++ b/tmux.h @@ -1486,7 +1486,9 @@ void input_key(struct window_pane *, int); void input_mouse(struct window_pane *, u_char, u_char, u_char); /* colour.c */ -const char *colour_tostring(u_char); +void colour_set_fg(struct grid_cell *, int); +void colour_set_bg(struct grid_cell *, int); +const char *colour_tostring(int); int colour_fromstring(const char *); u_char colour_256to16(u_char); u_char colour_256to88(u_char); diff --git a/tty.c b/tty.c index de6b4d0b..3d2d17d3 100644 --- a/tty.c +++ b/tty.c @@ -512,7 +512,8 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int py, u_int ox, u_int oy) if (screen_check_selection(s, i, py)) { memcpy(&tmpgc, &s->sel.cell, sizeof tmpgc); tmpgc.data = gc->data; - tmpgc.flags = gc->flags; + tmpgc.flags = gc->flags & ~(GRID_FLAG_FG256|GRID_FLAG_BG256); + tmpgc.flags |= s->sel.cell.flags & (GRID_FLAG_FG256|GRID_FLAG_BG256); tty_cell(tty, &tmpgc, gu); } else tty_cell(tty, gc, gu); diff --git a/window-choose.c b/window-choose.c index 4ef003df..acb6ab8a 100644 --- a/window-choose.c +++ b/window-choose.c @@ -295,6 +295,7 @@ window_choose_write_line( { struct window_choose_mode_data *data = wp->modedata; struct window_choose_mode_item *item; + struct options *oo = &wp->window->options; struct screen *s = &data->screen; struct grid_cell gc; int utf8flag; @@ -305,9 +306,9 @@ 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) { - gc.fg = options_get_number(&wp->window->options, "mode-fg"); - gc.bg = options_get_number(&wp->window->options, "mode-bg"); - gc.attr |= options_get_number(&wp->window->options, "mode-attr"); + 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"); } screen_write_cursormove(ctx, 0, py); diff --git a/window-copy.c b/window-copy.c index bacd6ad9..053a6a49 100644 --- a/window-copy.c +++ b/window-copy.c @@ -660,14 +660,15 @@ window_copy_write_line( { struct window_copy_mode_data *data = wp->modedata; 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; memcpy(&gc, &grid_default_cell, sizeof gc); - gc.fg = options_get_number(&wp->window->options, "mode-fg"); - gc.bg = options_get_number(&wp->window->options, "mode-bg"); - gc.attr |= options_get_number(&wp->window->options, "mode-attr"); + 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"); last = screen_size_y(s) - 1; if (py == 0) { @@ -765,6 +766,7 @@ window_copy_update_selection(struct window_pane *wp) { struct window_copy_mode_data *data = wp->modedata; struct screen *s = &data->screen; + struct options *oo = &wp->window->options; struct grid_cell gc; u_int sx, sy, ty; @@ -773,9 +775,9 @@ window_copy_update_selection(struct window_pane *wp) /* Set colours. */ memcpy(&gc, &grid_default_cell, sizeof gc); - gc.fg = options_get_number(&wp->window->options, "mode-fg"); - gc.bg = options_get_number(&wp->window->options, "mode-bg"); - gc.attr |= options_get_number(&wp->window->options, "mode-attr"); + 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"); /* Find top of screen. */ ty = screen_hsize(&wp->base) - data->oy; diff --git a/window-more.c b/window-more.c index 1ac453cc..94a08f1e 100644 --- a/window-more.c +++ b/window-more.c @@ -164,6 +164,7 @@ window_more_write_line( { struct window_more_mode_data *data = wp->modedata; struct screen *s = &data->screen; + struct options *oo = &wp->window->options; struct grid_cell gc; char *msg, hdr[32]; size_t size; @@ -176,9 +177,9 @@ window_more_write_line( size = xsnprintf(hdr, sizeof hdr, "[%u/%u]", data->top, ARRAY_LENGTH(&data->list)); screen_write_cursormove(ctx, screen_size_x(s) - size, 0); - gc.fg = options_get_number(&wp->window->options, "mode-fg"); - gc.bg = options_get_number(&wp->window->options, "mode-bg"); - gc.attr |= options_get_number(&wp->window->options, "mode-attr"); + 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"); screen_write_puts(ctx, &gc, "%s", hdr); memcpy(&gc, &grid_default_cell, sizeof gc); } else diff --git a/window-scroll.c b/window-scroll.c index 711976bb..fa6a5847 100644 --- a/window-scroll.c +++ b/window-scroll.c @@ -192,6 +192,7 @@ window_scroll_write_line( { struct window_scroll_mode_data *data = wp->modedata; struct screen *s = &data->screen; + struct options *oo = &wp->window->options; struct grid_cell gc; char hdr[32]; size_t size; @@ -200,9 +201,9 @@ window_scroll_write_line( memcpy(&gc, &grid_default_cell, sizeof gc); size = xsnprintf(hdr, sizeof hdr, "[%u,%u/%u]", data->ox, data->oy, screen_hsize(&wp->base)); - gc.fg = options_get_number(&wp->window->options, "mode-fg"); - gc.bg = options_get_number(&wp->window->options, "mode-bg"); - gc.attr |= options_get_number(&wp->window->options, "mode-attr"); + 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"); screen_write_cursormove(ctx, screen_size_x(s) - size, 0); screen_write_puts(ctx, &gc, "%s", hdr); memcpy(&gc, &grid_default_cell, sizeof gc); From d771614d33da54c2028a690079a64c0edb2949fc Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 12 Sep 2009 09:54:34 +0000 Subject: [PATCH 0323/1180] tmux always outputs \177 for backspace, so explicitly set VERASE to \177 for new windows. --- cmd-new-session.c | 1 + 1 file changed, 1 insertion(+) diff --git a/cmd-new-session.c b/cmd-new-session.c index 8cf30bc3..a05a4846 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -164,6 +164,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) fatal("tcgetattr failed"); } else memcpy(tio.c_cc, ttydefchars, sizeof tio.c_cc); + tio.c_cc[VERASE] = '\177'; tio.c_iflag = TTYDEF_IFLAG; tio.c_oflag = TTYDEF_OFLAG; tio.c_lflag = TTYDEF_LFLAG; From 8cb8a0da8d061293e9e4b52d99473ff574abf727 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 12 Sep 2009 13:01:19 +0000 Subject: [PATCH 0324/1180] Tidy some common code for destroying sessions into a new function. --- server-fn.c | 36 ++++++++++++++++++++---------------- server.c | 18 ++++-------------- tmux.h | 1 + 3 files changed, 25 insertions(+), 30 deletions(-) diff --git a/server-fn.c b/server-fn.c index d3cdbd60..d39108dd 100644 --- a/server-fn.c +++ b/server-fn.c @@ -272,10 +272,7 @@ server_kill_window(struct window *w) { struct session *s; struct winlink *wl; - struct client *c; - u_int i, j; - int destroyed; - + u_int i; for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { s = ARRAY_ITEM(&sessions, i); @@ -284,22 +281,29 @@ server_kill_window(struct window *w) if ((wl = winlink_find_by_window(&s->windows, w)) == NULL) continue; - destroyed = session_detach(s, wl); - for (j = 0; j < ARRAY_LENGTH(&clients); j++) { - c = ARRAY_ITEM(&clients, j); - if (c == NULL || c->session != s) - continue; - - if (destroyed) { - c->session = NULL; - server_write_client(c, MSG_EXIT, NULL, 0); - } else - server_redraw_client(c); - } + if (session_detach(s, wl)) + server_destroy_session(s); + else + server_redraw_session(s); } recalculate_sizes(); } +void +server_destroy_session(struct session *s) +{ + struct client *c; + u_int i; + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c == NULL || c->session != s) + continue; + c->session = NULL; + server_write_client(c, MSG_EXIT, NULL, 0); + } +} + void server_set_identify(struct client *c) { diff --git a/server.c b/server.c index ce2d984a..09ce8b36 100644 --- a/server.c +++ b/server.c @@ -1211,21 +1211,11 @@ server_check_window(struct window *w) RB_FOREACH(wl, winlinks, &s->windows) { if (wl->window != w) continue; - destroyed = session_detach(s, wl); - for (j = 0; j < ARRAY_LENGTH(&clients); j++) { - c = ARRAY_ITEM(&clients, j); - if (c == NULL || c->session != s) - continue; - if (!destroyed) { - server_redraw_client(c); - continue; - } - c->session = NULL; - server_write_client(c, MSG_EXIT, NULL, 0); - } - /* If the session was destroyed, bail now. */ - if (destroyed) + if (session_detach(s, wl)) { + server_destroy_session(s); break; + } + server_redraw_session(s); goto restart; } } diff --git a/tmux.h b/tmux.h index a1b7fea2..ed7242c5 100644 --- a/tmux.h +++ b/tmux.h @@ -1457,6 +1457,7 @@ void server_status_window(struct window *); void server_lock(void); int server_unlock(const char *); void server_kill_window(struct window *); +void server_destroy_session(struct session *); void server_set_identify(struct client *); void server_clear_identify(struct client *); From 8a873b97a31d97189a092ad68581fa872bc4f9ee Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 12 Sep 2009 13:09:43 +0000 Subject: [PATCH 0325/1180] Doh, trim variables unused now. --- server.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/server.c b/server.c index 09ce8b36..504269ea 100644 --- a/server.c +++ b/server.c @@ -1170,10 +1170,9 @@ server_check_window(struct window *w) { struct window_pane *wp, *wq; struct options *oo = &w->options; - struct client *c; struct session *s; struct winlink *wl; - u_int i, j; + u_int i; int destroyed; destroyed = 1; From 85486246761d1af0f0f13a20606077f11fa2d799 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 14 Sep 2009 11:25:35 +0000 Subject: [PATCH 0326/1180] Nuke unused server_client_index function, pointed out by martynas@. --- server.c | 13 ------------- tmux.h | 1 - 2 files changed, 14 deletions(-) diff --git a/server.c b/server.c index 504269ea..4afab67d 100644 --- a/server.c +++ b/server.c @@ -116,19 +116,6 @@ server_create_client(int fd) log_debug("new client %d", fd); } -/* Find client index. */ -int -server_client_index(struct client *c) -{ - u_int i; - - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - if (c == ARRAY_ITEM(&clients, i)) - return (i); - } - return (-1); -} - /* Fork new server. */ int server_start(char *path) diff --git a/tmux.h b/tmux.h index ed7242c5..63f75577 100644 --- a/tmux.h +++ b/tmux.h @@ -1435,7 +1435,6 @@ const char *key_string_lookup_key(int); /* server.c */ extern struct clients clients; extern struct clients dead_clients; -int server_client_index(struct client *); int server_start(char *); /* server-msg.c */ From f39865e8e4aa1a8918c64cfc40fb0acc644861a4 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 15 Sep 2009 07:45:16 +0000 Subject: [PATCH 0327/1180] The default terminal size should be 80x24, not 80x25. --- cmd-new-session.c | 2 +- server-msg.c | 4 ++-- server.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cmd-new-session.c b/cmd-new-session.c index a05a4846..df1ec45c 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -197,7 +197,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) /* Find new session size. */ if (detached) { sx = 80; - sy = 25; + sy = 24; } else if (ctx->cmdclient != NULL) { sx = ctx->cmdclient->tty.sx; sy = ctx->cmdclient->tty.sy; diff --git a/server-msg.c b/server-msg.c index 8c50339d..cb5dbf06 100644 --- a/server-msg.c +++ b/server-msg.c @@ -248,7 +248,7 @@ server_msg_identify(struct client *c, struct msg_identify_data *data, int fd) c->tty.sx = 80; c->tty.sy = data->sy; if (c->tty.sy == 0) - c->tty.sy = 25; + c->tty.sy = 24; c->cwd = NULL; data->cwd[(sizeof data->cwd) - 1] = '\0'; @@ -278,7 +278,7 @@ server_msg_resize(struct client *c, struct msg_resize_data *data) c->tty.sx = 80; c->tty.sy = data->sy; if (c->tty.sy == 0) - c->tty.sy = 25; + c->tty.sy = 24; c->tty.cx = UINT_MAX; c->tty.cy = UINT_MAX; diff --git a/server.c b/server.c index 4afab67d..268a79dd 100644 --- a/server.c +++ b/server.c @@ -97,7 +97,7 @@ server_create_client(int fd) c->session = NULL; c->tty.sx = 80; - c->tty.sy = 25; + c->tty.sy = 24; screen_init(&c->status, c->tty.sx, 1, 0); c->message_string = NULL; From 427819910184a7174391c2e688da6b89634045ec Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 15 Sep 2009 15:14:09 +0000 Subject: [PATCH 0328/1180] Stick line length to what is actually used (removing an optimization that allowed it to be bigger), and use clear line/EOL sequences rather than spaces in copy/scroll mode. This fixes xterm copy/paste from tmux which treats trailing spaces differently from clearing a line with the escape sequences. Reported by martynas@. --- grid.c | 24 ++++++++++-------------- screen-write.c | 43 ++++++++++++++++++++++++++++++------------- 2 files changed, 40 insertions(+), 27 deletions(-) diff --git a/grid.c b/grid.c index b79e8843..6e01aa7c 100644 --- a/grid.c +++ b/grid.c @@ -189,22 +189,15 @@ grid_scroll_line(struct grid *gd) /* Expand line to fit to cell. */ void -grid_expand_line(struct grid *gd, u_int py, u_int wantx) +grid_expand_line(struct grid *gd, u_int py, u_int sx) { struct grid_line *gl; - u_int xx, sx; + u_int xx; gl = &gd->linedata[py]; - if (wantx <= gl->cellsize) + if (sx <= gl->cellsize) return; - if (gl->cellsize > gd->sx / 2) - sx = gd->sx; - else { - sx = gl->cellsize + 1; - while (sx < wantx) - sx *= 2; - } gl->celldata = xrealloc(gl->celldata, sx, sizeof *gl->celldata); for (xx = gl->cellsize; xx < sx; xx++) grid_put_cell(gd, xx, py, &grid_default_cell); @@ -307,10 +300,7 @@ grid_set_utf8( grid_put_utf8(gd, px, py, gc); } -/* - * Clear area. Note this is different from a fill as it just omits unallocated - * cells. - */ +/* Clear area. */ void grid_clear(struct grid *gd, u_int px, u_int py, u_int nx, u_int ny) { @@ -336,6 +326,12 @@ grid_clear(struct grid *gd, u_int px, u_int py, u_int nx, u_int ny) return; for (yy = py; yy < py + ny; yy++) { + if (px >= gd->linedata[yy].cellsize) + continue; + if (px + nx >= gd->linedata[yy].cellsize) { + gd->linedata[yy].cellsize = px; + continue; + } for (xx = px; xx < px + nx; xx++) { if (xx >= gd->linedata[yy].cellsize) break; diff --git a/screen-write.c b/screen-write.c index dba5f708..507c527b 100644 --- a/screen-write.c +++ b/screen-write.c @@ -371,25 +371,42 @@ screen_write_copy(struct screen_write_ctx *ctx, struct grid_line *gl; const struct grid_cell *gc; u_char *udata; - u_int xx, yy, cx, cy; + u_int xx, yy, cx, cy, ax, bx; cx = s->cx; cy = s->cy; for (yy = py; yy < py + ny; yy++) { gl = &gd->linedata[yy]; - for (xx = px; xx < px + nx; xx++) { - udata = NULL; - - if (xx >= gl->cellsize || yy >= gd->hsize + gd->sy) - gc = &grid_default_cell; - else { - gc = &gl->celldata[xx]; - if (gc->flags & GRID_FLAG_UTF8) - udata = gl->utf8data[xx].data; + if (yy < gd->hsize + gd->sy) { + /* + * Find start and end position and copy between + * them. Limit to the real end of the line then use a + * clear EOL only if copying to the end, otherwise + * could overwrite whatever is there already. + */ + if (px > gl->cellsize) + ax = gl->cellsize; + else + ax = px; + if (px + nx == gd->sx && px + nx > gl->cellsize) + bx = gl->cellsize; + else + bx = px + nx; + for (xx = ax; xx < bx; xx++) { + udata = NULL; + if (xx >= gl->cellsize) + gc = &grid_default_cell; + else { + gc = &gl->celldata[xx]; + if (gc->flags & GRID_FLAG_UTF8) + udata = gl->utf8data[xx].data; + } + screen_write_cell(ctx, gc, udata); } - - screen_write_cell(ctx, gc, udata); - } + if (px + nx == gd->sx && px + nx > gl->cellsize) + screen_write_clearendofline(ctx); + } else + screen_write_clearline(ctx); cy++; screen_write_cursormove(ctx, cx, cy); } From a6dd9e8e7eb0d7734b0905a97f6e8b0087a2e09c Mon Sep 17 00:00:00 2001 From: Jacek Masiulaniec Date: Tue, 15 Sep 2009 18:12:51 +0000 Subject: [PATCH 0329/1180] Enclose repeated buffer draining code in a new msgbuf_drain() function, which is additionally exported for use by others. From nicm@, who reminded me that tmux is now using buffer.c, too. --- imsg-buffer.c | 46 ++++++++++++++++++++++------------------------ imsg.h | 1 + 2 files changed, 23 insertions(+), 24 deletions(-) diff --git a/imsg-buffer.c b/imsg-buffer.c index 06fe0b1a..613220d4 100644 --- a/imsg-buffer.c +++ b/imsg-buffer.c @@ -144,7 +144,7 @@ int buf_write(struct msgbuf *msgbuf) { struct iovec iov[IOV_MAX]; - struct buf *buf, *next; + struct buf *buf; unsigned int i = 0; ssize_t n; @@ -170,17 +170,7 @@ buf_write(struct msgbuf *msgbuf) return (-2); } - for (buf = TAILQ_FIRST(&msgbuf->bufs); buf != NULL && n > 0; - buf = next) { - next = TAILQ_NEXT(buf, entry); - if (buf->rpos + n >= buf->wpos) { - n -= buf->wpos - buf->rpos; - buf_dequeue(msgbuf, buf); - } else { - buf->rpos += n; - n = 0; - } - } + msgbuf_drain(msgbuf, n); return (0); } @@ -200,6 +190,24 @@ msgbuf_init(struct msgbuf *msgbuf) TAILQ_INIT(&msgbuf->bufs); } +void +msgbuf_drain(struct msgbuf *msgbuf, size_t n) +{ + struct buf *buf, *next; + + for (buf = TAILQ_FIRST(&msgbuf->bufs); buf != NULL && n > 0; + buf = next) { + next = TAILQ_NEXT(buf, entry); + if (buf->rpos + n >= buf->wpos) { + n -= buf->wpos - buf->rpos; + buf_dequeue(msgbuf, buf); + } else { + buf->rpos += n; + n = 0; + } + } +} + void msgbuf_clear(struct msgbuf *msgbuf) { @@ -213,7 +221,7 @@ int msgbuf_write(struct msgbuf *msgbuf) { struct iovec iov[IOV_MAX]; - struct buf *buf, *next; + struct buf *buf; unsigned int i = 0; ssize_t n; struct msghdr msg; @@ -270,17 +278,7 @@ msgbuf_write(struct msgbuf *msgbuf) buf->fd = -1; } - for (buf = TAILQ_FIRST(&msgbuf->bufs); buf != NULL && n > 0; - buf = next) { - next = TAILQ_NEXT(buf, entry); - if (buf->rpos + n >= buf->wpos) { - n -= buf->wpos - buf->rpos; - buf_dequeue(msgbuf, buf); - } else { - buf->rpos += n; - n = 0; - } - } + msgbuf_drain(msgbuf, n); return (0); } diff --git a/imsg.h b/imsg.h index 5de73f0c..b84be86f 100644 --- a/imsg.h +++ b/imsg.h @@ -90,6 +90,7 @@ void buf_free(struct buf *); void msgbuf_init(struct msgbuf *); void msgbuf_clear(struct msgbuf *); int msgbuf_write(struct msgbuf *); +void msgbuf_drain(struct msgbuf *, size_t); /* imsg.c */ void imsg_init(struct imsgbuf *, int); From 5c60162e3c4f8ac9deede6c0fb5a21930d92e3b4 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 16 Sep 2009 12:35:04 +0000 Subject: [PATCH 0330/1180] Rather than constructing an entire termios struct from ttydefaults.h, just let forkpty do it and then alter the bits that should be changed after fork. A little neater and more portable. --- cmd-new-session.c | 21 ++++++--------------- cmd-respawn-window.c | 2 +- cmd-split-window.c | 2 +- session.c | 12 ++++++++++-- tmux.h | 2 +- window.c | 11 ++++++++++- 6 files changed, 29 insertions(+), 21 deletions(-) diff --git a/cmd-new-session.c b/cmd-new-session.c index df1ec45c..467fa879 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -21,9 +21,6 @@ #include #include -#define TTYDEFCHARS -#include - #include "tmux.h" /* @@ -116,7 +113,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) struct session *s; struct window *w; struct environ env; - struct termios tio; + struct termios tio, *tiop; const char *update; char *overrides, *cmd, *cwd, *cause; int detached, idx; @@ -151,8 +148,8 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) detached = 1; /* - * Fill in the termios settings used for new windows in this session; - * if there is a command client, use the control characters from it. + * Save the termios settings, part of which is used for new windows in + * this session. * * This is read again with tcgetattr() rather than using tty.tio as if * detached, tty_open won't be called. Because of this, it must be done @@ -162,15 +159,9 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) if (ctx->cmdclient != NULL && ctx->cmdclient->tty.fd != -1) { if (tcgetattr(ctx->cmdclient->tty.fd, &tio) != 0) fatal("tcgetattr failed"); + tiop = &tio; } else - memcpy(tio.c_cc, ttydefchars, sizeof tio.c_cc); - tio.c_cc[VERASE] = '\177'; - tio.c_iflag = TTYDEF_IFLAG; - tio.c_oflag = TTYDEF_OFLAG; - tio.c_lflag = TTYDEF_LFLAG; - tio.c_cflag = TTYDEF_CFLAG; - cfsetispeed(&tio, TTYDEF_SPEED); - cfsetospeed(&tio, TTYDEF_SPEED); + tiop = NULL; /* Open the terminal if necessary. */ if (!detached && ctx->cmdclient != NULL) { @@ -227,7 +218,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) /* Create the new session. */ idx = -1 - options_get_number(&global_s_options, "base-index"); s = session_create( - data->newname, cmd, cwd, &env, &tio, idx, sx, sy, &cause); + data->newname, cmd, cwd, &env, tiop, idx, sx, sy, &cause); if (s == NULL) { ctx->error(ctx, "create session failed: %s", cause); xfree(cause); diff --git a/cmd-respawn-window.c b/cmd-respawn-window.c index cd96f50b..540931aa 100644 --- a/cmd-respawn-window.c +++ b/cmd-respawn-window.c @@ -76,7 +76,7 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_ctx *ctx) TAILQ_INSERT_HEAD(&w->panes, wp, entry); window_pane_resize(wp, w->sx, w->sy); if (window_pane_spawn( - wp, data->arg, NULL, NULL, &env, &s->tio, &cause) != 0) { + wp, data->arg, NULL, NULL, &env, s->tio, &cause) != 0) { ctx->error(ctx, "respawn window failed: %s", cause); xfree(cause); environ_free(&env); diff --git a/cmd-split-window.c b/cmd-split-window.c index d6fc3f78..1604d9e2 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -190,7 +190,7 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) shell = _PATH_BSHELL; wp = window_add_pane(w, hlimit); - if (window_pane_spawn(wp, cmd, shell, cwd, &env, &s->tio, &cause) != 0) + if (window_pane_spawn(wp, cmd, shell, cwd, &env, s->tio, &cause) != 0) goto error; if (layout_split_pane(w->active, type, size, wp) != 0) { cause = xstrdup("pane too small"); diff --git a/session.c b/session.c index 4e5ac83e..fd2345b3 100644 --- a/session.c +++ b/session.c @@ -139,7 +139,12 @@ session_create(const char *name, const char *cmd, const char *cwd, environ_init(&s->environ); if (env != NULL) environ_copy(env, &s->environ); - memcpy(&s->tio, tio, sizeof s->tio); + + s->tio = NULL; + if (tio != NULL) { + s->tio = xmalloc(sizeof *s->tio); + memcpy(s->tio, tio, sizeof *s->tio); + } s->sx = sx; s->sy = sy; @@ -182,6 +187,9 @@ session_destroy(struct session *s) while (!ARRAY_EMPTY(&sessions) && ARRAY_LAST(&sessions) == NULL) ARRAY_TRUNC(&sessions, 1); + if (s->tio != NULL) + xfree(s->tio); + session_alert_cancel(s, NULL); environ_free(&s->environ); options_free(&s->options); @@ -237,7 +245,7 @@ session_new(struct session *s, hlimit = options_get_number(&s->options, "history-limit"); w = window_create( - name, cmd, shell, cwd, &env, &s->tio, s->sx, s->sy, hlimit, cause); + name, cmd, shell, cwd, &env, s->tio, s->sx, s->sy, hlimit, cause); if (w == NULL) { environ_free(&env); return (NULL); diff --git a/tmux.h b/tmux.h index 63f75577..0c5d2686 100644 --- a/tmux.h +++ b/tmux.h @@ -815,7 +815,7 @@ struct session { #define SESSION_DEAD 0x2 int flags; - struct termios tio; + struct termios *tio; struct environ environ; diff --git a/window.c b/window.c index 62b1f487..5683f174 100644 --- a/window.c +++ b/window.c @@ -454,6 +454,7 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell, struct environ_entry *envent; const char *ptr; struct timeval tv; + struct termios tio2; u_int i; if (wp->fd != -1) @@ -484,7 +485,7 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell, tv.tv_usec = NAME_INTERVAL * 1000L; timeradd(&wp->window->name_timer, &tv, &wp->window->name_timer); - switch (wp->pid = forkpty(&wp->fd, wp->tty, tio, &ws)) { + switch (wp->pid = forkpty(&wp->fd, wp->tty, NULL, &ws)) { case -1: wp->fd = -1; xasprintf(cause, "%s: %s", cmd, strerror(errno)); @@ -493,6 +494,14 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell, if (chdir(wp->cwd) != 0) chdir("/"); + if (tcgetattr(STDIN_FILENO, &tio2) != 0) + fatal("tcgetattr failed"); + if (tio != NULL) + memcpy(tio2.c_cc, tio->c_cc, sizeof tio2.c_cc); + tio2.c_cc[VERASE] = '\177'; + if (tcsetattr(STDIN_FILENO, TCSANOW, &tio2) != 0) + fatal("tcgetattr failed"); + ARRAY_INIT(&varlist); for (varp = environ; *varp != NULL; varp++) { var = xstrdup(*varp); From 63d499f480e264f8251552fb6d16965a1065e0e6 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 18 Sep 2009 15:19:27 +0000 Subject: [PATCH 0331/1180] New option, set-titles-string, to allow the window title to be specified (as for status-left/right) if set-titles is on. Also only update the title when the status line is being redrawn. --- cmd-set-option.c | 1 + server.c | 37 ++++++++++++++++++++++++------------- tmux.1 | 7 +++++++ tmux.c | 1 + 4 files changed, 33 insertions(+), 13 deletions(-) diff --git a/cmd-set-option.c b/cmd-set-option.c index 90cb6e0b..254a5767 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -69,6 +69,7 @@ const struct set_option_entry set_option_table[] = { { "repeat-time", SET_OPTION_NUMBER, 0, SHRT_MAX, NULL }, { "set-remain-on-exit", SET_OPTION_FLAG, 0, 0, NULL }, { "set-titles", SET_OPTION_FLAG, 0, 0, NULL }, + { "set-titles-string", SET_OPTION_STRING, 0, 0, NULL }, { "status", SET_OPTION_FLAG, 0, 0, NULL }, { "status-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL }, { "status-bg", SET_OPTION_COLOUR, 0, 0, NULL }, diff --git a/server.c b/server.c index 268a79dd..2262b4fe 100644 --- a/server.c +++ b/server.c @@ -66,6 +66,7 @@ void server_clean_dead(void); void server_lost_client(struct client *); void server_check_window(struct window *); void server_check_redraw(struct client *); +void server_set_title(struct client *); void server_redraw_locked(struct client *); void server_check_timers(struct client *); void server_second_timers(void); @@ -516,7 +517,6 @@ server_check_redraw(struct client *c) { struct session *s; struct window_pane *wp; - char title[512]; int flags, redraw; if (c == NULL || c->session == NULL) @@ -526,19 +526,10 @@ server_check_redraw(struct client *c) flags = c->tty.flags & TTY_FREEZE; c->tty.flags &= ~TTY_FREEZE; - if (options_get_number(&s->options, "set-titles")) { - xsnprintf(title, sizeof title, "%s:%u:%s - \"%s\"", - s->name, s->curw->idx, s->curw->window->name, - s->curw->window->active->screen->title); - if (c->title == NULL || strcmp(title, c->title) != 0) { - if (c->title != NULL) - xfree(c->title); - c->title = xstrdup(title); - tty_set_title(&c->tty, c->title); - } - } - if (c->flags & (CLIENT_REDRAW|CLIENT_STATUS)) { + if (options_get_number(&s->options, "set-titles")) + server_set_title(c); + if (c->message_string != NULL) redraw = status_message_redraw(c); else if (c->prompt_string != NULL) @@ -570,6 +561,26 @@ server_check_redraw(struct client *c) c->flags &= ~(CLIENT_REDRAW|CLIENT_STATUS); } +/* Set client title. */ +void +server_set_title(struct client *c) +{ + struct session *s = c->session; + const char *template; + char *title; + + template = options_get_string(&s->options, "set-titles-string"); + + title = status_replace(c->session, template, time(NULL)); + if (c->title == NULL || strcmp(title, c->title) != 0) { + if (c->title != NULL) + xfree(c->title); + c->title = xstrdup(title); + tty_set_title(&c->tty, c->title); + } + xfree(title); +} + /* Redraw client when locked. */ void server_redraw_locked(struct client *c) diff --git a/tmux.1 b/tmux.1 index fb733bd5..5db6c0c9 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1287,6 +1287,13 @@ This option is off by default. Note that elinks will only attempt to set the window title if the STY environment variable is set. +.It Ic set-titles-string Ar string +String used to set the window title if +.Ic set-titles +is on. +Character sequences are replaced as for the +.Ic status-left +option. .It Xo Ic status .Op Ic on | off .Xc diff --git a/tmux.c b/tmux.c index 66ba8767..d75de607 100644 --- a/tmux.c +++ b/tmux.c @@ -413,6 +413,7 @@ main(int argc, char **argv) options_set_number(so, "repeat-time", 500); options_set_number(so, "set-remain-on-exit", 0); options_set_number(so, "set-titles", 0); + options_set_string(so, "set-titles-string", "#S:#I:#W - \"#T\""); options_set_number(so, "status", 1); options_set_number(so, "status-attr", 0); options_set_number(so, "status-bg", 2); From 273f1b385cdbe472501092edabf78acb2ea70a47 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 20 Sep 2009 14:58:12 +0000 Subject: [PATCH 0332/1180] Regularise some fatal messages. --- client.c | 2 +- names.c | 2 +- paste.c | 4 ++-- server-fn.c | 2 +- server.c | 8 ++++---- session.c | 2 +- status.c | 6 +++--- tty-keys.c | 4 ++-- window.c | 2 +- 9 files changed, 16 insertions(+), 16 deletions(-) diff --git a/client.c b/client.c index abf2f782..05d5b606 100644 --- a/client.c +++ b/client.c @@ -74,7 +74,7 @@ client_init(char *path, struct client_ctx *cctx, int cmdflags, int flags) } if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) - fatal("socket"); + fatal("socket failed"); if (connect(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1) { if (errno == ECONNREFUSED) { diff --git a/names.c b/names.c index 75f6c7b8..014a600c 100644 --- a/names.c +++ b/names.c @@ -36,7 +36,7 @@ set_window_names(void) struct timeval tv, tv2; if (gettimeofday(&tv, NULL) != 0) - fatal("gettimeofday"); + fatal("gettimeofday failed"); for (i = 0; i < ARRAY_LENGTH(&windows); i++) { w = ARRAY_ITEM(&windows, i); diff --git a/paste.c b/paste.c index f78c0241..582645d5 100644 --- a/paste.c +++ b/paste.c @@ -117,7 +117,7 @@ paste_add(struct paste_stack *ps, u_char *data, size_t size, u_int limit) pb->data = data; pb->size = size; if (gettimeofday(&pb->tv, NULL) != 0) - fatal("gettimeofday"); + fatal("gettimeofday failed"); } int @@ -134,7 +134,7 @@ paste_replace(struct paste_stack *ps, u_int idx, u_char *data, size_t size) pb->data = data; pb->size = size; if (gettimeofday(&pb->tv, NULL) != 0) - fatal("gettimeofday"); + fatal("gettimeofday failed"); return (0); } diff --git a/server-fn.c b/server-fn.c index d39108dd..4bb2ed92 100644 --- a/server-fn.c +++ b/server-fn.c @@ -315,7 +315,7 @@ server_set_identify(struct client *c) tv.tv_usec = (delay % 1000) * 1000L; if (gettimeofday(&c->identify_timer, NULL) != 0) - fatal("gettimeofday"); + fatal("gettimeofday failed"); timeradd(&c->identify_timer, &tv, &c->identify_timer); c->flags |= CLIENT_IDENTIFY; diff --git a/server.c b/server.c index 2262b4fe..73998042 100644 --- a/server.c +++ b/server.c @@ -435,7 +435,7 @@ server_child_signal(void) case -1: if (errno == ECHILD) return; - fatal("waitpid"); + fatal("waitpid failed"); case 0: return; } @@ -637,7 +637,7 @@ server_check_timers(struct client *c) s = c->session; if (gettimeofday(&tv, NULL) != 0) - fatal("gettimeofday"); + fatal("gettimeofday failed"); if (c->flags & CLIENT_IDENTIFY && timercmp(&tv, &c->identify_timer, >)) server_clear_identify(c); @@ -805,7 +805,7 @@ server_handle_client(struct client *c) xtimeout = options_get_number(&c->session->options, "repeat-time"); if (xtimeout != 0 && c->flags & CLIENT_REPEAT) { if (gettimeofday(&tv, NULL) != 0) - fatal("gettimeofday"); + fatal("gettimeofday failed"); if (timercmp(&tv, &c->repeat_timer, >)) c->flags &= ~(CLIENT_PREFIX|CLIENT_REPEAT); } @@ -889,7 +889,7 @@ server_handle_client(struct client *c) tv.tv_sec = xtimeout / 1000; tv.tv_usec = (xtimeout % 1000) * 1000L; if (gettimeofday(&c->repeat_timer, NULL) != 0) - fatal("gettimeofday"); + fatal("gettimeofday failed"); timeradd(&c->repeat_timer, &tv, &c->repeat_timer); } diff --git a/session.c b/session.c index fd2345b3..fb49a365 100644 --- a/session.c +++ b/session.c @@ -126,7 +126,7 @@ session_create(const char *name, const char *cmd, const char *cwd, s->flags = 0; if (gettimeofday(&s->tv, NULL) != 0) - fatal("gettimeofday"); + fatal("gettimeofday failed"); s->curw = NULL; SLIST_INIT(&s->lastw); diff --git a/status.c b/status.c index 7e25f235..77062729 100644 --- a/status.c +++ b/status.c @@ -64,7 +64,7 @@ status_redraw(struct client *c) screen_init(&c->status, c->tty.sx, 1, 0); if (gettimeofday(&c->status_timer, NULL) != 0) - fatal("gettimeofday"); + fatal("gettimeofday failed"); 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")); @@ -361,7 +361,7 @@ status_replace(struct session *s, const char *fmt, time_t t) case 'H': if (ptr == NULL) { if (gethostname(tmp, sizeof tmp) != 0) - fatal("gethostname"); + fatal("gethostname failed"); ptr = tmp; } /* FALLTHROUGH */ @@ -565,7 +565,7 @@ status_message_set(struct client *c, const char *fmt, ...) tv.tv_usec = (delay % 1000) * 1000L; if (gettimeofday(&c->message_timer, NULL) != 0) - fatal("gettimeofday"); + fatal("gettimeofday failed"); timeradd(&c->message_timer, &tv, &c->message_timer); c->tty.flags |= (TTY_NOCURSOR|TTY_FREEZE); diff --git a/tty-keys.c b/tty-keys.c index f25dc169..11a3187f 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -287,7 +287,7 @@ tty_keys_next(struct tty *tty, int *key, u_char *mouse) tv.tv_sec = 0; tv.tv_usec = ESCAPE_PERIOD * 1000L; if (gettimeofday(&tty->key_timer, NULL) != 0) - fatal("gettimeofday"); + fatal("gettimeofday failed"); timeradd(&tty->key_timer, &tv, &tty->key_timer); tty->flags |= TTY_ESCAPE; @@ -317,7 +317,7 @@ tty_keys_next(struct tty *tty, int *key, u_char *mouse) /* If the timer hasn't expired, keep waiting. */ if (gettimeofday(&tv, NULL) != 0) - fatal("gettimeofday"); + fatal("gettimeofday failed"); if (timercmp(&tty->key_timer, &tv, >)) return (1); diff --git a/window.c b/window.c index 5683f174..b663acf3 100644 --- a/window.c +++ b/window.c @@ -480,7 +480,7 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell, ws.ws_row = screen_size_y(&wp->base); if (gettimeofday(&wp->window->name_timer, NULL) != 0) - fatal("gettimeofday"); + fatal("gettimeofday failed"); tv.tv_sec = 0; tv.tv_usec = NAME_INTERVAL * 1000L; timeradd(&wp->window->name_timer, &tv, &wp->window->name_timer); From 9b5f5ed8e8f74a9a615dfb6f5975b2f054d6d1fd Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 20 Sep 2009 17:27:18 +0000 Subject: [PATCH 0333/1180] Move some common and untidy code for window link/unlink into generic functions instead of duplicating it in move/link window.. --- cmd-kill-pane.c | 1 + cmd-kill-window.c | 1 + cmd-link-window.c | 46 ++++++---------------------------- cmd-move-window.c | 61 ++++++--------------------------------------- cmd-unlink-window.c | 12 +-------- server-fn.c | 54 ++++++++++++++++++++++++++++++++++++++- tmux.h | 3 +++ 7 files changed, 74 insertions(+), 104 deletions(-) diff --git a/cmd-kill-pane.c b/cmd-kill-pane.c index 1548a75e..38d0daef 100644 --- a/cmd-kill-pane.c +++ b/cmd-kill-pane.c @@ -52,6 +52,7 @@ cmd_kill_pane_exec(struct cmd *self, struct cmd_ctx *ctx) if (window_count_panes(wl->window) == 1) { /* Only one pane, kill the window. */ server_kill_window(wl->window); + recalculate_sizes(); return (0); } diff --git a/cmd-kill-window.c b/cmd-kill-window.c index ed15fb33..d213a90e 100644 --- a/cmd-kill-window.c +++ b/cmd-kill-window.c @@ -47,6 +47,7 @@ cmd_kill_window_exec(struct cmd *self, struct cmd_ctx *ctx) return (-1); server_kill_window(wl->window); + recalculate_sizes(); return (0); } diff --git a/cmd-link-window.c b/cmd-link-window.c index c13dbc90..cbc0b083 100644 --- a/cmd-link-window.c +++ b/cmd-link-window.c @@ -44,54 +44,22 @@ cmd_link_window_exec(struct cmd *self, struct cmd_ctx *ctx) { struct cmd_srcdst_data *data = self->data; struct session *dst; - struct winlink *wl_src, *wl_dst; + struct winlink *wl; char *cause; - int idx; + int idx, kflag, dflag; - if ((wl_src = cmd_find_window(ctx, data->src, NULL)) == NULL) + if ((wl = cmd_find_window(ctx, data->src, NULL)) == NULL) return (-1); if ((idx = cmd_find_index(ctx, data->dst, &dst)) == -2) return (-1); - wl_dst = NULL; - if (idx != -1) - wl_dst = winlink_find_by_index(&dst->windows, idx); - if (wl_dst != NULL) { - if (wl_dst->window == wl_src->window) - return (0); - - if (data->chflags & CMD_CHFLAG('k')) { - /* - * Can't use session_detach as it will destroy session - * if this makes it empty. - */ - session_alert_cancel(dst, wl_dst); - winlink_stack_remove(&dst->lastw, wl_dst); - winlink_remove(&dst->windows, wl_dst); - - /* Force select/redraw if current. */ - if (wl_dst == dst->curw) { - data->chflags &= ~CMD_CHFLAG('d'); - dst->curw = NULL; - } - } - } - - if (idx == -1) - idx = -1 - options_get_number(&dst->options, "base-index"); - wl_dst = session_attach(dst, wl_src->window, idx, &cause); - if (wl_dst == NULL) { - ctx->error(ctx, "create session failed: %s", cause); + kflag = data->chflags & CMD_CHFLAG('k'); + dflag = data->chflags & CMD_CHFLAG('d'); + if (server_link_window(wl, dst, idx, kflag, !dflag, &cause) != 0) { + ctx->error(ctx, "can't create session: %s", cause); xfree(cause); return (-1); } - - if (data->chflags & CMD_CHFLAG('d')) - server_status_session(dst); - else { - session_select(dst, wl_dst->idx); - server_redraw_session(dst); - } recalculate_sizes(); return (0); diff --git a/cmd-move-window.c b/cmd-move-window.c index 1cf72f94..de00f2dd 100644 --- a/cmd-move-window.c +++ b/cmd-move-window.c @@ -44,68 +44,23 @@ cmd_move_window_exec(struct cmd *self, struct cmd_ctx *ctx) { struct cmd_srcdst_data *data = self->data; struct session *src, *dst; - struct winlink *wl_src, *wl_dst; - struct client *c; - u_int i; - int destroyed, idx; + struct winlink *wl; char *cause; + int idx, kflag, dflag; - if ((wl_src = cmd_find_window(ctx, data->src, &src)) == NULL) + if ((wl = cmd_find_window(ctx, data->src, &src)) == NULL) return (-1); if ((idx = cmd_find_index(ctx, data->dst, &dst)) == -2) return (-1); - wl_dst = NULL; - if (idx != -1) - wl_dst = winlink_find_by_index(&dst->windows, idx); - if (wl_dst != NULL) { - if (wl_dst->window == wl_src->window) - return (0); - - if (data->chflags & CMD_CHFLAG('k')) { - /* - * Can't use session_detach as it will destroy session - * if this makes it empty. - */ - session_alert_cancel(dst, wl_dst); - winlink_stack_remove(&dst->lastw, wl_dst); - winlink_remove(&dst->windows, wl_dst); - - /* Force select/redraw if current. */ - if (wl_dst == dst->curw) { - data->chflags &= ~CMD_CHFLAG('d'); - dst->curw = NULL; - } - } - } - - if (idx == -1) - idx = -1 - options_get_number(&dst->options, "base-index"); - wl_dst = session_attach(dst, wl_src->window, idx, &cause); - if (wl_dst == NULL) { - ctx->error(ctx, "attach window failed: %s", cause); + kflag = data->chflags & CMD_CHFLAG('k'); + dflag = data->chflags & CMD_CHFLAG('d'); + if (server_link_window(wl, dst, idx, kflag, !dflag, &cause) != 0) { + ctx->error(ctx, "can't create session: %s", cause); xfree(cause); return (-1); } - - destroyed = session_detach(src, wl_src); - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - c = ARRAY_ITEM(&clients, i); - if (c == NULL || c->session != src) - continue; - if (destroyed) { - c->session = NULL; - server_write_client(c, MSG_EXIT, NULL, 0); - } else - server_redraw_client(c); - } - - if (data->chflags & CMD_CHFLAG('d')) - server_status_session(dst); - else { - session_select(dst, wl_dst->idx); - server_redraw_session(dst); - } + server_unlink_window(src, wl); recalculate_sizes(); return (0); diff --git a/cmd-unlink-window.c b/cmd-unlink-window.c index fd72b252..5c9f811b 100644 --- a/cmd-unlink-window.c +++ b/cmd-unlink-window.c @@ -55,17 +55,7 @@ cmd_unlink_window_exec(struct cmd *self, struct cmd_ctx *ctx) return (-1); } - destroyed = session_detach(s, wl); - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - c = ARRAY_ITEM(&clients, i); - if (c == NULL || c->session != s) - continue; - if (destroyed) { - c->session = NULL; - server_write_client(c, MSG_EXIT, NULL, 0); - } else - server_redraw_client(c); - } + server_unlink_window(s, wl); recalculate_sizes(); return (0); diff --git a/server-fn.c b/server-fn.c index 4bb2ed92..e3cee410 100644 --- a/server-fn.c +++ b/server-fn.c @@ -286,7 +286,59 @@ server_kill_window(struct window *w) else server_redraw_session(s); } - recalculate_sizes(); +} + +int +server_link_window( + struct winlink *srcwl, struct session *dst, int dstidx, + int killflag, int selectflag, char **cause) +{ + struct winlink *dstwl; + + dstwl = NULL; + if (dstidx != -1) + dstwl = winlink_find_by_index(&dst->windows, dstidx); + if (dstwl != NULL) { + if (dstwl->window == srcwl->window) + return (0); + if (killflag) { + /* + * Can't use session_detach as it will destroy session + * if this makes it empty. + */ + session_alert_cancel(dst, dstwl); + winlink_stack_remove(&dst->lastw, dstwl); + winlink_remove(&dst->windows, dstwl); + + /* Force select/redraw if current. */ + if (dstwl == dst->curw) + selectflag = 1; + } + } + + if (dstidx == -1) + dstidx = -1 - options_get_number(&dst->options, "base-index"); + dstwl = session_attach(dst, srcwl->window, dstidx, cause); + if (dstwl == NULL) + return (-1); + + if (!selectflag) + server_status_session(dst); + else { + session_select(dst, dstwl->idx); + server_redraw_session(dst); + } + + return (0); +} + +void +server_unlink_window(struct session *s, struct winlink *wl) +{ + if (session_detach(s, wl)) + server_destroy_session(s); + else + server_redraw_session(s); } void diff --git a/tmux.h b/tmux.h index 0c5d2686..c6d77b40 100644 --- a/tmux.h +++ b/tmux.h @@ -1456,6 +1456,9 @@ void server_status_window(struct window *); void server_lock(void); int server_unlock(const char *); void server_kill_window(struct window *); +int server_link_window( + struct winlink *, struct session *, int, int, int, char **); +void server_unlink_window(struct session *, struct winlink *); void server_destroy_session(struct session *); void server_set_identify(struct client *); void server_clear_identify(struct client *); From 105ce36792717a0916cab18b7dd0a11db1f7c84a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 20 Sep 2009 17:31:26 +0000 Subject: [PATCH 0334/1180] Nuke unused variables and fix stupid error message. --- cmd-link-window.c | 2 +- cmd-move-window.c | 2 +- cmd-unlink-window.c | 3 --- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/cmd-link-window.c b/cmd-link-window.c index cbc0b083..95514d40 100644 --- a/cmd-link-window.c +++ b/cmd-link-window.c @@ -56,7 +56,7 @@ cmd_link_window_exec(struct cmd *self, struct cmd_ctx *ctx) kflag = data->chflags & CMD_CHFLAG('k'); dflag = data->chflags & CMD_CHFLAG('d'); if (server_link_window(wl, dst, idx, kflag, !dflag, &cause) != 0) { - ctx->error(ctx, "can't create session: %s", cause); + ctx->error(ctx, "can't link window: %s", cause); xfree(cause); return (-1); } diff --git a/cmd-move-window.c b/cmd-move-window.c index de00f2dd..4c92556a 100644 --- a/cmd-move-window.c +++ b/cmd-move-window.c @@ -56,7 +56,7 @@ cmd_move_window_exec(struct cmd *self, struct cmd_ctx *ctx) kflag = data->chflags & CMD_CHFLAG('k'); dflag = data->chflags & CMD_CHFLAG('d'); if (server_link_window(wl, dst, idx, kflag, !dflag, &cause) != 0) { - ctx->error(ctx, "can't create session: %s", cause); + ctx->error(ctx, "can't move window: %s", cause); xfree(cause); return (-1); } diff --git a/cmd-unlink-window.c b/cmd-unlink-window.c index 5c9f811b..38904689 100644 --- a/cmd-unlink-window.c +++ b/cmd-unlink-window.c @@ -43,9 +43,6 @@ cmd_unlink_window_exec(struct cmd *self, struct cmd_ctx *ctx) struct cmd_target_data *data = self->data; struct winlink *wl; struct session *s; - struct client *c; - u_int i; - int destroyed; if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL) return (-1); From 14ebcab5b016828c64c6d4564e50159f5dedf130 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 20 Sep 2009 19:15:01 +0000 Subject: [PATCH 0335/1180] run-shell command to run a shell command without opening a window, sending stdout to output mode. --- Makefile | 2 +- cmd-run-shell.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++ cmd.c | 1 + tmux.1 | 9 +++++ tmux.h | 1 + 5 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 cmd-run-shell.c diff --git a/Makefile b/Makefile index fcb1d43b..c2a51436 100644 --- a/Makefile +++ b/Makefile @@ -23,7 +23,7 @@ SRCS= attributes.c buffer-poll.c buffer.c cfg.c client-fn.c \ cmd-set-password.c cmd-set-window-option.c cmd-show-buffer.c \ cmd-show-options.c cmd-show-window-options.c cmd-source-file.c \ cmd-split-window.c cmd-start-server.c cmd-string.c cmd-if-shell.c \ - cmd-suspend-client.c cmd-swap-pane.c cmd-swap-window.c \ + cmd-run-shell.c cmd-suspend-client.c cmd-swap-pane.c cmd-swap-window.c \ cmd-switch-client.c cmd-unbind-key.c cmd-unlink-window.c \ cmd-set-environment.c cmd-show-environment.c cmd-choose-client.c \ cmd-up-pane.c cmd-display-message.c cmd-display-panes.c cmd.c \ diff --git a/cmd-run-shell.c b/cmd-run-shell.c new file mode 100644 index 00000000..71e5b96b --- /dev/null +++ b/cmd-run-shell.c @@ -0,0 +1,96 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2009 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 + +#include + +#include "tmux.h" + +/* + * Runs a command without a window. + */ + +int cmd_run_shell_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_run_shell_entry = { + "run-shell", "run", + "command", + CMD_ARG1, 0, + cmd_target_init, + cmd_target_parse, + cmd_run_shell_exec, + cmd_target_free, + cmd_target_print +}; + +int +cmd_run_shell_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_target_data *data = self->data; + FILE *fp; + char *buf, *lbuf, *msg; + size_t len; + int has_output, ret, status; + + if ((fp = popen(data->arg, "r")) == NULL) { + ctx->error(ctx, "popen error"); + return (-1); + } + + has_output = 0; + lbuf = NULL; + while ((buf = fgetln(fp, &len)) != NULL) { + if (buf[len - 1] == '\n') + buf[len - 1] = '\0'; + else { + lbuf = xmalloc(len + 1); + memcpy(lbuf, buf, len); + lbuf[len] = '\0'; + buf = lbuf; + } + ctx->print(ctx, "%s", buf); + has_output = 1; + } + if (lbuf != NULL) + xfree(lbuf); + + msg = NULL; + status = pclose(fp); + + if (WIFEXITED(status)) { + if ((ret = WEXITSTATUS(status)) == 0) + return (0); + xasprintf(&msg, "'%s' returned %d", data->arg, ret); + } else if (WIFSIGNALED(status)) { + xasprintf( + &msg, "'%s' terminated by signal %d", data->arg, + WTERMSIG(status)); + } + + if (msg != NULL) { + if (has_output) + ctx->print(ctx, "%s", msg); + else + ctx->info(ctx, "%s", msg); + xfree(msg); + } + + return (0); +} diff --git a/cmd.c b/cmd.c index 08aea7cb..a391945d 100644 --- a/cmd.c +++ b/cmd.c @@ -76,6 +76,7 @@ const struct cmd_entry *cmd_table[] = { &cmd_resize_pane_entry, &cmd_respawn_window_entry, &cmd_rotate_window_entry, + &cmd_run_shell_entry, &cmd_save_buffer_entry, &cmd_scroll_mode_entry, &cmd_select_layout_entry, diff --git a/tmux.1 b/tmux.1 index 5db6c0c9..d78981f7 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1959,6 +1959,15 @@ returns success. .It Ic lock-server .D1 (alias: Ic lock ) Lock the server until a password is entered. +.It Ic run-shell Ar command +.D1 (alias: Ic run ) +Execute +.Ar command +without creating a window. +Any output to stdout is displayed in output mode. +If +.Ar 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. diff --git a/tmux.h b/tmux.h index c6d77b40..6a453c1b 100644 --- a/tmux.h +++ b/tmux.h @@ -1338,6 +1338,7 @@ extern const struct cmd_entry cmd_rename_window_entry; extern const struct cmd_entry cmd_resize_pane_entry; extern const struct cmd_entry cmd_respawn_window_entry; extern const struct cmd_entry cmd_rotate_window_entry; +extern const struct cmd_entry cmd_run_shell_entry; extern const struct cmd_entry cmd_save_buffer_entry; extern const struct cmd_entry cmd_scroll_mode_entry; extern const struct cmd_entry cmd_select_layout_entry; From c7a8db55438deae5214956cbba42a3833c8ec0c9 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 21 Sep 2009 06:55:06 +0000 Subject: [PATCH 0336/1180] Key options were implemented as a number so these struct members are unused. --- tmux.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/tmux.h b/tmux.h index 6a453c1b..b69621d6 100644 --- a/tmux.h +++ b/tmux.h @@ -544,12 +544,10 @@ struct options_entry { enum { OPTIONS_STRING, OPTIONS_NUMBER, - OPTIONS_KEY, } type; union { char *string; long long number; - int key; } value; SPLAY_ENTRY(options_entry) entry; From fc9107a16aa9a8674c7b049ecc68ea25bb026df6 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 21 Sep 2009 07:00:09 +0000 Subject: [PATCH 0337/1180] Drop tiny union from option struct. --- options.c | 16 ++++++++-------- tmux.h | 7 +++---- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/options.c b/options.c index 45d9f714..90d9c88e 100644 --- a/options.c +++ b/options.c @@ -53,7 +53,7 @@ options_free(struct options *oo) SPLAY_REMOVE(options_tree, &oo->tree, o); xfree(o->name); if (o->type == OPTIONS_STRING) - xfree(o->value.string); + xfree(o->str); xfree(o); } } @@ -94,7 +94,7 @@ options_remove(struct options *oo, const char *name) SPLAY_REMOVE(options_tree, &oo->tree, o); xfree(o->name); if (o->type == OPTIONS_STRING) - xfree(o->value.string); + xfree(o->str); xfree(o); } @@ -109,11 +109,11 @@ options_set_string(struct options *oo, const char *name, const char *fmt, ...) o->name = xstrdup(name); SPLAY_INSERT(options_tree, &oo->tree, o); } else if (o->type == OPTIONS_STRING) - xfree(o->value.string); + xfree(o->str); va_start(ap, fmt); o->type = OPTIONS_STRING; - xvasprintf(&o->value.string, fmt, ap); + xvasprintf(&o->str, fmt, ap); va_end(ap); } @@ -126,7 +126,7 @@ options_get_string(struct options *oo, const char *name) fatalx("missing option"); if (o->type != OPTIONS_STRING) fatalx("option not a string"); - return (o->value.string); + return (o->str); } void @@ -139,10 +139,10 @@ options_set_number(struct options *oo, const char *name, long long value) o->name = xstrdup(name); SPLAY_INSERT(options_tree, &oo->tree, o); } else if (o->type == OPTIONS_STRING) - xfree(o->value.string); + xfree(o->str); o->type = OPTIONS_NUMBER; - o->value.number = value; + o->num = value; } @@ -155,5 +155,5 @@ options_get_number(struct options *oo, const char *name) fatalx("missing option"); if (o->type != OPTIONS_NUMBER) fatalx("option not a number"); - return (o->value.number); + return (o->num); } diff --git a/tmux.h b/tmux.h index b69621d6..64409ae8 100644 --- a/tmux.h +++ b/tmux.h @@ -545,10 +545,9 @@ struct options_entry { OPTIONS_STRING, OPTIONS_NUMBER, } type; - union { - char *string; - long long number; - } value; + + char *str; + long long num; SPLAY_ENTRY(options_entry) entry; }; From b769aa59d35e9feed05610e63ee3bda1bdc5a66e Mon Sep 17 00:00:00 2001 From: Jason McIntyre Date: Mon, 21 Sep 2009 07:45:10 +0000 Subject: [PATCH 0338/1180] zap trailing whitespace; --- tmux.1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tmux.1 b/tmux.1 index d78981f7..6d833238 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1966,7 +1966,7 @@ Execute without creating a window. Any output to stdout is displayed in output mode. If -.Ar command +.Ar command doesn't return success, the exit status is also displayed. .It Ic server-info .D1 (alias: Ic info ) From e3c3d746f7e78e5327627bed665a98e72d874774 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 21 Sep 2009 14:46:47 +0000 Subject: [PATCH 0339/1180] Move common code from show-options and show-window-options into a function. --- cmd-show-options.c | 46 +++++---------------------------------- cmd-show-window-options.c | 46 +++++---------------------------------- options-cmd.c | 40 ++++++++++++++++++++++++++++++++++ tmux.h | 2 ++ 4 files changed, 52 insertions(+), 82 deletions(-) diff --git a/cmd-show-options.c b/cmd-show-options.c index a5ee2e4f..9e84c64a 100644 --- a/cmd-show-options.c +++ b/cmd-show-options.c @@ -46,9 +46,9 @@ cmd_show_options_exec(struct cmd *self, struct cmd_ctx *ctx) struct cmd_target_data *data = self->data; struct session *s; struct options *oo; + struct options_entry *o; const struct set_option_entry *entry; - char *vs; - long long vn; + const char *optval; if (data->chflags & CMD_CHFLAG('g')) oo = &global_s_options; @@ -59,46 +59,10 @@ cmd_show_options_exec(struct cmd *self, struct cmd_ctx *ctx) } for (entry = set_option_table; entry->name != NULL; entry++) { - if (options_find1(oo, entry->name) == NULL) + if ((o = options_find1(oo, entry->name)) == NULL) continue; - - switch (entry->type) { - case SET_OPTION_STRING: - vs = options_get_string(oo, entry->name); - ctx->print(ctx, "%s \"%s\"", entry->name, vs); - break; - case SET_OPTION_NUMBER: - vn = options_get_number(oo, entry->name); - ctx->print(ctx, "%s %lld", entry->name, vn); - break; - case SET_OPTION_KEY: - vn = options_get_number(oo, entry->name); - ctx->print(ctx, "%s %s", - entry->name, key_string_lookup_key(vn)); - break; - case SET_OPTION_COLOUR: - vn = options_get_number(oo, entry->name); - ctx->print(ctx, "%s %s", - entry->name, colour_tostring(vn)); - break; - case SET_OPTION_ATTRIBUTES: - vn = options_get_number(oo, entry->name); - ctx->print(ctx, "%s %s", - entry->name, attributes_tostring(vn)); - break; - case SET_OPTION_FLAG: - vn = options_get_number(oo, entry->name); - if (vn) - ctx->print(ctx, "%s on", entry->name); - else - ctx->print(ctx, "%s off", entry->name); - break; - case SET_OPTION_CHOICE: - vn = options_get_number(oo, entry->name); - ctx->print(ctx, "%s %s", - entry->name, entry->choices[vn]); - break; - } + optval = set_option_print(entry, o); + ctx->print(ctx, "%s %s", entry->name, optval); } return (0); diff --git a/cmd-show-window-options.c b/cmd-show-window-options.c index cfff8045..04477233 100644 --- a/cmd-show-window-options.c +++ b/cmd-show-window-options.c @@ -46,9 +46,9 @@ cmd_show_window_options_exec(struct cmd *self, struct cmd_ctx *ctx) struct cmd_target_data *data = self->data; struct winlink *wl; struct options *oo; + struct options_entry *o; const struct set_option_entry *entry; - char *vs; - long long vn; + const char *optval; if (data->chflags & CMD_CHFLAG('g')) oo = &global_w_options; @@ -59,46 +59,10 @@ cmd_show_window_options_exec(struct cmd *self, struct cmd_ctx *ctx) } for (entry = set_window_option_table; entry->name != NULL; entry++) { - if (options_find1(oo, entry->name) == NULL) + if ((o = options_find1(oo, entry->name)) == NULL) continue; - - switch (entry->type) { - case SET_OPTION_STRING: - vs = options_get_string(oo, entry->name); - ctx->print(ctx, "%s \"%s\"", entry->name, vs); - break; - case SET_OPTION_NUMBER: - vn = options_get_number(oo, entry->name); - ctx->print(ctx, "%s %lld", entry->name, vn); - break; - case SET_OPTION_KEY: - vn = options_get_number(oo, entry->name); - ctx->print(ctx, "%s %s", - entry->name, key_string_lookup_key(vn)); - break; - case SET_OPTION_COLOUR: - vn = options_get_number(oo, entry->name); - ctx->print(ctx, "%s %s", - entry->name, colour_tostring(vn)); - break; - case SET_OPTION_ATTRIBUTES: - vn = options_get_number(oo, entry->name); - ctx->print(ctx, "%s %s", - entry->name, attributes_tostring(vn)); - break; - case SET_OPTION_FLAG: - vn = options_get_number(oo, entry->name); - if (vn) - ctx->print(ctx, "%s on", entry->name); - else - ctx->print(ctx, "%s off", entry->name); - break; - case SET_OPTION_CHOICE: - vn = options_get_number(oo, entry->name); - ctx->print(ctx, "%s %s", - entry->name, entry->choices[vn]); - break; - } + optval = set_option_print(entry, o); + ctx->print(ctx, "%s %s", entry->name, optval); } return (0); diff --git a/options-cmd.c b/options-cmd.c index 4cdd75d0..0e41a62c 100644 --- a/options-cmd.c +++ b/options-cmd.c @@ -23,6 +23,46 @@ #include "tmux.h" +const char * +set_option_print(const struct set_option_entry *entry, struct options_entry *o) +{ + static char out[BUFSIZ]; + const char *s; + + *out = '\0'; + switch (entry->type) { + case SET_OPTION_STRING: + xsnprintf(out, sizeof out, "\"%s\"", o->str); + break; + case SET_OPTION_NUMBER: + xsnprintf(out, sizeof out, "%lld", o->num); + break; + case SET_OPTION_KEY: + s = key_string_lookup_key(o->num); + xsnprintf(out, sizeof out, "%s", s); + break; + case SET_OPTION_COLOUR: + s = colour_tostring(o->num); + xsnprintf(out, sizeof out, "%s", s); + break; + case SET_OPTION_ATTRIBUTES: + s = attributes_tostring(o->num); + xsnprintf(out, sizeof out, "%s", s); + break; + case SET_OPTION_FLAG: + if (o->num) + strlcpy(out, "on", sizeof out); + else + strlcpy(out, "off", sizeof out); + break; + case SET_OPTION_CHOICE: + s = entry->choices[o->num]; + xsnprintf(out, sizeof out, "%s", s); + break; + } + return (out); +} + void set_option_string(struct cmd_ctx *ctx, struct options *oo, const struct set_option_entry *entry, char *value, int append) diff --git a/tmux.h b/tmux.h index 64409ae8..3f804b72 100644 --- a/tmux.h +++ b/tmux.h @@ -1238,6 +1238,8 @@ void tty_keys_free(struct tty *); int tty_keys_next(struct tty *, int *, u_char *); /* options-cmd.c */ +const char *set_option_print( + const struct set_option_entry *, struct options_entry *); void set_option_string(struct cmd_ctx *, struct options *, const struct set_option_entry *, char *, int); void set_option_number(struct cmd_ctx *, From 6b37b2d79d2fcf3af4d086272facebb0bb9c2df2 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 21 Sep 2009 14:56:03 +0000 Subject: [PATCH 0340/1180] Use option print function for info messages as well. --- options-cmd.c | 67 ++++++++++++++++++++++++++++++--------------------- options.c | 7 +++--- tmux.h | 5 ++-- 3 files changed, 46 insertions(+), 33 deletions(-) diff --git a/options-cmd.c b/options-cmd.c index 0e41a62c..649a89b2 100644 --- a/options-cmd.c +++ b/options-cmd.c @@ -67,7 +67,8 @@ void set_option_string(struct cmd_ctx *ctx, struct options *oo, const struct set_option_entry *entry, char *value, int append) { - char *oldvalue, *newvalue; + struct options_entry *o; + char *oldvalue, *newvalue; if (value == NULL) { ctx->error(ctx, "empty value"); @@ -80,8 +81,9 @@ set_option_string(struct cmd_ctx *ctx, struct options *oo, } else newvalue = value; - options_set_string(oo, entry->name, "%s", newvalue); - ctx->info(ctx, "set option: %s -> %s", entry->name, newvalue); + o = options_set_string(oo, entry->name, "%s", newvalue); + ctx->info( + ctx, "set option: %s -> %s", o->name, set_option_print(entry, o)); if (newvalue != value) xfree(newvalue); @@ -91,8 +93,9 @@ void set_option_number(struct cmd_ctx *ctx, struct options *oo, const struct set_option_entry *entry, char *value) { - long long number; - const char *errstr; + struct options_entry *o; + long long number; + const char *errstr; if (value == NULL) { ctx->error(ctx, "empty value"); @@ -104,15 +107,18 @@ set_option_number(struct cmd_ctx *ctx, struct options *oo, ctx->error(ctx, "value is %s: %s", errstr, value); return; } - options_set_number(oo, entry->name, number); - ctx->info(ctx, "set option: %s -> %lld", entry->name, number); + + o = options_set_number(oo, entry->name, number); + ctx->info( + ctx, "set option: %s -> %s", o->name, set_option_print(entry, o)); } void set_option_key(struct cmd_ctx *ctx, struct options *oo, const struct set_option_entry *entry, char *value) { - int key; + struct options_entry *o; + int key; if (value == NULL) { ctx->error(ctx, "empty value"); @@ -123,16 +129,18 @@ set_option_key(struct cmd_ctx *ctx, struct options *oo, ctx->error(ctx, "unknown key: %s", value); return; } - options_set_number(oo, entry->name, key); - ctx->info(ctx, - "set option: %s -> %s", entry->name, key_string_lookup_key(key)); + + o = options_set_number(oo, entry->name, key); + ctx->info( + ctx, "set option: %s -> %s", o->name, set_option_print(entry, o)); } void set_option_colour(struct cmd_ctx *ctx, struct options *oo, const struct set_option_entry *entry, char *value) { - int colour; + struct options_entry *o; + int colour; if (value == NULL) { ctx->error(ctx, "empty value"); @@ -144,16 +152,17 @@ set_option_colour(struct cmd_ctx *ctx, struct options *oo, return; } - options_set_number(oo, entry->name, colour); - ctx->info(ctx, - "set option: %s -> %s", entry->name, colour_tostring(colour)); + o = options_set_number(oo, entry->name, colour); + ctx->info( + ctx, "set option: %s -> %s", o->name, set_option_print(entry, o)); } void set_option_attributes(struct cmd_ctx *ctx, struct options *oo, const struct set_option_entry *entry, char *value) { - int attr; + struct options_entry *o; + int attr; if (value == NULL) { ctx->error(ctx, "empty value"); @@ -165,16 +174,17 @@ set_option_attributes(struct cmd_ctx *ctx, struct options *oo, return; } - options_set_number(oo, entry->name, attr); - ctx->info(ctx, - "set option: %s -> %s", entry->name, attributes_tostring(attr)); + o = options_set_number(oo, entry->name, attr); + ctx->info( + ctx, "set option: %s -> %s", o->name, set_option_print(entry, o)); } void set_option_flag(struct cmd_ctx *ctx, struct options *oo, const struct set_option_entry *entry, char *value) { - int flag; + struct options_entry *o; + int flag; if (value == NULL || *value == '\0') flag = !options_get_number(oo, entry->name); @@ -193,17 +203,18 @@ set_option_flag(struct cmd_ctx *ctx, struct options *oo, } } - options_set_number(oo, entry->name, flag); - ctx->info(ctx, - "set option: %s -> %s", entry->name, flag ? "on" : "off"); + o = options_set_number(oo, entry->name, flag); + ctx->info( + ctx, "set option: %s -> %s", o->name, set_option_print(entry, o)); } void set_option_choice(struct cmd_ctx *ctx, struct options *oo, const struct set_option_entry *entry, char *value) { - const char **choicep; - int n, choice = -1; + struct options_entry *o; + const char **choicep; + int n, choice = -1; if (value == NULL) { ctx->error(ctx, "empty value"); @@ -227,7 +238,7 @@ set_option_choice(struct cmd_ctx *ctx, struct options *oo, return; } - options_set_number(oo, entry->name, choice); - ctx->info(ctx, - "set option: %s -> %s", entry->name, entry->choices[choice]); + o = options_set_number(oo, entry->name, choice); + ctx->info( + ctx, "set option: %s -> %s", o->name, set_option_print(entry, o)); } diff --git a/options.c b/options.c index 90d9c88e..6ee4bf1d 100644 --- a/options.c +++ b/options.c @@ -98,7 +98,7 @@ options_remove(struct options *oo, const char *name) xfree(o); } -void printflike3 +struct options_entry *printflike3 options_set_string(struct options *oo, const char *name, const char *fmt, ...) { struct options_entry *o; @@ -115,6 +115,7 @@ options_set_string(struct options *oo, const char *name, const char *fmt, ...) o->type = OPTIONS_STRING; xvasprintf(&o->str, fmt, ap); va_end(ap); + return (o); } char * @@ -129,7 +130,7 @@ options_get_string(struct options *oo, const char *name) return (o->str); } -void +struct options_entry * options_set_number(struct options *oo, const char *name, long long value) { struct options_entry *o; @@ -143,7 +144,7 @@ options_set_number(struct options *oo, const char *name, long long value) o->type = OPTIONS_NUMBER; o->num = value; - + return (o); } long long diff --git a/tmux.h b/tmux.h index 3f804b72..e8e35ba1 100644 --- a/tmux.h +++ b/tmux.h @@ -1159,10 +1159,11 @@ 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 *); -void printflike3 options_set_string( +struct options_entry *printflike3 options_set_string( struct options *, const char *, const char *, ...); char *options_get_string(struct options *, const char *); -void 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 *); /* environ.c */ From a44852442404fc466015a08e5de03fa552e5eb2c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 21 Sep 2009 15:25:36 +0000 Subject: [PATCH 0341/1180] Nuke -i option which isn't used anymore. --- cmd-send-keys.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/cmd-send-keys.c b/cmd-send-keys.c index 037cbf33..ff41c1ee 100644 --- a/cmd-send-keys.c +++ b/cmd-send-keys.c @@ -33,7 +33,6 @@ size_t cmd_send_keys_print(struct cmd *, char *, size_t); struct cmd_send_keys_data { char *target; - int idx; u_int nkeys; int *keys; }; @@ -58,7 +57,6 @@ cmd_send_keys_parse(struct cmd *self, int argc, char **argv, char **cause) self->data = data = xmalloc(sizeof *data); data->target = NULL; - data->idx = -1; data->nkeys = 0; data->keys = NULL; @@ -143,8 +141,6 @@ cmd_send_keys_print(struct cmd *self, char *buf, size_t len) return (off); if (off < len && data->target != NULL) off += cmd_prarg(buf + off, len - off, " -t ", data->target); - if (off < len && data->idx != -1) - off += xsnprintf(buf + off, len - off, " -i %d", data->idx); for (i = 0; i < data->nkeys; i++) { if (off >= len) From 6fab9a3e6f0a18ce63662fceedb87e96f2680d83 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 21 Sep 2009 15:32:06 +0000 Subject: [PATCH 0342/1180] Use KEYC_NONE constant instead of 0 on init. --- cmd-command-prompt.c | 2 +- cmd-copy-buffer.c | 2 +- cmd-if-shell.c | 2 +- cmd-new-session.c | 2 +- cmd-new-window.c | 2 +- cmd-set-password.c | 2 +- cmd-source-file.c | 2 +- cmd-split-window.c | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/cmd-command-prompt.c b/cmd-command-prompt.c index 6aee2ec0..bcbde064 100644 --- a/cmd-command-prompt.c +++ b/cmd-command-prompt.c @@ -90,7 +90,7 @@ cmd_command_prompt_parse(struct cmd *self, int argc, char **argv, char **cause) struct cmd_command_prompt_data *data; int opt; - self->entry->init(self, 0); + self->entry->init(self, KEYC_NONE); data = self->data; while ((opt = getopt(argc, argv, "p:t:")) != -1) { diff --git a/cmd-copy-buffer.c b/cmd-copy-buffer.c index 695c909c..98166c4b 100644 --- a/cmd-copy-buffer.c +++ b/cmd-copy-buffer.c @@ -70,7 +70,7 @@ cmd_copy_buffer_parse(struct cmd *self, int argc, char **argv, char **cause) const char *errstr; int n, opt; - self->entry->init(self, 0); + self->entry->init(self, KEYC_NONE); data = self->data; while ((opt = getopt(argc, argv, "a:b:s:t:")) != -1) { diff --git a/cmd-if-shell.c b/cmd-if-shell.c index 86502a7f..e84efa84 100644 --- a/cmd-if-shell.c +++ b/cmd-if-shell.c @@ -66,7 +66,7 @@ cmd_if_shell_parse(struct cmd *self, int argc, char **argv, char **cause) struct cmd_if_shell_data *data; int opt; - self->entry->init(self, 0); + self->entry->init(self, KEYC_NONE); data = self->data; while ((opt = getopt(argc, argv, "")) != -1) { diff --git a/cmd-new-session.c b/cmd-new-session.c index 467fa879..2aafdb1b 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -69,7 +69,7 @@ cmd_new_session_parse(struct cmd *self, int argc, char **argv, char **cause) struct cmd_new_session_data *data; int opt; - self->entry->init(self, 0); + self->entry->init(self, KEYC_NONE); data = self->data; while ((opt = getopt(argc, argv, "ds:n:")) != -1) { diff --git a/cmd-new-window.c b/cmd-new-window.c index b3ec4379..bbffad14 100644 --- a/cmd-new-window.c +++ b/cmd-new-window.c @@ -70,7 +70,7 @@ cmd_new_window_parse(struct cmd *self, int argc, char **argv, char **cause) struct cmd_new_window_data *data; int opt; - self->entry->init(self, 0); + self->entry->init(self, KEYC_NONE); data = self->data; while ((opt = getopt(argc, argv, "dkt:n:")) != -1) { diff --git a/cmd-set-password.c b/cmd-set-password.c index 39b48eee..1a6da3f1 100644 --- a/cmd-set-password.c +++ b/cmd-set-password.c @@ -66,7 +66,7 @@ cmd_set_password_parse(struct cmd *self, int argc, char **argv, char **cause) int opt; char *out; - self->entry->init(self, 0); + self->entry->init(self, KEYC_NONE); data = self->data; while ((opt = getopt(argc, argv, "c")) != -1) { diff --git a/cmd-source-file.c b/cmd-source-file.c index 247b06ec..2cb47c6e 100644 --- a/cmd-source-file.c +++ b/cmd-source-file.c @@ -60,7 +60,7 @@ cmd_source_file_parse(struct cmd *self, int argc, char **argv, char **cause) struct cmd_source_file_data *data; int opt; - self->entry->init(self, 0); + self->entry->init(self, KEYC_NONE); data = self->data; while ((opt = getopt(argc, argv, "")) != -1) { diff --git a/cmd-split-window.c b/cmd-split-window.c index 1604d9e2..a1a012a2 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -84,7 +84,7 @@ cmd_split_window_parse(struct cmd *self, int argc, char **argv, char **cause) int opt; const char *errstr; - self->entry->init(self, 0); + self->entry->init(self, KEYC_NONE); data = self->data; while ((opt = getopt(argc, argv, "dhl:p:t:v")) != -1) { From 96dd3e8eb9bbe5393050acfd4ac7759ae27d00c8 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 22 Sep 2009 12:38:10 +0000 Subject: [PATCH 0343/1180] Permit multiple prefix keys to be defined, separated by commas, for example: set -g prefix ^a,^b Any key in the list acts as the prefix. The send-prefix command always sends the first key in the list. --- cmd-send-prefix.c | 6 +++--- cmd-set-option.c | 6 +++--- cmd-set-window-option.c | 4 ++-- options-cmd.c | 39 +++++++++++++++++++++++++++++---------- options.c | 41 +++++++++++++++++++++++++++++++++++++++++ server.c | 22 ++++++++++++++++------ tmux.1 | 8 ++++++-- tmux.c | 7 ++++++- tmux.h | 14 ++++++++++++-- 9 files changed, 118 insertions(+), 29 deletions(-) diff --git a/cmd-send-prefix.c b/cmd-send-prefix.c index aeefc701..a149fdac 100644 --- a/cmd-send-prefix.c +++ b/cmd-send-prefix.c @@ -43,13 +43,13 @@ cmd_send_prefix_exec(struct cmd *self, struct cmd_ctx *ctx) struct cmd_target_data *data = self->data; struct session *s; struct window_pane *wp; - int key; + struct keylist *keylist; if (cmd_find_pane(ctx, data->target, &s, &wp) == NULL) return (-1); - key = options_get_number(&s->options, "prefix"); - window_pane_key(wp, ctx->curclient, key); + keylist = options_get_data(&s->options, "prefix"); + window_pane_key(wp, ctx->curclient, ARRAY_FIRST(keylist)); return (0); } diff --git a/cmd-set-option.c b/cmd-set-option.c index 254a5767..3a6bf022 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -65,7 +65,7 @@ const struct set_option_entry set_option_table[] = { { "message-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL }, { "message-bg", SET_OPTION_COLOUR, 0, 0, NULL }, { "message-fg", SET_OPTION_COLOUR, 0, 0, NULL }, - { "prefix", SET_OPTION_KEY, 0, 0, NULL }, + { "prefix", SET_OPTION_KEYS, 0, 0, NULL }, { "repeat-time", SET_OPTION_NUMBER, 0, SHRT_MAX, NULL }, { "set-remain-on-exit", SET_OPTION_FLAG, 0, 0, NULL }, { "set-titles", SET_OPTION_FLAG, 0, 0, NULL }, @@ -162,8 +162,8 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) case SET_OPTION_NUMBER: set_option_number(ctx, oo, entry, data->arg2); break; - case SET_OPTION_KEY: - set_option_key(ctx, oo, entry, data->arg2); + case SET_OPTION_KEYS: + set_option_keys(ctx, oo, entry, data->arg2); break; case SET_OPTION_COLOUR: set_option_colour(ctx, oo, entry, data->arg2); diff --git a/cmd-set-window-option.c b/cmd-set-window-option.c index 01e10a35..76d00e19 100644 --- a/cmd-set-window-option.c +++ b/cmd-set-window-option.c @@ -140,8 +140,8 @@ cmd_set_window_option_exec(struct cmd *self, struct cmd_ctx *ctx) case SET_OPTION_NUMBER: set_option_number(ctx, oo, entry, data->arg2); break; - case SET_OPTION_KEY: - set_option_key(ctx, oo, entry, data->arg2); + case SET_OPTION_KEYS: + set_option_keys(ctx, oo, entry, data->arg2); break; case SET_OPTION_COLOUR: set_option_colour(ctx, oo, entry, data->arg2); diff --git a/options-cmd.c b/options-cmd.c index 649a89b2..8c0e0d1a 100644 --- a/options-cmd.c +++ b/options-cmd.c @@ -28,6 +28,8 @@ set_option_print(const struct set_option_entry *entry, struct options_entry *o) { static char out[BUFSIZ]; const char *s; + struct keylist *keylist; + u_int i; *out = '\0'; switch (entry->type) { @@ -37,9 +39,14 @@ set_option_print(const struct set_option_entry *entry, struct options_entry *o) case SET_OPTION_NUMBER: xsnprintf(out, sizeof out, "%lld", o->num); break; - case SET_OPTION_KEY: - s = key_string_lookup_key(o->num); - xsnprintf(out, sizeof out, "%s", s); + case SET_OPTION_KEYS: + keylist = o->data; + for (i = 0; i < ARRAY_LENGTH(keylist); i++) { + strlcat(out, key_string_lookup_key( + ARRAY_ITEM(keylist, i)), sizeof out); + if (i != ARRAY_LENGTH(keylist) - 1) + strlcat(out, ",", sizeof out); + } break; case SET_OPTION_COLOUR: s = colour_tostring(o->num); @@ -114,23 +121,35 @@ set_option_number(struct cmd_ctx *ctx, struct options *oo, } void -set_option_key(struct cmd_ctx *ctx, struct options *oo, +set_option_keys(struct cmd_ctx *ctx, struct options *oo, const struct set_option_entry *entry, char *value) { struct options_entry *o; - int key; + struct keylist *keylist; + char *copyvalue, *ptr, *str; + int key; if (value == NULL) { ctx->error(ctx, "empty value"); return; } - if ((key = key_string_lookup_string(value)) == KEYC_NONE) { - ctx->error(ctx, "unknown key: %s", value); - return; - } + keylist = xmalloc(sizeof *keylist); + ARRAY_INIT(keylist); - o = options_set_number(oo, entry->name, key); + ptr = copyvalue = xstrdup(value); + while ((str = strsep(&ptr, ",")) != NULL) { + if ((key = key_string_lookup_string(str)) == KEYC_NONE) { + xfree(keylist); + ctx->error(ctx, "unknown key: %s", str); + xfree(copyvalue); + return; + } + ARRAY_ADD(keylist, key); + } + xfree(copyvalue); + + o = options_set_data(oo, entry->name, keylist, xfree); ctx->info( ctx, "set option: %s -> %s", o->name, set_option_print(entry, o)); } diff --git a/options.c b/options.c index 6ee4bf1d..f7efdc29 100644 --- a/options.c +++ b/options.c @@ -54,6 +54,8 @@ options_free(struct options *oo) xfree(o->name); if (o->type == OPTIONS_STRING) xfree(o->str); + else if (o->type == OPTIONS_DATA) + o->freefn(o->data); xfree(o); } } @@ -95,6 +97,8 @@ options_remove(struct options *oo, const char *name) xfree(o->name); if (o->type == OPTIONS_STRING) xfree(o->str); + else if (o->type == OPTIONS_DATA) + o->freefn(o->data); xfree(o); } @@ -110,6 +114,8 @@ options_set_string(struct options *oo, const char *name, const char *fmt, ...) SPLAY_INSERT(options_tree, &oo->tree, o); } else if (o->type == OPTIONS_STRING) xfree(o->str); + else if (o->type == OPTIONS_DATA) + o->freefn(o->data); va_start(ap, fmt); o->type = OPTIONS_STRING; @@ -141,6 +147,8 @@ options_set_number(struct options *oo, const char *name, long long value) SPLAY_INSERT(options_tree, &oo->tree, o); } else if (o->type == OPTIONS_STRING) xfree(o->str); + else if (o->type == OPTIONS_DATA) + o->freefn(o->data); o->type = OPTIONS_NUMBER; o->num = value; @@ -158,3 +166,36 @@ options_get_number(struct options *oo, const char *name) fatalx("option not a number"); return (o->num); } + +struct options_entry * +options_set_data( + struct options *oo, const char *name, void *value, void (*freefn)(void *)) +{ + struct options_entry *o; + + if ((o = options_find1(oo, name)) == NULL) { + o = xmalloc(sizeof *o); + o->name = xstrdup(name); + SPLAY_INSERT(options_tree, &oo->tree, o); + } else if (o->type == OPTIONS_STRING) + xfree(o->str); + else if (o->type == OPTIONS_DATA) + o->freefn(o->data); + + o->type = OPTIONS_DATA; + o->data = value; + o->freefn = freefn; + return (o); +} + +void * +options_get_data(struct options *oo, const char *name) +{ + struct options_entry *o; + + if ((o = options_find(oo, name)) == NULL) + fatalx("missing option"); + if (o->type != OPTIONS_DATA) + fatalx("option not data"); + return (o->data); +} diff --git a/server.c b/server.c index 73998042..cb69df0f 100644 --- a/server.c +++ b/server.c @@ -798,8 +798,9 @@ server_handle_client(struct client *c) struct screen *s; struct timeval tv; struct key_binding *bd; - int key, prefix, status, xtimeout; - int mode; + struct keylist *keylist; + int key, status, xtimeout, mode, isprefix; + u_int i; u_char mouse[3]; xtimeout = options_get_number(&c->session->options, "repeat-time"); @@ -811,7 +812,7 @@ server_handle_client(struct client *c) } /* Process keys. */ - prefix = options_get_number(&c->session->options, "prefix"); + keylist = options_get_data(&c->session->options, "prefix"); while (tty_keys_next(&c->tty, &key, mouse) == 0) { server_activity = time(NULL); @@ -844,9 +845,18 @@ server_handle_client(struct client *c) continue; } + /* Is this a prefix key? */ + isprefix = 0; + for (i = 0; i < ARRAY_LENGTH(keylist); i++) { + if (key == ARRAY_ITEM(keylist, i)) { + isprefix = 1; + break; + } + } + /* No previous prefix key. */ if (!(c->flags & CLIENT_PREFIX)) { - if (key == prefix) + if (isprefix) c->flags |= CLIENT_PREFIX; else { /* Try as a non-prefix key binding. */ @@ -864,7 +874,7 @@ server_handle_client(struct client *c) /* If repeating, treat this as a key, else ignore. */ if (c->flags & CLIENT_REPEAT) { c->flags &= ~CLIENT_REPEAT; - if (key == prefix) + if (isprefix) c->flags |= CLIENT_PREFIX; else window_pane_key(wp, c, key); @@ -875,7 +885,7 @@ server_handle_client(struct client *c) /* If already repeating, but this key can't repeat, skip it. */ if (c->flags & CLIENT_REPEAT && !bd->can_repeat) { c->flags &= ~CLIENT_REPEAT; - if (key == prefix) + if (isprefix) c->flags |= CLIENT_PREFIX; else window_pane_key(wp, c, key); diff --git a/tmux.1 b/tmux.1 index 6d833238..802b0fd9 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1048,6 +1048,7 @@ characters. All arguments are sent sequentially from first to last. .It Ic send-prefix Op Fl t Ar target-pane Send the prefix key to a window as if it was pressed. +If multiple prefix keys are configured, only the first is sent. .It Xo Ic unbind-key .Op Fl cn .Op Fl t Ar key-table @@ -1258,8 +1259,11 @@ from the 256-colour palette, or .Ic default . .It Ic message-fg Ar colour Set status line message foreground colour. -.It Ic prefix Ar key -Set the current prefix key. +.It Ic prefix Ar keys +Set the keys accepted as a prefix key. +.Ar keys +is a comma-separated list of key names, each of which individually behave as +the prefix key. .It Ic repeat-time Ar time Allow multiple commands to be entered without pressing the prefix-key again in the specified diff --git a/tmux.c b/tmux.c index d75de607..02657e32 100644 --- a/tmux.c +++ b/tmux.c @@ -309,6 +309,7 @@ main(int argc, char **argv) enum msgtype msg; struct passwd *pw; struct options *so, *wo; + struct keylist *keylist; char *s, *path, *label, *home, *cause, **var; char cwd[MAXPATHLEN]; void *buf; @@ -409,7 +410,6 @@ main(int argc, char **argv) options_set_number(so, "message-attr", 0); options_set_number(so, "message-bg", 3); options_set_number(so, "message-fg", 0); - options_set_number(so, "prefix", '\002'); options_set_number(so, "repeat-time", 500); options_set_number(so, "set-remain-on-exit", 0); options_set_number(so, "set-titles", 0); @@ -439,6 +439,11 @@ main(int argc, char **argv) options_set_number(so, "visual-bell", 0); options_set_number(so, "visual-content", 0); + keylist = xmalloc(sizeof *keylist); + ARRAY_INIT(keylist); + ARRAY_ADD(keylist, '\002'); + options_set_data(so, "prefix", keylist, xfree); + options_init(&global_w_options, NULL); wo = &global_w_options; options_set_number(wo, "aggressive-resize", 0); diff --git a/tmux.h b/tmux.h index e8e35ba1..0ffb0b53 100644 --- a/tmux.h +++ b/tmux.h @@ -544,10 +544,14 @@ struct options_entry { enum { OPTIONS_STRING, OPTIONS_NUMBER, + OPTIONS_DATA, } type; char *str; long long num; + void *data; + + void (*freefn)(void *); SPLAY_ENTRY(options_entry) entry; }; @@ -557,6 +561,9 @@ struct options { struct options *parent; }; +/* Key list for prefix option. */ +ARRAY_DECL(keylist, int); + /* Screen selection. */ struct screen_sel { int flag; @@ -1085,7 +1092,7 @@ struct set_option_entry { enum { SET_OPTION_STRING, SET_OPTION_NUMBER, - SET_OPTION_KEY, + SET_OPTION_KEYS, SET_OPTION_COLOUR, SET_OPTION_ATTRIBUTES, SET_OPTION_FLAG, @@ -1165,6 +1172,9 @@ char *options_get_string(struct options *, const char *); 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_data( + struct options *, const char *, void *, void (*)(void *)); +void *options_get_data(struct options *, const char *); /* environ.c */ int environ_cmp(struct environ_entry *, struct environ_entry *); @@ -1245,7 +1255,7 @@ void set_option_string(struct cmd_ctx *, struct options *, const struct set_option_entry *, char *, int); void set_option_number(struct cmd_ctx *, struct options *, const struct set_option_entry *, char *); -void set_option_key(struct cmd_ctx *, +void set_option_keys(struct cmd_ctx *, struct options *, const struct set_option_entry *, char *); void set_option_colour(struct cmd_ctx *, struct options *, const struct set_option_entry *, char *); From 0a9005678da04b1e7783d26b02041e3973f26127 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 22 Sep 2009 19:11:52 +0000 Subject: [PATCH 0344/1180] Be more careful about what flags are cleared when opening the terminal, otherwise the opened/started flags are cleared and the terminal never released. --- tty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tty.c b/tty.c index 3d2d17d3..b0810219 100644 --- a/tty.c +++ b/tty.c @@ -93,7 +93,7 @@ tty_open(struct tty *tty, const char *overrides, char **cause) tty->in = buffer_create(BUFSIZ); tty->out = buffer_create(BUFSIZ); - tty->flags &= TTY_UTF8; + tty->flags &= ~(TTY_NOCURSOR|TTY_FREEZE|TTY_ESCAPE); tty_start_tty(tty); From 64caf59e84c3ae1c06773bb8ec91165eeedabe6d Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 23 Sep 2009 06:05:02 +0000 Subject: [PATCH 0345/1180] Don't attempt to open() the tty path, rely on the client sending its stdin fd with imsg and fatal if it doesn't, then set the FD_CLOEXEC flag in tty_init instead of tty_open to prevent them leaking into child processes if any are created between the two calls. This bumps the protocol version, so the tmux server should be killed before upgrading. --- client.c | 11 +++-------- server-msg.c | 19 ++++++++++--------- tmux.h | 6 ++---- tty.c | 46 ++++++++++++++++++++++++---------------------- 4 files changed, 39 insertions(+), 43 deletions(-) diff --git a/client.c b/client.c index 05d5b606..ee3bba50 100644 --- a/client.c +++ b/client.c @@ -45,7 +45,7 @@ client_init(char *path, struct client_ctx *cctx, int cmdflags, int flags) struct winsize ws; size_t size; int fd, fd2, mode; - char *name, *term; + char *term; char rpathbuf[MAXPATHLEN]; if (realpath(path, rpathbuf) == NULL) @@ -113,13 +113,8 @@ server_started: *data.term = '\0'; } - *data.tty = '\0'; - if ((name = ttyname(STDIN_FILENO)) == NULL) - fatal("ttyname failed"); - if (strlcpy(data.tty, name, sizeof data.tty) >= sizeof data.tty) - fatalx("ttyname failed"); - - fd2 = dup(STDIN_FILENO); + if ((fd2 = dup(STDIN_FILENO)) == -1) + fatal("dup failed"); imsg_compose(&cctx->ibuf, MSG_IDENTIFY, PROTOCOL_VERSION, -1, fd2, &data, sizeof data); } diff --git a/server-msg.c b/server-msg.c index cb5dbf06..cf0f346c 100644 --- a/server-msg.c +++ b/server-msg.c @@ -74,6 +74,8 @@ server_msg_dispatch(struct client *c) case MSG_IDENTIFY: if (datalen != sizeof identifydata) fatalx("bad MSG_IDENTIFY size"); + if (imsg.fd == -1) + fatalx("MSG_IDENTIFY missing fd"); memcpy(&identifydata, imsg.data, sizeof identifydata); server_msg_identify(c, &identifydata, imsg.fd); @@ -243,21 +245,13 @@ error: void server_msg_identify(struct client *c, struct msg_identify_data *data, int fd) { - c->tty.sx = data->sx; - if (c->tty.sx == 0) - c->tty.sx = 80; - c->tty.sy = data->sy; - if (c->tty.sy == 0) - c->tty.sy = 24; - c->cwd = NULL; data->cwd[(sizeof data->cwd) - 1] = '\0'; if (*data->cwd != '\0') c->cwd = xstrdup(data->cwd); - data->tty[(sizeof data->tty) - 1] = '\0'; data->term[(sizeof data->term) - 1] = '\0'; - tty_init(&c->tty, fd, data->tty, data->term); + tty_init(&c->tty, fd, data->term); if (data->flags & IDENTIFY_UTF8) c->tty.flags |= TTY_UTF8; if (data->flags & IDENTIFY_256COLOURS) @@ -267,6 +261,13 @@ server_msg_identify(struct client *c, struct msg_identify_data *data, int fd) if (data->flags & IDENTIFY_HASDEFAULTS) c->tty.term_flags |= TERM_HASDEFAULTS; + c->tty.sx = data->sx; + if (c->tty.sx == 0) + c->tty.sx = 80; + c->tty.sy = data->sy; + if (c->tty.sy == 0) + c->tty.sy = 24; + c->flags |= CLIENT_TERMINAL; } diff --git a/tmux.h b/tmux.h index 0ffb0b53..bdaf5f6e 100644 --- a/tmux.h +++ b/tmux.h @@ -19,7 +19,7 @@ #ifndef TMUX_H #define TMUX_H -#define PROTOCOL_VERSION 1 +#define PROTOCOL_VERSION 2 #include #include @@ -328,8 +328,6 @@ struct msg_command_data { }; struct msg_identify_data { - char tty[TTY_NAME_MAX]; - char cwd[MAXPATHLEN]; char term[TERMINAL_LENGTH]; @@ -1200,7 +1198,7 @@ void tty_putcode2(struct tty *, enum tty_code_code, int, int); void tty_puts(struct tty *, const char *); void tty_putc(struct tty *, u_char); void tty_pututf8(struct tty *, const struct grid_utf8 *); -void tty_init(struct tty *, int, char *, char *); +void tty_init(struct tty *, int, char *); void tty_start_tty(struct tty *); void tty_stop_tty(struct tty *); void tty_detect_utf8(struct tty *); diff --git a/tty.c b/tty.c index b0810219..574e9a7b 100644 --- a/tty.c +++ b/tty.c @@ -44,16 +44,31 @@ void tty_cell(struct tty *, const struct grid_cell *, const struct grid_utf8 *); void -tty_init(struct tty *tty, int fd, char *path, char *term) +tty_init(struct tty *tty, int fd, char *term) { - tty->path = xstrdup(path); - tty->fd = fd; + int mode; + char *path; + + memset(tty, 0, sizeof *tty); tty->log_fd = -1; if (term == NULL || *term == '\0') tty->termname = xstrdup("unknown"); else tty->termname = xstrdup(term); + + if ((mode = fcntl(fd, F_GETFL)) == -1) + fatal("fcntl failed"); + if (fcntl(fd, F_SETFL, mode|O_NONBLOCK) == -1) + fatal("fcntl failed"); + if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) + fatal("fcntl failed"); + tty->fd = fd; + + if ((path = ttyname(fd)) == NULL) + fatalx("ttyname failed"); + tty->path = xstrdup(path); + tty->flags = 0; tty->term_flags = 0; } @@ -61,28 +76,15 @@ tty_init(struct tty *tty, int fd, char *path, char *term) int tty_open(struct tty *tty, const char *overrides, char **cause) { - int mode; + int fd; - if (tty->fd == -1) { - tty->fd = open(tty->path, O_RDWR|O_NONBLOCK); - if (tty->fd == -1) { - xasprintf(cause, "%s: %s", tty->path, strerror(errno)); - return (-1); - } + if (debug_level > 3) { + fd = open("tmux.out", O_WRONLY|O_CREAT|O_TRUNC, 0644); + if (fd != -1 && fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) + fatal("fcntl failed"); + tty->log_fd = fd; } - if ((mode = fcntl(tty->fd, F_GETFL)) == -1) - fatal("fcntl failed"); - if (fcntl(tty->fd, F_SETFL, mode|O_NONBLOCK) == -1) - fatal("fcntl failed"); - if (fcntl(tty->fd, F_SETFD, FD_CLOEXEC) == -1) - fatal("fcntl failed"); - - if (debug_level > 3) - tty->log_fd = open("tmux.out", O_WRONLY|O_CREAT|O_TRUNC, 0644); - else - tty->log_fd = -1; - tty->term = tty_term_find(tty->termname, tty->fd, overrides, cause); if (tty->term == NULL) { tty_close(tty); From 962fa20b36cc6d38d9a44612441f3f706c29b71e Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 23 Sep 2009 06:12:58 +0000 Subject: [PATCH 0346/1180] Trim some code by moving the ioctl(TIOCGWINSZ) after SIGWINCH from the client into the server. This is another (the second of four) protocol version changes coming this morning, so again the server should be killed before upgrading. --- client.c | 25 ++++--------------------- server-msg.c | 38 ++++++-------------------------------- tmux.h | 11 ++--------- tty.c | 21 +++++++++++++++++++++ 4 files changed, 33 insertions(+), 62 deletions(-) diff --git a/client.c b/client.c index ee3bba50..7ef61106 100644 --- a/client.c +++ b/client.c @@ -34,7 +34,6 @@ #include "tmux.h" void client_send_environ(struct client_ctx *); -void client_handle_winch(struct client_ctx *); int client_init(char *path, struct client_ctx *cctx, int cmdflags, int flags) @@ -100,8 +99,6 @@ server_started: if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1) fatal("ioctl(TIOCGWINSZ)"); data.flags = flags; - data.sx = ws.ws_col; - data.sy = ws.ws_row; if (getcwd(data.cwd, sizeof data.cwd) == NULL) *data.cwd = '\0'; @@ -169,8 +166,10 @@ client_main(struct client_ctx *cctx) waitpid(WAIT_ANY, NULL, WNOHANG); sigchld = 0; } - if (sigwinch) - client_handle_winch(cctx); + if (sigwinch) { + client_write_server(cctx, MSG_RESIZE, NULL, 0); + sigwinch = 0; + } if (sigcont) { siginit(); client_write_server(cctx, MSG_WAKEUP, NULL, 0); @@ -238,22 +237,6 @@ out: } } -void -client_handle_winch(struct client_ctx *cctx) -{ - struct msg_resize_data data; - struct winsize ws; - - if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1) - fatal("ioctl failed"); - - data.sx = ws.ws_col; - data.sy = ws.ws_row; - client_write_server(cctx, MSG_RESIZE, &data, sizeof data); - - sigwinch = 0; -} - int client_msg_dispatch(struct client_ctx *cctx) { diff --git a/server-msg.c b/server-msg.c index cf0f346c..7f88e262 100644 --- a/server-msg.c +++ b/server-msg.c @@ -17,6 +17,7 @@ */ #include +#include #include #include @@ -28,7 +29,6 @@ void server_msg_command(struct client *, struct msg_command_data *); void server_msg_identify(struct client *, struct msg_identify_data *, int); -void server_msg_resize(struct client *, struct msg_resize_data *); void printflike2 server_msg_command_error(struct cmd_ctx *, const char *, ...); void printflike2 server_msg_command_print(struct cmd_ctx *, const char *, ...); @@ -40,7 +40,6 @@ server_msg_dispatch(struct client *c) struct imsg imsg; struct msg_command_data commanddata; struct msg_identify_data identifydata; - struct msg_resize_data resizedata; struct msg_unlock_data unlockdata; struct msg_environ_data environdata; ssize_t n, datalen; @@ -81,11 +80,12 @@ server_msg_dispatch(struct client *c) server_msg_identify(c, &identifydata, imsg.fd); break; case MSG_RESIZE: - if (datalen != sizeof resizedata) + if (datalen != 0) fatalx("bad MSG_RESIZE size"); - memcpy(&resizedata, imsg.data, sizeof resizedata); - server_msg_resize(c, &resizedata); + tty_resize(&c->tty); + recalculate_sizes(); + server_redraw_client(c); break; case MSG_EXITING: if (datalen != 0) @@ -261,33 +261,7 @@ server_msg_identify(struct client *c, struct msg_identify_data *data, int fd) if (data->flags & IDENTIFY_HASDEFAULTS) c->tty.term_flags |= TERM_HASDEFAULTS; - c->tty.sx = data->sx; - if (c->tty.sx == 0) - c->tty.sx = 80; - c->tty.sy = data->sy; - if (c->tty.sy == 0) - c->tty.sy = 24; + tty_resize(&c->tty); c->flags |= CLIENT_TERMINAL; } - -void -server_msg_resize(struct client *c, struct msg_resize_data *data) -{ - c->tty.sx = data->sx; - if (c->tty.sx == 0) - c->tty.sx = 80; - c->tty.sy = data->sy; - if (c->tty.sy == 0) - c->tty.sy = 24; - - c->tty.cx = UINT_MAX; - c->tty.cy = UINT_MAX; - c->tty.rupper = UINT_MAX; - c->tty.rlower = UINT_MAX; - - recalculate_sizes(); - - /* Always redraw this client. */ - server_redraw_client(c); -} diff --git a/tmux.h b/tmux.h index bdaf5f6e..6325bca2 100644 --- a/tmux.h +++ b/tmux.h @@ -19,7 +19,7 @@ #ifndef TMUX_H #define TMUX_H -#define PROTOCOL_VERSION 2 +#define PROTOCOL_VERSION 3 #include #include @@ -337,14 +337,6 @@ struct msg_identify_data { #define IDENTIFY_88COLOURS 0x4 #define IDENTIFY_HASDEFAULTS 0x8 int flags; - - u_int sx; - u_int sy; -}; - -struct msg_resize_data { - u_int sx; - u_int sy; }; struct msg_unlock_data { @@ -1199,6 +1191,7 @@ void tty_puts(struct tty *, const char *); void tty_putc(struct tty *, u_char); void tty_pututf8(struct tty *, const struct grid_utf8 *); void tty_init(struct tty *, int, char *); +void tty_resize(struct tty *); void tty_start_tty(struct tty *); void tty_stop_tty(struct tty *); void tty_detect_utf8(struct tty *); diff --git a/tty.c b/tty.c index 574e9a7b..12535f94 100644 --- a/tty.c +++ b/tty.c @@ -73,6 +73,27 @@ tty_init(struct tty *tty, int fd, char *term) tty->term_flags = 0; } +void +tty_resize(struct tty *tty) +{ + struct winsize ws; + + if (ioctl(tty->fd, TIOCGWINSZ, &ws) != -1) { + tty->sx = ws.ws_col; + tty->sy = ws.ws_row; + } + if (tty->sx == 0) + tty->sx = 80; + if (tty->sy == 0) + tty->sy = 24; + + tty->cx = UINT_MAX; + tty->cy = UINT_MAX; + + tty->rupper = UINT_MAX; + tty->rlower = UINT_MAX; +} + int tty_open(struct tty *tty, const char *overrides, char **cause) { From b01dcd79715d968cb39dc892215c2f6921d43974 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 23 Sep 2009 06:18:47 +0000 Subject: [PATCH 0347/1180] Remove the internal tmux locking and instead detach each client and run the command specified by a new option "lock-command" (by default "lock -np") in each client. This means each terminal has to be unlocked individually but simplifies the code and allows the system password to be used to unlock. Note that the set-password command is gone, so it will need to be removed from configuration files, and the -U command line flag has been removed. This is the third protocol version change so again it is best to stop the tmux server before upgrading. --- Makefile | 2 +- client.c | 10 ++++ cmd-set-option.c | 1 + cmd-set-password.c | 145 --------------------------------------------- cmd.c | 5 -- server-fn.c | 110 ++++------------------------------ server-msg.c | 21 +------ server.c | 83 +------------------------- status.c | 9 --- tmux.1 | 40 ++++--------- tmux.c | 58 +++--------------- tmux.h | 18 +++--- tty.c | 2 - 13 files changed, 55 insertions(+), 449 deletions(-) delete mode 100644 cmd-set-password.c diff --git a/Makefile b/Makefile index c2a51436..f35149df 100644 --- a/Makefile +++ b/Makefile @@ -20,7 +20,7 @@ SRCS= attributes.c buffer-poll.c buffer.c cfg.c client-fn.c \ cmd-scroll-mode.c cmd-select-layout.c cmd-select-pane.c \ cmd-select-prompt.c cmd-select-window.c cmd-send-keys.c \ cmd-send-prefix.c cmd-server-info.c cmd-set-buffer.c cmd-set-option.c \ - cmd-set-password.c cmd-set-window-option.c cmd-show-buffer.c \ + cmd-set-window-option.c cmd-show-buffer.c \ cmd-show-options.c cmd-show-window-options.c cmd-source-file.c \ cmd-split-window.c cmd-start-server.c cmd-string.c cmd-if-shell.c \ cmd-run-shell.c cmd-suspend-client.c cmd-swap-pane.c cmd-swap-window.c \ diff --git a/client.c b/client.c index 7ef61106..ceb054bb 100644 --- a/client.c +++ b/client.c @@ -242,6 +242,7 @@ client_msg_dispatch(struct client_ctx *cctx) { struct imsg imsg; struct msg_print_data printdata; + struct msg_lock_data lockdata; ssize_t n, datalen; for (;;) { @@ -295,6 +296,15 @@ client_msg_dispatch(struct client_ctx *cctx) client_suspend(); break; + case MSG_LOCK: + if (datalen != sizeof lockdata) + fatalx("bad MSG_LOCK size"); + memcpy(&lockdata, imsg.data, sizeof lockdata); + + lockdata.cmd[(sizeof lockdata.cmd) - 1] = '\0'; + system(lockdata.cmd); + client_write_server(cctx, MSG_UNLOCK, NULL, 0); + break; default: fatalx("unexpected message"); } diff --git a/cmd-set-option.c b/cmd-set-option.c index 3a6bf022..4984cb1a 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -62,6 +62,7 @@ const struct set_option_entry set_option_table[] = { { "display-time", SET_OPTION_NUMBER, 1, INT_MAX, NULL }, { "history-limit", SET_OPTION_NUMBER, 0, INT_MAX, NULL }, { "lock-after-time", SET_OPTION_NUMBER, 0, INT_MAX, NULL }, + { "lock-command", SET_OPTION_STRING, 0, 0, NULL }, { "message-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL }, { "message-bg", SET_OPTION_COLOUR, 0, 0, NULL }, { "message-fg", SET_OPTION_COLOUR, 0, 0, NULL }, diff --git a/cmd-set-password.c b/cmd-set-password.c deleted file mode 100644 index 1a6da3f1..00000000 --- a/cmd-set-password.c +++ /dev/null @@ -1,145 +0,0 @@ -/* $OpenBSD$ */ - -/* - * Copyright (c) 2009 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 "tmux.h" - -/* - * Set server password. - */ - -int cmd_set_password_parse(struct cmd *, int, char **, char **); -int cmd_set_password_exec(struct cmd *, struct cmd_ctx *); -void cmd_set_password_free(struct cmd *); -void cmd_set_password_init(struct cmd *, int); -size_t cmd_set_password_print(struct cmd *, char *, size_t); - -struct cmd_set_password_data { - char *password; - int flag_encrypted; -}; - -const struct cmd_entry cmd_set_password_entry = { - "set-password", "pass", - "[-c] password", - 0, 0, - cmd_set_password_init, - cmd_set_password_parse, - cmd_set_password_exec, - cmd_set_password_free, - cmd_set_password_print -}; - -void -cmd_set_password_init(struct cmd *self, unused int arg) -{ - struct cmd_set_password_data *data; - - self->data = data = xmalloc(sizeof *data); - data->password = NULL; - data->flag_encrypted = 0; -} - -int -cmd_set_password_parse(struct cmd *self, int argc, char **argv, char **cause) -{ - struct cmd_set_password_data *data; - int opt; - char *out; - - self->entry->init(self, KEYC_NONE); - data = self->data; - - while ((opt = getopt(argc, argv, "c")) != -1) { - switch (opt) { - case 'c': - data->flag_encrypted = 1; - break; - default: - goto usage; - } - } - argc -= optind; - argv += optind; - if (argc != 1) - goto usage; - - if (!data->flag_encrypted) { - if ((out = crypt(argv[0], "$1")) != NULL) - data->password = xstrdup(out); - } else - data->password = xstrdup(argv[0]); - - return (0); - -usage: - xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); - - self->entry->free(self); - return (-1); -} - -int -cmd_set_password_exec(struct cmd *self, struct cmd_ctx *ctx) -{ - struct cmd_set_password_data *data = self->data; - - if (data->password == NULL) { - ctx->error(ctx, "failed to encrypt password"); - return (-1); - } - - if (server_password != NULL) - xfree(server_password); - if (*data->password == '\0') - server_password = NULL; - else - server_password = xstrdup(data->password); - - return (0); -} - -void -cmd_set_password_free(struct cmd *self) -{ - struct cmd_set_password_data *data = self->data; - - if (data->password != NULL) - xfree(data->password); - xfree(data); -} - -size_t -cmd_set_password_print(struct cmd *self, char *buf, size_t len) -{ - struct cmd_set_password_data *data = self->data; - size_t off = 0; - - off += xsnprintf(buf, len, "%s", self->entry->name); - if (data == NULL) - return (off); - if (off < len && data->flag_encrypted) - off += xsnprintf(buf + off, len - off, " -c"); - if (off < len && data->password != NULL) - off += xsnprintf(buf + off, len - off, " password"); - return (off); -} diff --git a/cmd.c b/cmd.c index a391945d..d027cd9c 100644 --- a/cmd.c +++ b/cmd.c @@ -89,7 +89,6 @@ const struct cmd_entry *cmd_table[] = { &cmd_set_buffer_entry, &cmd_set_environment_entry, &cmd_set_option_entry, - &cmd_set_password_entry, &cmd_set_window_option_entry, &cmd_show_buffer_entry, &cmd_show_environment_entry, @@ -260,10 +259,6 @@ usage: int cmd_exec(struct cmd *cmd, struct cmd_ctx *ctx) { - if (server_locked) { - ctx->error(ctx, "server is locked"); - return (-1); - } return (cmd->entry->exec(cmd, ctx)); } diff --git a/server-fn.c b/server-fn.c index e3cee410..b9be1794 100644 --- a/server-fn.c +++ b/server-fn.c @@ -18,16 +18,12 @@ #include -#include -#include #include #include #include #include "tmux.h" -int server_lock_callback(void *, const char *); - void server_fill_environ(struct session *s, struct environ *env) { @@ -161,110 +157,30 @@ server_status_window(struct window *w) void server_lock(void) { - struct client *c; - static struct passwd *pw, pwstore; - static char pwbuf[_PW_BUF_LEN]; - u_int i; - - if (server_locked) - return; - - if (getpwuid_r(getuid(), &pwstore, pwbuf, sizeof pwbuf, &pw) != 0) { - server_locked_pw = NULL; - return; - } - server_locked_pw = pw; + struct client *c; + const char *cmd; + struct msg_lock_data lockdata; + u_int i; for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); if (c == NULL || c->session == NULL) continue; - - status_prompt_clear(c); - status_prompt_set(c, - "Password:", server_lock_callback, NULL, c, PROMPT_HIDDEN); - server_redraw_client(c); - } - - server_locked = 1; -} - -int -server_lock_callback(unused void *data, const char *s) -{ - return (server_unlock(s)); -} - -int -server_unlock(const char *s) -{ - struct client *c; - login_cap_t *lc; - u_int i; - char *out; - u_int failures, tries, backoff; - - if (!server_locked || server_locked_pw == NULL) - return (0); - server_activity = time(NULL); - if (server_activity < password_backoff) - return (-2); - - if (server_password != NULL) { - if (s == NULL) - return (-1); - out = crypt(s, server_password); - if (strcmp(out, server_password) != 0) - goto wrong; - } - - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - c = ARRAY_ITEM(&clients, i); - if (c == NULL) + if (c->flags & CLIENT_SUSPENDED) continue; - status_prompt_clear(c); - server_redraw_client(c); - } - - server_locked = 0; - password_failures = 0; - password_backoff = 0; - return (0); - -wrong: - password_failures++; - password_backoff = 0; - - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - c = ARRAY_ITEM(&clients, i); - if (c == NULL || c->prompt_buffer == NULL) + cmd = options_get_string(&c->session->options, "lock-command"); + if (strlcpy(lockdata.cmd, + cmd, sizeof lockdata.cmd) >= sizeof lockdata.cmd) continue; - *c->prompt_buffer = '\0'; - c->prompt_index = 0; - server_redraw_client(c); - } + tty_stop_tty(&c->tty); + tty_raw(&c->tty, tty_term_string(c->tty.term, TTYC_SMCUP)); + tty_raw(&c->tty, tty_term_string(c->tty.term, TTYC_CLEAR)); - /* - * Start slowing down after "login-backoff" attempts and reset every - * "login-tries" attempts. - */ - lc = login_getclass(server_locked_pw->pw_class); - if (lc != NULL) { - tries = login_getcapnum(lc, (char *) "login-tries", 10, 10); - backoff = login_getcapnum(lc, (char *) "login-backoff", 3, 3); - } else { - tries = 10; - backoff = 3; + c->flags |= CLIENT_SUSPENDED; + server_write_client(c, MSG_LOCK, &lockdata, sizeof lockdata); } - failures = password_failures % tries; - if (failures > backoff) { - password_backoff = - server_activity + ((failures - backoff) * tries / 2); - return (-2); - } - return (-1); } void diff --git a/server-msg.c b/server-msg.c index 7f88e262..0b9b2a90 100644 --- a/server-msg.c +++ b/server-msg.c @@ -40,7 +40,6 @@ server_msg_dispatch(struct client *c) struct imsg imsg; struct msg_command_data commanddata; struct msg_identify_data identifydata; - struct msg_unlock_data unlockdata; struct msg_environ_data environdata; ssize_t n, datalen; @@ -95,31 +94,15 @@ server_msg_dispatch(struct client *c) tty_close(&c->tty); server_write_client(c, MSG_EXITED, NULL, 0); break; - case MSG_UNLOCK: - if (datalen != sizeof unlockdata) - fatalx("bad MSG_UNLOCK size"); - memcpy(&unlockdata, imsg.data, sizeof unlockdata); - - unlockdata.pass[(sizeof unlockdata.pass) - 1] = '\0'; - switch (server_unlock(unlockdata.pass)) { - case -1: - server_write_error(c, "bad password"); - break; - case -2: - server_write_error(c, - "too many bad passwords, sleeping"); - break; - } - memset(&unlockdata, 0, sizeof unlockdata); - server_write_client(c, MSG_EXIT, NULL, 0); - break; case MSG_WAKEUP: + case MSG_UNLOCK: if (datalen != 0) fatalx("bad MSG_WAKEUP size"); c->flags &= ~CLIENT_SUSPENDED; tty_start_tty(&c->tty); server_redraw_client(c); + server_activity = time(NULL); break; case MSG_ENVIRON: if (datalen != sizeof environdata) diff --git a/server.c b/server.c index cb69df0f..e465ace0 100644 --- a/server.c +++ b/server.c @@ -67,7 +67,6 @@ void server_lost_client(struct client *); void server_check_window(struct window *); void server_check_redraw(struct client *); void server_set_title(struct client *); -void server_redraw_locked(struct client *); void server_check_timers(struct client *); void server_second_timers(void); int server_update_socket(void); @@ -160,8 +159,6 @@ server_start(char *path) key_bindings_init(); utf8_build(); - server_locked = 0; - server_password = NULL; server_activity = time(NULL); start_time = time(NULL); @@ -382,8 +379,6 @@ server_main(int srv_fd) options_free(&global_s_options); options_free(&global_w_options); - if (server_password != NULL) - xfree(server_password); return (0); } @@ -541,10 +536,7 @@ server_check_redraw(struct client *c) } if (c->flags & CLIENT_REDRAW) { - if (server_locked) - server_redraw_locked(c); - else - screen_redraw_screen(c, 0); + screen_redraw_screen(c, 0); c->flags &= ~CLIENT_STATUS; } else { TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry) { @@ -581,49 +573,6 @@ server_set_title(struct client *c) xfree(title); } -/* Redraw client when locked. */ -void -server_redraw_locked(struct client *c) -{ - struct screen_write_ctx ctx; - struct screen screen; - struct grid_cell gc; - u_int colour, xx, yy, i; - int style; - - xx = c->tty.sx; - yy = c->tty.sy - 1; - if (xx == 0 || yy == 0) - return; - colour = options_get_number(&global_w_options, "clock-mode-colour"); - style = options_get_number(&global_w_options, "clock-mode-style"); - - memcpy(&gc, &grid_default_cell, sizeof gc); - colour_set_fg(&gc, colour); - gc.attr |= GRID_ATTR_BRIGHT; - - screen_init(&screen, xx, yy, 0); - - screen_write_start(&ctx, NULL, &screen); - clock_draw(&ctx, colour, style); - - if (password_failures != 0) { - screen_write_cursormove(&ctx, 0, 0); - screen_write_puts( - &ctx, &gc, "%u failed attempts", password_failures); - if (time(NULL) < password_backoff) - screen_write_puts(&ctx, &gc, "; sleeping"); - } - - screen_write_stop(&ctx); - - for (i = 0; i < screen_size_y(&screen); i++) - tty_draw_line(&c->tty, &screen, i, 0, 0); - screen_redraw_screen(c, 1); - - screen_free(&screen); -} - /* Check for timers on client. */ void server_check_timers(struct client *c) @@ -836,8 +785,6 @@ server_handle_client(struct client *c) status_prompt_key(c, key); continue; } - if (server_locked) - continue; /* Check for mouse keys. */ if (key == KEYC_MOUSE) { @@ -929,8 +876,6 @@ server_handle_client(struct client *c) tty_cursor(&c->tty, s->cx, s->cy, wp->xoff, wp->yoff); mode = s->mode; - if (server_locked) - mode &= ~TTY_NOCURSOR; tty_update_mode(&c->tty, mode); tty_reset(&c->tty); } @@ -1235,12 +1180,9 @@ void server_second_timers(void) { struct window *w; - struct client *c; struct window_pane *wp; u_int i; int xtimeout; - struct tm now, then; - static time_t last_t = 0; time_t t; t = time(NULL); @@ -1259,29 +1201,6 @@ server_second_timers(void) wp->mode->timer(wp); } } - - if (password_backoff != 0 && t >= password_backoff) { - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - if ((c = ARRAY_ITEM(&clients, i)) != NULL) - server_redraw_client(c); - } - password_backoff = 0; - } - - /* Check for a minute having passed. */ - gmtime_r(&t, &now); - gmtime_r(&last_t, &then); - if (now.tm_min == then.tm_min) - return; - last_t = t; - - /* If locked, redraw all clients. */ - if (server_locked) { - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - if ((c = ARRAY_ITEM(&clients, i)) != NULL) - server_redraw_client(c); - } - } } /* Update socket execute permissions based on whether sessions are attached. */ diff --git a/status.c b/status.c index 77062729..6527630c 100644 --- a/status.c +++ b/status.c @@ -890,9 +890,6 @@ status_prompt_key(struct client *c, int key) } break; case MODEKEYEDIT_HISTORYUP: - if (server_locked) - break; - if (ARRAY_LENGTH(&c->prompt_hdata) == 0) break; if (c->prompt_flags & PROMPT_HIDDEN) @@ -908,9 +905,6 @@ status_prompt_key(struct client *c, int key) c->flags |= CLIENT_STATUS; break; case MODEKEYEDIT_HISTORYDOWN: - if (server_locked) - break; - if (c->prompt_flags & PROMPT_HIDDEN) memset(c->prompt_buffer, 0, strlen(c->prompt_buffer)); xfree(c->prompt_buffer); @@ -1003,9 +997,6 @@ status_prompt_key(struct client *c, int key) void status_prompt_add_history(struct client *c) { - if (server_locked) - return; - if (ARRAY_LENGTH(&c->prompt_hdata) > 0 && strcmp(ARRAY_LAST(&c->prompt_hdata), c->prompt_buffer) == 0) return; diff --git a/tmux.1 b/tmux.1 index 802b0fd9..7155dcd2 100644 --- a/tmux.1 +++ b/tmux.1 @@ -23,7 +23,7 @@ .Sh SYNOPSIS .Nm tmux .Bk -words -.Op Fl 28dlqUuv +.Op Fl 28dlquv .Op Fl f Ar file .Op Fl L Ar socket-name .Op Fl S Ar socket-path @@ -154,8 +154,6 @@ If is specified, the default socket directory is not used and any .Fl L flag is ignored. -.It Fl U -Unlock the server. .It Fl u .Nm attempts to guess if the terminal is likely to support UTF-8 by checking the @@ -337,8 +335,6 @@ rename-session -tfirst newname set-window-option -t:0 monitor-activity on new-window ; split-window -d - -bind-key D detach-client \e\; lock-server .Ed .Sh CLIENTS AND SESSIONS The following commands are available: @@ -1213,17 +1209,20 @@ Set the maximum number of lines held in window history. This setting applies only to new windows - existing window histories are not resized and retain the limit at the point they were created. .It Ic lock-after-time Ar number -Lock the server after +Lock the server (like the +.Ic lock-server +command) after .Ar number seconds of inactivity. The default is off (set to 0). This has no effect as a session option; it must be set as a global option using .Fl g . -When passwords are entered incorrectly, -.Nm -follows the behaviour of -.Xr login 1 -and ignores further password attempts for an increasing timeout. +.It Ic lock-command Ar command +Command to run when locking each client. +The default is to run +.Xr lock 1 +with +.Fl np . .It Ic message-attr Ar attributes Set status line message attributes, where .Ar attributes @@ -1962,7 +1961,9 @@ if returns success. .It Ic lock-server .D1 (alias: Ic lock ) -Lock the server until a password is entered. +Lock each client individually by running the command specified by the +.Ic lock-command +option. .It Ic run-shell Ar command .D1 (alias: Ic run ) Execute @@ -1975,21 +1976,6 @@ 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 set-password -.Op Fl c -.Ar password -.Xc -.D1 (alias: Ic pass ) -Set the server password. -If the -.Fl c -option is given, a pre-encrypted password may be specified. -By default, the password is blank, thus any entered password will be accepted -when unlocking the server (see the -.Ic lock-server -command). -To prevent variable expansion when an encrypted password is read from a -configuration file, enclose it in single quotes ('). .El .Sh FILES .Bl -tag -width "/etc/tmux.confXXX" -compact diff --git a/tmux.c b/tmux.c index 02657e32..bde1e7f2 100644 --- a/tmux.c +++ b/tmux.c @@ -46,11 +46,6 @@ struct options global_s_options; /* session options */ struct options global_w_options; /* window options */ struct environ global_environ; -int server_locked; -struct passwd *server_locked_pw; -u_int password_failures; -time_t password_backoff; -char *server_password; time_t server_activity; int debug_level; @@ -61,7 +56,6 @@ int login_shell; __dead void usage(void); char *makesockpath(const char *); -int prepare_unlock(enum msgtype *, void **, size_t *, int); int prepare_cmd(enum msgtype *, void **, size_t *, int, char **); int dispatch_imsg(struct client_ctx *, int *); @@ -69,7 +63,7 @@ __dead void usage(void) { fprintf(stderr, - "usage: %s [-28dlqUuv] [-f file] [-L socket-name]\n" + "usage: %s [-28dlquv] [-f file] [-L socket-name]\n" " [-S socket-path] [command [flags]]\n", __progname); exit(1); @@ -250,35 +244,6 @@ makesockpath(const char *label) return (path); } -int -prepare_unlock(enum msgtype *msg, void **buf, size_t *len, int argc) -{ - static struct msg_unlock_data unlockdata; - char *pass; - - if (argc != 0) { - log_warnx("can't specify a command when unlocking"); - return (-1); - } - - if ((pass = getpass("Password:")) == NULL) - return (-1); - - if (strlen(pass) >= sizeof unlockdata.pass) { - log_warnx("password too long"); - return (-1); - } - - strlcpy(unlockdata.pass, pass, sizeof unlockdata.pass); - memset(pass, 0, strlen(pass)); - - *buf = &unlockdata; - *len = sizeof unlockdata; - - *msg = MSG_UNLOCK; - return (0); -} - int prepare_cmd(enum msgtype *msg, void **buf, size_t *len, int argc, char **argv) { @@ -314,10 +279,10 @@ main(int argc, char **argv) char cwd[MAXPATHLEN]; void *buf; size_t len; - int retcode, opt, flags, unlock, cmdflags = 0; + int retcode, opt, flags, cmdflags = 0; int nfds; - unlock = flags = 0; + flags = 0; label = path = NULL; login_shell = (**argv == '-'); while ((opt = getopt(argc, argv, "28df:lL:qS:uUv")) != -1) { @@ -357,9 +322,6 @@ main(int argc, char **argv) case 'u': flags |= IDENTIFY_UTF8; break; - case 'U': - unlock = 1; - break; case 'v': debug_level++; break; @@ -407,6 +369,7 @@ main(int argc, char **argv) options_set_number(so, "display-time", 750); options_set_number(so, "history-limit", 2000); options_set_number(so, "lock-after-time", 0); + options_set_string(so, "lock-command", "lock -np"); options_set_number(so, "message-attr", 0); options_set_number(so, "message-bg", 3); options_set_number(so, "message-fg", 0); @@ -514,17 +477,10 @@ main(int argc, char **argv) } xfree(label); - if (unlock) { - if (prepare_unlock(&msg, &buf, &len, argc) != 0) - exit(1); - } else { - if (prepare_cmd(&msg, &buf, &len, argc, argv) != 0) - exit(1); - } + if (prepare_cmd(&msg, &buf, &len, argc, argv) != 0) + exit(1); - if (unlock) - cmdflags &= ~CMD_STARTSERVER; - else if (argc == 0) /* new-session is the default */ + if (argc == 0) /* new-session is the default */ cmdflags |= CMD_STARTSERVER|CMD_SENDENVIRON; else { /* diff --git a/tmux.h b/tmux.h index 6325bca2..cea6c194 100644 --- a/tmux.h +++ b/tmux.h @@ -19,7 +19,7 @@ #ifndef TMUX_H #define TMUX_H -#define PROTOCOL_VERSION 3 +#define PROTOCOL_VERSION 4 #include #include @@ -304,10 +304,11 @@ enum msgtype { MSG_RESIZE, MSG_SHUTDOWN, MSG_SUSPEND, - MSG_UNLOCK, MSG_VERSION, MSG_WAKEUP, - MSG_ENVIRON + MSG_ENVIRON, + MSG_UNLOCK, + MSG_LOCK }; /* @@ -339,8 +340,8 @@ struct msg_identify_data { int flags; }; -struct msg_unlock_data { - char pass[PASS_MAX]; +struct msg_lock_data { + char cmd[COMMAND_LENGTH]; }; struct msg_environ_data { @@ -1108,11 +1109,6 @@ extern struct options global_s_options; extern struct options global_w_options; extern struct environ global_environ; extern char *cfg_file; -extern int server_locked; -extern struct passwd *server_locked_pw; -extern u_int password_failures; -extern time_t password_backoff; -extern char *server_password; extern time_t server_activity; extern int debug_level; extern int be_quiet; @@ -1179,6 +1175,7 @@ void environ_unset(struct environ *, const char *); void environ_update(const char *, struct environ *, struct environ *); /* tty.c */ +void tty_raw(struct tty *, const char *); u_char tty_get_acs(struct tty *, u_char); void tty_attributes(struct tty *, const struct grid_cell *); void tty_reset(struct tty *); @@ -1352,7 +1349,6 @@ extern const struct cmd_entry cmd_server_info_entry; extern const struct cmd_entry cmd_set_buffer_entry; extern const struct cmd_entry cmd_set_environment_entry; extern const struct cmd_entry cmd_set_option_entry; -extern const struct cmd_entry cmd_set_password_entry; extern const struct cmd_entry cmd_set_window_option_entry; extern const struct cmd_entry cmd_show_buffer_entry; extern const struct cmd_entry cmd_show_environment_entry; diff --git a/tty.c b/tty.c index 12535f94..82cfac80 100644 --- a/tty.c +++ b/tty.c @@ -29,8 +29,6 @@ void tty_fill_acs(struct tty *); -void tty_raw(struct tty *, const char *); - int tty_try_256(struct tty *, u_char, const char *); int tty_try_88(struct tty *, u_char, const char *); From 631a6182381f246c4c6aa9a200c744fcd5be015c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 23 Sep 2009 07:25:31 +0000 Subject: [PATCH 0348/1180] Don't die if the client is detaching (the tty has been closed) after waking up from locking. --- tty.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tty.c b/tty.c index 82cfac80..2129747d 100644 --- a/tty.c +++ b/tty.c @@ -131,6 +131,9 @@ tty_start_tty(struct tty *tty) struct termios tio; int what; + if (tty->fd == -1) + return; + #if 0 tty_detect_utf8(tty); #endif From 18ea820cb0f1e7d9936c89abf15130e40efc956b Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 23 Sep 2009 08:21:57 +0000 Subject: [PATCH 0349/1180] On SIGTERM, just abandon any suspended/locked clients and leave them to it, otherwise the server will hang around (refusing new connections) until they exit properly. --- server.c | 56 +++++++++++++++++++++++++++++++------------------------- 1 file changed, 31 insertions(+), 25 deletions(-) diff --git a/server.c b/server.c index e465ace0..6dac5f5b 100644 --- a/server.c +++ b/server.c @@ -49,6 +49,7 @@ void server_create_client(int); int server_create_socket(void); int server_main(int); void server_shutdown(void); +int server_should_shutdown(void); void server_child_signal(void); void server_fill_windows(struct pollfd **); void server_handle_windows(struct pollfd **); @@ -244,7 +245,7 @@ server_main(int srv_fd) struct window *w; struct pollfd *pfds, *pfd; int nfds, xtimeout; - u_int i, n; + u_int i; time_t now, last; siginit(); @@ -258,6 +259,10 @@ server_main(int srv_fd) if (sigterm) server_shutdown(); + /* Stop if no sessions or clients left. */ + if (server_should_shutdown()) + break; + /* Handle child exit. */ if (sigchld) { server_child_signal(); @@ -337,22 +342,6 @@ server_main(int srv_fd) /* Collect dead clients and sessions. */ server_clean_dead(); - - /* - * If we have no sessions and clients left, let's get out - * of here... - */ - n = 0; - for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { - if (ARRAY_ITEM(&sessions, i) != NULL) - n++; - } - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - if (ARRAY_ITEM(&clients, i) != NULL) - n++; - } - if (n == 0) - break; } if (pfds != NULL) xfree(pfds); @@ -391,6 +380,16 @@ server_shutdown(void) struct client *c; u_int i, j; + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c != NULL) { + if (c->flags & (CLIENT_BAD|CLIENT_SUSPENDED)) + server_lost_client(c); + else + server_write_client(c, MSG_SHUTDOWN, NULL, 0); + } + } + for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { s = ARRAY_ITEM(&sessions, i); for (j = 0; j < ARRAY_LENGTH(&clients); j++) { @@ -403,16 +402,23 @@ server_shutdown(void) if (s != NULL) session_destroy(s); } +} - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - c = ARRAY_ITEM(&clients, i); - if (c != NULL) { - if (c->flags & CLIENT_BAD) - server_lost_client(c); - else - server_write_client(c, MSG_SHUTDOWN, NULL, 0); - } +/* Check if the server should be shutting down (no more clients or windows). */ +int +server_should_shutdown(void) +{ + u_int i; + + for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { + if (ARRAY_ITEM(&sessions, i) != NULL) + return (0); } + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + if (ARRAY_ITEM(&clients, i) != NULL) + return (0); + } + return (1); } /* Handle SIGCHLD. */ From 9200a0be7a515cd04c1a05d120002c73932cbf98 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 23 Sep 2009 12:03:30 +0000 Subject: [PATCH 0350/1180] Support -c like sh(1) to execute a command, useful when tmux is a login shell. Suggested by halex@. This includes another protocol version increase (the last for now) so again restart the tmux server before upgrading. --- client.c | 2 ++ server-msg.c | 25 ++++++++++++++++++++ tmux.1 | 10 ++++++++ tmux.c | 66 ++++++++++++++++++++++++++++++++++++++++++++-------- tmux.h | 10 ++++++-- tty.c | 17 +++++++++----- 6 files changed, 112 insertions(+), 18 deletions(-) diff --git a/client.c b/client.c index ceb054bb..e93272de 100644 --- a/client.c +++ b/client.c @@ -91,6 +91,8 @@ server_started: fatal("fcntl failed"); if (fcntl(fd, F_SETFL, mode|O_NONBLOCK) == -1) fatal("fcntl failed"); + if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) + fatal("fcntl failed"); imsg_init(&cctx->ibuf, fd); if (cmdflags & CMD_SENDENVIRON) diff --git a/server-msg.c b/server-msg.c index 0b9b2a90..b7b45c6c 100644 --- a/server-msg.c +++ b/server-msg.c @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -29,6 +30,7 @@ void server_msg_command(struct client *, struct msg_command_data *); void server_msg_identify(struct client *, struct msg_identify_data *, int); +void server_msg_shell(struct client *); void printflike2 server_msg_command_error(struct cmd_ctx *, const char *, ...); void printflike2 server_msg_command_print(struct cmd_ctx *, const char *, ...); @@ -113,6 +115,12 @@ server_msg_dispatch(struct client *c) if (strchr(environdata.var, '=') != NULL) environ_put(&c->environ, environdata.var); break; + case MSG_SHELL: + if (datalen != 0) + fatalx("bad MSG_SHELL size"); + + server_msg_shell(c); + break; default: fatalx("unexpected message"); } @@ -248,3 +256,20 @@ server_msg_identify(struct client *c, struct msg_identify_data *data, int fd) c->flags |= CLIENT_TERMINAL; } + +void +server_msg_shell(struct client *c) +{ + struct msg_shell_data data; + const char *shell; + + shell = options_get_string(&global_s_options, "default-shell"); + + if (*shell == '\0' || areshell(shell)) + shell = _PATH_BSHELL; + if (strlcpy(data.shell, shell, sizeof data.shell) >= sizeof data.shell) + strlcpy(data.shell, _PATH_BSHELL, sizeof data.shell); + + server_write_client(c, MSG_SHELL, &data, sizeof data); + c->flags |= CLIENT_BAD; /* it will die after exec */ +} diff --git a/tmux.1 b/tmux.1 index 7155dcd2..542663d7 100644 --- a/tmux.1 +++ b/tmux.1 @@ -24,6 +24,7 @@ .Nm tmux .Bk -words .Op Fl 28dlquv +.Op Fl c Ar shell-command .Op Fl f Ar file .Op Fl L Ar socket-name .Op Fl S Ar socket-path @@ -101,6 +102,15 @@ to assume the terminal supports 256 colours. Like .Fl 2 , but indicates that the terminal supports 88 colours. +.It Fl c Ar shell-command +Execute +.Ar shell-command +using the default shell. +If necessary, the +.Nm +server will be started to retrieve the +.Ic default-shell +option. .It Fl d Force .Nm diff --git a/tmux.c b/tmux.c index bde1e7f2..5673282f 100644 --- a/tmux.c +++ b/tmux.c @@ -57,13 +57,14 @@ int login_shell; __dead void usage(void); char *makesockpath(const char *); int prepare_cmd(enum msgtype *, void **, size_t *, int, char **); -int dispatch_imsg(struct client_ctx *, int *); +int dispatch_imsg(struct client_ctx *, const char *, int *); +__dead void shell_exec(const char *, const char *); __dead void usage(void) { fprintf(stderr, - "usage: %s [-28dlquv] [-f file] [-L socket-name]\n" + "usage: %s [-28dlquv] [-c shell-command] [-f file] [-L socket-name]\n" " [-S socket-path] [command [flags]]\n", __progname); exit(1); @@ -275,17 +276,17 @@ main(int argc, char **argv) struct passwd *pw; struct options *so, *wo; struct keylist *keylist; - char *s, *path, *label, *home, *cause, **var; - char cwd[MAXPATHLEN]; + char *s, *shellcmd, *path, *label, *home, *cause; + char cwd[MAXPATHLEN], **var; void *buf; size_t len; int retcode, opt, flags, cmdflags = 0; int nfds; flags = 0; - label = path = NULL; + shellcmd = label = path = NULL; login_shell = (**argv == '-'); - while ((opt = getopt(argc, argv, "28df:lL:qS:uUv")) != -1) { + while ((opt = getopt(argc, argv, "28c:df:lL:qS:uUv")) != -1) { switch (opt) { case '2': flags |= IDENTIFY_256COLOURS; @@ -295,6 +296,11 @@ main(int argc, char **argv) flags |= IDENTIFY_88COLOURS; flags &= ~IDENTIFY_256COLOURS; break; + case 'c': + if (shellcmd != NULL) + xfree(shellcmd); + shellcmd = xstrdup(optarg); + break; case 'd': flags |= IDENTIFY_HASDEFAULTS; break; @@ -332,6 +338,9 @@ main(int argc, char **argv) argc -= optind; argv += optind; + if (shellcmd != NULL && argc != 0) + usage(); + log_open_tty(debug_level); siginit(); @@ -477,10 +486,16 @@ main(int argc, char **argv) } xfree(label); - if (prepare_cmd(&msg, &buf, &len, argc, argv) != 0) + if (shellcmd != NULL) { + msg = MSG_SHELL; + buf = NULL; + len = 0; + } else if (prepare_cmd(&msg, &buf, &len, argc, argv) != 0) exit(1); - if (argc == 0) /* new-session is the default */ + if (shellcmd != NULL) + cmdflags |= CMD_STARTSERVER; + else if (argc == 0) /* new-session is the default */ cmdflags |= CMD_STARTSERVER|CMD_SENDENVIRON; else { /* @@ -529,7 +544,7 @@ main(int argc, char **argv) fatalx("socket error"); if (pfd.revents & POLLIN) { - if (dispatch_imsg(&cctx, &retcode) != 0) + if (dispatch_imsg(&cctx, shellcmd, &retcode) != 0) break; } @@ -546,11 +561,12 @@ main(int argc, char **argv) } int -dispatch_imsg(struct client_ctx *cctx, int *retcode) +dispatch_imsg(struct client_ctx *cctx, const char *shellcmd, int *retcode) { struct imsg imsg; ssize_t n, datalen; struct msg_print_data printdata; + struct msg_shell_data shelldata; if ((n = imsg_read(&cctx->ibuf)) == -1 || n == 0) fatalx("imsg_read failed"); @@ -594,6 +610,13 @@ dispatch_imsg(struct client_ctx *cctx, int *retcode) "server %u)", PROTOCOL_VERSION, imsg.hdr.peerid); *retcode = 1; return (-1); + case MSG_SHELL: + if (datalen != sizeof shelldata) + fatalx("bad MSG_SHELL size"); + memcpy(&shelldata, imsg.data, sizeof shelldata); + shelldata.shell[(sizeof shelldata.shell) - 1] = '\0'; + + shell_exec(shelldata.shell, shellcmd); default: fatalx("unexpected message"); } @@ -601,3 +624,26 @@ dispatch_imsg(struct client_ctx *cctx, int *retcode) imsg_free(&imsg); } } + +__dead void +shell_exec(const char *shell, const char *shellcmd) +{ + const char *shellname, *ptr; + char *argv0; + + sigreset(); + + ptr = strrchr(shell, '/'); + if (ptr != NULL && *(ptr + 1) != '\0') + shellname = ptr + 1; + else + shellname = shell; + if (login_shell) + xasprintf(&argv0, "-%s", shellname); + else + xasprintf(&argv0, "%s", shellname); + setenv("SHELL", shell, 1); + + execl(shell, argv0, "-c", shellcmd, (char *) NULL); + fatal("execl failed"); +} diff --git a/tmux.h b/tmux.h index cea6c194..5ec263e7 100644 --- a/tmux.h +++ b/tmux.h @@ -19,7 +19,7 @@ #ifndef TMUX_H #define TMUX_H -#define PROTOCOL_VERSION 4 +#define PROTOCOL_VERSION 5 #include #include @@ -130,6 +130,7 @@ enum key_code { /* Function keys. */ KEYC_F1, + KEYC_F2, KEYC_F3, KEYC_F4, @@ -308,7 +309,8 @@ enum msgtype { MSG_WAKEUP, MSG_ENVIRON, MSG_UNLOCK, - MSG_LOCK + MSG_LOCK, + MSG_SHELL }; /* @@ -348,6 +350,10 @@ struct msg_environ_data { char var[ENVIRON_LENGTH]; }; +struct msg_shell_data { + char shell[MAXPATHLEN]; +}; + /* Mode key commands. */ enum mode_key_cmd { MODEKEY_NONE, diff --git a/tty.c b/tty.c index 2129747d..774808db 100644 --- a/tty.c +++ b/tty.c @@ -44,7 +44,6 @@ void tty_cell(struct tty *, void tty_init(struct tty *tty, int fd, char *term) { - int mode; char *path; memset(tty, 0, sizeof *tty); @@ -55,10 +54,6 @@ tty_init(struct tty *tty, int fd, char *term) else tty->termname = xstrdup(term); - if ((mode = fcntl(fd, F_GETFL)) == -1) - fatal("fcntl failed"); - if (fcntl(fd, F_SETFL, mode|O_NONBLOCK) == -1) - fatal("fcntl failed"); if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) fatal("fcntl failed"); tty->fd = fd; @@ -129,11 +124,16 @@ void tty_start_tty(struct tty *tty) { struct termios tio; - int what; + int what, mode; if (tty->fd == -1) return; + if ((mode = fcntl(tty->fd, F_GETFL)) == -1) + fatal("fcntl failed"); + if (fcntl(tty->fd, F_SETFL, mode|O_NONBLOCK) == -1) + fatal("fcntl failed"); + #if 0 tty_detect_utf8(tty); #endif @@ -183,6 +183,7 @@ void tty_stop_tty(struct tty *tty) { struct winsize ws; + int mode; if (!(tty->flags & TTY_STARTED)) return; @@ -193,6 +194,10 @@ tty_stop_tty(struct tty *tty) * because the fd is invalid. Things like ssh -t can easily leave us * with a dead tty. */ + if ((mode = fcntl(tty->fd, F_GETFL)) == -1) + return; + if (fcntl(tty->fd, F_SETFL, mode & ~O_NONBLOCK) == -1) + return; if (ioctl(tty->fd, TIOCGWINSZ, &ws) == -1) return; if (tcsetattr(tty->fd, TCSANOW, &tty->tio) == -1) From fecf8dc44ee88bd5aee02035d13b118fa514f253 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 23 Sep 2009 14:42:48 +0000 Subject: [PATCH 0351/1180] Remove PROMPT_HIDDEN code which is now unused. --- status.c | 25 +++++-------------------- tmux.h | 3 +-- 2 files changed, 6 insertions(+), 22 deletions(-) diff --git a/status.c b/status.c index 6527630c..3ffee331 100644 --- a/status.c +++ b/status.c @@ -673,8 +673,6 @@ status_prompt_clear(struct client *c) xfree(c->prompt_string); c->prompt_string = NULL; - if (c->prompt_flags & PROMPT_HIDDEN) - memset(c->prompt_buffer, 0, strlen(c->prompt_buffer)); xfree(c->prompt_buffer); c->prompt_buffer = NULL; @@ -739,26 +737,17 @@ status_prompt_redraw(struct client *c) left--; size = left; } - if (c->prompt_flags & PROMPT_HIDDEN) - size = 0; - else { - screen_write_puts(&ctx, &gc, - "%.*s", (int) left, c->prompt_buffer + off); - } + screen_write_puts( + &ctx, &gc, "%.*s", (int) left, c->prompt_buffer + off); for (i = len + size; i < c->tty.sx; i++) screen_write_putc(&ctx, &gc, ' '); /* Draw a fake cursor. */ ch = ' '; - if (c->prompt_flags & PROMPT_HIDDEN) - screen_write_cursormove(&ctx, len, 0); - else { - screen_write_cursormove(&ctx, - len + c->prompt_index - off, 0); - if (c->prompt_index < strlen(c->prompt_buffer)) - ch = c->prompt_buffer[c->prompt_index]; - } + screen_write_cursormove(&ctx, len + c->prompt_index - off, 0); + if (c->prompt_index < strlen(c->prompt_buffer)) + ch = c->prompt_buffer[c->prompt_index]; gc.attr ^= GRID_ATTR_REVERSE; screen_write_putc(&ctx, &gc, ch); } @@ -892,8 +881,6 @@ status_prompt_key(struct client *c, int key) case MODEKEYEDIT_HISTORYUP: if (ARRAY_LENGTH(&c->prompt_hdata) == 0) break; - if (c->prompt_flags & PROMPT_HIDDEN) - memset(c->prompt_buffer, 0, strlen(c->prompt_buffer)); xfree(c->prompt_buffer); c->prompt_buffer = xstrdup(ARRAY_ITEM(&c->prompt_hdata, @@ -905,8 +892,6 @@ status_prompt_key(struct client *c, int key) c->flags |= CLIENT_STATUS; break; case MODEKEYEDIT_HISTORYDOWN: - if (c->prompt_flags & PROMPT_HIDDEN) - memset(c->prompt_buffer, 0, strlen(c->prompt_buffer)); xfree(c->prompt_buffer); if (c->prompt_hindex != 0) { diff --git a/tmux.h b/tmux.h index 5ec263e7..46117659 100644 --- a/tmux.h +++ b/tmux.h @@ -958,8 +958,7 @@ struct client { void (*prompt_freefn)(void *); void *prompt_data; -#define PROMPT_HIDDEN 0x1 -#define PROMPT_SINGLE 0x2 +#define PROMPT_SINGLE 0x1 int prompt_flags; u_int prompt_hindex; From 1764ef81efce5f265f61107f0b1e91d73b858fb4 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 24 Sep 2009 07:02:56 +0000 Subject: [PATCH 0352/1180] Don't allow locked or suspended clients to limit the size of active clients. --- cmd-lock-server.c | 1 + resize.c | 2 +- server-msg.c | 1 + server.c | 4 +++- 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/cmd-lock-server.c b/cmd-lock-server.c index 54f2efd2..55c19e38 100644 --- a/cmd-lock-server.c +++ b/cmd-lock-server.c @@ -45,6 +45,7 @@ int cmd_lock_server_exec(unused struct cmd *self, unused struct cmd_ctx *ctx) { server_lock(); + recalculate_sizes(); return (0); } diff --git a/resize.c b/resize.c index d549ea5b..5635f9d4 100644 --- a/resize.c +++ b/resize.c @@ -60,7 +60,7 @@ recalculate_sizes(void) ssx = ssy = UINT_MAX; for (j = 0; j < ARRAY_LENGTH(&clients); j++) { c = ARRAY_ITEM(&clients, j); - if (c == NULL) + if (c == NULL || c->flags & CLIENT_SUSPENDED) continue; if (c->session == s) { if (c->tty.sx < ssx) diff --git a/server-msg.c b/server-msg.c index b7b45c6c..ec085610 100644 --- a/server-msg.c +++ b/server-msg.c @@ -104,6 +104,7 @@ server_msg_dispatch(struct client *c) c->flags &= ~CLIENT_SUSPENDED; tty_start_tty(&c->tty); server_redraw_client(c); + recalculate_sizes(); server_activity = time(NULL); break; case MSG_ENVIRON: diff --git a/server.c b/server.c index 6dac5f5b..f7136784 100644 --- a/server.c +++ b/server.c @@ -1194,8 +1194,10 @@ server_second_timers(void) t = time(NULL); xtimeout = options_get_number(&global_s_options, "lock-after-time"); - if (xtimeout > 0 && t > server_activity + xtimeout) + if (xtimeout > 0 && t > server_activity + xtimeout) { server_lock(); + recalculate_sizes(); + } for (i = 0; i < ARRAY_LENGTH(&windows); i++) { w = ARRAY_ITEM(&windows, i); From 8fa1858a2c02aafa31695a12fa40cd5dbdd53cd2 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 24 Sep 2009 14:17:09 +0000 Subject: [PATCH 0353/1180] New lock-client and lock-session commands to lock an individual client or all clients attached to a session respectively. --- Makefile | 3 ++- cmd-lock-client.c | 53 ++++++++++++++++++++++++++++++++++++++++++++ cmd-lock-session.c | 53 ++++++++++++++++++++++++++++++++++++++++++++ cmd.c | 2 ++ server-fn.c | 55 ++++++++++++++++++++++++++++++++-------------- tmux.1 | 13 +++++++++++ tmux.h | 4 ++++ 7 files changed, 166 insertions(+), 17 deletions(-) create mode 100644 cmd-lock-client.c create mode 100644 cmd-lock-session.c diff --git a/Makefile b/Makefile index f35149df..f6df7718 100644 --- a/Makefile +++ b/Makefile @@ -12,7 +12,8 @@ SRCS= attributes.c buffer-poll.c buffer.c cfg.c client-fn.c \ cmd-last-window.c cmd-link-window.c cmd-list-buffers.c \ cmd-list-clients.c cmd-list-commands.c cmd-list-keys.c \ cmd-list-sessions.c cmd-list-windows.c cmd-list.c cmd-load-buffer.c \ - cmd-lock-server.c cmd-move-window.c cmd-new-session.c cmd-new-window.c \ + cmd-lock-server.c cmd-lock-client.c cmd-lock-session.c \ + cmd-move-window.c cmd-new-session.c cmd-new-window.c \ cmd-next-layout.c cmd-next-window.c cmd-paste-buffer.c \ cmd-previous-layout.c cmd-previous-window.c cmd-refresh-client.c \ cmd-rename-session.c cmd-rename-window.c cmd-resize-pane.c \ diff --git a/cmd-lock-client.c b/cmd-lock-client.c new file mode 100644 index 00000000..e855d32c --- /dev/null +++ b/cmd-lock-client.c @@ -0,0 +1,53 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2009 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" + +/* + * Lock a single client. + */ + +int cmd_lock_client_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_lock_client_entry = { + "lock-client", "lockc", + CMD_TARGET_CLIENT_USAGE, + 0, 0, + cmd_target_init, + cmd_target_parse, + cmd_lock_client_exec, + cmd_target_free, + cmd_target_print +}; + +int +cmd_lock_client_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_target_data *data = self->data; + struct client *c; + + if ((c = cmd_find_client(ctx, data->target)) == NULL) + return (-1); + + server_lock_client(c); + recalculate_sizes(); + + return (0); +} diff --git a/cmd-lock-session.c b/cmd-lock-session.c new file mode 100644 index 00000000..c0a6569c --- /dev/null +++ b/cmd-lock-session.c @@ -0,0 +1,53 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2009 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" + +/* + * Lock all clients attached to a session. + */ + +int cmd_lock_session_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_lock_session_entry = { + "lock-session", "locks", + CMD_TARGET_SESSION_USAGE, + 0, 0, + cmd_target_init, + cmd_target_parse, + cmd_lock_session_exec, + cmd_target_free, + cmd_target_print +}; + +int +cmd_lock_session_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_target_data *data = self->data; + struct session *s; + + if ((s = cmd_find_session(ctx, data->target)) == NULL) + return (-1); + + server_lock_session(s); + recalculate_sizes(); + + return (0); +} diff --git a/cmd.c b/cmd.c index d027cd9c..05294be1 100644 --- a/cmd.c +++ b/cmd.c @@ -61,7 +61,9 @@ const struct cmd_entry *cmd_table[] = { &cmd_list_sessions_entry, &cmd_list_windows_entry, &cmd_load_buffer_entry, + &cmd_lock_client_entry, &cmd_lock_server_entry, + &cmd_lock_session_entry, &cmd_move_window_entry, &cmd_new_session_entry, &cmd_new_window_entry, diff --git a/server-fn.c b/server-fn.c index b9be1794..6acca2bf 100644 --- a/server-fn.c +++ b/server-fn.c @@ -157,10 +157,8 @@ server_status_window(struct window *w) void server_lock(void) { - struct client *c; - const char *cmd; - struct msg_lock_data lockdata; - u_int i; + struct client *c; + u_int i; for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); @@ -168,21 +166,46 @@ server_lock(void) continue; if (c->flags & CLIENT_SUSPENDED) continue; - - cmd = options_get_string(&c->session->options, "lock-command"); - if (strlcpy(lockdata.cmd, - cmd, sizeof lockdata.cmd) >= sizeof lockdata.cmd) - continue; - - tty_stop_tty(&c->tty); - tty_raw(&c->tty, tty_term_string(c->tty.term, TTYC_SMCUP)); - tty_raw(&c->tty, tty_term_string(c->tty.term, TTYC_CLEAR)); - - c->flags |= CLIENT_SUSPENDED; - server_write_client(c, MSG_LOCK, &lockdata, sizeof lockdata); + server_lock_client(c); } } +void +server_lock_session(struct session *s) +{ + struct client *c; + u_int i; + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c == NULL || c->session == NULL || c->session != s) + continue; + if (c->flags & CLIENT_SUSPENDED) + continue; + server_lock_client(c); + } +} + +void +server_lock_client(struct client *c) +{ + const char *cmd; + size_t cmdlen; + struct msg_lock_data lockdata; + + cmd = options_get_string(&c->session->options, "lock-command"); + cmdlen = strlcpy(lockdata.cmd, cmd, sizeof lockdata.cmd); + if (cmdlen >= sizeof lockdata.cmd) + return; + + tty_stop_tty(&c->tty); + tty_raw(&c->tty, tty_term_string(c->tty.term, TTYC_SMCUP)); + tty_raw(&c->tty, tty_term_string(c->tty.term, TTYC_CLEAR)); + + c->flags |= CLIENT_SUSPENDED; + server_write_client(c, MSG_LOCK, &lockdata, sizeof lockdata); +} + void server_kill_window(struct window *w) { diff --git a/tmux.1 b/tmux.1 index 542663d7..22351bfa 100644 --- a/tmux.1 +++ b/tmux.1 @@ -392,6 +392,19 @@ List the syntax of all commands supported by .It Ic list-sessions .D1 (alias: Ic ls ) List all sessions managed by the server. +.It Xo Ic lock-client +.Op Fl t Ar target-client +.Xc +Lock +.Ar target-client , +see the +.Ic lock-server +command. +.It Xo Ic lock-session +.Op Fl t Ar target-session +.Xc +Lock all clients attached to +.Ar target-session . .It Xo Ic new-session .Op Fl d .Op Fl n Ar window-name diff --git a/tmux.h b/tmux.h index 46117659..3c49ae30 100644 --- a/tmux.h +++ b/tmux.h @@ -1326,7 +1326,9 @@ extern const struct cmd_entry cmd_list_keys_entry; extern const struct cmd_entry cmd_list_sessions_entry; extern const struct cmd_entry cmd_list_windows_entry; extern const struct cmd_entry cmd_load_buffer_entry; +extern const struct cmd_entry cmd_lock_client_entry; extern const struct cmd_entry cmd_lock_server_entry; +extern const struct cmd_entry cmd_lock_session_entry; extern const struct cmd_entry cmd_move_window_entry; extern const struct cmd_entry cmd_new_session_entry; extern const struct cmd_entry cmd_new_window_entry; @@ -1457,6 +1459,8 @@ void server_status_session(struct session *); void server_redraw_window(struct window *); void server_status_window(struct window *); void server_lock(void); +void server_lock_session(struct session *); +void server_lock_client(struct client *); int server_unlock(const char *); void server_kill_window(struct window *); int server_link_window( From 123ae9e103d007ca2967f1c642f06c3736411ae0 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 4 Oct 2009 08:23:01 +0000 Subject: [PATCH 0354/1180] Support C-n/C-p with emacs keys in choice mode, also fix a comment. --- mode-key.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mode-key.c b/mode-key.c index ce711e0f..2f1a883c 100644 --- a/mode-key.c +++ b/mode-key.c @@ -191,7 +191,7 @@ struct mode_key_tree mode_key_tree_vi_copy; /* emacs editing keys. */ const struct mode_key_entry mode_key_emacs_edit[] = { { '\001' /* C-a */, 0, MODEKEYEDIT_STARTOFLINE }, - { '\002' /* C-p */, 0, MODEKEYEDIT_CURSORLEFT }, + { '\002' /* C-b */, 0, MODEKEYEDIT_CURSORLEFT }, { '\003' /* C-c */, 0, MODEKEYEDIT_CANCEL }, { '\004' /* C-d */, 0, MODEKEYEDIT_DELETE }, { '\005' /* C-e */, 0, MODEKEYEDIT_ENDOFLINE }, @@ -221,6 +221,8 @@ struct mode_key_tree mode_key_tree_emacs_edit; /* emacs choice selection keys. */ const struct mode_key_entry mode_key_emacs_choice[] = { { '\003' /* C-c */, 0, MODEKEYCHOICE_CANCEL }, + { '\016' /* C-n */, 0, MODEKEYCHOICE_DOWN }, + { '\020' /* C-p */, 0, MODEKEYCHOICE_UP }, { '\033' /* Escape */, 0, MODEKEYCHOICE_CANCEL }, { '\r', 0, MODEKEYCHOICE_CHOOSE }, { 'q', 0, MODEKEYCHOICE_CANCEL }, From 97ca5711f937c56bf667aa3b27f2c449d58d4510 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 4 Oct 2009 08:26:41 +0000 Subject: [PATCH 0355/1180] C-v and M-v too. --- mode-key.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mode-key.c b/mode-key.c index 2f1a883c..088d1b3a 100644 --- a/mode-key.c +++ b/mode-key.c @@ -223,9 +223,11 @@ const struct mode_key_entry mode_key_emacs_choice[] = { { '\003' /* C-c */, 0, MODEKEYCHOICE_CANCEL }, { '\016' /* C-n */, 0, MODEKEYCHOICE_DOWN }, { '\020' /* C-p */, 0, MODEKEYCHOICE_UP }, + { '\026' /* C-v */, 0, MODEKEYCHOICE_PAGEDOWN }, { '\033' /* Escape */, 0, MODEKEYCHOICE_CANCEL }, { '\r', 0, MODEKEYCHOICE_CHOOSE }, { 'q', 0, MODEKEYCHOICE_CANCEL }, + { 'v' | KEYC_ESCAPE, 0, MODEKEYCHOICE_PAGEUP }, { KEYC_DOWN, 0, MODEKEYCHOICE_DOWN }, { KEYC_NPAGE, 0, MODEKEYCHOICE_PAGEDOWN }, { KEYC_PPAGE, 0, MODEKEYCHOICE_PAGEUP }, From 205857b2320522c5c27cce9e98ad01972fda5e92 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 4 Oct 2009 08:50:05 +0000 Subject: [PATCH 0356/1180] Add a key string for space ("Space") and document the names, suggested by guenther@. Also document how to bind " and ', suggested by miod@. --- key-string.c | 1 + tmux.1 | 52 ++++++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 45 insertions(+), 8 deletions(-) diff --git a/key-string.c b/key-string.c index 68a57f8b..55de32fe 100644 --- a/key-string.c +++ b/key-string.c @@ -57,6 +57,7 @@ struct { { "PPage", KEYC_PPAGE }, { "Tab", '\011' }, { "BTab", KEYC_BTAB }, + { "Space", ' ' }, { "BSpace", KEYC_BSPACE }, { "Enter", '\r' }, { "Escape", '\033' }, diff --git a/tmux.1 b/tmux.1 index 22351bfa..a37a5939 100644 --- a/tmux.1 +++ b/tmux.1 @@ -978,6 +978,50 @@ destroyed. Move up a pane. .El .Sh KEY BINDINGS +.Nm +allows a command to be bound to most keys, with or without a prefix key. +When specifying keys, most represent themselves (for example +.Ql A +to +.Ql Z +). +Ctrl keys may be prefixed with +.Ql C- +or +.Ql ^ +, and Alt (meta) with +.Ql M- . +In addition, the following special key names are accepted: +.Em BSpace , +.Em BTab , +.Em DC +(Delete), +.Em End , +.Em Enter , +.Em Escape , +.Em F1 +to +.Em F20 , +.Em Home , +.Em IC +(Insert), +.Em NPage +(Page Up), +.Em PPage +(Page Down), +.Em Space , +and +.Em Tab . +Note that to bind the +.Ql \&" +or +.Ql ' +keys, quotation marks are necessary, for example: +.Bd -literal -offset indent +bind-key '"' split-window +bind-key "'" select-prompt +.Ed +.Pp Commands related to key bindings are as follows: .Bl -tag -width Ds .It Xo Ic bind-key @@ -990,14 +1034,6 @@ Bind key .Ar key to .Ar command . -Keys may be specified prefixed with -.Ql C- -or -.Ql ^ -for Ctrl keys, or -.Ql M- -for Alt (meta) keys. -.Pp By default (without .Fl t ) the primary key bindings are modified (those normally activated with the prefix From c734789b1876151704fadc834bb163994131037c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 4 Oct 2009 10:55:30 +0000 Subject: [PATCH 0357/1180] Check for already locked/suspended clients in server_lock_client rather than its callers. --- server-fn.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/server-fn.c b/server-fn.c index 6acca2bf..4e3e12ec 100644 --- a/server-fn.c +++ b/server-fn.c @@ -164,8 +164,6 @@ server_lock(void) c = ARRAY_ITEM(&clients, i); if (c == NULL || c->session == NULL) continue; - if (c->flags & CLIENT_SUSPENDED) - continue; server_lock_client(c); } } @@ -180,8 +178,6 @@ server_lock_session(struct session *s) c = ARRAY_ITEM(&clients, i); if (c == NULL || c->session == NULL || c->session != s) continue; - if (c->flags & CLIENT_SUSPENDED) - continue; server_lock_client(c); } } @@ -193,6 +189,9 @@ server_lock_client(struct client *c) size_t cmdlen; struct msg_lock_data lockdata; + if (c->flags & CLIENT_SUSPENDED) + return; + cmd = options_get_string(&c->session->options, "lock-command"); cmdlen = strlcpy(lockdata.cmd, cmd, sizeof lockdata.cmd); if (cmdlen >= sizeof lockdata.cmd) From d42b86d22b4c381717ca7f293359a2ca594ab59a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 4 Oct 2009 11:18:26 +0000 Subject: [PATCH 0358/1180] Get / and ? the right way round in vi mode, and use : for goto line rather than g. --- mode-key.c | 6 +++--- tmux.1 | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mode-key.c b/mode-key.c index 088d1b3a..9fc8c4b2 100644 --- a/mode-key.c +++ b/mode-key.c @@ -155,9 +155,10 @@ struct mode_key_tree mode_key_tree_vi_choice; const struct mode_key_entry mode_key_vi_copy[] = { { ' ', 0, MODEKEYCOPY_STARTSELECTION }, { '$', 0, MODEKEYCOPY_ENDOFLINE }, - { '/', 0, MODEKEYCOPY_SEARCHUP }, + { '/', 0, MODEKEYCOPY_SEARCHDOWN }, { '0', 0, MODEKEYCOPY_STARTOFLINE }, - { '?', 0, MODEKEYCOPY_SEARCHDOWN }, + { ':', 0, MODEKEYCOPY_GOTOLINE }, + { '?', 0, MODEKEYCOPY_SEARCHUP }, { '\002' /* C-b */, 0, MODEKEYCOPY_PREVIOUSPAGE }, { '\003' /* C-c */, 0, MODEKEYCOPY_CANCEL }, { '\004' /* C-d */, 0, MODEKEYCOPY_HALFPAGEDOWN }, @@ -168,7 +169,6 @@ const struct mode_key_entry mode_key_vi_copy[] = { { '\r', 0, MODEKEYCOPY_COPYSELECTION }, { '^', 0, MODEKEYCOPY_BACKTOINDENTATION }, { 'b', 0, MODEKEYCOPY_PREVIOUSWORD }, - { 'g', 0, MODEKEYCOPY_GOTOLINE }, { 'h', 0, MODEKEYCOPY_LEFT }, { 'j', 0, MODEKEYCOPY_DOWN }, { 'k', 0, MODEKEYCOPY_UP }, diff --git a/tmux.1 b/tmux.1 index a37a5939..637745a3 100644 --- a/tmux.1 +++ b/tmux.1 @@ -508,7 +508,7 @@ The following keys are supported as appropriate for the mode: .It Li "Delete entire line" Ta "d" Ta "C-u" .It Li "Delete to end of line" Ta "D" Ta "C-k" .It Li "End of line" Ta "$" Ta "C-e" -.It Li "Goto line" Ta "g" Ta "g" +.It Li "Goto line" Ta ":" Ta "g" .It Li "Next page" Ta "C-f" Ta "Page down" .It Li "Next word" Ta "w" Ta "M-f" .It Li "Paste buffer" Ta "p" Ta "C-y" From 45043ebf3ecabb8847d404baa7b3e9d66696f667 Mon Sep 17 00:00:00 2001 From: Jason McIntyre Date: Sun, 4 Oct 2009 11:33:35 +0000 Subject: [PATCH 0359/1180] tweak previous; --- tmux.1 | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tmux.1 b/tmux.1 index 637745a3..7a3daaf4 100644 --- a/tmux.1 +++ b/tmux.1 @@ -983,13 +983,12 @@ allows a command to be bound to most keys, with or without a prefix key. When specifying keys, most represent themselves (for example .Ql A to -.Ql Z -). +.Ql Z ) . Ctrl keys may be prefixed with .Ql C- or -.Ql ^ -, and Alt (meta) with +.Ql ^ , +and Alt (meta) with .Ql M- . In addition, the following special key names are accepted: .Em BSpace , From 4ca2200d838732c129c6dd5c11f92245346a1e28 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 5 Oct 2009 18:30:54 +0000 Subject: [PATCH 0360/1180] If no target client is specified to commands which accept one, try to guess the current client, in a similar manner to how sessions already work: if the current session can be established and has only one client, use that; otherwise use the most recently created client. --- cmd.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++-- server.c | 3 +++ tmux.h | 1 + 3 files changed, 53 insertions(+), 2 deletions(-) diff --git a/cmd.c b/cmd.c index 05294be1..17cf0c16 100644 --- a/cmd.c +++ b/cmd.c @@ -110,6 +110,7 @@ const struct cmd_entry *cmd_table[] = { }; struct session *cmd_newest_session(struct sessions *); +struct client *cmd_newest_client(void); struct client *cmd_lookup_client(const char *); struct session *cmd_lookup_session(const char *, int *); struct winlink *cmd_lookup_window(struct session *, const char *, int *); @@ -369,17 +370,63 @@ cmd_newest_session(struct sessions *ss) return (snewest); } +/* Find the newest client. */ +struct client * +cmd_newest_client(void) +{ + struct client *c, *cnewest; + struct timeval *tv = NULL; + u_int i; + + cnewest = NULL; + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + if ((c = ARRAY_ITEM(&clients, i)) == NULL) + continue; + if (c->session == NULL) + continue; + + if (tv == NULL || timercmp(&c->tv, tv, >)) { + cnewest = c; + tv = &c->tv; + } + } + + return (cnewest); +} + /* Find the target client or report an error and return NULL. */ struct client * cmd_find_client(struct cmd_ctx *ctx, const char *arg) { struct client *c; + struct session *s; char *tmparg; size_t arglen; + u_int i; /* A NULL argument means the current client. */ - if (arg == NULL) - return (ctx->curclient); + if (arg == NULL) { + if (ctx->curclient != NULL) + return (ctx->curclient); + /* + * No current client set. Find the current session and see if + * it has only has one client. + */ + s = cmd_current_session(ctx); + if (s != NULL) { + c = NULL; + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + if (ARRAY_ITEM(&clients, i)->session == s) { + if (c != NULL) + break; + c = ARRAY_ITEM(&clients, i); + } + } + if (i == ARRAY_LENGTH(&clients) && c != NULL) + return (c); + } + return (cmd_newest_client()); + } tmparg = xstrdup(arg); /* Trim a single trailing colon if any. */ diff --git a/server.c b/server.c index f7136784..b192cace 100644 --- a/server.c +++ b/server.c @@ -90,6 +90,9 @@ server_create_client(int fd) c = xcalloc(1, sizeof *c); c->references = 0; imsg_init(&c->ibuf, fd); + + if (gettimeofday(&c->tv, NULL) != 0) + fatal("gettimeofday failed"); ARRAY_INIT(&c->prompt_hdata); diff --git a/tmux.h b/tmux.h index 3c49ae30..f21962b9 100644 --- a/tmux.h +++ b/tmux.h @@ -922,6 +922,7 @@ struct tty_ctx { /* Client connection. */ struct client { struct imsgbuf ibuf; + struct timeval tv; struct environ environ; From 9400fdac77cff0607f592c969949c7e4feed4913 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 6 Oct 2009 07:09:00 +0000 Subject: [PATCH 0361/1180] Make C-Up and C-Down in copy mode scroll the screen up and down one line without moving the cursor, like Up and Down in scroll mode (which will shortly disappear). --- mode-key.c | 6 ++++++ tmux.1 | 2 ++ tmux.h | 2 ++ window-copy.c | 38 ++++++++++++++++++++++++-------------- 4 files changed, 34 insertions(+), 14 deletions(-) diff --git a/mode-key.c b/mode-key.c index 9fc8c4b2..864989de 100644 --- a/mode-key.c +++ b/mode-key.c @@ -89,6 +89,8 @@ struct mode_key_cmdstr mode_key_cmdstr_copy[] = { { MODEKEYCOPY_PREVIOUSPAGE, "page-up" }, { MODEKEYCOPY_PREVIOUSWORD, "previous-word" }, { MODEKEYCOPY_RIGHT, "cursor-right" }, + { MODEKEYCOPY_SCROLLDOWN, "scroll-down" }, + { MODEKEYCOPY_SCROLLUP, "scroll-up" }, { MODEKEYCOPY_SEARCHAGAIN, "search-again" }, { MODEKEYCOPY_SEARCHDOWN, "search-forward" }, { MODEKEYCOPY_SEARCHUP, "search-backward" }, @@ -177,11 +179,13 @@ const struct mode_key_entry mode_key_vi_copy[] = { { 'q', 0, MODEKEYCOPY_CANCEL }, { 'w', 0, MODEKEYCOPY_NEXTWORD }, { KEYC_BSPACE, 0, MODEKEYCOPY_LEFT }, + { KEYC_DOWN | KEYC_CTRL,0, MODEKEYCOPY_SCROLLDOWN }, { KEYC_DOWN, 0, MODEKEYCOPY_DOWN }, { KEYC_LEFT, 0, MODEKEYCOPY_LEFT }, { KEYC_NPAGE, 0, MODEKEYCOPY_NEXTPAGE }, { KEYC_PPAGE, 0, MODEKEYCOPY_PREVIOUSPAGE }, { KEYC_RIGHT, 0, MODEKEYCOPY_RIGHT }, + { KEYC_UP | KEYC_CTRL, 0, MODEKEYCOPY_SCROLLUP }, { KEYC_UP, 0, MODEKEYCOPY_UP }, { 0, -1, 0 } @@ -262,12 +266,14 @@ const struct mode_key_entry mode_key_emacs_copy[] = { { 'q', 0, MODEKEYCOPY_CANCEL }, { 'v' | KEYC_ESCAPE, 0, MODEKEYCOPY_PREVIOUSPAGE }, { 'w' | KEYC_ESCAPE, 0, MODEKEYCOPY_COPYSELECTION }, + { KEYC_DOWN | KEYC_CTRL,0, MODEKEYCOPY_SCROLLDOWN }, { KEYC_DOWN | KEYC_ESCAPE, 0, MODEKEYCOPY_HALFPAGEDOWN }, { KEYC_DOWN, 0, MODEKEYCOPY_DOWN }, { KEYC_LEFT, 0, MODEKEYCOPY_LEFT }, { KEYC_NPAGE, 0, MODEKEYCOPY_NEXTPAGE }, { KEYC_PPAGE, 0, MODEKEYCOPY_PREVIOUSPAGE }, { KEYC_RIGHT, 0, MODEKEYCOPY_RIGHT }, + { KEYC_UP | KEYC_CTRL, 0, MODEKEYCOPY_SCROLLUP }, { KEYC_UP | KEYC_ESCAPE, 0, MODEKEYCOPY_HALFPAGEUP }, { KEYC_UP, 0, MODEKEYCOPY_UP }, diff --git a/tmux.1 b/tmux.1 index 7a3daaf4..40955cce 100644 --- a/tmux.1 +++ b/tmux.1 @@ -515,6 +515,8 @@ The following keys are supported as appropriate for the mode: .It Li "Previous page" Ta "C-u" Ta "Page up" .It Li "Previous word" Ta "b" Ta "M-b" .It Li "Quit mode" Ta "q" Ta "Escape" +.It Li "Scroll down" Ta "C-Down" Ta "C-Down" +.It Li "Scroll up" Ta "C-Up" Ta "C-Up" .It Li "Search again" Ta "n" Ta "n" .It Li "Search backward" Ta "?" Ta "C-r" .It Li "Search forward" Ta "/" Ta "C-s" diff --git a/tmux.h b/tmux.h index f21962b9..89d68e2c 100644 --- a/tmux.h +++ b/tmux.h @@ -402,6 +402,8 @@ enum mode_key_cmd { MODEKEYCOPY_PREVIOUSPAGE, MODEKEYCOPY_PREVIOUSWORD, MODEKEYCOPY_RIGHT, + MODEKEYCOPY_SCROLLDOWN, + MODEKEYCOPY_SCROLLUP, MODEKEYCOPY_SEARCHAGAIN, MODEKEYCOPY_SEARCHDOWN, MODEKEYCOPY_SEARCHUP, diff --git a/window-copy.c b/window-copy.c index 053a6a49..0f497f87 100644 --- a/window-copy.c +++ b/window-copy.c @@ -61,8 +61,8 @@ void window_copy_cursor_back_to_indentation(struct window_pane *); void window_copy_cursor_end_of_line(struct window_pane *); void window_copy_cursor_left(struct window_pane *); void window_copy_cursor_right(struct window_pane *); -void window_copy_cursor_up(struct window_pane *); -void window_copy_cursor_down(struct window_pane *); +void window_copy_cursor_up(struct window_pane *, int); +void window_copy_cursor_down(struct window_pane *, int); void window_copy_cursor_next_word(struct window_pane *); void window_copy_cursor_previous_word(struct window_pane *); void window_copy_scroll_up(struct window_pane *, u_int); @@ -235,11 +235,17 @@ window_copy_key(struct window_pane *wp, struct client *c, int key) window_copy_cursor_right(wp); return; case MODEKEYCOPY_UP: - window_copy_cursor_up(wp); + window_copy_cursor_up(wp, 0); return; case MODEKEYCOPY_DOWN: - window_copy_cursor_down(wp); + window_copy_cursor_down(wp, 0); return; + case MODEKEYCOPY_SCROLLUP: + window_copy_cursor_up(wp, 1); + break; + case MODEKEYCOPY_SCROLLDOWN: + window_copy_cursor_down(wp, 1); + break; case MODEKEYCOPY_PREVIOUSPAGE: window_copy_pageup(wp); break; @@ -1020,7 +1026,7 @@ window_copy_cursor_left(struct window_pane *wp) struct window_copy_mode_data *data = wp->modedata; if (data->cx == 0) { - window_copy_cursor_up(wp); + window_copy_cursor_up(wp, 0); window_copy_cursor_end_of_line(wp); } else { window_copy_update_cursor(wp, data->cx - 1, data->cy); @@ -1040,7 +1046,7 @@ window_copy_cursor_right(struct window_pane *wp) if (data->cx >= px) { window_copy_cursor_start_of_line(wp); - window_copy_cursor_down(wp); + window_copy_cursor_down(wp, 0); } else { window_copy_update_cursor(wp, data->cx + 1, data->cy); if (window_copy_update_selection(wp)) @@ -1049,7 +1055,7 @@ window_copy_cursor_right(struct window_pane *wp) } void -window_copy_cursor_up(struct window_pane *wp) +window_copy_cursor_up(struct window_pane *wp, int scroll_only) { struct window_copy_mode_data *data = wp->modedata; u_int ox, oy, px, py; @@ -1062,9 +1068,11 @@ window_copy_cursor_up(struct window_pane *wp) } data->cx = data->lastcx; - if (data->cy == 0) + if (scroll_only || data->cy == 0) { window_copy_scroll_down(wp, 1); - else { + if (scroll_only && window_copy_update_selection(wp)) + window_copy_redraw_lines(wp, data->cy, 2); + } else { window_copy_update_cursor(wp, data->cx, data->cy - 1); if (window_copy_update_selection(wp)) window_copy_redraw_lines(wp, data->cy, 2); @@ -1077,7 +1085,7 @@ window_copy_cursor_up(struct window_pane *wp) } void -window_copy_cursor_down(struct window_pane *wp) +window_copy_cursor_down(struct window_pane *wp, int scroll_only) { struct window_copy_mode_data *data = wp->modedata; struct screen *s = &data->screen; @@ -1091,9 +1099,11 @@ window_copy_cursor_down(struct window_pane *wp) } data->cx = data->lastcx; - if (data->cy == screen_size_y(s) - 1) + if (scroll_only || data->cy == screen_size_y(s) - 1) { window_copy_scroll_up(wp, 1); - else { + if (scroll_only && window_copy_update_selection(wp)) + window_copy_redraw_lines(wp, data->cy - 1, 2); + } else { window_copy_update_cursor(wp, data->cx, data->cy + 1); if (window_copy_update_selection(wp)) window_copy_redraw_lines(wp, data->cy - 1, 2); @@ -1137,7 +1147,7 @@ window_copy_cursor_next_word(struct window_pane *wp) } px = 0; - window_copy_cursor_down(wp); + window_copy_cursor_down(wp, 0); py =screen_hsize( &wp->base) + data->cy - data->oy; @@ -1185,7 +1195,7 @@ window_copy_cursor_previous_word(struct window_pane *wp) (screen_hsize(&wp->base) == 0 || data->oy >= screen_hsize(&wp->base) - 1)) goto out; - window_copy_cursor_up(wp); + window_copy_cursor_up(wp, 0); py = screen_hsize( &wp->base) + data->cy - data->oy; From 35ca994ba274a0f3f71e50b0a1aadf275d4441dc Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 6 Oct 2009 07:19:32 +0000 Subject: [PATCH 0362/1180] Remove scroll mode which is now redundant, copy mode should be used instead. The = key binding now does nothing. --- Makefile | 4 +- cmd-copy-mode.c | 18 ++- cmd-scroll-mode.c | 70 ---------- cmd.c | 1 - key-bindings.c | 3 +- tmux.1 | 18 +-- tmux.h | 5 - window-scroll.c | 323 ---------------------------------------------- 8 files changed, 21 insertions(+), 421 deletions(-) delete mode 100644 cmd-scroll-mode.c delete mode 100644 window-scroll.c diff --git a/Makefile b/Makefile index f6df7718..591badde 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,7 @@ SRCS= attributes.c buffer-poll.c buffer.c cfg.c client-fn.c \ cmd-previous-layout.c cmd-previous-window.c cmd-refresh-client.c \ cmd-rename-session.c cmd-rename-window.c cmd-resize-pane.c \ cmd-respawn-window.c cmd-rotate-window.c cmd-save-buffer.c \ - cmd-scroll-mode.c cmd-select-layout.c cmd-select-pane.c \ + cmd-select-layout.c cmd-select-pane.c \ cmd-select-prompt.c cmd-select-window.c cmd-send-keys.c \ cmd-send-prefix.c cmd-server-info.c cmd-set-buffer.c cmd-set-option.c \ cmd-set-window-option.c cmd-show-buffer.c \ @@ -35,7 +35,7 @@ SRCS= attributes.c buffer-poll.c buffer.c cfg.c client-fn.c \ resize.c screen-redraw.c screen-write.c screen.c server-fn.c \ server-msg.c server.c session.c status.c tmux.c tty-keys.c tty-term.c \ tty.c utf8.c window-choose.c window-clock.c \ - window-copy.c window-more.c window-scroll.c window.c xmalloc.c + window-copy.c window-more.c window.c xmalloc.c CDIAGFLAGS+= -Wno-long-long -Wall -W -Wnested-externs -Wformat=2 CDIAGFLAGS+= -Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations diff --git a/cmd-copy-mode.c b/cmd-copy-mode.c index f72f1c1b..fda19efb 100644 --- a/cmd-copy-mode.c +++ b/cmd-copy-mode.c @@ -24,19 +24,35 @@ * Enter copy mode. */ +void cmd_copy_mode_init(struct cmd *, int); int cmd_copy_mode_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_copy_mode_entry = { "copy-mode", NULL, "[-u] " CMD_TARGET_PANE_USAGE, 0, CMD_CHFLAG('u'), - cmd_target_init, + cmd_copy_mode_init, cmd_target_parse, cmd_copy_mode_exec, cmd_target_free, NULL }; +void +cmd_copy_mode_init(struct cmd *self, int key) +{ + struct cmd_target_data *data; + + cmd_target_init(self, key); + data = self->data; + + switch (key) { + case KEYC_PPAGE: + data->chflags |= CMD_CHFLAG('u'); + break; + } +} + int cmd_copy_mode_exec(struct cmd *self, struct cmd_ctx *ctx) { diff --git a/cmd-scroll-mode.c b/cmd-scroll-mode.c deleted file mode 100644 index b5e4d7c9..00000000 --- a/cmd-scroll-mode.c +++ /dev/null @@ -1,70 +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" - -/* - * Enter scroll mode. - */ - -void cmd_scroll_mode_init(struct cmd *, int); -int cmd_scroll_mode_exec(struct cmd *, struct cmd_ctx *); - -const struct cmd_entry cmd_scroll_mode_entry = { - "scroll-mode", NULL, - "[-u] " CMD_TARGET_PANE_USAGE, - 0, CMD_CHFLAG('u'), - cmd_scroll_mode_init, - cmd_target_parse, - cmd_scroll_mode_exec, - cmd_target_free, - cmd_target_print -}; - -void -cmd_scroll_mode_init(struct cmd *self, int key) -{ - struct cmd_target_data *data; - - cmd_target_init(self, key); - data = self->data; - - switch (key) { - case KEYC_PPAGE: - data->chflags |= CMD_CHFLAG('u'); - break; - } -} - -int -cmd_scroll_mode_exec(struct cmd *self, struct cmd_ctx *ctx) -{ - struct cmd_target_data *data = self->data; - struct window_pane *wp; - - if (cmd_find_pane(ctx, data->target, NULL, &wp) == NULL) - return (-1); - - window_pane_set_mode(wp, &window_scroll_mode); - if (wp->mode == &window_scroll_mode && data->chflags & CMD_CHFLAG('u')) - window_scroll_pageup(wp); - - return (0); -} diff --git a/cmd.c b/cmd.c index 17cf0c16..1119bdc7 100644 --- a/cmd.c +++ b/cmd.c @@ -80,7 +80,6 @@ const struct cmd_entry *cmd_table[] = { &cmd_rotate_window_entry, &cmd_run_shell_entry, &cmd_save_buffer_entry, - &cmd_scroll_mode_entry, &cmd_select_layout_entry, &cmd_select_pane_entry, &cmd_select_prompt_entry, diff --git a/key-bindings.c b/key-bindings.c index 31c7e5e9..d15e0186 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -122,7 +122,6 @@ key_bindings_init(void) { '8', 0, &cmd_select_window_entry }, { '9', 0, &cmd_select_window_entry }, { ':', 0, &cmd_command_prompt_entry }, - { '=', 0, &cmd_scroll_mode_entry }, { '?', 0, &cmd_list_keys_entry }, { '[', 0, &cmd_copy_mode_entry }, { '\'', 0, &cmd_select_prompt_entry }, @@ -150,7 +149,7 @@ key_bindings_init(void) { '2' | KEYC_ESCAPE, 0, &cmd_select_layout_entry }, { '3' | KEYC_ESCAPE, 0, &cmd_select_layout_entry }, { '4' | KEYC_ESCAPE, 0, &cmd_select_layout_entry }, - { KEYC_PPAGE, 0, &cmd_scroll_mode_entry }, + { KEYC_PPAGE, 0, &cmd_copy_mode_entry }, { 'n' | KEYC_ESCAPE, 0, &cmd_next_window_entry }, { 'p' | KEYC_ESCAPE, 0, &cmd_previous_window_entry }, { KEYC_UP, 0, &cmd_up_pane_entry }, diff --git a/tmux.1 b/tmux.1 index 40955cce..31afd505 100644 --- a/tmux.1 +++ b/tmux.1 @@ -474,12 +474,6 @@ The others are: This is entered when a command which produces output, such as .Ic list-keys , is executed from a key binding. -.It Em scroll mode -This is entered with the -.Ic scroll-mode -command (bound to -.Ql = -by default) and permits the window history buffer to be inspected. .It Em copy mode This permits a section of a window or its history to be copied to a .Em paste buffer @@ -539,7 +533,7 @@ command) or in output mode; and .Em vi-copy and .Em emacs-copy -used in copy and scroll modes. +used in copy mode. The tables may be viewed with the .Ic list-keys command and keys modified or removed with @@ -560,16 +554,6 @@ Enter copy mode. The .Fl u option scrolls one page up. -.It Xo Ic scroll-mode -.Op Fl u -.Op Fl t Ar target-pane -.Xc -Enter scroll mode. -The -.Fl u -has the same meaning as in the -.Ic copy-mode -command. .El .Pp Each window displayed by diff --git a/tmux.h b/tmux.h index 89d68e2c..6a478614 100644 --- a/tmux.h +++ b/tmux.h @@ -1348,7 +1348,6 @@ extern const struct cmd_entry cmd_respawn_window_entry; extern const struct cmd_entry cmd_rotate_window_entry; extern const struct cmd_entry cmd_run_shell_entry; extern const struct cmd_entry cmd_save_buffer_entry; -extern const struct cmd_entry cmd_scroll_mode_entry; extern const struct cmd_entry cmd_select_layout_entry; extern const struct cmd_entry cmd_select_pane_entry; extern const struct cmd_entry cmd_select_prompt_entry; @@ -1701,10 +1700,6 @@ extern const struct window_mode window_clock_mode; extern const struct window_mode window_copy_mode; void window_copy_pageup(struct window_pane *); -/* window-scroll.c */ -extern const struct window_mode window_scroll_mode; -void window_scroll_pageup(struct window_pane *); - /* window-more.c */ extern const struct window_mode window_more_mode; void window_more_vadd(struct window_pane *, const char *, va_list); diff --git a/window-scroll.c b/window-scroll.c deleted file mode 100644 index fa6a5847..00000000 --- a/window-scroll.c +++ /dev/null @@ -1,323 +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 - -#include "tmux.h" - -struct screen *window_scroll_init(struct window_pane *); -void window_scroll_free(struct window_pane *); -void window_scroll_resize(struct window_pane *, u_int, u_int); -void window_scroll_key(struct window_pane *, struct client *, int); - -void window_scroll_redraw_screen(struct window_pane *); -void window_scroll_write_line( - struct window_pane *, struct screen_write_ctx *, u_int); -void window_scroll_write_column( - struct window_pane *, struct screen_write_ctx *, u_int); - -void window_scroll_scroll_up(struct window_pane *); -void window_scroll_scroll_down(struct window_pane *); -void window_scroll_scroll_left(struct window_pane *); -void window_scroll_scroll_right(struct window_pane *); - -const struct window_mode window_scroll_mode = { - window_scroll_init, - window_scroll_free, - window_scroll_resize, - window_scroll_key, - NULL, - NULL, -}; - -struct window_scroll_mode_data { - struct screen screen; - - struct mode_key_data mdata; - - u_int ox; - u_int oy; -}; - -struct screen * -window_scroll_init(struct window_pane *wp) -{ - struct window_scroll_mode_data *data; - struct screen *s; - struct screen_write_ctx ctx; - u_int i; - int keys; - - wp->modedata = data = xmalloc(sizeof *data); - data->ox = 0; - data->oy = 0; - - s = &data->screen; - screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0); - s->mode &= ~MODE_CURSOR; - - keys = options_get_number(&wp->window->options, "mode-keys"); - if (keys == MODEKEY_EMACS) - mode_key_init(&data->mdata, &mode_key_tree_emacs_copy); - else - mode_key_init(&data->mdata, &mode_key_tree_vi_copy); - - screen_write_start(&ctx, NULL, s); - for (i = 0; i < screen_size_y(s); i++) - window_scroll_write_line(wp, &ctx, i); - screen_write_stop(&ctx); - - return (s); -} - -void -window_scroll_free(struct window_pane *wp) -{ - struct window_scroll_mode_data *data = wp->modedata; - - screen_free(&data->screen); - xfree(data); -} - -void -window_scroll_pageup(struct window_pane *wp) -{ - struct window_scroll_mode_data *data = wp->modedata; - struct screen *s = &data->screen; - u_int n; - - n = 1; - if (screen_size_y(s) > 2) - n = screen_size_y(s) - 2; - if (data->oy + n > screen_hsize(&wp->base)) - data->oy = screen_hsize(&wp->base); - else - data->oy += n; - - window_scroll_redraw_screen(wp); -} - -void -window_scroll_resize(struct window_pane *wp, u_int sx, u_int sy) -{ - struct window_scroll_mode_data *data = wp->modedata; - struct screen *s = &data->screen; - struct screen_write_ctx ctx; - u_int i; - - screen_resize(s, sx, sy); - screen_write_start(&ctx, NULL, s); - for (i = 0; i < screen_size_y(s); i++) - window_scroll_write_line(wp, &ctx, i); - screen_write_stop(&ctx); -} - -void -window_scroll_key(struct window_pane *wp, unused struct client *c, int key) -{ - struct window_scroll_mode_data *data = wp->modedata; - struct screen *s = &data->screen; - u_int n; - - switch (mode_key_lookup(&data->mdata, key)) { - case MODEKEYCOPY_CANCEL: - window_pane_reset_mode(wp); - break; - case MODEKEYCOPY_LEFT: - window_scroll_scroll_left(wp); - break; - case MODEKEYCOPY_RIGHT: - window_scroll_scroll_right(wp); - break; - case MODEKEYCOPY_UP: - window_scroll_scroll_up(wp); - break; - case MODEKEYCOPY_DOWN: - window_scroll_scroll_down(wp); - break; - case MODEKEYCOPY_PREVIOUSPAGE: - window_scroll_pageup(wp); - break; - case MODEKEYCOPY_NEXTPAGE: - n = 1; - if (screen_size_y(s) > 2) - n = screen_size_y(s) - 2; - if (data->oy < n) - data->oy = 0; - else - data->oy -= n; - window_scroll_redraw_screen(wp); - break; - case MODEKEYCOPY_HALFPAGEUP: - n = screen_size_y(s) / 2; - if (data->oy + n > screen_hsize(&wp->base)) - data->oy = screen_hsize(&wp->base); - else - data->oy += n; - window_scroll_redraw_screen(wp); - break; - case MODEKEYCOPY_HALFPAGEDOWN: - n = screen_size_y(s) / 2; - if (data->oy < n) - data->oy = 0; - else - data->oy -= n; - window_scroll_redraw_screen(wp); - break; - default: - break; - } -} - -void -window_scroll_write_line( - struct window_pane *wp, struct screen_write_ctx *ctx, u_int py) -{ - struct window_scroll_mode_data *data = wp->modedata; - struct screen *s = &data->screen; - struct options *oo = &wp->window->options; - struct grid_cell gc; - char hdr[32]; - size_t size; - - if (py == 0) { - memcpy(&gc, &grid_default_cell, sizeof gc); - size = xsnprintf(hdr, sizeof hdr, - "[%u,%u/%u]", data->ox, data->oy, screen_hsize(&wp->base)); - 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"); - screen_write_cursormove(ctx, screen_size_x(s) - size, 0); - screen_write_puts(ctx, &gc, "%s", hdr); - memcpy(&gc, &grid_default_cell, sizeof gc); - } else - size = 0; - - screen_write_cursormove(ctx, 0, py); - screen_write_copy(ctx, &wp->base, data->ox, (screen_hsize(&wp->base) - - data->oy) + py, screen_size_x(s) - size, 1); -} - -void -window_scroll_write_column( - struct window_pane *wp, struct screen_write_ctx *ctx, u_int px) -{ - struct window_scroll_mode_data *data = wp->modedata; - struct screen *s = &data->screen; - - screen_write_cursormove(ctx, px, 0); - screen_write_copy(ctx, &wp->base, data->ox + px, - screen_hsize(&wp->base) - data->oy, 1, screen_size_y(s)); -} - -void -window_scroll_redraw_screen(struct window_pane *wp) -{ - struct window_scroll_mode_data *data = wp->modedata; - struct screen *s = &data->screen; - struct screen_write_ctx ctx; - u_int i; - - screen_write_start(&ctx, wp, NULL); - for (i = 0; i < screen_size_y(s); i++) - window_scroll_write_line(wp, &ctx, i); - screen_write_stop(&ctx); -} - -void -window_scroll_scroll_up(struct window_pane *wp) -{ - struct window_scroll_mode_data *data = wp->modedata; - struct screen_write_ctx ctx; - - if (data->oy >= screen_hsize(&wp->base)) - return; - data->oy++; - - screen_write_start(&ctx, wp, NULL); - screen_write_cursormove(&ctx, 0, 0); - screen_write_insertline(&ctx, 1); - window_scroll_write_line(wp, &ctx, 0); - window_scroll_write_line(wp, &ctx, 1); - screen_write_stop(&ctx); -} - -void -window_scroll_scroll_down(struct window_pane *wp) -{ - struct window_scroll_mode_data *data = wp->modedata; - struct screen *s = &data->screen; - struct screen_write_ctx ctx; - - if (data->oy == 0) - return; - data->oy--; - - screen_write_start(&ctx, wp, NULL); - screen_write_cursormove(&ctx, 0, 0); - screen_write_deleteline(&ctx, 1); - window_scroll_write_line(wp, &ctx, screen_size_y(s) - 1); - window_scroll_write_line(wp, &ctx, 0); - screen_write_stop(&ctx); -} - -void -window_scroll_scroll_right(struct window_pane *wp) -{ - struct window_scroll_mode_data *data = wp->modedata; - struct screen *s = &data->screen; - struct screen_write_ctx ctx; - u_int i; - - if (data->ox >= SHRT_MAX) - return; - data->ox++; - - screen_write_start(&ctx, wp, NULL); - for (i = 1; i < screen_size_y(s); i++) { - screen_write_cursormove(&ctx, 0, i); - screen_write_deletecharacter(&ctx, 1); - } - window_scroll_write_column(wp, &ctx, screen_size_x(s) - 1); - window_scroll_write_line(wp, &ctx, 0); - screen_write_stop(&ctx); -} - -void -window_scroll_scroll_left(struct window_pane *wp) -{ - struct window_scroll_mode_data *data = wp->modedata; - struct screen *s = &data->screen; - struct screen_write_ctx ctx; - u_int i; - - if (data->ox == 0) - return; - data->ox--; - - screen_write_start(&ctx, wp, NULL); - for (i = 1; i < screen_size_y(s); i++) { - screen_write_cursormove(&ctx, 0, i); - screen_write_insertcharacter(&ctx, 1); - } - window_scroll_write_column(wp, &ctx, 0); - window_scroll_write_line(wp, &ctx, 0); - screen_write_stop(&ctx); -} From 82efcc32ec4ccd12d5119942e62b8e11f9cb333b Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 6 Oct 2009 07:32:26 +0000 Subject: [PATCH 0363/1180] Accept ^? for backspace as well as BSpace. --- key-string.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/key-string.c b/key-string.c index 55de32fe..45026d59 100644 --- a/key-string.c +++ b/key-string.c @@ -121,6 +121,8 @@ key_string_lookup_string(const char *string) if (ptr[1] == '\0') { if (ptr[0] == 32) return (0); + if (ptr[0] == 63) + return (KEYC_BSPACE); if (ptr[0] >= 64 && ptr[0] <= 95) return (ptr[0] - 64); if (ptr[0] >= 97 && ptr[0] <= 122) From 56ddd3c0b16b4b22fd4f8e70f0ebbfb5a900e0ce Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 7 Oct 2009 07:02:40 +0000 Subject: [PATCH 0364/1180] Fix comment. --- cmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd.c b/cmd.c index 1119bdc7..9ae1fa17 100644 --- a/cmd.c +++ b/cmd.c @@ -409,7 +409,7 @@ cmd_find_client(struct cmd_ctx *ctx, const char *arg) return (ctx->curclient); /* * No current client set. Find the current session and see if - * it has only has one client. + * it has only one client. */ s = cmd_current_session(ctx); if (s != NULL) { From 2cb2bb8257b0d9258381829752bf12b29e35547c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 7 Oct 2009 15:58:40 +0000 Subject: [PATCH 0365/1180] Support J and K for scroll up and scroll down in copy mode with vi keys, suggested by martynas. --- mode-key.c | 2 ++ tmux.1 | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/mode-key.c b/mode-key.c index 864989de..3c15ff40 100644 --- a/mode-key.c +++ b/mode-key.c @@ -161,6 +161,8 @@ const struct mode_key_entry mode_key_vi_copy[] = { { '0', 0, MODEKEYCOPY_STARTOFLINE }, { ':', 0, MODEKEYCOPY_GOTOLINE }, { '?', 0, MODEKEYCOPY_SEARCHUP }, + { 'J', 0, MODEKEYCOPY_SCROLLDOWN }, + { 'K', 0, MODEKEYCOPY_SCROLLUP }, { '\002' /* C-b */, 0, MODEKEYCOPY_PREVIOUSPAGE }, { '\003' /* C-c */, 0, MODEKEYCOPY_CANCEL }, { '\004' /* C-d */, 0, MODEKEYCOPY_HALFPAGEDOWN }, diff --git a/tmux.1 b/tmux.1 index 31afd505..938dba43 100644 --- a/tmux.1 +++ b/tmux.1 @@ -490,7 +490,7 @@ The keys available depend on whether emacs or vi mode is selected .Ic mode-keys option). The following keys are supported as appropriate for the mode: -.Bl -column "FunctionXXXXXXXXXXXX" "viXXXXXX" "emacs" -offset indent +.Bl -column "FunctionXXXXXXXXXXXX" "viXXXXXXXXX" "emacs" -offset indent .It Sy "Function" Ta Sy "vi" Ta Sy "emacs" .It Li "Back to indentation" Ta "^" Ta "M-m" .It Li "Clear selection" Ta "Escape" Ta "C-g" @@ -509,8 +509,8 @@ The following keys are supported as appropriate for the mode: .It Li "Previous page" Ta "C-u" Ta "Page up" .It Li "Previous word" Ta "b" Ta "M-b" .It Li "Quit mode" Ta "q" Ta "Escape" -.It Li "Scroll down" Ta "C-Down" Ta "C-Down" -.It Li "Scroll up" Ta "C-Up" Ta "C-Up" +.It Li "Scroll down" Ta "C-Down or J" Ta "C-Down" +.It Li "Scroll up" Ta "C-Up or K" Ta "C-Up" .It Li "Search again" Ta "n" Ta "n" .It Li "Search backward" Ta "?" Ta "C-r" .It Li "Search forward" Ta "/" Ta "C-s" From d5281848361ede97d871553b011a706457acabd0 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 9 Oct 2009 07:23:28 +0000 Subject: [PATCH 0366/1180] Be less aggressive about turning the cursor off, only explicitly turn it off when tmux is redrawing, otherwise leave in the state set by the application. --- tty.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tty.c b/tty.c index 774808db..8dde904c 100644 --- a/tty.c +++ b/tty.c @@ -524,6 +524,8 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int py, u_int ox, u_int oy) const struct grid_utf8 *gu; u_int i, sx; + tty_update_mode(tty, tty->mode & ~MODE_CURSOR); + sx = screen_size_x(s); if (sx > s->grid->linedata[s->grid->hsize + py].cellsize) sx = s->grid->linedata[s->grid->hsize + py].cellsize; @@ -548,8 +550,10 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int py, u_int ox, u_int oy) tty_cell(tty, gc, gu); } - if (sx >= tty->sx) + if (sx >= tty->sx) { + tty_update_mode(tty, tty->mode); return; + } tty_reset(tty); tty_cursor(tty, sx, py, ox, oy); @@ -559,6 +563,7 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int py, u_int ox, u_int oy) for (i = sx; i < screen_size_x(s); i++) tty_putc(tty, ' '); } + tty_update_mode(tty, tty->mode); } void @@ -587,7 +592,6 @@ tty_write(void (*cmdfn)( if (c->session->curw->window == wp->window) { if (c->tty.flags & TTY_FREEZE || c->tty.term == NULL) continue; - tty_update_mode(&c->tty, c->tty.mode & ~MODE_CURSOR); cmdfn(&c->tty, ctx); } } From 3af09ac94697097d5a8cd45b82638ed9c3e941cc Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 9 Oct 2009 07:27:00 +0000 Subject: [PATCH 0367/1180] Add a simple synchronize-panes window option: when set, all input to any pane that is part of the window is also sent to all other panes in the same window. Suggested by several, most recently Tomasz Pajor. --- cmd-set-window-option.c | 1 + tmux.1 | 5 +++++ tmux.c | 1 + window.c | 16 ++++++++++++++-- 4 files changed, 21 insertions(+), 2 deletions(-) diff --git a/cmd-set-window-option.c b/cmd-set-window-option.c index 76d00e19..1ac62147 100644 --- a/cmd-set-window-option.c +++ b/cmd-set-window-option.c @@ -64,6 +64,7 @@ const struct set_option_entry set_window_option_table[] = { { "monitor-activity", SET_OPTION_FLAG, 0, 0, NULL }, { "monitor-content", SET_OPTION_STRING, 0, 0, NULL }, { "remain-on-exit", SET_OPTION_FLAG, 0, 0, NULL }, + { "synchronize-panes", SET_OPTION_FLAG, 0, 0, NULL }, { "utf8", SET_OPTION_FLAG, 0, 0, NULL }, { "window-status-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL }, { "window-status-bg", SET_OPTION_COLOUR, 0, 0, NULL }, diff --git a/tmux.1 b/tmux.1 index 938dba43..397ff83b 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1662,6 +1662,11 @@ The window may be reactivated with the .Ic respawn-window command. .Pp +.It Xo Ic synchronize-panes +.Op Ic on | off +.Xc +Duplicate input to any pane to all other panes in the same window, except +for panes that are not in output mode. .It Xo Ic utf8 .Op Ic on | off .Xc diff --git a/tmux.c b/tmux.c index 5673282f..eed7e9e1 100644 --- a/tmux.c +++ b/tmux.c @@ -441,6 +441,7 @@ main(int argc, char **argv) options_set_number(wo, "window-status-fg", 8); options_set_number(wo, "xterm-keys", 0); options_set_number(wo, "remain-on-exit", 0); + options_set_number(wo, "synchronize-panes", 0); if (flags & IDENTIFY_UTF8) { options_set_number(so, "status-utf8", 1); diff --git a/window.c b/window.c index b663acf3..9d2f3975 100644 --- a/window.c +++ b/window.c @@ -610,14 +610,26 @@ window_pane_parse(struct window_pane *wp) void window_pane_key(struct window_pane *wp, struct client *c, int key) { + struct window_pane *wp2; + if (wp->fd == -1 || !window_pane_visible(wp)) return; if (wp->mode != NULL) { if (wp->mode->key != NULL) wp->mode->key(wp, c, key); - } else - input_key(wp, key); + return; + } + + input_key(wp, key); + if (options_get_number(&wp->window->options, "synchronize-panes")) { + TAILQ_FOREACH(wp2, &wp->window->panes, entry) { + if (wp2 == wp || wp2->mode != NULL) + continue; + if (wp2->fd != -1 && window_pane_visible(wp2)) + input_key(wp2, key); + } + } } void From bf38a311daa8a8048974a401b88909aa56b25e19 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 9 Oct 2009 07:33:12 +0000 Subject: [PATCH 0368/1180] The UTF-8 detection idea doesn't work and I am reasonably happy with the current methods, so remove the (already #ifdef 0'd) code. --- tmux.h | 1 - tty.c | 81 ---------------------------------------------------------- 2 files changed, 82 deletions(-) diff --git a/tmux.h b/tmux.h index 6a478614..100793ed 100644 --- a/tmux.h +++ b/tmux.h @@ -1199,7 +1199,6 @@ void tty_init(struct tty *, int, char *); void tty_resize(struct tty *); void tty_start_tty(struct tty *); void tty_stop_tty(struct tty *); -void tty_detect_utf8(struct tty *); void tty_set_title(struct tty *, const char *); void tty_update_mode(struct tty *, int); void tty_draw_line(struct tty *, struct screen *, u_int, u_int, u_int); diff --git a/tty.c b/tty.c index 8dde904c..c61fd6b0 100644 --- a/tty.c +++ b/tty.c @@ -134,10 +134,6 @@ tty_start_tty(struct tty *tty) if (fcntl(tty->fd, F_SETFL, mode|O_NONBLOCK) == -1) fatal("fcntl failed"); -#if 0 - tty_detect_utf8(tty); -#endif - if (tcgetattr(tty->fd, &tty->tio) != 0) fatal("tcgetattr failed"); memcpy(&tio, &tty->tio, sizeof tio); @@ -216,83 +212,6 @@ tty_stop_tty(struct tty *tty) tty_raw(tty, tty_term_string(tty->term, TTYC_RMCUP)); } -#if 0 -void -tty_detect_utf8(struct tty *tty) -{ - struct pollfd pfd; - char buf[7]; - size_t len; - ssize_t n; - int nfds; - struct termios tio, old_tio; - int what; - - if (tty->flags & TTY_UTF8) - return; - - /* - * If the terminal looks reasonably likely to support this, try to - * write a three-byte UTF-8 wide character to the terminal, then read - * the cursor position. - * - * XXX This entire function is a hack. - */ - - /* Check if the terminal looks sort of vt100. */ - if (strstr(tty_term_string(tty->term, TTYC_CLEAR), "[2J") == NULL || - strstr(tty_term_string(tty->term, TTYC_CUP), "H") == NULL) - return; - - if (tcgetattr(tty->fd, &old_tio) != 0) - fatal("tcgetattr failed"); - cfmakeraw(&tio); - if (tcsetattr(tty->fd, TCSANOW, &tio) != 0) - fatal("tcsetattr failed"); - - what = 0; - if (ioctl(tty->fd, TIOCFLUSH, &what) != 0) - fatal("ioctl(TIOCFLUSH)"); - -#define UTF8_TEST_DATA "\033[H\357\277\246\033[6n" - if (write(tty->fd, UTF8_TEST_DATA, (sizeof UTF8_TEST_DATA) - 1) == -1) - fatal("write failed"); -#undef UTF8_TEST_DATA - - len = 0; - for (;;) { - pfd.fd = tty->fd; - pfd.events = POLLIN; - - nfds = poll(&pfd, 1, 500); - if (nfds == -1) { - if (errno == EAGAIN || errno == EINTR) - continue; - fatal("poll failed"); - } - if (nfds == 0) - break; - if (pfd.revents & (POLLERR|POLLNVAL|POLLHUP)) - break; - if (!(pfd.revents & POLLIN)) - continue; - - if ((n = read(tty->fd, buf + len, 1)) != 1) - break; - buf[++len] = '\0'; - - if (len == (sizeof buf) - 1) { - if (strcmp(buf, "\033[1;3R") == 0) - tty->flags |= TTY_UTF8; - break; - } - } - - if (tcsetattr(tty->fd, TCSANOW, &old_tio) != 0) - fatal("tcsetattr failed"); -} -#endif - void tty_fill_acs(struct tty *tty) { From 93b353d3532cc12e7e8ca05f59a2199398252df5 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 10 Oct 2009 09:31:39 +0000 Subject: [PATCH 0369/1180] Instead of passing a struct pollfd ** around through various functions, build them into a tree and then convert into a flat poll array before and after poll. This adds a little code but should reduce annoying problems with ordering when adding new things that also need to be polled. --- server.c | 218 ++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 144 insertions(+), 74 deletions(-) diff --git a/server.c b/server.c index b192cace..a1a0211f 100644 --- a/server.c +++ b/server.c @@ -45,16 +45,33 @@ struct clients clients; struct clients dead_clients; +/* Mapping of a pollfd to an fd independent of its position in the array. */ +struct poll_item { + struct pollfd pfd; + + RB_ENTRY(poll_item) entry; +}; +RB_HEAD(poll_items, poll_item) poll_items; + +int server_poll_cmp(struct poll_item *, struct poll_item *); +struct pollfd *server_poll_lookup(int); +void server_poll_add(int, int); +struct pollfd *server_poll_flatten(int *); +void server_poll_parse(struct pollfd *); +void server_poll_reset(void); +RB_PROTOTYPE(poll_items, poll_item, entry, server_poll_cmp); +RB_GENERATE(poll_items, poll_item, entry, server_poll_cmp); + void server_create_client(int); int server_create_socket(void); int server_main(int); void server_shutdown(void); int server_should_shutdown(void); void server_child_signal(void); -void server_fill_windows(struct pollfd **); -void server_handle_windows(struct pollfd **); -void server_fill_clients(struct pollfd **); -void server_handle_clients(struct pollfd **); +void server_fill_windows(void); +void server_handle_windows(void); +void server_fill_clients(void); +void server_handle_clients(void); void server_accept_client(int); void server_handle_client(struct client *); void server_handle_window(struct window *, struct window_pane *); @@ -72,6 +89,75 @@ void server_check_timers(struct client *); void server_second_timers(void); int server_update_socket(void); +int +server_poll_cmp(struct poll_item *pitem1, struct poll_item *pitem2) +{ + return (pitem1->pfd.fd - pitem2->pfd.fd); +} + +struct pollfd * +server_poll_lookup(int fd) +{ + struct poll_item pitem; + + pitem.pfd.fd = fd; + return (&RB_FIND(poll_items, &poll_items, &pitem)->pfd); +} + +void +server_poll_add(int fd, int events) +{ + struct poll_item *pitem; + + pitem = xmalloc(sizeof *pitem); + pitem->pfd.fd = fd; + pitem->pfd.events = events; + RB_INSERT(poll_items, &poll_items, pitem); +} + +struct pollfd * +server_poll_flatten(int *nfds) +{ + struct poll_item *pitem; + struct pollfd *pfds; + + pfds = NULL; + *nfds = 0; + RB_FOREACH(pitem, poll_items, &poll_items) { + pfds = xrealloc(pfds, (*nfds) + 1, sizeof *pfds); + pfds[*nfds].fd = pitem->pfd.fd; + pfds[*nfds].events = pitem->pfd.events; + (*nfds)++; + } + return (pfds); +} + +void +server_poll_parse(struct pollfd *pfds) +{ + struct poll_item *pitem; + int nfds; + + nfds = 0; + RB_FOREACH(pitem, poll_items, &poll_items) { + pitem->pfd.revents = pfds[nfds].revents; + nfds++; + } + xfree(pfds); +} + +void +server_poll_reset(void) +{ + struct poll_item *pitem; + + while (!RB_EMPTY(&poll_items)) { + pitem = RB_ROOT(&poll_items); + RB_REMOVE(poll_items, &poll_items, pitem); + xfree(pitem); + } +} + /* Create a new client. */ void server_create_client(int fd) @@ -245,7 +331,6 @@ server_create_socket(void) int server_main(int srv_fd) { - struct window *w; struct pollfd *pfds, *pfd; int nfds, xtimeout; u_int i; @@ -279,26 +364,13 @@ server_main(int srv_fd) sigusr1 = 0; } - /* Initialise pollfd array. */ - nfds = 1; - for (i = 0; i < ARRAY_LENGTH(&windows); i++) { - w = ARRAY_ITEM(&windows, i); - if (w != NULL) - nfds += window_count_panes(w); - } - nfds += ARRAY_LENGTH(&clients) * 2; - pfds = xrealloc(pfds, nfds, sizeof *pfds); - memset(pfds, 0, nfds * sizeof *pfds); - pfd = pfds; - - /* Fill server socket. */ - pfd->fd = srv_fd; - pfd->events = POLLIN; - pfd++; + /* Initialise pollfd array and add server socket. */ + server_poll_reset(); + server_poll_add(srv_fd, POLLIN); /* Fill window and client sockets. */ - server_fill_windows(&pfd); - server_fill_clients(&pfd); + server_fill_windows(); + server_fill_clients(); /* Update socket permissions. */ xtimeout = INFTIM; @@ -306,21 +378,23 @@ server_main(int srv_fd) xtimeout = POLL_TIMEOUT; /* Do the poll. */ + pfds = server_poll_flatten(&nfds); + log_debug("polling %d", nfds); if (poll(pfds, nfds, xtimeout) == -1) { if (errno == EAGAIN || errno == EINTR) continue; fatal("poll failed"); } - pfd = pfds; + server_poll_parse(pfds); /* Handle server socket. */ + pfd = server_poll_lookup(srv_fd); if (pfd->revents & (POLLERR|POLLNVAL|POLLHUP)) fatalx("lost server socket"); if (pfd->revents & POLLIN) { server_accept_client(srv_fd); continue; } - pfd++; /* Call second-based timers. */ now = time(NULL); @@ -337,8 +411,8 @@ server_main(int srv_fd) * windows, so windows must come first to avoid messing up by * increasing the array size. */ - server_handle_windows(&pfd); - server_handle_clients(&pfd); + server_handle_windows(); + server_handle_clients(); /* Collect any unset key bindings. */ key_bindings_clean(); @@ -346,8 +420,7 @@ server_main(int srv_fd) /* Collect dead clients and sessions. */ server_clean_dead(); } - if (pfds != NULL) - xfree(pfds); + server_poll_reset(); for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { if (ARRAY_ITEM(&sessions, i) != NULL) @@ -464,35 +537,36 @@ server_child_signal(void) /* Fill window pollfds. */ void -server_fill_windows(struct pollfd **pfd) +server_fill_windows(void) { struct window *w; struct window_pane *wp; u_int i; + int events; for (i = 0; i < ARRAY_LENGTH(&windows); i++) { w = ARRAY_ITEM(&windows, i); if (w == NULL) continue; - TAILQ_FOREACH(wp, &w->panes, entry) { - (*pfd)->fd = wp->fd; - if (wp->fd != -1) { - (*pfd)->events = POLLIN; - if (BUFFER_USED(wp->out) > 0) - (*pfd)->events |= POLLOUT; - } - (*pfd)++; + TAILQ_FOREACH(wp, &w->panes, entry) { + if (wp->fd == -1) + continue; + events = POLLIN; + if (BUFFER_USED(wp->out) > 0) + events |= POLLOUT; + server_poll_add(wp->fd, events); } } } /* Handle window pollfds. */ void -server_handle_windows(struct pollfd **pfd) +server_handle_windows(void) { struct window *w; struct window_pane *wp; + struct pollfd *pfd; u_int i; for (i = 0; i < ARRAY_LENGTH(&windows); i++) { @@ -501,14 +575,15 @@ server_handle_windows(struct pollfd **pfd) continue; TAILQ_FOREACH(wp, &w->panes, entry) { - if (wp->fd != -1) { - if (buffer_poll(*pfd, wp->in, wp->out) != 0) { - close(wp->fd); - wp->fd = -1; - } else - server_handle_window(w, wp); - } - (*pfd)++; + if (wp->fd == -1) + continue; + if ((pfd = server_poll_lookup(wp->fd)) == NULL) + continue; + if (buffer_poll(pfd, wp->in, wp->out) != 0) { + close(wp->fd); + wp->fd = -1; + } else + server_handle_window(w, wp); } server_check_window(w); @@ -624,12 +699,13 @@ server_check_timers(struct client *c) /* Fill client pollfds. */ void -server_fill_clients(struct pollfd **pfd) +server_fill_clients(void) { struct client *c; struct window *w; struct window_pane *wp; u_int i; + int events; for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); @@ -637,27 +713,22 @@ server_fill_clients(struct pollfd **pfd) server_check_timers(c); server_check_redraw(c); - if (c == NULL) - (*pfd)->fd = -1; - else { - (*pfd)->fd = c->ibuf.fd; + if (c != NULL) { + events = 0; if (!(c->flags & CLIENT_BAD)) - (*pfd)->events |= POLLIN; + events |= POLLIN; if (c->ibuf.w.queued > 0) - (*pfd)->events |= POLLOUT; + events |= POLLOUT; + server_poll_add(c->ibuf.fd, events); } - (*pfd)++; - if (c == NULL || c->flags & CLIENT_SUSPENDED || - c->tty.fd == -1 || c->session == NULL) - (*pfd)->fd = -1; - else { - (*pfd)->fd = c->tty.fd; - (*pfd)->events = POLLIN; + if (c != NULL && !(c->flags & CLIENT_SUSPENDED) && + c->tty.fd != -1 && c->session != NULL) { + events = POLLIN; if (BUFFER_USED(c->tty.out) > 0) - (*pfd)->events |= POLLOUT; + events |= POLLOUT; + server_poll_add(c->tty.fd, events); } - (*pfd)++; } /* @@ -677,25 +748,26 @@ server_fill_clients(struct pollfd **pfd) /* Handle client pollfds. */ void -server_handle_clients(struct pollfd **pfd) +server_handle_clients(void) { struct client *c; + struct pollfd *pfd; u_int i; for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); if (c != NULL) { - if ((*pfd)->revents & (POLLERR|POLLNVAL|POLLHUP)) { + if ((pfd = server_poll_lookup(c->ibuf.fd)) == NULL) + continue; + if (pfd->revents & (POLLERR|POLLNVAL|POLLHUP)) { server_lost_client(c); - (*pfd) += 2; continue; } - if ((*pfd)->revents & POLLOUT) { + if (pfd->revents & POLLOUT) { if (msgbuf_write(&c->ibuf.w) < 0) { server_lost_client(c); - (*pfd) += 2; continue; } } @@ -703,26 +775,24 @@ server_handle_clients(struct pollfd **pfd) if (c->flags & CLIENT_BAD) { if (c->ibuf.w.queued == 0) server_lost_client(c); - (*pfd) += 2; continue; - } else if ((*pfd)->revents & POLLIN) { + } else if (pfd->revents & POLLIN) { if (server_msg_dispatch(c) != 0) { server_lost_client(c); - (*pfd) += 2; continue; } } } - (*pfd)++; if (c != NULL && !(c->flags & CLIENT_SUSPENDED) && c->tty.fd != -1 && c->session != NULL) { - if (buffer_poll(*pfd, c->tty.in, c->tty.out) != 0) + if ((pfd = server_poll_lookup(c->tty.fd)) == NULL) + continue; + if (buffer_poll(pfd, c->tty.in, c->tty.out) != 0) server_lost_client(c); else server_handle_client(c); } - (*pfd)++; } } From b7d031cc92a1d9ac3ca8c2a71b76b0a78ea77465 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 10 Oct 2009 09:46:11 +0000 Subject: [PATCH 0370/1180] Support for individual session idle time locking. May be enabled by turning off the lock-server option (it is on by default). When this is off, each session locks when it has been idle for the lock-after-time setting. When on, the entire server locks when ALL sessions have been idle for their individual lock-after-time settings. This replaces one global-only option (lock-after-time) with another (lock-server), but the default behaviour is usually preferable so there don't seem to be many alternatives. Diff/idea largely from Thomas Adam, tweaked by me. --- cmd-set-option.c | 1 + server-msg.c | 6 +++-- server.c | 66 ++++++++++++++++++++++++++++++++++++++---------- session.c | 2 ++ tmux.1 | 25 +++++++++++++----- tmux.c | 3 +-- tmux.h | 2 +- 7 files changed, 81 insertions(+), 24 deletions(-) diff --git a/cmd-set-option.c b/cmd-set-option.c index 4984cb1a..5fbb9e85 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -63,6 +63,7 @@ const struct set_option_entry set_option_table[] = { { "history-limit", SET_OPTION_NUMBER, 0, INT_MAX, NULL }, { "lock-after-time", SET_OPTION_NUMBER, 0, INT_MAX, NULL }, { "lock-command", SET_OPTION_STRING, 0, 0, NULL }, + { "lock-server", SET_OPTION_FLAG, 0, 0, NULL }, { "message-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL }, { "message-bg", SET_OPTION_COLOUR, 0, 0, NULL }, { "message-fg", SET_OPTION_COLOUR, 0, 0, NULL }, diff --git a/server-msg.c b/server-msg.c index ec085610..248b94d4 100644 --- a/server-msg.c +++ b/server-msg.c @@ -105,7 +105,8 @@ server_msg_dispatch(struct client *c) tty_start_tty(&c->tty); server_redraw_client(c); recalculate_sizes(); - server_activity = time(NULL); + if (c->session != NULL) + c->session->activity = time(NULL); break; case MSG_ENVIRON: if (datalen != sizeof environdata) @@ -181,7 +182,8 @@ server_msg_command(struct client *c, struct msg_command_data *data) int argc; char **argv, *cause; - server_activity = time(NULL); + if (c->session != NULL) + c->session->activity = time(NULL); ctx.error = server_msg_command_error; ctx.print = server_msg_command_print; diff --git a/server.c b/server.c index a1a0211f..9c37b7c1 100644 --- a/server.c +++ b/server.c @@ -86,6 +86,8 @@ void server_check_window(struct window *); void server_check_redraw(struct client *); void server_set_title(struct client *); void server_check_timers(struct client *); +void server_lock_server(void); +void server_lock_sessions(void); void server_second_timers(void); int server_update_socket(void); @@ -249,8 +251,6 @@ server_start(char *path) key_bindings_init(); utf8_build(); - server_activity = time(NULL); - start_time = time(NULL); socket_path = path; @@ -842,10 +842,10 @@ server_handle_client(struct client *c) /* Process keys. */ keylist = options_get_data(&c->session->options, "prefix"); while (tty_keys_next(&c->tty, &key, mouse) == 0) { - server_activity = time(NULL); - if (c->session == NULL) return; + + c->session->activity = time(NULL); w = c->session->curw->window; wp = w->active; /* could die */ @@ -1254,6 +1254,51 @@ server_check_window(struct window *w) recalculate_sizes(); } +/* Lock the server if ALL sessions have hit the time limit. */ +void +server_lock_server(void) +{ + struct session *s; + u_int i; + int timeout; + time_t t; + + t = time(NULL); + for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { + if ((s = ARRAY_ITEM(&sessions, i)) == NULL) + continue; + + timeout = options_get_number(&s->options, "lock-after-time"); + if (timeout <= 0 || t <= s->activity + timeout) + return; /* not timed out */ + } + + server_lock(); + recalculate_sizes(); +} + +/* Lock any sessions which have timed out. */ +void +server_lock_sessions(void) +{ + struct session *s; + u_int i; + int timeout; + time_t t; + + t = time(NULL); + for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { + if ((s = ARRAY_ITEM(&sessions, i)) == NULL) + continue; + + timeout = options_get_number(&s->options, "lock-after-time"); + if (timeout > 0 && t > s->activity + timeout) { + server_lock_session(s); + recalculate_sizes(); + } + } +} + /* Call any once-per-second timers. */ void server_second_timers(void) @@ -1261,16 +1306,11 @@ server_second_timers(void) struct window *w; struct window_pane *wp; u_int i; - int xtimeout; - time_t t; - t = time(NULL); - - xtimeout = options_get_number(&global_s_options, "lock-after-time"); - if (xtimeout > 0 && t > server_activity + xtimeout) { - server_lock(); - recalculate_sizes(); - } + if (options_get_number(&global_s_options, "lock-server")) + server_lock_server(); + else + server_lock_sessions(); for (i = 0; i < ARRAY_LENGTH(&windows); i++) { w = ARRAY_ITEM(&windows, i); diff --git a/session.c b/session.c index fb49a365..62c5b746 100644 --- a/session.c +++ b/session.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "tmux.h" @@ -124,6 +125,7 @@ session_create(const char *name, const char *cmd, const char *cwd, s = xmalloc(sizeof *s); s->references = 0; s->flags = 0; + s->activity = time(NULL); if (gettimeofday(&s->tv, NULL) != 0) fatal("gettimeofday failed"); diff --git a/tmux.1 b/tmux.1 index 397ff83b..750e0134 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1253,20 +1253,33 @@ Set the maximum number of lines held in window history. This setting applies only to new windows - existing window histories are not resized and retain the limit at the point they were created. .It Ic lock-after-time Ar number -Lock the server (like the -.Ic lock-server +Lock the session (like the +.Ic lock-session command) after .Ar number -seconds of inactivity. -The default is off (set to 0). -This has no effect as a session option; it must be set as a global option using -.Fl g . +seconds of inactivity, or the entire server (all sessions) if the +.Ic lock-server +option is set. +The default is not to lock (set to 0). .It Ic lock-command Ar command Command to run when locking each client. The default is to run .Xr lock 1 with .Fl np . +.It Xo Ic lock-server +.Op Ic on | off +.Xc +If this option is +.Ic on +(the default), +instead of each session locking individually as each has been +idle for +.Ic lock-after-time +, 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 diff --git a/tmux.c b/tmux.c index eed7e9e1..cfbf8aac 100644 --- a/tmux.c +++ b/tmux.c @@ -46,8 +46,6 @@ struct options global_s_options; /* session options */ struct options global_w_options; /* window options */ struct environ global_environ; -time_t server_activity; - int debug_level; int be_quiet; time_t start_time; @@ -379,6 +377,7 @@ main(int argc, char **argv) options_set_number(so, "history-limit", 2000); options_set_number(so, "lock-after-time", 0); options_set_string(so, "lock-command", "lock -np"); + options_set_number(so, "lock-server", 1); options_set_number(so, "message-attr", 0); options_set_number(so, "message-bg", 3); options_set_number(so, "message-fg", 0); diff --git a/tmux.h b/tmux.h index 100793ed..9fd864f5 100644 --- a/tmux.h +++ b/tmux.h @@ -800,6 +800,7 @@ struct session_alert { struct session { char *name; struct timeval tv; + time_t activity; u_int sx; u_int sy; @@ -1117,7 +1118,6 @@ extern struct options global_s_options; extern struct options global_w_options; extern struct environ global_environ; extern char *cfg_file; -extern time_t server_activity; extern int debug_level; extern int be_quiet; extern time_t start_time; From 9dd72b958366c44b6d62680836983c58d2a0a42f Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 10 Oct 2009 10:02:48 +0000 Subject: [PATCH 0371/1180] Add "grouped sessions" which have independent name, options, current window and so on but where the linked windows are synchronized (ie creating, killing windows and so on are mirrored between the sessions). A grouped session may be created by passing -t to new-session. Had this around for a while, tested by a couple of people. --- cmd-break-pane.c | 1 + cmd-choose-session.c | 14 +++- cmd-choose-window.c | 2 +- cmd-kill-session.c | 2 +- cmd-link-window.c | 6 +- cmd-list-sessions.c | 21 +++-- cmd-move-window.c | 2 +- cmd-new-session.c | 36 +++++++-- cmd-new-window.c | 6 +- cmd-rename-window.c | 2 +- cmd-swap-window.c | 18 ++++- cmd-unlink-window.c | 18 ++++- server-fn.c | 73 ++++++++++++++--- server.c | 4 +- session.c | 189 +++++++++++++++++++++++++++++++++++++++++-- status.c | 2 +- tmux.1 | 21 +++++ tmux.h | 26 +++++- window.c | 8 +- 19 files changed, 392 insertions(+), 59 deletions(-) diff --git a/cmd-break-pane.c b/cmd-break-pane.c index b8d489de..58a93de2 100644 --- a/cmd-break-pane.c +++ b/cmd-break-pane.c @@ -78,6 +78,7 @@ cmd_break_pane_exec(struct cmd *self, struct cmd_ctx *ctx) session_select(s, wl->idx); server_redraw_session(s); + server_status_session_group(s); return (0); } diff --git a/cmd-choose-session.c b/cmd-choose-session.c index 7bc34853..b9c7c258 100644 --- a/cmd-choose-session.c +++ b/cmd-choose-session.c @@ -54,7 +54,9 @@ cmd_choose_session_exec(struct cmd *self, struct cmd_ctx *ctx) struct cmd_choose_session_data *cdata; struct winlink *wl; struct session *s; + struct session_group *sg; u_int i, idx, cur; + char tmp[64]; if (ctx->curclient == NULL) { ctx->error(ctx, "must be run interactively"); @@ -76,10 +78,18 @@ cmd_choose_session_exec(struct cmd *self, struct cmd_ctx *ctx) cur = idx; idx++; + sg = session_group_find(s); + if (sg == NULL) + *tmp = '\0'; + else { + idx = session_group_index(sg); + xsnprintf(tmp, sizeof tmp, " (group %u)", idx); + } + window_choose_add(wl->window->active, i, - "%s: %u windows [%ux%u]%s", s->name, + "%s: %u windows [%ux%u]%s%s", s->name, winlink_count(&s->windows), s->sx, s->sy, - s->flags & SESSION_UNATTACHED ? "" : " (attached)"); + tmp, s->flags & SESSION_UNATTACHED ? "" : " (attached)"); } cdata = xmalloc(sizeof *cdata); diff --git a/cmd-choose-window.c b/cmd-choose-window.c index 43a24585..9d6cd932 100644 --- a/cmd-choose-window.c +++ b/cmd-choose-window.c @@ -89,7 +89,7 @@ cmd_choose_window_exec(struct cmd *self, struct cmd_ctx *ctx) flag = '+'; else if (wm == s->curw) flag = '*'; - else if (wm == SLIST_FIRST(&s->lastw)) + else if (wm == TAILQ_FIRST(&s->lastw)) flag = '-'; title = w->active->screen->title; diff --git a/cmd-kill-session.c b/cmd-kill-session.c index 51a3edaf..402b869b 100644 --- a/cmd-kill-session.c +++ b/cmd-kill-session.c @@ -53,7 +53,7 @@ cmd_kill_session_exec(struct cmd *self, struct cmd_ctx *ctx) for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); - if (c->session == s) { + if (c != NULL && c->session == s) { c->session = NULL; server_write_client(c, MSG_EXIT, NULL, 0); } diff --git a/cmd-link-window.c b/cmd-link-window.c index 95514d40..a0b81dcc 100644 --- a/cmd-link-window.c +++ b/cmd-link-window.c @@ -43,19 +43,19 @@ int cmd_link_window_exec(struct cmd *self, struct cmd_ctx *ctx) { struct cmd_srcdst_data *data = self->data; - struct session *dst; + struct session *src, *dst; struct winlink *wl; char *cause; int idx, kflag, dflag; - if ((wl = cmd_find_window(ctx, data->src, NULL)) == NULL) + if ((wl = cmd_find_window(ctx, data->src, &src)) == NULL) return (-1); if ((idx = cmd_find_index(ctx, data->dst, &dst)) == -2) return (-1); kflag = data->chflags & CMD_CHFLAG('k'); dflag = data->chflags & CMD_CHFLAG('d'); - if (server_link_window(wl, dst, idx, kflag, !dflag, &cause) != 0) { + if (server_link_window(src, wl, dst, idx, kflag, !dflag, &cause) != 0) { ctx->error(ctx, "can't link window: %s", cause); xfree(cause); return (-1); diff --git a/cmd-list-sessions.c b/cmd-list-sessions.c index 95c26567..cfa1433b 100644 --- a/cmd-list-sessions.c +++ b/cmd-list-sessions.c @@ -42,23 +42,32 @@ const struct cmd_entry cmd_list_sessions_entry = { int cmd_list_sessions_exec(unused struct cmd *self, struct cmd_ctx *ctx) { - struct session *s; - char *tim; - u_int i; - time_t t; + struct session *s; + struct session_group *sg; + char *tim, tmp[64]; + u_int i, idx; + time_t t; for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { s = ARRAY_ITEM(&sessions, i); if (s == NULL) continue; + sg = session_group_find(s); + if (sg == NULL) + *tmp = '\0'; + else { + idx = session_group_index(sg); + xsnprintf(tmp, sizeof tmp, " (group %u)", idx); + } + t = s->tv.tv_sec; tim = ctime(&t); *strchr(tim, '\n') = '\0'; - ctx->print(ctx, "%s: %u windows (created %s) [%ux%u]%s", + ctx->print(ctx, "%s: %u windows (created %s) [%ux%u]%s%s", s->name, winlink_count(&s->windows), tim, s->sx, s->sy, - s->flags & SESSION_UNATTACHED ? "" : " (attached)"); + tmp, s->flags & SESSION_UNATTACHED ? "" : " (attached)"); } return (0); diff --git a/cmd-move-window.c b/cmd-move-window.c index 4c92556a..175e6576 100644 --- a/cmd-move-window.c +++ b/cmd-move-window.c @@ -55,7 +55,7 @@ cmd_move_window_exec(struct cmd *self, struct cmd_ctx *ctx) kflag = data->chflags & CMD_CHFLAG('k'); dflag = data->chflags & CMD_CHFLAG('d'); - if (server_link_window(wl, dst, idx, kflag, !dflag, &cause) != 0) { + if (server_link_window(src, wl, dst, idx, kflag, !dflag, &cause) != 0) { ctx->error(ctx, "can't move window: %s", cause); xfree(cause); return (-1); diff --git a/cmd-new-session.c b/cmd-new-session.c index 2aafdb1b..4889ab4b 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -34,6 +34,7 @@ void cmd_new_session_init(struct cmd *, int); size_t cmd_new_session_print(struct cmd *, char *, size_t); struct cmd_new_session_data { + char *target; char *newname; char *winname; char *cmd; @@ -42,7 +43,7 @@ struct cmd_new_session_data { const struct cmd_entry cmd_new_session_entry = { "new-session", "new", - "[-d] [-n window-name] [-s session-name] [command]", + "[-d] [-n window-name] [-s session-name] [-t target-session] [command]", CMD_STARTSERVER|CMD_CANTNEST|CMD_SENDENVIRON, 0, cmd_new_session_init, cmd_new_session_parse, @@ -58,6 +59,7 @@ cmd_new_session_init(struct cmd *self, unused int arg) self->data = data = xmalloc(sizeof *data); data->flag_detached = 0; + data->target = NULL; data->newname = NULL; data->winname = NULL; data->cmd = NULL; @@ -72,7 +74,7 @@ cmd_new_session_parse(struct cmd *self, int argc, char **argv, char **cause) self->entry->init(self, KEYC_NONE); data = self->data; - while ((opt = getopt(argc, argv, "ds:n:")) != -1) { + while ((opt = getopt(argc, argv, "ds:t:n:")) != -1) { switch (opt) { case 'd': data->flag_detached = 1; @@ -81,6 +83,10 @@ cmd_new_session_parse(struct cmd *self, int argc, char **argv, char **cause) if (data->newname == NULL) data->newname = xstrdup(optarg); break; + case 't': + if (data->target == NULL) + data->target = xstrdup(optarg); + break; case 'n': if (data->winname == NULL) data->winname = xstrdup(optarg); @@ -94,6 +100,9 @@ cmd_new_session_parse(struct cmd *self, int argc, char **argv, char **cause) if (argc != 0 && argc != 1) goto usage; + if (data->target != NULL && (argc == 1 || data->winname != NULL)) + goto usage; + if (argc == 1) data->cmd = xstrdup(argv[0]); @@ -110,7 +119,7 @@ int cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) { struct cmd_new_session_data *data = self->data; - struct session *s; + struct session *s, *groupwith; struct window *w; struct environ env; struct termios tio, *tiop; @@ -124,6 +133,11 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) return (-1); } + groupwith = NULL; + if (data->target != NULL && + (groupwith = cmd_find_session(ctx, data->target)) == NULL) + return (-1); + /* * There are three cases: * @@ -204,7 +218,9 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) sy = 1; /* Figure out the command for the new window. */ - if (data->cmd != NULL) + if (data->target != NULL) + cmd = NULL; + else if (data->cmd != NULL) cmd = data->cmd; else cmd = options_get_string(&global_s_options, "default-command"); @@ -227,7 +243,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) environ_free(&env); /* Set the initial window name if one given. */ - if (data->winname != NULL) { + if (cmd != NULL && data->winname != NULL) { w = s->curw->window; xfree(w->name); @@ -236,6 +252,16 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) options_set_number(&w->options, "automatic-rename", 0); } + /* + * If a target session is given, this is to be part of a session group, + * so add it to the group and synchronize. + */ + if (groupwith != NULL) { + session_group_add(groupwith, s); + session_group_synchronize_to(s); + session_select(s, RB_ROOT(&s->windows)->idx); + } + /* * Set the client to the new session. If a command client exists, it is * taking this session and needs to get MSG_READY and stay around. diff --git a/cmd-new-window.c b/cmd-new-window.c index bbffad14..44fe6b5a 100644 --- a/cmd-new-window.c +++ b/cmd-new-window.c @@ -164,9 +164,9 @@ cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx) } if (!data->flag_detached) { session_select(s, wl->idx); - server_redraw_session(s); - } else - server_status_session(s); + server_redraw_session_group(s); + } else + server_status_session_group(s); return (0); } diff --git a/cmd-rename-window.c b/cmd-rename-window.c index 1037b25a..6f4f9ab8 100644 --- a/cmd-rename-window.c +++ b/cmd-rename-window.c @@ -53,7 +53,7 @@ cmd_rename_window_exec(struct cmd *self, struct cmd_ctx *ctx) wl->window->name = xstrdup(data->arg); options_set_number(&wl->window->options, "automatic-rename", 0); - server_status_session(s); + server_status_window(wl->window); return (0); } diff --git a/cmd-swap-window.c b/cmd-swap-window.c index 875291f2..f164f234 100644 --- a/cmd-swap-window.c +++ b/cmd-swap-window.c @@ -44,6 +44,7 @@ cmd_swap_window_exec(struct cmd *self, struct cmd_ctx *ctx) { struct cmd_srcdst_data *data = self->data; struct session *src, *dst; + struct session_group *sg_src, *sg_dst; struct winlink *wl_src, *wl_dst; struct window *w; @@ -52,6 +53,14 @@ cmd_swap_window_exec(struct cmd *self, struct cmd_ctx *ctx) if ((wl_dst = cmd_find_window(ctx, data->dst, &dst)) == NULL) return (-1); + sg_src = session_group_find(src); + sg_dst = session_group_find(dst); + if (src != dst && + sg_src != NULL && sg_dst != NULL && sg_src == sg_dst) { + ctx->error(ctx, "can't move window, sessions are grouped"); + return (-1); + } + if (wl_dst->window == wl_src->window) return (0); @@ -64,9 +73,12 @@ cmd_swap_window_exec(struct cmd *self, struct cmd_ctx *ctx) if (src != dst) session_select(src, wl_src->idx); } - server_redraw_session(src); - if (src != dst) - server_redraw_session(dst); + session_group_synchronize_from(src); + server_redraw_session_group(src); + if (src != dst) { + session_group_synchronize_from(dst); + server_redraw_session_group(dst); + } recalculate_sizes(); return (0); diff --git a/cmd-unlink-window.c b/cmd-unlink-window.c index 38904689..e38b6e1e 100644 --- a/cmd-unlink-window.c +++ b/cmd-unlink-window.c @@ -42,16 +42,28 @@ cmd_unlink_window_exec(struct cmd *self, struct cmd_ctx *ctx) { struct cmd_target_data *data = self->data; struct winlink *wl; - struct session *s; + struct window *w; + struct session *s, *s2; + struct session_group *sg; + u_int references; if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL) return (-1); + w = wl->window; - if (!(data->chflags & CMD_CHFLAG('k')) && wl->window->references == 1) { + sg = session_group_find(s); + if (sg != NULL) { + references = 0; + TAILQ_FOREACH(s2, &sg->sessions, gentry) + references++; + } else + references = 1; + + if (!(data->chflags & CMD_CHFLAG('k')) && w->references == references) { ctx->error(ctx, "window is only linked to one session"); return (-1); } - + server_unlink_window(s, wl); recalculate_sizes(); diff --git a/server-fn.c b/server-fn.c index 4e3e12ec..beaae07a 100644 --- a/server-fn.c +++ b/server-fn.c @@ -104,6 +104,19 @@ server_redraw_session(struct session *s) } } +void +server_redraw_session_group(struct session *s) +{ + struct session_group *sg; + + if ((sg = session_group_find(s)) == NULL) + server_redraw_session(s); + else { + TAILQ_FOREACH(s, &sg->sessions, gentry) + server_redraw_session(s); + } +} + void server_status_session(struct session *s) { @@ -119,6 +132,19 @@ server_status_session(struct session *s) } } +void +server_status_session_group(struct session *s) +{ + struct session_group *sg; + + if ((sg = session_group_find(s)) == NULL) + server_status_session(s); + else { + TAILQ_FOREACH(s, &sg->sessions, gentry) + server_status_session(s); + } +} + void server_redraw_window(struct window *w) { @@ -220,18 +246,27 @@ server_kill_window(struct window *w) continue; if (session_detach(s, wl)) - server_destroy_session(s); - else + server_destroy_session_group(s); + else { server_redraw_session(s); + server_status_session_group(s); + } } } int -server_link_window( - struct winlink *srcwl, struct session *dst, int dstidx, - int killflag, int selectflag, char **cause) +server_link_window(struct session *src, struct winlink *srcwl, + struct session *dst, int dstidx, int killflag, int selectflag, char **cause) { - struct winlink *dstwl; + struct winlink *dstwl; + struct session_group *srcsg, *dstsg; + + srcsg = session_group_find(src); + dstsg = session_group_find(dst); + if (src != dst && srcsg != NULL && dstsg != NULL && srcsg == dstsg) { + xasprintf(cause, "sessions are grouped"); + return (-1); + } dstwl = NULL; if (dstidx != -1) @@ -260,12 +295,9 @@ server_link_window( if (dstwl == NULL) return (-1); - if (!selectflag) - server_status_session(dst); - else { + if (selectflag) session_select(dst, dstwl->idx); - server_redraw_session(dst); - } + server_redraw_session_group(dst); return (0); } @@ -274,9 +306,24 @@ void server_unlink_window(struct session *s, struct winlink *wl) { if (session_detach(s, wl)) - server_destroy_session(s); + server_destroy_session_group(s); else - server_redraw_session(s); + server_redraw_session_group(s); +} + +void +server_destroy_session_group(struct session *s) +{ + struct session_group *sg; + + if ((sg = session_group_find(s)) == NULL) + server_destroy_session(s); + else { + TAILQ_FOREACH(s, &sg->sessions, gentry) + server_destroy_session(s); + TAILQ_REMOVE(&session_groups, sg, entry); + xfree(sg); + } } void diff --git a/server.c b/server.c index 9c37b7c1..1de30ad6 100644 --- a/server.c +++ b/server.c @@ -247,6 +247,7 @@ server_start(char *path) ARRAY_INIT(&dead_clients); ARRAY_INIT(&sessions); ARRAY_INIT(&dead_sessions); + TAILQ_INIT(&session_groups); mode_key_init_trees(); key_bindings_init(); utf8_build(); @@ -1243,10 +1244,11 @@ server_check_window(struct window *w) if (wl->window != w) continue; if (session_detach(s, wl)) { - server_destroy_session(s); + server_destroy_session_group(s); break; } server_redraw_session(s); + server_status_session_group(s); goto restart; } } diff --git a/session.c b/session.c index 62c5b746..a477634e 100644 --- a/session.c +++ b/session.c @@ -30,6 +30,7 @@ /* Global session list. */ struct sessions sessions; struct sessions dead_sessions; +struct session_groups session_groups; struct winlink *session_next_activity(struct session *, struct winlink *); struct winlink *session_previous_activity(struct session *, struct winlink *); @@ -131,7 +132,7 @@ session_create(const char *name, const char *cmd, const char *cwd, fatal("gettimeofday failed"); s->curw = NULL; - SLIST_INIT(&s->lastw); + TAILQ_INIT(&s->lastw); RB_INIT(&s->windows); SLIST_INIT(&s->alerts); @@ -164,11 +165,14 @@ session_create(const char *name, const char *cmd, const char *cwd, s->name = xstrdup(name); else xasprintf(&s->name, "%u", i); - if (session_new(s, NULL, cmd, cwd, idx, cause) == NULL) { - session_destroy(s); - return (NULL); + + if (cmd != NULL) { + if (session_new(s, NULL, cmd, cwd, idx, cause) == NULL) { + session_destroy(s); + return (NULL); + } + session_select(s, RB_ROOT(&s->windows)->idx); } - session_select(s, RB_ROOT(&s->windows)->idx); log_debug("session %s created", s->name); @@ -192,13 +196,14 @@ session_destroy(struct session *s) if (s->tio != NULL) xfree(s->tio); + session_group_remove(s); session_alert_cancel(s, NULL); environ_free(&s->environ); options_free(&s->options); paste_free_stack(&s->buffers); - while (!SLIST_EMPTY(&s->lastw)) - winlink_stack_remove(&s->lastw, SLIST_FIRST(&s->lastw)); + while (!TAILQ_EMPTY(&s->lastw)) + winlink_stack_remove(&s->lastw, TAILQ_FIRST(&s->lastw)); while (!RB_EMPTY(&s->windows)) winlink_remove(&s->windows, RB_ROOT(&s->windows)); @@ -268,6 +273,7 @@ session_attach(struct session *s, struct window *w, int idx, char **cause) if ((wl = winlink_add(&s->windows, w, idx)) == NULL) xasprintf(cause, "index in use: %d", idx); + session_group_synchronize_from(s); return (wl); } @@ -282,6 +288,7 @@ session_detach(struct session *s, struct winlink *wl) session_alert_cancel(s, wl); winlink_stack_remove(&s->lastw, wl); winlink_remove(&s->windows, wl); + session_group_synchronize_from(s); if (RB_EMPTY(&s->windows)) { session_destroy(s); return (1); @@ -408,7 +415,7 @@ session_last(struct session *s) { struct winlink *wl; - wl = SLIST_FIRST(&s->lastw); + wl = TAILQ_FIRST(&s->lastw); if (wl == NULL) return (-1); if (wl == s->curw) @@ -420,3 +427,169 @@ session_last(struct session *s) session_alert_cancel(s, wl); return (0); } + +/* Find the session group containing a session. */ +struct session_group * +session_group_find(struct session *target) +{ + struct session_group *sg; + struct session *s; + + TAILQ_FOREACH(sg, &session_groups, entry) { + TAILQ_FOREACH(s, &sg->sessions, gentry) { + if (s == target) + return (sg); + } + } + return (NULL); +} + +/* Find session group index. */ +u_int +session_group_index(struct session_group *sg) +{ + struct session_group *sg2; + u_int i; + + i = 0; + TAILQ_FOREACH(sg2, &session_groups, entry) { + if (sg == sg2) + return (i); + i++; + } + + fatalx("session group not found"); +} + +/* + * Add a session to the session group containing target, creating it if + * necessary. + */ +void +session_group_add(struct session *target, struct session *s) +{ + struct session_group *sg; + + if ((sg = session_group_find(target)) == NULL) { + sg = xmalloc(sizeof *sg); + TAILQ_INSERT_TAIL(&session_groups, sg, entry); + TAILQ_INIT(&sg->sessions); + TAILQ_INSERT_TAIL(&sg->sessions, target, gentry); + } + TAILQ_INSERT_TAIL(&sg->sessions, s, gentry); +} + +/* Remove a session from its group and destroy the group if empty. */ +void +session_group_remove(struct session *s) +{ + struct session_group *sg; + + if ((sg = session_group_find(s)) == NULL) + return; + TAILQ_REMOVE(&sg->sessions, s, gentry); + if (TAILQ_NEXT(TAILQ_FIRST(&sg->sessions), gentry) == NULL) + TAILQ_REMOVE(&sg->sessions, TAILQ_FIRST(&sg->sessions), gentry); + if (TAILQ_EMPTY(&sg->sessions)) { + TAILQ_REMOVE(&session_groups, sg, entry); + xfree(sg); + } +} + +/* Synchronize a session to its session group. */ +void +session_group_synchronize_to(struct session *s) +{ + struct session_group *sg; + struct session *target; + + if ((sg = session_group_find(s)) == NULL) + return; + + target = NULL; + TAILQ_FOREACH(target, &sg->sessions, gentry) { + if (target != s) + break; + } + session_group_synchronize1(target, s); +} + +/* Synchronize a session group to a session. */ +void +session_group_synchronize_from(struct session *target) +{ + struct session_group *sg; + struct session *s; + + if ((sg = session_group_find(target)) == NULL) + return; + + TAILQ_FOREACH(s, &sg->sessions, gentry) { + if (s != target) + session_group_synchronize1(target, s); + } +} + +/* + * Synchronize a session with a target session. This means destroying all + * winlinks then recreating them, then updating the current window, last window + * stack and alerts. + */ +void +session_group_synchronize1(struct session *target, struct session *s) +{ + struct winlinks old_windows, *ww; + struct winlink_stack old_lastw; + struct winlink *wl, *wl2; + struct session_alert *sa; + + /* Don't do anything if the session is empty (it'll be destroyed). */ + ww = &target->windows; + if (RB_EMPTY(ww)) + return; + + /* If the current window has vanished, move to the next now. */ + if (s->curw != NULL) { + while (winlink_find_by_index(ww, s->curw->idx) == NULL) + session_next(s, 0); + } + + /* Save the old pointer and reset it. */ + memcpy(&old_windows, &s->windows, sizeof old_windows); + RB_INIT(&s->windows); + + /* Link all the windows from the target. */ + RB_FOREACH(wl, winlinks, ww) + winlink_add(&s->windows, wl->window, wl->idx); + + /* Fix up the current window. */ + if (s->curw != NULL) + s->curw = winlink_find_by_index(&s->windows, s->curw->idx); + else + s->curw = winlink_find_by_index(&s->windows, target->curw->idx); + + /* Fix up the last window stack. */ + memcpy(&old_lastw, &s->lastw, sizeof old_lastw); + TAILQ_INIT(&s->lastw); + TAILQ_FOREACH(wl, &old_lastw, sentry) { + wl2 = winlink_find_by_index(&s->windows, wl->idx); + if (wl2 != NULL) + TAILQ_INSERT_TAIL(&s->lastw, wl2, sentry); + } + + /* And update the alerts list. */ + SLIST_FOREACH(sa, &s->alerts, entry) { + wl = winlink_find_by_index(&s->windows, sa->wl->idx); + if (wl == NULL) + session_alert_cancel(s, sa->wl); + else + sa->wl = wl; + } + + /* Then free the old winlinks list. */ + while (!RB_EMPTY(&old_windows)) { + wl = RB_ROOT(&old_windows); + RB_REMOVE(winlinks, &old_windows, wl); + xfree(wl); + } +} diff --git a/status.c b/status.c index 3ffee331..dbf82c14 100644 --- a/status.c +++ b/status.c @@ -516,7 +516,7 @@ status_print(struct session *s, struct winlink *wl, struct grid_cell *gc) gc->attr = attr; flag = ' '; - if (wl == SLIST_FIRST(&s->lastw)) + if (wl == TAILQ_FIRST(&s->lastw)) flag = '-'; if (wl == s->curw) { fg = options_get_number(oo, "window-status-current-fg"); diff --git a/tmux.1 b/tmux.1 index 750e0134..9c9b5caa 100644 --- a/tmux.1 +++ b/tmux.1 @@ -409,6 +409,7 @@ Lock all clients attached to .Op Fl d .Op Fl n Ar window-name .Op Fl s Ar session-name +.Op Fl t Ar target-session .Op Ar command .Xc .D1 (alias: Ic new ) @@ -425,6 +426,26 @@ are the name of and command to execute in the initial window. If run from a terminal, any .Xr termios 4 special characters are saved and used for new windows in the new session. +.Pp +If +.Fl t +is given, the new session is +.Em grouped +with +.Ar target-session . +This means they share the same set of windows - all windows from +.Ar target-session +are linked to the new session and any subsequent new windows or windows being +closed are applied to both sessions. +The current and previous window and any session options remain independent and +either session may be killed without affecting the other. +Giving +.Fl n +or +.Ar command +are invalid if +.Fl t +is used. .It Ic refresh-client Op Fl t Ar target-client .D1 (alias: Ic refresh ) Refresh the current client if bound to a key, or a single client if one is given diff --git a/tmux.h b/tmux.h index 9fd864f5..f4a25b5d 100644 --- a/tmux.h +++ b/tmux.h @@ -739,10 +739,10 @@ struct winlink { struct window *window; RB_ENTRY(winlink) entry; - SLIST_ENTRY(winlink) sentry; + TAILQ_ENTRY(winlink) sentry; }; RB_HEAD(winlinks, winlink); -SLIST_HEAD(winlink_stack, winlink); +TAILQ_HEAD(winlink_stack, winlink); /* Layout direction. */ enum layout_type { @@ -797,6 +797,13 @@ struct session_alert { SLIST_ENTRY(session_alert) entry; }; +struct session_group { + TAILQ_HEAD(, session) sessions; + + TAILQ_ENTRY(session_group) entry; +}; +TAILQ_HEAD(session_groups, session_group); + struct session { char *name; struct timeval tv; @@ -824,6 +831,8 @@ struct session { struct environ environ; int references; + + TAILQ_ENTRY(session) gentry; }; ARRAY_DECL(sessions, struct session *); @@ -1456,7 +1465,9 @@ void server_write_session( void server_redraw_client(struct client *); void server_status_client(struct client *); void server_redraw_session(struct session *); +void server_redraw_session_group(struct session *); void server_status_session(struct session *); +void server_status_session_group(struct session *); void server_redraw_window(struct window *); void server_status_window(struct window *); void server_lock(void); @@ -1464,9 +1475,10 @@ void server_lock_session(struct session *); void server_lock_client(struct client *); int server_unlock(const char *); void server_kill_window(struct window *); -int server_link_window( +int server_link_window(struct session *, struct winlink *, struct session *, int, int, int, char **); void server_unlink_window(struct session *, struct winlink *); +void server_destroy_session_group(struct session *); void server_destroy_session(struct session *); void server_set_identify(struct client *); void server_clear_identify(struct client *); @@ -1719,6 +1731,7 @@ char *default_window_name(struct window *); /* session.c */ extern struct sessions sessions; extern struct sessions dead_sessions; +extern struct session_groups session_groups; void session_alert_add(struct session *, struct window *, int); void session_alert_cancel(struct session *, struct winlink *); int session_alert_has(struct session *, struct winlink *, int); @@ -1739,6 +1752,13 @@ int session_next(struct session *, int); int session_previous(struct session *, int); int session_select(struct session *, int); int session_last(struct session *); +struct session_group *session_group_find(struct session *); +u_int session_group_index(struct session_group *); +void session_group_add(struct session *, struct session *); +void session_group_remove(struct session *); +void session_group_synchronize_to(struct session *); +void session_group_synchronize_from(struct session *); +void session_group_synchronize1(struct session *, struct session *); /* utf8.c */ void utf8_build(void); diff --git a/window.c b/window.c index 9d2f3975..24d74fd2 100644 --- a/window.c +++ b/window.c @@ -174,7 +174,7 @@ winlink_stack_push(struct winlink_stack *stack, struct winlink *wl) return; winlink_stack_remove(stack, wl); - SLIST_INSERT_HEAD(stack, wl, sentry); + TAILQ_INSERT_HEAD(stack, wl, sentry); } void @@ -184,10 +184,10 @@ winlink_stack_remove(struct winlink_stack *stack, struct winlink *wl) if (wl == NULL) return; - - SLIST_FOREACH(wl2, stack, sentry) { + + TAILQ_FOREACH(wl2, stack, sentry) { if (wl2 == wl) { - SLIST_REMOVE(stack, wl, winlink, sentry); + TAILQ_REMOVE(stack, wl, sentry); return; } } From 3a20a05a49bdf7cfd7d2131c6f31a2ebf76ad4e5 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 10 Oct 2009 10:36:46 +0000 Subject: [PATCH 0372/1180] There is no point setting the scroll region up for line feeds unless scrolling is actually going to happen, so don't. --- tty.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tty.c b/tty.c index c61fd6b0..7b0454f7 100644 --- a/tty.c +++ b/tty.c @@ -693,11 +693,10 @@ tty_cmd_linefeed(struct tty *tty, const struct tty_ctx *ctx) return; } - tty_reset(tty); - - tty_region(tty, ctx->orupper, ctx->orlower, wp->yoff); if (ctx->ocy == ctx->orlower) { + tty_reset(tty); + tty_region(tty, ctx->orupper, ctx->orlower, wp->yoff); tty_cursor(tty, ctx->ocx, ctx->ocy, wp->xoff, wp->yoff); tty_putc(tty, '\n'); } From 4658c063d59bab42ccca8c2e58a50800b00b956f Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 10 Oct 2009 14:51:16 +0000 Subject: [PATCH 0373/1180] New option, mouse-select-pane. If on, the mouse may be used to select the current pane. Suggested by sthen@ and also by someone else ages ago who I have forgotten. --- cmd-set-option.c | 1 + server.c | 15 +++++++++++++-- tmux.1 | 10 +++++++++- tmux.c | 1 + tmux.h | 1 + window.c | 17 +++++++++++++++++ 6 files changed, 42 insertions(+), 3 deletions(-) diff --git a/cmd-set-option.c b/cmd-set-option.c index 5fbb9e85..2a3b2877 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -67,6 +67,7 @@ const struct set_option_entry set_option_table[] = { { "message-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL }, { "message-bg", SET_OPTION_COLOUR, 0, 0, NULL }, { "message-fg", SET_OPTION_COLOUR, 0, 0, NULL }, + { "mouse-select-pane", SET_OPTION_FLAG, 0, 0, NULL }, { "prefix", SET_OPTION_KEYS, 0, 0, NULL }, { "repeat-time", SET_OPTION_NUMBER, 0, SHRT_MAX, NULL }, { "set-remain-on-exit", SET_OPTION_FLAG, 0, 0, NULL }, diff --git a/server.c b/server.c index 1de30ad6..096ada83 100644 --- a/server.c +++ b/server.c @@ -825,6 +825,7 @@ server_handle_client(struct client *c) struct window *w; struct window_pane *wp; struct screen *s; + struct options *oo; struct timeval tv; struct key_binding *bd; struct keylist *keylist; @@ -849,6 +850,7 @@ server_handle_client(struct client *c) c->session->activity = time(NULL); w = c->session->curw->window; wp = w->active; /* could die */ + oo = &c->session->options; /* Special case: number keys jump to pane in identify mode. */ if (c->flags & CLIENT_IDENTIFY && key >= '0' && key <= '9') { @@ -868,6 +870,10 @@ server_handle_client(struct client *c) /* Check for mouse keys. */ if (key == KEYC_MOUSE) { + if (options_get_number(oo, "mouse-select-pane")) { + window_set_active_at(w, mouse[1], mouse[2]); + wp = w->active; + } window_pane_mouse(wp, c, mouse[0], mouse[1], mouse[2]); continue; } @@ -935,7 +941,9 @@ server_handle_client(struct client *c) } if (c->session == NULL) return; - wp = c->session->curw->window->active; /* could die - do each loop */ + w = c->session->curw->window; + wp = w->active; + oo = &c->session->options; s = wp->screen; /* @@ -948,7 +956,7 @@ server_handle_client(struct client *c) * tty_region/tty_reset/tty_update_mode already take care of not * resetting things that are already in their default state. */ - status = options_get_number(&c->session->options, "status"); + status = options_get_number(oo, "status"); tty_region(&c->tty, 0, c->tty.sy - 1, 0); if (!window_pane_visible(wp) || wp->yoff + s->cy >= c->tty.sy - status) tty_cursor(&c->tty, 0, 0, 0, 0); @@ -956,6 +964,9 @@ server_handle_client(struct client *c) tty_cursor(&c->tty, s->cx, s->cy, wp->xoff, wp->yoff); mode = s->mode; + if (TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry) != NULL && + options_get_number(oo, "mouse-select-pane")) + mode |= MODE_MOUSE; tty_update_mode(&c->tty, mode); tty_reset(&c->tty); } diff --git a/tmux.1 b/tmux.1 index 9c9b5caa..c5ccc63d 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1292,7 +1292,7 @@ with .Op Ic on | off .Xc If this option is -.Ic on +.Ic on (the default), instead of each session locking individually as each has been idle for @@ -1336,6 +1336,14 @@ from the 256-colour palette, or .Ic default . .It Ic message-fg Ar colour Set status line message foreground colour. +.It Xo Ic mouse-select-pane +.Op Ic on | off +.Xc +If on, +.Nm +captures the mouse and when a window is split into multiple panes the mouse may +be used to select the current pane. +The mouse click is also passed through to the application as normal. .It Ic prefix Ar keys Set the keys accepted as a prefix key. .Ar keys diff --git a/tmux.c b/tmux.c index cfbf8aac..6e747bbe 100644 --- a/tmux.c +++ b/tmux.c @@ -381,6 +381,7 @@ main(int argc, char **argv) options_set_number(so, "message-attr", 0); options_set_number(so, "message-bg", 3); options_set_number(so, "message-fg", 0); + options_set_number(so, "mouse-select-pane", 0); options_set_number(so, "repeat-time", 500); options_set_number(so, "set-remain-on-exit", 0); options_set_number(so, "set-titles", 0); diff --git a/tmux.h b/tmux.h index f4a25b5d..e9c7d7f9 100644 --- a/tmux.h +++ b/tmux.h @@ -1648,6 +1648,7 @@ struct window *window_create(const char *, const char *, const char *, const char *, struct environ *, struct termios *, u_int, u_int, u_int, char **); void window_destroy(struct window *); +void window_set_active_at(struct window *, u_int, u_int); void window_set_active_pane(struct window *, struct window_pane *); struct window_pane *window_add_pane(struct window *, u_int); void window_resize(struct window *, u_int, u_int); diff --git a/window.c b/window.c index 24d74fd2..71e09b52 100644 --- a/window.c +++ b/window.c @@ -304,6 +304,23 @@ window_set_active_pane(struct window *w, struct window_pane *wp) } } +void +window_set_active_at(struct window *w, u_int x, u_int y) +{ + struct window_pane *wp; + + TAILQ_FOREACH(wp, &w->panes, entry) { + if (!window_pane_visible(wp)) + continue; + if (x < wp->xoff || x >= wp->xoff + wp->sx) + continue; + if (y < wp->yoff || y >= wp->yoff + wp->sy) + continue; + window_set_active_pane(w, wp); + break; + } +} + struct window_pane * window_add_pane(struct window *w, u_int hlimit) { From 6bca92db4ddd2d3d25671aa83e74dd11aca652a8 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 10 Oct 2009 15:03:01 +0000 Subject: [PATCH 0374/1180] Rather than running status-left, status-right and window title #() with popen immediately every redraw, queue them up and run them in the background, starting each once every status-interval. The actual status line uses the output from the last run. This brings several advantages: - tmux itself may be called from inside #() without causing the server to hang; - likewise, sleep or similar doesn't cause the server to block; - commands aren't run excessively often when redrawing; - commands shared by status-left and status-right, or used multiple times, will only be run once. run-shell and if-shell still use system()/popen() but will be changed over to use this too later. --- Makefile | 2 +- buffer-poll.c | 9 +- cmd-display-message.c | 2 +- cmd-set-option.c | 5 +- job.c | 187 ++++++++++++++++++++++++++++++++++++++++++ server.c | 78 +++++++++++++++++- status.c | 85 +++++++++++-------- tmux.1 | 5 ++ tmux.h | 37 ++++++++- 9 files changed, 364 insertions(+), 46 deletions(-) create mode 100644 job.c diff --git a/Makefile b/Makefile index 591badde..a3872ee1 100644 --- a/Makefile +++ b/Makefile @@ -30,7 +30,7 @@ SRCS= attributes.c buffer-poll.c buffer.c cfg.c client-fn.c \ cmd-up-pane.c cmd-display-message.c cmd-display-panes.c cmd.c \ colour.c environ.c grid-view.c grid.c input-keys.c \ imsg.c imsg-buffer.c input.c key-bindings.c key-string.c \ - layout-set.c layout.c log.c \ + layout-set.c layout.c log.c job.c \ mode-key.c names.c options-cmd.c options.c paste.c procname.c \ resize.c screen-redraw.c screen-write.c screen.c server-fn.c \ server-msg.c server.c session.c status.c tmux.c tty-keys.c tty-term.c \ diff --git a/buffer-poll.c b/buffer-poll.c index cb645194..58c2d555 100644 --- a/buffer-poll.c +++ b/buffer-poll.c @@ -29,9 +29,9 @@ buffer_poll(struct pollfd *pfd, struct buffer *in, struct buffer *out) { ssize_t n; - if (pfd->revents & (POLLERR|POLLNVAL|POLLHUP)) + if (pfd->revents & (POLLERR|POLLNVAL)) return (-1); - if (pfd->revents & POLLIN) { + if (in != NULL && pfd->revents & POLLIN) { buffer_ensure(in, BUFSIZ); n = read(pfd->fd, BUFFER_IN(in), BUFFER_FREE(in)); if (n == 0) @@ -41,8 +41,9 @@ buffer_poll(struct pollfd *pfd, struct buffer *in, struct buffer *out) return (-1); } else buffer_add(in, n); - } - if (BUFFER_USED(out) > 0 && pfd->revents & POLLOUT) { + } else if (pfd->revents & POLLHUP) + return (-1); + if (out != NULL && BUFFER_USED(out) > 0 && pfd->revents & POLLOUT) { n = write(pfd->fd, BUFFER_OUT(out), BUFFER_USED(out)); if (n == -1) { if (errno != EINTR && errno != EAGAIN) diff --git a/cmd-display-message.c b/cmd-display-message.c index 20758daa..71421ea2 100644 --- a/cmd-display-message.c +++ b/cmd-display-message.c @@ -55,7 +55,7 @@ cmd_display_message_exec(struct cmd *self, struct cmd_ctx *ctx) else template = data->arg; - msg = status_replace(c->session, template, time(NULL)); + msg = status_replace(c, template, time(NULL)); status_message_set(c, "%s", msg); xfree(msg); diff --git a/cmd-set-option.c b/cmd-set-option.c index 2a3b2877..a495a15d 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -186,8 +186,11 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) recalculate_sizes(); for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); - if (c != NULL && c->session != NULL) + if (c != NULL && c->session != NULL) { + job_tree_free(&c->status_jobs); + job_tree_init(&c->status_jobs); server_redraw_client(c); + } } return (0); diff --git a/job.c b/job.c new file mode 100644 index 00000000..91646eda --- /dev/null +++ b/job.c @@ -0,0 +1,187 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2009 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 "tmux.h" + +/* + * Job scheduling. Run queued commands in the background and record their + * output. + */ + +RB_GENERATE(jobs, job, entry, job_cmp); + +int +job_cmp(struct job *job1, struct job *job2) +{ + return (strcmp(job1->cmd, job2->cmd)); +} + +/* Initialise job tree. */ +void +job_tree_init(struct jobs *jobs) +{ + RB_INIT(jobs); +} + +/* Count the number of jobs in a tree. */ +u_int +job_tree_size(struct jobs *jobs) +{ + struct job *job; + u_int n; + + n = 0; + RB_FOREACH(job, jobs, jobs) + n++; + return (n); +} + +/* Destroy a job tree. */ +void +job_tree_free(struct jobs *jobs) +{ + struct job *job; + + while (!RB_EMPTY(jobs)) { + job = RB_ROOT(jobs); + RB_REMOVE(jobs, jobs, job); + job_free(job); + } +} + +/* Find a job and return it. */ +struct job * +job_get(struct jobs *jobs, const char *cmd) +{ + struct job job; + + job.cmd = (char *) cmd; + return (RB_FIND(jobs, jobs, &job)); +} + +/* Add a job. */ +struct job * +job_add(struct jobs *jobs, struct client *c, const char *cmd, + void (*callbackfn)(struct job *), void (*freefn)(void *), void *data) +{ + struct job *job; + + job = xmalloc(sizeof *job); + job->cmd = xstrdup(cmd); + + job->client = c; + + job->fd = -1; + job->out = buffer_create(BUFSIZ); + + job->callbackfn = callbackfn; + job->freefn = freefn; + job->data = data; + + RB_INSERT(jobs, jobs, job); + + return (job); +} + +/* Kill and free an individual job. */ +void +job_free(struct job *job) +{ + job_kill(job); + + xfree(job->cmd); + + if (job->fd != -1) + close(job->fd); + if (job->out != NULL) + buffer_destroy(job->out); + + xfree(job); +} + +/* Start a job running, if it isn't already. */ +int +job_run(struct job *job) +{ + int nullfd, out[2], mode; + + if (job->fd != -1) + return (0); + + if (pipe(out) != 0) + return (-1); + + switch (job->pid = fork()) { + case -1: + return (-1); + case 0: /* child */ + sigreset(); + /* XXX environ? */ + + nullfd = open(_PATH_DEVNULL, O_RDONLY, 0); + if (nullfd < 0) + fatal("open failed"); + if (dup2(nullfd, STDIN_FILENO) == -1) + fatal("dup2 failed"); + if (dup2(nullfd, STDERR_FILENO) == -1) + fatal("dup2 failed"); + if (nullfd != STDIN_FILENO && nullfd != STDERR_FILENO) + close(nullfd); + + close(out[1]); + if (dup2(out[0], STDOUT_FILENO) == -1) + fatal("dup2 failed"); + if (out[0] != STDOUT_FILENO) + close(out[0]); + + execl(_PATH_BSHELL, "sh", "-c", job->cmd, (char *) NULL); + fatal("execl failed"); + default: /* parent */ + close(out[0]); + + job->fd = out[1]; + if ((mode = fcntl(job->fd, F_GETFL)) == -1) + fatal("fcntl failed"); + if (fcntl(job->fd, F_SETFL, mode|O_NONBLOCK) == -1) + fatal("fcntl failed"); + if (fcntl(job->fd, F_SETFD, FD_CLOEXEC) == -1) + fatal("fcntl failed"); + + if (BUFFER_USED(job->out) != 0) + buffer_remove(job->out, BUFFER_USED(job->out)); + + return (0); + } +} + +/* Kill a job. */ +void +job_kill(struct job *job) +{ + if (job->pid == -1) + return; + kill(job->pid, SIGTERM); + job->pid = -1; +} diff --git a/server.c b/server.c index 096ada83..a38f2974 100644 --- a/server.c +++ b/server.c @@ -72,6 +72,10 @@ void server_fill_windows(void); void server_handle_windows(void); void server_fill_clients(void); void server_handle_clients(void); +void server_fill_jobs(void); +void server_fill_jobs1(struct jobs *); +void server_handle_jobs(void); +void server_handle_jobs1(struct jobs *); void server_accept_client(int); void server_handle_client(struct client *); void server_handle_window(struct window *, struct window_pane *); @@ -190,7 +194,9 @@ server_create_client(int fd) c->session = NULL; c->tty.sx = 80; c->tty.sy = 24; + screen_init(&c->status, c->tty.sx, 1, 0); + job_tree_init(&c->status_jobs); c->message_string = NULL; @@ -370,6 +376,7 @@ server_main(int srv_fd) server_poll_add(srv_fd, POLLIN); /* Fill window and client sockets. */ + server_fill_jobs(); server_fill_windows(); server_fill_clients(); @@ -412,6 +419,7 @@ server_main(int srv_fd) * windows, so windows must come first to avoid messing up by * increasing the array size. */ + server_handle_jobs(); server_handle_windows(); server_handle_clients(); @@ -648,7 +656,7 @@ server_set_title(struct client *c) template = options_get_string(&s->options, "set-titles-string"); - title = status_replace(c->session, template, time(NULL)); + title = status_replace(c, template, time(NULL)); if (c->title == NULL || strcmp(title, c->title) != 0) { if (c->title != NULL) xfree(c->title); @@ -663,6 +671,7 @@ void server_check_timers(struct client *c) { struct session *s; + struct job *job; struct timeval tv; u_int interval; @@ -694,8 +703,12 @@ server_check_timers(struct client *c) if (interval == 0) return; if (tv.tv_sec < c->status_timer.tv_sec || - ((u_int) tv.tv_sec) - c->status_timer.tv_sec >= interval) + ((u_int) tv.tv_sec) - c->status_timer.tv_sec >= interval) { + /* Run the jobs for this client and schedule for redraw. */ + RB_FOREACH(job, jobs, &c->status_jobs) + job_run(job); c->flags |= CLIENT_STATUS; + } } /* Fill client pollfds. */ @@ -747,6 +760,66 @@ server_fill_clients(void) } } +/* Fill in job fds. */ +void +server_fill_jobs(void) +{ + struct client *c; + u_int i; + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c != NULL) + server_fill_jobs1(&c->status_jobs); + } +} + +void +server_fill_jobs1(struct jobs *jobs) +{ + struct job *job; + + RB_FOREACH(job, jobs, jobs) { + if (job->fd == -1) + continue; + server_poll_add(job->fd, POLLIN); + } +} + +/* Handle job fds. */ +void +server_handle_jobs(void) +{ + struct client *c; + u_int i; + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c != NULL) + server_handle_jobs1(&c->status_jobs); + } +} + +void +server_handle_jobs1(struct jobs *jobs) +{ + struct job *job; + struct pollfd *pfd; + + RB_FOREACH(job, jobs, jobs) { + if (job->fd == -1) + continue; + if ((pfd = server_poll_lookup(job->fd)) == NULL) + continue; + if (buffer_poll(pfd, job->out, NULL) != 0) { + close(job->fd); + job->fd = -1; + if (job->callbackfn != NULL) + job->callbackfn(job); + } + } +} + /* Handle client pollfds. */ void server_handle_clients(void) @@ -991,6 +1064,7 @@ server_lost_client(struct client *c) tty_free(&c->tty); screen_free(&c->status); + job_tree_free(&c->status_jobs); if (c->title != NULL) xfree(c->title); diff --git a/status.c b/status.c index dbf82c14..9a3f4867 100644 --- a/status.c +++ b/status.c @@ -29,7 +29,8 @@ #include "tmux.h" -char *status_replace_popen(char **); +char *status_job(struct client *, char **); +void status_job_callback(struct job *); size_t status_width(struct winlink *); char *status_print(struct session *, struct winlink *, struct grid_cell *); @@ -104,14 +105,14 @@ status_redraw(struct client *c) utf8flag = options_get_number(&s->options, "status-utf8"); /* Work out the left and right strings. */ - left = status_replace(s, options_get_string( + left = status_replace(c, options_get_string( &s->options, "status-left"), c->status_timer.tv_sec); llen = options_get_number(&s->options, "status-left-length"); llen2 = screen_write_cstrlen(utf8flag, "%s", left); if (llen2 < llen) llen = llen2; - right = status_replace(s, options_get_string( + right = status_replace(c, options_get_string( &s->options, "status-right"), c->status_timer.tv_sec); rlen = options_get_number(&s->options, "status-right-length"); rlen2 = screen_write_cstrlen(utf8flag, "%s", right); @@ -317,15 +318,17 @@ out: } char * -status_replace(struct session *s, const char *fmt, time_t t) +status_replace(struct client *c, const char *fmt, time_t t) { + struct session *s = c->session; struct winlink *wl = s->curw; static char out[BUFSIZ]; char in[BUFSIZ], tmp[256], ch, *iptr, *optr, *ptr, *endptr; - char *savedptr; + char *savedptr; /* freed at end of each loop */ size_t len; long n; - + + strftime(in, sizeof in, fmt, localtime(&t)); in[(sizeof in) - 1] = '\0'; @@ -352,7 +355,7 @@ status_replace(struct session *s, const char *fmt, time_t t) switch (*iptr++) { case '(': if (ptr == NULL) { - ptr = status_replace_popen(&iptr); + ptr = status_job(c, &iptr); if (ptr == NULL) break; savedptr = ptr; @@ -374,8 +377,8 @@ status_replace(struct session *s, const char *fmt, time_t t) case 'P': if (ptr == NULL) { xsnprintf(tmp, sizeof tmp, "%u", - window_pane_index(wl->window, - wl->window->active)); + window_pane_index(wl->window, + wl->window->active)); ptr = tmp; } /* FALLTHROUGH */ @@ -434,12 +437,12 @@ status_replace(struct session *s, const char *fmt, time_t t) } char * -status_replace_popen(char **iptr) +status_job(struct client *c, char **iptr) { - FILE *f; - char *buf, *cmd, *ptr; - int lastesc; - size_t len; + struct job *job; + char *buf, *cmd; + int lastesc; + size_t len; if (**iptr == '\0') return (NULL); @@ -464,32 +467,44 @@ status_replace_popen(char **iptr) lastesc = 0; cmd[len++] = **iptr; } - if (**iptr == '\0') /* no terminating ) */ - goto out; + if (**iptr == '\0') /* no terminating ) */ { + xfree(cmd); + return (NULL); + } (*iptr)++; /* skip final ) */ cmd[len] = '\0'; - if ((f = popen(cmd, "r")) == NULL) - goto out; - - if ((buf = fgetln(f, &len)) == NULL) { - pclose(f); - goto out; + job = job_get(&c->status_jobs, cmd); + if (job == NULL) { + job = job_add( + &c->status_jobs, c, cmd, status_job_callback, xfree, NULL); + job_run(job); } - if (buf[len - 1] == '\n') { - buf[len - 1] = '\0'; - buf = xstrdup(buf); - } else { - ptr = xmalloc(len + 1); - memcpy(ptr, buf, len); - ptr[len] = '\0'; - buf = ptr; - } - pclose(f); + if (job->data == NULL) + return (xstrdup("")); + return (xstrdup(job->data)); +} -out: - xfree(cmd); - return (buf); +void +status_job_callback(struct job *job) +{ + char *buf; + size_t len; + + len = BUFFER_USED(job->out); + buf = xmalloc(len + 1); + if (len != 0) + buffer_read(job->out, buf, len); + buf[len] = '\0'; + buf[strcspn(buf, "\n")] = '\0'; + + if (job->data != NULL) + xfree(job->data); + else + server_redraw_client(job->client); + job->data = xstrdup(buf); + + xfree(buf); } size_t diff --git a/tmux.1 b/tmux.1 index c5ccc63d..9e2365dd 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1437,6 +1437,11 @@ may contain any of the following special character sequences: The #(command) form executes .Ql command as a shell command and inserts the first line of its output. +Note that shell commands are only executed once at the interval specified by +the +.Ic status-interval +option: if the status line is redrawn in the meantime, the previous result is +used. #[attributes] allows a comma-separated list of attributes to be specified, these may be .Ql fg=colour diff --git a/tmux.h b/tmux.h index e9c7d7f9..2e2ee06a 100644 --- a/tmux.h +++ b/tmux.h @@ -563,6 +563,24 @@ struct options { /* Key list for prefix option. */ ARRAY_DECL(keylist, int); +/* Scheduled job. */ +struct job { + char *cmd; + pid_t pid; + + struct client *client; + + int fd; + struct buffer *out; + + void (*callbackfn)(struct job *); + void (*freefn)(void *); + void *data; + + RB_ENTRY(job) entry; +}; +RB_HEAD(jobs, job); + /* Screen selection. */ struct screen_sel { int flag; @@ -942,9 +960,10 @@ struct client { char *cwd; struct tty tty; - struct timeval status_timer; struct timeval repeat_timer; + struct timeval status_timer; + struct jobs status_jobs; struct screen status; #define CLIENT_TERMINAL 0x1 @@ -1179,6 +1198,20 @@ struct options_entry *options_set_data( struct options *, const char *, void *, void (*)(void *)); void *options_get_data(struct options *, const char *); +/* job.c */ +extern struct jobs jobs_tree; +int job_cmp(struct job *, struct job *); +RB_PROTOTYPE(jobs, job, entry, job_cmp); +void job_tree_init(struct jobs *); +void job_tree_free(struct jobs *); +u_int job_tree_size(struct jobs *); +struct job *job_get(struct jobs *, const char *); +struct job *job_add(struct jobs *, struct client *, + const char *, void (*)(struct job *), void (*)(void *), void *); +void job_free(struct job *); +int job_run(struct job *); +void job_kill(struct job *); + /* environ.c */ int environ_cmp(struct environ_entry *, struct environ_entry *); RB_PROTOTYPE(environ, environ_entry, entry, environ_cmp); @@ -1485,7 +1518,7 @@ void server_clear_identify(struct client *); /* status.c */ int status_redraw(struct client *); -char *status_replace(struct session *, const char *, time_t); +char *status_replace(struct client *, const char *, time_t); void printflike2 status_message_set(struct client *, const char *, ...); void status_message_clear(struct client *); int status_message_redraw(struct client *); From 9ed62eeb911ff58efbea7688ed8e77b611dcaaa2 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 10 Oct 2009 15:23:13 +0000 Subject: [PATCH 0375/1180] When a window is zombified and automatic-rename is on, append [dead] to the name. --- names.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/names.c b/names.c index 014a600c..fe26938d 100644 --- a/names.c +++ b/names.c @@ -73,6 +73,12 @@ set_window_names(void) xfree(name); } + if (w->active->fd == -1) { + xasprintf(&name, "%s[dead]", wname); + xfree(wname); + wname = name; + } + if (strcmp(wname, w->name) == 0) xfree(wname); else { From 2988c594cc030ae11a4a3713882c3209a63aa4a4 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 10 Oct 2009 15:29:34 +0000 Subject: [PATCH 0376/1180] Accept key and mouse input for keys in zombified windows if they are in a mode.. --- window.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/window.c b/window.c index 71e09b52..20ea37d9 100644 --- a/window.c +++ b/window.c @@ -629,15 +629,17 @@ window_pane_key(struct window_pane *wp, struct client *c, int key) { struct window_pane *wp2; - if (wp->fd == -1 || !window_pane_visible(wp)) + if (!window_pane_visible(wp)) return; if (wp->mode != NULL) { if (wp->mode->key != NULL) wp->mode->key(wp, c, key); return; - } + } + if (wp->fd == -1) + return; input_key(wp, key); if (options_get_number(&wp->window->options, "synchronize-panes")) { TAILQ_FOREACH(wp2, &wp->window->panes, entry) { @@ -653,7 +655,7 @@ void window_pane_mouse( struct window_pane *wp, struct client *c, u_char b, u_char x, u_char y) { - if (wp->fd == -1 || !window_pane_visible(wp)) + if (!window_pane_visible(wp)) return; /* XXX convert from 1-based? */ @@ -668,7 +670,7 @@ window_pane_mouse( if (wp->mode != NULL) { if (wp->mode->mouse != NULL) wp->mode->mouse(wp, c, b, x, y); - } else + } else if (wp->fd != -1) input_mouse(wp, b, x, y); } From 5aa49e695ecb31bdef210fc1dec2b2ef0d460845 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 10 Oct 2009 17:19:38 +0000 Subject: [PATCH 0377/1180] Split list-panes off from list-windows. --- Makefile | 3 +- cmd-list-panes.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++ cmd-list-windows.c | 33 ++------------------ cmd.c | 1 + tmux.1 | 4 +++ tmux.h | 1 + 6 files changed, 88 insertions(+), 32 deletions(-) create mode 100644 cmd-list-panes.c diff --git a/Makefile b/Makefile index a3872ee1..17097ea6 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,8 @@ SRCS= attributes.c buffer-poll.c buffer.c cfg.c client-fn.c \ cmd-kill-server.c cmd-kill-session.c cmd-kill-window.c \ cmd-last-window.c cmd-link-window.c cmd-list-buffers.c \ cmd-list-clients.c cmd-list-commands.c cmd-list-keys.c \ - cmd-list-sessions.c cmd-list-windows.c cmd-list.c cmd-load-buffer.c \ + cmd-list-sessions.c cmd-list-windows.c cmd-list-panes.c \ + cmd-list.c cmd-load-buffer.c \ cmd-lock-server.c cmd-lock-client.c cmd-lock-session.c \ cmd-move-window.c cmd-new-session.c cmd-new-window.c \ cmd-next-layout.c cmd-next-window.c cmd-paste-buffer.c \ diff --git a/cmd-list-panes.c b/cmd-list-panes.c new file mode 100644 index 00000000..0dcf0009 --- /dev/null +++ b/cmd-list-panes.c @@ -0,0 +1,78 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2009 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 "tmux.h" + +/* + * List panes on given window.. + */ + +int cmd_list_panes_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_list_panes_entry = { + "list-panes", "lsp", + CMD_TARGET_WINDOW_USAGE, + 0, 0, + cmd_target_init, + cmd_target_parse, + cmd_list_panes_exec, + cmd_target_free, + cmd_target_print +}; + +int +cmd_list_panes_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_target_data *data = self->data; + struct winlink *wl; + struct window_pane *wp; + struct grid *gd; + struct grid_line *gl; + u_int i; + unsigned long long size; + const char *name; + + if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) + return (-1); + + TAILQ_FOREACH(wp, &wl->window->panes, entry) { + gd = wp->base.grid; + + size = 0; + for (i = 0; i < gd->hsize; i++) { + gl = &gd->linedata[i]; + size += gl->cellsize * sizeof *gl->celldata; + size += gl->utf8size * sizeof *gl->utf8data; + } + size += gd->hsize * sizeof *gd->linedata; + + name = NULL; + if (wp->fd != -1) + name = ttyname(wp->fd); + if (name == NULL) + name = "unknown"; + ctx->print(ctx, "%s [%ux%u] [history %u/%u, %llu bytes]", + name, wp->sx, wp->sy, gd->hsize, gd->hlimit, size); + } + + return (0); +} diff --git a/cmd-list-windows.c b/cmd-list-windows.c index c2f8bbd1..f8a46bcd 100644 --- a/cmd-list-windows.c +++ b/cmd-list-windows.c @@ -45,42 +45,13 @@ cmd_list_windows_exec(struct cmd *self, struct cmd_ctx *ctx) struct cmd_target_data *data = self->data; struct session *s; struct winlink *wl; - struct window *w; - struct window_pane *wp; - struct grid *gd; - struct grid_line *gl; - u_int i; - unsigned long long size; - const char *name; if ((s = cmd_find_session(ctx, data->target)) == NULL) return (-1); RB_FOREACH(wl, winlinks, &s->windows) { - w = wl->window; - ctx->print(ctx, - "%3d: %s [%ux%u]", wl->idx, w->name, w->sx, w->sy); - - TAILQ_FOREACH(wp, &w->panes, entry) { - gd = wp->base.grid; - - size = 0; - for (i = 0; i < gd->hsize; i++) { - gl = &gd->linedata[i]; - size += gl->cellsize * sizeof *gl->celldata; - size += gl->utf8size * sizeof *gl->utf8data; - } - size += gd->hsize * sizeof *gd->linedata; - - name = NULL; - if (wp->fd != -1) - name = ttyname(wp->fd); - if (name == NULL) - name = "unknown"; - ctx->print(ctx, - " %s [%ux%u] [history %u/%u, %llu bytes]", - name, wp->sx, wp->sy, gd->hsize, gd->hlimit, size); - } + ctx->print(ctx, "%d: %s [%ux%u]", + wl->idx, wl->window->name, wl->window->sx, wl->window->sy); } return (0); diff --git a/cmd.c b/cmd.c index 9ae1fa17..d453c726 100644 --- a/cmd.c +++ b/cmd.c @@ -58,6 +58,7 @@ const struct cmd_entry *cmd_table[] = { &cmd_list_clients_entry, &cmd_list_commands_entry, &cmd_list_keys_entry, + &cmd_list_panes_entry, &cmd_list_sessions_entry, &cmd_list_windows_entry, &cmd_load_buffer_entry, diff --git a/tmux.1 b/tmux.1 index 9e2365dd..ce662961 100644 --- a/tmux.1 +++ b/tmux.1 @@ -775,6 +775,10 @@ exists, it is killed, otherwise an error is generated. If .Fl d is given, the newly linked window is not selected. +.It Ic list-panes Op Fl t Ar target-window +.D1 (alias: Ic lsp ) +List the panes in the current window or in +.Ar target-window . .It Ic list-windows Op Fl t Ar target-session .D1 (alias: Ic lsw ) List windows in the current session or in diff --git a/tmux.h b/tmux.h index 2e2ee06a..c31039ad 100644 --- a/tmux.h +++ b/tmux.h @@ -1367,6 +1367,7 @@ extern const struct cmd_entry cmd_list_buffers_entry; extern const struct cmd_entry cmd_list_clients_entry; extern const struct cmd_entry cmd_list_commands_entry; extern const struct cmd_entry cmd_list_keys_entry; +extern const struct cmd_entry cmd_list_panes_entry; extern const struct cmd_entry cmd_list_sessions_entry; extern const struct cmd_entry cmd_list_windows_entry; extern const struct cmd_entry cmd_load_buffer_entry; From b7c364a853352531dbc48758046ae7056a8885fa Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 10 Oct 2009 17:39:55 +0000 Subject: [PATCH 0378/1180] -scroll mode which is dead. --- tmux.1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tmux.1 b/tmux.1 index ce662961..6921976d 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1678,7 +1678,7 @@ Set window modes foreground colour. .It Xo Ic mode-keys .Op Ic vi | emacs .Xc -Use vi or emacs-style key bindings in scroll, copy and choice modes. +Use vi or emacs-style key bindings in copy and choice modes. Key bindings default to emacs. .Pp .It Xo Ic mode-mouse From 095ecf2d9002a10e034268a0a709c5b5bb5c2ae5 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 10 Oct 2009 18:42:14 +0000 Subject: [PATCH 0379/1180] Put all jobs on a global all_jobs list and use that in server.c instead of running through all the clients. --- job.c | 6 ++++++ server.c | 38 +++----------------------------------- tmux.h | 4 +++- 3 files changed, 12 insertions(+), 36 deletions(-) diff --git a/job.c b/job.c index 91646eda..53b05bb4 100644 --- a/job.c +++ b/job.c @@ -30,6 +30,9 @@ * output. */ +/* All jobs list. */ +struct joblist all_jobs = SLIST_HEAD_INITIALIZER(&all_jobs); + RB_GENERATE(jobs, job, entry, job_cmp); int @@ -67,6 +70,7 @@ job_tree_free(struct jobs *jobs) while (!RB_EMPTY(jobs)) { job = RB_ROOT(jobs); RB_REMOVE(jobs, jobs, job); + SLIST_REMOVE(&all_jobs, job, job, lentry); job_free(job); } } @@ -90,6 +94,7 @@ job_add(struct jobs *jobs, struct client *c, const char *cmd, job = xmalloc(sizeof *job); job->cmd = xstrdup(cmd); + job->pid = -1; job->client = c; @@ -101,6 +106,7 @@ job_add(struct jobs *jobs, struct client *c, const char *cmd, job->data = data; RB_INSERT(jobs, jobs, job); + SLIST_INSERT_HEAD(&all_jobs, job, lentry); return (job); } diff --git a/server.c b/server.c index a38f2974..8a0784b3 100644 --- a/server.c +++ b/server.c @@ -73,9 +73,7 @@ void server_handle_windows(void); void server_fill_clients(void); void server_handle_clients(void); void server_fill_jobs(void); -void server_fill_jobs1(struct jobs *); void server_handle_jobs(void); -void server_handle_jobs1(struct jobs *); void server_accept_client(int); void server_handle_client(struct client *); void server_handle_window(struct window *, struct window_pane *); @@ -414,11 +412,7 @@ server_main(int srv_fd) /* Set window names. */ set_window_names(); - /* - * Handle window and client sockets. Clients can create - * windows, so windows must come first to avoid messing up by - * increasing the array size. - */ + /* Handle window and client sockets. */ server_handle_jobs(); server_handle_windows(); server_handle_clients(); @@ -763,23 +757,10 @@ server_fill_clients(void) /* Fill in job fds. */ void server_fill_jobs(void) -{ - struct client *c; - u_int i; - - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - c = ARRAY_ITEM(&clients, i); - if (c != NULL) - server_fill_jobs1(&c->status_jobs); - } -} - -void -server_fill_jobs1(struct jobs *jobs) { struct job *job; - RB_FOREACH(job, jobs, jobs) { + SLIST_FOREACH(job, &all_jobs, lentry) { if (job->fd == -1) continue; server_poll_add(job->fd, POLLIN); @@ -789,24 +770,11 @@ server_fill_jobs1(struct jobs *jobs) /* Handle job fds. */ void server_handle_jobs(void) -{ - struct client *c; - u_int i; - - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - c = ARRAY_ITEM(&clients, i); - if (c != NULL) - server_handle_jobs1(&c->status_jobs); - } -} - -void -server_handle_jobs1(struct jobs *jobs) { struct job *job; struct pollfd *pfd; - RB_FOREACH(job, jobs, jobs) { + SLIST_FOREACH(job, &all_jobs, lentry) { if (job->fd == -1) continue; if ((pfd = server_poll_lookup(job->fd)) == NULL) diff --git a/tmux.h b/tmux.h index c31039ad..6687d84a 100644 --- a/tmux.h +++ b/tmux.h @@ -578,8 +578,10 @@ struct job { void *data; RB_ENTRY(job) entry; + SLIST_ENTRY(job) lentry; }; RB_HEAD(jobs, job); +SLIST_HEAD(joblist, job); /* Screen selection. */ struct screen_sel { @@ -1199,7 +1201,7 @@ struct options_entry *options_set_data( void *options_get_data(struct options *, const char *); /* job.c */ -extern struct jobs jobs_tree; +extern struct joblist all_jobs; int job_cmp(struct job *, struct job *); RB_PROTOTYPE(jobs, job, entry, job_cmp); void job_tree_init(struct jobs *); From f68ade7b1d1c3aa74a11a5eeed35ea409d5d63c7 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 11 Oct 2009 00:53:14 +0000 Subject: [PATCH 0380/1180] Braek some bits out of server_fill_client() that aren't really related to polling into their own function. --- server.c | 74 ++++++++++++++++++++++++++++++++------------------------ 1 file changed, 42 insertions(+), 32 deletions(-) diff --git a/server.c b/server.c index 8a0784b3..c724d186 100644 --- a/server.c +++ b/server.c @@ -90,6 +90,7 @@ void server_set_title(struct client *); void server_check_timers(struct client *); void server_lock_server(void); void server_lock_sessions(void); +void server_check_clients(void); void server_second_timers(void); int server_update_socket(void); @@ -369,6 +370,9 @@ server_main(int srv_fd) sigusr1 = 0; } + /* Process client actions. */ + server_check_clients(); + /* Initialise pollfd array and add server socket. */ server_poll_reset(); server_poll_add(srv_fd, POLLIN); @@ -593,18 +597,47 @@ server_handle_windows(void) } } +/* Check clients for redraw and timers. */ +void +server_check_clients(void) +{ + struct client *c; + struct window *w; + struct window_pane *wp; + u_int i; + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c == NULL || c->session == NULL) + continue; + + server_check_timers(c); + server_check_redraw(c); + } + + /* + * Clear any window redraw flags (will have been redrawn as part of + * client). + */ + for (i = 0; i < ARRAY_LENGTH(&windows); i++) { + w = ARRAY_ITEM(&windows, i); + if (w == NULL) + continue; + + w->flags &= ~WINDOW_REDRAW; + TAILQ_FOREACH(wp, &w->panes, entry) + wp->flags &= ~PANE_REDRAW; + } +} + /* Check for general redraw on client. */ void server_check_redraw(struct client *c) { - struct session *s; + struct session *s = c->session; struct window_pane *wp; int flags, redraw; - if (c == NULL || c->session == NULL) - return; - s = c->session; - flags = c->tty.flags & TTY_FREEZE; c->tty.flags &= ~TTY_FREEZE; @@ -664,15 +697,11 @@ server_set_title(struct client *c) void server_check_timers(struct client *c) { - struct session *s; + struct session *s = c->session; struct job *job; struct timeval tv; u_int interval; - if (c == NULL || c->session == NULL) - return; - s = c->session; - if (gettimeofday(&tv, NULL) != 0) fatal("gettimeofday failed"); @@ -709,18 +738,13 @@ server_check_timers(struct client *c) void server_fill_clients(void) { - struct client *c; - struct window *w; - struct window_pane *wp; - u_int i; - int events; + struct client *c; + u_int i; + int events; for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); - server_check_timers(c); - server_check_redraw(c); - if (c != NULL) { events = 0; if (!(c->flags & CLIENT_BAD)) @@ -738,20 +762,6 @@ server_fill_clients(void) server_poll_add(c->tty.fd, events); } } - - /* - * Clear any window redraw flags (will have been redrawn as part of - * client). - */ - for (i = 0; i < ARRAY_LENGTH(&windows); i++) { - w = ARRAY_ITEM(&windows, i); - if (w == NULL) - continue; - - w->flags &= ~WINDOW_REDRAW; - TAILQ_FOREACH(wp, &w->panes, entry) - wp->flags &= ~PANE_REDRAW; - } } /* Fill in job fds. */ From 4bc0f6e7e9eac73f7a1221ed4c2854d12eb1cf7e Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 11 Oct 2009 07:01:10 +0000 Subject: [PATCH 0381/1180] Clean up by introducing a wrapper struct for mouse clicks rather than passing three u_chars around. As a side-effect this fixes incorrectly rejecting high cursor positions (because it was comparing them as signed char), reported by Tom Doherty. --- input-keys.c | 8 ++++---- server.c | 8 ++++---- tmux.h | 16 ++++++++++++---- tty-keys.c | 21 +++++++++++---------- window-choose.c | 14 +++++++------- window-copy.c | 14 +++++++------- window.c | 16 +++++++--------- 7 files changed, 52 insertions(+), 45 deletions(-) diff --git a/input-keys.c b/input-keys.c index 30e2be05..f73bcf36 100644 --- a/input-keys.c +++ b/input-keys.c @@ -219,12 +219,12 @@ input_key(struct window_pane *wp, int key) /* Handle input mouse. */ void -input_mouse(struct window_pane *wp, u_char b, u_char x, u_char y) +input_mouse(struct window_pane *wp, struct mouse_event *m) { if (wp->screen->mode & MODE_MOUSE) { buffer_write(wp->out, "\033[M", 3); - buffer_write8(wp->out, b + 32); - buffer_write8(wp->out, x + 33); - buffer_write8(wp->out, y + 33); + buffer_write8(wp->out, m->b + 32); + buffer_write8(wp->out, m->x + 33); + buffer_write8(wp->out, m->y + 33); } } diff --git a/server.c b/server.c index c724d186..cff3db3b 100644 --- a/server.c +++ b/server.c @@ -880,9 +880,9 @@ server_handle_client(struct client *c) struct timeval tv; struct key_binding *bd; struct keylist *keylist; + struct mouse_event mouse; int key, status, xtimeout, mode, isprefix; u_int i; - u_char mouse[3]; xtimeout = options_get_number(&c->session->options, "repeat-time"); if (xtimeout != 0 && c->flags & CLIENT_REPEAT) { @@ -894,7 +894,7 @@ server_handle_client(struct client *c) /* Process keys. */ keylist = options_get_data(&c->session->options, "prefix"); - while (tty_keys_next(&c->tty, &key, mouse) == 0) { + while (tty_keys_next(&c->tty, &key, &mouse) == 0) { if (c->session == NULL) return; @@ -922,10 +922,10 @@ server_handle_client(struct client *c) /* Check for mouse keys. */ if (key == KEYC_MOUSE) { if (options_get_number(oo, "mouse-select-pane")) { - window_set_active_at(w, mouse[1], mouse[2]); + window_set_active_at(w, mouse.x, mouse.y); wp = w->active; } - window_pane_mouse(wp, c, mouse[0], mouse[1], mouse[2]); + window_pane_mouse(wp, c, &mouse); continue; } diff --git a/tmux.h b/tmux.h index 6687d84a..71b307fb 100644 --- a/tmux.h +++ b/tmux.h @@ -674,13 +674,14 @@ struct input_ctx { */ struct client; struct window; +struct mouse_event; struct window_mode { struct screen *(*init)(struct window_pane *); void (*free)(struct window_pane *); void (*resize)(struct window_pane *, u_int, u_int); void (*key)(struct window_pane *, struct client *, int); void (*mouse)(struct window_pane *, - struct client *, u_char, u_char, u_char); + struct client *, struct mouse_event *); void (*timer)(struct window_pane *); }; @@ -951,6 +952,13 @@ struct tty_ctx { u_int orlower; }; +/* Mouse input. */ +struct mouse_event { + u_char b; + u_char x; + u_char y; +}; + /* Client connection. */ struct client { struct imsgbuf ibuf; @@ -1285,7 +1293,7 @@ int tty_keys_cmp(struct tty_key *, struct tty_key *); RB_PROTOTYPE(tty_keys, tty_key, entry, tty_keys_cmp); void tty_keys_init(struct tty *); void tty_keys_free(struct tty *); -int tty_keys_next(struct tty *, int *, u_char *); +int tty_keys_next(struct tty *, int *, struct mouse_event *); /* options-cmd.c */ const char *set_option_print( @@ -1542,7 +1550,7 @@ void input_parse(struct window_pane *); /* input-key.c */ void input_key(struct window_pane *, int); -void input_mouse(struct window_pane *, u_char, u_char, u_char); +void input_mouse(struct window_pane *, struct mouse_event *); /* colour.c */ void colour_set_fg(struct grid_cell *, int); @@ -1705,7 +1713,7 @@ void window_pane_reset_mode(struct window_pane *); void window_pane_parse(struct window_pane *); void window_pane_key(struct window_pane *, struct client *, int); void window_pane_mouse(struct window_pane *, - struct client *, u_char, u_char, u_char); + struct client *, struct mouse_event *); int window_pane_visible(struct window_pane *); char *window_pane_search( struct window_pane *, const char *, u_int *); diff --git a/tty-keys.c b/tty-keys.c index 11a3187f..a443bd5a 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -27,7 +27,7 @@ void tty_keys_add(struct tty *, const char *, int, int); int tty_keys_parse_xterm(struct tty *, char *, size_t, size_t *); -int tty_keys_parse_mouse(struct tty *, char *, size_t, size_t *, u_char *); +int tty_keys_parse_mouse(char *, size_t, size_t *, struct mouse_event *); struct tty_key_ent { enum tty_code_code code; @@ -231,7 +231,7 @@ tty_keys_find(struct tty *tty, char *buf, size_t len, size_t *size) } int -tty_keys_next(struct tty *tty, int *key, u_char *mouse) +tty_keys_next(struct tty *tty, int *key, struct mouse_event *mouse) { struct tty_key *tk; struct timeval tv; @@ -269,7 +269,7 @@ tty_keys_next(struct tty *tty, int *key, u_char *mouse) } /* Not found. Is this a mouse key press? */ - *key = tty_keys_parse_mouse(tty, buf, len, &size, mouse); + *key = tty_keys_parse_mouse(buf, len, &size, mouse); if (*key != KEYC_NONE) { buffer_remove(tty->in, size); goto found; @@ -331,8 +331,7 @@ found: } int -tty_keys_parse_mouse( - unused struct tty *tty, char *buf, size_t len, size_t *size, u_char *mouse) +tty_keys_parse_mouse(char *buf, size_t len, size_t *size, struct mouse_event *m) { /* * Mouse sequences are \033[M followed by three characters indicating @@ -344,12 +343,14 @@ tty_keys_parse_mouse( return (KEYC_NONE); *size = 6; - if (buf[3] < 32 || buf[4] < 33 || buf[5] < 33) + m->b = buf[3]; + m->x = buf[4]; + m->y = buf[5]; + if (m->b < 32 || m->x < 33 || m->y < 33) return (KEYC_NONE); - - mouse[0] = buf[3] - 32; - mouse[1] = buf[4] - 33; - mouse[2] = buf[5] - 33; + m->b -= 32; + m->x -= 33; + m->y -= 33; return (KEYC_MOUSE); } diff --git a/window-choose.c b/window-choose.c index acb6ab8a..c44fe88d 100644 --- a/window-choose.c +++ b/window-choose.c @@ -27,7 +27,7 @@ void window_choose_free(struct window_pane *); void window_choose_resize(struct window_pane *, u_int, u_int); void window_choose_key(struct window_pane *, struct client *, int); void window_choose_mouse( - struct window_pane *, struct client *, u_char, u_char, u_char); + struct window_pane *, struct client *, struct mouse_event *); void window_choose_redraw_screen(struct window_pane *); void window_choose_write_line( @@ -264,22 +264,22 @@ window_choose_key(struct window_pane *wp, unused struct client *c, int key) } void -window_choose_mouse(struct window_pane *wp, - unused struct client *c, u_char b, u_char x, u_char y) +window_choose_mouse( + struct window_pane *wp, unused struct client *c, struct mouse_event *m) { struct window_choose_mode_data *data = wp->modedata; struct screen *s = &data->screen; struct window_choose_mode_item *item; u_int idx; - if ((b & 3) == 3) + if ((m->b & 3) == 3) return; - if (x >= screen_size_x(s)) + if (m->x >= screen_size_x(s)) return; - if (y >= screen_size_y(s)) + if (m->y >= screen_size_y(s)) return; - idx = data->top + y; + idx = data->top + m->y; if (idx >= ARRAY_LENGTH(&data->list)) return; data->selected = idx; diff --git a/window-copy.c b/window-copy.c index 0f497f87..2eb91acb 100644 --- a/window-copy.c +++ b/window-copy.c @@ -29,7 +29,7 @@ void window_copy_resize(struct window_pane *, u_int, u_int); void window_copy_key(struct window_pane *, struct client *, int); int window_copy_key_input(struct window_pane *, int); void window_copy_mouse( - struct window_pane *, struct client *, u_char, u_char, u_char); + struct window_pane *, struct client *, struct mouse_event *); void window_copy_redraw_lines(struct window_pane *, u_int, u_int); void window_copy_redraw_screen(struct window_pane *); @@ -418,20 +418,20 @@ window_copy_key_input(struct window_pane *wp, int key) } void -window_copy_mouse(struct window_pane *wp, - unused struct client *c, u_char b, u_char x, u_char y) +window_copy_mouse( + struct window_pane *wp, unused struct client *c, struct mouse_event *m) { struct window_copy_mode_data *data = wp->modedata; struct screen *s = &data->screen; - if ((b & 3) == 3) + if ((m->b & 3) == 3) return; - if (x >= screen_size_x(s)) + if (m->x >= screen_size_x(s)) return; - if (y >= screen_size_y(s)) + if (m->y >= screen_size_y(s)) return; - window_copy_update_cursor(wp, x, y); + window_copy_update_cursor(wp, m->x, m->y); if (window_copy_update_selection(wp)) window_copy_redraw_screen(wp); } diff --git a/window.c b/window.c index 20ea37d9..17a8f018 100644 --- a/window.c +++ b/window.c @@ -653,25 +653,23 @@ window_pane_key(struct window_pane *wp, struct client *c, int key) void window_pane_mouse( - struct window_pane *wp, struct client *c, u_char b, u_char x, u_char y) + struct window_pane *wp, struct client *c, struct mouse_event *m) { if (!window_pane_visible(wp)) return; - /* XXX convert from 1-based? */ - - if (x < wp->xoff || x >= wp->xoff + wp->sx) + if (m->x < wp->xoff || m->x >= wp->xoff + wp->sx) return; - if (y < wp->yoff || y >= wp->yoff + wp->sy) + if (m->y < wp->yoff || m->y >= wp->yoff + wp->sy) return; - x -= wp->xoff; - y -= wp->yoff; + m->x -= wp->xoff; + m->y -= wp->yoff; if (wp->mode != NULL) { if (wp->mode->mouse != NULL) - wp->mode->mouse(wp, c, b, x, y); + wp->mode->mouse(wp, c, m); } else if (wp->fd != -1) - input_mouse(wp, b, x, y); + input_mouse(wp, m); } int From ff4b4e667a64b30e4323df4b0e1637fc7ebae6c1 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 11 Oct 2009 07:20:16 +0000 Subject: [PATCH 0382/1180] Collect status from dead jobs and don't invoke the callback until both all input (the socket is closed) and status is available. --- job.c | 5 ++++- server.c | 32 +++++++++++++++++++++++++++----- tmux.h | 4 ++++ 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/job.c b/job.c index 53b05bb4..df515b37 100644 --- a/job.c +++ b/job.c @@ -105,6 +105,8 @@ job_add(struct jobs *jobs, struct client *c, const char *cmd, job->freefn = freefn; job->data = data; + job->flags = JOB_DONE; + RB_INSERT(jobs, jobs, job); SLIST_INSERT_HEAD(&all_jobs, job, lentry); @@ -133,8 +135,9 @@ job_run(struct job *job) { int nullfd, out[2], mode; - if (job->fd != -1) + if (!(job->flags & JOB_DONE)) return (0); + job->flags &= ~JOB_DONE; if (pipe(out) != 0) return (-1); diff --git a/server.c b/server.c index cff3db3b..d19b321d 100644 --- a/server.c +++ b/server.c @@ -88,6 +88,7 @@ void server_check_window(struct window *); void server_check_redraw(struct client *); void server_set_title(struct client *); void server_check_timers(struct client *); +void server_check_jobs(void); void server_lock_server(void); void server_lock_sessions(void); void server_check_clients(void); @@ -370,7 +371,8 @@ server_main(int srv_fd) sigusr1 = 0; } - /* Process client actions. */ + /* Collect any jobs that have died and process clients. */ + server_check_jobs(); server_check_clients(); /* Initialise pollfd array and add server socket. */ @@ -389,7 +391,6 @@ server_main(int srv_fd) /* Do the poll. */ pfds = server_poll_flatten(&nfds); - log_debug("polling %d", nfds); if (poll(pfds, nfds, xtimeout) == -1) { if (errno == EAGAIN || errno == EINTR) continue; @@ -510,6 +511,7 @@ server_child_signal(void) { struct window *w; struct window_pane *wp; + struct job *job; int status; pid_t pid; u_int i; @@ -523,8 +525,15 @@ server_child_signal(void) case 0: return; } - if (!WIFSTOPPED(status)) + if (!WIFSTOPPED(status)) { + SLIST_FOREACH(job, &all_jobs, lentry) { + if (pid == job->pid) { + job->pid = -1; + job->status = status; + } + } continue; + } if (WSTOPSIG(status) == SIGTTIN || WSTOPSIG(status) == SIGTTOU) continue; @@ -792,12 +801,25 @@ server_handle_jobs(void) if (buffer_poll(pfd, job->out, NULL) != 0) { close(job->fd); job->fd = -1; - if (job->callbackfn != NULL) - job->callbackfn(job); } } } +/* Handle job fds. */ +void +server_check_jobs(void) +{ + struct job *job; + + SLIST_FOREACH(job, &all_jobs, lentry) { + if (job->flags & JOB_DONE || job->fd != -1 || job->pid != -1) + continue; + if (job->callbackfn != NULL) + job->callbackfn(job); + job->flags |= JOB_DONE; + } +} + /* Handle client pollfds. */ void server_handle_clients(void) diff --git a/tmux.h b/tmux.h index 71b307fb..a975dca3 100644 --- a/tmux.h +++ b/tmux.h @@ -567,6 +567,7 @@ ARRAY_DECL(keylist, int); struct job { char *cmd; pid_t pid; + int status; struct client *client; @@ -577,6 +578,9 @@ struct job { void (*freefn)(void *); void *data; + int flags; +#define JOB_DONE 0x1 + RB_ENTRY(job) entry; SLIST_ENTRY(job) lentry; }; From abedfa77daf3b8a815b134e3650bece0bb646631 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 11 Oct 2009 07:30:07 +0000 Subject: [PATCH 0383/1180] There isn't much point in having a free function if it isn't used. Also allow a NULL tree. --- job.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/job.c b/job.c index df515b37..15155bb3 100644 --- a/job.c +++ b/job.c @@ -107,7 +107,8 @@ job_add(struct jobs *jobs, struct client *c, const char *cmd, job->flags = JOB_DONE; - RB_INSERT(jobs, jobs, job); + if (jobs != NULL) + RB_INSERT(jobs, jobs, job); SLIST_INSERT_HEAD(&all_jobs, job, lentry); return (job); @@ -121,6 +122,9 @@ job_free(struct job *job) xfree(job->cmd); + if (job->freefn != NULL && job->data != NULL) + job->freefn(job->data); + if (job->fd != -1) close(job->fd); if (job->out != NULL) From cebc988dd4b8372b84747a132d0e2babaa84e988 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 11 Oct 2009 08:58:05 +0000 Subject: [PATCH 0384/1180] Switch run-shell over to queue the command in the background like #(). --- cmd-run-shell.c | 115 +++++++++++++++++++++++++++++++++--------------- job.c | 2 +- server.c | 10 +++-- tmux.1 | 4 +- 4 files changed, 89 insertions(+), 42 deletions(-) diff --git a/cmd-run-shell.c b/cmd-run-shell.c index 71e5b96b..d00571a2 100644 --- a/cmd-run-shell.c +++ b/cmd-run-shell.c @@ -29,6 +29,9 @@ int cmd_run_shell_exec(struct cmd *, struct cmd_ctx *); +void cmd_run_shell_callback(struct job *); +void cmd_run_shell_free(void *); + const struct cmd_entry cmd_run_shell_entry = { "run-shell", "run", "command", @@ -40,57 +43,97 @@ const struct cmd_entry cmd_run_shell_entry = { cmd_target_print }; +struct cmd_run_shell_data { + char *cmd; + struct cmd_ctx ctx; +}; + int cmd_run_shell_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; - FILE *fp; - char *buf, *lbuf, *msg; - size_t len; - int has_output, ret, status; + struct cmd_target_data *data = self->data; + struct cmd_run_shell_data *cdata; + struct job *job; - if ((fp = popen(data->arg, "r")) == NULL) { - ctx->error(ctx, "popen error"); - return (-1); - } + cdata = xmalloc(sizeof *cdata); + cdata->cmd = xstrdup(data->arg); + memcpy(&cdata->ctx, ctx, sizeof cdata->ctx); - has_output = 0; - lbuf = NULL; - while ((buf = fgetln(fp, &len)) != NULL) { - if (buf[len - 1] == '\n') - buf[len - 1] = '\0'; - else { - lbuf = xmalloc(len + 1); - memcpy(lbuf, buf, len); - lbuf[len] = '\0'; - buf = lbuf; + if (ctx->cmdclient != NULL) + ctx->cmdclient->references++; + if (ctx->curclient != NULL) + ctx->curclient->references++; + + job = job_add(NULL, NULL, + data->arg, cmd_run_shell_callback, cmd_run_shell_free, cdata); + job_run(job); + + return (1); /* don't let client exit */ +} + +void +cmd_run_shell_callback(struct job *job) +{ + struct cmd_run_shell_data *cdata = job->data; + struct cmd_ctx *ctx = &cdata->ctx; + char *cmd, *msg, *line, *buf; + size_t off, len, llen; + int retcode; + + buf = BUFFER_OUT(job->out); + len = BUFFER_USED(job->out); + + cmd = cdata->cmd; + + if (len != 0) { + line = buf; + for (off = 0; off < len; off++) { + if (buf[off] == '\n') { + llen = buf + off - line; + if (llen > INT_MAX) + break; + ctx->print(ctx, "%.*s", (int) llen, line); + line = buf + off + 1; + } } - ctx->print(ctx, "%s", buf); - has_output = 1; + llen = buf + len - line; + if (llen > 0 && llen < INT_MAX) + ctx->print(ctx, "%.*s", (int) llen, line); } - if (lbuf != NULL) - xfree(lbuf); msg = NULL; - status = pclose(fp); - - if (WIFEXITED(status)) { - if ((ret = WEXITSTATUS(status)) == 0) - return (0); - xasprintf(&msg, "'%s' returned %d", data->arg, ret); - } else if (WIFSIGNALED(status)) { - xasprintf( - &msg, "'%s' terminated by signal %d", data->arg, - WTERMSIG(status)); + if (WIFEXITED(job->status)) { + if ((retcode = WEXITSTATUS(job->status)) != 0) + xasprintf(&msg, "'%s' returned %d", cmd, retcode); + } else if (WIFSIGNALED(job->status)) { + retcode = WTERMSIG(job->status); + xasprintf(&msg, "'%s' terminated by signal %d", cmd, retcode); } - if (msg != NULL) { - if (has_output) + if (len != 0) ctx->print(ctx, "%s", msg); else ctx->info(ctx, "%s", msg); xfree(msg); } - return (0); + job_free(job); /* calls cmd_run_shell_free */ +} + +void +cmd_run_shell_free(void *data) +{ + struct cmd_run_shell_data *cdata = data; + struct cmd_ctx *ctx = &cdata->ctx; + + return; + if (ctx->cmdclient != NULL) { + ctx->cmdclient->references--; + server_write_client(ctx->cmdclient, MSG_EXIT, NULL, 0); + } + if (ctx->curclient != NULL) + ctx->curclient->references--; + + xfree(cdata->cmd); + xfree(cdata); } diff --git a/job.c b/job.c index 15155bb3..6a824fa6 100644 --- a/job.c +++ b/job.c @@ -70,7 +70,6 @@ job_tree_free(struct jobs *jobs) while (!RB_EMPTY(jobs)) { job = RB_ROOT(jobs); RB_REMOVE(jobs, jobs, job); - SLIST_REMOVE(&all_jobs, job, job, lentry); job_free(job); } } @@ -120,6 +119,7 @@ job_free(struct job *job) { job_kill(job); + SLIST_REMOVE(&all_jobs, job, job, lentry); xfree(job->cmd); if (job->freefn != NULL && job->data != NULL) diff --git a/server.c b/server.c index d19b321d..bf9aba94 100644 --- a/server.c +++ b/server.c @@ -810,13 +810,17 @@ void server_check_jobs(void) { struct job *job; - + +restart: SLIST_FOREACH(job, &all_jobs, lentry) { if (job->flags & JOB_DONE || job->fd != -1 || job->pid != -1) continue; - if (job->callbackfn != NULL) - job->callbackfn(job); job->flags |= JOB_DONE; + + if (job->callbackfn != NULL) { + job->callbackfn(job); + goto restart; /* could be freed by callback */ + } } } diff --git a/tmux.1 b/tmux.1 index 6921976d..f4616ed4 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2068,8 +2068,8 @@ option. .D1 (alias: Ic run ) Execute .Ar command -without creating a window. -Any output to stdout is displayed in output mode. +in the background without creating a window. +After the command finishes, any output to stdout is displayed in output mode. If .Ar command doesn't return success, the exit status is also displayed. From 88f3ffe86ead70d37c918c7c33970929c481f9ee Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 11 Oct 2009 09:04:33 +0000 Subject: [PATCH 0385/1180] Remove a debugging leftover and add copyright. --- cmd-run-shell.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd-run-shell.c b/cmd-run-shell.c index d00571a2..ca414dc8 100644 --- a/cmd-run-shell.c +++ b/cmd-run-shell.c @@ -2,6 +2,7 @@ /* * Copyright (c) 2009 Tiago Cunha + * Copyright (c) 2009 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 @@ -126,7 +127,6 @@ cmd_run_shell_free(void *data) struct cmd_run_shell_data *cdata = data; struct cmd_ctx *ctx = &cdata->ctx; - return; if (ctx->cmdclient != NULL) { ctx->cmdclient->references--; server_write_client(ctx->cmdclient, MSG_EXIT, NULL, 0); From 325e20d76d25685a3a7d9e5042928b2691c7bc8f Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 11 Oct 2009 09:10:57 +0000 Subject: [PATCH 0386/1180] Convert if-shell over to the background job framework as well. --- cmd-if-shell.c | 146 +++++++++++++++++++------------------------------ 1 file changed, 57 insertions(+), 89 deletions(-) diff --git a/cmd-if-shell.c b/cmd-if-shell.c index e84efa84..e0775da8 100644 --- a/cmd-if-shell.c +++ b/cmd-if-shell.c @@ -2,6 +2,7 @@ /* * Copyright (c) 2009 Tiago Cunha + * Copyright (c) 2009 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 @@ -17,9 +18,8 @@ */ #include +#include -#include -#include #include #include "tmux.h" @@ -28,124 +28,92 @@ * Executes a tmux command if a shell command returns true. */ -int cmd_if_shell_parse(struct cmd *, int, char **, char **); int cmd_if_shell_exec(struct cmd *, struct cmd_ctx *); -void cmd_if_shell_free(struct cmd *); -void cmd_if_shell_init(struct cmd *, int); -size_t cmd_if_shell_print(struct cmd *, char *, size_t); -struct cmd_if_shell_data { - char *cmd; - char *sh_cmd; -}; +void cmd_if_shell_callback(struct job *); +void cmd_if_shell_free(void *); const struct cmd_entry cmd_if_shell_entry = { "if-shell", "if", "shell-command command", - 0, 0, - cmd_if_shell_init, - cmd_if_shell_parse, + CMD_ARG2, 0, + cmd_target_init, + cmd_target_parse, cmd_if_shell_exec, - cmd_if_shell_free, - cmd_if_shell_print + cmd_target_free, + cmd_target_print }; -void -cmd_if_shell_init(struct cmd *self, unused int arg) -{ - struct cmd_if_shell_data *data; - - self->data = data = xmalloc(sizeof *data); - data->cmd = NULL; - data->sh_cmd = NULL; -} - -int -cmd_if_shell_parse(struct cmd *self, int argc, char **argv, char **cause) -{ - struct cmd_if_shell_data *data; - int opt; - - self->entry->init(self, KEYC_NONE); - data = self->data; - - while ((opt = getopt(argc, argv, "")) != -1) { - switch (opt) { - default: - goto usage; - } - } - argc -= optind; - argv += optind; - if (argc != 2) - goto usage; - - data->sh_cmd = xstrdup(argv[0]); - data->cmd = xstrdup(argv[1]); - return (0); - -usage: - xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); - - self->entry->free(self); - return (-1); -} +struct cmd_if_shell_data { + char *cmd; + struct cmd_ctx ctx; +}; int cmd_if_shell_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_if_shell_data *data = self->data; + struct cmd_target_data *data = self->data; + struct cmd_if_shell_data *cdata; + struct job *job; + + cdata = xmalloc(sizeof *cdata); + cdata->cmd = xstrdup(data->arg2); + memcpy(&cdata->ctx, ctx, sizeof cdata->ctx); + + if (ctx->cmdclient != NULL) + ctx->cmdclient->references++; + if (ctx->curclient != NULL) + ctx->curclient->references++; + + job = job_add(NULL, NULL, + data->arg, cmd_if_shell_callback, cmd_if_shell_free, cdata); + job_run(job); + + return (1); /* don't let client exit */ +} + +void +cmd_if_shell_callback(struct job *job) +{ + struct cmd_if_shell_data *cdata = job->data; + struct cmd_ctx *ctx = &cdata->ctx; struct cmd_list *cmdlist; char *cause; - int ret; - if ((ret = system(data->sh_cmd)) < 0) { - ctx->error(ctx, "system error: %s", strerror(errno)); - return (-1); - } else if (ret != 0) - return (0); + if (!WIFEXITED(job->status) || WEXITSTATUS(job->status) != 0) { + job_free(job); /* calls cmd_if_shell_free */ + return; + } - if (cmd_string_parse(data->cmd, &cmdlist, &cause) != 0) { + if (cmd_string_parse(cdata->cmd, &cmdlist, &cause) != 0) { if (cause != NULL) { ctx->error(ctx, "%s", cause); xfree(cause); } - return (-1); + return; } if (cmd_list_exec(cmdlist, ctx) < 0) { cmd_list_free(cmdlist); - return (-1); + return; } cmd_list_free(cmdlist); - return (0); } void -cmd_if_shell_free(struct cmd *self) +cmd_if_shell_free(void *data) { - struct cmd_if_shell_data *data = self->data; + struct cmd_if_shell_data *cdata = data; + struct cmd_ctx *ctx = &cdata->ctx; - if (data->cmd != NULL) - xfree(data->cmd); - if (data->sh_cmd != NULL) - xfree(data->sh_cmd); - xfree(data); -} - -size_t -cmd_if_shell_print(struct cmd *self, char *buf, size_t len) -{ - struct cmd_if_shell_data *data = self->data; - size_t off = 0; - - off += xsnprintf(buf, len, "%s", self->entry->name); - if (data == NULL) - return (off); - if (off < len && data->sh_cmd != NULL) - off += cmd_prarg(buf + off, len - off, " ", data->sh_cmd); - if (off < len && data->cmd != NULL) - off += cmd_prarg(buf + off, len - off, " ", data->cmd); - return (off); + if (ctx->cmdclient != NULL) { + ctx->cmdclient->references--; + server_write_client(ctx->cmdclient, MSG_EXIT, NULL, 0); + } + if (ctx->curclient != NULL) + ctx->curclient->references--; + + xfree(cdata->cmd); + xfree(cdata); } From 64b5f39656f02a7c4cc6d5d4690c9b0ccc3f6c15 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 11 Oct 2009 10:04:27 +0000 Subject: [PATCH 0387/1180] Add a pipe-pane command to allow a pane to be piped to a shell command, for example: pipe-pane 'cat >~/out' No arguments stops outputing and closes the pipe; the -o flag toggles a pipe and on and off (useful for key bindings). Suggested by espie@. --- Makefile | 3 +- cmd-pipe-pane.c | 127 ++++++++++++++++++++++++++++++++++++++++++++++++ cmd.c | 1 + server.c | 17 +++++++ tmux.1 | 24 +++++++++ tmux.h | 5 ++ window.c | 17 +++++++ 7 files changed, 193 insertions(+), 1 deletion(-) create mode 100644 cmd-pipe-pane.c diff --git a/Makefile b/Makefile index 17097ea6..32195762 100644 --- a/Makefile +++ b/Makefile @@ -28,7 +28,8 @@ SRCS= attributes.c buffer-poll.c buffer.c cfg.c client-fn.c \ cmd-run-shell.c cmd-suspend-client.c cmd-swap-pane.c cmd-swap-window.c \ cmd-switch-client.c cmd-unbind-key.c cmd-unlink-window.c \ cmd-set-environment.c cmd-show-environment.c cmd-choose-client.c \ - cmd-up-pane.c cmd-display-message.c cmd-display-panes.c cmd.c \ + cmd-up-pane.c cmd-display-message.c cmd-display-panes.c \ + cmd-pipe-pane.c cmd.c \ colour.c environ.c grid-view.c grid.c input-keys.c \ imsg.c imsg-buffer.c input.c key-bindings.c key-string.c \ layout-set.c layout.c log.c job.c \ diff --git a/cmd-pipe-pane.c b/cmd-pipe-pane.c new file mode 100644 index 00000000..9a4f44d3 --- /dev/null +++ b/cmd-pipe-pane.c @@ -0,0 +1,127 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2009 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 "tmux.h" + +/* + * Open pipe to redirect pane output. If already open, close first. + */ + +int cmd_pipe_pane_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_pipe_pane_entry = { + "pipe-pane", "pipep", + CMD_TARGET_PANE_USAGE "[-o] [command]", + CMD_ARG01, CMD_CHFLAG('o'), + cmd_target_init, + cmd_target_parse, + cmd_pipe_pane_exec, + cmd_target_free, + cmd_target_print +}; + +int +cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_target_data *data = self->data; + struct winlink *wl; + struct window_pane *wp; + int old_fd, pipe_fd[2], null_fd, mode; + + if ((wl = cmd_find_pane(ctx, data->target, NULL, &wp)) == NULL) + return (-1); + + /* Destroy the old pipe. */ + old_fd = wp->pipe_fd; + if (wp->pipe_fd != -1) { + buffer_destroy(wp->pipe_buf); + close(wp->pipe_fd); + wp->pipe_fd = -1; + } + + /* If no pipe command, that is enough. */ + if (data->arg == NULL || *data->arg == '\0') + return (0); + + /* + * With -o, only open the new pipe if there was no previous one. This + * allows a pipe to be toggled with a single key, for example: + * + * bind ^p pipep -o 'cat >>~/output' + */ + if (data->chflags & CMD_CHFLAG('o') && old_fd != -1) + return (0); + + /* Open the new pipe. */ + if (pipe(pipe_fd) != 0) { + ctx->error(ctx, "pipe error: %s", strerror(errno)); + return (-1); + } + + /* Fork the child. */ + switch (fork()) { + case -1: + ctx->error(ctx, "fork error: %s", strerror(errno)); + return (-1); + case 0: + /* Child process. */ + close(pipe_fd[0]); + sigreset(); + + if (dup2(pipe_fd[1], STDIN_FILENO) == -1) + _exit(1); + if (pipe_fd[1] != STDIN_FILENO) + close(pipe_fd[1]); + + null_fd = open(_PATH_DEVNULL, O_WRONLY, 0); + if (dup2(null_fd, STDOUT_FILENO) == -1) + _exit(1); + if (dup2(null_fd, STDERR_FILENO) == -1) + _exit(1); + if (null_fd != STDOUT_FILENO && null_fd != STDERR_FILENO) + close(null_fd); + + execl(_PATH_BSHELL, "sh", "-c", data->arg, (char *) NULL); + _exit(1); + default: + /* Parent process. */ + close(pipe_fd[1]); + + wp->pipe_fd = pipe_fd[0]; + wp->pipe_buf = buffer_create(BUFSIZ); + wp->pipe_off = BUFFER_USED(wp->in); + + if ((mode = fcntl(wp->pipe_fd, F_GETFL)) == -1) + fatal("fcntl failed"); + if (fcntl(wp->pipe_fd, F_SETFL, mode|O_NONBLOCK) == -1) + fatal("fcntl failed"); + if (fcntl(wp->pipe_fd, F_SETFD, FD_CLOEXEC) == -1) + fatal("fcntl failed"); + return (0); + } + + return (0); +} diff --git a/cmd.c b/cmd.c index d453c726..0fb1ff57 100644 --- a/cmd.c +++ b/cmd.c @@ -71,6 +71,7 @@ const struct cmd_entry *cmd_table[] = { &cmd_next_layout_entry, &cmd_next_window_entry, &cmd_paste_buffer_entry, + &cmd_pipe_pane_entry, &cmd_previous_layout_entry, &cmd_previous_window_entry, &cmd_refresh_client_entry, diff --git a/server.c b/server.c index bf9aba94..18152b85 100644 --- a/server.c +++ b/server.c @@ -572,6 +572,13 @@ server_fill_windows(void) if (BUFFER_USED(wp->out) > 0) events |= POLLOUT; server_poll_add(wp->fd, events); + + if (wp->pipe_fd == -1) + continue; + events = 0; + if (BUFFER_USED(wp->pipe_buf) > 0) + events |= POLLOUT; + server_poll_add(wp->pipe_fd, events); } } } @@ -600,6 +607,16 @@ server_handle_windows(void) wp->fd = -1; } else server_handle_window(w, wp); + + if (wp->pipe_fd == -1) + continue; + if ((pfd = server_poll_lookup(wp->pipe_fd)) == NULL) + continue; + if (buffer_poll(pfd, NULL, wp->pipe_buf) != 0) { + buffer_destroy(wp->pipe_buf); + close(wp->pipe_fd); + wp->pipe_fd = -1; + } } server_check_window(w); diff --git a/tmux.1 b/tmux.1 index f4616ed4..40ca8f83 100644 --- a/tmux.1 +++ b/tmux.1 @@ -840,6 +840,30 @@ Move to the next window in the session. If .Fl a is used, move to the next window with a bell, activity or content alert. +.It Xo Ic pipe-pane +.Op Fl o +.Op Fl t Ar target-pane +.Op Ar command +.Xc +.D1 (alias: Ic pipep ) +Pipe any output sent by the program in +.Ar target-pane +to a shell command. +A pane may only be piped to one command at a time, any existing pipe is +closed before +.Ar command +is executed. +If no +.Ar command +is given, the current pipe (if any) is closed. +.Pp +The +.Fl o +option only opens a new pipe if no previous pipe exists, allowing a pipe to +be toggled with a single key, for example: +.Bd -literal -offset indent +bind-key C-p pipe-pane -o 'cat >>~/output' +.Ed .It Xo Ic previous-window .Op Fl a .Op Fl t Ar target-session diff --git a/tmux.h b/tmux.h index a975dca3..9525070b 100644 --- a/tmux.h +++ b/tmux.h @@ -715,6 +715,10 @@ struct window_pane { struct input_ctx ictx; + int pipe_fd; + struct buffer *pipe_buf; + size_t pipe_off; + struct screen *screen; struct screen base; @@ -1394,6 +1398,7 @@ extern const struct cmd_entry cmd_new_window_entry; extern const struct cmd_entry cmd_next_layout_entry; extern const struct cmd_entry cmd_next_window_entry; extern const struct cmd_entry cmd_paste_buffer_entry; +extern const struct cmd_entry cmd_pipe_pane_entry; extern const struct cmd_entry cmd_previous_layout_entry; extern const struct cmd_entry cmd_previous_window_entry; extern const struct cmd_entry cmd_refresh_client_entry; diff --git a/window.c b/window.c index 17a8f018..7472815e 100644 --- a/window.c +++ b/window.c @@ -425,6 +425,10 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit) wp->sx = sx; wp->sy = sy; + wp->pipe_fd = -1; + wp->pipe_buf = NULL; + wp->pipe_off = 0; + wp->saved_grid = NULL; screen_init(&wp->base, sx, sy, hlimit); @@ -448,6 +452,11 @@ window_pane_destroy(struct window_pane *wp) if (wp->saved_grid != NULL) grid_destroy(wp->saved_grid); + if (wp->pipe_fd != -1) { + buffer_destroy(wp->pipe_buf); + close(wp->pipe_fd); + } + buffer_destroy(wp->in); buffer_destroy(wp->out); @@ -621,7 +630,15 @@ window_pane_reset_mode(struct window_pane *wp) void window_pane_parse(struct window_pane *wp) { + size_t new_size; + + new_size = BUFFER_USED(wp->in) - wp->pipe_off; + if (wp->pipe_fd != -1 && new_size > 0) + buffer_write(wp->pipe_buf, BUFFER_OUT(wp->in), new_size); + input_parse(wp); + + wp->pipe_off = BUFFER_USED(wp->in); } void From fbb030d7f767513aa9b646c67cab4659599682d3 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 11 Oct 2009 10:39:27 +0000 Subject: [PATCH 0388/1180] Set the current window pointer to NULL when killing a winlink that is to be replaced with link-window -k. This prevents it being pushed onto the last window stack and causing a use-after-free. Only took me an hour to find this :-/... --- server-fn.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/server-fn.c b/server-fn.c index beaae07a..f4f71980 100644 --- a/server-fn.c +++ b/server-fn.c @@ -284,8 +284,10 @@ server_link_window(struct session *src, struct winlink *srcwl, winlink_remove(&dst->windows, dstwl); /* Force select/redraw if current. */ - if (dstwl == dst->curw) + if (dstwl == dst->curw) { selectflag = 1; + dst->curw = NULL; + } } } From b4ef3e507109c95ae89ed6b4c156e8f5f17358f9 Mon Sep 17 00:00:00 2001 From: Jason McIntyre Date: Sun, 11 Oct 2009 14:12:10 +0000 Subject: [PATCH 0389/1180] punctuation fix; --- tmux.1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tmux.1 b/tmux.1 index 40ca8f83..5954cc7c 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1324,8 +1324,8 @@ If this option is (the default), instead of each session locking individually as each has been idle for -.Ic lock-after-time -, the entire server will lock after +.Ic lock-after-time , +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. From 0a2a3544993a569e277f893ddac610313a42bfde Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 11 Oct 2009 22:35:10 +0000 Subject: [PATCH 0390/1180] Like linefeed, don't set the scroll region for reverse index unless it will be needed. While here, also tidy up a couple of long lines and remove an extraneous blank. --- tty.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/tty.c b/tty.c index 7b0454f7..389fe11f 100644 --- a/tty.c +++ b/tty.c @@ -462,8 +462,10 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int py, u_int ox, u_int oy) if (screen_check_selection(s, i, py)) { memcpy(&tmpgc, &s->sel.cell, sizeof tmpgc); tmpgc.data = gc->data; - tmpgc.flags = gc->flags & ~(GRID_FLAG_FG256|GRID_FLAG_BG256); - tmpgc.flags |= s->sel.cell.flags & (GRID_FLAG_FG256|GRID_FLAG_BG256); + tmpgc.flags = gc->flags & + ~(GRID_FLAG_FG256|GRID_FLAG_BG256); + tmpgc.flags |= s->sel.cell.flags & + (GRID_FLAG_FG256|GRID_FLAG_BG256); tty_cell(tty, &tmpgc, gu); } else tty_cell(tty, gc, gu); @@ -671,11 +673,9 @@ tty_cmd_reverseindex(struct tty *tty, const struct tty_ctx *ctx) return; } - tty_reset(tty); - - tty_region(tty, ctx->orupper, ctx->orlower, wp->yoff); - if (ctx->ocy == ctx->orupper) { + tty_reset(tty); + tty_region(tty, ctx->orupper, ctx->orlower, wp->yoff); tty_cursor(tty, ctx->ocx, ctx->orupper, wp->xoff, wp->yoff); tty_putcode(tty, TTYC_RI); } @@ -693,7 +693,6 @@ tty_cmd_linefeed(struct tty *tty, const struct tty_ctx *ctx) return; } - if (ctx->ocy == ctx->orlower) { tty_reset(tty); tty_region(tty, ctx->orupper, ctx->orlower, wp->yoff); From f05b32f7adc7de4dac3afa59ce91986202f17769 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 12 Oct 2009 09:09:35 +0000 Subject: [PATCH 0391/1180] Cleanup: use two functions for region setting, one for absolute and one inside pane. --- server.c | 3 ++- tmux.h | 3 ++- tty.c | 51 +++++++++++++++++++++++++++++++++++---------------- 3 files changed, 39 insertions(+), 18 deletions(-) diff --git a/server.c b/server.c index 18152b85..fab8d886 100644 --- a/server.c +++ b/server.c @@ -1050,8 +1050,9 @@ server_handle_client(struct client *c) * tty_region/tty_reset/tty_update_mode already take care of not * resetting things that are already in their default state. */ + tty_region_absolute(&c->tty, 0, c->tty.sy - 1); + status = options_get_number(oo, "status"); - tty_region(&c->tty, 0, c->tty.sy - 1, 0); if (!window_pane_visible(wp) || wp->yoff + s->cy >= c->tty.sy - status) tty_cursor(&c->tty, 0, 0, 0, 0); else diff --git a/tmux.h b/tmux.h index 9525070b..179c030a 100644 --- a/tmux.h +++ b/tmux.h @@ -1247,7 +1247,8 @@ void tty_raw(struct tty *, const char *); u_char tty_get_acs(struct tty *, u_char); void tty_attributes(struct tty *, const struct grid_cell *); void tty_reset(struct tty *); -void tty_region(struct tty *, u_int, u_int, u_int); +void tty_region_pane(struct tty *, const struct tty_ctx *, u_int, u_int); +void tty_region_absolute(struct tty *, u_int, u_int); void tty_cursor(struct tty *, u_int, u_int, u_int, u_int); void tty_putcode(struct tty *, enum tty_code_code); void tty_putcode1(struct tty *, enum tty_code_code, int); diff --git a/tty.c b/tty.c index 389fe11f..fd271335 100644 --- a/tty.c +++ b/tty.c @@ -579,7 +579,7 @@ tty_cmd_insertline(struct tty *tty, const struct tty_ctx *ctx) tty_reset(tty); - tty_region(tty, ctx->orupper, ctx->orlower, wp->yoff); + tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower); tty_cursor(tty, ctx->ocx, ctx->ocy, wp->xoff, wp->yoff); tty_emulate_repeat(tty, TTYC_IL, TTYC_IL1, ctx->num); @@ -599,7 +599,7 @@ tty_cmd_deleteline(struct tty *tty, const struct tty_ctx *ctx) tty_reset(tty); - tty_region(tty, ctx->orupper, ctx->orlower, wp->yoff); + tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower); tty_cursor(tty, ctx->ocx, ctx->ocy, wp->xoff, wp->yoff); tty_emulate_repeat(tty, TTYC_DL, TTYC_DL1, ctx->num); @@ -675,8 +675,10 @@ tty_cmd_reverseindex(struct tty *tty, const struct tty_ctx *ctx) if (ctx->ocy == ctx->orupper) { tty_reset(tty); - tty_region(tty, ctx->orupper, ctx->orlower, wp->yoff); + + tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower); tty_cursor(tty, ctx->ocx, ctx->orupper, wp->xoff, wp->yoff); + tty_putcode(tty, TTYC_RI); } } @@ -695,8 +697,10 @@ tty_cmd_linefeed(struct tty *tty, const struct tty_ctx *ctx) if (ctx->ocy == ctx->orlower) { tty_reset(tty); - tty_region(tty, ctx->orupper, ctx->orlower, wp->yoff); + + tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower); tty_cursor(tty, ctx->ocx, ctx->ocy, wp->xoff, wp->yoff); + tty_putc(tty, '\n'); } } @@ -710,8 +714,9 @@ tty_cmd_clearendofscreen(struct tty *tty, const struct tty_ctx *ctx) tty_reset(tty); - tty_region(tty, 0, screen_size_y(s) - 1, wp->yoff); + tty_region_pane(tty, ctx, 0, screen_size_y(s) - 1); tty_cursor(tty, ctx->ocx, ctx->ocy, wp->xoff, wp->yoff); + if (wp->xoff == 0 && screen_size_x(s) >= tty->sx && tty_term_has(tty->term, TTYC_EL)) { tty_putcode(tty, TTYC_EL); @@ -745,8 +750,9 @@ tty_cmd_clearstartofscreen(struct tty *tty, const struct tty_ctx *ctx) tty_reset(tty); - tty_region(tty, 0, screen_size_y(s) - 1, wp->yoff); + tty_region_pane(tty, ctx, 0, screen_size_y(s) - 1); tty_cursor(tty, 0, 0, wp->xoff, wp->yoff); + if (wp->xoff == 0 && screen_size_x(s) >= tty->sx && tty_term_has(tty->term, TTYC_EL)) { for (i = 0; i < ctx->ocy; i++) { @@ -774,8 +780,9 @@ tty_cmd_clearscreen(struct tty *tty, const struct tty_ctx *ctx) tty_reset(tty); - tty_region(tty, 0, screen_size_y(s) - 1, wp->yoff); + tty_region_pane(tty, ctx, 0, screen_size_y(s) - 1); tty_cursor(tty, 0, 0, wp->xoff, wp->yoff); + if (wp->xoff == 0 && screen_size_x(s) >= tty->sx && tty_term_has(tty->term, TTYC_EL)) { for (i = 0; i < screen_size_y(s); i++) { @@ -803,7 +810,7 @@ tty_cmd_alignmenttest(struct tty *tty, const struct tty_ctx *ctx) tty_reset(tty); - tty_region(tty, 0, screen_size_y(s) - 1, wp->yoff); + tty_region_pane(tty, ctx, 0, screen_size_y(s) - 1); for (j = 0; j < screen_size_y(s); j++) { tty_cursor(tty, 0, j, wp->xoff, wp->yoff); @@ -887,17 +894,29 @@ tty_reset(struct tty *tty) } void -tty_region(struct tty *tty, u_int rupper, u_int rlower, u_int oy) +tty_region_pane( + struct tty *tty, const struct tty_ctx *ctx, u_int rupper, u_int rlower) { + struct window_pane *wp = ctx->wp; + + tty_region_absolute(tty, wp->yoff + rupper, wp->yoff + rlower); +} + +void +tty_region_absolute(struct tty *tty, u_int rupper, u_int rlower) +{ + if (tty->rlower == rlower && tty->rupper == rupper) + return; if (!tty_term_has(tty->term, TTYC_CSR)) return; - if (tty->rlower != oy + rlower || tty->rupper != oy + rupper) { - tty->rlower = oy + rlower; - tty->rupper = oy + rupper; - tty->cx = 0; - tty->cy = 0; - tty_putcode2(tty, TTYC_CSR, tty->rupper, tty->rlower); - } + + tty->rupper = rupper; + tty->rlower = rlower; + + tty->cx = 0; + tty->cy = 0; + + tty_putcode2(tty, TTYC_CSR, tty->rupper, tty->rlower); } void From 972a6f565660a7ca5c0307c1085825a254fba20e Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 12 Oct 2009 09:16:59 +0000 Subject: [PATCH 0392/1180] _absolute is redundant, just use tty_region. --- server.c | 2 +- tmux.h | 2 +- tty.c | 6 ++++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/server.c b/server.c index fab8d886..6360be1d 100644 --- a/server.c +++ b/server.c @@ -1050,7 +1050,7 @@ server_handle_client(struct client *c) * tty_region/tty_reset/tty_update_mode already take care of not * resetting things that are already in their default state. */ - tty_region_absolute(&c->tty, 0, c->tty.sy - 1); + tty_region(&c->tty, 0, c->tty.sy - 1); status = options_get_number(oo, "status"); if (!window_pane_visible(wp) || wp->yoff + s->cy >= c->tty.sy - status) diff --git a/tmux.h b/tmux.h index 179c030a..0b1ba198 100644 --- a/tmux.h +++ b/tmux.h @@ -1248,7 +1248,7 @@ u_char tty_get_acs(struct tty *, u_char); void tty_attributes(struct tty *, const struct grid_cell *); void tty_reset(struct tty *); void tty_region_pane(struct tty *, const struct tty_ctx *, u_int, u_int); -void tty_region_absolute(struct tty *, u_int, u_int); +void tty_region(struct tty *, u_int, u_int); void tty_cursor(struct tty *, u_int, u_int, u_int, u_int); void tty_putcode(struct tty *, enum tty_code_code); void tty_putcode1(struct tty *, enum tty_code_code, int); diff --git a/tty.c b/tty.c index fd271335..bddb83e3 100644 --- a/tty.c +++ b/tty.c @@ -893,17 +893,19 @@ tty_reset(struct tty *tty) memcpy(gc, &grid_default_cell, sizeof *gc); } +/* Set region inside pane. */ void tty_region_pane( struct tty *tty, const struct tty_ctx *ctx, u_int rupper, u_int rlower) { struct window_pane *wp = ctx->wp; - tty_region_absolute(tty, wp->yoff + rupper, wp->yoff + rlower); + tty_region(tty, wp->yoff + rupper, wp->yoff + rlower); } +/* Set region at absolute position. */ void -tty_region_absolute(struct tty *tty, u_int rupper, u_int rlower) +tty_region(struct tty *tty, u_int rupper, u_int rlower) { if (tty->rlower == rlower && tty->rupper == rupper) return; From 762459954f1b8f00f93780212053288d6096a611 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 12 Oct 2009 09:29:58 +0000 Subject: [PATCH 0393/1180] Similarly add a tty_cursor_pane function to tidy up most of the calls. --- screen-redraw.c | 13 +++++----- server.c | 4 +-- tmux.h | 3 ++- tty.c | 66 ++++++++++++++++++++++++++++--------------------- 4 files changed, 49 insertions(+), 37 deletions(-) diff --git a/screen-redraw.c b/screen-redraw.c index d22591f0..0e612461 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -195,7 +195,7 @@ screen_redraw_screen(struct client *c, int status_only) for (i = 0; i < tty->sx; i++) { type = screen_redraw_check_cell(c, i, j); if (type != CELL_INSIDE) { - tty_cursor(tty, i, j, 0, 0); + tty_cursor(tty, i, j); tty_putc(tty, border[type]); } } @@ -239,7 +239,7 @@ screen_redraw_draw_number(struct client *c, struct window_pane *wp) struct tty *tty = &c->tty; struct session *s = c->session; struct grid_cell gc; - u_int idx, px, py, i, j; + u_int idx, px, py, i, j, xoff, yoff; int colour; char buf[16], *ptr; size_t len; @@ -251,10 +251,11 @@ screen_redraw_draw_number(struct client *c, struct window_pane *wp) return; colour = options_get_number(&s->options, "display-panes-colour"); - px = wp->sx / 2; - py = wp->sy / 2; + px = wp->sx / 2; py = wp->sy / 2; + xoff = wp->xoff; yoff = wp->yoff; + if (wp->sx < len * 6 || wp->sy < 5) { - tty_cursor(tty, px - len / 2, py, wp->xoff, wp->yoff); + tty_cursor(tty, xoff + px - len / 2, yoff + py); memcpy(&gc, &grid_default_cell, sizeof gc); colour_set_fg(&gc, colour); tty_attributes(tty, &gc); @@ -275,7 +276,7 @@ screen_redraw_draw_number(struct client *c, struct window_pane *wp) for (j = 0; j < 5; j++) { for (i = px; i < px + 5; i++) { - tty_cursor(tty, i, py + j, wp->xoff, wp->yoff); + tty_cursor(tty, xoff + i, yoff + py + j); if (clock_table[idx][j][i - px]) tty_putc(tty, ' '); } diff --git a/server.c b/server.c index 6360be1d..2906fb87 100644 --- a/server.c +++ b/server.c @@ -1054,9 +1054,9 @@ server_handle_client(struct client *c) status = options_get_number(oo, "status"); if (!window_pane_visible(wp) || wp->yoff + s->cy >= c->tty.sy - status) - tty_cursor(&c->tty, 0, 0, 0, 0); + tty_cursor(&c->tty, 0, 0); else - tty_cursor(&c->tty, s->cx, s->cy, wp->xoff, wp->yoff); + tty_cursor(&c->tty, wp->xoff + s->cx, wp->yoff + s->cy); mode = s->mode; if (TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry) != NULL && diff --git a/tmux.h b/tmux.h index 0b1ba198..93e178e1 100644 --- a/tmux.h +++ b/tmux.h @@ -1249,7 +1249,8 @@ void tty_attributes(struct tty *, const struct grid_cell *); void tty_reset(struct tty *); void tty_region_pane(struct tty *, const struct tty_ctx *, u_int, u_int); void tty_region(struct tty *, u_int, u_int); -void tty_cursor(struct tty *, u_int, u_int, u_int, u_int); +void tty_cursor_pane(struct tty *, const struct tty_ctx *, u_int, u_int); +void tty_cursor(struct tty *, u_int, u_int); void tty_putcode(struct tty *, enum tty_code_code); void tty_putcode1(struct tty *, enum tty_code_code, int); void tty_putcode2(struct tty *, enum tty_code_code, int, int); diff --git a/tty.c b/tty.c index bddb83e3..f7ef8c0d 100644 --- a/tty.c +++ b/tty.c @@ -451,7 +451,7 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int py, u_int ox, u_int oy) if (sx > tty->sx) sx = tty->sx; - tty_cursor(tty, 0, py, ox, oy); + tty_cursor(tty, ox, oy + py); for (i = 0; i < sx; i++) { gc = grid_view_peek_cell(s->grid, i, py); @@ -477,7 +477,7 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int py, u_int ox, u_int oy) } tty_reset(tty); - tty_cursor(tty, sx, py, ox, oy); + tty_cursor(tty, ox + sx, oy + py); if (screen_size_x(s) >= tty->sx && tty_term_has(tty->term, TTYC_EL)) tty_putcode(tty, TTYC_EL); else { @@ -532,7 +532,8 @@ tty_cmd_insertcharacter(struct tty *tty, const struct tty_ctx *ctx) tty_reset(tty); - tty_cursor(tty, ctx->ocx, ctx->ocy, wp->xoff, wp->yoff); + tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); + if (tty_term_has(tty->term, TTYC_ICH) || tty_term_has(tty->term, TTYC_ICH1)) tty_emulate_repeat(tty, TTYC_ICH, TTYC_ICH1, ctx->num); @@ -559,7 +560,8 @@ tty_cmd_deletecharacter(struct tty *tty, const struct tty_ctx *ctx) tty_reset(tty); - tty_cursor(tty, ctx->ocx, ctx->ocy, wp->xoff, wp->yoff); + tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); + if (tty_term_has(tty->term, TTYC_DCH) || tty_term_has(tty->term, TTYC_DCH1)) tty_emulate_repeat(tty, TTYC_DCH, TTYC_DCH1, ctx->num); @@ -580,8 +582,8 @@ tty_cmd_insertline(struct tty *tty, const struct tty_ctx *ctx) tty_reset(tty); tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower); + tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); - tty_cursor(tty, ctx->ocx, ctx->ocy, wp->xoff, wp->yoff); tty_emulate_repeat(tty, TTYC_IL, TTYC_IL1, ctx->num); } @@ -600,8 +602,8 @@ tty_cmd_deleteline(struct tty *tty, const struct tty_ctx *ctx) tty_reset(tty); tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower); + tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); - tty_cursor(tty, ctx->ocx, ctx->ocy, wp->xoff, wp->yoff); tty_emulate_repeat(tty, TTYC_DL, TTYC_DL1, ctx->num); } @@ -614,7 +616,8 @@ tty_cmd_clearline(struct tty *tty, const struct tty_ctx *ctx) tty_reset(tty); - tty_cursor(tty, 0, ctx->ocy, wp->xoff, wp->yoff); + tty_cursor_pane(tty, ctx, 0, ctx->ocy); + if (wp->xoff == 0 && screen_size_x(s) >= tty->sx && tty_term_has(tty->term, TTYC_EL)) { tty_putcode(tty, TTYC_EL); @@ -633,7 +636,8 @@ tty_cmd_clearendofline(struct tty *tty, const struct tty_ctx *ctx) tty_reset(tty); - tty_cursor(tty, ctx->ocx, ctx->ocy, wp->xoff, wp->yoff); + tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); + if (wp->xoff == 0 && screen_size_x(s) >= tty->sx && tty_term_has(tty->term, TTYC_EL)) tty_putcode(tty, TTYC_EL); @@ -652,10 +656,10 @@ tty_cmd_clearstartofline(struct tty *tty, const struct tty_ctx *ctx) tty_reset(tty); if (wp->xoff == 0 && tty_term_has(tty->term, TTYC_EL1)) { - tty_cursor(tty, ctx->ocx, ctx->ocy, wp->xoff, wp->yoff); + tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); tty_putcode(tty, TTYC_EL1); } else { - tty_cursor(tty, 0, ctx->ocy, wp->xoff, wp->yoff); + tty_cursor_pane(tty, ctx, 0, ctx->ocy); for (i = 0; i < ctx->ocx + 1; i++) tty_putc(tty, ' '); } @@ -677,7 +681,7 @@ tty_cmd_reverseindex(struct tty *tty, const struct tty_ctx *ctx) tty_reset(tty); tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower); - tty_cursor(tty, ctx->ocx, ctx->orupper, wp->xoff, wp->yoff); + tty_cursor_pane(tty, ctx, ctx->ocx, ctx->orupper); tty_putcode(tty, TTYC_RI); } @@ -699,7 +703,7 @@ tty_cmd_linefeed(struct tty *tty, const struct tty_ctx *ctx) tty_reset(tty); tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower); - tty_cursor(tty, ctx->ocx, ctx->ocy, wp->xoff, wp->yoff); + tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); tty_putc(tty, '\n'); } @@ -715,13 +719,13 @@ tty_cmd_clearendofscreen(struct tty *tty, const struct tty_ctx *ctx) tty_reset(tty); tty_region_pane(tty, ctx, 0, screen_size_y(s) - 1); - tty_cursor(tty, ctx->ocx, ctx->ocy, wp->xoff, wp->yoff); + tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); if (wp->xoff == 0 && screen_size_x(s) >= tty->sx && tty_term_has(tty->term, TTYC_EL)) { tty_putcode(tty, TTYC_EL); if (ctx->ocy != screen_size_y(s) - 1) { - tty_cursor(tty, 0, ctx->ocy + 1, wp->xoff, wp->yoff); + tty_cursor_pane(tty, ctx, 0, ctx->ocy + 1); for (i = ctx->ocy + 1; i < screen_size_y(s); i++) { tty_putcode(tty, TTYC_EL); if (i == screen_size_y(s) - 1) @@ -734,7 +738,7 @@ tty_cmd_clearendofscreen(struct tty *tty, const struct tty_ctx *ctx) for (i = ctx->ocx; i < screen_size_x(s); i++) tty_putc(tty, ' '); for (j = ctx->ocy; j < screen_size_y(s); j++) { - tty_cursor(tty, 0, j, wp->xoff, wp->yoff); + tty_cursor_pane(tty, ctx, 0, j); for (i = 0; i < screen_size_x(s); i++) tty_putc(tty, ' '); } @@ -751,7 +755,7 @@ tty_cmd_clearstartofscreen(struct tty *tty, const struct tty_ctx *ctx) tty_reset(tty); tty_region_pane(tty, ctx, 0, screen_size_y(s) - 1); - tty_cursor(tty, 0, 0, wp->xoff, wp->yoff); + tty_cursor_pane(tty, ctx, 0, 0); if (wp->xoff == 0 && screen_size_x(s) >= tty->sx && tty_term_has(tty->term, TTYC_EL)) { @@ -762,7 +766,7 @@ tty_cmd_clearstartofscreen(struct tty *tty, const struct tty_ctx *ctx) } } else { for (j = 0; j < ctx->ocy; j++) { - tty_cursor(tty, 0, j, wp->xoff, wp->yoff); + tty_cursor_pane(tty, ctx, 0, j); for (i = 0; i < screen_size_x(s); i++) tty_putc(tty, ' '); } @@ -781,7 +785,7 @@ tty_cmd_clearscreen(struct tty *tty, const struct tty_ctx *ctx) tty_reset(tty); tty_region_pane(tty, ctx, 0, screen_size_y(s) - 1); - tty_cursor(tty, 0, 0, wp->xoff, wp->yoff); + tty_cursor_pane(tty, ctx, 0, 0); if (wp->xoff == 0 && screen_size_x(s) >= tty->sx && tty_term_has(tty->term, TTYC_EL)) { @@ -794,7 +798,7 @@ tty_cmd_clearscreen(struct tty *tty, const struct tty_ctx *ctx) } } else { for (j = 0; j < screen_size_y(s); j++) { - tty_cursor(tty, 0, j, wp->xoff, wp->yoff); + tty_cursor_pane(tty, ctx, 0, j); for (i = 0; i < screen_size_x(s); i++) tty_putc(tty, ' '); } @@ -813,7 +817,7 @@ tty_cmd_alignmenttest(struct tty *tty, const struct tty_ctx *ctx) tty_region_pane(tty, ctx, 0, screen_size_y(s) - 1); for (j = 0; j < screen_size_y(s); j++) { - tty_cursor(tty, 0, j, wp->xoff, wp->yoff); + tty_cursor_pane(tty, ctx, 0, j); for (i = 0; i < screen_size_x(s); i++) tty_putc(tty, 'E'); } @@ -822,9 +826,7 @@ tty_cmd_alignmenttest(struct tty *tty, const struct tty_ctx *ctx) void tty_cmd_cell(struct tty *tty, const struct tty_ctx *ctx) { - struct window_pane *wp = ctx->wp; - - tty_cursor(tty, ctx->ocx, ctx->ocy, wp->xoff, wp->yoff); + tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); tty_cell(tty, ctx->cell, ctx->utf8); } @@ -922,14 +924,22 @@ tty_region(struct tty *tty, u_int rupper, u_int rlower) } void -tty_cursor(struct tty *tty, u_int cx, u_int cy, u_int ox, u_int oy) +tty_cursor_pane(struct tty *tty, const struct tty_ctx *ctx, u_int cx, u_int cy) { - if (ox + cx == 0 && tty->cx != 0 && tty->cy == oy + cy) { + struct window_pane *wp = ctx->wp; + + tty_cursor(tty, wp->xoff + cx, wp->yoff + cy); +} + +void +tty_cursor(struct tty *tty, u_int cx, u_int cy) +{ + if (cx == 0 && tty->cx != 0 && tty->cy == cy) { tty->cx = 0; tty_putc(tty, '\r'); - } else if (tty->cx != ox + cx || tty->cy != oy + cy) { - tty->cx = ox + cx; - tty->cy = oy + cy; + } else if (tty->cx != cx || tty->cy != cy) { + tty->cx = cx; + tty->cy = cy; tty_putcode2(tty, TTYC_CUP, tty->cy, tty->cx); } } From 33ae063cae422dc97633ac43a4f8ded43da5c143 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 12 Oct 2009 11:08:02 +0000 Subject: [PATCH 0394/1180] Permit attributes to be turned off in #[] by prefixing with "no", for example "noblink". --- screen-write.c | 4 ++++ tmux.1 | 12 ++++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/screen-write.c b/screen-write.c index 507c527b..a0c28575 100644 --- a/screen-write.c +++ b/screen-write.c @@ -347,6 +347,10 @@ screen_write_parsestyle( bg = defgc->bg; } 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; diff --git a/tmux.1 b/tmux.1 index 5954cc7c..fc1801f2 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1470,22 +1470,26 @@ the .Ic status-interval option: if the status line is redrawn in the meantime, the previous result is used. +.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, or one of the attributes described under the +to set the background colour, the name of one of the attributes (listed under the .Ic message-attr -option. +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) #[fg=yellow,bold]#(apm -l)%%#[default] [#S] .Ed .Pp -Where appropriate, these may be prefixed with a number to specify the maximum -length, for example +Where appropriate, special character sequences may be prefixed with a number to +specify the maximum length, for example .Ql #24T . .Pp By default, UTF-8 in From 687c4a9fabbd1f6a2b7c8ae9050f087c13565f1b Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 12 Oct 2009 13:01:18 +0000 Subject: [PATCH 0395/1180] Use relative cursor movement instead of absolute when possible and when supported by the terminal to reduce the size of the output data (generally about 10-20%). --- tmux.h | 11 ++++- tty-term.c | 11 ++++- tty.c | 123 +++++++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 135 insertions(+), 10 deletions(-) diff --git a/tmux.h b/tmux.h index 93e178e1..02f9bbd0 100644 --- a/tmux.h +++ b/tmux.h @@ -195,9 +195,15 @@ enum tty_code_code { TTYC_CNORM, /* cursor_normal, ve */ TTYC_COLORS, /* max_colors, Co */ TTYC_CSR, /* change_scroll_region, cs */ + TTYC_CUB, /* parm_left_cursor, LE */ + TTYC_CUB1, /* cursor_left, le */ TTYC_CUD, /* parm_down_cursor, DO */ TTYC_CUD1, /* cursor_down, do */ + TTYC_CUF, /* parm_right_cursor, RI */ + TTYC_CUF1, /* cursor_right, nd */ TTYC_CUP, /* cursor_address, cm */ + TTYC_CUU, /* parm_up_cursor, UP */ + TTYC_CUU1, /* cursor_up, up */ TTYC_DCH, /* parm_dch, DC */ TTYC_DCH1, /* delete_character, dc */ TTYC_DIM, /* enter_dim_mode, mh */ @@ -206,6 +212,8 @@ enum tty_code_code { TTYC_EL, /* clr_eol, ce */ TTYC_EL1, /* clr_bol, cb */ TTYC_ENACS, /* ena_acs, eA */ + TTYC_HOME, /* cursor_home, ho */ + TTYC_HPA, /* column_address, ch */ TTYC_ICH, /* parm_ich, IC */ TTYC_ICH1, /* insert_character, ic */ TTYC_IL, /* parm_insert_line, IL */ @@ -232,8 +240,8 @@ enum tty_code_code { TTYC_KF17, /* key_f17, F7 */ TTYC_KF18, /* key_f18, F8 */ TTYC_KF19, /* key_f19, F9 */ - TTYC_KF20, /* key_f20, F10 */ TTYC_KF2, /* key_f2, k2 */ + TTYC_KF20, /* key_f20, F10 */ TTYC_KF3, /* key_f3, k3 */ TTYC_KF4, /* key_f4, k4 */ TTYC_KF5, /* key_f5, k5 */ @@ -262,6 +270,7 @@ enum tty_code_code { TTYC_SMKX, /* keypad_xmit, ks */ TTYC_SMSO, /* enter_standout_mode, so */ TTYC_SMUL, /* enter_underline_mode, us */ + TTYC_VPA, /* row_address, cv */ TTYC_XENL, /* eat_newline_glitch, xn */ }; #define NTTYCODE (TTYC_XENL + 1) diff --git a/tty-term.c b/tty-term.c index dd3e8e00..02dece6e 100644 --- a/tty-term.c +++ b/tty-term.c @@ -43,9 +43,15 @@ struct tty_term_code_entry tty_term_codes[NTTYCODE] = { { TTYC_CNORM, TTYCODE_STRING, "cnorm" }, { TTYC_COLORS, TTYCODE_NUMBER, "colors" }, { TTYC_CSR, TTYCODE_STRING, "csr" }, + { TTYC_CUB, TTYCODE_STRING, "cub" }, + { TTYC_CUB1, TTYCODE_STRING, "cub1" }, { TTYC_CUD, TTYCODE_STRING, "cud" }, { TTYC_CUD1, TTYCODE_STRING, "cud1" }, + { TTYC_CUF, TTYCODE_STRING, "cuf" }, + { TTYC_CUF1, TTYCODE_STRING, "cuf1" }, { TTYC_CUP, TTYCODE_STRING, "cup" }, + { TTYC_CUU, TTYCODE_STRING, "cuu" }, + { TTYC_CUU1, TTYCODE_STRING, "cuu1" }, { TTYC_DCH, TTYCODE_STRING, "dch" }, { TTYC_DCH1, TTYCODE_STRING, "dch1" }, { TTYC_DIM, TTYCODE_STRING, "dim" }, @@ -54,6 +60,8 @@ struct tty_term_code_entry tty_term_codes[NTTYCODE] = { { TTYC_EL, TTYCODE_STRING, "el" }, { TTYC_EL1, TTYCODE_STRING, "el1" }, { TTYC_ENACS, TTYCODE_STRING, "enacs" }, + { TTYC_HOME, TTYCODE_STRING, "home" }, + { TTYC_HPA, TTYCODE_STRING, "hpa" }, { TTYC_ICH, TTYCODE_STRING, "ich" }, { TTYC_ICH1, TTYCODE_STRING, "ich1" }, { TTYC_IL, TTYCODE_STRING, "il" }, @@ -80,8 +88,8 @@ struct tty_term_code_entry tty_term_codes[NTTYCODE] = { { TTYC_KF17, TTYCODE_STRING, "kf17" }, { TTYC_KF18, TTYCODE_STRING, "kf18" }, { TTYC_KF19, TTYCODE_STRING, "kf19" }, - { TTYC_KF20, TTYCODE_STRING, "kf20" }, { TTYC_KF2, TTYCODE_STRING, "kf2" }, + { TTYC_KF20, TTYCODE_STRING, "kf20" }, { TTYC_KF3, TTYCODE_STRING, "kf3" }, { TTYC_KF4, TTYCODE_STRING, "kf4" }, { TTYC_KF5, TTYCODE_STRING, "kf5" }, @@ -110,6 +118,7 @@ struct tty_term_code_entry tty_term_codes[NTTYCODE] = { { TTYC_SMKX, TTYCODE_STRING, "smkx" }, { TTYC_SMSO, TTYCODE_STRING, "smso" }, { TTYC_SMUL, TTYCODE_STRING, "smul" }, + { TTYC_VPA, TTYCODE_STRING, "vpa" }, { TTYC_XENL, TTYCODE_FLAG, "xenl" }, }; diff --git a/tty.c b/tty.c index f7ef8c0d..4172e38c 100644 --- a/tty.c +++ b/tty.c @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -916,13 +917,14 @@ tty_region(struct tty *tty, u_int rupper, u_int rlower) tty->rupper = rupper; tty->rlower = rlower; - + tty->cx = 0; tty->cy = 0; tty_putcode2(tty, TTYC_CSR, tty->rupper, tty->rlower); } +/* Move cursor inside pane. */ void tty_cursor_pane(struct tty *tty, const struct tty_ctx *ctx, u_int cx, u_int cy) { @@ -931,17 +933,122 @@ tty_cursor_pane(struct tty *tty, const struct tty_ctx *ctx, u_int cx, u_int cy) tty_cursor(tty, wp->xoff + cx, wp->yoff + cy); } +/* Move cursor to absolute position. */ void tty_cursor(struct tty *tty, u_int cx, u_int cy) { - if (cx == 0 && tty->cx != 0 && tty->cy == cy) { - tty->cx = 0; - tty_putc(tty, '\r'); - } else if (tty->cx != cx || tty->cy != cy) { - tty->cx = cx; - tty->cy = cy; - tty_putcode2(tty, TTYC_CUP, tty->cy, tty->cx); + struct tty_term *term = tty->term; + u_int thisx, thisy; + int change; + + if (cx > tty->sx - 1) + cx = tty->sx - 1; + + thisx = tty->cx; + if (thisx > tty->sx - 1) + thisx = tty->sx - 1; + thisy = tty->cy; + + /* No change. */ + if (cx == thisx && cy == thisy) + return; + + /* Move to home position (0, 0). */ + if (cx == 0 && cy == 0 && tty_term_has(term, TTYC_HOME)) { + tty_putcode(tty, TTYC_HOME); + goto out; } + + /* Zero on the next line. */ + if (cx == 0 && cy == thisy + 1) { + tty_putc(tty, '\r'); + tty_putc(tty, '\n'); + goto out; + } + + /* Row staying the same. */ + if (cy == thisy) { + /* To left edge. */ + if (cx == 0) { + tty_putc(tty, '\r'); + goto out; + } + + /* One to the left. */ + if (cx == thisx - 1 && tty_term_has(term, TTYC_CUB1)) { + tty_putcode(tty, TTYC_CUB1); + goto out; + } + + /* One to the right. */ + if (cx == thisx + 1 && tty_term_has(term, TTYC_CUF1)) { + tty_putcode(tty, TTYC_CUF1); + goto out; + } + + /* Calculate difference. */ + change = thisx - cx; /* +ve left, -ve right */ + + /* + * Use HPA if change is larger than absolute, otherwise move + * the cursor with CUB/CUF. + */ + if (abs(change) > cx && tty_term_has(term, TTYC_HPA)) { + tty_putcode1(tty, TTYC_HPA, cx); + goto out; + } else if (change > 0 && tty_term_has(term, TTYC_CUB)) { + tty_putcode1(tty, TTYC_CUB, change); + goto out; + } else if (change < 0 && tty_term_has(term, TTYC_CUF)) { + tty_putcode1(tty, TTYC_CUF, -change); + goto out; + } + } + + /* Column staying the same. */ + if (cx == thisx ) { + /* One above. */ + if (cy != tty->rupper && + cy == thisy - 1 && tty_term_has(term, TTYC_CUU1)) { + tty_putcode(tty, TTYC_CUU1); + goto out; + } + + /* One below. */ + if (cy != tty->rlower && + cy == thisy + 1 && tty_term_has(term, TTYC_CUD1)) { + tty_putcode(tty, TTYC_CUD1); + goto out; + } + + /* Calculate difference. */ + change = thisy - cy; /* +ve up, -ve down */ + + /* + * Use VPA if change is larger than absolute or if this change + * would cross the scroll region, otherwise use CUU/CUD. + */ + if ((abs(change) > cy || + (change < 0 && cy - change > tty->rlower) || + (change > 0 && cy - change < tty->rupper)) && + tty_term_has(term, TTYC_VPA)) { + tty_putcode1(tty, TTYC_VPA, cy); + goto out; + } else if (change > 0 && tty_term_has(term, TTYC_CUU)) { + tty_putcode1(tty, TTYC_CUU, change); + goto out; + } else if (change < 0 && tty_term_has(term, TTYC_CUD)) { + tty_putcode1(tty, TTYC_CUD, -change); + goto out; + } + } + + /* Absolute movement. */ + tty_putcode2(tty, TTYC_CUP, cy, cx); + +out: + tty->cx = cx; + tty->cy = cy; } void From 0aab5811ca1d249b5c087241f77fbe21a6a1d31d Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 12 Oct 2009 14:54:19 +0000 Subject: [PATCH 0396/1180] Use absolute movement if right at the end of the line as it isn't a reliable place to move from relatively. --- tty.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tty.c b/tty.c index 4172e38c..665d0871 100644 --- a/tty.c +++ b/tty.c @@ -945,14 +945,16 @@ tty_cursor(struct tty *tty, u_int cx, u_int cy) cx = tty->sx - 1; thisx = tty->cx; - if (thisx > tty->sx - 1) - thisx = tty->sx - 1; thisy = tty->cy; /* No change. */ if (cx == thisx && cy == thisy) return; + /* Very end of the line, just use absolute movement. */ + if (thisx > tty->sx - 1) + goto absolute; + /* Move to home position (0, 0). */ if (cx == 0 && cy == 0 && tty_term_has(term, TTYC_HOME)) { tty_putcode(tty, TTYC_HOME); @@ -1043,6 +1045,7 @@ tty_cursor(struct tty *tty, u_int cx, u_int cy) } } +absolute: /* Absolute movement. */ tty_putcode2(tty, TTYC_CUP, cy, cx); From 56157444dea9539552c2d2f003ee0cc81a1422fc Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 12 Oct 2009 16:33:39 +0000 Subject: [PATCH 0397/1180] Wrap a couple of long lines. --- screen-write.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/screen-write.c b/screen-write.c index a0c28575..6b6aa400 100644 --- a/screen-write.c +++ b/screen-write.c @@ -1035,8 +1035,10 @@ screen_write_cell( if (screen_check_selection(s, s->cx - width, s->cy)) { memcpy(&tmp_gc2, &s->sel.cell, sizeof tmp_gc2); tmp_gc2.data = gc->data; - tmp_gc2.flags = gc->flags & ~(GRID_FLAG_FG256|GRID_FLAG_BG256); - tmp_gc2.flags |= s->sel.cell.flags & (GRID_FLAG_FG256|GRID_FLAG_BG256); + tmp_gc2.flags = gc->flags & + ~(GRID_FLAG_FG256|GRID_FLAG_BG256); + tmp_gc2.flags |= s->sel.cell.flags & + (GRID_FLAG_FG256|GRID_FLAG_BG256); ttyctx.cell = &tmp_gc2; tty_write(tty_cmd_cell, &ttyctx); } else { From eb9826f65d5584bc791cb35eb91ab6a5894b888c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 12 Oct 2009 16:37:43 +0000 Subject: [PATCH 0398/1180] If the vertical cursor movement crosses the scroll region, CUU and CUD shouldn't be used even if VPA isn't present - in that case CUP should be used. --- tty.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/tty.c b/tty.c index 665d0871..29c84832 100644 --- a/tty.c +++ b/tty.c @@ -1027,15 +1027,16 @@ tty_cursor(struct tty *tty, u_int cx, u_int cy) change = thisy - cy; /* +ve up, -ve down */ /* - * Use VPA if change is larger than absolute or if this change + * Try to use VPA if change is larger than absolute or if this change * would cross the scroll region, otherwise use CUU/CUD. */ - if ((abs(change) > cy || + if (abs(change) > cy || (change < 0 && cy - change > tty->rlower) || - (change > 0 && cy - change < tty->rupper)) && - tty_term_has(term, TTYC_VPA)) { - tty_putcode1(tty, TTYC_VPA, cy); - goto out; + (change > 0 && cy - change < tty->rupper)) { + if (tty_term_has(term, TTYC_VPA)) { + tty_putcode1(tty, TTYC_VPA, cy); + goto out; + } } else if (change > 0 && tty_term_has(term, TTYC_CUU)) { tty_putcode1(tty, TTYC_CUU, change); goto out; From 693b3d03e66e5ab2f4c4e31b7d5d2c1629afbd8c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 12 Oct 2009 16:41:02 +0000 Subject: [PATCH 0399/1180] Don't run through the column unchanged case if the row was unchanged but there were no suitable optimisations, instead make it an else to fall through to absolute addressing. --- tty.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/tty.c b/tty.c index 29c84832..53e017bc 100644 --- a/tty.c +++ b/tty.c @@ -968,8 +968,12 @@ tty_cursor(struct tty *tty, u_int cx, u_int cy) goto out; } - /* Row staying the same. */ + /* Moving column or row. */ if (cy == thisy) { + /* + * Moving column only, row staying the same. + */ + /* To left edge. */ if (cx == 0) { tty_putc(tty, '\r'); @@ -1005,10 +1009,11 @@ tty_cursor(struct tty *tty, u_int cx, u_int cy) tty_putcode1(tty, TTYC_CUF, -change); goto out; } - } + } else if (cx == thisx) { + /* + * Moving row only, column staying the same. + */ - /* Column staying the same. */ - if (cx == thisx ) { /* One above. */ if (cy != tty->rupper && cy == thisy - 1 && tty_term_has(term, TTYC_CUU1)) { From 8608c6970d67d5dec37400bcb4fb6a0c46efc165 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 12 Oct 2009 16:59:55 +0000 Subject: [PATCH 0400/1180] When backspace is received at the beginning of a line and the previous line was wrapped, move the cursor back up to the end of the previous line. Another one of the forgotten persons requested this quite a while ago (I need to start noting names on todo items...) when it was quite hard to implement. Now it is easy and I don't see it can do any harm, so hey presto... --- input.c | 2 +- screen-write.c | 20 ++++++++++++++++++++ tmux.h | 1 + 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/input.c b/input.c index ba3d9223..d8737888 100644 --- a/input.c +++ b/input.c @@ -646,7 +646,7 @@ input_handle_c0_control(u_char ch, struct input_ctx *ictx) ictx->wp->window->flags |= WINDOW_BELL; break; case '\010': /* BS */ - screen_write_cursorleft(&ictx->ctx, 1); + screen_write_backspace(&ictx->ctx); break; case '\011': /* TAB */ /* Don't tab beyond the end of the line. */ diff --git a/screen-write.c b/screen-write.c index 6b6aa400..2ce98dee 100644 --- a/screen-write.c +++ b/screen-write.c @@ -513,6 +513,25 @@ screen_write_cursorleft(struct screen_write_ctx *ctx, u_int nx) s->cx -= nx; } +/* Backspace; cursor left unless at start of wrapped line when can move up. */ +void +screen_write_backspace(struct screen_write_ctx *ctx) +{ + struct screen *s = ctx->s; + struct grid_line *gl; + + if (s->cx == 0) { + if (s->cy == 0) + return; + gl = &s->grid->linedata[s->grid->hsize + s->cy - 1]; + if (gl->flags & GRID_LINE_WRAPPED) { + s->cy--; + s->cx = screen_size_x(s) - 1; + } + } else + s->cx--; +} + /* VT100 alignment test. */ void screen_write_alignmenttest(struct screen_write_ctx *ctx) @@ -536,6 +555,7 @@ screen_write_alignmenttest(struct screen_write_ctx *ctx) s->cy = 0; s->rupper = 0; + s->rlower = screen_size_y(s) - 1; tty_write(tty_cmd_alignmenttest, &ttyctx); diff --git a/tmux.h b/tmux.h index 02f9bbd0..2d25c1de 100644 --- a/tmux.h +++ b/tmux.h @@ -1646,6 +1646,7 @@ void screen_write_putc( struct screen_write_ctx *, struct grid_cell *, u_char); void screen_write_copy(struct screen_write_ctx *, struct screen *, u_int, u_int, u_int, u_int); +void screen_write_backspace(struct screen_write_ctx *); void screen_write_cursorup(struct screen_write_ctx *, u_int); void screen_write_cursordown(struct screen_write_ctx *, u_int); void screen_write_cursorright(struct screen_write_ctx *, u_int); From d7626cd9d766bdffb3f1dc729933a98c77379da2 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 12 Oct 2009 17:19:47 +0000 Subject: [PATCH 0401/1180] When drawing lines that have wrapped naturally, don't force a newline but permit them to wrap naturally again. This allows terminals that use this to guess where lines start and end for eg mouse selecting (like xterm) to work correctly. This was another long-standing issue raised by several people over the last while. Thanks to martynas@ for much testing. This was not trivial to get right so bringing it in for wider testing and adn to fix any further glitches in-tree. --- screen-write.c | 34 ++++++++++++++++++++++++++------- tmux.h | 1 + tty.c | 51 +++++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 74 insertions(+), 12 deletions(-) diff --git a/screen-write.c b/screen-write.c index 2ce98dee..bcaabc14 100644 --- a/screen-write.c +++ b/screen-write.c @@ -833,15 +833,15 @@ screen_write_mousemode(struct screen_write_ctx *ctx, int state) s->mode &= ~MODE_MOUSE; } -/* Line feed (down with scroll). */ +/* + * Line feed the screen only (don't update the tty). Used for printing single + * characters, where might want to let the scroll happen naturally. + */ void -screen_write_linefeed(struct screen_write_ctx *ctx, int wrapped) +screen_write_linefeedscreen(struct screen_write_ctx *ctx, int wrapped) { struct screen *s = ctx->s; struct grid_line *gl; - struct tty_ctx ttyctx; - - screen_write_initctx(ctx, &ttyctx); gl = &s->grid->linedata[s->grid->hsize + s->cy]; if (wrapped) @@ -853,6 +853,17 @@ screen_write_linefeed(struct screen_write_ctx *ctx, int wrapped) grid_view_scroll_region_up(s->grid, s->rupper, s->rlower); else if (s->cy < screen_size_y(s) - 1) s->cy++; +} + +/* Line feed (down with scroll). */ +void +screen_write_linefeed(struct screen_write_ctx *ctx, int wrapped) +{ + struct tty_ctx ttyctx; + + screen_write_initctx(ctx, &ttyctx); + + screen_write_linefeedscreen(ctx, wrapped); tty_write(tty_cmd_linefeed, &ttyctx); } @@ -952,6 +963,7 @@ screen_write_cell( struct screen_write_ctx *ctx, const struct grid_cell *gc, u_char *udata) { struct screen *s = ctx->s; + struct window_pane *wp = ctx->wp; struct grid *gd = s->grid; struct tty_ctx ttyctx; struct grid_utf8 gu, *tmp_gu; @@ -1016,8 +1028,16 @@ screen_write_cell( /* Check this will fit on the current line and wrap if not. */ if (s->cx > screen_size_x(s) - width) { - screen_write_carriagereturn(ctx); - screen_write_linefeed(ctx, 1); + /* + * Don't update the terminal now, just update the screen and + * leave the cursor to scroll naturally, unless this is only + * part of the screen width. + */ + if (wp->xoff != 0 || wp->sx != screen_size_x(s)) + screen_write_linefeed(ctx, 1); + else + screen_write_linefeedscreen(ctx, 1); + s->cx = 0; /* carriage return */ } /* Sanity checks. */ diff --git a/tmux.h b/tmux.h index 2d25c1de..1fe67a5b 100644 --- a/tmux.h +++ b/tmux.h @@ -1666,6 +1666,7 @@ void screen_write_scrollregion(struct screen_write_ctx *, u_int, u_int); void screen_write_insertmode(struct screen_write_ctx *, int); void screen_write_mousemode(struct screen_write_ctx *, int); void screen_write_linefeed(struct screen_write_ctx *, int); +void screen_write_linefeedscreen(struct screen_write_ctx *, int); void screen_write_carriagereturn(struct screen_write_ctx *); void screen_write_kcursormode(struct screen_write_ctx *, int); void screen_write_kkeypadmode(struct screen_write_ctx *, int); diff --git a/tty.c b/tty.c index 53e017bc..866ee93c 100644 --- a/tty.c +++ b/tty.c @@ -327,9 +327,10 @@ tty_putc(struct tty *tty, u_char ch) if (tty->term->flags & TERM_EARLYWRAP) sx--; - if (tty->cx == sx) { - tty->cx = 0; - tty->cy++; + if (tty->cx >= sx) { + tty->cx = 1; + if (tty->cy != tty->rlower) + tty->cy++; } else tty->cx++; } @@ -440,6 +441,7 @@ void tty_draw_line(struct tty *tty, struct screen *s, u_int py, u_int ox, u_int oy) { const struct grid_cell *gc; + struct grid_line *gl; struct grid_cell tmpgc; const struct grid_utf8 *gu; u_int i, sx; @@ -452,7 +454,17 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int py, u_int ox, u_int oy) if (sx > tty->sx) sx = tty->sx; - tty_cursor(tty, ox, oy + py); + /* + * Don't move the cursor to the start permission if it will wrap there + * itself; much the same as the conditions in tty_cmd_cell. + */ + gl = NULL; + if (py != 0) + gl = &s->grid->linedata[s->grid->hsize + py - 1]; + if (ox != 0 || (gl != NULL && !(gl->flags & GRID_LINE_WRAPPED)) || + tty->cy != oy + py - 1 || tty->cx < tty->sx) + tty_cursor(tty, ox, oy + py); + for (i = 0; i < sx; i++) { gc = grid_view_peek_cell(s->grid, i, py); @@ -827,7 +839,36 @@ tty_cmd_alignmenttest(struct tty *tty, const struct tty_ctx *ctx) void tty_cmd_cell(struct tty *tty, const struct tty_ctx *ctx) { - tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); + struct window_pane *wp = ctx->wp; + struct screen *s = wp->screen; + struct grid_line *gl; + u_int wx, wy; + + tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower); + + wx = ctx->ocx + wp->xoff; + wy = ctx->ocy + wp->yoff; + + /* + * If: + * + * - the line was wrapped: + * - the cursor is beyond the edge of the screen, + * - the desired position is at the left, + * - and either a) the desired next line is the one below the current + * or b) the current line is the bottom of the scroll region, + * + * Then just printing the next character will be enough to scroll into + * place, so don't do an explicit cursor move. + */ + gl = NULL; + if (ctx->ocy != 0) + gl = &s->grid->linedata[s->grid->hsize + ctx->ocy - 1]; + if (wy == 0 || (gl != NULL && !(gl->flags & GRID_LINE_WRAPPED)) || + tty->cx < tty->sx || /* not at edge of screen */ + wx != 0 || /* don't want 0 next */ + (wy != tty->cy + 1 && tty->cy != ctx->orlower + wp->yoff)) + tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); tty_cell(tty, ctx->cell, ctx->utf8); } From 4dcb5040a0bdf73ecbf504ed887600ec2f100d4c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 13 Oct 2009 00:44:16 +0000 Subject: [PATCH 0402/1180] Instead of using something sort of similar for both newline checks, use something the same. Doesn't fix the bug I'm looking for though :-/. --- tty.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tty.c b/tty.c index 866ee93c..75721c63 100644 --- a/tty.c +++ b/tty.c @@ -461,8 +461,9 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int py, u_int ox, u_int oy) gl = NULL; if (py != 0) gl = &s->grid->linedata[s->grid->hsize + py - 1]; - if (ox != 0 || (gl != NULL && !(gl->flags & GRID_LINE_WRAPPED)) || - tty->cy != oy + py - 1 || tty->cx < tty->sx) + if (oy + py == 0 || (gl != NULL && !(gl->flags & GRID_LINE_WRAPPED)) || + tty->cx < tty->sx || ox != 0 || + (oy + py != tty->cy + 1 && tty->cy != s->rlower + oy)) tty_cursor(tty, ox, oy + py); for (i = 0; i < sx; i++) { From 9294cb099ff371998055410bb3cfd7be0a518368 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 13 Oct 2009 06:14:08 +0000 Subject: [PATCH 0403/1180] When a session is unattached, reset its activity timer to prevent it locking instantly when reattached. --- server.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/server.c b/server.c index 2906fb87..6fdcf940 100644 --- a/server.c +++ b/server.c @@ -1377,6 +1377,11 @@ server_lock_server(void) if ((s = ARRAY_ITEM(&sessions, i)) == NULL) continue; + if (s->flags & SESSION_UNATTACHED) { + s->activity = time(NULL); + continue; + } + timeout = options_get_number(&s->options, "lock-after-time"); if (timeout <= 0 || t <= s->activity + timeout) return; /* not timed out */ @@ -1400,6 +1405,11 @@ server_lock_sessions(void) if ((s = ARRAY_ITEM(&sessions, i)) == NULL) continue; + if (s->flags & SESSION_UNATTACHED) { + s->activity = time(NULL); + continue; + } + timeout = options_get_number(&s->options, "lock-after-time"); if (timeout > 0 && t > s->activity + timeout) { server_lock_session(s); From 5d78371628a719d5d1f0e5a0ecc99b885f4e7d15 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 13 Oct 2009 08:37:15 +0000 Subject: [PATCH 0404/1180] Don't try to use \n across scroll region when doing \r\n either. --- tty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tty.c b/tty.c index 75721c63..5bf9b6d3 100644 --- a/tty.c +++ b/tty.c @@ -1004,7 +1004,7 @@ tty_cursor(struct tty *tty, u_int cx, u_int cy) } /* Zero on the next line. */ - if (cx == 0 && cy == thisy + 1) { + if (cx == 0 && cy == thisy + 1 && thisy != tty->rlower) { tty_putc(tty, '\r'); tty_putc(tty, '\n'); goto out; From 760e39e405fc5b31432989df146b21bb8b78c205 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 13 Oct 2009 13:11:06 +0000 Subject: [PATCH 0405/1180] Don't print exit messages when used as a login shell, requested by martynas@ a while back. --- client.c | 50 ++++++++++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/client.c b/client.c index e93272de..214ec6a0 100644 --- a/client.c +++ b/client.c @@ -212,30 +212,36 @@ client_main(struct client_ctx *cctx) } out: - if (sigterm) { - printf("[terminated]\n"); - return (1); - } - switch (cctx->exittype) { - case CCTX_DIED: - printf("[lost server]\n"); - return (0); - case CCTX_SHUTDOWN: - printf("[server exited]\n"); - return (0); - case CCTX_EXIT: - if (cctx->errstr != NULL) { - printf("[error: %s]\n", cctx->errstr); + /* + * Print exit status message, unless running as a login shell where it + * would either be pointless or irritating. + */ + if (!login_shell) { + if (sigterm) { + printf("[terminated]\n"); + return (1); + } + switch (cctx->exittype) { + case CCTX_DIED: + printf("[lost server]\n"); + return (0); + case CCTX_SHUTDOWN: + printf("[server exited]\n"); + return (0); + case CCTX_EXIT: + if (cctx->errstr != NULL) { + printf("[error: %s]\n", cctx->errstr); + return (1); + } + printf("[exited]\n"); + return (0); + case CCTX_DETACH: + printf("[detached]\n"); + return (0); + default: + printf("[unknown error]\n"); return (1); } - printf("[exited]\n"); - return (0); - case CCTX_DETACH: - printf("[detached]\n"); - return (0); - default: - printf("[unknown error]\n"); - return (1); } } From 0907ca19310267a40a1e4edd76ec81e2bb79231d Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 13 Oct 2009 13:15:26 +0000 Subject: [PATCH 0406/1180] Do this in a better way - print messages when exiting with nonzero. Also remove the login shell information from server-info, only the client should care about it. --- client.c | 47 ++++++++++++++++++++++++----------------------- cmd-server-info.c | 5 ++--- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/client.c b/client.c index 214ec6a0..e7118a3b 100644 --- a/client.c +++ b/client.c @@ -216,32 +216,33 @@ out: * Print exit status message, unless running as a login shell where it * would either be pointless or irritating. */ - if (!login_shell) { - if (sigterm) { - printf("[terminated]\n"); - return (1); - } - switch (cctx->exittype) { - case CCTX_DIED: - printf("[lost server]\n"); - return (0); - case CCTX_SHUTDOWN: + if (sigterm) { + printf("[terminated]\n"); + return (1); + } + switch (cctx->exittype) { + case CCTX_DIED: + printf("[lost server]\n"); + return (0); + case CCTX_SHUTDOWN: + if (!login_shell) printf("[server exited]\n"); - return (0); - case CCTX_EXIT: - if (cctx->errstr != NULL) { - printf("[error: %s]\n", cctx->errstr); - return (1); - } - printf("[exited]\n"); - return (0); - case CCTX_DETACH: - printf("[detached]\n"); - return (0); - default: - printf("[unknown error]\n"); + return (0); + case CCTX_EXIT: + if (cctx->errstr != NULL) { + printf("[error: %s]\n", cctx->errstr); return (1); } + if (!login_shell) + printf("[exited]\n"); + return (0); + case CCTX_DETACH: + if (!login_shell) + printf("[detached]\n"); + return (0); + default: + printf("[unknown error]\n"); + return (1); } } diff --git a/cmd-server-info.c b/cmd-server-info.c index 48ea3707..7ad7bdd6 100644 --- a/cmd-server-info.c +++ b/cmd-server-info.c @@ -68,9 +68,8 @@ cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx) tim = ctime(&start_time); *strchr(tim, '\n') = '\0'; ctx->print(ctx, "pid %ld, started %s", (long) getpid(), tim); - ctx->print(ctx, "socket path %s, debug level %d%s%s", - socket_path, debug_level, be_quiet ? ", quiet" : "", - login_shell ? ", login shell" : ""); + ctx->print(ctx, "socket path %s, debug level %d%s", + socket_path, debug_level, be_quiet ? ", quiet" : ""); if (uname(&un) == 0) { ctx->print(ctx, "system is %s %s %s %s", un.sysname, un.release, un.version, un.machine); From 38df960e68302b0bce9f0812d9fcb22c42b72d19 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 13 Oct 2009 13:45:56 +0000 Subject: [PATCH 0407/1180] Add mode keys to move the cursor to the top, middle and bottom of the screen. H/M/L in vi mode and M-R/M-r in emacs (bottom of screen not bound in emacs). --- mode-key.c | 10 +++++++++- tmux.1 | 3 +++ tmux.h | 3 +++ window-copy.c | 18 ++++++++++++++++++ 4 files changed, 33 insertions(+), 1 deletion(-) diff --git a/mode-key.c b/mode-key.c index 3c15ff40..d23c54d2 100644 --- a/mode-key.c +++ b/mode-key.c @@ -77,6 +77,7 @@ struct mode_key_cmdstr mode_key_cmdstr_choice[] = { /* Copy keys command strings. */ struct mode_key_cmdstr mode_key_cmdstr_copy[] = { { MODEKEYCOPY_BACKTOINDENTATION, "back-to-indentation" }, + { MODEKEYCOPY_BOTTOMLINE, "bottom-line" }, { MODEKEYCOPY_CANCEL, "cancel" }, { MODEKEYCOPY_CLEARSELECTION, "clear-selection" }, { MODEKEYCOPY_COPYSELECTION, "copy-selection" }, @@ -84,6 +85,7 @@ struct mode_key_cmdstr mode_key_cmdstr_copy[] = { { MODEKEYCOPY_ENDOFLINE, "end-of-line" }, { MODEKEYCOPY_GOTOLINE, "goto-line" }, { MODEKEYCOPY_LEFT, "cursor-left" }, + { MODEKEYCOPY_MIDDLELINE, "middle-line" }, { MODEKEYCOPY_NEXTPAGE, "page-down" }, { MODEKEYCOPY_NEXTWORD, "next-word" }, { MODEKEYCOPY_PREVIOUSPAGE, "page-up" }, @@ -96,6 +98,7 @@ struct mode_key_cmdstr mode_key_cmdstr_copy[] = { { MODEKEYCOPY_SEARCHUP, "search-backward" }, { MODEKEYCOPY_STARTOFLINE, "start-of-line" }, { MODEKEYCOPY_STARTSELECTION, "begin-selection" }, + { MODEKEYCOPY_TOPLINE, "top-line" }, { MODEKEYCOPY_UP, "cursor-up" }, { 0, NULL } @@ -161,8 +164,11 @@ const struct mode_key_entry mode_key_vi_copy[] = { { '0', 0, MODEKEYCOPY_STARTOFLINE }, { ':', 0, MODEKEYCOPY_GOTOLINE }, { '?', 0, MODEKEYCOPY_SEARCHUP }, + { 'H', 0, MODEKEYCOPY_TOPLINE }, { 'J', 0, MODEKEYCOPY_SCROLLDOWN }, { 'K', 0, MODEKEYCOPY_SCROLLUP }, + { 'L', 0, MODEKEYCOPY_BOTTOMLINE }, + { 'M', 0, MODEKEYCOPY_MIDDLELINE }, { '\002' /* C-b */, 0, MODEKEYCOPY_PREVIOUSPAGE }, { '\003' /* C-c */, 0, MODEKEYCOPY_CANCEL }, { '\004' /* C-d */, 0, MODEKEYCOPY_HALFPAGEDOWN }, @@ -189,7 +195,7 @@ const struct mode_key_entry mode_key_vi_copy[] = { { KEYC_RIGHT, 0, MODEKEYCOPY_RIGHT }, { KEYC_UP | KEYC_CTRL, 0, MODEKEYCOPY_SCROLLUP }, { KEYC_UP, 0, MODEKEYCOPY_UP }, - + { 0, -1, 0 } }; struct mode_key_tree mode_key_tree_vi_copy; @@ -266,6 +272,8 @@ const struct mode_key_entry mode_key_emacs_copy[] = { { 'm' | KEYC_ESCAPE, 0, MODEKEYCOPY_BACKTOINDENTATION }, { 'n', 0, MODEKEYCOPY_SEARCHAGAIN }, { 'q', 0, MODEKEYCOPY_CANCEL }, + { 'r' | KEYC_ESCAPE, 0, MODEKEYCOPY_MIDDLELINE }, + { 'R' | KEYC_ESCAPE, 0, MODEKEYCOPY_TOPLINE }, { 'v' | KEYC_ESCAPE, 0, MODEKEYCOPY_PREVIOUSPAGE }, { 'w' | KEYC_ESCAPE, 0, MODEKEYCOPY_COPYSELECTION }, { KEYC_DOWN | KEYC_CTRL,0, MODEKEYCOPY_SCROLLDOWN }, diff --git a/tmux.1 b/tmux.1 index fc1801f2..2992bb23 100644 --- a/tmux.1 +++ b/tmux.1 @@ -538,6 +538,9 @@ The following keys are supported as appropriate for the mode: .It Li "Start of line" Ta "0" Ta "C-a" .It Li "Start selection" Ta "Space" Ta "C-Space" .It Li "Transpose chars" Ta "" Ta "C-t" +.It Li "Cursor to top line" Ta "H" Ta "M-R" +.It Li "Cursor to middle line" Ta "M" Ta "M-r" +.It Li "Cursor to bottom line" Ta "L" Ta "" .El .Pp These key bindings are defined in a set of named tables: diff --git a/tmux.h b/tmux.h index 1fe67a5b..35a542fa 100644 --- a/tmux.h +++ b/tmux.h @@ -397,6 +397,7 @@ enum mode_key_cmd { /* Copy keys. */ MODEKEYCOPY_BACKTOINDENTATION, + MODEKEYCOPY_BOTTOMLINE, MODEKEYCOPY_CANCEL, MODEKEYCOPY_CLEARSELECTION, MODEKEYCOPY_COPYSELECTION, @@ -406,6 +407,7 @@ enum mode_key_cmd { MODEKEYCOPY_HALFPAGEDOWN, MODEKEYCOPY_HALFPAGEUP, MODEKEYCOPY_LEFT, + MODEKEYCOPY_MIDDLELINE, MODEKEYCOPY_NEXTPAGE, MODEKEYCOPY_NEXTWORD, MODEKEYCOPY_PREVIOUSPAGE, @@ -418,6 +420,7 @@ enum mode_key_cmd { MODEKEYCOPY_SEARCHUP, MODEKEYCOPY_STARTOFLINE, MODEKEYCOPY_STARTSELECTION, + MODEKEYCOPY_TOPLINE, MODEKEYCOPY_UP, }; diff --git a/window-copy.c b/window-copy.c index 2eb91acb..cdd84b4c 100644 --- a/window-copy.c +++ b/window-copy.c @@ -278,6 +278,24 @@ window_copy_key(struct window_pane *wp, struct client *c, int key) window_copy_update_selection(wp); window_copy_redraw_screen(wp); break; + case MODEKEYCOPY_TOPLINE: + data->cx = 0; + data->cy = 0; + window_copy_update_selection(wp); + window_copy_redraw_screen(wp); + break; + case MODEKEYCOPY_MIDDLELINE: + data->cx = 0; + data->cy = (screen_size_y(s) - 1) / 2; + window_copy_update_selection(wp); + window_copy_redraw_screen(wp); + break; + case MODEKEYCOPY_BOTTOMLINE: + data->cx = 0; + data->cy = screen_size_y(s) - 1; + window_copy_update_selection(wp); + window_copy_redraw_screen(wp); + break; case MODEKEYCOPY_STARTSELECTION: window_copy_start_selection(wp); window_copy_redraw_screen(wp); From 71dc6e04e8ca9ab85acbef90bbfd57463be0dc07 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 13 Oct 2009 15:23:13 +0000 Subject: [PATCH 0408/1180] Handle DECCOLM by just emulating its side-effect of clearing the screen. --- input.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/input.c b/input.c index d8737888..fa7661f7 100644 --- a/input.c +++ b/input.c @@ -1185,6 +1185,10 @@ input_handle_sequence_sm(struct input_ctx *ictx) screen_write_kcursormode(&ictx->ctx, 1); log_debug("kcursor on"); break; + case 3: /* DECCOLM */ + screen_write_cursormove(&ictx->ctx, 0, 0); + screen_write_clearscreen(&ictx->ctx); + break; case 25: /* TCEM */ screen_write_cursormode(&ictx->ctx, 1); log_debug("cursor on"); @@ -1257,6 +1261,10 @@ input_handle_sequence_rm(struct input_ctx *ictx) screen_write_kcursormode(&ictx->ctx, 0); log_debug("kcursor off"); break; + case 3: /* DECCOLM */ + screen_write_cursormove(&ictx->ctx, 0, 0); + screen_write_clearscreen(&ictx->ctx); + break; case 25: /* TCEM */ screen_write_cursormode(&ictx->ctx, 0); log_debug("cursor off"); From ad566a86de2368aa4a42cd26dafecc066cff41eb Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 13 Oct 2009 15:38:37 +0000 Subject: [PATCH 0409/1180] Move lines into the history when scrolling even if the scroll region is not the entire screen. Allows ircII users to see history, prompted by naddy. --- grid-view.c | 21 ++++++++++------ grid.c | 70 ++++++++++++++++++++++++++++++++++++++++++++--------- tmux.h | 4 ++- 3 files changed, 75 insertions(+), 20 deletions(-) diff --git a/grid-view.c b/grid-view.c index bf58c61f..f6bde853 100644 --- a/grid-view.c +++ b/grid-view.c @@ -92,15 +92,20 @@ grid_view_scroll_region_up(struct grid *gd, u_int rupper, u_int rlower) { GRID_DEBUG(gd, "rupper=%u, rlower=%u", rupper, rlower); - if (gd->flags & GRID_HISTORY && rupper == 0 && rlower == gd->sy - 1) { - grid_scroll_line(gd); - return; + if (gd->flags & GRID_HISTORY) { + grid_collect_history(gd); + if (rupper == 0 && rlower == gd->sy - 1) + grid_scroll_history(gd); + else { + rupper = grid_view_y(gd, rupper); + rlower = grid_view_y(gd, rlower); + grid_scroll_history_region(gd, rupper, rlower); + } + } else { + rupper = grid_view_y(gd, rupper); + rlower = grid_view_y(gd, rlower); + grid_move_lines(gd, rupper, rupper + 1, rlower - rupper); } - - rupper = grid_view_y(gd, rupper); - rlower = grid_view_y(gd, rlower); - - grid_move_lines(gd, rupper, rupper + 1, rlower - rupper); } /* Scroll region down. */ diff --git a/grid.c b/grid.c index 6e01aa7c..1041528d 100644 --- a/grid.c +++ b/grid.c @@ -161,29 +161,77 @@ grid_compare(struct grid *ga, struct grid *gb) return (0); } -/* Scroll a line into the history. */ +/* + * Collect lines from the history if at the limit. Free the top (oldest) 10% + * and shift up. + */ void -grid_scroll_line(struct grid *gd) +grid_collect_history(struct grid *gd) { u_int yy; GRID_DEBUG(gd, ""); - if (gd->hsize >= gd->hlimit) { - /* If the limit is hit, free the bottom 10% and shift up. */ - yy = gd->hlimit / 10; - if (yy < 1) - yy = 1; + if (gd->hsize < gd->hlimit) + return; - grid_move_lines(gd, 0, yy, gd->hsize + gd->sy - yy); - gd->hsize -= yy; - } + yy = gd->hlimit / 10; + if (yy < 1) + yy = 1; + + grid_move_lines(gd, 0, yy, gd->hsize + gd->sy - yy); + gd->hsize -= yy; +} + +/* + * Scroll the entire visible screen, moving one line into the history. Just + * allocate a new line at the bottom and move the history size indicator. + */ +void +grid_scroll_history(struct grid *gd) +{ + u_int yy; + + GRID_DEBUG(gd, ""); yy = gd->hsize + gd->sy; - gd->linedata = xrealloc(gd->linedata, yy + 1, sizeof *gd->linedata); memset(&gd->linedata[yy], 0, sizeof gd->linedata[yy]); + + gd->hsize++; +} +/* Scroll a region up, moving the top line into the history. */ +void +grid_scroll_history_region(struct grid *gd, u_int upper, u_int lower) +{ + struct grid_line *gl_history, *gl_upper, *gl_lower; + u_int yy; + + GRID_DEBUG(gd, "upper=%u, lower=%u", upper, lower); + + /* Create a space for a new line. */ + yy = gd->hsize + gd->sy; + gd->linedata = xrealloc(gd->linedata, yy + 1, sizeof *gd->linedata); + + /* Move the entire screen down to free a space for this line. */ + gl_history = &gd->linedata[gd->hsize]; + memmove(gl_history + 1, gl_history, gd->sy * sizeof *gl_history); + + /* Adjust the region and find its start and end. */ + upper++; + gl_upper = &gd->linedata[upper]; + lower++; + gl_lower = &gd->linedata[lower]; + + /* Move the line into the history. */ + memcpy(gl_history, gl_upper, sizeof *gl_history); + + /* Then move the region up and clear the bottom line. */ + memmove(gl_upper, gl_upper + 1, (lower - upper) * sizeof *gl_upper); + memset(gl_lower, 0, sizeof *gl_lower); + + /* Move the history offset down over the line. */ gd->hsize++; } diff --git a/tmux.h b/tmux.h index 35a542fa..0dcf7c37 100644 --- a/tmux.h +++ b/tmux.h @@ -1592,9 +1592,11 @@ extern const struct grid_cell grid_default_cell; struct grid *grid_create(u_int, u_int, u_int); void grid_destroy(struct grid *); int grid_compare(struct grid *, struct grid *); +void grid_collect_history(struct grid *); +void grid_scroll_history(struct grid *); +void grid_scroll_history_region(struct grid *, u_int, u_int); void grid_expand_line(struct grid *, u_int, u_int); void grid_expand_line_utf8(struct grid *, u_int, u_int); -void grid_scroll_line(struct grid *); const struct grid_cell *grid_peek_cell(struct grid *, u_int, u_int); struct grid_cell *grid_get_cell(struct grid *, u_int, u_int); void grid_set_cell(struct grid *, u_int, u_int, const struct grid_cell *); From adad5574996cabc2e91bd267d2a86b3c6cec584d Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 14 Oct 2009 09:29:10 +0000 Subject: [PATCH 0410/1180] Don't allow cmd_lookup_client to test clients without a session. --- cmd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmd.c b/cmd.c index 0fb1ff57..198daa84 100644 --- a/cmd.c +++ b/cmd.c @@ -458,7 +458,8 @@ cmd_lookup_client(const char *name) u_int i; for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - if ((c = ARRAY_ITEM(&clients, i)) == NULL) + c = ARRAY_ITEM(&clients, i); + if (c == NULL || c->session == NULL) continue; path = c->tty.path; From 1a3c334c753b9c22dc06105cc8009655bd9589c1 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 14 Oct 2009 20:52:28 +0000 Subject: [PATCH 0411/1180] cmd_find_client shouldn't die when there is an empty slot in the clients array. DOH. --- cmd.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/cmd.c b/cmd.c index 198daa84..bf07c3b0 100644 --- a/cmd.c +++ b/cmd.c @@ -399,7 +399,7 @@ cmd_newest_client(void) struct client * cmd_find_client(struct cmd_ctx *ctx, const char *arg) { - struct client *c; + struct client *c, *lastc; struct session *s; char *tmparg; size_t arglen; @@ -415,16 +415,17 @@ cmd_find_client(struct cmd_ctx *ctx, const char *arg) */ s = cmd_current_session(ctx); if (s != NULL) { - c = NULL; + lastc = NULL; for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - if (ARRAY_ITEM(&clients, i)->session == s) { - if (c != NULL) + c = ARRAY_ITEM(&clients, i); + if (c != NULL && c->session == s) { + if (lastc != NULL) break; - c = ARRAY_ITEM(&clients, i); + lastc = c; } } - if (i == ARRAY_LENGTH(&clients) && c != NULL) - return (c); + if (i == ARRAY_LENGTH(&clients) && lastc != NULL) + return (lastc); } return (cmd_newest_client()); } From dba0d54cf537ebfd125aa17a20eb88ef266db9c1 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 15 Oct 2009 07:05:38 +0000 Subject: [PATCH 0412/1180] The pane pty name isn't useful for anything so show the pane number instead. --- cmd-list-panes.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/cmd-list-panes.c b/cmd-list-panes.c index 0dcf0009..5a06eb7a 100644 --- a/cmd-list-panes.c +++ b/cmd-list-panes.c @@ -47,13 +47,13 @@ cmd_list_panes_exec(struct cmd *self, struct cmd_ctx *ctx) struct window_pane *wp; struct grid *gd; struct grid_line *gl; - u_int i; + u_int i, n; unsigned long long size; - const char *name; if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) return (-1); + n = 0; TAILQ_FOREACH(wp, &wl->window->panes, entry) { gd = wp->base.grid; @@ -65,13 +65,9 @@ cmd_list_panes_exec(struct cmd *self, struct cmd_ctx *ctx) } size += gd->hsize * sizeof *gd->linedata; - name = NULL; - if (wp->fd != -1) - name = ttyname(wp->fd); - if (name == NULL) - name = "unknown"; - ctx->print(ctx, "%s [%ux%u] [history %u/%u, %llu bytes]", - name, wp->sx, wp->sy, gd->hsize, gd->hlimit, size); + ctx->print(ctx, "%u: [%ux%u] [history %u/%u, %llu bytes]", + n, wp->sx, wp->sy, gd->hsize, gd->hlimit, size); + n++; } return (0); From 70355021d8e8b83eaa3d947dc7a49b4eacff17fa Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 16 Oct 2009 19:09:40 +0000 Subject: [PATCH 0413/1180] When checking whether the region will scroll and the cursor position is thus unsuitable for using CUD/CUU, check the current cursor position not the target position. --- tty.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tty.c b/tty.c index 5bf9b6d3..53cd3362 100644 --- a/tty.c +++ b/tty.c @@ -1057,14 +1057,14 @@ tty_cursor(struct tty *tty, u_int cx, u_int cy) */ /* One above. */ - if (cy != tty->rupper && + if (thisy != tty->rupper && cy == thisy - 1 && tty_term_has(term, TTYC_CUU1)) { tty_putcode(tty, TTYC_CUU1); goto out; } /* One below. */ - if (cy != tty->rlower && + if (thisy != tty->rlower && cy == thisy + 1 && tty_term_has(term, TTYC_CUD1)) { tty_putcode(tty, TTYC_CUD1); goto out; From 43d62c1ae3846ba1b33d79349be367ed3b6763cf Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 17 Oct 2009 08:24:46 +0000 Subject: [PATCH 0414/1180] Instead of having a complicated check to see if the cursor is in the last position to avoid an explicit wrap, actually move it there. Some UTF-8 fixes to come. --- screen-write.c | 70 +++++++++++++++++++++++++++++++++++--------------- tmux.h | 5 ++++ tty.c | 34 ++++++++---------------- 3 files changed, 65 insertions(+), 44 deletions(-) diff --git a/screen-write.c b/screen-write.c index bcaabc14..cb379a57 100644 --- a/screen-write.c +++ b/screen-write.c @@ -22,7 +22,7 @@ #include "tmux.h" -void screen_write_initctx(struct screen_write_ctx *, struct tty_ctx *); +void screen_write_initctx(struct screen_write_ctx *, struct tty_ctx *, int); void screen_write_overwrite(struct screen_write_ctx *); /* Initialise writing with a window. */ @@ -418,9 +418,14 @@ screen_write_copy(struct screen_write_ctx *ctx, /* Set up context for TTY command. */ void -screen_write_initctx(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx) +screen_write_initctx( + struct screen_write_ctx *ctx, struct tty_ctx *ttyctx, int save_last) { - struct screen *s = ctx->s; + struct screen *s = ctx->s; + struct grid *gd = s->grid; + const struct grid_cell *gc; + const struct grid_utf8 *gu; + u_int xx; ttyctx->wp = ctx->wp; @@ -429,6 +434,23 @@ screen_write_initctx(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx) ttyctx->orlower = s->rlower; ttyctx->orupper = s->rupper; + + if (!save_last) + return; + + /* Save the last cell on the screen. */ + gc = NULL; + for (xx = 1; xx < screen_size_x(s); xx++) { + gc = grid_view_peek_cell(gd, screen_size_x(s) - xx, s->cy); + if (!(gc->flags & GRID_FLAG_PADDING)) + break; + } + ttyctx->last_width = xx; + memcpy(&ttyctx->last_cell, gc, sizeof ttyctx->last_cell); + if (gc->flags & GRID_FLAG_UTF8) { + gu = grid_view_peek_utf8(gd, screen_size_x(s) - xx, s->cy); + memcpy(&ttyctx->last_utf8, gu, sizeof ttyctx->last_utf8); + } } /* Cursor up by ny. */ @@ -541,7 +563,7 @@ screen_write_alignmenttest(struct screen_write_ctx *ctx) struct grid_cell gc; u_int xx, yy; - screen_write_initctx(ctx, &ttyctx); + screen_write_initctx(ctx, &ttyctx, 0); memcpy(&gc, &grid_default_cell, sizeof gc); gc.data = 'E'; @@ -576,7 +598,7 @@ screen_write_insertcharacter(struct screen_write_ctx *ctx, u_int nx) if (nx == 0) return; - screen_write_initctx(ctx, &ttyctx); + screen_write_initctx(ctx, &ttyctx, 0); if (s->cx <= screen_size_x(s) - 1) grid_view_insert_cells(s->grid, s->cx, s->cy, nx); @@ -600,7 +622,7 @@ screen_write_deletecharacter(struct screen_write_ctx *ctx, u_int nx) if (nx == 0) return; - screen_write_initctx(ctx, &ttyctx); + screen_write_initctx(ctx, &ttyctx, 0); if (s->cx <= screen_size_x(s) - 1) grid_view_delete_cells(s->grid, s->cx, s->cy, nx); @@ -625,7 +647,7 @@ screen_write_insertline(struct screen_write_ctx *ctx, u_int ny) if (ny == 0) return; - screen_write_initctx(ctx, &ttyctx); + screen_write_initctx(ctx, &ttyctx, 0); grid_view_insert_lines(s->grid, s->cy, ny); @@ -639,7 +661,7 @@ screen_write_insertline(struct screen_write_ctx *ctx, u_int ny) if (ny == 0) return; - screen_write_initctx(ctx, &ttyctx); + screen_write_initctx(ctx, &ttyctx, 0); if (s->cy < s->rupper || s->cy > s->rlower) grid_view_insert_lines(s->grid, s->cy, ny); @@ -666,7 +688,7 @@ screen_write_deleteline(struct screen_write_ctx *ctx, u_int ny) if (ny == 0) return; - screen_write_initctx(ctx, &ttyctx); + screen_write_initctx(ctx, &ttyctx, 0); grid_view_delete_lines(s->grid, s->cy, ny); @@ -680,7 +702,7 @@ screen_write_deleteline(struct screen_write_ctx *ctx, u_int ny) if (ny == 0) return; - screen_write_initctx(ctx, &ttyctx); + screen_write_initctx(ctx, &ttyctx, 0); if (s->cy < s->rupper || s->cy > s->rlower) grid_view_delete_lines(s->grid, s->cy, ny); @@ -698,7 +720,7 @@ screen_write_clearline(struct screen_write_ctx *ctx) struct screen *s = ctx->s; struct tty_ctx ttyctx; - screen_write_initctx(ctx, &ttyctx); + screen_write_initctx(ctx, &ttyctx, 0); grid_view_clear(s->grid, 0, s->cy, screen_size_x(s), 1); @@ -713,7 +735,7 @@ screen_write_clearendofline(struct screen_write_ctx *ctx) struct tty_ctx ttyctx; u_int sx; - screen_write_initctx(ctx, &ttyctx); + screen_write_initctx(ctx, &ttyctx, 0); sx = screen_size_x(s); @@ -731,7 +753,7 @@ screen_write_clearstartofline(struct screen_write_ctx *ctx) struct tty_ctx ttyctx; u_int sx; - screen_write_initctx(ctx, &ttyctx); + screen_write_initctx(ctx, &ttyctx, 0); sx = screen_size_x(s); @@ -777,7 +799,7 @@ screen_write_reverseindex(struct screen_write_ctx *ctx) struct screen *s = ctx->s; struct tty_ctx ttyctx; - screen_write_initctx(ctx, &ttyctx); + screen_write_initctx(ctx, &ttyctx, 0); if (s->cy == s->rupper) grid_view_scroll_region_down(s->grid, s->rupper, s->rlower); @@ -861,7 +883,7 @@ screen_write_linefeed(struct screen_write_ctx *ctx, int wrapped) { struct tty_ctx ttyctx; - screen_write_initctx(ctx, &ttyctx); + screen_write_initctx(ctx, &ttyctx, 0); screen_write_linefeedscreen(ctx, wrapped); @@ -909,7 +931,7 @@ screen_write_clearendofscreen(struct screen_write_ctx *ctx) struct tty_ctx ttyctx; u_int sx, sy; - screen_write_initctx(ctx, &ttyctx); + screen_write_initctx(ctx, &ttyctx, 0); sx = screen_size_x(s); sy = screen_size_y(s); @@ -929,7 +951,7 @@ screen_write_clearstartofscreen(struct screen_write_ctx *ctx) struct tty_ctx ttyctx; u_int sx; - screen_write_initctx(ctx, &ttyctx); + screen_write_initctx(ctx, &ttyctx, 0); sx = screen_size_x(s); @@ -950,7 +972,7 @@ screen_write_clearscreen(struct screen_write_ctx *ctx) struct screen *s = ctx->s; struct tty_ctx ttyctx; - screen_write_initctx(ctx, &ttyctx); + screen_write_initctx(ctx, &ttyctx, 0); grid_view_clear(s->grid, 0, 0, screen_size_x(s), screen_size_y(s)); @@ -1004,8 +1026,12 @@ screen_write_cell( } memcpy(tmp_gu->data + i, udata, UTF8_SIZE - i); - /* Assume the previous character has just been input. */ - screen_write_initctx(ctx, &ttyctx); + /* + * Assume the previous character has just been input. + * XXX There is no guarantee this is true, need to redraw + * entire line. + */ + screen_write_initctx(ctx, &ttyctx, 0); ttyctx.ptr = udata; tty_write(tty_cmd_utf8character, &ttyctx); return; @@ -1019,6 +1045,9 @@ screen_write_cell( gc = &tmp_gc; } + /* Initialise the redraw context, saving the last cell. */ + screen_write_initctx(ctx, &ttyctx, 1); + /* If in insert mode, make space for the cells. */ if (s->mode & MODE_INSERT && s->cx <= screen_size_x(s) - width) { xx = screen_size_x(s) - s->cx - width; @@ -1063,7 +1092,6 @@ screen_write_cell( grid_view_set_utf8(gd, s->cx, s->cy, &gu); /* Move the cursor. */ - screen_write_initctx(ctx, &ttyctx); s->cx += width; /* Draw to the screen if necessary. */ diff --git a/tmux.h b/tmux.h index 0dcf7c37..ba14585a 100644 --- a/tmux.h +++ b/tmux.h @@ -970,6 +970,11 @@ struct tty_ctx { u_int orupper; u_int orlower; + + /* Saved last cell on line. */ + struct grid_cell last_cell; + struct grid_utf8 last_utf8; + u_int last_width; }; /* Mouse input. */ diff --git a/tty.c b/tty.c index 53cd3362..37cff1fc 100644 --- a/tty.c +++ b/tty.c @@ -456,7 +456,7 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int py, u_int ox, u_int oy) /* * Don't move the cursor to the start permission if it will wrap there - * itself; much the same as the conditions in tty_cmd_cell. + * itself. */ gl = NULL; if (py != 0) @@ -842,33 +842,21 @@ tty_cmd_cell(struct tty *tty, const struct tty_ctx *ctx) { struct window_pane *wp = ctx->wp; struct screen *s = wp->screen; - struct grid_line *gl; - u_int wx, wy; + u_int cx; tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower); - wx = ctx->ocx + wp->xoff; - wy = ctx->ocy + wp->yoff; - /* - * If: - * - * - the line was wrapped: - * - the cursor is beyond the edge of the screen, - * - the desired position is at the left, - * - and either a) the desired next line is the one below the current - * or b) the current line is the bottom of the scroll region, - * - * Then just printing the next character will be enough to scroll into - * place, so don't do an explicit cursor move. + * Should the cursor be in the last cursor position ready for a natural + * wrap? If so - and it isn't - move to and rewrite the last cell. */ - gl = NULL; - if (ctx->ocy != 0) - gl = &s->grid->linedata[s->grid->hsize + ctx->ocy - 1]; - if (wy == 0 || (gl != NULL && !(gl->flags & GRID_LINE_WRAPPED)) || - tty->cx < tty->sx || /* not at edge of screen */ - wx != 0 || /* don't want 0 next */ - (wy != tty->cy + 1 && tty->cy != ctx->orlower + wp->yoff)) + if (ctx->ocx + wp->xoff > tty->sx - ctx->last_width) { + if (tty->cx < tty->sx) { + cx = screen_size_x(s) - ctx->last_width; + tty_cursor_pane(tty, ctx, cx, ctx->ocy); + tty_cell(tty, &ctx->last_cell, &ctx->last_utf8); + } + } else tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); tty_cell(tty, ctx->cell, ctx->utf8); From fe26b5d25fd9bfda2a787db1dc524c76004703dd Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 17 Oct 2009 08:32:18 +0000 Subject: [PATCH 0415/1180] Don't print wide characters at screen width - 1. Matches uterm behaviour and is probably a better idea anyway. --- screen-write.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/screen-write.c b/screen-write.c index cb379a57..0cee126f 100644 --- a/screen-write.c +++ b/screen-write.c @@ -1006,6 +1006,14 @@ screen_write_cell( } else width = 1; + /* + * If this is a wide character and there is no room on the screen, for + * the entire character, don't print it. + */ + if (width > 1 && (width > screen_size_x(s) || + (s->cx != screen_size_x(s) && s->cx > screen_size_x(s) - width))) + return; + /* If the width is zero, combine onto the previous character. */ if (width == 0) { if (s->cx == 0) @@ -1037,14 +1045,6 @@ screen_write_cell( return; } - /* If the character is wider than the screen, don't print it. */ - if (width > screen_size_x(s)) { - memcpy(&tmp_gc, gc, sizeof tmp_gc); - tmp_gc.data = '_'; - width = 1; - gc = &tmp_gc; - } - /* Initialise the redraw context, saving the last cell. */ screen_write_initctx(ctx, &ttyctx, 1); From daa26079ee82aed8a1eaf053ea3df5d2276eb472 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 17 Oct 2009 08:35:38 +0000 Subject: [PATCH 0416/1180] Always move the cursor position on !xenl terminals, since there is no invisible last cursor position. Also nuke an unused variable. --- screen-write.c | 12 ++++++------ tty.c | 3 ++- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/screen-write.c b/screen-write.c index 0cee126f..035ca89f 100644 --- a/screen-write.c +++ b/screen-write.c @@ -990,7 +990,7 @@ screen_write_cell( struct tty_ctx ttyctx; struct grid_utf8 gu, *tmp_gu; u_int width, xx, i; - struct grid_cell tmp_gc, tmp_gc2, *tmp_gcp; + struct grid_cell tmp_gc, *tmp_gcp; int insert = 0; /* Ignore padding. */ @@ -1101,13 +1101,13 @@ screen_write_cell( } ttyctx.utf8 = &gu; if (screen_check_selection(s, s->cx - width, s->cy)) { - memcpy(&tmp_gc2, &s->sel.cell, sizeof tmp_gc2); - tmp_gc2.data = gc->data; - tmp_gc2.flags = gc->flags & + memcpy(&tmp_gc, &s->sel.cell, sizeof tmp_gc); + tmp_gc.data = gc->data; + tmp_gc.flags = gc->flags & ~(GRID_FLAG_FG256|GRID_FLAG_BG256); - tmp_gc2.flags |= s->sel.cell.flags & + tmp_gc.flags |= s->sel.cell.flags & (GRID_FLAG_FG256|GRID_FLAG_BG256); - ttyctx.cell = &tmp_gc2; + ttyctx.cell = &tmp_gc; tty_write(tty_cmd_cell, &ttyctx); } else { ttyctx.cell = gc; diff --git a/tty.c b/tty.c index 37cff1fc..9f4fbc2e 100644 --- a/tty.c +++ b/tty.c @@ -850,7 +850,8 @@ tty_cmd_cell(struct tty *tty, const struct tty_ctx *ctx) * Should the cursor be in the last cursor position ready for a natural * wrap? If so - and it isn't - move to and rewrite the last cell. */ - if (ctx->ocx + wp->xoff > tty->sx - ctx->last_width) { + if (!(tty->term->flags & TERM_EARLYWRAP) && + ctx->ocx + wp->xoff > tty->sx - ctx->last_width) { if (tty->cx < tty->sx) { cx = screen_size_x(s) - ctx->last_width; tty_cursor_pane(tty, ctx, cx, ctx->ocy); From 2afe395ff225e2f3ee1838f60abb4f614ef6ac39 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 19 Oct 2009 13:18:13 +0000 Subject: [PATCH 0417/1180] Stop updating the screen when not in output mode, stops copy mode getting confused. --- window.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/window.c b/window.c index 7472815e..d982ccc3 100644 --- a/window.c +++ b/window.c @@ -632,6 +632,9 @@ window_pane_parse(struct window_pane *wp) { size_t new_size; + if (wp->mode != NULL) + return; + new_size = BUFFER_USED(wp->in) - wp->pipe_off; if (wp->pipe_fd != -1 && new_size > 0) buffer_write(wp->pipe_buf, BUFFER_OUT(wp->in), new_size); From d1e6388fedbf0be5018320ceae680d323424dc13 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 20 Oct 2009 14:22:57 +0000 Subject: [PATCH 0418/1180] Nuke stray blank line. --- tmux.h | 1 - 1 file changed, 1 deletion(-) diff --git a/tmux.h b/tmux.h index ba14585a..5cd5132b 100644 --- a/tmux.h +++ b/tmux.h @@ -130,7 +130,6 @@ enum key_code { /* Function keys. */ KEYC_F1, - KEYC_F2, KEYC_F3, KEYC_F4, From 387f4d42ccfb9aab1b8d5f10176dac2a3209c3fa Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 20 Oct 2009 16:32:23 +0000 Subject: [PATCH 0419/1180] Move the check for whether to force a line wrapper lower down into the tty code where it has access to the tty width, which is what should have been checked. --- screen-write.c | 28 +++++++--------------------- tty.c | 8 ++++++++ 2 files changed, 15 insertions(+), 21 deletions(-) diff --git a/screen-write.c b/screen-write.c index 035ca89f..9f98153b 100644 --- a/screen-write.c +++ b/screen-write.c @@ -855,15 +855,15 @@ screen_write_mousemode(struct screen_write_ctx *ctx, int state) s->mode &= ~MODE_MOUSE; } -/* - * Line feed the screen only (don't update the tty). Used for printing single - * characters, where might want to let the scroll happen naturally. - */ +/* Line feed. */ void -screen_write_linefeedscreen(struct screen_write_ctx *ctx, int wrapped) +screen_write_linefeed(struct screen_write_ctx *ctx, int wrapped) { struct screen *s = ctx->s; struct grid_line *gl; + struct tty_ctx ttyctx; + + screen_write_initctx(ctx, &ttyctx, 0); gl = &s->grid->linedata[s->grid->hsize + s->cy]; if (wrapped) @@ -875,18 +875,8 @@ screen_write_linefeedscreen(struct screen_write_ctx *ctx, int wrapped) grid_view_scroll_region_up(s->grid, s->rupper, s->rlower); else if (s->cy < screen_size_y(s) - 1) s->cy++; -} - -/* Line feed (down with scroll). */ -void -screen_write_linefeed(struct screen_write_ctx *ctx, int wrapped) -{ - struct tty_ctx ttyctx; - - screen_write_initctx(ctx, &ttyctx, 0); - - screen_write_linefeedscreen(ctx, wrapped); + ttyctx.num = wrapped; tty_write(tty_cmd_linefeed, &ttyctx); } @@ -985,7 +975,6 @@ screen_write_cell( struct screen_write_ctx *ctx, const struct grid_cell *gc, u_char *udata) { struct screen *s = ctx->s; - struct window_pane *wp = ctx->wp; struct grid *gd = s->grid; struct tty_ctx ttyctx; struct grid_utf8 gu, *tmp_gu; @@ -1062,10 +1051,7 @@ screen_write_cell( * leave the cursor to scroll naturally, unless this is only * part of the screen width. */ - if (wp->xoff != 0 || wp->sx != screen_size_x(s)) - screen_write_linefeed(ctx, 1); - else - screen_write_linefeedscreen(ctx, 1); + screen_write_linefeed(ctx, 1); s->cx = 0; /* carriage return */ } diff --git a/tty.c b/tty.c index 9f4fbc2e..93d61c0e 100644 --- a/tty.c +++ b/tty.c @@ -713,6 +713,14 @@ tty_cmd_linefeed(struct tty *tty, const struct tty_ctx *ctx) return; } + /* + * If this line wrapped naturally (ctx->num is nonzero), don't do + * anything - the cursor can just be moved to the last cell and wrap + * naturally. + */ + if (ctx->num && !(tty->term->flags & TERM_EARLYWRAP)) + return; + if (ctx->ocy == ctx->orlower) { tty_reset(tty); From 62f234ce3b3fb10633f8bbb1d4159cd5c179345a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 20 Oct 2009 17:33:33 +0000 Subject: [PATCH 0420/1180] UTF-8 combined character fixes. Thai can have treble combinations (1 x width=1 then 2 x width=0) so bump the UTF-8 cell data size to 9 and alter the code to allow this. Also break off the combining code into a separate function, handle any further combining beyond the buffer size by replacing the character with _s, and when redrawing the UTF-8 character don't assume the first part has just been printed, redraw the entire line. --- screen-write.c | 94 +++++++++++++++++++++++++++++++++++--------------- tmux.h | 2 +- tty.c | 13 ++++--- 3 files changed, 73 insertions(+), 36 deletions(-) diff --git a/screen-write.c b/screen-write.c index 9f98153b..9ed8f93b 100644 --- a/screen-write.c +++ b/screen-write.c @@ -24,6 +24,7 @@ void screen_write_initctx(struct screen_write_ctx *, struct tty_ctx *, int); void screen_write_overwrite(struct screen_write_ctx *); +int screen_write_combine(struct screen_write_ctx *, u_char *); /* Initialise writing with a window. */ void @@ -977,8 +978,8 @@ screen_write_cell( struct screen *s = ctx->s; struct grid *gd = s->grid; struct tty_ctx ttyctx; - struct grid_utf8 gu, *tmp_gu; - u_int width, xx, i; + struct grid_utf8 gu; + u_int width, xx; struct grid_cell tmp_gc, *tmp_gcp; int insert = 0; @@ -1003,34 +1004,15 @@ screen_write_cell( (s->cx != screen_size_x(s) && s->cx > screen_size_x(s) - width))) return; - /* If the width is zero, combine onto the previous character. */ + /* + * If the width is zero, combine onto the previous character, if + * there is space. + */ if (width == 0) { - if (s->cx == 0) - return; - tmp_gcp = grid_view_get_cell(gd, s->cx - 1, s->cy); - if (!(tmp_gcp->flags & GRID_FLAG_UTF8)) { - tmp_gcp->flags |= GRID_FLAG_UTF8; - memset(&gu.data, 0xff, sizeof gu.data); - *gu.data = tmp_gcp->data; - gu.width = 1; - grid_view_set_utf8(gd, s->cx - 1, s->cy, &gu); + if (screen_write_combine(ctx, udata) == 0) { + screen_write_initctx(ctx, &ttyctx, 0); + tty_write(tty_cmd_utf8character, &ttyctx); } - tmp_gu = grid_view_get_utf8(gd, s->cx - 1, s->cy); - - for (i = 0; i < UTF8_SIZE; i++) { - if (tmp_gu->data[i] == 0xff) - break; - } - memcpy(tmp_gu->data + i, udata, UTF8_SIZE - i); - - /* - * Assume the previous character has just been input. - * XXX There is no guarantee this is true, need to redraw - * entire line. - */ - screen_write_initctx(ctx, &ttyctx, 0); - ttyctx.ptr = udata; - tty_write(tty_cmd_utf8character, &ttyctx); return; } @@ -1101,6 +1083,62 @@ screen_write_cell( } } +/* Combine a UTF-8 zero-width character onto the previous. */ +int +screen_write_combine(struct screen_write_ctx *ctx, u_char *udata) +{ + struct screen *s = ctx->s; + struct grid *gd = s->grid; + struct grid_cell *gc; + struct grid_utf8 *gu, tmp_gu; + u_int i, old_size, new_size; + + /* Can't combine if at 0. */ + if (s->cx == 0) + return (-1); + + /* Retrieve the previous cell and convert to UTF-8 if not already. */ + gc = grid_view_get_cell(gd, s->cx - 1, s->cy); + if (!(gc->flags & GRID_FLAG_UTF8)) { + memset(&tmp_gu.data, 0xff, sizeof tmp_gu.data); + *tmp_gu.data = gc->data; + tmp_gu.width = 1; + + grid_view_set_utf8(gd, s->cx - 1, s->cy, &tmp_gu); + gc->flags |= GRID_FLAG_UTF8; + } + + /* Get the previous cell's UTF-8 data. */ + gu = grid_view_get_utf8(gd, s->cx - 1, s->cy); + + /* Find the new size. */ + for (new_size = 0; new_size < UTF8_SIZE; new_size++) { + if (udata[new_size] == 0xff) + break; + } + + /* And the old size. */ + for (old_size = 0; old_size < UTF8_SIZE; old_size++) { + if (gu->data[old_size] == 0xff) + break; + } + + /* If there isn't space, scrap this character. */ + if (old_size + new_size > UTF8_SIZE) { + for (i = 0; i < gu->width && i != UTF8_SIZE; i++) + gu->data[i] = '_'; + if (i != UTF8_SIZE) + gu->data[i] = 0xff; + return (0); + } + + /* Otherwise save the character. */ + memcpy(gu->data + old_size, udata, new_size); + if (old_size + new_size != UTF8_SIZE) + gu->data[old_size + new_size] = 0xff; + return (0); +} + /* * UTF-8 wide characters are a bit of an annoyance. They take up more than one * cell on the screen, so following cells must not be drawn by marking them as diff --git a/tmux.h b/tmux.h index 5cd5132b..a61040b6 100644 --- a/tmux.h +++ b/tmux.h @@ -516,7 +516,7 @@ struct grid_cell { } __packed; /* Grid cell UTF-8 data. Used instead of data in grid_cell for UTF-8 cells. */ -#define UTF8_SIZE 8 +#define UTF8_SIZE 9 struct grid_utf8 { u_char width; u_char data[UTF8_SIZE]; diff --git a/tty.c b/tty.c index 93d61c0e..9ddffb95 100644 --- a/tty.c +++ b/tty.c @@ -874,14 +874,13 @@ tty_cmd_cell(struct tty *tty, const struct tty_ctx *ctx) void tty_cmd_utf8character(struct tty *tty, const struct tty_ctx *ctx) { - u_char *ptr = ctx->ptr; - size_t i; + struct window_pane *wp = ctx->wp; - for (i = 0; i < UTF8_SIZE; i++) { - if (ptr[i] == 0xff) - break; - tty_putc(tty, ptr[i]); - } + /* + * Cannot rely on not being a partial character, so just redraw the + * whole line. + */ + tty_draw_line(tty, wp->screen, ctx->ocy, wp->xoff, wp->yoff); } void From 1af09d6330ddba2d3ffc9c15d056fe8c4321f17e Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 20 Oct 2009 19:18:28 +0000 Subject: [PATCH 0421/1180] Try to reduce the UTF-8 mess. Get rid of passing around u_char[4]s and define a struct utf8_data which has character data, size (sequence length) and width. Move UTF-8 character collection into two functions utf8_open/utf8_append in utf8.c which fill in this struct and use these functions from input.c and the various functions in screen-write.c. Space for rather more data than is necessary for one UTF-8 sequence is in the utf8_data struct because screen_write_copy is still nasty and needs to reinject the character (after combining) into screen_write_cell. --- input.c | 40 +++-------- screen-write.c | 185 ++++++++++++++++++++++--------------------------- tmux.h | 29 ++++++-- tty.c | 5 +- utf8.c | 116 +++++++++++++++++++++---------- 5 files changed, 195 insertions(+), 180 deletions(-) diff --git a/input.c b/input.c index fa7661f7..4035b2c8 100644 --- a/input.c +++ b/input.c @@ -572,15 +572,14 @@ input_state_string_escape(u_char ch, struct input_ctx *ictx) void input_state_utf8(u_char ch, struct input_ctx *ictx) { - log_debug2("-- un %zu: %hhu (%c)", ictx->off, ch, ch); + log_debug2("-- utf8 next: %zu: %hhu (%c)", ictx->off, ch, ch); - ictx->utf8_buf[ictx->utf8_off++] = ch; - if (--ictx->utf8_len != 0) - return; + if (utf8_append(&ictx->utf8data, ch)) + return; /* more to come */ input_state(ictx, input_state_first); ictx->cell.flags |= GRID_FLAG_UTF8; - screen_write_cell(&ictx->ctx, &ictx->cell, ictx->utf8_buf); + screen_write_cell(&ictx->ctx, &ictx->cell, &ictx->utf8data); ictx->cell.flags &= ~GRID_FLAG_UTF8; } @@ -590,40 +589,17 @@ input_handle_character(u_char ch, struct input_ctx *ictx) struct window_pane *wp = ictx->wp; if (ch > 0x7f && options_get_number(&wp->window->options, "utf8")) { - /* - * UTF-8 sequence. - * - * 11000010-11011111 C2-DF start of 2-byte sequence - * 11100000-11101111 E0-EF start of 3-byte sequence - * 11110000-11110100 F0-F4 start of 4-byte sequence - */ - memset(ictx->utf8_buf, 0xff, sizeof ictx->utf8_buf); - ictx->utf8_buf[0] = ch; - ictx->utf8_off = 1; - - if (ch >= 0xc2 && ch <= 0xdf) { - log_debug2("-- u2 %zu: %hhu (%c)", ictx->off, ch, ch); + if (utf8_open(&ictx->utf8data, ch)) { + log_debug2("-- utf8 size %u: %zu: %hhu (%c)", + ictx->utf8data.size, ictx->off, ch, ch); input_state(ictx, input_state_utf8); - ictx->utf8_len = 1; - return; - } - if (ch >= 0xe0 && ch <= 0xef) { - log_debug2("-- u3 %zu: %hhu (%c)", ictx->off, ch, ch); - input_state(ictx, input_state_utf8); - ictx->utf8_len = 2; - return; - } - if (ch >= 0xf0 && ch <= 0xf4) { - log_debug2("-- u4 %zu: %hhu (%c)", ictx->off, ch, ch); - input_state(ictx, input_state_utf8); - ictx->utf8_len = 3; return; } } log_debug2("-- ch %zu: %hhu (%c)", ictx->off, ch, ch); ictx->cell.data = ch; - screen_write_cell(&ictx->ctx, &ictx->cell, ictx->utf8_buf); + screen_write_cell(&ictx->ctx, &ictx->cell, NULL); } void diff --git a/screen-write.c b/screen-write.c index 9ed8f93b..8f10976f 100644 --- a/screen-write.c +++ b/screen-write.c @@ -24,7 +24,8 @@ void screen_write_initctx(struct screen_write_ctx *, struct tty_ctx *, int); void screen_write_overwrite(struct screen_write_ctx *); -int screen_write_combine(struct screen_write_ctx *, u_char *); +int screen_write_combine( + struct screen_write_ctx *, const struct utf8_data *); /* Initialise writing with a window. */ void @@ -92,10 +93,11 @@ screen_write_cstrlen(int utf8flag, const char *fmt, ...) size_t printflike2 screen_write_strlen(int utf8flag, const char *fmt, ...) { - va_list ap; - char *msg; - u_char *ptr, utf8buf[4]; - size_t left, size = 0; + va_list ap; + char *msg; + struct utf8_data utf8data; + u_char *ptr; + size_t left, size = 0; va_start(ap, fmt); xvasprintf(&msg, fmt, ap); @@ -103,24 +105,17 @@ screen_write_strlen(int utf8flag, const char *fmt, ...) ptr = msg; while (*ptr != '\0') { - if (utf8flag && *ptr > 0x7f) { - memset(utf8buf, 0xff, sizeof utf8buf); + if (utf8flag && *ptr > 0x7f && utf8_open(&utf8data, *ptr)) { + ptr++; left = strlen(ptr); - if (*ptr >= 0xc2 && *ptr <= 0xdf && left >= 2) { - memcpy(utf8buf, ptr, 2); - ptr += 2; - } else if (*ptr >= 0xe0 && *ptr <= 0xef && left >= 3) { - memcpy(utf8buf, ptr, 3); - ptr += 3; - } else if (*ptr >= 0xf0 && *ptr <= 0xf4 && left >= 4) { - memcpy(utf8buf, ptr, 4); - ptr += 4; - } else { - *utf8buf = *ptr; + if (left < utf8data.size - 1) + break; + while (utf8_append(&utf8data, *ptr)) ptr++; - } - size += utf8_width(utf8buf); + ptr++; + + size += utf8data.width; } else { size++; ptr++; @@ -159,47 +154,38 @@ void screen_write_vnputs(struct screen_write_ctx *ctx, ssize_t maxlen, struct grid_cell *gc, int utf8flag, const char *fmt, va_list ap) { - char *msg; - u_char *ptr, utf8buf[4]; - size_t left, size = 0; - int width; + char *msg; + struct utf8_data utf8data; + u_char *ptr; + size_t left, size = 0; xvasprintf(&msg, fmt, ap); ptr = msg; while (*ptr != '\0') { - if (utf8flag && *ptr > 0x7f) { - memset(utf8buf, 0xff, sizeof utf8buf); + if (utf8flag && *ptr > 0x7f && utf8_open(&utf8data, *ptr)) { + ptr++; left = strlen(ptr); - if (*ptr >= 0xc2 && *ptr <= 0xdf && left >= 2) { - memcpy(utf8buf, ptr, 2); - ptr += 2; - } else if (*ptr >= 0xe0 && *ptr <= 0xef && left >= 3) { - memcpy(utf8buf, ptr, 3); - ptr += 3; - } else if (*ptr >= 0xf0 && *ptr <= 0xf4 && left >= 4) { - memcpy(utf8buf, ptr, 4); - ptr += 4; - } else { - *utf8buf = *ptr; + if (left < utf8data.size - 1) + break; + while (utf8_append(&utf8data, *ptr)) ptr++; - } + ptr++; - width = utf8_width(utf8buf); - if (maxlen > 0 && size + width > (size_t) maxlen) { + if (maxlen > 0 && + size + utf8data.width > (size_t) maxlen) { while (size < (size_t) maxlen) { screen_write_putc(ctx, gc, ' '); size++; } break; } - size += width; - + size += utf8data.width; + gc->flags |= GRID_FLAG_UTF8; - screen_write_cell(ctx, gc, utf8buf); + screen_write_cell(ctx, gc, &utf8data); gc->flags &= ~GRID_FLAG_UTF8; - } else { if (maxlen > 0 && size + 1 > (size_t) maxlen) break; @@ -219,11 +205,11 @@ screen_write_cnputs(struct screen_write_ctx *ctx, ssize_t maxlen, struct grid_cell *gc, int utf8flag, const char *fmt, ...) { struct grid_cell lgc; + struct utf8_data utf8data; va_list ap; char *msg; - u_char *ptr, *last, utf8buf[4]; + u_char *ptr, *last; size_t left, size = 0; - int width; va_start(ap, fmt); xvasprintf(&msg, fmt, ap); @@ -247,38 +233,29 @@ screen_write_cnputs(struct screen_write_ctx *ctx, continue; } - if (utf8flag && *ptr > 0x7f) { - memset(utf8buf, 0xff, sizeof utf8buf); + if (utf8flag && *ptr > 0x7f && utf8_open(&utf8data, *ptr)) { + ptr++; left = strlen(ptr); - if (*ptr >= 0xc2 && *ptr <= 0xdf && left >= 2) { - memcpy(utf8buf, ptr, 2); - ptr += 2; - } else if (*ptr >= 0xe0 && *ptr <= 0xef && left >= 3) { - memcpy(utf8buf, ptr, 3); - ptr += 3; - } else if (*ptr >= 0xf0 && *ptr <= 0xf4 && left >= 4) { - memcpy(utf8buf, ptr, 4); - ptr += 4; - } else { - *utf8buf = *ptr; + if (left < utf8data.size - 1) + break; + while (utf8_append(&utf8data, *ptr)) ptr++; - } + ptr++; - width = utf8_width(utf8buf); - if (maxlen > 0 && size + width > (size_t) maxlen) { + if (maxlen > 0 && + size + utf8data.width > (size_t) maxlen) { while (size < (size_t) maxlen) { screen_write_putc(ctx, gc, ' '); size++; } break; } - size += width; + size += utf8data.width; lgc.flags |= GRID_FLAG_UTF8; - screen_write_cell(ctx, &lgc, utf8buf); + screen_write_cell(ctx, &lgc, &utf8data); lgc.flags &= ~GRID_FLAG_UTF8; - } else { if (maxlen > 0 && size + 1 > (size_t) maxlen) break; @@ -375,8 +352,9 @@ screen_write_copy(struct screen_write_ctx *ctx, struct grid *gd = src->grid; struct grid_line *gl; const struct grid_cell *gc; - u_char *udata; - u_int xx, yy, cx, cy, ax, bx; + const struct grid_utf8 *gu; + struct utf8_data utf8data; + u_int xx, yy, cx, cy, ax, bx, i; cx = s->cx; cy = s->cy; @@ -397,21 +375,30 @@ screen_write_copy(struct screen_write_ctx *ctx, bx = gl->cellsize; else bx = px + nx; + for (xx = ax; xx < bx; xx++) { - udata = NULL; if (xx >= gl->cellsize) gc = &grid_default_cell; - else { + else gc = &gl->celldata[xx]; - if (gc->flags & GRID_FLAG_UTF8) - udata = gl->utf8data[xx].data; + if (gc->flags & GRID_FLAG_UTF8) { + gu = &gl->utf8data[xx]; + memcpy(utf8data.data, + gu->data, sizeof utf8data.data); + utf8data.width = gu->width; + utf8data.size = 0; + for (i = 0; i < UTF8_SIZE; i++) { + if (gu->data[i] == 0xff) + break; + utf8data.size++; + } } - screen_write_cell(ctx, gc, udata); + screen_write_cell(ctx, gc, &utf8data); } if (px + nx == gd->sx && px + nx > gl->cellsize) screen_write_clearendofline(ctx); } else - screen_write_clearline(ctx); + screen_write_clearline(ctx); cy++; screen_write_cursormove(ctx, cx, cy); } @@ -972,8 +959,8 @@ screen_write_clearscreen(struct screen_write_ctx *ctx) /* Write cell data. */ void -screen_write_cell( - struct screen_write_ctx *ctx, const struct grid_cell *gc, u_char *udata) +screen_write_cell(struct screen_write_ctx *ctx, + const struct grid_cell *gc, const struct utf8_data *utf8data) { struct screen *s = ctx->s; struct grid *gd = s->grid; @@ -988,12 +975,9 @@ screen_write_cell( return; /* Find character width. */ - if (gc->flags & GRID_FLAG_UTF8) { - width = utf8_width(udata); - - gu.width = width; - memcpy(&gu.data, udata, sizeof gu.data); - } else + if (gc->flags & GRID_FLAG_UTF8) + width = utf8data->width; + else width = 1; /* @@ -1009,7 +993,7 @@ screen_write_cell( * there is space. */ if (width == 0) { - if (screen_write_combine(ctx, udata) == 0) { + if (screen_write_combine(ctx, utf8data) == 0) { screen_write_initctx(ctx, &ttyctx, 0); tty_write(tty_cmd_utf8character, &ttyctx); } @@ -1028,11 +1012,6 @@ screen_write_cell( /* Check this will fit on the current line and wrap if not. */ if (s->cx > screen_size_x(s) - width) { - /* - * Don't update the terminal now, just update the screen and - * leave the cursor to scroll naturally, unless this is only - * part of the screen width. - */ screen_write_linefeed(ctx, 1); s->cx = 0; /* carriage return */ } @@ -1056,8 +1035,15 @@ screen_write_cell( /* Set the cell. */ grid_view_set_cell(gd, s->cx, s->cy, gc); - if (gc->flags & GRID_FLAG_UTF8) + if (gc->flags & GRID_FLAG_UTF8) { + /* Construct UTF-8 and write it. */ + gu.width = utf8data->width; + memset(gu.data, 0xff, sizeof gu.data); + if (utf8data->size > sizeof gu.data) + fatalx("UTF-8 data overflow"); + memcpy(gu.data, utf8data->data, utf8data->size); grid_view_set_utf8(gd, s->cx, s->cy, &gu); + } /* Move the cursor. */ s->cx += width; @@ -1085,13 +1071,14 @@ screen_write_cell( /* Combine a UTF-8 zero-width character onto the previous. */ int -screen_write_combine(struct screen_write_ctx *ctx, u_char *udata) +screen_write_combine( + struct screen_write_ctx *ctx, const struct utf8_data *utf8data) { struct screen *s = ctx->s; struct grid *gd = s->grid; struct grid_cell *gc; struct grid_utf8 *gu, tmp_gu; - u_int i, old_size, new_size; + u_int i, old_size; /* Can't combine if at 0. */ if (s->cx == 0) @@ -1108,23 +1095,15 @@ screen_write_combine(struct screen_write_ctx *ctx, u_char *udata) gc->flags |= GRID_FLAG_UTF8; } - /* Get the previous cell's UTF-8 data. */ + /* Get the previous cell's UTF-8 data and its size. */ gu = grid_view_get_utf8(gd, s->cx - 1, s->cy); - - /* Find the new size. */ - for (new_size = 0; new_size < UTF8_SIZE; new_size++) { - if (udata[new_size] == 0xff) - break; - } - - /* And the old size. */ for (old_size = 0; old_size < UTF8_SIZE; old_size++) { if (gu->data[old_size] == 0xff) break; } /* If there isn't space, scrap this character. */ - if (old_size + new_size > UTF8_SIZE) { + if (old_size + utf8data->size > UTF8_SIZE) { for (i = 0; i < gu->width && i != UTF8_SIZE; i++) gu->data[i] = '_'; if (i != UTF8_SIZE) @@ -1133,9 +1112,9 @@ screen_write_combine(struct screen_write_ctx *ctx, u_char *udata) } /* Otherwise save the character. */ - memcpy(gu->data + old_size, udata, new_size); - if (old_size + new_size != UTF8_SIZE) - gu->data[old_size + new_size] = 0xff; + memcpy(gu->data + old_size, utf8data->data, utf8data->size); + if (old_size + utf8data->size != UTF8_SIZE) + gu->data[old_size + utf8data->size] = 0xff; return (0); } diff --git a/tmux.h b/tmux.h index a61040b6..850c2f5b 100644 --- a/tmux.h +++ b/tmux.h @@ -477,6 +477,23 @@ struct mode_key_table { #define MODE_KKEYPAD 0x8 #define MODE_MOUSE 0x10 +/* + * A single UTF-8 character. + * + * The data member in this must be UTF8_SIZE to allow screen_write_copy to + * reinject stored UTF-8 data back into screen_write_cell after combining (ugh + * XXX XXX). + */ +#define UTF8_SIZE 9 +struct utf8_data { + u_char data[UTF8_SIZE]; + + size_t have; + size_t size; + + u_int width; +}; + /* Grid output. */ #if defined(DEBUG) && \ ((defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || \ @@ -516,7 +533,6 @@ struct grid_cell { } __packed; /* Grid cell UTF-8 data. Used instead of data in grid_cell for UTF-8 cells. */ -#define UTF8_SIZE 9 struct grid_utf8 { u_char width; u_char data[UTF8_SIZE]; @@ -672,9 +688,7 @@ struct input_ctx { #define STRING_APPLICATION 1 #define STRING_NAME 2 - u_char utf8_buf[4]; - u_int utf8_len; - u_int utf8_off; + struct utf8_data utf8data; u_char intermediate; void *(*state)(u_char, struct input_ctx *); @@ -1682,8 +1696,8 @@ void screen_write_kkeypadmode(struct screen_write_ctx *, int); void screen_write_clearendofscreen(struct screen_write_ctx *); void screen_write_clearstartofscreen(struct screen_write_ctx *); void screen_write_clearscreen(struct screen_write_ctx *); -void screen_write_cell( - struct screen_write_ctx *, const struct grid_cell *, u_char *); +void screen_write_cell(struct screen_write_ctx *, + const struct grid_cell *, const struct utf8_data *); /* screen-redraw.c */ void screen_redraw_screen(struct client *, int); @@ -1838,7 +1852,8 @@ void session_group_synchronize1(struct session *, struct session *); /* utf8.c */ void utf8_build(void); -int utf8_width(const u_char *); +int utf8_open(struct utf8_data *, u_char); +int utf8_append(struct utf8_data *, u_char); /* procname.c */ char *get_proc_name(int, char *); diff --git a/tty.c b/tty.c index 9ddffb95..ee725edf 100644 --- a/tty.c +++ b/tty.c @@ -342,7 +342,7 @@ tty_putc(struct tty *tty, u_char ch) void tty_pututf8(struct tty *tty, const struct grid_utf8 *gu) { - u_int i, width; + u_int i; for (i = 0; i < UTF8_SIZE; i++) { if (gu->data[i] == 0xff) @@ -352,8 +352,7 @@ tty_pututf8(struct tty *tty, const struct grid_utf8 *gu) write(tty->log_fd, &gu->data[i], 1); } - width = utf8_width(gu->data); - tty->cx += width; + tty->cx += gu->width; } void diff --git a/utf8.c b/utf8.c index 9b499d1c..52cc709e 100644 --- a/utf8.c +++ b/utf8.c @@ -196,9 +196,56 @@ struct utf8_width_entry utf8_width_table[] = { struct utf8_width_entry *utf8_width_root = NULL; int utf8_overlap(struct utf8_width_entry *, struct utf8_width_entry *); -void utf8_print(struct utf8_width_entry *, int); -u_int utf8_combine(const u_char *); +u_int utf8_combine(const struct utf8_data *); +u_int utf8_width(const struct utf8_data *); +/* + * Open UTF-8 sequence. + * + * 11000010-11011111 C2-DF start of 2-byte sequence + * 11100000-11101111 E0-EF start of 3-byte sequence + * 11110000-11110100 F0-F4 start of 4-byte sequence + * + * Returns 1 if more UTF-8 to come, 0 if not UTF-8. + */ +int +utf8_open(struct utf8_data *utf8data, u_char ch) +{ + memset(utf8data, 0, sizeof *utf8data); + if (ch >= 0xc2 && ch <= 0xdf) + utf8data->size = 2; + else if (ch >= 0xe0 && ch <= 0xef) + utf8data->size = 3; + else if (ch >= 0xf0 && ch <= 0xf4) + utf8data->size = 4; + else + return (0); + utf8_append(utf8data, ch); + return (1); +} + +/* + * Append character to UTF-8, closing if finished. + * + * Returns 1 if more UTF-8 data to come, 1 if finished. + */ +int +utf8_append(struct utf8_data *utf8data, u_char ch) +{ + if (utf8data->have >= utf8data->size) + fatalx("UTF-8 character overflow"); + if (utf8data->size > sizeof utf8data->data) + fatalx("UTF-8 character size too large"); + + utf8data->data[utf8data->have++] = ch; + if (utf8data->have != utf8data->size) + return (1); + + utf8data->width = utf8_width(utf8data); + return (0); +} + +/* Check if two width tree entries overlap. */ int utf8_overlap( struct utf8_width_entry *item1, struct utf8_width_entry *item2) @@ -214,6 +261,7 @@ utf8_overlap( return (0); } +/* Build UTF-8 width tree. */ void utf8_build(void) { @@ -240,52 +288,50 @@ utf8_build(void) } } -void -utf8_print(struct utf8_width_entry *node, int n) -{ - log_debug("%*s%04x -> %04x", n, " ", node->first, node->last); - if (node->left != NULL) - utf8_print(node->left, n + 1); - if (node->right != NULL) - utf8_print(node->right, n + 1); -} - +/* Combine UTF-8 into 32-bit Unicode. */ u_int -utf8_combine(const u_char *data) +utf8_combine(const struct utf8_data *utf8data) { - u_int uvalue; + u_int value; - if (data[1] == 0xff) - uvalue = data[0]; - else if (data[2] == 0xff) { - uvalue = data[1] & 0x3f; - uvalue |= (data[0] & 0x1f) << 6; - } else if (data[3] == 0xff) { - uvalue = data[2] & 0x3f; - uvalue |= (data[1] & 0x3f) << 6; - uvalue |= (data[0] & 0x0f) << 12; - } else { - uvalue = data[3] & 0x3f; - uvalue |= (data[2] & 0x3f) << 6; - uvalue |= (data[1] & 0x3f) << 12; - uvalue |= (data[0] & 0x3f) << 18; + value = 0xff; + switch (utf8data->size) { + case 1: + value = utf8data->data[0]; + break; + case 2: + value = utf8data->data[1] & 0x3f; + value |= (utf8data->data[0] & 0x1f) << 6; + break; + case 3: + value = utf8data->data[2] & 0x3f; + value |= (utf8data->data[1] & 0x3f) << 6; + value |= (utf8data->data[0] & 0x0f) << 12; + break; + case 4: + value = utf8data->data[3] & 0x3f; + value |= (utf8data->data[2] & 0x3f) << 6; + value |= (utf8data->data[1] & 0x3f) << 12; + value |= (utf8data->data[0] & 0x3f) << 18; + break; } - return (uvalue); + return (value); } -int -utf8_width(const u_char *udata) +/* Lookup width of UTF-8 data in tree. */ +u_int +utf8_width(const struct utf8_data *utf8data) { struct utf8_width_entry *item; - u_int uvalue; + u_int value; - uvalue = utf8_combine(udata); + value = utf8_combine(utf8data); item = utf8_width_root; while (item != NULL) { - if (uvalue < item->first) + if (value < item->first) item = item->left; - else if (uvalue > item->last) + else if (value > item->last) item = item->right; else return (item->width); From 480f5d31848dd79ed6d127a31899262cbe17626a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 20 Oct 2009 21:35:25 +0000 Subject: [PATCH 0422/1180] Correctly nuke the EOL $ marker when scrolling, reported by martynas@, thanks. --- window-copy.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/window-copy.c b/window-copy.c index cdd84b4c..499ead33 100644 --- a/window-copy.c +++ b/window-copy.c @@ -1088,7 +1088,7 @@ window_copy_cursor_up(struct window_pane *wp, int scroll_only) data->cx = data->lastcx; if (scroll_only || data->cy == 0) { window_copy_scroll_down(wp, 1); - if (scroll_only && window_copy_update_selection(wp)) + if (scroll_only) window_copy_redraw_lines(wp, data->cy, 2); } else { window_copy_update_cursor(wp, data->cx, data->cy - 1); @@ -1119,7 +1119,7 @@ window_copy_cursor_down(struct window_pane *wp, int scroll_only) data->cx = data->lastcx; if (scroll_only || data->cy == screen_size_y(s) - 1) { window_copy_scroll_up(wp, 1); - if (scroll_only && window_copy_update_selection(wp)) + if (scroll_only && data->cy > 0) window_copy_redraw_lines(wp, data->cy - 1, 2); } else { window_copy_update_cursor(wp, data->cx, data->cy + 1); @@ -1250,7 +1250,10 @@ window_copy_scroll_up(struct window_pane *wp, u_int ny) screen_write_deleteline(&ctx, ny); window_copy_write_lines(wp, &ctx, screen_size_y(s) - ny, ny); window_copy_write_line(wp, &ctx, 0); - window_copy_write_line(wp, &ctx, 1); + if (screen_size_y(s) > 1) + window_copy_write_line(wp, &ctx, 1); + if (screen_size_y(s) > 3) + window_copy_write_line(wp, &ctx, screen_size_y(s) - 2); if (s->sel.flag && screen_size_y(s) > ny) window_copy_write_line(wp, &ctx, screen_size_y(s) - ny - 1); screen_write_cursormove(&ctx, data->cx, data->cy); From 6f2169037ecbadef09520e50ec4f2ef029f097a9 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 20 Oct 2009 22:15:32 +0000 Subject: [PATCH 0423/1180] Sort out stdout before stdin/stderr in case the stdout side of the pipe got one of their fds. --- job.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/job.c b/job.c index 6a824fa6..09ef6bc0 100644 --- a/job.c +++ b/job.c @@ -153,6 +153,12 @@ job_run(struct job *job) sigreset(); /* XXX environ? */ + close(out[1]); + if (dup2(out[0], STDOUT_FILENO) == -1) + fatal("dup2 failed"); + if (out[0] != STDOUT_FILENO) + close(out[0]); + nullfd = open(_PATH_DEVNULL, O_RDONLY, 0); if (nullfd < 0) fatal("open failed"); @@ -163,12 +169,6 @@ job_run(struct job *job) if (nullfd != STDIN_FILENO && nullfd != STDERR_FILENO) close(nullfd); - close(out[1]); - if (dup2(out[0], STDOUT_FILENO) == -1) - fatal("dup2 failed"); - if (out[0] != STDOUT_FILENO) - close(out[0]); - execl(_PATH_BSHELL, "sh", "-c", job->cmd, (char *) NULL); fatal("execl failed"); default: /* parent */ From 9afb0d739e96a8b5a8ac4a2ae19803443135d0e2 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 20 Oct 2009 22:17:33 +0000 Subject: [PATCH 0424/1180] %zu not %u, doh. --- input.c | 2 +- utf8.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/input.c b/input.c index 4035b2c8..ff7990e0 100644 --- a/input.c +++ b/input.c @@ -590,7 +590,7 @@ input_handle_character(u_char ch, struct input_ctx *ictx) if (ch > 0x7f && options_get_number(&wp->window->options, "utf8")) { if (utf8_open(&ictx->utf8data, ch)) { - log_debug2("-- utf8 size %u: %zu: %hhu (%c)", + log_debug2("-- utf8 size %zu: %zu: %hhu (%c)", ictx->utf8data.size, ictx->off, ch, ch); input_state(ictx, input_state_utf8); return; diff --git a/utf8.c b/utf8.c index 52cc709e..00b1c736 100644 --- a/utf8.c +++ b/utf8.c @@ -227,7 +227,7 @@ utf8_open(struct utf8_data *utf8data, u_char ch) /* * Append character to UTF-8, closing if finished. * - * Returns 1 if more UTF-8 data to come, 1 if finished. + * Returns 1 if more UTF-8 data to come, 0 if finished. */ int utf8_append(struct utf8_data *utf8data, u_char ch) From 7825871d6a04494c704521abb6fc4240216382ca Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 21 Oct 2009 07:24:23 +0000 Subject: [PATCH 0425/1180] Getting the read and write ends of the pipe the right way round is usually recommended. DOH. --- job.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/job.c b/job.c index 09ef6bc0..dea37784 100644 --- a/job.c +++ b/job.c @@ -153,13 +153,13 @@ job_run(struct job *job) sigreset(); /* XXX environ? */ - close(out[1]); - if (dup2(out[0], STDOUT_FILENO) == -1) + if (dup2(out[1], STDOUT_FILENO) == -1) fatal("dup2 failed"); - if (out[0] != STDOUT_FILENO) - close(out[0]); + if (out[1] != STDOUT_FILENO) + close(out[1]); + close(out[0]); - nullfd = open(_PATH_DEVNULL, O_RDONLY, 0); + nullfd = open(_PATH_DEVNULL, O_RDWR, 0); if (nullfd < 0) fatal("open failed"); if (dup2(nullfd, STDIN_FILENO) == -1) @@ -172,9 +172,9 @@ job_run(struct job *job) execl(_PATH_BSHELL, "sh", "-c", job->cmd, (char *) NULL); fatal("execl failed"); default: /* parent */ - close(out[0]); + close(out[1]); - job->fd = out[1]; + job->fd = out[0]; if ((mode = fcntl(job->fd, F_GETFL)) == -1) fatal("fcntl failed"); if (fcntl(job->fd, F_SETFL, mode|O_NONBLOCK) == -1) From 683ddbc466bbd6ff2a890c11edccc482bfe0dc87 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 21 Oct 2009 09:36:53 +0000 Subject: [PATCH 0426/1180] Some terminals don't correctly clear their let's-wrap flag after changing the scroll region (which moves the cursor to 0,0). This means that if the cursor was at the edge of the screen, any further output after scroll region change incorrectly causes a line wrap. Add a workaround to move the cursor to position 0 if it is at the screen edge before changing scroll region. --- tty.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tty.c b/tty.c index ee725edf..177648b7 100644 --- a/tty.c +++ b/tty.c @@ -955,6 +955,15 @@ tty_region(struct tty *tty, u_int rupper, u_int rlower) tty->rupper = rupper; tty->rlower = rlower; + /* + * Some terminals (such as PuTTY) do not correctly reset the cursor to + * 0,0 if it is beyond the last column (they do not reset their wrap + * flag so further output causes a line feed). As a workaround, do an + * explicit move to 0 first. + */ + if (tty->cx >= tty->sx) + tty_cursor(tty, 0, tty->cy); + tty->cx = 0; tty->cy = 0; From 9b5da97e6f55b65fc892aa702fbe41aee9159865 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 21 Oct 2009 13:42:44 +0000 Subject: [PATCH 0427/1180] Don't redraw the scroll region on linefeed/reverse index unless it is necessary (the cursor is at the bottom/top). Should fix slow cursor movement when using vi in a pane spotted by pirofti@. --- tty.c | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/tty.c b/tty.c index 177648b7..89b245b1 100644 --- a/tty.c +++ b/tty.c @@ -684,20 +684,21 @@ tty_cmd_reverseindex(struct tty *tty, const struct tty_ctx *ctx) struct window_pane *wp = ctx->wp; struct screen *s = wp->screen; + if (ctx->ocy != ctx->orupper) + return; + if (wp->xoff != 0 || screen_size_x(s) < tty->sx || !tty_term_has(tty->term, TTYC_CSR)) { tty_redraw_region(tty, ctx); return; } - if (ctx->ocy == ctx->orupper) { - tty_reset(tty); - - tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower); - tty_cursor_pane(tty, ctx, ctx->ocx, ctx->orupper); - - tty_putcode(tty, TTYC_RI); - } + tty_reset(tty); + + tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower); + tty_cursor_pane(tty, ctx, ctx->ocx, ctx->orupper); + + tty_putcode(tty, TTYC_RI); } void @@ -706,6 +707,9 @@ tty_cmd_linefeed(struct tty *tty, const struct tty_ctx *ctx) struct window_pane *wp = ctx->wp; struct screen *s = wp->screen; + if (ctx->ocy != ctx->orlower) + return; + if (wp->xoff != 0 || screen_size_x(s) < tty->sx || !tty_term_has(tty->term, TTYC_CSR)) { tty_redraw_region(tty, ctx); @@ -720,14 +724,12 @@ tty_cmd_linefeed(struct tty *tty, const struct tty_ctx *ctx) if (ctx->num && !(tty->term->flags & TERM_EARLYWRAP)) return; - if (ctx->ocy == ctx->orlower) { - tty_reset(tty); - - tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower); - tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); - - tty_putc(tty, '\n'); - } + tty_reset(tty); + + tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower); + tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); + + tty_putc(tty, '\n'); } void From af2b0f452c1376c31d9261b0681927ed63f2f822 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 21 Oct 2009 13:48:27 +0000 Subject: [PATCH 0428/1180] Tweak descriptions for up/down pane to be clearer. --- tmux.1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tmux.1 b/tmux.1 index 2992bb23..e25657e2 100644 --- a/tmux.1 +++ b/tmux.1 @@ -725,7 +725,7 @@ to keys. .It Ic down-pane Op Fl t Ar target-pane .D1 (alias: Ic downp ) -Move down a pane. +Change the active pane to the next pane (higher index). .It Xo Ic find-window .Op Fl t Ar target-window .Ar match-string @@ -1013,7 +1013,7 @@ is specified and the window is linked to only one session, it is unlinked and destroyed. .It Ic up-pane Op Fl t Ar target-pane .D1 (alias: Ic upp ) -Move up a pane. +Change the active pane to the previous pane (lower index). .El .Sh KEY BINDINGS .Nm From dd46f634fe807e4819f8ba3c5cc6f290e530a54e Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 21 Oct 2009 16:52:30 +0000 Subject: [PATCH 0429/1180] Now we are correctly not redrawing the whole pane on linefeed, redo the last-cursor-position code to move to the right position when panes reach EOL. --- tty.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/tty.c b/tty.c index 89b245b1..249e65c1 100644 --- a/tty.c +++ b/tty.c @@ -851,17 +851,24 @@ tty_cmd_cell(struct tty *tty, const struct tty_ctx *ctx) { struct window_pane *wp = ctx->wp; struct screen *s = wp->screen; - u_int cx; + u_int cx, sx; tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower); - /* - * Should the cursor be in the last cursor position ready for a natural - * wrap? If so - and it isn't - move to and rewrite the last cell. - */ - if (!(tty->term->flags & TERM_EARLYWRAP) && - ctx->ocx + wp->xoff > tty->sx - ctx->last_width) { - if (tty->cx < tty->sx) { + /* Is the cursor in the very last position? */ + if (ctx->ocx > wp->sx - ctx->last_width) { + if (wp->xoff != 0 || wp->sx != tty->sx) { + /* + * The pane doesn't fill the entire line, the linefeed + * will already have happened, so just move the cursor. + */ + tty_cursor_pane(tty, ctx, 0, ctx->ocy + 1); + } else if (tty->cx < tty->sx) { + /* + * The cursor isn't in the last position already, so + * move as far left as possinble and redraw the last + * cell to move into the last position. + */ cx = screen_size_x(s) - ctx->last_width; tty_cursor_pane(tty, ctx, cx, ctx->ocy); tty_cell(tty, &ctx->last_cell, &ctx->last_utf8); From 9a4855295b9116e9bfe9003ec480e6bc27826bc7 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 21 Oct 2009 18:12:31 +0000 Subject: [PATCH 0430/1180] Nuke dead store. --- cmd-pipe-pane.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cmd-pipe-pane.c b/cmd-pipe-pane.c index 9a4f44d3..4fa43184 100644 --- a/cmd-pipe-pane.c +++ b/cmd-pipe-pane.c @@ -47,11 +47,10 @@ int cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx) { struct cmd_target_data *data = self->data; - struct winlink *wl; struct window_pane *wp; int old_fd, pipe_fd[2], null_fd, mode; - if ((wl = cmd_find_pane(ctx, data->target, NULL, &wp)) == NULL) + if (cmd_find_pane(ctx, data->target, NULL, &wp) == NULL) return (-1); /* Destroy the old pipe. */ From a22c06a2d6fddd0dda33219ef79b5b646fc973b9 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 21 Oct 2009 18:20:16 +0000 Subject: [PATCH 0431/1180] Remove unused function. --- job.c | 13 ------------- tmux.h | 1 - 2 files changed, 14 deletions(-) diff --git a/job.c b/job.c index dea37784..93ff0644 100644 --- a/job.c +++ b/job.c @@ -48,19 +48,6 @@ job_tree_init(struct jobs *jobs) RB_INIT(jobs); } -/* Count the number of jobs in a tree. */ -u_int -job_tree_size(struct jobs *jobs) -{ - struct job *job; - u_int n; - - n = 0; - RB_FOREACH(job, jobs, jobs) - n++; - return (n); -} - /* Destroy a job tree. */ void job_tree_free(struct jobs *jobs) diff --git a/tmux.h b/tmux.h index 850c2f5b..0e89a135 100644 --- a/tmux.h +++ b/tmux.h @@ -1252,7 +1252,6 @@ int job_cmp(struct job *, struct job *); RB_PROTOTYPE(jobs, job, entry, job_cmp); void job_tree_init(struct jobs *); void job_tree_free(struct jobs *); -u_int job_tree_size(struct jobs *); struct job *job_get(struct jobs *, const char *); struct job *job_add(struct jobs *, struct client *, const char *, void (*)(struct job *), void (*)(void *), void *); From 59e667906f2530a9dc7a6bdb2871c7f2a27a4906 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 21 Oct 2009 19:27:09 +0000 Subject: [PATCH 0432/1180] Unused variable. --- tty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tty.c b/tty.c index 249e65c1..596779e1 100644 --- a/tty.c +++ b/tty.c @@ -851,7 +851,7 @@ tty_cmd_cell(struct tty *tty, const struct tty_ctx *ctx) { struct window_pane *wp = ctx->wp; struct screen *s = wp->screen; - u_int cx, sx; + u_int cx; tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower); From 90ad041fa581a907a6efd1d9764b80f37d373447 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 21 Oct 2009 20:11:47 +0000 Subject: [PATCH 0433/1180] Client tidying: get rid of client_ctx struct in favour of two variables in client.c, and move the functions in client-fn.c into other files. --- Makefile | 2 +- client-fn.c | 90 -------------------------------- client.c | 148 ++++++++++++++++++++++++++-------------------------- tmux.c | 93 +++++++++++++++++++++++---------- tmux.h | 23 +------- 5 files changed, 140 insertions(+), 216 deletions(-) delete mode 100644 client-fn.c diff --git a/Makefile b/Makefile index 32195762..cf856b6c 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # $OpenBSD$ PROG= tmux -SRCS= attributes.c buffer-poll.c buffer.c cfg.c client-fn.c \ +SRCS= attributes.c buffer-poll.c buffer.c cfg.c \ client.c clock.c cmd-attach-session.c cmd-bind-key.c \ cmd-break-pane.c cmd-choose-session.c cmd-choose-window.c \ cmd-clear-history.c cmd-clock-mode.c cmd-command-prompt.c \ diff --git a/client-fn.c b/client-fn.c deleted file mode 100644 index 789ac427..00000000 --- a/client-fn.c +++ /dev/null @@ -1,90 +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 -#include -#include - -#include "tmux.h" - -void -client_fill_session(struct msg_command_data *data) -{ - char *env, *ptr1, *ptr2, buf[256]; - size_t len; - const char *errstr; - long long ll; - - data->pid = -1; - if ((env = getenv("TMUX")) == NULL) - return; - - if ((ptr2 = strrchr(env, ',')) == NULL || ptr2 == env) - return; - for (ptr1 = ptr2 - 1; ptr1 > env && *ptr1 != ','; ptr1--) - ; - if (*ptr1 != ',') - return; - ptr1++; - ptr2++; - - len = ptr2 - ptr1 - 1; - if (len > (sizeof buf) - 1) - return; - memcpy(buf, ptr1, len); - buf[len] = '\0'; - - ll = strtonum(buf, 0, LONG_MAX, &errstr); - if (errstr != NULL) - return; - data->pid = ll; - - ll = strtonum(ptr2, 0, UINT_MAX, &errstr); - if (errstr != NULL) - return; - data->idx = ll; -} - -void -client_write_server( - struct client_ctx *cctx, enum msgtype type, void *buf, size_t len) -{ - imsg_compose(&cctx->ibuf, type, PROTOCOL_VERSION, -1, -1, buf, len); -} - -void -client_suspend(void) -{ - struct sigaction act; - - memset(&act, 0, sizeof act); - sigemptyset(&act.sa_mask); - act.sa_flags = SA_RESTART; - - act.sa_handler = SIG_DFL; - if (sigaction(SIGTSTP, &act, NULL) != 0) - fatal("sigaction failed"); - - act.sa_handler = sighandler; - if (sigaction(SIGCONT, &act, NULL) != 0) - fatal("sigaction failed"); - - kill(getpid(), SIGTSTP); -} diff --git a/client.c b/client.c index e7118a3b..b048645e 100644 --- a/client.c +++ b/client.c @@ -33,10 +33,16 @@ #include "tmux.h" -void client_send_environ(struct client_ctx *); +struct imsgbuf client_ibuf; +const char *client_exitmsg; -int -client_init(char *path, struct client_ctx *cctx, int cmdflags, int flags) +void client_send_environ(void); +void client_write_server(enum msgtype, void *, size_t); +int client_dispatch(void); +void client_suspend(void); + +struct imsgbuf * +client_init(char *path, int cmdflags, int flags) { struct sockaddr_un sa; struct stat sb; @@ -93,10 +99,10 @@ server_started: fatal("fcntl failed"); if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) fatal("fcntl failed"); - imsg_init(&cctx->ibuf, fd); + imsg_init(&client_ibuf, fd); if (cmdflags & CMD_SENDENVIRON) - client_send_environ(cctx); + client_send_environ(); if (isatty(STDIN_FILENO)) { if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1) fatal("ioctl(TIOCGWINSZ)"); @@ -114,23 +120,23 @@ server_started: if ((fd2 = dup(STDIN_FILENO)) == -1) fatal("dup failed"); - imsg_compose(&cctx->ibuf, MSG_IDENTIFY, + imsg_compose(&client_ibuf, MSG_IDENTIFY, PROTOCOL_VERSION, -1, fd2, &data, sizeof data); } - return (0); + return (&client_ibuf); start_failed: log_warnx("server failed to start"); - return (1); + return (NULL); not_found: log_warn("server not found"); - return (1); + return (NULL); } void -client_send_environ(struct client_ctx *cctx) +client_send_environ(void) { char **var; struct msg_environ_data data; @@ -138,12 +144,18 @@ client_send_environ(struct client_ctx *cctx) for (var = environ; *var != NULL; var++) { if (strlcpy(data.var, *var, sizeof data.var) >= sizeof data.var) continue; - client_write_server(cctx, MSG_ENVIRON, &data, sizeof data); + client_write_server(MSG_ENVIRON, &data, sizeof data); } } -int -client_main(struct client_ctx *cctx) +void +client_write_server(enum msgtype type, void *buf, size_t len) +{ + imsg_compose(&client_ibuf, type, PROTOCOL_VERSION, -1, -1, buf, len); +} + +__dead void +client_main(void) { struct pollfd pfd; int n, nfds; @@ -158,29 +170,31 @@ client_main(struct client_ctx *cctx) * MSG_READY switched to here. Process anything outstanding now so poll * doesn't hang waiting for messages that have already arrived. */ - if (client_msg_dispatch(cctx) != 0) + if (client_dispatch() != 0) goto out; for (;;) { - if (sigterm) - client_write_server(cctx, MSG_EXITING, NULL, 0); + if (sigterm) { + client_exitmsg = "terminated"; + client_write_server(MSG_EXITING, NULL, 0); + } if (sigchld) { waitpid(WAIT_ANY, NULL, WNOHANG); sigchld = 0; } if (sigwinch) { - client_write_server(cctx, MSG_RESIZE, NULL, 0); + client_write_server(MSG_RESIZE, NULL, 0); sigwinch = 0; } if (sigcont) { siginit(); - client_write_server(cctx, MSG_WAKEUP, NULL, 0); + client_write_server(MSG_WAKEUP, NULL, 0); sigcont = 0; } - pfd.fd = cctx->ibuf.fd; + pfd.fd = client_ibuf.fd; pfd.events = POLLIN; - if (cctx->ibuf.w.queued > 0) + if (client_ibuf.w.queued > 0) pfd.events |= POLLOUT; if ((nfds = poll(&pfd, 1, INFTIM)) == -1) { @@ -195,67 +209,41 @@ client_main(struct client_ctx *cctx) fatalx("socket error"); if (pfd.revents & POLLIN) { - if ((n = imsg_read(&cctx->ibuf)) == -1 || n == 0) { - cctx->exittype = CCTX_DIED; + if ((n = imsg_read(&client_ibuf)) == -1 || n == 0) { + client_exitmsg = "lost server"; break; } - if (client_msg_dispatch(cctx) != 0) + if (client_dispatch() != 0) break; } if (pfd.revents & POLLOUT) { - if (msgbuf_write(&cctx->ibuf.w) < 0) { - cctx->exittype = CCTX_DIED; + if (msgbuf_write(&client_ibuf.w) < 0) { + client_exitmsg = "lost server"; break; } } } out: - /* - * Print exit status message, unless running as a login shell where it - * would either be pointless or irritating. - */ - if (sigterm) { - printf("[terminated]\n"); - return (1); - } - switch (cctx->exittype) { - case CCTX_DIED: - printf("[lost server]\n"); - return (0); - case CCTX_SHUTDOWN: - if (!login_shell) - printf("[server exited]\n"); - return (0); - case CCTX_EXIT: - if (cctx->errstr != NULL) { - printf("[error: %s]\n", cctx->errstr); - return (1); - } - if (!login_shell) - printf("[exited]\n"); - return (0); - case CCTX_DETACH: + /* Print the exit message, if any, and exit. */ + if (client_exitmsg != NULL) { if (!login_shell) - printf("[detached]\n"); - return (0); - default: - printf("[unknown error]\n"); - return (1); + printf("[%s]\n", client_exitmsg); + exit(1); } + exit(0); } int -client_msg_dispatch(struct client_ctx *cctx) +client_dispatch(void) { struct imsg imsg; - struct msg_print_data printdata; struct msg_lock_data lockdata; ssize_t n, datalen; for (;;) { - if ((n = imsg_get(&cctx->ibuf, &imsg)) == -1) + if ((n = imsg_get(&client_ibuf, &imsg)) == -1) fatalx("imsg_get failed"); if (n == 0) return (0); @@ -266,25 +254,15 @@ client_msg_dispatch(struct client_ctx *cctx) if (datalen != 0) fatalx("bad MSG_DETACH size"); - client_write_server(cctx, MSG_EXITING, NULL, 0); - cctx->exittype = CCTX_DETACH; + client_write_server(MSG_EXITING, NULL, 0); + client_exitmsg = "detached"; break; - case MSG_ERROR: - if (datalen != sizeof printdata) - fatalx("bad MSG_ERROR size"); - memcpy(&printdata, imsg.data, sizeof printdata); - - printdata.msg[(sizeof printdata.msg) - 1] = '\0'; - /* Error string used after exit message from server. */ - cctx->errstr = xstrdup(printdata.msg); - imsg_free(&imsg); - return (-1); case MSG_EXIT: if (datalen != 0) fatalx("bad MSG_EXIT size"); - client_write_server(cctx, MSG_EXITING, NULL, 0); - cctx->exittype = CCTX_EXIT; + client_write_server(MSG_EXITING, NULL, 0); + client_exitmsg = "exited"; break; case MSG_EXITED: if (datalen != 0) @@ -296,8 +274,8 @@ client_msg_dispatch(struct client_ctx *cctx) if (datalen != 0) fatalx("bad MSG_SHUTDOWN size"); - client_write_server(cctx, MSG_EXITING, NULL, 0); - cctx->exittype = CCTX_SHUTDOWN; + client_write_server(MSG_EXITING, NULL, 0); + client_exitmsg = "server exited"; break; case MSG_SUSPEND: if (datalen != 0) @@ -312,7 +290,7 @@ client_msg_dispatch(struct client_ctx *cctx) lockdata.cmd[(sizeof lockdata.cmd) - 1] = '\0'; system(lockdata.cmd); - client_write_server(cctx, MSG_UNLOCK, NULL, 0); + client_write_server(MSG_UNLOCK, NULL, 0); break; default: fatalx("unexpected message"); @@ -321,3 +299,23 @@ client_msg_dispatch(struct client_ctx *cctx) imsg_free(&imsg); } } + +void +client_suspend(void) +{ + struct sigaction act; + + memset(&act, 0, sizeof act); + sigemptyset(&act.sa_mask); + act.sa_flags = SA_RESTART; + + act.sa_handler = SIG_DFL; + if (sigaction(SIGTSTP, &act, NULL) != 0) + fatal("sigaction failed"); + + act.sa_handler = sighandler; + if (sigaction(SIGCONT, &act, NULL) != 0) + fatal("sigaction failed"); + + kill(getpid(), SIGTSTP); +} diff --git a/tmux.c b/tmux.c index 6e747bbe..f6d96c54 100644 --- a/tmux.c +++ b/tmux.c @@ -53,9 +53,10 @@ char *socket_path; int login_shell; __dead void usage(void); +void fill_session(struct msg_command_data *); char *makesockpath(const char *); int prepare_cmd(enum msgtype *, void **, size_t *, int, char **); -int dispatch_imsg(struct client_ctx *, const char *, int *); +int dispatch_imsg(struct imsgbuf *, const char *, int *); __dead void shell_exec(const char *, const char *); __dead void @@ -215,6 +216,44 @@ areshell(const char *shell) return (0); } +void +fill_session(struct msg_command_data *data) +{ + char *env, *ptr1, *ptr2, buf[256]; + size_t len; + const char *errstr; + long long ll; + + data->pid = -1; + if ((env = getenv("TMUX")) == NULL) + return; + + if ((ptr2 = strrchr(env, ',')) == NULL || ptr2 == env) + return; + for (ptr1 = ptr2 - 1; ptr1 > env && *ptr1 != ','; ptr1--) + ; + if (*ptr1 != ',') + return; + ptr1++; + ptr2++; + + len = ptr2 - ptr1 - 1; + if (len > (sizeof buf) - 1) + return; + memcpy(buf, ptr1, len); + buf[len] = '\0'; + + ll = strtonum(buf, 0, LONG_MAX, &errstr); + if (errstr != NULL) + return; + data->pid = ll; + + ll = strtonum(ptr2, 0, UINT_MAX, &errstr); + if (errstr != NULL) + return; + data->idx = ll; +} + char * makesockpath(const char *label) { @@ -248,7 +287,7 @@ prepare_cmd(enum msgtype *msg, void **buf, size_t *len, int argc, char **argv) { static struct msg_command_data cmddata; - client_fill_session(&cmddata); + fill_session(&cmddata); cmddata.argc = argc; if (cmd_pack_argv(argc, argv, cmddata.argv, sizeof cmddata.argv) != 0) { @@ -266,20 +305,19 @@ prepare_cmd(enum msgtype *msg, void **buf, size_t *len, int argc, char **argv) int main(int argc, char **argv) { - struct client_ctx cctx; - struct cmd_list *cmdlist; - struct cmd *cmd; - struct pollfd pfd; - enum msgtype msg; - struct passwd *pw; - struct options *so, *wo; - struct keylist *keylist; - char *s, *shellcmd, *path, *label, *home, *cause; - char cwd[MAXPATHLEN], **var; - void *buf; - size_t len; - int retcode, opt, flags, cmdflags = 0; - int nfds; + struct cmd_list *cmdlist; + struct cmd *cmd; + struct pollfd pfd; + enum msgtype msg; + struct passwd *pw; + struct options *so, *wo; + struct keylist *keylist; + struct imsgbuf *ibuf; + char *s, *shellcmd, *path, *label, *home, *cause; + char cwd[MAXPATHLEN], **var; + void *buf; + size_t len; + int nfds, retcode, opt, flags, cmdflags = 0; flags = 0; shellcmd = label = path = NULL; @@ -518,19 +556,17 @@ main(int argc, char **argv) cmd_list_free(cmdlist); } - memset(&cctx, 0, sizeof cctx); - if (client_init(path, &cctx, cmdflags, flags) != 0) + if ((ibuf = client_init(path, cmdflags, flags)) == NULL) exit(1); xfree(path); - client_write_server(&cctx, msg, buf, len); - memset(buf, 0, len); + imsg_compose(ibuf, msg, PROTOCOL_VERSION, -1, -1, buf, len); retcode = 0; for (;;) { - pfd.fd = cctx.ibuf.fd; + pfd.fd = ibuf->fd; pfd.events = POLLIN; - if (cctx.ibuf.w.queued != 0) + if (ibuf->w.queued != 0) pfd.events |= POLLOUT; if ((nfds = poll(&pfd, 1, INFTIM)) == -1) { @@ -545,12 +581,12 @@ main(int argc, char **argv) fatalx("socket error"); if (pfd.revents & POLLIN) { - if (dispatch_imsg(&cctx, shellcmd, &retcode) != 0) + if (dispatch_imsg(ibuf, shellcmd, &retcode) != 0) break; } if (pfd.revents & POLLOUT) { - if (msgbuf_write(&cctx.ibuf.w) < 0) + if (msgbuf_write(&ibuf->w) < 0) fatalx("msgbuf_write failed"); } } @@ -562,18 +598,18 @@ main(int argc, char **argv) } int -dispatch_imsg(struct client_ctx *cctx, const char *shellcmd, int *retcode) +dispatch_imsg(struct imsgbuf *ibuf, const char *shellcmd, int *retcode) { struct imsg imsg; ssize_t n, datalen; struct msg_print_data printdata; struct msg_shell_data shelldata; - if ((n = imsg_read(&cctx->ibuf)) == -1 || n == 0) + if ((n = imsg_read(ibuf)) == -1 || n == 0) fatalx("imsg_read failed"); for (;;) { - if ((n = imsg_get(&cctx->ibuf, &imsg)) == -1) + if ((n = imsg_get(ibuf, &imsg)) == -1) fatalx("imsg_get failed"); if (n == 0) return (0); @@ -601,8 +637,7 @@ dispatch_imsg(struct client_ctx *cctx, const char *shellcmd, int *retcode) if (datalen != 0) fatalx("bad MSG_READY size"); - *retcode = client_main(cctx); - return (-1); + client_main(); /* doesn't return */ case MSG_VERSION: if (datalen != 0) fatalx("bad MSG_VERSION size"); diff --git a/tmux.h b/tmux.h index 0e89a135..e97d4aaa 100644 --- a/tmux.h +++ b/tmux.h @@ -1052,19 +1052,6 @@ struct client { }; ARRAY_DECL(clients, struct client *); -/* Client context. */ -struct client_ctx { - struct imsgbuf ibuf; - - enum { - CCTX_DETACH, - CCTX_EXIT, - CCTX_DIED, - CCTX_SHUTDOWN - } exittype; - const char *errstr; -}; - /* Key/command line command. */ struct cmd_ctx { /* @@ -1503,14 +1490,8 @@ void cmd_buffer_free(struct cmd *); size_t cmd_buffer_print(struct cmd *, char *, size_t); /* client.c */ -int client_init(char *, struct client_ctx *, int, int); -int client_main(struct client_ctx *); -int client_msg_dispatch(struct client_ctx *); - -/* client-fn.c */ -void client_write_server(struct client_ctx *, enum msgtype, void *, size_t); -void client_fill_session(struct msg_command_data *); -void client_suspend(void); +struct imsgbuf *client_init(char *, int, int); +__dead void client_main(void); /* key-bindings.c */ extern struct key_bindings key_bindings; From d69b364b5f043cec5ff0c160a13c144c3dc4b035 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 21 Oct 2009 20:16:40 +0000 Subject: [PATCH 0434/1180] Don't try to unsuspend a client if it isn't suspended. --- server-msg.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/server-msg.c b/server-msg.c index 248b94d4..02ceb078 100644 --- a/server-msg.c +++ b/server-msg.c @@ -101,6 +101,8 @@ server_msg_dispatch(struct client *c) if (datalen != 0) fatalx("bad MSG_WAKEUP size"); + if (!(c->flags & CLIENT_SUSPENDED)) + break; c->flags &= ~CLIENT_SUSPENDED; tty_start_tty(&c->tty); server_redraw_client(c); From 284b94662ad60f11d5cf91fe407786372a2da29b Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 21 Oct 2009 21:11:55 +0000 Subject: [PATCH 0435/1180] Tidy identify message send into a separate function. --- client.c | 64 +++++++++++++++++++++++++++++++------------------------- 1 file changed, 35 insertions(+), 29 deletions(-) diff --git a/client.c b/client.c index b048645e..7959559b 100644 --- a/client.c +++ b/client.c @@ -36,6 +36,7 @@ struct imsgbuf client_ibuf; const char *client_exitmsg; +void client_send_identify(int); void client_send_environ(void); void client_write_server(enum msgtype, void *, size_t); int client_dispatch(void); @@ -44,14 +45,11 @@ void client_suspend(void); struct imsgbuf * client_init(char *path, int cmdflags, int flags) { - struct sockaddr_un sa; - struct stat sb; - struct msg_identify_data data; - struct winsize ws; - size_t size; - int fd, fd2, mode; - char *term; - char rpathbuf[MAXPATHLEN]; + struct sockaddr_un sa; + struct stat sb; + size_t size; + int fd, mode; + char rpathbuf[MAXPATHLEN]; if (realpath(path, rpathbuf) == NULL) strlcpy(rpathbuf, path, sizeof rpathbuf); @@ -103,26 +101,8 @@ server_started: if (cmdflags & CMD_SENDENVIRON) client_send_environ(); - if (isatty(STDIN_FILENO)) { - if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1) - fatal("ioctl(TIOCGWINSZ)"); - data.flags = flags; - - if (getcwd(data.cwd, sizeof data.cwd) == NULL) - *data.cwd = '\0'; - - *data.term = '\0'; - if ((term = getenv("TERM")) != NULL) { - if (strlcpy(data.term, - term, sizeof data.term) >= sizeof data.term) - *data.term = '\0'; - } - - if ((fd2 = dup(STDIN_FILENO)) == -1) - fatal("dup failed"); - imsg_compose(&client_ibuf, MSG_IDENTIFY, - PROTOCOL_VERSION, -1, fd2, &data, sizeof data); - } + if (isatty(STDIN_FILENO)) + client_send_identify(flags); return (&client_ibuf); @@ -135,11 +115,37 @@ not_found: return (NULL); } +void +client_send_identify(int flags) +{ + struct msg_identify_data data; + struct winsize ws; + char *term; + int fd; + + if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1) + fatal("ioctl(TIOCGWINSZ)"); + data.flags = flags; + + if (getcwd(data.cwd, sizeof data.cwd) == NULL) + *data.cwd = '\0'; + + term = getenv("TERM"); + if (term == NULL || + strlcpy(data.term, term, sizeof data.term) >= sizeof data.term) + *data.term = '\0'; + + if ((fd = dup(STDIN_FILENO)) == -1) + fatal("dup failed"); + imsg_compose(&client_ibuf, + MSG_IDENTIFY, PROTOCOL_VERSION, -1, fd, &data, sizeof data); +} + void client_send_environ(void) { - char **var; struct msg_environ_data data; + char **var; for (var = environ; *var != NULL; var++) { if (strlcpy(data.var, *var, sizeof data.var) >= sizeof data.var) From eb0c33cba43c8f7b35de20ffa55c318779e171de Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 22 Oct 2009 10:04:07 +0000 Subject: [PATCH 0436/1180] Merge prepare_cmd into main as it is short and only called once. --- tmux.c | 64 +++++++++++++++++++++++++--------------------------------- 1 file changed, 28 insertions(+), 36 deletions(-) diff --git a/tmux.c b/tmux.c index f6d96c54..d15b3fe1 100644 --- a/tmux.c +++ b/tmux.c @@ -55,7 +55,6 @@ int login_shell; __dead void usage(void); void fill_session(struct msg_command_data *); char *makesockpath(const char *); -int prepare_cmd(enum msgtype *, void **, size_t *, int, char **); int dispatch_imsg(struct imsgbuf *, const char *, int *); __dead void shell_exec(const char *, const char *); @@ -282,42 +281,23 @@ makesockpath(const char *label) return (path); } -int -prepare_cmd(enum msgtype *msg, void **buf, size_t *len, int argc, char **argv) -{ - static struct msg_command_data cmddata; - - fill_session(&cmddata); - - cmddata.argc = argc; - if (cmd_pack_argv(argc, argv, cmddata.argv, sizeof cmddata.argv) != 0) { - log_warnx("command too long"); - return (-1); - } - - *buf = &cmddata; - *len = sizeof cmddata; - - *msg = MSG_COMMAND; - return (0); -} - int main(int argc, char **argv) { - struct cmd_list *cmdlist; - struct cmd *cmd; - struct pollfd pfd; - enum msgtype msg; - struct passwd *pw; - struct options *so, *wo; - struct keylist *keylist; - struct imsgbuf *ibuf; - char *s, *shellcmd, *path, *label, *home, *cause; - char cwd[MAXPATHLEN], **var; - void *buf; - size_t len; - int nfds, retcode, opt, flags, cmdflags = 0; + struct cmd_list *cmdlist; + struct cmd *cmd; + struct pollfd pfd; + enum msgtype msg; + struct passwd *pw; + struct options *so, *wo; + struct keylist *keylist; + struct imsgbuf *ibuf; + struct msg_command_data cmddata; + char *s, *shellcmd, *path, *label, *home, *cause; + char cwd[MAXPATHLEN], **var; + void *buf; + size_t len; + int nfds, retcode, opt, flags, cmdflags = 0; flags = 0; shellcmd = label = path = NULL; @@ -529,8 +509,20 @@ main(int argc, char **argv) msg = MSG_SHELL; buf = NULL; len = 0; - } else if (prepare_cmd(&msg, &buf, &len, argc, argv) != 0) - exit(1); + } else { + fill_session(&cmddata); + + cmddata.argc = argc; + if (cmd_pack_argv( + argc, argv, cmddata.argv, sizeof cmddata.argv) != 0) { + log_warnx("command too long"); + exit(1); + } + + msg = MSG_COMMAND; + buf = &cmddata; + len = sizeof cmddata; + } if (shellcmd != NULL) cmdflags |= CMD_STARTSERVER; From fd35b6f836565d2d46b8c9869f8ea6590face8d6 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 22 Oct 2009 12:30:00 +0000 Subject: [PATCH 0437/1180] Only redraw the pane when changing mode, not the entire window. --- window.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/window.c b/window.c index d982ccc3..5d40cfc2 100644 --- a/window.c +++ b/window.c @@ -610,7 +610,7 @@ window_pane_set_mode(struct window_pane *wp, const struct window_mode *mode) if ((s = wp->mode->init(wp)) != NULL) wp->screen = s; - server_redraw_window(wp->window); + wp->flags |= PANE_REDRAW; return (0); } @@ -624,7 +624,7 @@ window_pane_reset_mode(struct window_pane *wp) wp->mode = NULL; wp->screen = &wp->base; - server_redraw_window(wp->window); + wp->flags |= PANE_REDRAW; } void From eddcc3dfa9d3e5b45675de6287f0a359893b1bc1 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 22 Oct 2009 19:41:51 +0000 Subject: [PATCH 0438/1180] Split the server code handling clients, jobs and windows off into separate files from server.c (merging server-msg.c into the client file) and rather than iterating over each set after poll(), allow a callback to be specified when the fd is added and just walk once over the returned pollfds calling each callback where needed. More to come, getting this in so it is tested. --- Makefile | 9 +- buffer-poll.c | 14 +- server-client.c | 728 +++++++++++++++++++++++++++++++++++ server-job.c | 57 +++ server-msg.c | 280 -------------- server-window.c | 281 ++++++++++++++ server.c | 994 ++++++------------------------------------------ tmux.h | 17 +- 8 files changed, 1211 insertions(+), 1169 deletions(-) create mode 100644 server-client.c create mode 100644 server-job.c delete mode 100644 server-msg.c create mode 100644 server-window.c diff --git a/Makefile b/Makefile index cf856b6c..e6b8b1dd 100644 --- a/Makefile +++ b/Makefile @@ -34,10 +34,11 @@ SRCS= attributes.c buffer-poll.c buffer.c cfg.c \ imsg.c imsg-buffer.c input.c key-bindings.c key-string.c \ layout-set.c layout.c log.c job.c \ mode-key.c names.c options-cmd.c options.c paste.c procname.c \ - resize.c screen-redraw.c screen-write.c screen.c server-fn.c \ - server-msg.c server.c session.c status.c tmux.c tty-keys.c tty-term.c \ - tty.c utf8.c window-choose.c window-clock.c \ - window-copy.c window-more.c window.c xmalloc.c + resize.c screen-redraw.c screen-write.c screen.c session.c status.c \ + server-fn.c server.c server-client.c server-window.c server-job.c \ + tmux.c tty-keys.c tty-term.c tty.c utf8.c \ + window-choose.c window-clock.c window-copy.c window-more.c window.c \ + xmalloc.c CDIAGFLAGS+= -Wno-long-long -Wall -W -Wnested-externs -Wformat=2 CDIAGFLAGS+= -Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations diff --git a/buffer-poll.c b/buffer-poll.c index 58c2d555..cf70c04c 100644 --- a/buffer-poll.c +++ b/buffer-poll.c @@ -25,15 +25,15 @@ /* Fill buffers from socket based on poll results. */ int -buffer_poll(struct pollfd *pfd, struct buffer *in, struct buffer *out) +buffer_poll(int fd, int events, struct buffer *in, struct buffer *out) { ssize_t n; - if (pfd->revents & (POLLERR|POLLNVAL)) + if (events & (POLLERR|POLLNVAL)) return (-1); - if (in != NULL && pfd->revents & POLLIN) { + if (in != NULL && events & POLLIN) { buffer_ensure(in, BUFSIZ); - n = read(pfd->fd, BUFFER_IN(in), BUFFER_FREE(in)); + n = read(fd, BUFFER_IN(in), BUFFER_FREE(in)); if (n == 0) return (-1); if (n == -1) { @@ -41,10 +41,10 @@ buffer_poll(struct pollfd *pfd, struct buffer *in, struct buffer *out) return (-1); } else buffer_add(in, n); - } else if (pfd->revents & POLLHUP) + } else if (events & POLLHUP) return (-1); - if (out != NULL && BUFFER_USED(out) > 0 && pfd->revents & POLLOUT) { - n = write(pfd->fd, BUFFER_OUT(out), BUFFER_USED(out)); + if (out != NULL && BUFFER_USED(out) > 0 && events & POLLOUT) { + n = write(fd, BUFFER_OUT(out), BUFFER_USED(out)); if (n == -1) { if (errno != EINTR && errno != EAGAIN) return (-1); diff --git a/server-client.c b/server-client.c new file mode 100644 index 00000000..5775a2fb --- /dev/null +++ b/server-client.c @@ -0,0 +1,728 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2009 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 "tmux.h" + +void server_client_handle_data(struct client *); +void server_client_check_redraw(struct client *); +void server_client_set_title(struct client *); +void server_client_check_timers(struct client *); + +int server_client_msg_dispatch(struct client *); +void server_client_msg_command(struct client *, struct msg_command_data *); +void server_client_msg_identify( + struct client *, struct msg_identify_data *, int); +void server_client_msg_shell(struct client *); + +void printflike2 server_client_msg_error(struct cmd_ctx *, const char *, ...); +void printflike2 server_client_msg_print(struct cmd_ctx *, const char *, ...); +void printflike2 server_client_msg_info(struct cmd_ctx *, const char *, ...); + + +/* Create a new client. */ +void +server_client_create(int fd) +{ + struct client *c; + int mode; + u_int i; + + if ((mode = fcntl(fd, F_GETFL)) == -1) + fatal("fcntl failed"); + if (fcntl(fd, F_SETFL, mode|O_NONBLOCK) == -1) + fatal("fcntl failed"); + if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) + fatal("fcntl failed"); + + c = xcalloc(1, sizeof *c); + c->references = 0; + imsg_init(&c->ibuf, fd); + + if (gettimeofday(&c->tv, NULL) != 0) + fatal("gettimeofday failed"); + + ARRAY_INIT(&c->prompt_hdata); + + c->tty.fd = -1; + c->title = NULL; + + c->session = NULL; + c->tty.sx = 80; + c->tty.sy = 24; + + screen_init(&c->status, c->tty.sx, 1, 0); + job_tree_init(&c->status_jobs); + + c->message_string = NULL; + + c->prompt_string = NULL; + c->prompt_buffer = NULL; + c->prompt_index = 0; + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + if (ARRAY_ITEM(&clients, i) == NULL) { + ARRAY_SET(&clients, i, c); + return; + } + } + ARRAY_ADD(&clients, c); + log_debug("new client %d", fd); +} + +/* Lost a client. */ +void +server_client_lost(struct client *c) +{ + u_int i; + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + if (ARRAY_ITEM(&clients, i) == c) + ARRAY_SET(&clients, i, NULL); + } + log_debug("lost client %d", c->ibuf.fd); + + /* + * If CLIENT_TERMINAL hasn't been set, then tty_init hasn't been called + * and tty_free might close an unrelated fd. + */ + if (c->flags & CLIENT_TERMINAL) + tty_free(&c->tty); + + screen_free(&c->status); + job_tree_free(&c->status_jobs); + + if (c->title != NULL) + xfree(c->title); + + if (c->message_string != NULL) + xfree(c->message_string); + + if (c->prompt_string != NULL) + xfree(c->prompt_string); + if (c->prompt_buffer != NULL) + xfree(c->prompt_buffer); + for (i = 0; i < ARRAY_LENGTH(&c->prompt_hdata); i++) + xfree(ARRAY_ITEM(&c->prompt_hdata, i)); + ARRAY_FREE(&c->prompt_hdata); + + if (c->cwd != NULL) + xfree(c->cwd); + + close(c->ibuf.fd); + imsg_clear(&c->ibuf); + + for (i = 0; i < ARRAY_LENGTH(&dead_clients); i++) { + if (ARRAY_ITEM(&dead_clients, i) == NULL) { + ARRAY_SET(&dead_clients, i, c); + break; + } + } + if (i == ARRAY_LENGTH(&dead_clients)) + ARRAY_ADD(&dead_clients, c); + c->flags |= CLIENT_DEAD; + + recalculate_sizes(); +} + +/* Process a single client event. */ +void +server_client_callback(int fd, int events, void *data) +{ + struct client *c = data; + + if (fd == c->ibuf.fd) { + if (events & (POLLERR|POLLNVAL|POLLHUP)) + goto client_lost; + + if (events & POLLOUT && msgbuf_write(&c->ibuf.w) < 0) + goto client_lost; + + if (c->flags & CLIENT_BAD) { + if (c->ibuf.w.queued == 0) + goto client_lost; + return; + } + + if (events & POLLIN && server_client_msg_dispatch(c) != 0) + goto client_lost; + } + + if (c->tty.fd != -1 && fd == c->tty.fd) { + if (c->flags & CLIENT_SUSPENDED || c->session == NULL) + return; + + if (buffer_poll(fd, events, c->tty.in, c->tty.out) != 0) + goto client_lost; + server_client_handle_data(c); + } + + return; + +client_lost: + server_client_lost(c); +} + +/* Input data from client. */ +void +server_client_handle_data(struct client *c) +{ + struct window *w; + struct window_pane *wp; + struct screen *s; + struct options *oo; + struct timeval tv; + struct key_binding *bd; + struct keylist *keylist; + struct mouse_event mouse; + int key, status, xtimeout, mode, isprefix; + u_int i; + + xtimeout = options_get_number(&c->session->options, "repeat-time"); + if (xtimeout != 0 && c->flags & CLIENT_REPEAT) { + if (gettimeofday(&tv, NULL) != 0) + fatal("gettimeofday failed"); + if (timercmp(&tv, &c->repeat_timer, >)) + c->flags &= ~(CLIENT_PREFIX|CLIENT_REPEAT); + } + + /* Process keys. */ + keylist = options_get_data(&c->session->options, "prefix"); + while (tty_keys_next(&c->tty, &key, &mouse) == 0) { + if (c->session == NULL) + return; + + c->session->activity = time(NULL); + w = c->session->curw->window; + wp = w->active; /* could die */ + oo = &c->session->options; + + /* Special case: number keys jump to pane in identify mode. */ + if (c->flags & CLIENT_IDENTIFY && key >= '0' && key <= '9') { + wp = window_pane_at_index(w, key - '0'); + if (wp != NULL && window_pane_visible(wp)) + window_set_active_pane(w, wp); + server_clear_identify(c); + continue; + } + + status_message_clear(c); + server_clear_identify(c); + if (c->prompt_string != NULL) { + status_prompt_key(c, key); + continue; + } + + /* Check for mouse keys. */ + if (key == KEYC_MOUSE) { + if (options_get_number(oo, "mouse-select-pane")) { + window_set_active_at(w, mouse.x, mouse.y); + wp = w->active; + } + window_pane_mouse(wp, c, &mouse); + continue; + } + + /* Is this a prefix key? */ + isprefix = 0; + for (i = 0; i < ARRAY_LENGTH(keylist); i++) { + if (key == ARRAY_ITEM(keylist, i)) { + isprefix = 1; + break; + } + } + + /* No previous prefix key. */ + if (!(c->flags & CLIENT_PREFIX)) { + if (isprefix) + c->flags |= CLIENT_PREFIX; + else { + /* Try as a non-prefix key binding. */ + if ((bd = key_bindings_lookup(key)) == NULL) + window_pane_key(wp, c, key); + else + key_bindings_dispatch(bd, c); + } + continue; + } + + /* Prefix key already pressed. Reset prefix and lookup key. */ + c->flags &= ~CLIENT_PREFIX; + if ((bd = key_bindings_lookup(key | KEYC_PREFIX)) == NULL) { + /* If repeating, treat this as a key, else ignore. */ + if (c->flags & CLIENT_REPEAT) { + c->flags &= ~CLIENT_REPEAT; + if (isprefix) + c->flags |= CLIENT_PREFIX; + else + window_pane_key(wp, c, key); + } + continue; + } + + /* If already repeating, but this key can't repeat, skip it. */ + if (c->flags & CLIENT_REPEAT && !bd->can_repeat) { + c->flags &= ~CLIENT_REPEAT; + if (isprefix) + c->flags |= CLIENT_PREFIX; + else + window_pane_key(wp, c, key); + continue; + } + + /* If this key can repeat, reset the repeat flags and timer. */ + if (xtimeout != 0 && bd->can_repeat) { + c->flags |= CLIENT_PREFIX|CLIENT_REPEAT; + + tv.tv_sec = xtimeout / 1000; + tv.tv_usec = (xtimeout % 1000) * 1000L; + if (gettimeofday(&c->repeat_timer, NULL) != 0) + fatal("gettimeofday failed"); + timeradd(&c->repeat_timer, &tv, &c->repeat_timer); + } + + /* Dispatch the command. */ + key_bindings_dispatch(bd, c); + } + if (c->session == NULL) + return; + w = c->session->curw->window; + wp = w->active; + oo = &c->session->options; + s = wp->screen; + + /* + * Update cursor position and mode settings. The scroll region and + * attributes are cleared across poll(2) as this is the most likely + * time a user may interrupt tmux, for example with ~^Z in ssh(1). This + * is a compromise between excessive resets and likelihood of an + * interrupt. + * + * tty_region/tty_reset/tty_update_mode already take care of not + * resetting things that are already in their default state. + */ + tty_region(&c->tty, 0, c->tty.sy - 1); + + status = options_get_number(oo, "status"); + if (!window_pane_visible(wp) || wp->yoff + s->cy >= c->tty.sy - status) + tty_cursor(&c->tty, 0, 0); + else + tty_cursor(&c->tty, wp->xoff + s->cx, wp->yoff + s->cy); + + mode = s->mode; + if (TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry) != NULL && + options_get_number(oo, "mouse-select-pane")) + mode |= MODE_MOUSE; + tty_update_mode(&c->tty, mode); + tty_reset(&c->tty); +} + +/* Client functions that need to happen every loop. */ +void +server_client_loop(void) +{ + struct client *c; + struct window *w; + struct window_pane *wp; + u_int i; + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c == NULL || c->session == NULL) + continue; + + server_client_check_timers(c); + server_client_check_redraw(c); + } + + /* + * Any windows will have been redrawn as part of clients, so clear + * their flags now. + */ + for (i = 0; i < ARRAY_LENGTH(&windows); i++) { + w = ARRAY_ITEM(&windows, i); + if (w == NULL) + continue; + + w->flags &= ~WINDOW_REDRAW; + TAILQ_FOREACH(wp, &w->panes, entry) + wp->flags &= ~PANE_REDRAW; + } +} + +/* Check for client redraws. */ +void +server_client_check_redraw(struct client *c) +{ + struct session *s = c->session; + struct window_pane *wp; + int flags, redraw; + + flags = c->tty.flags & TTY_FREEZE; + c->tty.flags &= ~TTY_FREEZE; + + if (c->flags & (CLIENT_REDRAW|CLIENT_STATUS)) { + if (options_get_number(&s->options, "set-titles")) + server_client_set_title(c); + + if (c->message_string != NULL) + redraw = status_message_redraw(c); + else if (c->prompt_string != NULL) + redraw = status_prompt_redraw(c); + else + redraw = status_redraw(c); + if (!redraw) + c->flags &= ~CLIENT_STATUS; + } + + if (c->flags & CLIENT_REDRAW) { + screen_redraw_screen(c, 0); + c->flags &= ~CLIENT_STATUS; + } else { + TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry) { + if (wp->flags & PANE_REDRAW) + screen_redraw_pane(c, wp); + } + } + + if (c->flags & CLIENT_STATUS) + screen_redraw_screen(c, 1); + + c->tty.flags |= flags; + + c->flags &= ~(CLIENT_REDRAW|CLIENT_STATUS); +} + +/* Set client title. */ +void +server_client_set_title(struct client *c) +{ + struct session *s = c->session; + const char *template; + char *title; + + template = options_get_string(&s->options, "set-titles-string"); + + title = status_replace(c, template, time(NULL)); + if (c->title == NULL || strcmp(title, c->title) != 0) { + if (c->title != NULL) + xfree(c->title); + c->title = xstrdup(title); + tty_set_title(&c->tty, c->title); + } + xfree(title); +} + +/* Check client timers. */ +void +server_client_check_timers(struct client *c) +{ + struct session *s = c->session; + struct job *job; + struct timeval tv; + u_int interval; + + if (gettimeofday(&tv, NULL) != 0) + fatal("gettimeofday failed"); + + if (c->flags & CLIENT_IDENTIFY && timercmp(&tv, &c->identify_timer, >)) + server_clear_identify(c); + + if (c->message_string != NULL && timercmp(&tv, &c->message_timer, >)) + status_message_clear(c); + + if (c->message_string != NULL || c->prompt_string != NULL) { + /* + * Don't need timed redraw for messages/prompts so bail now. + * The status timer isn't reset when they are redrawn anyway. + */ + return; + + } + if (!options_get_number(&s->options, "status")) + return; + + /* Check timer; resolution is only a second so don't be too clever. */ + interval = options_get_number(&s->options, "status-interval"); + if (interval == 0) + return; + if (tv.tv_sec < c->status_timer.tv_sec || + ((u_int) tv.tv_sec) - c->status_timer.tv_sec >= interval) { + /* Run the jobs for this client and schedule for redraw. */ + RB_FOREACH(job, jobs, &c->status_jobs) + job_run(job); + c->flags |= CLIENT_STATUS; + } +} + +/* Dispatch message from client. */ +int +server_client_msg_dispatch(struct client *c) +{ + struct imsg imsg; + struct msg_command_data commanddata; + struct msg_identify_data identifydata; + struct msg_environ_data environdata; + ssize_t n, datalen; + + if ((n = imsg_read(&c->ibuf)) == -1 || n == 0) + return (-1); + + for (;;) { + if ((n = imsg_get(&c->ibuf, &imsg)) == -1) + return (-1); + if (n == 0) + return (0); + datalen = imsg.hdr.len - IMSG_HEADER_SIZE; + + if (imsg.hdr.peerid != PROTOCOL_VERSION) { + server_write_client(c, MSG_VERSION, NULL, 0); + c->flags |= CLIENT_BAD; + imsg_free(&imsg); + continue; + } + + log_debug("got %d from client %d", imsg.hdr.type, c->ibuf.fd); + switch (imsg.hdr.type) { + case MSG_COMMAND: + if (datalen != sizeof commanddata) + fatalx("bad MSG_COMMAND size"); + memcpy(&commanddata, imsg.data, sizeof commanddata); + + server_client_msg_command(c, &commanddata); + break; + case MSG_IDENTIFY: + if (datalen != sizeof identifydata) + fatalx("bad MSG_IDENTIFY size"); + if (imsg.fd == -1) + fatalx("MSG_IDENTIFY missing fd"); + memcpy(&identifydata, imsg.data, sizeof identifydata); + + server_client_msg_identify(c, &identifydata, imsg.fd); + break; + case MSG_RESIZE: + if (datalen != 0) + fatalx("bad MSG_RESIZE size"); + + tty_resize(&c->tty); + recalculate_sizes(); + server_redraw_client(c); + break; + case MSG_EXITING: + if (datalen != 0) + fatalx("bad MSG_EXITING size"); + + c->session = NULL; + tty_close(&c->tty); + server_write_client(c, MSG_EXITED, NULL, 0); + break; + case MSG_WAKEUP: + case MSG_UNLOCK: + if (datalen != 0) + fatalx("bad MSG_WAKEUP size"); + + if (!(c->flags & CLIENT_SUSPENDED)) + break; + c->flags &= ~CLIENT_SUSPENDED; + tty_start_tty(&c->tty); + server_redraw_client(c); + recalculate_sizes(); + if (c->session != NULL) + c->session->activity = time(NULL); + break; + case MSG_ENVIRON: + if (datalen != sizeof environdata) + fatalx("bad MSG_ENVIRON size"); + memcpy(&environdata, imsg.data, sizeof environdata); + + environdata.var[(sizeof environdata.var) - 1] = '\0'; + if (strchr(environdata.var, '=') != NULL) + environ_put(&c->environ, environdata.var); + break; + case MSG_SHELL: + if (datalen != 0) + fatalx("bad MSG_SHELL size"); + + server_client_msg_shell(c); + break; + default: + fatalx("unexpected message"); + } + + imsg_free(&imsg); + } +} + +/* Callback to send error message to client. */ +void printflike2 +server_client_msg_error(struct cmd_ctx *ctx, const char *fmt, ...) +{ + struct msg_print_data data; + va_list ap; + + va_start(ap, fmt); + xvsnprintf(data.msg, sizeof data.msg, fmt, ap); + va_end(ap); + + server_write_client(ctx->cmdclient, MSG_ERROR, &data, sizeof data); +} + +/* Callback to send print message to client. */ +void printflike2 +server_client_msg_print(struct cmd_ctx *ctx, const char *fmt, ...) +{ + struct msg_print_data data; + va_list ap; + + va_start(ap, fmt); + xvsnprintf(data.msg, sizeof data.msg, fmt, ap); + va_end(ap); + + server_write_client(ctx->cmdclient, MSG_PRINT, &data, sizeof data); +} + +/* Callback to send print message to client, if not quiet. */ +void printflike2 +server_client_msg_info(struct cmd_ctx *ctx, const char *fmt, ...) +{ + struct msg_print_data data; + va_list ap; + + if (be_quiet) + return; + + va_start(ap, fmt); + xvsnprintf(data.msg, sizeof data.msg, fmt, ap); + va_end(ap); + + server_write_client(ctx->cmdclient, MSG_PRINT, &data, sizeof data); +} + +/* Handle command message. */ +void +server_client_msg_command(struct client *c, struct msg_command_data *data) +{ + struct cmd_ctx ctx; + struct cmd_list *cmdlist = NULL; + struct cmd *cmd; + int argc; + char **argv, *cause; + + if (c->session != NULL) + c->session->activity = time(NULL); + + ctx.error = server_client_msg_error; + ctx.print = server_client_msg_print; + ctx.info = server_client_msg_info; + + ctx.msgdata = data; + ctx.curclient = NULL; + + ctx.cmdclient = c; + + argc = data->argc; + data->argv[(sizeof data->argv) - 1] = '\0'; + if (cmd_unpack_argv(data->argv, sizeof data->argv, argc, &argv) != 0) { + server_client_msg_error(&ctx, "command too long"); + goto error; + } + + if (argc == 0) { + argc = 1; + argv = xcalloc(1, sizeof *argv); + *argv = xstrdup("new-session"); + } + + if ((cmdlist = cmd_list_parse(argc, argv, &cause)) == NULL) { + server_client_msg_error(&ctx, "%s", cause); + cmd_free_argv(argc, argv); + goto error; + } + cmd_free_argv(argc, argv); + + if (data->pid != -1) { + TAILQ_FOREACH(cmd, cmdlist, qentry) { + if (cmd->entry->flags & CMD_CANTNEST) { + server_client_msg_error(&ctx, + "sessions should be nested with care. " + "unset $TMUX to force"); + goto error; + } + } + } + + if (cmd_list_exec(cmdlist, &ctx) != 1) + server_write_client(c, MSG_EXIT, NULL, 0); + cmd_list_free(cmdlist); + return; + +error: + if (cmdlist != NULL) + cmd_list_free(cmdlist); + server_write_client(c, MSG_EXIT, NULL, 0); +} + +/* Handle identify message. */ +void +server_client_msg_identify( + struct client *c, struct msg_identify_data *data, int fd) +{ + c->cwd = NULL; + data->cwd[(sizeof data->cwd) - 1] = '\0'; + if (*data->cwd != '\0') + c->cwd = xstrdup(data->cwd); + + data->term[(sizeof data->term) - 1] = '\0'; + tty_init(&c->tty, fd, data->term); + if (data->flags & IDENTIFY_UTF8) + c->tty.flags |= TTY_UTF8; + if (data->flags & IDENTIFY_256COLOURS) + c->tty.term_flags |= TERM_256COLOURS; + else if (data->flags & IDENTIFY_88COLOURS) + c->tty.term_flags |= TERM_88COLOURS; + if (data->flags & IDENTIFY_HASDEFAULTS) + c->tty.term_flags |= TERM_HASDEFAULTS; + + tty_resize(&c->tty); + + c->flags |= CLIENT_TERMINAL; +} + +/* Handle shell message. */ +void +server_client_msg_shell(struct client *c) +{ + struct msg_shell_data data; + const char *shell; + + shell = options_get_string(&global_s_options, "default-shell"); + + if (*shell == '\0' || areshell(shell)) + shell = _PATH_BSHELL; + if (strlcpy(data.shell, shell, sizeof data.shell) >= sizeof data.shell) + strlcpy(data.shell, _PATH_BSHELL, sizeof data.shell); + + server_write_client(c, MSG_SHELL, &data, sizeof data); + c->flags |= CLIENT_BAD; /* it will die after exec */ +} diff --git a/server-job.c b/server-job.c new file mode 100644 index 00000000..f1903237 --- /dev/null +++ b/server-job.c @@ -0,0 +1,57 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2009 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 "tmux.h" + +/* Process a single job event. */ +void +server_job_callback(int fd, int events, void *data) +{ + struct job *job = data; + + if (job->fd == -1) + return; + + if (buffer_poll(fd, events, job->out, NULL) != 0) { + close(job->fd); + job->fd = -1; + } +} + +/* Job functions that happen once a loop. */ +void +server_job_loop(void) +{ + struct job *job; + +restart: + SLIST_FOREACH(job, &all_jobs, lentry) { + if (job->flags & JOB_DONE || job->fd != -1 || job->pid != -1) + continue; + job->flags |= JOB_DONE; + + if (job->callbackfn != NULL) { + job->callbackfn(job); + goto restart; /* could be freed by callback */ + } + } +} diff --git a/server-msg.c b/server-msg.c deleted file mode 100644 index 02ceb078..00000000 --- a/server-msg.c +++ /dev/null @@ -1,280 +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 - -#include -#include -#include -#include -#include -#include - -#include "tmux.h" - -void server_msg_command(struct client *, struct msg_command_data *); -void server_msg_identify(struct client *, struct msg_identify_data *, int); -void server_msg_shell(struct client *); - -void printflike2 server_msg_command_error(struct cmd_ctx *, const char *, ...); -void printflike2 server_msg_command_print(struct cmd_ctx *, const char *, ...); -void printflike2 server_msg_command_info(struct cmd_ctx *, const char *, ...); - -int -server_msg_dispatch(struct client *c) -{ - struct imsg imsg; - struct msg_command_data commanddata; - struct msg_identify_data identifydata; - struct msg_environ_data environdata; - ssize_t n, datalen; - - if ((n = imsg_read(&c->ibuf)) == -1 || n == 0) - return (-1); - - for (;;) { - if ((n = imsg_get(&c->ibuf, &imsg)) == -1) - return (-1); - if (n == 0) - return (0); - datalen = imsg.hdr.len - IMSG_HEADER_SIZE; - - if (imsg.hdr.peerid != PROTOCOL_VERSION) { - server_write_client(c, MSG_VERSION, NULL, 0); - c->flags |= CLIENT_BAD; - imsg_free(&imsg); - continue; - } - - log_debug("got %d from client %d", imsg.hdr.type, c->ibuf.fd); - switch (imsg.hdr.type) { - case MSG_COMMAND: - if (datalen != sizeof commanddata) - fatalx("bad MSG_COMMAND size"); - memcpy(&commanddata, imsg.data, sizeof commanddata); - - server_msg_command(c, &commanddata); - break; - case MSG_IDENTIFY: - if (datalen != sizeof identifydata) - fatalx("bad MSG_IDENTIFY size"); - if (imsg.fd == -1) - fatalx("MSG_IDENTIFY missing fd"); - memcpy(&identifydata, imsg.data, sizeof identifydata); - - server_msg_identify(c, &identifydata, imsg.fd); - break; - case MSG_RESIZE: - if (datalen != 0) - fatalx("bad MSG_RESIZE size"); - - tty_resize(&c->tty); - recalculate_sizes(); - server_redraw_client(c); - break; - case MSG_EXITING: - if (datalen != 0) - fatalx("bad MSG_EXITING size"); - - c->session = NULL; - tty_close(&c->tty); - server_write_client(c, MSG_EXITED, NULL, 0); - break; - case MSG_WAKEUP: - case MSG_UNLOCK: - if (datalen != 0) - fatalx("bad MSG_WAKEUP size"); - - if (!(c->flags & CLIENT_SUSPENDED)) - break; - c->flags &= ~CLIENT_SUSPENDED; - tty_start_tty(&c->tty); - server_redraw_client(c); - recalculate_sizes(); - if (c->session != NULL) - c->session->activity = time(NULL); - break; - case MSG_ENVIRON: - if (datalen != sizeof environdata) - fatalx("bad MSG_ENVIRON size"); - memcpy(&environdata, imsg.data, sizeof environdata); - - environdata.var[(sizeof environdata.var) - 1] = '\0'; - if (strchr(environdata.var, '=') != NULL) - environ_put(&c->environ, environdata.var); - break; - case MSG_SHELL: - if (datalen != 0) - fatalx("bad MSG_SHELL size"); - - server_msg_shell(c); - break; - default: - fatalx("unexpected message"); - } - - imsg_free(&imsg); - } -} - -void printflike2 -server_msg_command_error(struct cmd_ctx *ctx, const char *fmt, ...) -{ - struct msg_print_data data; - va_list ap; - - va_start(ap, fmt); - xvsnprintf(data.msg, sizeof data.msg, fmt, ap); - va_end(ap); - - server_write_client(ctx->cmdclient, MSG_ERROR, &data, sizeof data); -} - -void printflike2 -server_msg_command_print(struct cmd_ctx *ctx, const char *fmt, ...) -{ - struct msg_print_data data; - va_list ap; - - va_start(ap, fmt); - xvsnprintf(data.msg, sizeof data.msg, fmt, ap); - va_end(ap); - - server_write_client(ctx->cmdclient, MSG_PRINT, &data, sizeof data); -} - -void printflike2 -server_msg_command_info(struct cmd_ctx *ctx, const char *fmt, ...) -{ - struct msg_print_data data; - va_list ap; - - if (be_quiet) - return; - - va_start(ap, fmt); - xvsnprintf(data.msg, sizeof data.msg, fmt, ap); - va_end(ap); - - server_write_client(ctx->cmdclient, MSG_PRINT, &data, sizeof data); -} - -void -server_msg_command(struct client *c, struct msg_command_data *data) -{ - struct cmd_ctx ctx; - struct cmd_list *cmdlist = NULL; - struct cmd *cmd; - int argc; - char **argv, *cause; - - if (c->session != NULL) - c->session->activity = time(NULL); - - ctx.error = server_msg_command_error; - ctx.print = server_msg_command_print; - ctx.info = server_msg_command_info; - - ctx.msgdata = data; - ctx.curclient = NULL; - - ctx.cmdclient = c; - - argc = data->argc; - data->argv[(sizeof data->argv) - 1] = '\0'; - if (cmd_unpack_argv(data->argv, sizeof data->argv, argc, &argv) != 0) { - server_msg_command_error(&ctx, "command too long"); - goto error; - } - - if (argc == 0) { - argc = 1; - argv = xcalloc(1, sizeof *argv); - *argv = xstrdup("new-session"); - } - - if ((cmdlist = cmd_list_parse(argc, argv, &cause)) == NULL) { - server_msg_command_error(&ctx, "%s", cause); - cmd_free_argv(argc, argv); - goto error; - } - cmd_free_argv(argc, argv); - - if (data->pid != -1) { - TAILQ_FOREACH(cmd, cmdlist, qentry) { - if (cmd->entry->flags & CMD_CANTNEST) { - server_msg_command_error(&ctx, - "sessions should be nested with care. " - "unset $TMUX to force"); - goto error; - } - } - } - - if (cmd_list_exec(cmdlist, &ctx) != 1) - server_write_client(c, MSG_EXIT, NULL, 0); - cmd_list_free(cmdlist); - return; - -error: - if (cmdlist != NULL) - cmd_list_free(cmdlist); - server_write_client(c, MSG_EXIT, NULL, 0); -} - -void -server_msg_identify(struct client *c, struct msg_identify_data *data, int fd) -{ - c->cwd = NULL; - data->cwd[(sizeof data->cwd) - 1] = '\0'; - if (*data->cwd != '\0') - c->cwd = xstrdup(data->cwd); - - data->term[(sizeof data->term) - 1] = '\0'; - tty_init(&c->tty, fd, data->term); - if (data->flags & IDENTIFY_UTF8) - c->tty.flags |= TTY_UTF8; - if (data->flags & IDENTIFY_256COLOURS) - c->tty.term_flags |= TERM_256COLOURS; - else if (data->flags & IDENTIFY_88COLOURS) - c->tty.term_flags |= TERM_88COLOURS; - if (data->flags & IDENTIFY_HASDEFAULTS) - c->tty.term_flags |= TERM_HASDEFAULTS; - - tty_resize(&c->tty); - - c->flags |= CLIENT_TERMINAL; -} - -void -server_msg_shell(struct client *c) -{ - struct msg_shell_data data; - const char *shell; - - shell = options_get_string(&global_s_options, "default-shell"); - - if (*shell == '\0' || areshell(shell)) - shell = _PATH_BSHELL; - if (strlcpy(data.shell, shell, sizeof data.shell) >= sizeof data.shell) - strlcpy(data.shell, _PATH_BSHELL, sizeof data.shell); - - server_write_client(c, MSG_SHELL, &data, sizeof data); - c->flags |= CLIENT_BAD; /* it will die after exec */ -} diff --git a/server-window.c b/server-window.c new file mode 100644 index 00000000..d9ff128d --- /dev/null +++ b/server-window.c @@ -0,0 +1,281 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2009 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 "tmux.h" + +int server_window_check_bell(struct session *, struct window *); +int server_window_check_activity(struct session *, struct window *); +int server_window_check_content( + struct session *, struct window *, struct window_pane *); +void server_window_check_alive(struct window *); + +/* Process a single window pane event. */ +void +server_window_callback(int fd, int events, void *data) +{ + struct window_pane *wp = data; + + if (wp->fd == -1) + return; + + if (fd == wp->fd) { + if (buffer_poll(fd, events, wp->in, wp->out) != 0) { + close(wp->fd); + wp->fd = -1; + } else + window_pane_parse(wp); + } + + if (fd == wp->pipe_fd) { + if (buffer_poll(fd, events, NULL, wp->pipe_buf) != 0) { + buffer_destroy(wp->pipe_buf); + close(wp->pipe_fd); + wp->pipe_fd = -1; + } + } +} + +/* Window functions that need to happen every loop. */ +void +server_window_loop(void) +{ + struct window *w; + struct window_pane *wp; + struct session *s; + u_int i, j; + + for (i = 0; i < ARRAY_LENGTH(&windows); i++) { + w = ARRAY_ITEM(&windows, i); + if (w == NULL) + continue; + + for (j = 0; j < ARRAY_LENGTH(&sessions); j++) { + s = ARRAY_ITEM(&sessions, j); + if (s == NULL || !session_has(s, w)) + continue; + + if (server_window_check_bell(s, w) || + server_window_check_activity(s, w)) + server_status_session(s); + TAILQ_FOREACH(wp, &w->panes, entry) + server_window_check_content(s, w, wp); + } + w->flags &= ~(WINDOW_BELL|WINDOW_ACTIVITY|WINDOW_CONTENT); + + server_window_check_alive(w); + } + + set_window_names(); +} + +/* Check for bell in window. */ +int +server_window_check_bell(struct session *s, struct window *w) +{ + struct client *c; + u_int i; + int action, visual; + + if (!(w->flags & WINDOW_BELL)) + return (0); + + if (session_alert_has_window(s, w, WINDOW_BELL)) + return (0); + session_alert_add(s, w, WINDOW_BELL); + + action = options_get_number(&s->options, "bell-action"); + switch (action) { + case BELL_ANY: + if (s->flags & SESSION_UNATTACHED) + break; + visual = options_get_number(&s->options, "visual-bell"); + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c == NULL || c->session != s) + continue; + if (!visual) { + tty_putcode(&c->tty, TTYC_BEL); + continue; + } + if (c->session->curw->window == w) { + status_message_set(c, "Bell in current window"); + continue; + } + status_message_set(c, "Bell in window %u", + winlink_find_by_window(&s->windows, w)->idx); + } + break; + case BELL_CURRENT: + if (s->flags & SESSION_UNATTACHED) + break; + visual = options_get_number(&s->options, "visual-bell"); + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c == NULL || c->session != s) + continue; + if (c->session->curw->window != w) + continue; + if (!visual) { + tty_putcode(&c->tty, TTYC_BEL); + continue; + } + status_message_set(c, "Bell in current window"); + } + break; + } + + return (1); +} + +/* Check for activity in window. */ +int +server_window_check_activity(struct session *s, struct window *w) +{ + struct client *c; + u_int i; + + if (!(w->flags & WINDOW_ACTIVITY)) + return (0); + if (s->curw->window == w) + return (0); + + if (!options_get_number(&w->options, "monitor-activity")) + return (0); + + if (session_alert_has_window(s, w, WINDOW_ACTIVITY)) + return (0); + session_alert_add(s, w, WINDOW_ACTIVITY); + + if (s->flags & SESSION_UNATTACHED) + return (0); + if (options_get_number(&s->options, "visual-activity")) { + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c == NULL || c->session != s) + continue; + status_message_set(c, "Activity in window %u", + winlink_find_by_window(&s->windows, w)->idx); + } + } + + return (1); +} + +/* Check for content change in window. */ +int +server_window_check_content( + struct session *s, struct window *w, struct window_pane *wp) +{ + struct client *c; + u_int i; + char *found, *ptr; + + if (!(w->flags & WINDOW_ACTIVITY)) /* activity for new content */ + return (0); + if (s->curw->window == w) + return (0); + + ptr = options_get_string(&w->options, "monitor-content"); + if (ptr == NULL || *ptr == '\0') + return (0); + + if (session_alert_has_window(s, w, WINDOW_CONTENT)) + return (0); + + if ((found = window_pane_search(wp, ptr, NULL)) == NULL) + return (0); + xfree(found); + + session_alert_add(s, w, WINDOW_CONTENT); + if (s->flags & SESSION_UNATTACHED) + return (0); + if (options_get_number(&s->options, "visual-content")) { + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c == NULL || c->session != s) + continue; + status_message_set(c, "Content in window %u", + winlink_find_by_window(&s->windows, w)->idx); + } + } + + return (1); +} + +/* Check if window still exists. */ +void +server_window_check_alive(struct window *w) +{ + struct window_pane *wp, *wq; + struct options *oo = &w->options; + struct session *s; + struct winlink *wl; + u_int i; + int destroyed; + + destroyed = 1; + + wp = TAILQ_FIRST(&w->panes); + while (wp != NULL) { + wq = TAILQ_NEXT(wp, entry); + /* + * If the pane has died and the remain-on-exit flag is not set, + * remove the pane; otherwise, if the flag is set, don't allow + * the window to be destroyed (or it'll close when the last + * pane dies). + */ + if (wp->fd == -1 && !options_get_number(oo, "remain-on-exit")) { + layout_close_pane(wp); + window_remove_pane(w, wp); + server_redraw_window(w); + } else + destroyed = 0; + wp = wq; + } + + if (!destroyed) + return; + + for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { + s = ARRAY_ITEM(&sessions, i); + if (s == NULL) + continue; + if (!session_has(s, w)) + continue; + + restart: + /* Detach window and either redraw or kill clients. */ + RB_FOREACH(wl, winlinks, &s->windows) { + if (wl->window != w) + continue; + if (session_detach(s, wl)) { + server_destroy_session_group(s); + break; + } + server_redraw_session(s); + server_status_session_group(s); + goto restart; + } + } + + recalculate_sizes(); +} diff --git a/server.c b/server.c index 6fdcf940..e1ec4eb8 100644 --- a/server.c +++ b/server.c @@ -47,80 +47,70 @@ struct clients dead_clients; /* Mapping of a pollfd to an fd independent of its position in the array. */ struct poll_item { - struct pollfd pfd; + int fd; + int events; + + void (*fn)(int, int, void *); + void *data; RB_ENTRY(poll_item) entry; }; RB_HEAD(poll_items, poll_item) poll_items; int server_poll_cmp(struct poll_item *, struct poll_item *); -struct pollfd *server_poll_lookup(int); -void server_poll_add(int, int); +struct poll_item*server_poll_lookup(int); +void server_poll_add(int, int, void (*)(int, int, void *), void *); struct pollfd *server_poll_flatten(int *); -void server_poll_parse(struct pollfd *); +void server_poll_dispatch(struct pollfd *, int); void server_poll_reset(void); RB_PROTOTYPE(poll_items, poll_item, entry, server_poll_cmp); RB_GENERATE(poll_items, poll_item, entry, server_poll_cmp); -void server_create_client(int); int server_create_socket(void); +void server_callback(int, int, void *); int server_main(int); void server_shutdown(void); int server_should_shutdown(void); void server_child_signal(void); void server_fill_windows(void); -void server_handle_windows(void); void server_fill_clients(void); -void server_handle_clients(void); void server_fill_jobs(void); -void server_handle_jobs(void); -void server_accept_client(int); -void server_handle_client(struct client *); -void server_handle_window(struct window *, struct window_pane *); -int server_check_window_bell(struct session *, struct window *); -int server_check_window_activity(struct session *, - struct window *); -int server_check_window_content(struct session *, struct window *, - struct window_pane *); void server_clean_dead(void); -void server_lost_client(struct client *); -void server_check_window(struct window *); -void server_check_redraw(struct client *); -void server_set_title(struct client *); -void server_check_timers(struct client *); -void server_check_jobs(void); +void server_second_timers(void); void server_lock_server(void); void server_lock_sessions(void); -void server_check_clients(void); -void server_second_timers(void); int server_update_socket(void); int server_poll_cmp(struct poll_item *pitem1, struct poll_item *pitem2) { - return (pitem1->pfd.fd - pitem2->pfd.fd); -} - -struct pollfd * -server_poll_lookup(int fd) -{ - struct poll_item pitem; - - pitem.pfd.fd = fd; - return (&RB_FIND(poll_items, &poll_items, &pitem)->pfd); + return (pitem1->fd - pitem2->fd); } void -server_poll_add(int fd, int events) +server_poll_add(int fd, int events, void (*fn)(int, int, void *), void *data) { struct poll_item *pitem; pitem = xmalloc(sizeof *pitem); - pitem->pfd.fd = fd; - pitem->pfd.events = events; + pitem->fd = fd; + pitem->events = events; + + pitem->fn = fn; + pitem->data = data; + RB_INSERT(poll_items, &poll_items, pitem); } +struct poll_item * +server_poll_lookup(int fd) +{ + struct poll_item pitem; + + pitem.fd = fd; + return (RB_FIND(poll_items, &poll_items, &pitem)); +} + struct pollfd * server_poll_flatten(int *nfds) { @@ -131,23 +121,25 @@ server_poll_flatten(int *nfds) *nfds = 0; RB_FOREACH(pitem, poll_items, &poll_items) { pfds = xrealloc(pfds, (*nfds) + 1, sizeof *pfds); - pfds[*nfds].fd = pitem->pfd.fd; - pfds[*nfds].events = pitem->pfd.events; + pfds[*nfds].fd = pitem->fd; + pfds[*nfds].events = pitem->events; (*nfds)++; } return (pfds); } void -server_poll_parse(struct pollfd *pfds) +server_poll_dispatch(struct pollfd *pfds, int nfds) { struct poll_item *pitem; - int nfds; + struct pollfd *pfd; - nfds = 0; - RB_FOREACH(pitem, poll_items, &poll_items) { - pitem->pfd.revents = pfds[nfds].revents; - nfds++; + while (nfds > 0) { + pfd = &pfds[--nfds]; + if (pfd->revents != 0) { + pitem = server_poll_lookup(pfd->fd); + pitem->fn(pitem->fd, pfd->revents, pitem->data); + } } xfree(pfds); } @@ -164,13 +156,34 @@ server_poll_reset(void) } } -/* Create a new client. */ -void -server_create_client(int fd) +/* Create server socket. */ +int +server_create_socket(void) { - struct client *c; - int mode; - u_int i; + struct sockaddr_un sa; + size_t size; + mode_t mask; + int fd, mode; + + memset(&sa, 0, sizeof sa); + sa.sun_family = AF_UNIX; + size = strlcpy(sa.sun_path, socket_path, sizeof sa.sun_path); + if (size >= sizeof sa.sun_path) { + errno = ENAMETOOLONG; + fatal("socket failed"); + } + unlink(sa.sun_path); + + if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) + fatal("socket failed"); + + mask = umask(S_IXUSR|S_IRWXG|S_IRWXO); + if (bind(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1) + fatal("bind failed"); + umask(mask); + + if (listen(fd, 16) == -1) + fatal("listen failed"); if ((mode = fcntl(fd, F_GETFL)) == -1) fatal("fcntl failed"); @@ -179,39 +192,33 @@ server_create_client(int fd) if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) fatal("fcntl failed"); - c = xcalloc(1, sizeof *c); - c->references = 0; - imsg_init(&c->ibuf, fd); - - if (gettimeofday(&c->tv, NULL) != 0) - fatal("gettimeofday failed"); + return (fd); +} - ARRAY_INIT(&c->prompt_hdata); +/* Callback for server socket. */ +void +server_callback(int fd, int events, unused void *data) +{ + struct sockaddr_storage sa; + socklen_t slen = sizeof sa; + int newfd; - c->tty.fd = -1; - c->title = NULL; + if (events & (POLLERR|POLLNVAL|POLLHUP)) + fatalx("lost server socket"); + if (!(events & POLLIN)) + return; - c->session = NULL; - c->tty.sx = 80; - c->tty.sy = 24; - - screen_init(&c->status, c->tty.sx, 1, 0); - job_tree_init(&c->status_jobs); - - c->message_string = NULL; - - c->prompt_string = NULL; - c->prompt_buffer = NULL; - c->prompt_index = 0; - - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - if (ARRAY_ITEM(&clients, i) == NULL) { - ARRAY_SET(&clients, i, c); + newfd = accept(fd, (struct sockaddr *) &sa, &slen); + if (newfd == -1) { + if (errno == EAGAIN || errno == EINTR || errno == ECONNABORTED) return; - } + fatal("accept failed"); } - ARRAY_ADD(&clients, c); - log_debug("new client %d", fd); + if (sigterm) { + close(newfd); + return; + } + server_client_create(newfd); } /* Fork new server. */ @@ -267,7 +274,7 @@ server_start(char *path) setproctitle("server (%s)", rpathbuf); srv_fd = server_create_socket(); - server_create_client(pair[1]); + server_client_create(pair[1]); if (access(SYSTEM_CFG, R_OK) != 0) { if (errno != ENOENT) { @@ -295,50 +302,11 @@ error: exit(server_main(srv_fd)); } -/* Create server socket. */ -int -server_create_socket(void) -{ - struct sockaddr_un sa; - size_t size; - mode_t mask; - int fd, mode; - - memset(&sa, 0, sizeof sa); - sa.sun_family = AF_UNIX; - size = strlcpy(sa.sun_path, socket_path, sizeof sa.sun_path); - if (size >= sizeof sa.sun_path) { - errno = ENAMETOOLONG; - fatal("socket failed"); - } - unlink(sa.sun_path); - - if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) - fatal("socket failed"); - - mask = umask(S_IXUSR|S_IRWXG|S_IRWXO); - if (bind(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1) - fatal("bind failed"); - umask(mask); - - if (listen(fd, 16) == -1) - fatal("listen failed"); - - if ((mode = fcntl(fd, F_GETFL)) == -1) - fatal("fcntl failed"); - if (fcntl(fd, F_SETFL, mode|O_NONBLOCK) == -1) - fatal("fcntl failed"); - if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) - fatal("fcntl failed"); - - return (fd); -} - /* Main server loop. */ int server_main(int srv_fd) { - struct pollfd *pfds, *pfd; + struct pollfd *pfds; int nfds, xtimeout; u_int i; time_t now, last; @@ -371,13 +339,9 @@ server_main(int srv_fd) sigusr1 = 0; } - /* Collect any jobs that have died and process clients. */ - server_check_jobs(); - server_check_clients(); - /* Initialise pollfd array and add server socket. */ server_poll_reset(); - server_poll_add(srv_fd, POLLIN); + server_poll_add(srv_fd, POLLIN, server_callback, NULL); /* Fill window and client sockets. */ server_fill_jobs(); @@ -396,16 +360,7 @@ server_main(int srv_fd) continue; fatal("poll failed"); } - server_poll_parse(pfds); - - /* Handle server socket. */ - pfd = server_poll_lookup(srv_fd); - if (pfd->revents & (POLLERR|POLLNVAL|POLLHUP)) - fatalx("lost server socket"); - if (pfd->revents & POLLIN) { - server_accept_client(srv_fd); - continue; - } + server_poll_dispatch(pfds, nfds); /* Call second-based timers. */ now = time(NULL); @@ -414,13 +369,10 @@ server_main(int srv_fd) server_second_timers(); } - /* Set window names. */ - set_window_names(); - - /* Handle window and client sockets. */ - server_handle_jobs(); - server_handle_windows(); - server_handle_clients(); + /* Run once-per-loop events. */ + server_job_loop(); + server_window_loop(); + server_client_loop(); /* Collect any unset key bindings. */ key_bindings_clean(); @@ -438,7 +390,7 @@ server_main(int srv_fd) for (i = 0; i < ARRAY_LENGTH(&clients); i++) { if (ARRAY_ITEM(&clients, i) != NULL) - server_lost_client(ARRAY_ITEM(&clients, i)); + server_client_lost(ARRAY_ITEM(&clients, i)); } ARRAY_FREE(&clients); @@ -468,7 +420,7 @@ server_shutdown(void) c = ARRAY_ITEM(&clients, i); if (c != NULL) { if (c->flags & (CLIENT_BAD|CLIENT_SUSPENDED)) - server_lost_client(c); + server_client_lost(c); else server_write_client(c, MSG_SHUTDOWN, NULL, 0); } @@ -571,195 +523,20 @@ server_fill_windows(void) events = POLLIN; if (BUFFER_USED(wp->out) > 0) events |= POLLOUT; - server_poll_add(wp->fd, events); + server_poll_add( + wp->fd, events, server_window_callback, wp); if (wp->pipe_fd == -1) continue; events = 0; if (BUFFER_USED(wp->pipe_buf) > 0) events |= POLLOUT; - server_poll_add(wp->pipe_fd, events); + server_poll_add( + wp->pipe_fd, events, server_window_callback, wp); } } } -/* Handle window pollfds. */ -void -server_handle_windows(void) -{ - struct window *w; - struct window_pane *wp; - struct pollfd *pfd; - u_int i; - - for (i = 0; i < ARRAY_LENGTH(&windows); i++) { - w = ARRAY_ITEM(&windows, i); - if (w == NULL) - continue; - - TAILQ_FOREACH(wp, &w->panes, entry) { - if (wp->fd == -1) - continue; - if ((pfd = server_poll_lookup(wp->fd)) == NULL) - continue; - if (buffer_poll(pfd, wp->in, wp->out) != 0) { - close(wp->fd); - wp->fd = -1; - } else - server_handle_window(w, wp); - - if (wp->pipe_fd == -1) - continue; - if ((pfd = server_poll_lookup(wp->pipe_fd)) == NULL) - continue; - if (buffer_poll(pfd, NULL, wp->pipe_buf) != 0) { - buffer_destroy(wp->pipe_buf); - close(wp->pipe_fd); - wp->pipe_fd = -1; - } - } - - server_check_window(w); - } -} - -/* Check clients for redraw and timers. */ -void -server_check_clients(void) -{ - struct client *c; - struct window *w; - struct window_pane *wp; - u_int i; - - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - c = ARRAY_ITEM(&clients, i); - if (c == NULL || c->session == NULL) - continue; - - server_check_timers(c); - server_check_redraw(c); - } - - /* - * Clear any window redraw flags (will have been redrawn as part of - * client). - */ - for (i = 0; i < ARRAY_LENGTH(&windows); i++) { - w = ARRAY_ITEM(&windows, i); - if (w == NULL) - continue; - - w->flags &= ~WINDOW_REDRAW; - TAILQ_FOREACH(wp, &w->panes, entry) - wp->flags &= ~PANE_REDRAW; - } -} - -/* Check for general redraw on client. */ -void -server_check_redraw(struct client *c) -{ - struct session *s = c->session; - struct window_pane *wp; - int flags, redraw; - - flags = c->tty.flags & TTY_FREEZE; - c->tty.flags &= ~TTY_FREEZE; - - if (c->flags & (CLIENT_REDRAW|CLIENT_STATUS)) { - if (options_get_number(&s->options, "set-titles")) - server_set_title(c); - - if (c->message_string != NULL) - redraw = status_message_redraw(c); - else if (c->prompt_string != NULL) - redraw = status_prompt_redraw(c); - else - redraw = status_redraw(c); - if (!redraw) - c->flags &= ~CLIENT_STATUS; - } - - if (c->flags & CLIENT_REDRAW) { - screen_redraw_screen(c, 0); - c->flags &= ~CLIENT_STATUS; - } else { - TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry) { - if (wp->flags & PANE_REDRAW) - screen_redraw_pane(c, wp); - } - } - - if (c->flags & CLIENT_STATUS) - screen_redraw_screen(c, 1); - - c->tty.flags |= flags; - - c->flags &= ~(CLIENT_REDRAW|CLIENT_STATUS); -} - -/* Set client title. */ -void -server_set_title(struct client *c) -{ - struct session *s = c->session; - const char *template; - char *title; - - template = options_get_string(&s->options, "set-titles-string"); - - title = status_replace(c, template, time(NULL)); - if (c->title == NULL || strcmp(title, c->title) != 0) { - if (c->title != NULL) - xfree(c->title); - c->title = xstrdup(title); - tty_set_title(&c->tty, c->title); - } - xfree(title); -} - -/* Check for timers on client. */ -void -server_check_timers(struct client *c) -{ - struct session *s = c->session; - struct job *job; - struct timeval tv; - u_int interval; - - if (gettimeofday(&tv, NULL) != 0) - fatal("gettimeofday failed"); - - if (c->flags & CLIENT_IDENTIFY && timercmp(&tv, &c->identify_timer, >)) - server_clear_identify(c); - - if (c->message_string != NULL && timercmp(&tv, &c->message_timer, >)) - status_message_clear(c); - - if (c->message_string != NULL || c->prompt_string != NULL) { - /* - * Don't need timed redraw for messages/prompts so bail now. - * The status timer isn't reset when they are redrawn anyway. - */ - return; - } - if (!options_get_number(&s->options, "status")) - return; - - /* Check timer; resolution is only a second so don't be too clever. */ - interval = options_get_number(&s->options, "status-interval"); - if (interval == 0) - return; - if (tv.tv_sec < c->status_timer.tv_sec || - ((u_int) tv.tv_sec) - c->status_timer.tv_sec >= interval) { - /* Run the jobs for this client and schedule for redraw. */ - RB_FOREACH(job, jobs, &c->status_jobs) - job_run(job); - c->flags |= CLIENT_STATUS; - } -} - /* Fill client pollfds. */ void server_fill_clients(void) @@ -777,7 +554,8 @@ server_fill_clients(void) events |= POLLIN; if (c->ibuf.w.queued > 0) events |= POLLOUT; - server_poll_add(c->ibuf.fd, events); + server_poll_add( + c->ibuf.fd, events, server_client_callback, c); } if (c != NULL && !(c->flags & CLIENT_SUSPENDED) && @@ -785,7 +563,8 @@ server_fill_clients(void) events = POLLIN; if (BUFFER_USED(c->tty.out) > 0) events |= POLLOUT; - server_poll_add(c->tty.fd, events); + server_poll_add( + c->tty.fd, events, server_client_callback, c); } } } @@ -799,328 +578,10 @@ server_fill_jobs(void) SLIST_FOREACH(job, &all_jobs, lentry) { if (job->fd == -1) continue; - server_poll_add(job->fd, POLLIN); + server_poll_add(job->fd, POLLIN, server_job_callback, job); } } -/* Handle job fds. */ -void -server_handle_jobs(void) -{ - struct job *job; - struct pollfd *pfd; - - SLIST_FOREACH(job, &all_jobs, lentry) { - if (job->fd == -1) - continue; - if ((pfd = server_poll_lookup(job->fd)) == NULL) - continue; - if (buffer_poll(pfd, job->out, NULL) != 0) { - close(job->fd); - job->fd = -1; - } - } -} - -/* Handle job fds. */ -void -server_check_jobs(void) -{ - struct job *job; - -restart: - SLIST_FOREACH(job, &all_jobs, lentry) { - if (job->flags & JOB_DONE || job->fd != -1 || job->pid != -1) - continue; - job->flags |= JOB_DONE; - - if (job->callbackfn != NULL) { - job->callbackfn(job); - goto restart; /* could be freed by callback */ - } - } -} - -/* Handle client pollfds. */ -void -server_handle_clients(void) -{ - struct client *c; - struct pollfd *pfd; - u_int i; - - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - c = ARRAY_ITEM(&clients, i); - - if (c != NULL) { - if ((pfd = server_poll_lookup(c->ibuf.fd)) == NULL) - continue; - if (pfd->revents & (POLLERR|POLLNVAL|POLLHUP)) { - server_lost_client(c); - continue; - } - - if (pfd->revents & POLLOUT) { - if (msgbuf_write(&c->ibuf.w) < 0) { - server_lost_client(c); - continue; - } - } - - if (c->flags & CLIENT_BAD) { - if (c->ibuf.w.queued == 0) - server_lost_client(c); - continue; - } else if (pfd->revents & POLLIN) { - if (server_msg_dispatch(c) != 0) { - server_lost_client(c); - continue; - } - } - } - - if (c != NULL && !(c->flags & CLIENT_SUSPENDED) && - c->tty.fd != -1 && c->session != NULL) { - if ((pfd = server_poll_lookup(c->tty.fd)) == NULL) - continue; - if (buffer_poll(pfd, c->tty.in, c->tty.out) != 0) - server_lost_client(c); - else - server_handle_client(c); - } - } -} - -/* accept(2) and create new client. */ -void -server_accept_client(int srv_fd) -{ - struct sockaddr_storage sa; - socklen_t slen = sizeof sa; - int fd; - - fd = accept(srv_fd, (struct sockaddr *) &sa, &slen); - if (fd == -1) { - if (errno == EAGAIN || errno == EINTR || errno == ECONNABORTED) - return; - fatal("accept failed"); - } - if (sigterm) { - close(fd); - return; - } - server_create_client(fd); -} - -/* Input data from client. */ -void -server_handle_client(struct client *c) -{ - struct window *w; - struct window_pane *wp; - struct screen *s; - struct options *oo; - struct timeval tv; - struct key_binding *bd; - struct keylist *keylist; - struct mouse_event mouse; - int key, status, xtimeout, mode, isprefix; - u_int i; - - xtimeout = options_get_number(&c->session->options, "repeat-time"); - if (xtimeout != 0 && c->flags & CLIENT_REPEAT) { - if (gettimeofday(&tv, NULL) != 0) - fatal("gettimeofday failed"); - if (timercmp(&tv, &c->repeat_timer, >)) - c->flags &= ~(CLIENT_PREFIX|CLIENT_REPEAT); - } - - /* Process keys. */ - keylist = options_get_data(&c->session->options, "prefix"); - while (tty_keys_next(&c->tty, &key, &mouse) == 0) { - if (c->session == NULL) - return; - - c->session->activity = time(NULL); - w = c->session->curw->window; - wp = w->active; /* could die */ - oo = &c->session->options; - - /* Special case: number keys jump to pane in identify mode. */ - if (c->flags & CLIENT_IDENTIFY && key >= '0' && key <= '9') { - wp = window_pane_at_index(w, key - '0'); - if (wp != NULL && window_pane_visible(wp)) - window_set_active_pane(w, wp); - server_clear_identify(c); - continue; - } - - status_message_clear(c); - server_clear_identify(c); - if (c->prompt_string != NULL) { - status_prompt_key(c, key); - continue; - } - - /* Check for mouse keys. */ - if (key == KEYC_MOUSE) { - if (options_get_number(oo, "mouse-select-pane")) { - window_set_active_at(w, mouse.x, mouse.y); - wp = w->active; - } - window_pane_mouse(wp, c, &mouse); - continue; - } - - /* Is this a prefix key? */ - isprefix = 0; - for (i = 0; i < ARRAY_LENGTH(keylist); i++) { - if (key == ARRAY_ITEM(keylist, i)) { - isprefix = 1; - break; - } - } - - /* No previous prefix key. */ - if (!(c->flags & CLIENT_PREFIX)) { - if (isprefix) - c->flags |= CLIENT_PREFIX; - else { - /* Try as a non-prefix key binding. */ - if ((bd = key_bindings_lookup(key)) == NULL) - window_pane_key(wp, c, key); - else - key_bindings_dispatch(bd, c); - } - continue; - } - - /* Prefix key already pressed. Reset prefix and lookup key. */ - c->flags &= ~CLIENT_PREFIX; - if ((bd = key_bindings_lookup(key | KEYC_PREFIX)) == NULL) { - /* If repeating, treat this as a key, else ignore. */ - if (c->flags & CLIENT_REPEAT) { - c->flags &= ~CLIENT_REPEAT; - if (isprefix) - c->flags |= CLIENT_PREFIX; - else - window_pane_key(wp, c, key); - } - continue; - } - - /* If already repeating, but this key can't repeat, skip it. */ - if (c->flags & CLIENT_REPEAT && !bd->can_repeat) { - c->flags &= ~CLIENT_REPEAT; - if (isprefix) - c->flags |= CLIENT_PREFIX; - else - window_pane_key(wp, c, key); - continue; - } - - /* If this key can repeat, reset the repeat flags and timer. */ - if (xtimeout != 0 && bd->can_repeat) { - c->flags |= CLIENT_PREFIX|CLIENT_REPEAT; - - tv.tv_sec = xtimeout / 1000; - tv.tv_usec = (xtimeout % 1000) * 1000L; - if (gettimeofday(&c->repeat_timer, NULL) != 0) - fatal("gettimeofday failed"); - timeradd(&c->repeat_timer, &tv, &c->repeat_timer); - } - - /* Dispatch the command. */ - key_bindings_dispatch(bd, c); - } - if (c->session == NULL) - return; - w = c->session->curw->window; - wp = w->active; - oo = &c->session->options; - s = wp->screen; - - /* - * Update cursor position and mode settings. The scroll region and - * attributes are cleared across poll(2) as this is the most likely - * time a user may interrupt tmux, for example with ~^Z in ssh(1). This - * is a compromise between excessive resets and likelihood of an - * interrupt. - * - * tty_region/tty_reset/tty_update_mode already take care of not - * resetting things that are already in their default state. - */ - tty_region(&c->tty, 0, c->tty.sy - 1); - - status = options_get_number(oo, "status"); - if (!window_pane_visible(wp) || wp->yoff + s->cy >= c->tty.sy - status) - tty_cursor(&c->tty, 0, 0); - else - tty_cursor(&c->tty, wp->xoff + s->cx, wp->yoff + s->cy); - - mode = s->mode; - if (TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry) != NULL && - options_get_number(oo, "mouse-select-pane")) - mode |= MODE_MOUSE; - tty_update_mode(&c->tty, mode); - tty_reset(&c->tty); -} - -/* Lost a client. */ -void -server_lost_client(struct client *c) -{ - u_int i; - - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - if (ARRAY_ITEM(&clients, i) == c) - ARRAY_SET(&clients, i, NULL); - } - log_debug("lost client %d", c->ibuf.fd); - - /* - * If CLIENT_TERMINAL hasn't been set, then tty_init hasn't been called - * and tty_free might close an unrelated fd. - */ - if (c->flags & CLIENT_TERMINAL) - tty_free(&c->tty); - - screen_free(&c->status); - job_tree_free(&c->status_jobs); - - if (c->title != NULL) - xfree(c->title); - - if (c->message_string != NULL) - xfree(c->message_string); - - if (c->prompt_string != NULL) - xfree(c->prompt_string); - if (c->prompt_buffer != NULL) - xfree(c->prompt_buffer); - for (i = 0; i < ARRAY_LENGTH(&c->prompt_hdata); i++) - xfree(ARRAY_ITEM(&c->prompt_hdata, i)); - ARRAY_FREE(&c->prompt_hdata); - - if (c->cwd != NULL) - xfree(c->cwd); - - close(c->ibuf.fd); - imsg_clear(&c->ibuf); - - for (i = 0; i < ARRAY_LENGTH(&dead_clients); i++) { - if (ARRAY_ITEM(&dead_clients, i) == NULL) { - ARRAY_SET(&dead_clients, i, c); - break; - } - } - if (i == ARRAY_LENGTH(&dead_clients)) - ARRAY_ADD(&dead_clients, c); - c->flags |= CLIENT_DEAD; - - recalculate_sizes(); -} - /* Free dead, unreferenced clients and sessions. */ void server_clean_dead(void) @@ -1146,221 +607,29 @@ server_clean_dead(void) } } -/* Handle window data. */ +/* Call any once-per-second timers. */ void -server_handle_window(struct window *w, struct window_pane *wp) +server_second_timers(void) { - struct session *s; - u_int i; - int update; - - window_pane_parse(wp); - - if ((w->flags & (WINDOW_BELL|WINDOW_ACTIVITY|WINDOW_CONTENT)) == 0) - return; - - update = 0; - for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { - s = ARRAY_ITEM(&sessions, i); - if (s == NULL || !session_has(s, w)) - continue; - - update += server_check_window_bell(s, w); - update += server_check_window_activity(s, w); - update += server_check_window_content(s, w, wp); - } - if (update) - server_status_window(w); - - w->flags &= ~(WINDOW_BELL|WINDOW_ACTIVITY|WINDOW_CONTENT); -} - -int -server_check_window_bell(struct session *s, struct window *w) -{ - struct client *c; - u_int i; - int action, visual; - - if (!(w->flags & WINDOW_BELL)) - return (0); - if (session_alert_has_window(s, w, WINDOW_BELL)) - return (0); - session_alert_add(s, w, WINDOW_BELL); - - action = options_get_number(&s->options, "bell-action"); - switch (action) { - case BELL_ANY: - if (s->flags & SESSION_UNATTACHED) - break; - visual = options_get_number(&s->options, "visual-bell"); - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - c = ARRAY_ITEM(&clients, i); - if (c == NULL || c->session != s) - continue; - if (!visual) { - tty_putcode(&c->tty, TTYC_BEL); - continue; - } - if (c->session->curw->window == w) { - status_message_set(c, "Bell in current window"); - continue; - } - status_message_set(c, "Bell in window %u", - winlink_find_by_window(&s->windows, w)->idx); - } - break; - case BELL_CURRENT: - if (s->flags & SESSION_UNATTACHED) - break; - visual = options_get_number(&s->options, "visual-bell"); - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - c = ARRAY_ITEM(&clients, i); - if (c == NULL || c->session != s) - continue; - if (c->session->curw->window != w) - continue; - if (!visual) { - tty_putcode(&c->tty, TTYC_BEL); - continue; - } - status_message_set(c, "Bell in current window"); - } - break; - } - return (1); -} - -int -server_check_window_activity(struct session *s, struct window *w) -{ - struct client *c; - u_int i; - - if (!(w->flags & WINDOW_ACTIVITY)) - return (0); - - if (!options_get_number(&w->options, "monitor-activity")) - return (0); - - if (session_alert_has_window(s, w, WINDOW_ACTIVITY)) - return (0); - if (s->curw->window == w) - return (0); - - session_alert_add(s, w, WINDOW_ACTIVITY); - if (s->flags & SESSION_UNATTACHED) - return (0); - if (options_get_number(&s->options, "visual-activity")) { - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - c = ARRAY_ITEM(&clients, i); - if (c == NULL || c->session != s) - continue; - status_message_set(c, "Activity in window %u", - winlink_find_by_window(&s->windows, w)->idx); - } - } - - return (1); -} - -int -server_check_window_content( - struct session *s, struct window *w, struct window_pane *wp) -{ - struct client *c; - u_int i; - char *found, *ptr; - - if (!(w->flags & WINDOW_ACTIVITY)) /* activity for new content */ - return (0); - - ptr = options_get_string(&w->options, "monitor-content"); - if (ptr == NULL || *ptr == '\0') - return (0); - - if (session_alert_has_window(s, w, WINDOW_CONTENT)) - return (0); - if (s->curw->window == w) - return (0); - - if ((found = window_pane_search(wp, ptr, NULL)) == NULL) - return (0); - xfree(found); - - session_alert_add(s, w, WINDOW_CONTENT); - if (s->flags & SESSION_UNATTACHED) - return (0); - if (options_get_number(&s->options, "visual-content")) { - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - c = ARRAY_ITEM(&clients, i); - if (c == NULL || c->session != s) - continue; - status_message_set(c, "Content in window %u", - winlink_find_by_window(&s->windows, w)->idx); - } - } - - return (1); -} - -/* Check if window still exists. */ -void -server_check_window(struct window *w) -{ - struct window_pane *wp, *wq; - struct options *oo = &w->options; - struct session *s; - struct winlink *wl; + struct window *w; + struct window_pane *wp; u_int i; - int destroyed; - destroyed = 1; + if (options_get_number(&global_s_options, "lock-server")) + server_lock_server(); + else + server_lock_sessions(); - wp = TAILQ_FIRST(&w->panes); - while (wp != NULL) { - wq = TAILQ_NEXT(wp, entry); - /* - * If the pane has died and the remain-on-exit flag is not set, - * remove the pane; otherwise, if the flag is set, don't allow - * the window to be destroyed (or it'll close when the last - * pane dies). - */ - if (wp->fd == -1 && !options_get_number(oo, "remain-on-exit")) { - layout_close_pane(wp); - window_remove_pane(w, wp); - server_redraw_window(w); - } else - destroyed = 0; - wp = wq; - } - - if (!destroyed) - return; - - for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { - s = ARRAY_ITEM(&sessions, i); - if (s == NULL) - continue; - if (!session_has(s, w)) + for (i = 0; i < ARRAY_LENGTH(&windows); i++) { + w = ARRAY_ITEM(&windows, i); + if (w == NULL) continue; - restart: - /* Detach window and either redraw or kill clients. */ - RB_FOREACH(wl, winlinks, &s->windows) { - if (wl->window != w) - continue; - if (session_detach(s, wl)) { - server_destroy_session_group(s); - break; - } - server_redraw_session(s); - server_status_session_group(s); - goto restart; + TAILQ_FOREACH(wp, &w->panes, entry) { + if (wp->mode != NULL && wp->mode->timer != NULL) + wp->mode->timer(wp); } } - - recalculate_sizes(); } /* Lock the server if ALL sessions have hit the time limit. */ @@ -1418,31 +687,6 @@ server_lock_sessions(void) } } -/* Call any once-per-second timers. */ -void -server_second_timers(void) -{ - struct window *w; - struct window_pane *wp; - u_int i; - - if (options_get_number(&global_s_options, "lock-server")) - server_lock_server(); - else - server_lock_sessions(); - - for (i = 0; i < ARRAY_LENGTH(&windows); i++) { - w = ARRAY_ITEM(&windows, i); - if (w == NULL) - continue; - - TAILQ_FOREACH(wp, &w->panes, entry) { - if (wp->mode != NULL && wp->mode->timer != NULL) - wp->mode->timer(wp); - } - } -} - /* Update socket execute permissions based on whether sessions are attached. */ int server_update_socket(void) diff --git a/tmux.h b/tmux.h index e97d4aaa..42badd33 100644 --- a/tmux.h +++ b/tmux.h @@ -1517,8 +1517,19 @@ extern struct clients clients; extern struct clients dead_clients; int server_start(char *); -/* server-msg.c */ -int server_msg_dispatch(struct client *); +/* server-client.c */ +void server_client_create(int); +void server_client_lost(struct client *); +void server_client_callback(int, int, void *); +void server_client_loop(void); + +/* server-job.c */ +void server_job_callback(int, int, void *); +void server_job_loop(void); + +/* server-window.c */ +void server_window_callback(int, int, void *); +void server_window_loop(void); /* server-fn.c */ void server_fill_environ(struct session *, struct environ *); @@ -1850,7 +1861,7 @@ void buffer_write8(struct buffer *, uint8_t); uint8_t buffer_read8(struct buffer *); /* buffer-poll.c */ -int buffer_poll(struct pollfd *, struct buffer *, struct buffer *); +int buffer_poll(int, int, struct buffer *, struct buffer *); /* log.c */ void log_open_tty(int); From 9c40a4edc57f791d39ec5240c69716a663693d8a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 22 Oct 2009 20:04:21 +0000 Subject: [PATCH 0439/1180] The client buffers have to be checked after every event in order to catch the escape timers and properly reset the cursor. --- server-client.c | 71 +++++++++++++++++++++++++------------------------ 1 file changed, 36 insertions(+), 35 deletions(-) diff --git a/server-client.c b/server-client.c index 5775a2fb..0269e0c7 100644 --- a/server-client.c +++ b/server-client.c @@ -175,7 +175,6 @@ server_client_callback(int fd, int events, void *data) if (buffer_poll(fd, events, c->tty.in, c->tty.out) != 0) goto client_lost; - server_client_handle_data(c); } return; @@ -184,7 +183,42 @@ client_lost: server_client_lost(c); } -/* Input data from client. */ +/* Client functions that need to happen every loop. */ +void +server_client_loop(void) +{ + struct client *c; + struct window *w; + struct window_pane *wp; + u_int i; + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c == NULL || c->session == NULL) + continue; + + server_client_check_timers(c); + server_client_check_redraw(c); + + server_client_handle_data(c); + } + + /* + * Any windows will have been redrawn as part of clients, so clear + * their flags now. + */ + for (i = 0; i < ARRAY_LENGTH(&windows); i++) { + w = ARRAY_ITEM(&windows, i); + if (w == NULL) + continue; + + w->flags &= ~WINDOW_REDRAW; + TAILQ_FOREACH(wp, &w->panes, entry) + wp->flags &= ~PANE_REDRAW; + } +} + +/* Handle data input or output from client. */ void server_client_handle_data(struct client *c) { @@ -338,39 +372,6 @@ server_client_handle_data(struct client *c) tty_reset(&c->tty); } -/* Client functions that need to happen every loop. */ -void -server_client_loop(void) -{ - struct client *c; - struct window *w; - struct window_pane *wp; - u_int i; - - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - c = ARRAY_ITEM(&clients, i); - if (c == NULL || c->session == NULL) - continue; - - server_client_check_timers(c); - server_client_check_redraw(c); - } - - /* - * Any windows will have been redrawn as part of clients, so clear - * their flags now. - */ - for (i = 0; i < ARRAY_LENGTH(&windows); i++) { - w = ARRAY_ITEM(&windows, i); - if (w == NULL) - continue; - - w->flags &= ~WINDOW_REDRAW; - TAILQ_FOREACH(wp, &w->panes, entry) - wp->flags &= ~PANE_REDRAW; - } -} - /* Check for client redraws. */ void server_client_check_redraw(struct client *c) From 1f22a199fbecb64ed1ae872c009d5b5408acc95e Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 22 Oct 2009 21:01:52 +0000 Subject: [PATCH 0440/1180] Redraw checks have to after handling input or pane redraw flags set by key presses will not be acted on. --- server-client.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server-client.c b/server-client.c index 0269e0c7..e2acbf15 100644 --- a/server-client.c +++ b/server-client.c @@ -197,10 +197,10 @@ server_client_loop(void) if (c == NULL || c->session == NULL) continue; + server_client_handle_data(c); + server_client_check_timers(c); server_client_check_redraw(c); - - server_client_handle_data(c); } /* From c2b8f3b55a15e61ce5d1c601c75eca7a81006e0a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 23 Oct 2009 15:48:39 +0000 Subject: [PATCH 0441/1180] Support the bright fg/bg colour SGR 90-97 and 100-107. Reported by Tim Allen. --- input.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/input.c b/input.c index ff7990e0..bb6ac496 100644 --- a/input.c +++ b/input.c @@ -1470,6 +1470,28 @@ input_handle_sequence_sgr(struct input_ctx *ictx) gc->flags &= ~GRID_FLAG_BG256; gc->bg = 8; break; + case 90: + case 91: + case 92: + case 93: + case 94: + case 95: + case 96: + case 97: + gc->flags |= GRID_FLAG_FG256; + gc->fg = m - 82; + break; + case 100: + case 101: + case 102: + case 103: + case 104: + case 105: + case 106: + case 107: + gc->flags |= GRID_FLAG_BG256; + gc->bg = m - 92; + break; } } } From df818c1b69aed575d009221cdc4e9dc81135ed6c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 24 Oct 2009 10:12:39 +0000 Subject: [PATCH 0442/1180] -a option to kill all except current pane. From Tiago Cunha, thanks! --- cmd-kill-pane.c | 23 ++++++++++++++++++----- tmux.1 | 9 ++++++++- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/cmd-kill-pane.c b/cmd-kill-pane.c index 38d0daef..351ef0c8 100644 --- a/cmd-kill-pane.c +++ b/cmd-kill-pane.c @@ -30,8 +30,8 @@ int cmd_kill_pane_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_kill_pane_entry = { "kill-pane", "killp", - CMD_TARGET_PANE_USAGE, - 0, 0, + "[-a] " CMD_TARGET_PANE_USAGE, + 0, CMD_CHFLAG('a'), cmd_target_init, cmd_target_parse, cmd_kill_pane_exec, @@ -44,7 +44,7 @@ cmd_kill_pane_exec(struct cmd *self, struct cmd_ctx *ctx) { struct cmd_target_data *data = self->data; struct winlink *wl; - struct window_pane *wp; + struct window_pane *loopwp, *nextwp, *wp; if ((wl = cmd_find_pane(ctx, data->target, NULL, &wp)) == NULL) return (-1); @@ -56,8 +56,21 @@ cmd_kill_pane_exec(struct cmd *self, struct cmd_ctx *ctx) return (0); } - layout_close_pane(wp); - window_remove_pane(wl->window, wp); + if (data->chflags & CMD_CHFLAG('a')) { + loopwp = TAILQ_FIRST(&wl->window->panes); + while (loopwp != NULL) { + nextwp = TAILQ_NEXT(loopwp, entry); + if (loopwp != wp) { + layout_close_pane(loopwp); + window_remove_pane(wl->window, loopwp); + } + loopwp = nextwp; + } + } else { + layout_close_pane(wp); + window_remove_pane(wl->window, wp); + } server_redraw_window(wl->window); + return (0); } diff --git a/tmux.1 b/tmux.1 index e25657e2..80283678 100644 --- a/tmux.1 +++ b/tmux.1 @@ -740,10 +740,17 @@ If only one window is matched, it'll be automatically selected, otherwise a choice list is shown. This command only works from inside .Nm . -.It Ic kill-pane Op Fl t Ar target-pane +.It Xo Ic kill-pane +.Op Fl a +.Op Fl t Ar target-pane +.Xc .D1 (alias: Ic killp ) Destroy the given pane. If no panes remain in the containing window, it is also destroyed. +The +.Fl a +option kills all but the pane given with +.Fl t . .It Ic kill-window Op Fl t Ar target-window .D1 (alias: Ic killw ) Kill the current window or the window at From 385236e967b11889ccd7d7059e5604fe584b1712 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 24 Oct 2009 21:18:33 +0000 Subject: [PATCH 0443/1180] Bring a comment into line with reality. --- tty-term.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/tty-term.c b/tty-term.c index 02dece6e..7add7cab 100644 --- a/tty-term.c +++ b/tty-term.c @@ -359,11 +359,7 @@ tty_term_find(char *name, int fd, const char *overrides, char **cause) if (strcmp(tty_term_string(term, TTYC_OP), "\033[39;49m") == 0) term->flags |= TERM_HASDEFAULTS; - /* - * Try to figure out if we have 256 or 88 colours. The standard xterm - * definitions are broken (well, or the way they are parsed is: in any - * case they end up returning 8). So also do a hack. - */ + /* Figure out if we have 256 or 88 colours. */ if (tty_term_number(term, TTYC_COLORS) == 256) term->flags |= TERM_256COLOURS; if (tty_term_number(term, TTYC_COLORS) == 88) From 7b4f0398c38ada2c46a0d0c37d6bfc91e39eb78a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 25 Oct 2009 01:10:57 +0000 Subject: [PATCH 0444/1180] [ is a punctuation character and should be escaped with Ql. Although the current groff version we have seems to handle it fine, other versions are not so tolerant. --- tmux.1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tmux.1 b/tmux.1 index 80283678..f553b18c 100644 --- a/tmux.1 +++ b/tmux.1 @@ -502,7 +502,7 @@ for later insertion into another window. This mode is entered with the .Ic copy-mode command, bound to -.Ql [ +.Ql \&[ by default. .El .Pp From 5bed597e619e4b749c68273d45441406cbab16a9 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 25 Oct 2009 17:51:07 +0000 Subject: [PATCH 0445/1180] +time.h. --- server-client.c | 1 + 1 file changed, 1 insertion(+) diff --git a/server-client.c b/server-client.c index e2acbf15..ec08ed0e 100644 --- a/server-client.c +++ b/server-client.c @@ -20,6 +20,7 @@ #include #include +#include #include #include From 3a7636ff0f3eed214a847edbfb3bd8007128d49a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 25 Oct 2009 21:11:21 +0000 Subject: [PATCH 0446/1180] Remove the -d flag to tmux and just use op/AX to detect default colours. Irritatingly, although op can be used to tell if a terminal supports default colours, it can't be used to set them because in some terminfo descriptions it resets attributes as a side-effect (acts as sgr0) and in others it doesn't, so it is not possible to determine reliably what the terminal state will be afterwards. So if AX is missing and op is present, tmux just sends sgr0. Anyone using -d for a terminal who finds they actually needed it can replace it using terminal-overrides, but please let me know as it is probably an omission from terminfo. --- server-client.c | 2 -- tmux.c | 5 +---- tmux.h | 8 +++----- tty-term.c | 11 ----------- tty.c | 37 +++++++++++++++++++++++-------------- 5 files changed, 27 insertions(+), 36 deletions(-) diff --git a/server-client.c b/server-client.c index ec08ed0e..3c096e12 100644 --- a/server-client.c +++ b/server-client.c @@ -703,8 +703,6 @@ server_client_msg_identify( c->tty.term_flags |= TERM_256COLOURS; else if (data->flags & IDENTIFY_88COLOURS) c->tty.term_flags |= TERM_88COLOURS; - if (data->flags & IDENTIFY_HASDEFAULTS) - c->tty.term_flags |= TERM_HASDEFAULTS; tty_resize(&c->tty); diff --git a/tmux.c b/tmux.c index d15b3fe1..add7289e 100644 --- a/tmux.c +++ b/tmux.c @@ -62,7 +62,7 @@ __dead void usage(void) { fprintf(stderr, - "usage: %s [-28dlquv] [-c shell-command] [-f file] [-L socket-name]\n" + "usage: %s [-28lquv] [-c shell-command] [-f file] [-L socket-name]\n" " [-S socket-path] [command [flags]]\n", __progname); exit(1); @@ -317,9 +317,6 @@ main(int argc, char **argv) xfree(shellcmd); shellcmd = xstrdup(optarg); break; - case 'd': - flags |= IDENTIFY_HASDEFAULTS; - break; case 'f': if (cfg_file != NULL) xfree(cfg_file); diff --git a/tmux.h b/tmux.h index 42badd33..430470d4 100644 --- a/tmux.h +++ b/tmux.h @@ -346,7 +346,6 @@ struct msg_identify_data { #define IDENTIFY_UTF8 0x1 #define IDENTIFY_256COLOURS 0x2 #define IDENTIFY_88COLOURS 0x4 -#define IDENTIFY_HASDEFAULTS 0x8 int flags; }; @@ -908,10 +907,9 @@ struct tty_term { struct tty_code codes[NTTYCODE]; -#define TERM_HASDEFAULTS 0x1 -#define TERM_256COLOURS 0x2 -#define TERM_88COLOURS 0x4 -#define TERM_EARLYWRAP 0x8 +#define TERM_256COLOURS 0x1 +#define TERM_88COLOURS 0x2 +#define TERM_EARLYWRAP 0x4 int flags; SLIST_ENTRY(tty_term) entry; diff --git a/tty-term.c b/tty-term.c index 7add7cab..8a592b31 100644 --- a/tty-term.c +++ b/tty-term.c @@ -348,17 +348,6 @@ tty_term_find(char *name, int fd, const char *overrides, char **cause) goto error; } - /* - * Figure out if terminal support default colours. AX is a screen - * extension which indicates this. Also check if op (orig_pair) uses - * the default colours - if it does, this is a good indication the - * terminal supports them. - */ - if (tty_term_flag(term, TTYC_AX)) - term->flags |= TERM_HASDEFAULTS; - if (strcmp(tty_term_string(term, TTYC_OP), "\033[39;49m") == 0) - term->flags |= TERM_HASDEFAULTS; - /* Figure out if we have 256 or 88 colours. */ if (tty_term_number(term, TTYC_COLORS) == 256) term->flags |= TERM_256COLOURS; diff --git a/tty.c b/tty.c index 596779e1..d329e15b 100644 --- a/tty.c +++ b/tty.c @@ -1236,13 +1236,21 @@ tty_attributes_fg(struct tty *tty, const struct grid_cell *gc) tty_reset(tty); } - if (fg == 8 && - !(tty->term->flags & TERM_HASDEFAULTS) && - !(tty->term_flags & TERM_HASDEFAULTS)) - fg = 7; - if (fg == 8) - tty_puts(tty, "\033[39m"); - else + if (fg == 8) { + if (tty_term_has(tty->term, TTYC_AX)) { + /* AX is an extension that means \033[39m works. */ + tty_puts(tty, "\033[39m"); + } else if (tty_term_has(tty->term, TTYC_OP)) { + /* + * op can be used to look for default colours but there + * is no point in using it - with some terminals it + * does SGR0 and others not, so SGR0 is needed anyway + * to put the terminal into a known state. + */ + tty_reset(tty); + } else + tty_putcode1(tty, TTYC_SETAF, 7); + } else tty_putcode1(tty, TTYC_SETAF, fg); } @@ -1262,12 +1270,13 @@ tty_attributes_bg(struct tty *tty, const struct grid_cell *gc) bg &= 7; } - if (bg == 8 && - !(tty->term->flags & TERM_HASDEFAULTS) && - !(tty->term_flags & TERM_HASDEFAULTS)) - bg = 0; - if (bg == 8) - tty_puts(tty, "\033[49m"); - else + if (bg == 8) { + if (tty_term_has(tty->term, TTYC_AX)) { + tty_puts(tty, "\033[49m"); + } else if (tty_term_has(tty->term, TTYC_OP)) + tty_reset(tty); + else + tty_putcode1(tty, TTYC_SETAB, 0); + } else tty_putcode1(tty, TTYC_SETAB, bg); } From 48b6d18e7fc29c8bdbec24a76d017290cc93f748 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 25 Oct 2009 21:12:15 +0000 Subject: [PATCH 0447/1180] Remove -d from tmux.1 as well. --- tmux.1 | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/tmux.1 b/tmux.1 index f553b18c..497192fa 100644 --- a/tmux.1 +++ b/tmux.1 @@ -23,7 +23,7 @@ .Sh SYNOPSIS .Nm tmux .Bk -words -.Op Fl 28dlquv +.Op Fl 28lquv .Op Fl c Ar shell-command .Op Fl f Ar file .Op Fl L Ar socket-name @@ -111,10 +111,6 @@ If necessary, the server will be started to retrieve the .Ic default-shell option. -.It Fl d -Force -.Nm -to assume the terminal supports default colours. .It Fl f Ar file Specify an alternative configuration file. By default, From 3c9619bb0a748b127b2d7839e6e4c971ec02ba40 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 25 Oct 2009 22:00:15 +0000 Subject: [PATCH 0448/1180] Don't try to continue processing a client if the session has been destroyed. --- server-client.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/server-client.c b/server-client.c index 3c096e12..6d00dd37 100644 --- a/server-client.c +++ b/server-client.c @@ -199,9 +199,10 @@ server_client_loop(void) continue; server_client_handle_data(c); - - server_client_check_timers(c); - server_client_check_redraw(c); + if (c->session != NULL) { + server_client_check_timers(c); + server_client_check_redraw(c); + } } /* From 10a656eedb8c64407a80fe29b8f2ba5bbd7102d3 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 26 Oct 2009 13:02:53 +0000 Subject: [PATCH 0449/1180] Remove the xterm-keys code which is broken (a replacement is coming but some more cleanup is needed first). --- input-keys.c | 84 ++++++++++++++++------------------------------------ tty-keys.c | 79 ++---------------------------------------------- 2 files changed, 29 insertions(+), 134 deletions(-) diff --git a/input-keys.c b/input-keys.c index f73bcf36..c8697cd0 100644 --- a/input-keys.c +++ b/input-keys.c @@ -32,7 +32,6 @@ struct input_key_ent { #define INPUTKEY_KEYPAD 0x1 /* keypad key */ #define INPUTKEY_CURSOR 0x2 /* cursor key */ #define INPUTKEY_CTRL 0x4 /* may be modified with ctrl */ -#define INPUTKEY_XTERM 0x4 /* may have xterm argument appended */ }; struct input_key_ent input_keys[] = { @@ -40,32 +39,32 @@ struct input_key_ent input_keys[] = { { KEYC_BSPACE, "\177", 0 }, /* Function keys. */ - { KEYC_F1, "\033OP", INPUTKEY_CTRL|INPUTKEY_XTERM }, - { KEYC_F2, "\033OQ", INPUTKEY_CTRL|INPUTKEY_XTERM }, - { KEYC_F3, "\033OR", INPUTKEY_CTRL|INPUTKEY_XTERM }, - { KEYC_F4, "\033OS", INPUTKEY_CTRL|INPUTKEY_XTERM }, - { KEYC_F5, "\033[15~", INPUTKEY_CTRL|INPUTKEY_XTERM }, - { KEYC_F6, "\033[17~", INPUTKEY_CTRL|INPUTKEY_XTERM }, - { KEYC_F7, "\033[18~", INPUTKEY_CTRL|INPUTKEY_XTERM }, - { KEYC_F8, "\033[19~", INPUTKEY_CTRL|INPUTKEY_XTERM }, - { KEYC_F9, "\033[20~", INPUTKEY_CTRL|INPUTKEY_XTERM }, - { KEYC_F10, "\033[21~", INPUTKEY_CTRL|INPUTKEY_XTERM }, - { KEYC_F11, "\033[23~", INPUTKEY_CTRL|INPUTKEY_XTERM }, - { KEYC_F12, "\033[24~", INPUTKEY_CTRL|INPUTKEY_XTERM }, - { KEYC_F13, "\033[25~", INPUTKEY_CTRL|INPUTKEY_XTERM }, - { KEYC_F14, "\033[26~", INPUTKEY_CTRL|INPUTKEY_XTERM }, - { KEYC_F15, "\033[28~", INPUTKEY_CTRL|INPUTKEY_XTERM }, - { KEYC_F16, "\033[29~", INPUTKEY_CTRL|INPUTKEY_XTERM }, - { KEYC_F17, "\033[31~", INPUTKEY_CTRL|INPUTKEY_XTERM }, - { KEYC_F18, "\033[32~", INPUTKEY_CTRL|INPUTKEY_XTERM }, - { KEYC_F19, "\033[33~", INPUTKEY_CTRL|INPUTKEY_XTERM }, - { KEYC_F20, "\033[34~", INPUTKEY_CTRL|INPUTKEY_XTERM }, - { KEYC_IC, "\033[2~", INPUTKEY_CTRL|INPUTKEY_XTERM }, - { KEYC_DC, "\033[3~", INPUTKEY_CTRL|INPUTKEY_XTERM }, - { KEYC_HOME, "\033[1~", INPUTKEY_CTRL|INPUTKEY_XTERM }, - { KEYC_END, "\033[4~", INPUTKEY_CTRL|INPUTKEY_XTERM }, - { KEYC_NPAGE, "\033[6~", INPUTKEY_CTRL|INPUTKEY_XTERM }, - { KEYC_PPAGE, "\033[5~", INPUTKEY_CTRL|INPUTKEY_XTERM }, + { KEYC_F1, "\033OP", INPUTKEY_CTRL }, + { KEYC_F2, "\033OQ", INPUTKEY_CTRL }, + { KEYC_F3, "\033OR", INPUTKEY_CTRL }, + { KEYC_F4, "\033OS", INPUTKEY_CTRL }, + { KEYC_F5, "\033[15~", INPUTKEY_CTRL }, + { KEYC_F6, "\033[17~", INPUTKEY_CTRL }, + { KEYC_F7, "\033[18~", INPUTKEY_CTRL }, + { KEYC_F8, "\033[19~", INPUTKEY_CTRL }, + { KEYC_F9, "\033[20~", INPUTKEY_CTRL }, + { KEYC_F10, "\033[21~", INPUTKEY_CTRL }, + { KEYC_F11, "\033[23~", INPUTKEY_CTRL }, + { KEYC_F12, "\033[24~", INPUTKEY_CTRL }, + { KEYC_F13, "\033[25~", INPUTKEY_CTRL }, + { KEYC_F14, "\033[26~", INPUTKEY_CTRL }, + { KEYC_F15, "\033[28~", INPUTKEY_CTRL }, + { KEYC_F16, "\033[29~", INPUTKEY_CTRL }, + { KEYC_F17, "\033[31~", INPUTKEY_CTRL }, + { KEYC_F18, "\033[32~", INPUTKEY_CTRL }, + { KEYC_F19, "\033[33~", INPUTKEY_CTRL }, + { KEYC_F20, "\033[34~", INPUTKEY_CTRL }, + { KEYC_IC, "\033[2~", INPUTKEY_CTRL }, + { KEYC_DC, "\033[3~", INPUTKEY_CTRL }, + { KEYC_HOME, "\033[1~", INPUTKEY_CTRL }, + { KEYC_END, "\033[4~", INPUTKEY_CTRL }, + { KEYC_NPAGE, "\033[6~", INPUTKEY_CTRL }, + { KEYC_PPAGE, "\033[5~", INPUTKEY_CTRL }, { KEYC_BTAB, "\033[Z", INPUTKEY_CTRL }, /* Arrow keys. Cursor versions must come first. */ @@ -172,37 +171,6 @@ input_key(struct window_pane *wp, int key) log_debug2("found key 0x%x: \"%s\"", key, ike->data); - /* - * If in xterm keys mode, work out and append the modifier as an - * argument. - */ - xterm_keys = options_get_number(&wp->window->options, "xterm-keys"); - if (xterm_keys && ike->flags & INPUTKEY_XTERM) { - ch = '\0'; - if (key & (KEYC_SHIFT|KEYC_ESCAPE|KEYC_CTRL)) - ch = '8'; - else if (key & (KEYC_ESCAPE|KEYC_CTRL)) - ch = '7'; - else if (key & (KEYC_SHIFT|KEYC_CTRL)) - ch = '6'; - else if (key & KEYC_CTRL) - ch = '5'; - else if (key & (KEYC_SHIFT|KEYC_ESCAPE)) - ch = '4'; - else if (key & KEYC_ESCAPE) - ch = '3'; - else if (key & KEYC_SHIFT) - ch = '2'; - if (ch != '\0') { - buffer_write(wp->out, ike->data, dlen - 1); - buffer_write8(wp->out, ';'); - buffer_write8(wp->out, ch); - buffer_write8(wp->out, ike->data[dlen - 1]); - } else - buffer_write(wp->out, ike->data, dlen); - return; - } - /* * Not in xterm mode. Prefix a \033 for escape, and set bit 5 of the * last byte for ctrl. diff --git a/tty-keys.c b/tty-keys.c index a443bd5a..2a713933 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -26,8 +26,7 @@ #include "tmux.h" void tty_keys_add(struct tty *, const char *, int, int); -int tty_keys_parse_xterm(struct tty *, char *, size_t, size_t *); -int tty_keys_parse_mouse(char *, size_t, size_t *, struct mouse_event *); +int tty_keys_mouse(char *, size_t, size_t *, struct mouse_event *); struct tty_key_ent { enum tty_code_code code; @@ -269,14 +268,7 @@ tty_keys_next(struct tty *tty, int *key, struct mouse_event *mouse) } /* Not found. Is this a mouse key press? */ - *key = tty_keys_parse_mouse(buf, len, &size, mouse); - if (*key != KEYC_NONE) { - buffer_remove(tty->in, size); - goto found; - } - - /* Not found. Try to parse xterm-type arguments. */ - *key = tty_keys_parse_xterm(tty, buf, len, &size); + *key = tty_keys_mouse(buf, len, &size, mouse); if (*key != KEYC_NONE) { buffer_remove(tty->in, size); goto found; @@ -331,7 +323,7 @@ found: } int -tty_keys_parse_mouse(char *buf, size_t len, size_t *size, struct mouse_event *m) +tty_keys_mouse(char *buf, size_t len, size_t *size, struct mouse_event *m) { /* * Mouse sequences are \033[M followed by three characters indicating @@ -353,68 +345,3 @@ tty_keys_parse_mouse(char *buf, size_t len, size_t *size, struct mouse_event *m) m->y -= 33; return (KEYC_MOUSE); } - -int -tty_keys_parse_xterm(struct tty *tty, char *buf, size_t len, size_t *size) -{ - struct tty_key *tk; - char tmp[5]; - size_t tmplen; - int key; - - /* - * xterm sequences with modifier keys are of the form: - * - * ^[[1;xD becomes ^[[D - * ^[[5;x~ becomes ^[[5~ - * - * This function is a bit of a hack. Need to figure out what exact - * format and meaning xterm outputs and fix it. XXX - */ - - log_debug("xterm input is: %.*s", (int) len, buf); - if (len != 6 || memcmp(buf, "\033[1;", 4) != 0) - return (KEYC_NONE); - *size = 6; - - tmplen = 0; - tmp[tmplen++] = '['; - if (buf[5] == '~') { - tmp[tmplen++] = buf[2]; - tmp[tmplen++] = '~'; - } else - tmp[tmplen++] = buf[5]; - log_debug("xterm output is: %.*s", (int) tmplen, tmp); - - tk = tty_keys_find(tty, tmp, tmplen, size); - if (tk == NULL) - return (KEYC_NONE); - key = tk->key; - - switch (buf[4]) { - case '8': - key |= KEYC_SHIFT|KEYC_ESCAPE|KEYC_CTRL; - break; - case '7': - key |= KEYC_ESCAPE|KEYC_CTRL; - break; - case '6': - key |= KEYC_SHIFT|KEYC_CTRL; - break; - case '5': - key |= KEYC_CTRL; - break; - case '4': - key |= KEYC_SHIFT|KEYC_ESCAPE; - break; - case '3': - key |= KEYC_ESCAPE; - break; - case '2': - key |= KEYC_SHIFT; - break; - } - - *size = 6; - return (key); -} From db4452d3074d8e27e88029399bf80d6e5568f2cf Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 26 Oct 2009 13:13:33 +0000 Subject: [PATCH 0450/1180] Rename keypad keys to something more useful. --- input-keys.c | 64 ++++++++++++++++++++++++++-------------------------- key-string.c | 32 +++++++++++++------------- tmux.h | 34 ++++++++++++++-------------- tty-keys.c | 32 +++++++++++++------------- 4 files changed, 81 insertions(+), 81 deletions(-) diff --git a/input-keys.c b/input-keys.c index c8697cd0..f54a0653 100644 --- a/input-keys.c +++ b/input-keys.c @@ -89,38 +89,38 @@ struct input_key_ent input_keys[] = { { KEYC_LEFT, "\033[D", 0 }, /* Keypad keys. Keypad versions must come first. */ - { KEYC_KP0_1, "/", INPUTKEY_KEYPAD }, - { KEYC_KP0_2, "*", INPUTKEY_KEYPAD }, - { KEYC_KP0_3, "-", INPUTKEY_KEYPAD }, - { KEYC_KP1_0, "7", INPUTKEY_KEYPAD }, - { KEYC_KP1_1, "8", INPUTKEY_KEYPAD }, - { KEYC_KP1_2, "9", INPUTKEY_KEYPAD }, - { KEYC_KP1_3, "+", INPUTKEY_KEYPAD }, - { KEYC_KP2_0, "4", INPUTKEY_KEYPAD }, - { KEYC_KP2_1, "5", INPUTKEY_KEYPAD }, - { KEYC_KP2_2, "6", INPUTKEY_KEYPAD }, - { KEYC_KP3_0, "1", INPUTKEY_KEYPAD }, - { KEYC_KP3_1, "2", INPUTKEY_KEYPAD }, - { KEYC_KP3_2, "3", INPUTKEY_KEYPAD }, - { KEYC_KP3_3, "\n", INPUTKEY_KEYPAD }, /* this can be CRLF too? */ - { KEYC_KP4_0, "0", INPUTKEY_KEYPAD }, - { KEYC_KP4_2, ".", INPUTKEY_KEYPAD }, - { KEYC_KP0_1, "\033Oo", 0 }, - { KEYC_KP0_2, "\033Oj", 0 }, - { KEYC_KP0_3, "\033Om", 0 }, - { KEYC_KP1_0, "\033Ow", 0 }, - { KEYC_KP1_1, "\033Ox", 0 }, - { KEYC_KP1_2, "\033Oy", 0 }, - { KEYC_KP1_3, "\033Ok", 0 }, - { KEYC_KP2_0, "\033Ot", 0 }, - { KEYC_KP2_1, "\033Ou", 0 }, - { KEYC_KP2_2, "\033Ov", 0 }, - { KEYC_KP3_0, "\033Oq", 0 }, - { KEYC_KP3_1, "\033Or", 0 }, - { KEYC_KP3_2, "\033Os", 0 }, - { KEYC_KP3_3, "\033OM", 0 }, - { KEYC_KP4_0, "\033Op", 0 }, - { KEYC_KP4_2, "\033On", 0 }, + { KEYC_KP_SLASH, "/", INPUTKEY_KEYPAD }, + { KEYC_KP_STAR, "*", INPUTKEY_KEYPAD }, + { KEYC_KP_MINUS, "-", INPUTKEY_KEYPAD }, + { KEYC_KP_SEVEN, "7", INPUTKEY_KEYPAD }, + { KEYC_KP_EIGHT, "8", INPUTKEY_KEYPAD }, + { KEYC_KP_NINE, "9", INPUTKEY_KEYPAD }, + { KEYC_KP_PLUS, "+", INPUTKEY_KEYPAD }, + { KEYC_KP_FOUR, "4", INPUTKEY_KEYPAD }, + { KEYC_KP_FIVE, "5", INPUTKEY_KEYPAD }, + { KEYC_KP_SIX, "6", INPUTKEY_KEYPAD }, + { KEYC_KP_ONE, "1", INPUTKEY_KEYPAD }, + { KEYC_KP_TWO, "2", INPUTKEY_KEYPAD }, + { KEYC_KP_THREE, "3", INPUTKEY_KEYPAD }, + { KEYC_KP_ENTER, "\n", INPUTKEY_KEYPAD }, + { KEYC_KP_ZERO, "0", INPUTKEY_KEYPAD }, + { KEYC_KP_PERIOD, ".", INPUTKEY_KEYPAD }, + { KEYC_KP_SLASH, "\033Oo", 0 }, + { KEYC_KP_STAR, "\033Oj", 0 }, + { KEYC_KP_MINUS, "\033Om", 0 }, + { KEYC_KP_SEVEN, "\033Ow", 0 }, + { KEYC_KP_EIGHT, "\033Ox", 0 }, + { KEYC_KP_NINE, "\033Oy", 0 }, + { KEYC_KP_PLUS, "\033Ok", 0 }, + { KEYC_KP_FOUR, "\033Ot", 0 }, + { KEYC_KP_FIVE, "\033Ou", 0 }, + { KEYC_KP_SIX, "\033Ov", 0 }, + { KEYC_KP_ONE, "\033Oq", 0 }, + { KEYC_KP_TWO, "\033Or", 0 }, + { KEYC_KP_THREE, "\033Os", 0 }, + { KEYC_KP_ENTER, "\033OM", 0 }, + { KEYC_KP_ZERO, "\033Op", 0 }, + { KEYC_KP_PERIOD, "\033On", 0 }, }; /* Translate a key code from client into an output key sequence. */ diff --git a/key-string.c b/key-string.c index 45026d59..bfccb978 100644 --- a/key-string.c +++ b/key-string.c @@ -69,22 +69,22 @@ struct { { "Right", KEYC_RIGHT }, /* Numeric keypad. */ - { "KP/", KEYC_KP0_1 }, - { "KP*", KEYC_KP0_2 }, - { "KP-", KEYC_KP0_3 }, - { "KP7", KEYC_KP1_0 }, - { "KP8", KEYC_KP1_1 }, - { "KP9", KEYC_KP1_2 }, - { "KP+", KEYC_KP1_3 }, - { "KP4", KEYC_KP2_0 }, - { "KP5", KEYC_KP2_1 }, - { "KP6", KEYC_KP2_2 }, - { "KP1", KEYC_KP3_0 }, - { "KP2", KEYC_KP3_1 }, - { "KP3", KEYC_KP3_2 }, - { "KPEnter", KEYC_KP3_3 }, - { "KP0", KEYC_KP4_0 }, - { "KP.", KEYC_KP4_2 }, + { "KP/", KEYC_KP_SLASH }, + { "KP*", KEYC_KP_STAR }, + { "KP-", KEYC_KP_MINUS }, + { "KP7", KEYC_KP_SEVEN }, + { "KP8", KEYC_KP_EIGHT }, + { "KP9", KEYC_KP_NINE }, + { "KP+", KEYC_KP_PLUS }, + { "KP4", KEYC_KP_FOUR }, + { "KP5", KEYC_KP_FIVE }, + { "KP6", KEYC_KP_SIX }, + { "KP1", KEYC_KP_ONE }, + { "KP2", KEYC_KP_TWO }, + { "KP3", KEYC_KP_THREE }, + { "KPEnter", KEYC_KP_ENTER }, + { "KP0", KEYC_KP_ZERO }, + { "KP.", KEYC_KP_PERIOD }, }; int diff --git a/tmux.h b/tmux.h index 430470d4..5932cc10 100644 --- a/tmux.h +++ b/tmux.h @@ -163,23 +163,23 @@ enum key_code { KEYC_LEFT, KEYC_RIGHT, - /* Numeric keypad. Numbered from top-left, KPY_X. */ - KEYC_KP0_1, - KEYC_KP0_2, - KEYC_KP0_3, - KEYC_KP1_0, - KEYC_KP1_1, - KEYC_KP1_2, - KEYC_KP1_3, - KEYC_KP2_0, - KEYC_KP2_1, - KEYC_KP2_2, - KEYC_KP3_0, - KEYC_KP3_1, - KEYC_KP3_2, - KEYC_KP3_3, - KEYC_KP4_0, - KEYC_KP4_2, + /* Numeric keypad. */ + KEYC_KP_SLASH, + KEYC_KP_STAR, + KEYC_KP_MINUS, + KEYC_KP_SEVEN, + KEYC_KP_EIGHT, + KEYC_KP_NINE, + KEYC_KP_PLUS, + KEYC_KP_FOUR, + KEYC_KP_FIVE, + KEYC_KP_SIX, + KEYC_KP_ONE, + KEYC_KP_TWO, + KEYC_KP_THREE, + KEYC_KP_ENTER, + KEYC_KP_ZERO, + KEYC_KP_PERIOD, }; /* Termcap codes. */ diff --git a/tty-keys.c b/tty-keys.c index 2a713933..1711db7b 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -101,22 +101,22 @@ struct tty_key_ent tty_keys[] = { * mode. Translation of numbers mode/applications mode is done in * input-keys.c. */ - { 0, "\033Oo", KEYC_KP0_1, TTYKEY_RAW }, - { 0, "\033Oj", KEYC_KP0_2, TTYKEY_RAW }, - { 0, "\033Om", KEYC_KP0_3, TTYKEY_RAW }, - { 0, "\033Ow", KEYC_KP1_0, TTYKEY_RAW }, - { 0, "\033Ox", KEYC_KP1_1, TTYKEY_RAW }, - { 0, "\033Oy", KEYC_KP1_2, TTYKEY_RAW }, - { 0, "\033Ok", KEYC_KP1_3, TTYKEY_RAW }, - { 0, "\033Ot", KEYC_KP2_0, TTYKEY_RAW }, - { 0, "\033Ou", KEYC_KP2_1, TTYKEY_RAW }, - { 0, "\033Ov", KEYC_KP2_2, TTYKEY_RAW }, - { 0, "\033Oq", KEYC_KP3_0, TTYKEY_RAW }, - { 0, "\033Or", KEYC_KP3_1, TTYKEY_RAW }, - { 0, "\033Os", KEYC_KP3_2, TTYKEY_RAW }, - { 0, "\033OM", KEYC_KP3_3, TTYKEY_RAW }, - { 0, "\033Op", KEYC_KP4_0, TTYKEY_RAW }, - { 0, "\033On", KEYC_KP4_2, TTYKEY_RAW }, + { 0, "\033Oo", KEYC_KP_SLASH, TTYKEY_RAW }, + { 0, "\033Oj", KEYC_KP_STAR, TTYKEY_RAW }, + { 0, "\033Om", KEYC_KP_MINUS, TTYKEY_RAW }, + { 0, "\033Ow", KEYC_KP_SEVEN, TTYKEY_RAW }, + { 0, "\033Ox", KEYC_KP_EIGHT, TTYKEY_RAW }, + { 0, "\033Oy", KEYC_KP_NINE, TTYKEY_RAW }, + { 0, "\033Ok", KEYC_KP_PLUS, TTYKEY_RAW }, + { 0, "\033Ot", KEYC_KP_FOUR, TTYKEY_RAW }, + { 0, "\033Ou", KEYC_KP_FIVE, TTYKEY_RAW }, + { 0, "\033Ov", KEYC_KP_SIX, TTYKEY_RAW }, + { 0, "\033Oq", KEYC_KP_ONE, TTYKEY_RAW }, + { 0, "\033Or", KEYC_KP_TWO, TTYKEY_RAW }, + { 0, "\033Os", KEYC_KP_THREE, TTYKEY_RAW }, + { 0, "\033OM", KEYC_KP_ENTER, TTYKEY_RAW }, + { 0, "\033Op", KEYC_KP_ZERO, TTYKEY_RAW }, + { 0, "\033On", KEYC_KP_PERIOD, TTYKEY_RAW }, }; RB_GENERATE(tty_keys, tty_key, entry, tty_keys_cmp); From b3604dcf8338092997e7f905dc13b691c01fe5c8 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 26 Oct 2009 13:22:30 +0000 Subject: [PATCH 0451/1180] Tidy up table. --- input-keys.c | 157 ++++++++++++++++++++++++++------------------------- 1 file changed, 79 insertions(+), 78 deletions(-) diff --git a/input-keys.c b/input-keys.c index f54a0653..06a6e1e9 100644 --- a/input-keys.c +++ b/input-keys.c @@ -36,91 +36,92 @@ struct input_key_ent { struct input_key_ent input_keys[] = { /* Backspace key. */ - { KEYC_BSPACE, "\177", 0 }, + { KEYC_BSPACE, "\177", 0 }, /* Function keys. */ - { KEYC_F1, "\033OP", INPUTKEY_CTRL }, - { KEYC_F2, "\033OQ", INPUTKEY_CTRL }, - { KEYC_F3, "\033OR", INPUTKEY_CTRL }, - { KEYC_F4, "\033OS", INPUTKEY_CTRL }, - { KEYC_F5, "\033[15~", INPUTKEY_CTRL }, - { KEYC_F6, "\033[17~", INPUTKEY_CTRL }, - { KEYC_F7, "\033[18~", INPUTKEY_CTRL }, - { KEYC_F8, "\033[19~", INPUTKEY_CTRL }, - { KEYC_F9, "\033[20~", INPUTKEY_CTRL }, - { KEYC_F10, "\033[21~", INPUTKEY_CTRL }, - { KEYC_F11, "\033[23~", INPUTKEY_CTRL }, - { KEYC_F12, "\033[24~", INPUTKEY_CTRL }, - { KEYC_F13, "\033[25~", INPUTKEY_CTRL }, - { KEYC_F14, "\033[26~", INPUTKEY_CTRL }, - { KEYC_F15, "\033[28~", INPUTKEY_CTRL }, - { KEYC_F16, "\033[29~", INPUTKEY_CTRL }, - { KEYC_F17, "\033[31~", INPUTKEY_CTRL }, - { KEYC_F18, "\033[32~", INPUTKEY_CTRL }, - { KEYC_F19, "\033[33~", INPUTKEY_CTRL }, - { KEYC_F20, "\033[34~", INPUTKEY_CTRL }, - { KEYC_IC, "\033[2~", INPUTKEY_CTRL }, - { KEYC_DC, "\033[3~", INPUTKEY_CTRL }, - { KEYC_HOME, "\033[1~", INPUTKEY_CTRL }, - { KEYC_END, "\033[4~", INPUTKEY_CTRL }, - { KEYC_NPAGE, "\033[6~", INPUTKEY_CTRL }, - { KEYC_PPAGE, "\033[5~", INPUTKEY_CTRL }, - { KEYC_BTAB, "\033[Z", INPUTKEY_CTRL }, + { KEYC_F1, "\033OP", INPUTKEY_CTRL }, + { KEYC_F2, "\033OQ", INPUTKEY_CTRL }, + { KEYC_F3, "\033OR", INPUTKEY_CTRL }, + { KEYC_F4, "\033OS", INPUTKEY_CTRL }, + { KEYC_F5, "\033[15~", INPUTKEY_CTRL }, + { KEYC_F6, "\033[17~", INPUTKEY_CTRL }, + { KEYC_F7, "\033[18~", INPUTKEY_CTRL }, + { KEYC_F8, "\033[19~", INPUTKEY_CTRL }, + { KEYC_F9, "\033[20~", INPUTKEY_CTRL }, + { KEYC_F10, "\033[21~", INPUTKEY_CTRL }, + { KEYC_F11, "\033[23~", INPUTKEY_CTRL }, + { KEYC_F12, "\033[24~", INPUTKEY_CTRL }, + { KEYC_F13, "\033[25~", INPUTKEY_CTRL }, + { KEYC_F14, "\033[26~", INPUTKEY_CTRL }, + { KEYC_F15, "\033[28~", INPUTKEY_CTRL }, + { KEYC_F16, "\033[29~", INPUTKEY_CTRL }, + { KEYC_F17, "\033[31~", INPUTKEY_CTRL }, + { KEYC_F18, "\033[32~", INPUTKEY_CTRL }, + { KEYC_F19, "\033[33~", INPUTKEY_CTRL }, + { KEYC_F20, "\033[34~", INPUTKEY_CTRL }, + { KEYC_IC, "\033[2~", INPUTKEY_CTRL }, + { KEYC_DC, "\033[3~", INPUTKEY_CTRL }, + { KEYC_HOME, "\033[1~", INPUTKEY_CTRL }, + { KEYC_END, "\033[4~", INPUTKEY_CTRL }, + { KEYC_NPAGE, "\033[6~", INPUTKEY_CTRL }, + { KEYC_PPAGE, "\033[5~", INPUTKEY_CTRL }, + { KEYC_BTAB, "\033[Z", INPUTKEY_CTRL }, - /* Arrow keys. Cursor versions must come first. */ - { KEYC_UP | KEYC_CTRL, "\033Oa", 0 }, - { KEYC_DOWN | KEYC_CTRL, "\033Ob", 0 }, - { KEYC_RIGHT | KEYC_CTRL, "\033Oc", 0 }, - { KEYC_LEFT | KEYC_CTRL, "\033Od", 0 }, + /* Arrow keys. Cursor versions must come first .*/ + { KEYC_UP|KEYC_CTRL, "\033Oa", 0 }, + { KEYC_DOWN|KEYC_CTRL, "\033Ob", 0 }, + { KEYC_RIGHT|KEYC_CTRL, "\033Oc", 0 }, + { KEYC_LEFT|KEYC_CTRL, "\033Od", 0 }, - { KEYC_UP | KEYC_SHIFT, "\033[a", 0 }, - { KEYC_DOWN | KEYC_SHIFT, "\033[b", 0 }, - { KEYC_RIGHT | KEYC_SHIFT, "\033[c", 0 }, - { KEYC_LEFT | KEYC_SHIFT, "\033[d", 0 }, + { KEYC_UP|KEYC_SHIFT, "\033[a", 0 }, + { KEYC_DOWN|KEYC_SHIFT, "\033[b", 0 }, + { KEYC_RIGHT|KEYC_SHIFT,"\033[c", 0 }, + { KEYC_LEFT|KEYC_SHIFT, "\033[d", 0 }, - { KEYC_UP, "\033OA", INPUTKEY_CURSOR }, - { KEYC_DOWN, "\033OB", INPUTKEY_CURSOR }, - { KEYC_RIGHT, "\033OC", INPUTKEY_CURSOR }, - { KEYC_LEFT, "\033OD", INPUTKEY_CURSOR }, + { KEYC_UP, "\033OA", INPUTKEY_CURSOR }, + { KEYC_DOWN, "\033OB", INPUTKEY_CURSOR }, + { KEYC_RIGHT, "\033OC", INPUTKEY_CURSOR }, + { KEYC_LEFT, "\033OD", INPUTKEY_CURSOR }, - { KEYC_UP, "\033[A", 0 }, - { KEYC_DOWN, "\033[B", 0 }, - { KEYC_RIGHT, "\033[C", 0 }, - { KEYC_LEFT, "\033[D", 0 }, + { KEYC_UP, "\033[A", 0 }, + { KEYC_DOWN, "\033[B", 0 }, + { KEYC_RIGHT, "\033[C", 0 }, + { KEYC_LEFT, "\033[D", 0 }, - /* Keypad keys. Keypad versions must come first. */ - { KEYC_KP_SLASH, "/", INPUTKEY_KEYPAD }, - { KEYC_KP_STAR, "*", INPUTKEY_KEYPAD }, - { KEYC_KP_MINUS, "-", INPUTKEY_KEYPAD }, - { KEYC_KP_SEVEN, "7", INPUTKEY_KEYPAD }, - { KEYC_KP_EIGHT, "8", INPUTKEY_KEYPAD }, - { KEYC_KP_NINE, "9", INPUTKEY_KEYPAD }, - { KEYC_KP_PLUS, "+", INPUTKEY_KEYPAD }, - { KEYC_KP_FOUR, "4", INPUTKEY_KEYPAD }, - { KEYC_KP_FIVE, "5", INPUTKEY_KEYPAD }, - { KEYC_KP_SIX, "6", INPUTKEY_KEYPAD }, - { KEYC_KP_ONE, "1", INPUTKEY_KEYPAD }, - { KEYC_KP_TWO, "2", INPUTKEY_KEYPAD }, - { KEYC_KP_THREE, "3", INPUTKEY_KEYPAD }, - { KEYC_KP_ENTER, "\n", INPUTKEY_KEYPAD }, - { KEYC_KP_ZERO, "0", INPUTKEY_KEYPAD }, - { KEYC_KP_PERIOD, ".", INPUTKEY_KEYPAD }, - { KEYC_KP_SLASH, "\033Oo", 0 }, - { KEYC_KP_STAR, "\033Oj", 0 }, - { KEYC_KP_MINUS, "\033Om", 0 }, - { KEYC_KP_SEVEN, "\033Ow", 0 }, - { KEYC_KP_EIGHT, "\033Ox", 0 }, - { KEYC_KP_NINE, "\033Oy", 0 }, - { KEYC_KP_PLUS, "\033Ok", 0 }, - { KEYC_KP_FOUR, "\033Ot", 0 }, - { KEYC_KP_FIVE, "\033Ou", 0 }, - { KEYC_KP_SIX, "\033Ov", 0 }, - { KEYC_KP_ONE, "\033Oq", 0 }, - { KEYC_KP_TWO, "\033Or", 0 }, - { KEYC_KP_THREE, "\033Os", 0 }, - { KEYC_KP_ENTER, "\033OM", 0 }, - { KEYC_KP_ZERO, "\033Op", 0 }, - { KEYC_KP_PERIOD, "\033On", 0 }, + /* Keypad keys. Keypad versions must come first.*/ + { KEYC_KP_SLASH, "/", INPUTKEY_KEYPAD }, + { KEYC_KP_STAR, "*", INPUTKEY_KEYPAD }, + { KEYC_KP_MINUS, "-", INPUTKEY_KEYPAD }, + { KEYC_KP_SEVEN, "7", INPUTKEY_KEYPAD }, + { KEYC_KP_EIGHT, "8", INPUTKEY_KEYPAD }, + { KEYC_KP_NINE, "9", INPUTKEY_KEYPAD }, + { KEYC_KP_PLUS, "+", INPUTKEY_KEYPAD }, + { KEYC_KP_FOUR, "4", INPUTKEY_KEYPAD }, + { KEYC_KP_FIVE, "5", INPUTKEY_KEYPAD }, + { KEYC_KP_SIX, "6", INPUTKEY_KEYPAD }, + { KEYC_KP_ONE, "1", INPUTKEY_KEYPAD }, + { KEYC_KP_TWO, "2", INPUTKEY_KEYPAD }, + { KEYC_KP_THREE, "3", INPUTKEY_KEYPAD }, + { KEYC_KP_ENTER, "\n", INPUTKEY_KEYPAD }, + { KEYC_KP_ZERO, "0", INPUTKEY_KEYPAD }, + { KEYC_KP_PERIOD, ".", INPUTKEY_KEYPAD }, + + { KEYC_KP_SLASH, "\033Oo", 0 }, + { KEYC_KP_STAR, "\033Oj", 0 }, + { KEYC_KP_MINUS, "\033Om", 0 }, + { KEYC_KP_SEVEN, "\033Ow", 0 }, + { KEYC_KP_EIGHT, "\033Ox", 0 }, + { KEYC_KP_NINE, "\033Oy", 0 }, + { KEYC_KP_PLUS, "\033Ok", 0 }, + { KEYC_KP_FOUR, "\033Ot", 0 }, + { KEYC_KP_FIVE, "\033Ou", 0 }, + { KEYC_KP_SIX, "\033Ov", 0 }, + { KEYC_KP_ONE, "\033Oq", 0 }, + { KEYC_KP_TWO, "\033Or", 0 }, + { KEYC_KP_THREE, "\033Os", 0 }, + { KEYC_KP_ENTER, "\033OM", 0 }, + { KEYC_KP_ZERO, "\033Op", 0 }, + { KEYC_KP_PERIOD, "\033On", 0 }, }; /* Translate a key code from client into an output key sequence. */ From 25d20006257827e6c8171de1a33f7720977fde32 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 26 Oct 2009 13:29:24 +0000 Subject: [PATCH 0452/1180] Add or fix some comments. --- input-keys.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/input-keys.c b/input-keys.c index 06a6e1e9..4a870cbe 100644 --- a/input-keys.c +++ b/input-keys.c @@ -24,6 +24,13 @@ #include "tmux.h" +/* + * This file is rather misleadingly named, it contains the code which takes a + * key code and translates it into something suitable to be sent to the + * application running in a pane (similar to input.c does in the other + * direction with output). + */ + struct input_key_ent { int key; const char *data; @@ -88,7 +95,7 @@ struct input_key_ent input_keys[] = { { KEYC_RIGHT, "\033[C", 0 }, { KEYC_LEFT, "\033[D", 0 }, - /* Keypad keys. Keypad versions must come first.*/ + /* Keypad keys. Keypad versions must come first. */ { KEYC_KP_SLASH, "/", INPUTKEY_KEYPAD }, { KEYC_KP_STAR, "*", INPUTKEY_KEYPAD }, { KEYC_KP_MINUS, "-", INPUTKEY_KEYPAD }, @@ -124,18 +131,20 @@ struct input_key_ent input_keys[] = { { KEYC_KP_PERIOD, "\033On", 0 }, }; -/* Translate a key code from client into an output key sequence. */ +/* Translate a key code into an output key sequence. */ void input_key(struct window_pane *wp, int key) { struct input_key_ent *ike; u_int i; - char ch; size_t dlen; - int xterm_keys; log_debug2("writing key 0x%x", key); + /* + * If this is a normal 7-bit key, just send it, with a leading escape + * if necessary. + */ if (key != KEYC_NONE && (key & ~KEYC_ESCAPE) < 0x100) { if (key & KEYC_ESCAPE) buffer_write8(wp->out, '\033'); @@ -143,6 +152,7 @@ input_key(struct window_pane *wp, int key) return; } + /* Otherwise look the key up in the table. */ for (i = 0; i < nitems(input_keys); i++) { ike = &input_keys[i]; @@ -172,10 +182,7 @@ input_key(struct window_pane *wp, int key) log_debug2("found key 0x%x: \"%s\"", key, ike->data); - /* - * Not in xterm mode. Prefix a \033 for escape, and set bit 5 of the - * last byte for ctrl. - */ + /* Prefix a \033 for escape and set bit 5 of the last byte for ctrl. */ if (key & KEYC_ESCAPE) buffer_write8(wp->out, '\033'); if (key & KEYC_CTRL && ike->flags & INPUTKEY_CTRL) { @@ -186,7 +193,7 @@ input_key(struct window_pane *wp, int key) buffer_write(wp->out, ike->data, dlen); } -/* Handle input mouse. */ +/* Translate mouse and output. */ void input_mouse(struct window_pane *wp, struct mouse_event *m) { From a0ec4a11ee3a6d51295f671c437fefe9babe3385 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 26 Oct 2009 13:34:26 +0000 Subject: [PATCH 0453/1180] Drop INPUTKEY_CTRL and just handle it as part of the table. --- input-keys.c | 103 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 61 insertions(+), 42 deletions(-) diff --git a/input-keys.c b/input-keys.c index 4a870cbe..a5012b2f 100644 --- a/input-keys.c +++ b/input-keys.c @@ -38,7 +38,6 @@ struct input_key_ent { int flags; #define INPUTKEY_KEYPAD 0x1 /* keypad key */ #define INPUTKEY_CURSOR 0x2 /* cursor key */ -#define INPUTKEY_CTRL 0x4 /* may be modified with ctrl */ }; struct input_key_ent input_keys[] = { @@ -46,35 +45,57 @@ struct input_key_ent input_keys[] = { { KEYC_BSPACE, "\177", 0 }, /* Function keys. */ - { KEYC_F1, "\033OP", INPUTKEY_CTRL }, - { KEYC_F2, "\033OQ", INPUTKEY_CTRL }, - { KEYC_F3, "\033OR", INPUTKEY_CTRL }, - { KEYC_F4, "\033OS", INPUTKEY_CTRL }, - { KEYC_F5, "\033[15~", INPUTKEY_CTRL }, - { KEYC_F6, "\033[17~", INPUTKEY_CTRL }, - { KEYC_F7, "\033[18~", INPUTKEY_CTRL }, - { KEYC_F8, "\033[19~", INPUTKEY_CTRL }, - { KEYC_F9, "\033[20~", INPUTKEY_CTRL }, - { KEYC_F10, "\033[21~", INPUTKEY_CTRL }, - { KEYC_F11, "\033[23~", INPUTKEY_CTRL }, - { KEYC_F12, "\033[24~", INPUTKEY_CTRL }, - { KEYC_F13, "\033[25~", INPUTKEY_CTRL }, - { KEYC_F14, "\033[26~", INPUTKEY_CTRL }, - { KEYC_F15, "\033[28~", INPUTKEY_CTRL }, - { KEYC_F16, "\033[29~", INPUTKEY_CTRL }, - { KEYC_F17, "\033[31~", INPUTKEY_CTRL }, - { KEYC_F18, "\033[32~", INPUTKEY_CTRL }, - { KEYC_F19, "\033[33~", INPUTKEY_CTRL }, - { KEYC_F20, "\033[34~", INPUTKEY_CTRL }, - { KEYC_IC, "\033[2~", INPUTKEY_CTRL }, - { KEYC_DC, "\033[3~", INPUTKEY_CTRL }, - { KEYC_HOME, "\033[1~", INPUTKEY_CTRL }, - { KEYC_END, "\033[4~", INPUTKEY_CTRL }, - { KEYC_NPAGE, "\033[6~", INPUTKEY_CTRL }, - { KEYC_PPAGE, "\033[5~", INPUTKEY_CTRL }, - { KEYC_BTAB, "\033[Z", INPUTKEY_CTRL }, + { KEYC_F1, "\033OP", 0 }, + { KEYC_F2, "\033OQ", 0 }, + { KEYC_F3, "\033OR", 0 }, + { KEYC_F4, "\033OS", 0 }, + { KEYC_F5, "\033[15~", 0 }, + { KEYC_F5|KEYC_CTRL, "\033[15^", 0 }, + { KEYC_F6, "\033[17~", 0 }, + { KEYC_F6|KEYC_CTRL, "\033[17^", 0 }, + { KEYC_F7, "\033[18~", 0 }, + { KEYC_F7|KEYC_CTRL, "\033[18^", 0 }, + { KEYC_F8, "\033[19~", 0 }, + { KEYC_F8|KEYC_CTRL, "\033[19^", 0 }, + { KEYC_F9, "\033[20~", 0 }, + { KEYC_F9|KEYC_CTRL, "\033[20^", 0 }, + { KEYC_F10, "\033[21~", 0 }, + { KEYC_F10|KEYC_CTRL, "\033[21^", 0 }, + { KEYC_F11, "\033[23~", 0 }, + { KEYC_F1|KEYC_CTRL, "\033[23^", 0 }, + { KEYC_F12, "\033[24~", 0 }, + { KEYC_F12|KEYC_CTRL, "\033[24^", 0 }, + { KEYC_F13, "\033[25~", 0 }, + { KEYC_F13|KEYC_CTRL, "\033[25^", 0 }, + { KEYC_F14, "\033[26~", 0 }, + { KEYC_F14|KEYC_CTRL, "\033[26^", 0 }, + { KEYC_F15, "\033[28~", 0 }, + { KEYC_F15|KEYC_CTRL, "\033[28^", 0 }, + { KEYC_F16, "\033[29~", 0 }, + { KEYC_F16|KEYC_CTRL, "\033[29^", 0 }, + { KEYC_F17, "\033[31~", 0 }, + { KEYC_F17|KEYC_CTRL, "\033[31^", 0 }, + { KEYC_F18, "\033[32~", 0 }, + { KEYC_F18|KEYC_CTRL, "\033[32^", 0 }, + { KEYC_F19, "\033[33~", 0 }, + { KEYC_F19|KEYC_CTRL, "\033[33^", 0 }, + { KEYC_F20, "\033[34~", 0 }, + { KEYC_F20|KEYC_CTRL, "\033[34^", 0 }, + { KEYC_IC, "\033[2~", 0 }, + { KEYC_IC|KEYC_CTRL, "\033[2^", 0 }, + { KEYC_DC, "\033[3~", 0 }, + { KEYC_DC|KEYC_CTRL, "\033[3^", 0 }, + { KEYC_HOME, "\033[1~", 0 }, + { KEYC_HOME|KEYC_CTRL, "\033[1^", 0 }, + { KEYC_END, "\033[4~", 0 }, + { KEYC_END|KEYC_CTRL, "\033[4^", 0 }, + { KEYC_NPAGE, "\033[6~", 0 }, + { KEYC_NPAGE|KEYC_CTRL, "\033[6^", 0 }, + { KEYC_PPAGE, "\033[5~", 0 }, + { KEYC_PPAGE|KEYC_CTRL, "\033[5^", 0 }, + { KEYC_BTAB, "\033[Z", 0 }, - /* Arrow keys. Cursor versions must come first .*/ + /* Arrow keys. Cursor versions must come first. */ { KEYC_UP|KEYC_CTRL, "\033Oa", 0 }, { KEYC_DOWN|KEYC_CTRL, "\033Ob", 0 }, { KEYC_RIGHT|KEYC_CTRL, "\033Oc", 0 }, @@ -84,12 +105,22 @@ struct input_key_ent input_keys[] = { { KEYC_DOWN|KEYC_SHIFT, "\033[b", 0 }, { KEYC_RIGHT|KEYC_SHIFT,"\033[c", 0 }, { KEYC_LEFT|KEYC_SHIFT, "\033[d", 0 }, + + { KEYC_UP|KEYC_CTRL, "\033OA", INPUTKEY_CURSOR }, + { KEYC_DOWN|KEYC_CTRL, "\033OB", INPUTKEY_CURSOR }, + { KEYC_RIGHT|KEYC_CTRL, "\033OC", INPUTKEY_CURSOR }, + { KEYC_LEFT|KEYC_CTRL, "\033OD", INPUTKEY_CURSOR }, { KEYC_UP, "\033OA", INPUTKEY_CURSOR }, { KEYC_DOWN, "\033OB", INPUTKEY_CURSOR }, { KEYC_RIGHT, "\033OC", INPUTKEY_CURSOR }, { KEYC_LEFT, "\033OD", INPUTKEY_CURSOR }, + { KEYC_UP|KEYC_CTRL, "\033OA", 0 }, + { KEYC_DOWN|KEYC_CTRL, "\033OB", 0 }, + { KEYC_RIGHT|KEYC_CTRL, "\033OC", 0 }, + { KEYC_LEFT|KEYC_CTRL, "\033OD", 0 }, + { KEYC_UP, "\033[A", 0 }, { KEYC_DOWN, "\033[B", 0 }, { KEYC_RIGHT, "\033[C", 0 }, @@ -165,12 +196,6 @@ input_key(struct window_pane *wp, int key) if ((key & KEYC_ESCAPE) && (ike->key | KEYC_ESCAPE) == key) break; - if ((key & KEYC_SHIFT) && (ike->key | KEYC_SHIFT) == key) - break; - if ((key & KEYC_CTRL) && (ike->key | KEYC_CTRL) == key) { - if (ike->flags & INPUTKEY_CTRL) - break; - } if (ike->key == key) break; } @@ -179,17 +204,11 @@ input_key(struct window_pane *wp, int key) return; } dlen = strlen(ike->data); - log_debug2("found key 0x%x: \"%s\"", key, ike->data); - /* Prefix a \033 for escape and set bit 5 of the last byte for ctrl. */ + /* Prefix a \033 for escape. */ if (key & KEYC_ESCAPE) buffer_write8(wp->out, '\033'); - if (key & KEYC_CTRL && ike->flags & INPUTKEY_CTRL) { - buffer_write(wp->out, ike->data, dlen - 1); - buffer_write8(wp->out, ike->data[dlen - 1] ^ 0x20); - return; - } buffer_write(wp->out, ike->data, dlen); } From fcd3b260ac0a331b0295c2d21783013eaf9169db Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 26 Oct 2009 13:41:46 +0000 Subject: [PATCH 0454/1180] Tidy up table. --- tty-keys.c | 138 ++++++++++++++++++++++++++--------------------------- 1 file changed, 67 insertions(+), 71 deletions(-) diff --git a/tty-keys.c b/tty-keys.c index 1711db7b..5a7df479 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -38,85 +38,81 @@ struct tty_key_ent { struct tty_key_ent tty_keys[] = { /* Function keys. */ - { TTYC_KF1, NULL, KEYC_F1, TTYKEY_CTRL }, - { TTYC_KF2, NULL, KEYC_F2, TTYKEY_CTRL }, - { TTYC_KF3, NULL, KEYC_F3, TTYKEY_CTRL }, - { TTYC_KF4, NULL, KEYC_F4, TTYKEY_CTRL }, - { TTYC_KF5, NULL, KEYC_F5, TTYKEY_CTRL }, - { TTYC_KF6, NULL, KEYC_F6, TTYKEY_CTRL }, - { TTYC_KF7, NULL, KEYC_F7, TTYKEY_CTRL }, - { TTYC_KF8, NULL, KEYC_F8, TTYKEY_CTRL }, - { TTYC_KF9, NULL, KEYC_F9, TTYKEY_CTRL }, - { TTYC_KF10, NULL, KEYC_F10, TTYKEY_CTRL }, - { TTYC_KF11, NULL, KEYC_F11, TTYKEY_CTRL }, - { TTYC_KF12, NULL, KEYC_F12, TTYKEY_CTRL }, - { TTYC_KF13, NULL, KEYC_F13, TTYKEY_CTRL }, - { TTYC_KF14, NULL, KEYC_F14, TTYKEY_CTRL }, - { TTYC_KF15, NULL, KEYC_F15, TTYKEY_CTRL }, - { TTYC_KF16, NULL, KEYC_F16, TTYKEY_CTRL }, - { TTYC_KF17, NULL, KEYC_F17, TTYKEY_CTRL }, - { TTYC_KF18, NULL, KEYC_F18, TTYKEY_CTRL }, - { TTYC_KF19, NULL, KEYC_F19, TTYKEY_CTRL }, - { TTYC_KF20, NULL, KEYC_F20, TTYKEY_CTRL }, - { TTYC_KICH1, NULL, KEYC_IC, TTYKEY_CTRL }, - { TTYC_KDCH1, NULL, KEYC_DC, TTYKEY_CTRL }, - { TTYC_KHOME, NULL, KEYC_HOME, TTYKEY_CTRL }, - { TTYC_KEND, NULL, KEYC_END, TTYKEY_CTRL }, - { TTYC_KNP, NULL, KEYC_NPAGE, TTYKEY_CTRL }, - { TTYC_KPP, NULL, KEYC_PPAGE, TTYKEY_CTRL }, - { TTYC_KCBT, NULL, KEYC_BTAB, TTYKEY_CTRL }, + { TTYC_KF1, NULL, KEYC_F1, TTYKEY_CTRL }, + { TTYC_KF1, NULL, KEYC_F1, TTYKEY_CTRL }, + { TTYC_KF2, NULL, KEYC_F2, TTYKEY_CTRL }, + { TTYC_KF3, NULL, KEYC_F3, TTYKEY_CTRL }, + { TTYC_KF4, NULL, KEYC_F4, TTYKEY_CTRL }, + { TTYC_KF5, NULL, KEYC_F5, TTYKEY_CTRL }, + { TTYC_KF6, NULL, KEYC_F6, TTYKEY_CTRL }, + { TTYC_KF7, NULL, KEYC_F7, TTYKEY_CTRL }, + { TTYC_KF8, NULL, KEYC_F8, TTYKEY_CTRL }, + { TTYC_KF9, NULL, KEYC_F9, TTYKEY_CTRL }, + { TTYC_KF10, NULL, KEYC_F10, TTYKEY_CTRL }, + { TTYC_KF11, NULL, KEYC_F11, TTYKEY_CTRL }, + { TTYC_KF12, NULL, KEYC_F12, TTYKEY_CTRL }, + { TTYC_KF13, NULL, KEYC_F13, TTYKEY_CTRL }, + { TTYC_KF14, NULL, KEYC_F14, TTYKEY_CTRL }, + { TTYC_KF15, NULL, KEYC_F15, TTYKEY_CTRL }, + { TTYC_KF16, NULL, KEYC_F16, TTYKEY_CTRL }, + { TTYC_KF17, NULL, KEYC_F17, TTYKEY_CTRL }, + { TTYC_KF18, NULL, KEYC_F18, TTYKEY_CTRL }, + { TTYC_KF19, NULL, KEYC_F19, TTYKEY_CTRL }, + { TTYC_KF20, NULL, KEYC_F20, TTYKEY_CTRL }, + { TTYC_KICH1, NULL, KEYC_IC, TTYKEY_CTRL }, + { TTYC_KDCH1, NULL, KEYC_DC, TTYKEY_CTRL }, + { TTYC_KHOME, NULL, KEYC_HOME, TTYKEY_CTRL }, + { TTYC_KEND, NULL, KEYC_END, TTYKEY_CTRL }, + { TTYC_KNP, NULL, KEYC_NPAGE, TTYKEY_CTRL }, + { TTYC_KPP, NULL, KEYC_PPAGE, TTYKEY_CTRL }, + { TTYC_KCBT, NULL, KEYC_BTAB, TTYKEY_CTRL }, /* Arrow keys. */ - { 0, "\033OA", KEYC_UP, TTYKEY_RAW }, - { 0, "\033OB", KEYC_DOWN, TTYKEY_RAW }, - { 0, "\033OC", KEYC_RIGHT, TTYKEY_RAW }, - { 0, "\033OD", KEYC_LEFT, TTYKEY_RAW }, + { 0, "\033OA", KEYC_UP, TTYKEY_RAW }, + { 0, "\033OB", KEYC_DOWN, TTYKEY_RAW }, + { 0, "\033OC", KEYC_RIGHT, TTYKEY_RAW }, + { 0, "\033OD", KEYC_LEFT, TTYKEY_RAW }, - { 0, "\033[A", KEYC_UP, TTYKEY_RAW }, - { 0, "\033[B", KEYC_DOWN, TTYKEY_RAW }, - { 0, "\033[C", KEYC_RIGHT, TTYKEY_RAW }, - { 0, "\033[D", KEYC_LEFT, TTYKEY_RAW }, + { 0, "\033[A", KEYC_UP, TTYKEY_RAW }, + { 0, "\033[B", KEYC_DOWN, TTYKEY_RAW }, + { 0, "\033[C", KEYC_RIGHT, TTYKEY_RAW }, + { 0, "\033[D", KEYC_LEFT, TTYKEY_RAW }, - { 0, "\033Oa", KEYC_UP | KEYC_CTRL, TTYKEY_RAW }, - { 0, "\033Ob", KEYC_DOWN | KEYC_CTRL, TTYKEY_RAW }, - { 0, "\033Oc", KEYC_RIGHT | KEYC_CTRL, TTYKEY_RAW }, - { 0, "\033Od", KEYC_LEFT | KEYC_CTRL, TTYKEY_RAW }, - { 0, "\033[a", KEYC_UP | KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[b", KEYC_DOWN | KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[c", KEYC_RIGHT | KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[d", KEYC_LEFT | KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033Oa", KEYC_UP|KEYC_CTRL, TTYKEY_RAW }, + { 0, "\033Ob", KEYC_DOWN|KEYC_CTRL, TTYKEY_RAW }, + { 0, "\033Oc", KEYC_RIGHT|KEYC_CTRL, TTYKEY_RAW }, + { 0, "\033Od", KEYC_LEFT|KEYC_CTRL, TTYKEY_RAW }, + { 0, "\033[a", KEYC_UP|KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[b", KEYC_DOWN|KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[c", KEYC_RIGHT|KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[d", KEYC_LEFT|KEYC_SHIFT, TTYKEY_RAW }, - { TTYC_KCUU1, NULL, KEYC_UP, TTYKEY_CTRL }, - { TTYC_KCUD1, NULL, KEYC_DOWN, TTYKEY_CTRL }, - { TTYC_KCUB1, NULL, KEYC_LEFT, TTYKEY_CTRL }, - { TTYC_KCUF1, NULL, KEYC_RIGHT, TTYKEY_CTRL }, + { TTYC_KCUU1, NULL, KEYC_UP, TTYKEY_CTRL }, + { TTYC_KCUD1, NULL, KEYC_DOWN, TTYKEY_CTRL }, + { TTYC_KCUB1, NULL, KEYC_LEFT, TTYKEY_CTRL }, + { TTYC_KCUF1, NULL, KEYC_RIGHT, TTYKEY_CTRL }, /* - * Numeric keypad. termcap and terminfo are totally confusing for this. - * There are definitions for some keypad keys and for function keys, - * but these seem to now be used for the real function keys rather than - * for the keypad keys in application mode (which is different from - * what it says in the termcap file). So, we just hardcode the vt100 - * escape sequences here and always put the terminal into keypad_xmit - * mode. Translation of numbers mode/applications mode is done in - * input-keys.c. + * Numeric keypad. Just use the vt100 escape sequences here and always + * put the terminal into keypad_xmit mode. Translation of numbers + * mode/applications mode is done in input-keys.c. */ - { 0, "\033Oo", KEYC_KP_SLASH, TTYKEY_RAW }, - { 0, "\033Oj", KEYC_KP_STAR, TTYKEY_RAW }, - { 0, "\033Om", KEYC_KP_MINUS, TTYKEY_RAW }, - { 0, "\033Ow", KEYC_KP_SEVEN, TTYKEY_RAW }, - { 0, "\033Ox", KEYC_KP_EIGHT, TTYKEY_RAW }, - { 0, "\033Oy", KEYC_KP_NINE, TTYKEY_RAW }, - { 0, "\033Ok", KEYC_KP_PLUS, TTYKEY_RAW }, - { 0, "\033Ot", KEYC_KP_FOUR, TTYKEY_RAW }, - { 0, "\033Ou", KEYC_KP_FIVE, TTYKEY_RAW }, - { 0, "\033Ov", KEYC_KP_SIX, TTYKEY_RAW }, - { 0, "\033Oq", KEYC_KP_ONE, TTYKEY_RAW }, - { 0, "\033Or", KEYC_KP_TWO, TTYKEY_RAW }, - { 0, "\033Os", KEYC_KP_THREE, TTYKEY_RAW }, - { 0, "\033OM", KEYC_KP_ENTER, TTYKEY_RAW }, - { 0, "\033Op", KEYC_KP_ZERO, TTYKEY_RAW }, - { 0, "\033On", KEYC_KP_PERIOD, TTYKEY_RAW }, + { 0, "\033Oo", KEYC_KP_SLASH, TTYKEY_RAW }, + { 0, "\033Oj", KEYC_KP_STAR, TTYKEY_RAW }, + { 0, "\033Om", KEYC_KP_MINUS, TTYKEY_RAW }, + { 0, "\033Ow", KEYC_KP_SEVEN, TTYKEY_RAW }, + { 0, "\033Ox", KEYC_KP_EIGHT, TTYKEY_RAW }, + { 0, "\033Oy", KEYC_KP_NINE, TTYKEY_RAW }, + { 0, "\033Ok", KEYC_KP_PLUS, TTYKEY_RAW }, + { 0, "\033Ot", KEYC_KP_FOUR, TTYKEY_RAW }, + { 0, "\033Ou", KEYC_KP_FIVE, TTYKEY_RAW }, + { 0, "\033Ov", KEYC_KP_SIX, TTYKEY_RAW }, + { 0, "\033Oq", KEYC_KP_ONE, TTYKEY_RAW }, + { 0, "\033Or", KEYC_KP_TWO, TTYKEY_RAW }, + { 0, "\033Os", KEYC_KP_THREE, TTYKEY_RAW }, + { 0, "\033OM", KEYC_KP_ENTER, TTYKEY_RAW }, + { 0, "\033Op", KEYC_KP_ZERO, TTYKEY_RAW }, + { 0, "\033On", KEYC_KP_PERIOD, TTYKEY_RAW }, }; RB_GENERATE(tty_keys, tty_key, entry, tty_keys_cmp); From d0aa883e07c19040d23c2cd559850659323cdc90 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 26 Oct 2009 13:58:02 +0000 Subject: [PATCH 0455/1180] As we always put the cursor keys into application mode, assume keys sent with CSI have ctrl. Also add a couple of comments. --- tty-keys.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/tty-keys.c b/tty-keys.c index 5a7df479..c56f47a0 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -25,6 +25,10 @@ #include "tmux.h" +/* + * Handle keys input from the outside terminal. + */ + void tty_keys_add(struct tty *, const char *, int, int); int tty_keys_mouse(char *, size_t, size_t *, struct mouse_event *); @@ -67,21 +71,26 @@ struct tty_key_ent tty_keys[] = { { TTYC_KPP, NULL, KEYC_PPAGE, TTYKEY_CTRL }, { TTYC_KCBT, NULL, KEYC_BTAB, TTYKEY_CTRL }, - /* Arrow keys. */ + /* + * Arrow keys. There are several variants of these so just accept them. + * We always put the terminal into application keys mode so ctrl should + * swap between SS3 and CSI. + */ { 0, "\033OA", KEYC_UP, TTYKEY_RAW }, { 0, "\033OB", KEYC_DOWN, TTYKEY_RAW }, { 0, "\033OC", KEYC_RIGHT, TTYKEY_RAW }, { 0, "\033OD", KEYC_LEFT, TTYKEY_RAW }, - { 0, "\033[A", KEYC_UP, TTYKEY_RAW }, - { 0, "\033[B", KEYC_DOWN, TTYKEY_RAW }, - { 0, "\033[C", KEYC_RIGHT, TTYKEY_RAW }, - { 0, "\033[D", KEYC_LEFT, TTYKEY_RAW }, + { 0, "\033[A", KEYC_UP|KEYC_CTRL, TTYKEY_RAW }, + { 0, "\033[B", KEYC_DOWN|KEYC_CTRL, TTYKEY_RAW }, + { 0, "\033[C", KEYC_RIGHT|KEYC_CTRL, TTYKEY_RAW }, + { 0, "\033[D", KEYC_LEFT|KEYC_CTRL, TTYKEY_RAW }, { 0, "\033Oa", KEYC_UP|KEYC_CTRL, TTYKEY_RAW }, { 0, "\033Ob", KEYC_DOWN|KEYC_CTRL, TTYKEY_RAW }, { 0, "\033Oc", KEYC_RIGHT|KEYC_CTRL, TTYKEY_RAW }, { 0, "\033Od", KEYC_LEFT|KEYC_CTRL, TTYKEY_RAW }, + { 0, "\033[a", KEYC_UP|KEYC_SHIFT, TTYKEY_RAW }, { 0, "\033[b", KEYC_DOWN|KEYC_SHIFT, TTYKEY_RAW }, { 0, "\033[c", KEYC_RIGHT|KEYC_SHIFT, TTYKEY_RAW }, From 5cce40d4c38d6cbe0385b0ba682c0fd8259a7ab6 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 26 Oct 2009 14:27:13 +0000 Subject: [PATCH 0456/1180] Set the output code for ctrl+cursor keys correctly, and disable (comment) rxvt-style output. --- input-keys.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/input-keys.c b/input-keys.c index a5012b2f..9c2f7ca9 100644 --- a/input-keys.c +++ b/input-keys.c @@ -96,6 +96,7 @@ struct input_key_ent input_keys[] = { { KEYC_BTAB, "\033[Z", 0 }, /* Arrow keys. Cursor versions must come first. */ +/* { KEYC_UP|KEYC_CTRL, "\033Oa", 0 }, { KEYC_DOWN|KEYC_CTRL, "\033Ob", 0 }, { KEYC_RIGHT|KEYC_CTRL, "\033Oc", 0 }, @@ -105,11 +106,12 @@ struct input_key_ent input_keys[] = { { KEYC_DOWN|KEYC_SHIFT, "\033[b", 0 }, { KEYC_RIGHT|KEYC_SHIFT,"\033[c", 0 }, { KEYC_LEFT|KEYC_SHIFT, "\033[d", 0 }, +*/ - { KEYC_UP|KEYC_CTRL, "\033OA", INPUTKEY_CURSOR }, - { KEYC_DOWN|KEYC_CTRL, "\033OB", INPUTKEY_CURSOR }, - { KEYC_RIGHT|KEYC_CTRL, "\033OC", INPUTKEY_CURSOR }, - { KEYC_LEFT|KEYC_CTRL, "\033OD", INPUTKEY_CURSOR }, + { KEYC_UP|KEYC_CTRL, "\033[A", INPUTKEY_CURSOR }, + { KEYC_DOWN|KEYC_CTRL, "\033[B", INPUTKEY_CURSOR }, + { KEYC_RIGHT|KEYC_CTRL, "\033[C", INPUTKEY_CURSOR }, + { KEYC_LEFT|KEYC_CTRL, "\033[D", INPUTKEY_CURSOR }, { KEYC_UP, "\033OA", INPUTKEY_CURSOR }, { KEYC_DOWN, "\033OB", INPUTKEY_CURSOR }, @@ -169,6 +171,7 @@ input_key(struct window_pane *wp, int key) struct input_key_ent *ike; u_int i; size_t dlen; + char *out; log_debug2("writing key 0x%x", key); From bbca6fe5b01388e6256d3a31b80a45ce2b2a0ff2 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 26 Oct 2009 14:30:57 +0000 Subject: [PATCH 0457/1180] On second thoughts, drop the rxvt output entirely. --- input-keys.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/input-keys.c b/input-keys.c index 9c2f7ca9..0d9e3222 100644 --- a/input-keys.c +++ b/input-keys.c @@ -96,18 +96,6 @@ struct input_key_ent input_keys[] = { { KEYC_BTAB, "\033[Z", 0 }, /* Arrow keys. Cursor versions must come first. */ -/* - { KEYC_UP|KEYC_CTRL, "\033Oa", 0 }, - { KEYC_DOWN|KEYC_CTRL, "\033Ob", 0 }, - { KEYC_RIGHT|KEYC_CTRL, "\033Oc", 0 }, - { KEYC_LEFT|KEYC_CTRL, "\033Od", 0 }, - - { KEYC_UP|KEYC_SHIFT, "\033[a", 0 }, - { KEYC_DOWN|KEYC_SHIFT, "\033[b", 0 }, - { KEYC_RIGHT|KEYC_SHIFT,"\033[c", 0 }, - { KEYC_LEFT|KEYC_SHIFT, "\033[d", 0 }, -*/ - { KEYC_UP|KEYC_CTRL, "\033[A", INPUTKEY_CURSOR }, { KEYC_DOWN|KEYC_CTRL, "\033[B", INPUTKEY_CURSOR }, { KEYC_RIGHT|KEYC_CTRL, "\033[C", INPUTKEY_CURSOR }, From c92c2bfb10d9c94acf0d453d9b4e71d6d696e8af Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 26 Oct 2009 16:00:51 +0000 Subject: [PATCH 0458/1180] Support the (mostly new) function key+modifier caps (kIC-kIC7). Most of these will be caught (soon) by the xterm keys code in xterm itself but some other descriptions such as rxvt define them as well. --- tmux.h | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++ tty-keys.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ tty-term.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 183 insertions(+), 1 deletion(-) diff --git a/tmux.h b/tmux.h index 5932cc10..5bc509c5 100644 --- a/tmux.h +++ b/tmux.h @@ -226,8 +226,26 @@ enum tty_code_code { TTYC_KCUD1, /* key_down, kd */ TTYC_KCUF1, /* key_right, kr */ TTYC_KCUU1, /* key_up, ku */ + TTYC_KDC2, + TTYC_KDC3, + TTYC_KDC4, + TTYC_KDC5, + TTYC_KDC6, + TTYC_KDC7, TTYC_KDCH1, /* key_dc, kD */ + TTYC_KDN2, + TTYC_KDN3, + TTYC_KDN4, + TTYC_KDN5, + TTYC_KDN6, + TTYC_KDN7, TTYC_KEND, /* key_end, ke */ + TTYC_KEND2, + TTYC_KEND3, + TTYC_KEND4, + TTYC_KEND5, + TTYC_KEND6, + TTYC_KEND7, TTYC_KF1, /* key_f1, k1 */ TTYC_KF10, /* key_f10, k; */ TTYC_KF11, /* key_f11, F1 */ @@ -248,11 +266,53 @@ enum tty_code_code { TTYC_KF7, /* key_f7, k7 */ TTYC_KF8, /* key_f8, k8 */ TTYC_KF9, /* key_f9, k9 */ + TTYC_KHOM2, + TTYC_KHOM3, + TTYC_KHOM4, + TTYC_KHOM5, + TTYC_KHOM6, + TTYC_KHOM7, TTYC_KHOME, /* key_home, kh */ + TTYC_KIC2, + TTYC_KIC3, + TTYC_KIC4, + TTYC_KIC5, + TTYC_KIC6, + TTYC_KIC7, TTYC_KICH1, /* key_ic, kI */ + TTYC_KLFT2, + TTYC_KLFT3, + TTYC_KLFT4, + TTYC_KLFT5, + TTYC_KLFT6, + TTYC_KLFT7, TTYC_KMOUS, /* key_mouse, Km */ TTYC_KNP, /* key_npage, kN */ + TTYC_KNXT2, + TTYC_KNXT3, + TTYC_KNXT4, + TTYC_KNXT5, + TTYC_KNXT6, + TTYC_KNXT7, TTYC_KPP, /* key_ppage, kP */ + TTYC_KPRV2, + TTYC_KPRV3, + TTYC_KPRV4, + TTYC_KPRV5, + TTYC_KPRV6, + TTYC_KPRV7, + TTYC_KRIT2, + TTYC_KRIT3, + TTYC_KRIT4, + TTYC_KRIT5, + TTYC_KRIT6, + TTYC_KRIT7, + TTYC_KUP2, + TTYC_KUP3, + TTYC_KUP4, + TTYC_KUP5, + TTYC_KUP6, + TTYC_KUP7, TTYC_OP, /* orig_pair, op */ TTYC_REV, /* enter_reverse_mode, mr */ TTYC_RI, /* scroll_reverse, sr */ diff --git a/tty-keys.c b/tty-keys.c index c56f47a0..26bb2861 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -122,6 +122,68 @@ struct tty_key_ent tty_keys[] = { { 0, "\033OM", KEYC_KP_ENTER, TTYKEY_RAW }, { 0, "\033Op", KEYC_KP_ZERO, TTYKEY_RAW }, { 0, "\033On", KEYC_KP_PERIOD, TTYKEY_RAW }, + + /* Key and modifier capabilities. */ + { TTYC_KDC2, NULL, KEYC_DC|KEYC_SHIFT, 0 }, + { TTYC_KDC3, NULL, KEYC_DC|KEYC_ESCAPE, 0 }, + { TTYC_KDC4, NULL, KEYC_DC|KEYC_SHIFT|KEYC_ESCAPE, 0 }, + { TTYC_KDC5, NULL, KEYC_DC|KEYC_CTRL, 0 }, + { TTYC_KDC6, NULL, KEYC_DC|KEYC_SHIFT|KEYC_CTRL, 0 }, + { TTYC_KDC7, NULL, KEYC_DC|KEYC_ESCAPE|KEYC_CTRL, 0 }, + { TTYC_KDN2, NULL, KEYC_DOWN|KEYC_SHIFT, 0 }, + { TTYC_KDN3, NULL, KEYC_DOWN|KEYC_ESCAPE, 0 }, + { TTYC_KDN4, NULL, KEYC_DOWN|KEYC_SHIFT|KEYC_ESCAPE, 0 }, + { TTYC_KDN5, NULL, KEYC_DOWN|KEYC_CTRL, 0 }, + { TTYC_KDN6, NULL, KEYC_DOWN|KEYC_SHIFT|KEYC_CTRL, 0 }, + { TTYC_KDN7, NULL, KEYC_DOWN|KEYC_ESCAPE|KEYC_CTRL, 0 }, + { TTYC_KEND2, NULL, KEYC_END|KEYC_SHIFT, 0 }, + { TTYC_KEND3, NULL, KEYC_END|KEYC_ESCAPE, 0 }, + { TTYC_KEND4, NULL, KEYC_END|KEYC_SHIFT|KEYC_ESCAPE, 0 }, + { TTYC_KEND5, NULL, KEYC_END|KEYC_CTRL, 0 }, + { TTYC_KEND6, NULL, KEYC_END|KEYC_SHIFT|KEYC_CTRL, 0 }, + { TTYC_KEND7, NULL, KEYC_END|KEYC_ESCAPE|KEYC_CTRL, 0 }, + { TTYC_KHOM2, NULL, KEYC_HOME|KEYC_SHIFT, 0 }, + { TTYC_KHOM3, NULL, KEYC_HOME|KEYC_ESCAPE, 0 }, + { TTYC_KHOM4, NULL, KEYC_HOME|KEYC_SHIFT|KEYC_ESCAPE, 0 }, + { TTYC_KHOM5, NULL, KEYC_HOME|KEYC_CTRL, 0 }, + { TTYC_KHOM6, NULL, KEYC_HOME|KEYC_SHIFT|KEYC_CTRL, 0 }, + { TTYC_KHOM7, NULL, KEYC_HOME|KEYC_ESCAPE|KEYC_CTRL, 0 }, + { TTYC_KIC2, NULL, KEYC_IC|KEYC_SHIFT, 0 }, + { TTYC_KIC3, NULL, KEYC_IC|KEYC_ESCAPE, 0 }, + { TTYC_KIC4, NULL, KEYC_IC|KEYC_SHIFT|KEYC_ESCAPE, 0 }, + { TTYC_KIC5, NULL, KEYC_IC|KEYC_CTRL, 0 }, + { TTYC_KIC6, NULL, KEYC_IC|KEYC_SHIFT|KEYC_CTRL, 0 }, + { TTYC_KIC7, NULL, KEYC_IC|KEYC_ESCAPE|KEYC_CTRL, 0 }, + { TTYC_KLFT2, NULL, KEYC_LEFT|KEYC_SHIFT, 0 }, + { TTYC_KLFT3, NULL, KEYC_LEFT|KEYC_ESCAPE, 0 }, + { TTYC_KLFT4, NULL, KEYC_LEFT|KEYC_SHIFT|KEYC_ESCAPE, 0 }, + { TTYC_KLFT5, NULL, KEYC_LEFT|KEYC_CTRL, 0 }, + { TTYC_KLFT6, NULL, KEYC_LEFT|KEYC_SHIFT|KEYC_CTRL, 0 }, + { TTYC_KLFT7, NULL, KEYC_LEFT|KEYC_ESCAPE|KEYC_CTRL, 0 }, + { TTYC_KNXT2, NULL, KEYC_NPAGE|KEYC_SHIFT, 0 }, + { TTYC_KNXT3, NULL, KEYC_NPAGE|KEYC_ESCAPE, 0 }, + { TTYC_KNXT4, NULL, KEYC_NPAGE|KEYC_SHIFT|KEYC_ESCAPE, 0 }, + { TTYC_KNXT5, NULL, KEYC_NPAGE|KEYC_CTRL, 0 }, + { TTYC_KNXT6, NULL, KEYC_NPAGE|KEYC_SHIFT|KEYC_CTRL, 0 }, + { TTYC_KNXT7, NULL, KEYC_NPAGE|KEYC_ESCAPE|KEYC_CTRL, 0 }, + { TTYC_KPRV2, NULL, KEYC_PPAGE|KEYC_SHIFT, 0 }, + { TTYC_KPRV3, NULL, KEYC_PPAGE|KEYC_ESCAPE, 0 }, + { TTYC_KPRV4, NULL, KEYC_PPAGE|KEYC_SHIFT|KEYC_ESCAPE, 0 }, + { TTYC_KPRV5, NULL, KEYC_PPAGE|KEYC_CTRL, 0 }, + { TTYC_KPRV6, NULL, KEYC_PPAGE|KEYC_SHIFT|KEYC_CTRL, 0 }, + { TTYC_KPRV7, NULL, KEYC_PPAGE|KEYC_ESCAPE|KEYC_CTRL, 0 }, + { TTYC_KRIT2, NULL, KEYC_RIGHT|KEYC_SHIFT, 0 }, + { TTYC_KRIT3, NULL, KEYC_RIGHT|KEYC_ESCAPE, 0 }, + { TTYC_KRIT4, NULL, KEYC_RIGHT|KEYC_SHIFT|KEYC_ESCAPE, 0 }, + { TTYC_KRIT5, NULL, KEYC_RIGHT|KEYC_CTRL, 0 }, + { TTYC_KRIT6, NULL, KEYC_RIGHT|KEYC_SHIFT|KEYC_CTRL, 0 }, + { TTYC_KRIT7, NULL, KEYC_RIGHT|KEYC_ESCAPE|KEYC_CTRL, 0 }, + { TTYC_KUP2, NULL, KEYC_UP|KEYC_SHIFT, 0 }, + { TTYC_KUP3, NULL, KEYC_UP|KEYC_ESCAPE, 0 }, + { TTYC_KUP4, NULL, KEYC_UP|KEYC_SHIFT|KEYC_ESCAPE, 0 }, + { TTYC_KUP5, NULL, KEYC_UP|KEYC_CTRL, 0 }, + { TTYC_KUP6, NULL, KEYC_UP|KEYC_SHIFT|KEYC_CTRL, 0 }, + { TTYC_KUP7, NULL, KEYC_UP|KEYC_ESCAPE|KEYC_CTRL, 0 }, }; RB_GENERATE(tty_keys, tty_key, entry, tty_keys_cmp); diff --git a/tty-term.c b/tty-term.c index 8a592b31..22fdcb60 100644 --- a/tty-term.c +++ b/tty-term.c @@ -33,8 +33,8 @@ char *tty_term_strip(const char *); struct tty_terms tty_terms = SLIST_HEAD_INITIALIZER(tty_terms); struct tty_term_code_entry tty_term_codes[NTTYCODE] = { - { TTYC_AX, TTYCODE_FLAG, "AX" }, { TTYC_ACSC, TTYCODE_STRING, "acsc" }, + { TTYC_AX, TTYCODE_FLAG, "AX" }, { TTYC_BEL, TTYCODE_STRING, "bel" }, { TTYC_BLINK, TTYCODE_STRING, "blink" }, { TTYC_BOLD, TTYCODE_STRING, "bold" }, @@ -75,8 +75,26 @@ struct tty_term_code_entry tty_term_codes[NTTYCODE] = { { TTYC_KCUD1, TTYCODE_STRING, "kcud1" }, { TTYC_KCUF1, TTYCODE_STRING, "kcuf1" }, { TTYC_KCUU1, TTYCODE_STRING, "kcuu1" }, + { TTYC_KDC2, TTYCODE_STRING, "kDC" }, + { TTYC_KDC3, TTYCODE_STRING, "kDC3" }, + { TTYC_KDC4, TTYCODE_STRING, "kDC4" }, + { TTYC_KDC5, TTYCODE_STRING, "kDC5" }, + { TTYC_KDC6, TTYCODE_STRING, "kDC6" }, + { TTYC_KDC7, TTYCODE_STRING, "kDC7" }, { TTYC_KDCH1, TTYCODE_STRING, "kdch1" }, + { TTYC_KDN2, TTYCODE_STRING, "kDN" }, + { TTYC_KDN3, TTYCODE_STRING, "kDN3" }, + { TTYC_KDN4, TTYCODE_STRING, "kDN4" }, + { TTYC_KDN5, TTYCODE_STRING, "kDN5" }, + { TTYC_KDN6, TTYCODE_STRING, "kDN6" }, + { TTYC_KDN7, TTYCODE_STRING, "kDN7" }, { TTYC_KEND, TTYCODE_STRING, "kend" }, + { TTYC_KEND2, TTYCODE_STRING, "kEND" }, + { TTYC_KEND3, TTYCODE_STRING, "kEND3" }, + { TTYC_KEND4, TTYCODE_STRING, "kEND4" }, + { TTYC_KEND5, TTYCODE_STRING, "kEND5" }, + { TTYC_KEND6, TTYCODE_STRING, "kEND6" }, + { TTYC_KEND7, TTYCODE_STRING, "kEND7" }, { TTYC_KF1, TTYCODE_STRING, "kf1" }, { TTYC_KF10, TTYCODE_STRING, "kf10" }, { TTYC_KF11, TTYCODE_STRING, "kf11" }, @@ -97,11 +115,53 @@ struct tty_term_code_entry tty_term_codes[NTTYCODE] = { { TTYC_KF7, TTYCODE_STRING, "kf7" }, { TTYC_KF8, TTYCODE_STRING, "kf8" }, { TTYC_KF9, TTYCODE_STRING, "kf9" }, + { TTYC_KHOM2, TTYCODE_STRING, "kHOM" }, + { TTYC_KHOM3, TTYCODE_STRING, "kHOM3" }, + { TTYC_KHOM4, TTYCODE_STRING, "kHOM4" }, + { TTYC_KHOM5, TTYCODE_STRING, "kHOM5" }, + { TTYC_KHOM6, TTYCODE_STRING, "kHOM6" }, + { TTYC_KHOM7, TTYCODE_STRING, "kHOM7" }, { TTYC_KHOME, TTYCODE_STRING, "khome" }, + { TTYC_KIC2, TTYCODE_STRING, "kIC" }, + { TTYC_KIC3, TTYCODE_STRING, "kIC3" }, + { TTYC_KIC4, TTYCODE_STRING, "kIC4" }, + { TTYC_KIC5, TTYCODE_STRING, "kIC5" }, + { TTYC_KIC6, TTYCODE_STRING, "kIC6" }, + { TTYC_KIC7, TTYCODE_STRING, "kIC7" }, { TTYC_KICH1, TTYCODE_STRING, "kich1" }, + { TTYC_KLFT2, TTYCODE_STRING, "kLFT" }, + { TTYC_KLFT3, TTYCODE_STRING, "kLFT3" }, + { TTYC_KLFT4, TTYCODE_STRING, "kLFT4" }, + { TTYC_KLFT5, TTYCODE_STRING, "kLFT5" }, + { TTYC_KLFT6, TTYCODE_STRING, "kLFT6" }, + { TTYC_KLFT7, TTYCODE_STRING, "kLFT7" }, { TTYC_KMOUS, TTYCODE_STRING, "kmous" }, { TTYC_KNP, TTYCODE_STRING, "knp" }, + { TTYC_KNXT2, TTYCODE_STRING, "kNXT" }, + { TTYC_KNXT3, TTYCODE_STRING, "kNXT3" }, + { TTYC_KNXT4, TTYCODE_STRING, "kNXT4" }, + { TTYC_KNXT5, TTYCODE_STRING, "kNXT5" }, + { TTYC_KNXT6, TTYCODE_STRING, "kNXT6" }, + { TTYC_KNXT7, TTYCODE_STRING, "kNXT7" }, { TTYC_KPP, TTYCODE_STRING, "kpp" }, + { TTYC_KPRV2, TTYCODE_STRING, "kPRV" }, + { TTYC_KPRV3, TTYCODE_STRING, "kPRV3" }, + { TTYC_KPRV4, TTYCODE_STRING, "kPRV4" }, + { TTYC_KPRV5, TTYCODE_STRING, "kPRV5" }, + { TTYC_KPRV6, TTYCODE_STRING, "kPRV6" }, + { TTYC_KPRV7, TTYCODE_STRING, "kPRV7" }, + { TTYC_KRIT2, TTYCODE_STRING, "kRIT" }, + { TTYC_KRIT3, TTYCODE_STRING, "kRIT3" }, + { TTYC_KRIT4, TTYCODE_STRING, "kRIT4" }, + { TTYC_KRIT5, TTYCODE_STRING, "kRIT5" }, + { TTYC_KRIT6, TTYCODE_STRING, "kRIT6" }, + { TTYC_KRIT7, TTYCODE_STRING, "kRIT7" }, + { TTYC_KUP2, TTYCODE_STRING, "kUP" }, + { TTYC_KUP3, TTYCODE_STRING, "kUP3" }, + { TTYC_KUP4, TTYCODE_STRING, "kUP4" }, + { TTYC_KUP5, TTYCODE_STRING, "kUP5" }, + { TTYC_KUP6, TTYCODE_STRING, "kUP6" }, + { TTYC_KUP7, TTYCODE_STRING, "kUP7" }, { TTYC_OP, TTYCODE_STRING, "op" }, { TTYC_REV, TTYCODE_STRING, "rev" }, { TTYC_RI, TTYCODE_STRING, "ri" }, From fd2ef18a7004fb35dbe40b99765609189827a6f8 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 26 Oct 2009 17:46:33 +0000 Subject: [PATCH 0459/1180] Rewrite xterm-keys code (both input and output) so that works (doesn't always output the same modifiers, accepts all the possible input keys) and is more understandable. --- Makefile | 2 +- input-keys.c | 12 +++ tmux.h | 4 + tty-keys.c | 7 ++ xterm-keys.c | 202 +++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 226 insertions(+), 1 deletion(-) create mode 100644 xterm-keys.c diff --git a/Makefile b/Makefile index e6b8b1dd..68a34050 100644 --- a/Makefile +++ b/Makefile @@ -38,7 +38,7 @@ SRCS= attributes.c buffer-poll.c buffer.c cfg.c \ server-fn.c server.c server-client.c server-window.c server-job.c \ tmux.c tty-keys.c tty-term.c tty.c utf8.c \ window-choose.c window-clock.c window-copy.c window-more.c window.c \ - xmalloc.c + xterm-keys.c xmalloc.c CDIAGFLAGS+= -Wno-long-long -Wall -W -Wnested-externs -Wformat=2 CDIAGFLAGS+= -Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations diff --git a/input-keys.c b/input-keys.c index 0d9e3222..c276c498 100644 --- a/input-keys.c +++ b/input-keys.c @@ -174,6 +174,18 @@ input_key(struct window_pane *wp, int key) return; } + /* + * Then try to look this up as an xterm key, if the flag to output them + * is set. + */ + if (options_get_number(&wp->window->options, "xterm-keys")) { + if ((out = xterm_keys_lookup(key)) != NULL) { + buffer_write(wp->out, out, strlen(out)); + xfree(out); + return; + } + } + /* Otherwise look the key up in the table. */ for (i = 0; i < nitems(input_keys); i++) { ike = &input_keys[i]; diff --git a/tmux.h b/tmux.h index 5bc509c5..bc62c813 100644 --- a/tmux.h +++ b/tmux.h @@ -1642,6 +1642,10 @@ void input_parse(struct window_pane *); void input_key(struct window_pane *, int); void input_mouse(struct window_pane *, struct mouse_event *); +/* xterm-keys.c */ +char *xterm_keys_lookup(int); +int xterm_keys_find(const char *, size_t, size_t *); + /* colour.c */ void colour_set_fg(struct grid_cell *, int); void colour_set_bg(struct grid_cell *, int); diff --git a/tty-keys.c b/tty-keys.c index 26bb2861..d977708d 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -341,6 +341,13 @@ tty_keys_next(struct tty *tty, int *key, struct mouse_event *mouse) goto found; } + /* Not found. Try to parse a key with an xterm-style modifier. */ + *key = xterm_keys_find(buf, len, &size); + if (*key != KEYC_NONE) { + buffer_remove(tty->in, size); + goto found; + } + /* Escape but no key string. If the timer isn't started, start it. */ if (!(tty->flags & TTY_ESCAPE)) { tv.tv_sec = 0; diff --git a/xterm-keys.c b/xterm-keys.c new file mode 100644 index 00000000..8dadd530 --- /dev/null +++ b/xterm-keys.c @@ -0,0 +1,202 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2009 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 "tmux.h" + +/* + * xterm-style function keys append one of the following values before the last + * character: + * + * 2 Shift + * 3 Alt + * 4 Shift + Alt + * 5 Ctrl + * 6 Shift + Ctrl + * 7 Alt + Ctrl + * 8 Shift + Alt + Ctrl + * + * Rather than parsing them, just match against a table. + * + * There are two forms for F1-F4 (\\033O_P or \\033[1;_P). We accept either but + * always output the latter (it comes first in the table). + */ + +int xterm_keys_match(const char *, const char *, size_t); +int xterm_keys_modifiers(const char *, const char *, size_t); + +struct xterm_keys_entry { + int key; + const char *template; +}; + +struct xterm_keys_entry xterm_keys_table[] = { + { KEYC_F1, "\033[1;_P" }, + { KEYC_F1, "\033[O_P" }, + { KEYC_F2, "\033[1;_Q" }, + { KEYC_F2, "\033[O_Q" }, + { KEYC_F3, "\033[1;_R" }, + { KEYC_F3, "\033[O_R" }, + { KEYC_F4, "\033[1;_S" }, + { KEYC_F4, "\033[O_S" }, + { KEYC_F5, "\033[15;_~" }, + { KEYC_F6, "\033[17;_~" }, + { KEYC_F7, "\033[18;_~" }, + { KEYC_F8, "\033[19;_~" }, + { KEYC_F9, "\033[20;_~" }, + { KEYC_F10, "\033[21;_~" }, + { KEYC_F11, "\033[23;_~" }, + { KEYC_F12, "\033[24;_~" }, + { KEYC_F13, "\033[25;_~" }, + { KEYC_F14, "\033[26;_~" }, + { KEYC_F15, "\033[28;_~" }, + { KEYC_F16, "\033[29;_~" }, + { KEYC_F17, "\033[31;_~" }, + { KEYC_F18, "\033[32;_~" }, + { KEYC_F19, "\033[33;_~" }, + { KEYC_F20, "\033[34;_~" }, + { KEYC_UP, "\033[1;_A" }, + { KEYC_DOWN, "\033[1;_B" }, + { KEYC_RIGHT, "\033[1;_C" }, + { KEYC_LEFT, "\033[1;_D" }, + { KEYC_HOME, "\033[1;_H" }, + { KEYC_END, "\033[1;_F" }, + { KEYC_PPAGE, "\033[5;_~" }, + { KEYC_NPAGE, "\033[6;_~" }, + { KEYC_IC, "\033[2;_~" }, + { KEYC_DC, "\033[3;_~" }, +}; + +/* Match key against buffer, treating _ as a wildcard. */ +int +xterm_keys_match(const char *template, const char *buf, size_t len) +{ + size_t pos; + + if (len == 0 || len < strlen(template)) + return (0); + + pos = 0; + do { + if (*template != '_' && buf[pos] != *template) + return (0); + } while (pos++ != len && *++template != '\0'); + + return (1); +} + +/* Find modifiers based on template. */ +int +xterm_keys_modifiers(const char *template, const char *buf, size_t len) +{ + size_t idx; + + idx = strcspn(template, "_"); + if (idx >= len) + return (0); + switch (buf[idx]) { + case '2': + return (KEYC_SHIFT); + case '3': + return (KEYC_ESCAPE); + case '4': + return (KEYC_SHIFT|KEYC_ESCAPE); + case '5': + return (KEYC_CTRL); + case '6': + return (KEYC_SHIFT|KEYC_CTRL); + case '7': + return (KEYC_ESCAPE|KEYC_CTRL); + case '8': + return (KEYC_SHIFT|KEYC_ESCAPE|KEYC_CTRL); + } + return (0); +} + +/* Lookup key from buffer against table. */ +int +xterm_keys_find(const char *buf, size_t len, size_t *size) +{ + struct xterm_keys_entry *entry; + u_int i; + + for (i = 0; i < nitems(xterm_keys_table); i++) { + entry = &xterm_keys_table[i]; + if (xterm_keys_match(entry->template, buf, len)) + break; + } + if (i == nitems(xterm_keys_table)) + return (KEYC_NONE); + *size = strlen(entry->template); + log_debug("XXX %x %x", entry->key, xterm_keys_modifiers(entry->template, buf, len)); + return (entry->key | xterm_keys_modifiers(entry->template, buf, len)); +} + +/* Lookup a key number from the table. */ +char * +xterm_keys_lookup(int key) +{ + struct xterm_keys_entry *entry; + u_int i; + int modifiers; + char *out; + +#define KEY_MODIFIERS(key, modifiers) \ + (((key) & (KEYC_SHIFT|KEYC_ESCAPE|KEYC_CTRL)) == (modifiers)) + modifiers = 0; + if (KEY_MODIFIERS(key, KEYC_SHIFT)) + modifiers = 2; + else if (KEY_MODIFIERS(key, KEYC_ESCAPE)) + modifiers = 3; + else if (KEY_MODIFIERS(key, KEYC_SHIFT|KEYC_ESCAPE)) + modifiers = 4; + else if (KEY_MODIFIERS(key, KEYC_CTRL)) + modifiers = 5; + else if (KEY_MODIFIERS(key, KEYC_SHIFT|KEYC_CTRL)) + modifiers = 6; + else if (KEY_MODIFIERS(key, KEYC_ESCAPE|KEYC_CTRL)) + modifiers = 7; + else if (KEY_MODIFIERS(key, KEYC_SHIFT|KEYC_ESCAPE|KEYC_CTRL)) + modifiers = 8; +#undef KEY_MODIFIERS + + /* + * If the key has no modifiers, return NULL and let it fall through to + * the normal lookup. + */ + if (modifiers == 0) + return (NULL); + + /* Otherwise, find the key in the table. */ + key &= ~(KEYC_SHIFT|KEYC_ESCAPE|KEYC_CTRL); + for (i = 0; i < nitems(xterm_keys_table); i++) { + entry = &xterm_keys_table[i]; + if (key == entry->key) + break; + } + if (i == nitems(xterm_keys_table)) + return (NULL); + + /* Copy the template and replace the modifier. */ + out = xstrdup(entry->template); + out[strcspn(out, "_")] = '0' + modifiers; + return (out); +} From e831649b64014960777e27375a44000bbabf2ee8 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 26 Oct 2009 17:59:46 +0000 Subject: [PATCH 0460/1180] Not all terminals swap CSI and SS3 on ctrl, so remove that. Also mark the rxvt special-cases as such until terminfo is updated to have kLFT5, kRIT5 etc. --- input-keys.c | 5 ++++- tty-keys.c | 25 +++++++++++-------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/input-keys.c b/input-keys.c index c276c498..627b22cf 100644 --- a/input-keys.c +++ b/input-keys.c @@ -95,7 +95,10 @@ struct input_key_ent input_keys[] = { { KEYC_PPAGE|KEYC_CTRL, "\033[5^", 0 }, { KEYC_BTAB, "\033[Z", 0 }, - /* Arrow keys. Cursor versions must come first. */ + /* + * Arrow keys. Cursor versions must come first. The codes are toggled + * between CSI and SS3 versions when ctrl is pressed. + */ { KEYC_UP|KEYC_CTRL, "\033[A", INPUTKEY_CURSOR }, { KEYC_DOWN|KEYC_CTRL, "\033[B", INPUTKEY_CURSOR }, { KEYC_RIGHT|KEYC_CTRL, "\033[C", INPUTKEY_CURSOR }, diff --git a/tty-keys.c b/tty-keys.c index d977708d..2b7bae67 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -71,21 +71,23 @@ struct tty_key_ent tty_keys[] = { { TTYC_KPP, NULL, KEYC_PPAGE, TTYKEY_CTRL }, { TTYC_KCBT, NULL, KEYC_BTAB, TTYKEY_CTRL }, - /* - * Arrow keys. There are several variants of these so just accept them. - * We always put the terminal into application keys mode so ctrl should - * swap between SS3 and CSI. - */ + /* Arrow keys. */ { 0, "\033OA", KEYC_UP, TTYKEY_RAW }, { 0, "\033OB", KEYC_DOWN, TTYKEY_RAW }, { 0, "\033OC", KEYC_RIGHT, TTYKEY_RAW }, { 0, "\033OD", KEYC_LEFT, TTYKEY_RAW }, - { 0, "\033[A", KEYC_UP|KEYC_CTRL, TTYKEY_RAW }, - { 0, "\033[B", KEYC_DOWN|KEYC_CTRL, TTYKEY_RAW }, - { 0, "\033[C", KEYC_RIGHT|KEYC_CTRL, TTYKEY_RAW }, - { 0, "\033[D", KEYC_LEFT|KEYC_CTRL, TTYKEY_RAW }, + { 0, "\033[A", KEYC_UP, TTYKEY_RAW }, + { 0, "\033[B", KEYC_DOWN, TTYKEY_RAW }, + { 0, "\033[C", KEYC_RIGHT, TTYKEY_RAW }, + { 0, "\033[D", KEYC_LEFT, TTYKEY_RAW }, + { TTYC_KCUU1, NULL, KEYC_UP, TTYKEY_CTRL }, + { TTYC_KCUD1, NULL, KEYC_DOWN, TTYKEY_CTRL }, + { TTYC_KCUB1, NULL, KEYC_LEFT, TTYKEY_CTRL }, + { TTYC_KCUF1, NULL, KEYC_RIGHT, TTYKEY_CTRL }, + + /* Special-case arrow keys for rxvt until terminfo has kRIT5 etc. */ { 0, "\033Oa", KEYC_UP|KEYC_CTRL, TTYKEY_RAW }, { 0, "\033Ob", KEYC_DOWN|KEYC_CTRL, TTYKEY_RAW }, { 0, "\033Oc", KEYC_RIGHT|KEYC_CTRL, TTYKEY_RAW }, @@ -96,11 +98,6 @@ struct tty_key_ent tty_keys[] = { { 0, "\033[c", KEYC_RIGHT|KEYC_SHIFT, TTYKEY_RAW }, { 0, "\033[d", KEYC_LEFT|KEYC_SHIFT, TTYKEY_RAW }, - { TTYC_KCUU1, NULL, KEYC_UP, TTYKEY_CTRL }, - { TTYC_KCUD1, NULL, KEYC_DOWN, TTYKEY_CTRL }, - { TTYC_KCUB1, NULL, KEYC_LEFT, TTYKEY_CTRL }, - { TTYC_KCUF1, NULL, KEYC_RIGHT, TTYKEY_CTRL }, - /* * Numeric keypad. Just use the vt100 escape sequences here and always * put the terminal into keypad_xmit mode. Translation of numbers From 53957dcbaab49362748aa8b25b20e34274b6a3e9 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 26 Oct 2009 18:16:32 +0000 Subject: [PATCH 0461/1180] Nuke accidentally-committed debugging statement. --- xterm-keys.c | 1 - 1 file changed, 1 deletion(-) diff --git a/xterm-keys.c b/xterm-keys.c index 8dadd530..9a9b3242 100644 --- a/xterm-keys.c +++ b/xterm-keys.c @@ -146,7 +146,6 @@ xterm_keys_find(const char *buf, size_t len, size_t *size) if (i == nitems(xterm_keys_table)) return (KEYC_NONE); *size = strlen(entry->template); - log_debug("XXX %x %x", entry->key, xterm_keys_modifiers(entry->template, buf, len)); return (entry->key | xterm_keys_modifiers(entry->template, buf, len)); } From 353f2a2ad43256b6b1d8c17e3942316d0a8424e2 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 26 Oct 2009 20:47:00 +0000 Subject: [PATCH 0462/1180] Don't do anything in the client callback if the client has already died to avoid a use-after-free (the callback is used twice, once for the client itself and once for the tty). Fixes crashes seen by Han Boetes. --- server-client.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/server-client.c b/server-client.c index 6d00dd37..5038a036 100644 --- a/server-client.c +++ b/server-client.c @@ -153,6 +153,9 @@ server_client_callback(int fd, int events, void *data) { struct client *c = data; + if (c->flags & CLIENT_DEAD) + return; + if (fd == c->ibuf.fd) { if (events & (POLLERR|POLLNVAL|POLLHUP)) goto client_lost; From 6dc6333323cce1ccc9aaec7ef9e7e200919204e1 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 26 Oct 2009 21:10:24 +0000 Subject: [PATCH 0463/1180] Use strlcpy instead of strncpy, pointed out by deraadt. --- xmalloc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/xmalloc.c b/xmalloc.c index 6bf63bef..5eb5c4a8 100644 --- a/xmalloc.c +++ b/xmalloc.c @@ -29,13 +29,14 @@ char * xstrdup(const char *s) { - void *ptr; + char *ptr; size_t len; len = strlen(s) + 1; ptr = xmalloc(len); - return (strncpy(ptr, s, len)); + strlcpy(ptr, s, len); + return (ptr); } void * From 539c73bdb1865ad57600e3759f2475adef79ab41 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 26 Oct 2009 21:13:06 +0000 Subject: [PATCH 0464/1180] Reset the umask right after fopen to avoid leaving it changed on error, noticed by deraadt@. --- cmd-save-buffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd-save-buffer.c b/cmd-save-buffer.c index 5a779dc1..33859fd6 100644 --- a/cmd-save-buffer.c +++ b/cmd-save-buffer.c @@ -70,6 +70,7 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) f = fopen(data->arg, "ab"); else f = fopen(data->arg, "wb"); + umask(mask); if (f == NULL) { ctx->error(ctx, "%s: %s", data->arg, strerror(errno)); return (-1); @@ -82,7 +83,6 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) } fclose(f); - umask(mask); return (0); } From 6b804f3a4aaffc26d419b3ad7f96bd54456cdfc5 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 26 Oct 2009 21:25:57 +0000 Subject: [PATCH 0465/1180] Call fstat() after fopen() rather than stat() before. --- cmd-load-buffer.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cmd-load-buffer.c b/cmd-load-buffer.c index 1f8e75cd..a3f09ca4 100644 --- a/cmd-load-buffer.c +++ b/cmd-load-buffer.c @@ -56,13 +56,14 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) if ((s = cmd_find_session(ctx, data->target)) == NULL) return (-1); - if (stat(data->arg, &sb) < 0) { + if ((f = fopen(data->arg, "rb")) == NULL) { ctx->error(ctx, "%s: %s", data->arg, strerror(errno)); return (-1); } - if ((f = fopen(data->arg, "rb")) == NULL) { + if (fstat(fileno(f), &sb) < 0) { ctx->error(ctx, "%s: %s", data->arg, strerror(errno)); + fclose(f); return (-1); } From a8b1379ccbfbe7f1d7732147c4969bb92499555d Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 26 Oct 2009 21:38:18 +0000 Subject: [PATCH 0466/1180] Clear signal flags /before/ taking action and continue afterwards to reduce chance of dropping signals. Pointed out by deraadt@. --- client.c | 9 ++++++--- server.c | 6 ++++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/client.c b/client.c index 7959559b..a5c5e39e 100644 --- a/client.c +++ b/client.c @@ -185,17 +185,20 @@ client_main(void) client_write_server(MSG_EXITING, NULL, 0); } if (sigchld) { - waitpid(WAIT_ANY, NULL, WNOHANG); sigchld = 0; + waitpid(WAIT_ANY, NULL, WNOHANG); + continue; } if (sigwinch) { + sigwinch = 0; client_write_server(MSG_RESIZE, NULL, 0); - sigwinch = 0; + continue; } if (sigcont) { + sigcont = 0; siginit(); client_write_server(MSG_WAKEUP, NULL, 0); - sigcont = 0; + continue; } pfd.fd = client_ibuf.fd; diff --git a/server.c b/server.c index e1ec4eb8..78c5af94 100644 --- a/server.c +++ b/server.c @@ -328,15 +328,17 @@ server_main(int srv_fd) /* Handle child exit. */ if (sigchld) { - server_child_signal(); sigchld = 0; + server_child_signal(); + continue; } /* Recreate socket on SIGUSR1. */ if (sigusr1) { + sigusr1 = 0; close(srv_fd); srv_fd = server_create_socket(); - sigusr1 = 0; + continue; } /* Initialise pollfd array and add server socket. */ From ed62d1263ca180e8b088111bf77b8c7b4b2073de Mon Sep 17 00:00:00 2001 From: Theo Deraadt Date: Mon, 26 Oct 2009 21:42:04 +0000 Subject: [PATCH 0467/1180] tabs are better; ok nicm --- array.h | 2 +- cfg.c | 4 +-- cmd-server-info.c | 4 +-- cmd-string.c | 40 +++++++++++++++--------------- cmd.c | 4 +-- input.c | 6 ++--- server-client.c | 4 +-- server.c | 8 +++--- tmux.c | 10 ++++---- tty.c | 2 +- xmalloc.c | 62 +++++++++++++++++++++++------------------------ 11 files changed, 73 insertions(+), 73 deletions(-) diff --git a/array.h b/array.h index 46855d77..c5ed3d02 100644 --- a/array.h +++ b/array.h @@ -85,7 +85,7 @@ ARRAY_ITEMSIZE(a) * ((a)->num - (i) - 1)); \ } \ (a)->num--; \ - if ((a)->num == 0) \ + if ((a)->num == 0) \ ARRAY_FREE(a); \ } while (0) diff --git a/cfg.c b/cfg.c index d50eaae7..5f314b7b 100644 --- a/cfg.c +++ b/cfg.c @@ -53,9 +53,9 @@ cfg_error(unused struct cmd_ctx *ctx, const char *fmt, ...) int load_cfg(const char *path, struct cmd_ctx *ctxin, char **cause) { - FILE *f; + FILE *f; u_int n; - char *buf, *line, *ptr; + char *buf, *line, *ptr; size_t len; struct cmd_list *cmdlist; struct cmd_ctx ctx; diff --git a/cmd-server-info.c b/cmd-server-info.c index 7ad7bdd6..b4cce636 100644 --- a/cmd-server-info.c +++ b/cmd-server-info.c @@ -70,8 +70,8 @@ cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx) ctx->print(ctx, "pid %ld, started %s", (long) getpid(), tim); ctx->print(ctx, "socket path %s, debug level %d%s", socket_path, debug_level, be_quiet ? ", quiet" : ""); - if (uname(&un) == 0) { - ctx->print(ctx, "system is %s %s %s %s", + if (uname(&un) == 0) { + ctx->print(ctx, "system is %s %s %s %s", un.sysname, un.release, un.version, un.machine); } if (cfg_file != NULL) diff --git a/cmd-string.c b/cmd-string.c index 41b20948..06f01a54 100644 --- a/cmd-string.c +++ b/cmd-string.c @@ -204,33 +204,33 @@ cmd_string_string(const char *s, size_t *p, char endch, int esc) char *buf, *t; size_t len; - buf = NULL; + buf = NULL; len = 0; - while ((ch = cmd_string_getc(s, p)) != endch) { - switch (ch) { + while ((ch = cmd_string_getc(s, p)) != endch) { + switch (ch) { case EOF: goto error; - case '\\': + case '\\': if (!esc) break; - switch (ch = cmd_string_getc(s, p)) { + switch (ch = cmd_string_getc(s, p)) { case EOF: goto error; case 'e': ch = '\033'; break; - case 'r': - ch = '\r'; - break; - case 'n': - ch = '\n'; - break; - case 't': - ch = '\t'; - break; - } - break; + case 'r': + ch = '\r'; + break; + case 'n': + ch = '\n'; + break; + case 't': + ch = '\t'; + break; + } + break; case '$': if (!esc) break; @@ -241,13 +241,13 @@ cmd_string_string(const char *s, size_t *p, char endch, int esc) len += strlen(t); xfree(t); continue; - } + } if (len >= SIZE_MAX - 2) goto error; buf = xrealloc(buf, 1, len + 1); - buf[len++] = ch; - } + buf[len++] = ch; + } buf = xrealloc(buf, 1, len + 1); buf[len] = '\0'; @@ -272,7 +272,7 @@ cmd_string_variable(const char *s, size_t *p) ((ch) >= 'a' && (ch) <= 'z') || ((ch) >= 'A' && (ch) <= 'Z') || \ ((ch) >= '0' && (ch) <= '9')) - buf = NULL; + buf = NULL; len = 0; fch = EOF; diff --git a/cmd.c b/cmd.c index bf07c3b0..96a06b6c 100644 --- a/cmd.c +++ b/cmd.c @@ -179,7 +179,7 @@ struct cmd * cmd_parse(int argc, char **argv, char **cause) { const struct cmd_entry **entryp, *entry; - struct cmd *cmd; + struct cmd *cmd; char s[BUFSIZ]; int opt, ambiguous = 0; @@ -842,7 +842,7 @@ cmd_find_pane(struct cmd_ctx *ctx, /* Get the current session. */ if ((s = cmd_current_session(ctx)) == NULL) { - ctx->error(ctx, "can't establish current session"); + ctx->error(ctx, "can't establish current session"); return (NULL); } if (sp != NULL) diff --git a/input.c b/input.c index bb6ac496..f0a566e5 100644 --- a/input.c +++ b/input.c @@ -128,7 +128,7 @@ input_sequence_cmp(const void *a, const void *b) void input_new_argument(struct input_ctx *ictx) { - struct input_arg *arg; + struct input_arg *arg; ARRAY_EXPAND(&ictx->args, 1); @@ -139,7 +139,7 @@ input_new_argument(struct input_ctx *ictx) int input_add_argument(struct input_ctx *ictx, u_char ch) { - struct input_arg *arg; + struct input_arg *arg; if (ARRAY_LENGTH(&ictx->args) == 0) return (0); @@ -792,7 +792,7 @@ input_handle_sequence(u_char ch, struct input_ctx *ictx) { struct input_sequence_entry *entry, find; struct screen *s = ictx->ctx.s; - u_int i; + u_int i; struct input_arg *iarg; log_debug2("-- sq %zu: %hhu (%c): %u [sx=%u, sy=%u, cx=%u, cy=%u, " diff --git a/server-client.c b/server-client.c index 5038a036..0cc943d5 100644 --- a/server-client.c +++ b/server-client.c @@ -492,8 +492,8 @@ server_client_msg_dispatch(struct client *c) struct msg_environ_data environdata; ssize_t n, datalen; - if ((n = imsg_read(&c->ibuf)) == -1 || n == 0) - return (-1); + if ((n = imsg_read(&c->ibuf)) == -1 || n == 0) + return (-1); for (;;) { if ((n = imsg_get(&c->ibuf, &imsg)) == -1) diff --git a/server.c b/server.c index 78c5af94..b7b35892 100644 --- a/server.c +++ b/server.c @@ -667,12 +667,12 @@ void server_lock_sessions(void) { struct session *s; - u_int i; + u_int i; int timeout; - time_t t; + time_t t; - t = time(NULL); - for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { + t = time(NULL); + for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { if ((s = ARRAY_ITEM(&sessions, i)) == NULL) continue; diff --git a/tmux.c b/tmux.c index add7289e..51f8dbef 100644 --- a/tmux.c +++ b/tmux.c @@ -344,10 +344,10 @@ main(int argc, char **argv) case 'v': debug_level++; break; - default: + default: usage(); - } - } + } + } argc -= optind; argv += optind; @@ -569,7 +569,7 @@ main(int argc, char **argv) if (pfd.revents & (POLLERR|POLLHUP|POLLNVAL)) fatalx("socket error"); - if (pfd.revents & POLLIN) { + if (pfd.revents & POLLIN) { if (dispatch_imsg(ibuf, shellcmd, &retcode) != 0) break; } @@ -594,7 +594,7 @@ dispatch_imsg(struct imsgbuf *ibuf, const char *shellcmd, int *retcode) struct msg_print_data printdata; struct msg_shell_data shelldata; - if ((n = imsg_read(ibuf)) == -1 || n == 0) + if ((n = imsg_read(ibuf)) == -1 || n == 0) fatalx("imsg_read failed"); for (;;) { diff --git a/tty.c b/tty.c index d329e15b..b0a91ffc 100644 --- a/tty.c +++ b/tty.c @@ -144,7 +144,7 @@ tty_start_tty(struct tty *tty) tio.c_lflag &= ~(IEXTEN|ICANON|ECHO|ECHOE|ECHONL|ECHOCTL| ECHOPRT|ECHOKE|ECHOCTL|ISIG); tio.c_cc[VMIN] = 1; - tio.c_cc[VTIME] = 0; + tio.c_cc[VTIME] = 0; if (tcsetattr(tty->fd, TCSANOW, &tio) != 0) fatal("tcsetattr failed"); diff --git a/xmalloc.c b/xmalloc.c index 5eb5c4a8..43b0080d 100644 --- a/xmalloc.c +++ b/xmalloc.c @@ -42,16 +42,16 @@ xstrdup(const char *s) void * xcalloc(size_t nmemb, size_t size) { - void *ptr; + void *ptr; - if (size == 0 || nmemb == 0) + if (size == 0 || nmemb == 0) fatalx("zero size"); - if (SIZE_MAX / nmemb < size) - fatalx("nmemb * size > SIZE_MAX"); - if ((ptr = calloc(nmemb, size)) == NULL) + if (SIZE_MAX / nmemb < size) + fatalx("nmemb * size > SIZE_MAX"); + if ((ptr = calloc(nmemb, size)) == NULL) fatal("xcalloc failed"); - return (ptr); + return (ptr); } void * @@ -59,12 +59,12 @@ xmalloc(size_t size) { void *ptr; - if (size == 0) - fatalx("zero size"); - if ((ptr = malloc(size)) == NULL) + if (size == 0) + fatalx("zero size"); + if ((ptr = malloc(size)) == NULL) fatal("xmalloc failed"); - return (ptr); + return (ptr); } void * @@ -74,13 +74,13 @@ xrealloc(void *oldptr, size_t nmemb, size_t size) void *newptr; if (newsize == 0) - fatalx("zero size"); - if (SIZE_MAX / nmemb < size) - fatalx("nmemb * size > SIZE_MAX"); - if ((newptr = realloc(oldptr, newsize)) == NULL) + fatalx("zero size"); + if (SIZE_MAX / nmemb < size) + fatalx("nmemb * size > SIZE_MAX"); + if ((newptr = realloc(oldptr, newsize)) == NULL) fatal("xrealloc failed"); - return (newptr); + return (newptr); } void @@ -94,12 +94,12 @@ xfree(void *ptr) int printflike2 xasprintf(char **ret, const char *fmt, ...) { - va_list ap; - int i; + va_list ap; + int i; - va_start(ap, fmt); - i = xvasprintf(ret, fmt, ap); - va_end(ap); + va_start(ap, fmt); + i = xvasprintf(ret, fmt, ap); + va_end(ap); return (i); } @@ -110,21 +110,21 @@ xvasprintf(char **ret, const char *fmt, va_list ap) int i; i = vasprintf(ret, fmt, ap); - if (i < 0 || *ret == NULL) - fatal("xvasprintf failed"); + if (i < 0 || *ret == NULL) + fatal("xvasprintf failed"); - return (i); + return (i); } int printflike3 xsnprintf(char *buf, size_t len, const char *fmt, ...) { - va_list ap; - int i; + va_list ap; + int i; - va_start(ap, fmt); - i = xvsnprintf(buf, len, fmt, ap); - va_end(ap); + va_start(ap, fmt); + i = xvsnprintf(buf, len, fmt, ap); + va_end(ap); return (i); } @@ -138,8 +138,8 @@ xvsnprintf(char *buf, size_t len, const char *fmt, va_list ap) fatalx("len > INT_MAX"); i = vsnprintf(buf, len, fmt, ap); - if (i < 0) - fatal("vsnprintf failed"); + if (i < 0) + fatal("vsnprintf failed"); - return (i); + return (i); } From 37ffdff5baed2680ac51d694a50e853e5bdfef31 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 27 Oct 2009 13:03:33 +0000 Subject: [PATCH 0468/1180] Move the poll registration functions into the server-*.c files. --- server-client.c | 30 ++++++++++++++++ server-job.c | 13 +++++++ server-window.c | 33 ++++++++++++++++++ server.c | 91 +++---------------------------------------------- tmux.h | 4 +++ 5 files changed, 84 insertions(+), 87 deletions(-) diff --git a/server-client.c b/server-client.c index 0cc943d5..c1e3bec8 100644 --- a/server-client.c +++ b/server-client.c @@ -147,6 +147,36 @@ server_client_lost(struct client *c) recalculate_sizes(); } +/* Register clients for poll. */ +void +server_client_prepare(void) +{ + struct client *c; + u_int i; + int events; + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + if ((c = ARRAY_ITEM(&clients, i)) == NULL) + continue; + + events = 0; + if (!(c->flags & CLIENT_BAD)) + events |= POLLIN; + if (c->ibuf.w.queued > 0) + events |= POLLOUT; + server_poll_add(c->ibuf.fd, events, server_client_callback, c); + + if (c->tty.fd == -1) + continue; + if (c->flags & CLIENT_SUSPENDED || c->session == NULL) + continue; + events = POLLIN; + if (BUFFER_USED(c->tty.out) > 0) + events |= POLLOUT; + server_poll_add(c->tty.fd, events, server_client_callback, c); + } +} + /* Process a single client event. */ void server_client_callback(int fd, int events, void *data) diff --git a/server-job.c b/server-job.c index f1903237..5a703b7b 100644 --- a/server-job.c +++ b/server-job.c @@ -22,6 +22,19 @@ #include "tmux.h" +/* Register jobs for poll. */ +void +server_job_prepare(void) +{ + struct job *job; + + SLIST_FOREACH(job, &all_jobs, lentry) { + if (job->fd == -1) + continue; + server_poll_add(job->fd, POLLIN, server_job_callback, job); + } +} + /* Process a single job event. */ void server_job_callback(int fd, int events, void *data) diff --git a/server-window.c b/server-window.c index d9ff128d..969395c8 100644 --- a/server-window.c +++ b/server-window.c @@ -28,6 +28,39 @@ int server_window_check_content( struct session *, struct window *, struct window_pane *); void server_window_check_alive(struct window *); +/* Register windows for poll. */ +void +server_window_prepare(void) +{ + struct window *w; + struct window_pane *wp; + u_int i; + int events; + + for (i = 0; i < ARRAY_LENGTH(&windows); i++) { + if ((w = ARRAY_ITEM(&windows, i)) == NULL) + continue; + + TAILQ_FOREACH(wp, &w->panes, entry) { + if (wp->fd == -1) + continue; + events = POLLIN; + if (BUFFER_USED(wp->out) > 0) + events |= POLLOUT; + server_poll_add( + wp->fd, events, server_window_callback, wp); + + if (wp->pipe_fd == -1) + continue; + events = 0; + if (BUFFER_USED(wp->pipe_buf) > 0) + events |= POLLOUT; + server_poll_add( + wp->pipe_fd, events, server_window_callback, wp); + } + } +} + /* Process a single window pane event. */ void server_window_callback(int fd, int events, void *data) diff --git a/server.c b/server.c index b7b35892..1877aad1 100644 --- a/server.c +++ b/server.c @@ -59,7 +59,6 @@ RB_HEAD(poll_items, poll_item) poll_items; int server_poll_cmp(struct poll_item *, struct poll_item *); struct poll_item*server_poll_lookup(int); -void server_poll_add(int, int, void (*)(int, int, void *), void *); struct pollfd *server_poll_flatten(int *); void server_poll_dispatch(struct pollfd *, int); void server_poll_reset(void); @@ -72,9 +71,6 @@ int server_main(int); void server_shutdown(void); int server_should_shutdown(void); void server_child_signal(void); -void server_fill_windows(void); -void server_fill_clients(void); -void server_fill_jobs(void); void server_clean_dead(void); void server_second_timers(void); void server_lock_server(void); @@ -346,10 +342,10 @@ server_main(int srv_fd) server_poll_add(srv_fd, POLLIN, server_callback, NULL); /* Fill window and client sockets. */ - server_fill_jobs(); - server_fill_windows(); - server_fill_clients(); - + server_job_prepare(); + server_window_prepare(); + server_client_prepare(); + /* Update socket permissions. */ xtimeout = INFTIM; if (server_update_socket() != 0) @@ -505,85 +501,6 @@ server_child_signal(void) } } -/* Fill window pollfds. */ -void -server_fill_windows(void) -{ - struct window *w; - struct window_pane *wp; - u_int i; - int events; - - for (i = 0; i < ARRAY_LENGTH(&windows); i++) { - w = ARRAY_ITEM(&windows, i); - if (w == NULL) - continue; - - TAILQ_FOREACH(wp, &w->panes, entry) { - if (wp->fd == -1) - continue; - events = POLLIN; - if (BUFFER_USED(wp->out) > 0) - events |= POLLOUT; - server_poll_add( - wp->fd, events, server_window_callback, wp); - - if (wp->pipe_fd == -1) - continue; - events = 0; - if (BUFFER_USED(wp->pipe_buf) > 0) - events |= POLLOUT; - server_poll_add( - wp->pipe_fd, events, server_window_callback, wp); - } - } -} - -/* Fill client pollfds. */ -void -server_fill_clients(void) -{ - struct client *c; - u_int i; - int events; - - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - c = ARRAY_ITEM(&clients, i); - - if (c != NULL) { - events = 0; - if (!(c->flags & CLIENT_BAD)) - events |= POLLIN; - if (c->ibuf.w.queued > 0) - events |= POLLOUT; - server_poll_add( - c->ibuf.fd, events, server_client_callback, c); - } - - if (c != NULL && !(c->flags & CLIENT_SUSPENDED) && - c->tty.fd != -1 && c->session != NULL) { - events = POLLIN; - if (BUFFER_USED(c->tty.out) > 0) - events |= POLLOUT; - server_poll_add( - c->tty.fd, events, server_client_callback, c); - } - } -} - -/* Fill in job fds. */ -void -server_fill_jobs(void) -{ - struct job *job; - - SLIST_FOREACH(job, &all_jobs, lentry) { - if (job->fd == -1) - continue; - server_poll_add(job->fd, POLLIN, server_job_callback, job); - } -} - /* Free dead, unreferenced clients and sessions. */ void server_clean_dead(void) diff --git a/tmux.h b/tmux.h index bc62c813..e270e821 100644 --- a/tmux.h +++ b/tmux.h @@ -1574,18 +1574,22 @@ const char *key_string_lookup_key(int); extern struct clients clients; extern struct clients dead_clients; int server_start(char *); +void server_poll_add(int, int, void (*)(int, int, void *), void *); /* server-client.c */ void server_client_create(int); void server_client_lost(struct client *); +void server_client_prepare(void); void server_client_callback(int, int, void *); void server_client_loop(void); /* server-job.c */ +void server_job_prepare(void); void server_job_callback(int, int, void *); void server_job_loop(void); /* server-window.c */ +void server_window_prepare(void); void server_window_callback(int, int, void *); void server_window_loop(void); From eb5f4460d1dcee0e53197f4d3c4f28768da4b7f8 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 28 Oct 2009 08:27:33 +0000 Subject: [PATCH 0469/1180] Setting SGR0 when setting the fg and bg has problems if only one of the two is meant to be default, so rewrite the code to move this outside, move setting colours before attributes and generally clean up. Tested by sthen@, fixes problems he was seeing with mutt and should fix some existing problems with (rarely) lost attributes. --- tty.c | 231 ++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 144 insertions(+), 87 deletions(-) diff --git a/tty.c b/tty.c index b0a91ffc..e384d97b 100644 --- a/tty.c +++ b/tty.c @@ -33,8 +33,9 @@ void tty_fill_acs(struct tty *); int tty_try_256(struct tty *, u_char, const char *); int tty_try_88(struct tty *, u_char, const char *); -void tty_attributes_fg(struct tty *, const struct grid_cell *); -void tty_attributes_bg(struct tty *, const struct grid_cell *); +void tty_colours(struct tty *, const struct grid_cell *, int *); +void tty_colours_fg(struct tty *, const struct grid_cell *, int *); +void tty_colours_bg(struct tty *, const struct grid_cell *, int *); void tty_redraw_region(struct tty *, const struct tty_ctx *); void tty_emulate_repeat( @@ -1120,14 +1121,23 @@ tty_attributes(struct tty *tty, const struct grid_cell *gc) { struct grid_cell *tc = &tty->cell; u_char changed; - u_int fg, bg, attr; + u_int fg = gc->fg, bg = gc->bg, attr = gc->attr; + + /* If any bits are being cleared, reset everything. */ + if (tc->attr & ~attr) + tty_reset(tty); + + /* + * Set the colours. This may call tty_reset() (so it comes next) and + * may add to the desired attributes in attr. + */ + tty_colours(tty, gc, &attr); /* * If no setab, try to use the reverse attribute as a best-effort for a * non-default background. This is a bit of a hack but it doesn't do * any serious harm and makes a couple of applications happier. */ - fg = gc->fg; bg = gc->bg; attr = gc->attr; if (!tty_term_has(tty->term, TTYC_SETAB)) { if (attr & GRID_ATTR_REVERSE) { if (fg != 7 && fg != 8) @@ -1138,10 +1148,6 @@ tty_attributes(struct tty *tty, const struct grid_cell *gc) } } - /* If any bits are being cleared, reset everything. */ - if (tc->attr & ~attr) - tty_reset(tty); - /* Filter out attribute bits already set. */ changed = attr & ~tc->attr; tc->attr = attr; @@ -1167,24 +1173,140 @@ tty_attributes(struct tty *tty, const struct grid_cell *gc) tty_putcode(tty, TTYC_INVIS); if (changed & GRID_ATTR_CHARSET) tty_putcode(tty, TTYC_SMACS); +} - /* Set foreground colour. */ - if (fg != tc->fg || - (gc->flags & GRID_FLAG_FG256) != (tc->flags & GRID_FLAG_FG256)) { - tty_attributes_fg(tty, gc); - tc->fg = fg; - tc->flags &= ~GRID_FLAG_FG256; - tc->flags |= gc->flags & GRID_FLAG_FG256; +void +tty_colours(struct tty *tty, const struct grid_cell *gc, int *attr) +{ + struct grid_cell *tc = &tty->cell; + u_char fg = gc->fg, bg = gc->bg; + int flags, have_ax; + int fg_default, bg_default; + + /* No changes? Nothing is necessary. */ + flags = (gc->flags ^ tc->flags) & (GRID_FLAG_FG256|GRID_FLAG_BG256); + if (fg == tc->fg && bg == tc->bg && flags == 0) + return; + + /* + * Is either the default colour? This is handled specially because the + * best solution might be to reset both colours to default, in which + * case if only one is default need to fall onward to set the other + * colour. + */ + fg_default = (fg == 8 && !(gc->flags & GRID_FLAG_FG256)); + bg_default = (bg == 8 && !(gc->flags & GRID_FLAG_BG256)); + if (fg_default || bg_default) { + /* + * If don't have AX but do have op, send sgr0 (op can't + * actually be used because it is sometimes the same as sgr0 + * and sometimes isn't). This resets both colours to default. + * + * Otherwise, try to set the default colour only as needed. + */ + have_ax = tty_term_has(tty->term, TTYC_AX); + if (!have_ax && tty_term_has(tty->term, TTYC_OP)) + tty_reset(tty); + else { + if (fg_default && + fg != tc->fg && !(tc->flags & GRID_FLAG_FG256)) { + if (have_ax) + tty_puts(tty, "\033[39m"); + else if (tc->fg != 7) + tty_putcode1(tty, TTYC_SETAF, 7); + tc->fg = 8; + tc->flags &= ~GRID_FLAG_FG256; + } + if (bg_default && + bg != tc->bg && !(tc->flags & GRID_FLAG_BG256)) { + if (have_ax) + tty_puts(tty, "\033[49m"); + else if (tc->bg != 0) + tty_putcode1(tty, TTYC_SETAB, 0); + tc->bg = 8; + tc->flags &= ~GRID_FLAG_BG256; + } + } } - /* Set background colour. */ - if (bg != tc->bg || - (gc->flags & GRID_FLAG_BG256) != (tc->flags & GRID_FLAG_BG256)) { - tty_attributes_bg(tty, gc); - tc->bg = bg; - tc->flags &= ~GRID_FLAG_BG256; - tc->flags |= gc->flags & GRID_FLAG_BG256; + /* Set the foreground colour. */ + if (!fg_default && (fg != tc->fg || + ((gc->flags & GRID_FLAG_FG256) != (tc->flags & GRID_FLAG_FG256)))) + tty_colours_fg(tty, gc, attr); + + /* + * Set the background colour. This must come after the foreground as + * tty_colour_fg() can call tty_reset(). + */ + if (!bg_default && (bg != tc->bg || + ((gc->flags & GRID_FLAG_BG256) != (tc->flags & GRID_FLAG_BG256)))) + tty_colours_bg(tty, gc, attr); +} + +void +tty_colours_fg(struct tty *tty, const struct grid_cell *gc, int *attr) +{ + struct grid_cell *tc = &tty->cell; + u_char fg = gc->fg; + + /* Is this a 256-colour colour? */ + if (gc->flags & GRID_FLAG_FG256) { + /* Try as 256 colours or translating to 88. */ + if (tty_try_256(tty, fg, "38") == 0) + goto save_fg; + if (tty_try_88(tty, fg, "38") == 0) + goto save_fg; + + /* Translate to 16-colour palette, updating bold if needed. */ + fg = colour_256to16(fg); + if (fg & 8) { + fg &= 7; + (*attr) |= GRID_ATTR_BRIGHT; + } else + tty_reset(tty); /* turn off bold */ } + + /* Otherwise set the foreground colour. */ + tty_putcode1(tty, TTYC_SETAF, fg); + +save_fg: + /* Save the new values in the terminal current cell. */ + tc->fg = fg; + tc->flags &= ~GRID_FLAG_FG256; + tc->flags |= gc->flags & GRID_FLAG_FG256; +} + +void +tty_colours_bg(struct tty *tty, const struct grid_cell *gc, unused int *attr) +{ + struct grid_cell *tc = &tty->cell; + u_char bg = gc->bg; + + /* Is this a 256-colour colour? */ + if (gc->flags & GRID_FLAG_BG256) { + /* Try as 256 colours or translating to 88. */ + if (tty_try_256(tty, bg, "48") == 0) + goto save_bg; + if (tty_try_88(tty, bg, "48") == 0) + goto save_bg; + + /* + * Translate to 16-colour palette. Bold background doesn't + * exist portably, so just discard the bold bit if set. + */ + bg = colour_256to16(bg); + if (bg & 8) + bg &= 7; + } + + /* Otherwise set the background colour. */ + tty_putcode1(tty, TTYC_SETAB, bg); + +save_bg: + /* Save the new values in the terminal current cell. */ + tc->bg = bg; + tc->flags &= ~GRID_FLAG_BG256; + tc->flags |= gc->flags & GRID_FLAG_BG256; } int @@ -1215,68 +1337,3 @@ tty_try_88(struct tty *tty, u_char colour, const char *type) tty_puts(tty, s); return (0); } - -void -tty_attributes_fg(struct tty *tty, const struct grid_cell *gc) -{ - u_char fg; - - fg = gc->fg; - if (gc->flags & GRID_FLAG_FG256) { - if (tty_try_256(tty, fg, "38") == 0) - return; - if (tty_try_88(tty, fg, "38") == 0) - return; - fg = colour_256to16(fg); - if (fg & 8) { - fg &= 7; - tty_putcode(tty, TTYC_BOLD); - tty->cell.attr |= GRID_ATTR_BRIGHT; - } else if (tty->cell.attr & GRID_ATTR_BRIGHT) - tty_reset(tty); - } - - if (fg == 8) { - if (tty_term_has(tty->term, TTYC_AX)) { - /* AX is an extension that means \033[39m works. */ - tty_puts(tty, "\033[39m"); - } else if (tty_term_has(tty->term, TTYC_OP)) { - /* - * op can be used to look for default colours but there - * is no point in using it - with some terminals it - * does SGR0 and others not, so SGR0 is needed anyway - * to put the terminal into a known state. - */ - tty_reset(tty); - } else - tty_putcode1(tty, TTYC_SETAF, 7); - } else - tty_putcode1(tty, TTYC_SETAF, fg); -} - -void -tty_attributes_bg(struct tty *tty, const struct grid_cell *gc) -{ - u_char bg; - - bg = gc->bg; - if (gc->flags & GRID_FLAG_BG256) { - if (tty_try_256(tty, bg, "48") == 0) - return; - if (tty_try_88(tty, bg, "48") == 0) - return; - bg = colour_256to16(bg); - if (bg & 8) - bg &= 7; - } - - if (bg == 8) { - if (tty_term_has(tty->term, TTYC_AX)) { - tty_puts(tty, "\033[49m"); - } else if (tty_term_has(tty->term, TTYC_OP)) - tty_reset(tty); - else - tty_putcode1(tty, TTYC_SETAB, 0); - } else - tty_putcode1(tty, TTYC_SETAB, bg); -} From 5730cbf3e3627d40177f9377b068f2ba50144ed9 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 28 Oct 2009 08:33:20 +0000 Subject: [PATCH 0470/1180] Twaek this slightly to avoid confusing use of flags variable. --- tty.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/tty.c b/tty.c index e384d97b..8efc6866 100644 --- a/tty.c +++ b/tty.c @@ -1179,14 +1179,13 @@ void tty_colours(struct tty *tty, const struct grid_cell *gc, int *attr) { struct grid_cell *tc = &tty->cell; - u_char fg = gc->fg, bg = gc->bg; - int flags, have_ax; - int fg_default, bg_default; + u_char fg = gc->fg, bg = gc->bg, flags = gc->flags; + int have_ax, fg_default, bg_default; /* No changes? Nothing is necessary. */ - flags = (gc->flags ^ tc->flags) & (GRID_FLAG_FG256|GRID_FLAG_BG256); - if (fg == tc->fg && bg == tc->bg && flags == 0) - return; + if (fg == tc->fg && bg == tc->bg && + ((flags ^ tc->flags) & (GRID_FLAG_FG256|GRID_FLAG_BG256)) == 0) + return; /* * Is either the default colour? This is handled specially because the @@ -1194,8 +1193,8 @@ tty_colours(struct tty *tty, const struct grid_cell *gc, int *attr) * case if only one is default need to fall onward to set the other * colour. */ - fg_default = (fg == 8 && !(gc->flags & GRID_FLAG_FG256)); - bg_default = (bg == 8 && !(gc->flags & GRID_FLAG_BG256)); + fg_default = (fg == 8 && !(flags & GRID_FLAG_FG256)); + bg_default = (bg == 8 && !(flags & GRID_FLAG_BG256)); if (fg_default || bg_default) { /* * If don't have AX but do have op, send sgr0 (op can't @@ -1231,7 +1230,7 @@ tty_colours(struct tty *tty, const struct grid_cell *gc, int *attr) /* Set the foreground colour. */ if (!fg_default && (fg != tc->fg || - ((gc->flags & GRID_FLAG_FG256) != (tc->flags & GRID_FLAG_FG256)))) + ((flags & GRID_FLAG_FG256) != (tc->flags & GRID_FLAG_FG256)))) tty_colours_fg(tty, gc, attr); /* @@ -1239,7 +1238,7 @@ tty_colours(struct tty *tty, const struct grid_cell *gc, int *attr) * tty_colour_fg() can call tty_reset(). */ if (!bg_default && (bg != tc->bg || - ((gc->flags & GRID_FLAG_BG256) != (tc->flags & GRID_FLAG_BG256)))) + ((flags & GRID_FLAG_BG256) != (tc->flags & GRID_FLAG_BG256)))) tty_colours_bg(tty, gc, attr); } From 1eaefbf1698fc66815e538fc3040f4446f444f7b Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 28 Oct 2009 08:52:36 +0000 Subject: [PATCH 0471/1180] Add a minor optimisatin: if the character being printed is space, don't worry about setting the background colour or attributes (except reverse). --- screen-redraw.c | 2 ++ tty.c | 18 ++++++++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/screen-redraw.c b/screen-redraw.c index 0e612461..105cd4f4 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -257,6 +257,7 @@ screen_redraw_draw_number(struct client *c, struct window_pane *wp) if (wp->sx < len * 6 || wp->sy < 5) { tty_cursor(tty, xoff + px - len / 2, yoff + py); memcpy(&gc, &grid_default_cell, sizeof gc); + gc.data = '_'; /* not space */ colour_set_fg(&gc, colour); tty_attributes(tty, &gc); tty_puts(tty, buf); @@ -267,6 +268,7 @@ screen_redraw_draw_number(struct client *c, struct window_pane *wp) py -= 2; memcpy(&gc, &grid_default_cell, sizeof gc); + gc.data = '_'; /* not space */ colour_set_bg(&gc, colour); tty_attributes(tty, &gc); for (ptr = buf; *ptr != '\0'; ptr++) { diff --git a/tty.c b/tty.c index 8efc6866..1010217d 100644 --- a/tty.c +++ b/tty.c @@ -1119,10 +1119,24 @@ out: void tty_attributes(struct tty *tty, const struct grid_cell *gc) { - struct grid_cell *tc = &tty->cell; + struct grid_cell *tc = &tty->cell, gc2; u_char changed; u_int fg = gc->fg, bg = gc->bg, attr = gc->attr; + /* If the character is space, don't care about foreground. */ + if (gc->data == ' ' && !(gc->flags & GRID_FLAG_UTF8)) { + memcpy(&gc2, gc, sizeof gc2); + + if (gc->attr & GRID_ATTR_REVERSE) + gc2.bg = tc->bg; + else + gc2.fg = tc->fg; + gc2.attr = tc->attr & ~GRID_ATTR_REVERSE; + gc2.attr |= gc->attr & GRID_ATTR_REVERSE; + + gc = &gc2; + } + /* If any bits are being cleared, reset everything. */ if (tc->attr & ~attr) tty_reset(tty); @@ -1185,7 +1199,7 @@ tty_colours(struct tty *tty, const struct grid_cell *gc, int *attr) /* No changes? Nothing is necessary. */ if (fg == tc->fg && bg == tc->bg && ((flags ^ tc->flags) & (GRID_FLAG_FG256|GRID_FLAG_BG256)) == 0) - return; + return; /* * Is either the default colour? This is handled specially because the From dc3fdc8dc7c45fc4924ee4eeb8b6c7c6a80e41f1 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 28 Oct 2009 22:53:14 +0000 Subject: [PATCH 0472/1180] If any client currently displaying a window pane has more than 1 KB of output buffered, don't accept any further data from the process running in the pane. This makes tmux much more responsive when flooded with output, although other buffers can still have an impact when running remotely. Prompted by a query from Ranganathan Sankaralingam. --- server-window.c | 27 ++++++++++++++++++++++++++- tmux.h | 3 +++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/server-window.c b/server-window.c index 969395c8..122ca092 100644 --- a/server-window.c +++ b/server-window.c @@ -22,6 +22,7 @@ #include "tmux.h" +int server_window_backoff(struct window_pane *); int server_window_check_bell(struct session *, struct window *); int server_window_check_activity(struct session *, struct window *); int server_window_check_content( @@ -44,7 +45,9 @@ server_window_prepare(void) TAILQ_FOREACH(wp, &w->panes, entry) { if (wp->fd == -1) continue; - events = POLLIN; + events = 0; + if (!server_window_backoff(wp)) + events |= POLLIN; if (BUFFER_USED(wp->out) > 0) events |= POLLOUT; server_poll_add( @@ -61,6 +64,28 @@ server_window_prepare(void) } } +/* Check if this window should suspend reading. */ +int +server_window_backoff(struct window_pane *wp) +{ + struct client *c; + u_int i; + + if (!window_pane_visible(wp)) + return (0); + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c == NULL || c->session == NULL) + continue; + if (c->session->curw->window != wp->window) + continue; + if (BUFFER_USED(c->tty.out) > BACKOFF_THRESHOLD) + return (1); + } + return (0); +} + /* Process a single window pane event. */ void server_window_callback(int fd, int events, void *data) diff --git a/tmux.h b/tmux.h index e270e821..41ace3a8 100644 --- a/tmux.h +++ b/tmux.h @@ -65,6 +65,9 @@ extern char **environ; /* Maximum poll timeout (when attached). */ #define POLL_TIMEOUT 50 +/* Maximum data to buffer for output before suspending reading from panes. */ +#define BACKOFF_THRESHOLD 1024 + /* * Maximum sizes of strings in message data. Don't forget to bump * PROTOCOL_VERSION if any of these change! From e8b25188ade1b9a680ad8195a501e23a017be691 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 29 Oct 2009 08:59:17 +0000 Subject: [PATCH 0473/1180] Missing ;. From eric@ ages ago. --- array.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/array.h b/array.h index c5ed3d02..d48dbacb 100644 --- a/array.h +++ b/array.h @@ -102,7 +102,7 @@ #define ARRAY_CONCAT(a, b) do { \ ARRAY_ENSURE(a, (b)->num); \ - memcpy((a)->list + (a)->num, (b)->list, (b)->num * ARRAY_ITEMSIZE(a)) \ + memcpy((a)->list + (a)->num, (b)->list, (b)->num * ARRAY_ITEMSIZE(a)); \ (a)->num += (b)->num; \ } while (0) From 32299e401039e9c88e430516e9d85d59d551b859 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 1 Nov 2009 19:17:08 +0000 Subject: [PATCH 0474/1180] Missing setenv/showenv aliases. --- tmux.1 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tmux.1 b/tmux.1 index 497192fa..c9a9710a 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1838,6 +1838,7 @@ Commands to alter and view the environment are: .Op Fl t Ar target-session .Ar name Op Ar value .Xc +.D1 (alias: Ic setenv ) Set or unset an environment variable. If .Fl g @@ -1854,6 +1855,7 @@ new process. .Op Fl g .Op Fl t Ar target-session .Xc +.D1 (alias: Ic showenv ) Display the environment for .Ar target-session or the global environment with From 2f813ef75d7d1cfb32d78923ae6963be7266de55 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 1 Nov 2009 23:20:37 +0000 Subject: [PATCH 0475/1180] Add a flag for jobs that shouldn't be freed after they've died and use it for status jobs, then only kill those jobs when status-left, status-right or set-titles-string is changed. Fixes problems with changing options from inside #(). --- cmd-if-shell.c | 6 ++---- cmd-run-shell.c | 4 +--- cmd-server-info.c | 7 +++++++ cmd-set-option.c | 36 +++++++++++++++++++++++++++++++----- job.c | 16 +++++++++++++--- server-job.c | 5 ++++- status.c | 4 ++-- tmux.h | 4 +++- 8 files changed, 63 insertions(+), 19 deletions(-) diff --git a/cmd-if-shell.c b/cmd-if-shell.c index e0775da8..82da814a 100644 --- a/cmd-if-shell.c +++ b/cmd-if-shell.c @@ -65,7 +65,7 @@ cmd_if_shell_exec(struct cmd *self, struct cmd_ctx *ctx) if (ctx->curclient != NULL) ctx->curclient->references++; - job = job_add(NULL, NULL, + job = job_add(NULL, 0, NULL, data->arg, cmd_if_shell_callback, cmd_if_shell_free, cdata); job_run(job); @@ -80,10 +80,8 @@ cmd_if_shell_callback(struct job *job) struct cmd_list *cmdlist; char *cause; - if (!WIFEXITED(job->status) || WEXITSTATUS(job->status) != 0) { - job_free(job); /* calls cmd_if_shell_free */ + if (!WIFEXITED(job->status) || WEXITSTATUS(job->status) != 0) return; - } if (cmd_string_parse(cdata->cmd, &cmdlist, &cause) != 0) { if (cause != NULL) { diff --git a/cmd-run-shell.c b/cmd-run-shell.c index ca414dc8..1a8e28f4 100644 --- a/cmd-run-shell.c +++ b/cmd-run-shell.c @@ -65,7 +65,7 @@ cmd_run_shell_exec(struct cmd *self, struct cmd_ctx *ctx) if (ctx->curclient != NULL) ctx->curclient->references++; - job = job_add(NULL, NULL, + job = job_add(NULL, 0, NULL, data->arg, cmd_run_shell_callback, cmd_run_shell_free, cdata); job_run(job); @@ -117,8 +117,6 @@ cmd_run_shell_callback(struct job *job) ctx->info(ctx, "%s", msg); xfree(msg); } - - job_free(job); /* calls cmd_run_shell_free */ } void diff --git a/cmd-server-info.c b/cmd-server-info.c index b4cce636..4107527b 100644 --- a/cmd-server-info.c +++ b/cmd-server-info.c @@ -56,6 +56,7 @@ cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx) struct tty_code *code; struct tty_term_code_entry *ent; struct utsname un; + struct job *job; struct grid *gd; struct grid_line *gl; u_int i, j, k; @@ -178,5 +179,11 @@ cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx) } ctx->print(ctx, "%s", ""); + ctx->print(ctx, "Jobs:"); + SLIST_FOREACH(job, &all_jobs, lentry) { + ctx->print(ctx, "%s [fd=%d, pid=%d, status=%d, flags=0x%x]", + job->cmd, job->fd, job->pid, job->status, job->flags); + } + return (0); } diff --git a/cmd-set-option.c b/cmd-set-option.c index a495a15d..536b623b 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -108,7 +108,10 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) struct client *c; struct options *oo; const struct set_option_entry *entry, *opt; + struct jobs *jobs; + struct job *job, *nextjob; u_int i; + int try_again; if (data->chflags & CMD_CHFLAG('g')) oo = &global_s_options; @@ -184,11 +187,34 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) } recalculate_sizes(); - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - c = ARRAY_ITEM(&clients, i); - if (c != NULL && c->session != NULL) { - job_tree_free(&c->status_jobs); - job_tree_init(&c->status_jobs); + + /* + * Special-case: kill all persistent jobs if status-left, status-right + * or set-titles-string have changed. Persistent jobs are only used by + * the status line at the moment so this works XXX. + */ + if (strcmp(entry->name, "status-left") == 0 || + strcmp(entry->name, "status-right") == 0 || + strcmp(entry->name, "set-titles-string") == 0) { + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c == NULL || c->session == NULL) + continue; + + jobs = &c->status_jobs; + do { + try_again = 0; + job = RB_ROOT(jobs); + while (job != NULL) { + nextjob = RB_NEXT(jobs, jobs, job); + if (job->flags & JOB_PERSIST) { + job_remove(jobs, job); + try_again = 1; + break; + } + job = nextjob; + } + } while (try_again); server_redraw_client(c); } } diff --git a/job.c b/job.c index 93ff0644..a638e3d8 100644 --- a/job.c +++ b/job.c @@ -73,7 +73,7 @@ job_get(struct jobs *jobs, const char *cmd) /* Add a job. */ struct job * -job_add(struct jobs *jobs, struct client *c, const char *cmd, +job_add(struct jobs *jobs, int flags, struct client *c, const char *cmd, void (*callbackfn)(struct job *), void (*freefn)(void *), void *data) { struct job *job; @@ -81,6 +81,7 @@ job_add(struct jobs *jobs, struct client *c, const char *cmd, job = xmalloc(sizeof *job); job->cmd = xstrdup(cmd); job->pid = -1; + job->status = 0; job->client = c; @@ -91,15 +92,24 @@ job_add(struct jobs *jobs, struct client *c, const char *cmd, job->freefn = freefn; job->data = data; - job->flags = JOB_DONE; + job->flags = flags|JOB_DONE; if (jobs != NULL) RB_INSERT(jobs, jobs, job); SLIST_INSERT_HEAD(&all_jobs, job, lentry); - + return (job); } +/* Remove job from tree and free. */ +void +job_remove(struct jobs *jobs, struct job *job) +{ + if (jobs != NULL) + RB_REMOVE(jobs, jobs, job); + job_free(job); +} + /* Kill and free an individual job. */ void job_free(struct job *job) diff --git a/server-job.c b/server-job.c index 5a703b7b..6ff15860 100644 --- a/server-job.c +++ b/server-job.c @@ -64,7 +64,10 @@ restart: if (job->callbackfn != NULL) { job->callbackfn(job); - goto restart; /* could be freed by callback */ + if ((!job->flags & JOB_PERSIST)) { + job_free(job); + goto restart; + } } } } diff --git a/status.c b/status.c index 9a3f4867..643c30c6 100644 --- a/status.c +++ b/status.c @@ -476,8 +476,8 @@ status_job(struct client *c, char **iptr) job = job_get(&c->status_jobs, cmd); if (job == NULL) { - job = job_add( - &c->status_jobs, c, cmd, status_job_callback, xfree, NULL); + job = job_add(&c->status_jobs, + JOB_PERSIST, c, cmd, status_job_callback, xfree, NULL); job_run(job); } if (job->data == NULL) diff --git a/tmux.h b/tmux.h index 41ace3a8..73ac9803 100644 --- a/tmux.h +++ b/tmux.h @@ -669,6 +669,7 @@ struct job { int flags; #define JOB_DONE 0x1 +#define JOB_PERSIST 0x2 /* don't free after callback */ RB_ENTRY(job) entry; SLIST_ENTRY(job) lentry; @@ -1301,8 +1302,9 @@ RB_PROTOTYPE(jobs, job, entry, job_cmp); void job_tree_init(struct jobs *); void job_tree_free(struct jobs *); struct job *job_get(struct jobs *, const char *); -struct job *job_add(struct jobs *, struct client *, +struct job *job_add(struct jobs *, int, struct client *, const char *, void (*)(struct job *), void (*)(void *), void *); +void job_remove(struct jobs *, struct job *); void job_free(struct job *); int job_run(struct job *); void job_kill(struct job *); From 992dd863098183ffca267677f7d590c3cce6feee Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 2 Nov 2009 12:48:44 +0000 Subject: [PATCH 0476/1180] Reorder slightly to tidy code. --- server.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/server.c b/server.c index 1877aad1..ed551694 100644 --- a/server.c +++ b/server.c @@ -272,14 +272,13 @@ server_start(char *path) srv_fd = server_create_socket(); server_client_create(pair[1]); - if (access(SYSTEM_CFG, R_OK) != 0) { - if (errno != ENOENT) { - xasprintf( - &cause, "%s: %s", strerror(errno), SYSTEM_CFG); + if (access(SYSTEM_CFG, R_OK) == 0) { + if (load_cfg(SYSTEM_CFG, NULL, &cause) != 0) goto error; - } - } else if (load_cfg(SYSTEM_CFG, NULL, &cause) != 0) + } else if (errno != ENOENT) { + xasprintf(&cause, "%s: %s", strerror(errno), SYSTEM_CFG); goto error; + } if (cfg_file != NULL && load_cfg(cfg_file, NULL, &cause) != 0) goto error; From 42fd44f1dbe9e0ea339375185a2b984f21fad93d Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 2 Nov 2009 13:41:25 +0000 Subject: [PATCH 0477/1180] There isn't much point in doing lstat before connect so instead just do connect and handle ENOENT from it which is a little tidier. --- client.c | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/client.c b/client.c index a5c5e39e..c41c669e 100644 --- a/client.c +++ b/client.c @@ -55,19 +55,6 @@ client_init(char *path, int cmdflags, int flags) strlcpy(rpathbuf, path, sizeof rpathbuf); setproctitle("client (%s)", rpathbuf); - if (lstat(path, &sb) != 0) { - if (cmdflags & CMD_STARTSERVER && errno == ENOENT) { - if ((fd = server_start(path)) == -1) - goto start_failed; - goto server_started; - } - goto not_found; - } - if (!S_ISSOCK(sb.st_mode)) { - errno = ENOTSOCK; - goto not_found; - } - memset(&sa, 0, sizeof sa); sa.sun_family = AF_UNIX; size = strlcpy(sa.sun_path, path, sizeof sa.sun_path); @@ -80,9 +67,14 @@ client_init(char *path, int cmdflags, int flags) fatal("socket failed"); if (connect(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1) { - if (errno == ECONNREFUSED) { - if (unlink(path) != 0 || !(cmdflags & CMD_STARTSERVER)) + if (!(cmdflags & CMD_STARTSERVER)) + goto not_found; + switch (errno) { + case ECONNREFUSED: + if (unlink(path) != 0) goto not_found; + /* FALLTHROUGH */ + case ENOENT: if ((fd = server_start(path)) == -1) goto start_failed; goto server_started; From 2a585dc4ed3ad605487d00148b906325ff915a5c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 2 Nov 2009 13:42:25 +0000 Subject: [PATCH 0478/1180] Leftover unused variable :-/. --- client.c | 1 - 1 file changed, 1 deletion(-) diff --git a/client.c b/client.c index c41c669e..4d5fd696 100644 --- a/client.c +++ b/client.c @@ -46,7 +46,6 @@ struct imsgbuf * client_init(char *path, int cmdflags, int flags) { struct sockaddr_un sa; - struct stat sb; size_t size; int fd, mode; char rpathbuf[MAXPATHLEN]; From 1c853c68602cf713fe3de98ae2ea5a48a1120abc Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 2 Nov 2009 16:24:29 +0000 Subject: [PATCH 0479/1180] When matching the session names with -t, look for exact matches first before trying partial matches. Avoids problems where two ambiguous matches are present before an exact match (eg foo1, foo2, foo would give an error on trying -tfoo), reported by Natacha Port? natbsd at instinctive dot eu. --- cmd.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/cmd.c b/cmd.c index 96a06b6c..7ce88f47 100644 --- a/cmd.c +++ b/cmd.c @@ -488,19 +488,25 @@ cmd_lookup_session(const char *name, int *ambiguous) *ambiguous = 0; /* - * Look for matches. Session names must be unique so an exact match - * can't be ambigious and can just be returned. + * Look for matches. First look for exact matches - session names must + * be unique so an exact match can't be ambigious and can just be + * returned. + */ + for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { + if ((s = ARRAY_ITEM(&sessions, i)) == NULL) + continue; + if (strcmp(name, s->name) == 0) + return (s); + } + + /* + * Otherwise look for partial matches, returning early if it is found to + * be ambiguous. */ sfound = NULL; for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { if ((s = ARRAY_ITEM(&sessions, i)) == NULL) continue; - - /* Check for an exact match and return it if found. */ - if (strcmp(name, s->name) == 0) - return (s); - - /* Then check for pattern matches. */ if (strncmp(name, s->name, strlen(name)) == 0 || fnmatch(name, s->name, 0) == 0) { if (sfound != NULL) { @@ -510,7 +516,6 @@ cmd_lookup_session(const char *name, int *ambiguous) sfound = s; } } - return (sfound); } From 86182f33c32d3154a4d0fc9544f59c5504918d80 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 2 Nov 2009 20:18:22 +0000 Subject: [PATCH 0480/1180] Double the escape timer (the time after a \033 is received before tmux gives up waiting to see if it is part of a key sequence and passes it through) to 500 ms, the previous setting was too fast. Suggested by naddy. --- tmux.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tmux.h b/tmux.h index 73ac9803..6902483c 100644 --- a/tmux.h +++ b/tmux.h @@ -60,7 +60,7 @@ extern char **environ; #define NAME_INTERVAL 500 /* Escape timer period, in milliseconds. */ -#define ESCAPE_PERIOD 250 +#define ESCAPE_PERIOD 500 /* Maximum poll timeout (when attached). */ #define POLL_TIMEOUT 50 From 01943062b4f669309d75c9dccf373a798f73751f Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 3 Nov 2009 06:55:49 +0000 Subject: [PATCH 0481/1180] Fix vi page up mode key (from naddy), add missing half page keys, and sort. --- tmux.1 | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tmux.1 b/tmux.1 index c9a9710a..0014e6a0 100644 --- a/tmux.1 +++ b/tmux.1 @@ -515,15 +515,20 @@ The following keys are supported as appropriate for the mode: .It Li "Cursor down" Ta "j" Ta "Down" .It Li "Cursor left" Ta "h" Ta "Left" .It Li "Cursor right" Ta "l" Ta "Right" +.It Li "Cursor to bottom line" Ta "L" Ta "" +.It Li "Cursor to middle line" Ta "M" Ta "M-r" +.It Li "Cursor to top line" Ta "H" Ta "M-R" .It Li "Cursor up" Ta "k" Ta "Up" .It Li "Delete entire line" Ta "d" Ta "C-u" .It Li "Delete to end of line" Ta "D" Ta "C-k" .It Li "End of line" Ta "$" Ta "C-e" .It Li "Goto line" Ta ":" Ta "g" +.It Li "Half page down" Ta "C-d" Ta "M-Down" +.It Li "Half page up" Ta "C-u" Ta "M-Up" .It Li "Next page" Ta "C-f" Ta "Page down" .It Li "Next word" Ta "w" Ta "M-f" .It Li "Paste buffer" Ta "p" Ta "C-y" -.It Li "Previous page" Ta "C-u" Ta "Page up" +.It Li "Previous page" Ta "C-b" Ta "Page up" .It Li "Previous word" Ta "b" Ta "M-b" .It Li "Quit mode" Ta "q" Ta "Escape" .It Li "Scroll down" Ta "C-Down or J" Ta "C-Down" @@ -534,9 +539,6 @@ The following keys are supported as appropriate for the mode: .It Li "Start of line" Ta "0" Ta "C-a" .It Li "Start selection" Ta "Space" Ta "C-Space" .It Li "Transpose chars" Ta "" Ta "C-t" -.It Li "Cursor to top line" Ta "H" Ta "M-R" -.It Li "Cursor to middle line" Ta "M" Ta "M-r" -.It Li "Cursor to bottom line" Ta "L" Ta "" .El .Pp These key bindings are defined in a set of named tables: From c95f1d1ff951fdfea9057952ecadb25884ba8daa Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 3 Nov 2009 17:17:24 +0000 Subject: [PATCH 0482/1180] tv member of struct paste_buffer is updated but not otherwise used, so remove it. --- paste.c | 4 ---- tmux.h | 1 - 2 files changed, 5 deletions(-) diff --git a/paste.c b/paste.c index 582645d5..142e46cf 100644 --- a/paste.c +++ b/paste.c @@ -116,8 +116,6 @@ paste_add(struct paste_stack *ps, u_char *data, size_t size, u_int limit) pb->data = data; pb->size = size; - if (gettimeofday(&pb->tv, NULL) != 0) - fatal("gettimeofday failed"); } int @@ -133,8 +131,6 @@ paste_replace(struct paste_stack *ps, u_int idx, u_char *data, size_t size) pb->data = data; pb->size = size; - if (gettimeofday(&pb->tv, NULL) != 0) - fatal("gettimeofday failed"); return (0); } diff --git a/tmux.h b/tmux.h index 6902483c..20a1cbb9 100644 --- a/tmux.h +++ b/tmux.h @@ -893,7 +893,6 @@ struct layout_cell { struct paste_buffer { char *data; size_t size; - struct timeval tv; }; ARRAY_DECL(paste_stack, struct paste_buffer *); From 5289da29ba2fdf15413ec94fa7f2838469abccae Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 3 Nov 2009 20:29:47 +0000 Subject: [PATCH 0483/1180] Change session and client activity and creation time members to have more meaningful names. Also, remove the code to try and update the session activity time for the command client when a command message is received as is pointless because it des not have a session. --- cmd-list-sessions.c | 2 +- cmd-server-info.c | 2 +- cmd.c | 8 ++++---- server-client.c | 35 ++++++++++++++++++----------------- server.c | 10 ++++++---- session.c | 4 ++-- tmux.h | 8 +++++--- 7 files changed, 37 insertions(+), 32 deletions(-) diff --git a/cmd-list-sessions.c b/cmd-list-sessions.c index cfa1433b..908278d5 100644 --- a/cmd-list-sessions.c +++ b/cmd-list-sessions.c @@ -61,7 +61,7 @@ cmd_list_sessions_exec(unused struct cmd *self, struct cmd_ctx *ctx) xsnprintf(tmp, sizeof tmp, " (group %u)", idx); } - t = s->tv.tv_sec; + t = s->creation_time.tv_sec; tim = ctime(&t); *strchr(tim, '\n') = '\0'; diff --git a/cmd-server-info.c b/cmd-server-info.c index 4107527b..4bd6b67f 100644 --- a/cmd-server-info.c +++ b/cmd-server-info.c @@ -105,7 +105,7 @@ cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx) if (s == NULL) continue; - t = s->tv.tv_sec; + t = s->creation_time.tv_sec; tim = ctime(&t); *strchr(tim, '\n') = '\0'; diff --git a/cmd.c b/cmd.c index 7ce88f47..ee713a38 100644 --- a/cmd.c +++ b/cmd.c @@ -362,9 +362,9 @@ cmd_newest_session(struct sessions *ss) if ((s = ARRAY_ITEM(ss, i)) == NULL) continue; - if (tv == NULL || timercmp(&s->tv, tv, >)) { + if (tv == NULL || timercmp(&s->creation_time, tv, >)) { snewest = s; - tv = &s->tv; + tv = &s->creation_time; } } @@ -386,9 +386,9 @@ cmd_newest_client(void) if (c->session == NULL) continue; - if (tv == NULL || timercmp(&c->tv, tv, >)) { + if (tv == NULL || timercmp(&c->creation_time, tv, >)) { cnewest = c; - tv = &c->tv; + tv = &c->creation_time; } } diff --git a/server-client.c b/server-client.c index c1e3bec8..a337c6b2 100644 --- a/server-client.c +++ b/server-client.c @@ -61,7 +61,7 @@ server_client_create(int fd) c->references = 0; imsg_init(&c->ibuf, fd); - if (gettimeofday(&c->tv, NULL) != 0) + if (gettimeofday(&c->creation_time, NULL) != 0) fatal("gettimeofday failed"); ARRAY_INIT(&c->prompt_hdata); @@ -261,18 +261,19 @@ server_client_handle_data(struct client *c) struct window_pane *wp; struct screen *s; struct options *oo; - struct timeval tv; + struct timeval tv_add, tv_now; struct key_binding *bd; struct keylist *keylist; struct mouse_event mouse; int key, status, xtimeout, mode, isprefix; u_int i; + /* Check and update repeat flag. */ + if (gettimeofday(&tv_now, NULL) != 0) + fatal("gettimeofday failed"); xtimeout = options_get_number(&c->session->options, "repeat-time"); if (xtimeout != 0 && c->flags & CLIENT_REPEAT) { - if (gettimeofday(&tv, NULL) != 0) - fatal("gettimeofday failed"); - if (timercmp(&tv, &c->repeat_timer, >)) + if (timercmp(&tv_now, &c->repeat_timer, >)) c->flags &= ~(CLIENT_PREFIX|CLIENT_REPEAT); } @@ -281,12 +282,14 @@ server_client_handle_data(struct client *c) while (tty_keys_next(&c->tty, &key, &mouse) == 0) { if (c->session == NULL) return; - - c->session->activity = time(NULL); w = c->session->curw->window; wp = w->active; /* could die */ oo = &c->session->options; + /* Update activity timer. */ + memcpy(&c->session->activity_time, + &tv_now, sizeof c->session->activity_time); + /* Special case: number keys jump to pane in identify mode. */ if (c->flags & CLIENT_IDENTIFY && key >= '0' && key <= '9') { wp = window_pane_at_index(w, key - '0'); @@ -364,11 +367,9 @@ server_client_handle_data(struct client *c) if (xtimeout != 0 && bd->can_repeat) { c->flags |= CLIENT_PREFIX|CLIENT_REPEAT; - tv.tv_sec = xtimeout / 1000; - tv.tv_usec = (xtimeout % 1000) * 1000L; - if (gettimeofday(&c->repeat_timer, NULL) != 0) - fatal("gettimeofday failed"); - timeradd(&c->repeat_timer, &tv, &c->repeat_timer); + tv_add.tv_sec = xtimeout / 1000; + tv_add.tv_usec = (xtimeout % 1000) * 1000L; + timeradd(&tv_now, &tv_add, &c->repeat_timer); } /* Dispatch the command. */ @@ -581,11 +582,14 @@ server_client_msg_dispatch(struct client *c) if (!(c->flags & CLIENT_SUSPENDED)) break; c->flags &= ~CLIENT_SUSPENDED; + + if (c->session != NULL && + gettimeofday(&c->session->activity_time, NULL) != 0) + fatal("gettimeofday failed"); + tty_start_tty(&c->tty); server_redraw_client(c); recalculate_sizes(); - if (c->session != NULL) - c->session->activity = time(NULL); break; case MSG_ENVIRON: if (datalen != sizeof environdata) @@ -665,9 +669,6 @@ server_client_msg_command(struct client *c, struct msg_command_data *data) int argc; char **argv, *cause; - if (c->session != NULL) - c->session->activity = time(NULL); - ctx.error = server_client_msg_error; ctx.print = server_client_msg_print; ctx.info = server_client_msg_info; diff --git a/server.c b/server.c index ed551694..1113d4dc 100644 --- a/server.c +++ b/server.c @@ -565,12 +565,13 @@ server_lock_server(void) continue; if (s->flags & SESSION_UNATTACHED) { - s->activity = time(NULL); + if (gettimeofday(&s->activity_time, NULL) != 0) + fatal("gettimeofday failed"); continue; } timeout = options_get_number(&s->options, "lock-after-time"); - if (timeout <= 0 || t <= s->activity + timeout) + if (timeout <= 0 || t <= s->activity_time.tv_sec + timeout) return; /* not timed out */ } @@ -593,12 +594,13 @@ server_lock_sessions(void) continue; if (s->flags & SESSION_UNATTACHED) { - s->activity = time(NULL); + if (gettimeofday(&s->activity_time, NULL) != 0) + fatal("gettimeofday failed"); continue; } timeout = options_get_number(&s->options, "lock-after-time"); - if (timeout > 0 && t > s->activity + timeout) { + if (timeout > 0 && t > s->activity_time.tv_sec + timeout) { server_lock_session(s); recalculate_sizes(); } diff --git a/session.c b/session.c index a477634e..8d22ac77 100644 --- a/session.c +++ b/session.c @@ -126,10 +126,10 @@ session_create(const char *name, const char *cmd, const char *cwd, s = xmalloc(sizeof *s); s->references = 0; s->flags = 0; - s->activity = time(NULL); - if (gettimeofday(&s->tv, NULL) != 0) + if (gettimeofday(&s->creation_time, NULL) != 0) fatal("gettimeofday failed"); + memcpy(&s->activity_time, &s->creation_time, sizeof s->activity_time); s->curw = NULL; TAILQ_INIT(&s->lastw); diff --git a/tmux.h b/tmux.h index 20a1cbb9..62419913 100644 --- a/tmux.h +++ b/tmux.h @@ -922,8 +922,9 @@ TAILQ_HEAD(session_groups, session_group); struct session { char *name; - struct timeval tv; - time_t activity; + + struct timeval creation_time; + struct timeval activity_time; u_int sx; u_int sy; @@ -1061,7 +1062,8 @@ struct mouse_event { /* Client connection. */ struct client { struct imsgbuf ibuf; - struct timeval tv; + + struct timeval creation_time; struct environ environ; From 5761ab6b555db9ec16e79722897c09685a03f9d5 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 3 Nov 2009 20:59:22 +0000 Subject: [PATCH 0484/1180] If it isn't available explicitly, work out the current client in a similar way to the current session - build a list of the possibilities then pick the newest. --- cmd.c | 76 +++++++++++++++++++++++++++++++++++----------------------- tmux.h | 1 + 2 files changed, 47 insertions(+), 30 deletions(-) diff --git a/cmd.c b/cmd.c index ee713a38..23db4e84 100644 --- a/cmd.c +++ b/cmd.c @@ -111,7 +111,7 @@ const struct cmd_entry *cmd_table[] = { }; struct session *cmd_newest_session(struct sessions *); -struct client *cmd_newest_client(void); +struct client *cmd_newest_client(struct clients *); struct client *cmd_lookup_client(const char *); struct session *cmd_lookup_session(const char *, int *); struct winlink *cmd_lookup_window(struct session *, const char *, int *); @@ -371,17 +371,56 @@ cmd_newest_session(struct sessions *ss) return (snewest); } +/* + * Find the current client. First try the current client if set, then pick the + * newest of the clients attached to the current session if any, then the + * newest client. + */ +struct client * +cmd_current_client(struct cmd_ctx *ctx) +{ + struct session *s; + struct client *c; + struct clients cc; + u_int i; + + if (ctx->curclient != NULL) + return (ctx->curclient); + + /* + * No current client set. Find the current session and return the + * newest of its clients. + */ + s = cmd_current_session(ctx); + if (s != NULL && !(s->flags & SESSION_UNATTACHED)) { + ARRAY_INIT(&cc); + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + if ((c = ARRAY_ITEM(&clients, i)) == NULL) + continue; + if (s == c->session) + ARRAY_ADD(&cc, c); + } + + c = cmd_newest_client(&cc); + ARRAY_FREE(&cc); + if (c != NULL) + return (c); + } + + return (cmd_newest_client(&clients)); +} + /* Find the newest client. */ struct client * -cmd_newest_client(void) +cmd_newest_client(struct clients *cc) { struct client *c, *cnewest; struct timeval *tv = NULL; u_int i; cnewest = NULL; - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - if ((c = ARRAY_ITEM(&clients, i)) == NULL) + for (i = 0; i < ARRAY_LENGTH(cc); i++) { + if ((c = ARRAY_ITEM(cc, i)) == NULL) continue; if (c->session == NULL) continue; @@ -399,36 +438,13 @@ cmd_newest_client(void) struct client * cmd_find_client(struct cmd_ctx *ctx, const char *arg) { - struct client *c, *lastc; - struct session *s; + struct client *c; char *tmparg; size_t arglen; - u_int i; /* A NULL argument means the current client. */ - if (arg == NULL) { - if (ctx->curclient != NULL) - return (ctx->curclient); - /* - * No current client set. Find the current session and see if - * it has only one client. - */ - s = cmd_current_session(ctx); - if (s != NULL) { - lastc = NULL; - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - c = ARRAY_ITEM(&clients, i); - if (c != NULL && c->session == s) { - if (lastc != NULL) - break; - lastc = c; - } - } - if (i == ARRAY_LENGTH(&clients) && lastc != NULL) - return (lastc); - } - return (cmd_newest_client()); - } + if (arg == NULL) + return (cmd_current_client(ctx)); tmparg = xstrdup(arg); /* Trim a single trailing colon if any. */ diff --git a/tmux.h b/tmux.h index 62419913..bdbdf405 100644 --- a/tmux.h +++ b/tmux.h @@ -1427,6 +1427,7 @@ int cmd_exec(struct cmd *, struct cmd_ctx *); void cmd_free(struct cmd *); size_t cmd_print(struct cmd *, char *, size_t); struct session *cmd_current_session(struct cmd_ctx *); +struct client *cmd_current_client(struct cmd_ctx *); struct client *cmd_find_client(struct cmd_ctx *, const char *); struct session *cmd_find_session(struct cmd_ctx *, const char *); struct winlink *cmd_find_window( From 0785f2872f0f41f15c1c67bb1f6bfb4e1baba180 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 3 Nov 2009 22:40:40 +0000 Subject: [PATCH 0485/1180] Add an activity time for clients, like for sessions, and change session and client lookup to pick the most recently used rather than the most recently created - this is much more useful when used interactively and (because the activity time is set at creation) should have no effect on source-file. Based on a problem reported by Jan Johansson. --- cmd.c | 55 +++++++++++++++++++++++++------------------------ server-client.c | 12 ++++++++--- tmux.1 | 2 +- tmux.h | 1 + 4 files changed, 39 insertions(+), 31 deletions(-) diff --git a/cmd.c b/cmd.c index 23db4e84..9008a532 100644 --- a/cmd.c +++ b/cmd.c @@ -110,8 +110,8 @@ const struct cmd_entry *cmd_table[] = { NULL }; -struct session *cmd_newest_session(struct sessions *); -struct client *cmd_newest_client(struct clients *); +struct session *cmd_choose_session(struct sessions *); +struct client *cmd_choose_client(struct clients *); struct client *cmd_lookup_client(const char *); struct session *cmd_lookup_session(const char *, int *); struct winlink *cmd_lookup_window(struct session *, const char *, int *); @@ -285,9 +285,10 @@ cmd_print(struct cmd *cmd, char *buf, size_t len) /* * Figure out the current session. Use: 1) the current session, if the command - * context has one; 2) the session containing the pty of the calling client, if - * any 3) the session specified in the TMUX variable from the environment (as - * passed from the client); 3) the newest session. + * context has one; 2) the most recently used session containing the pty of the + * calling client, if any; 3) the session specified in the TMUX variable from + * the environment (as passed from the client); 4) the most recently used + * session from all sessions. */ struct session * cmd_current_session(struct cmd_ctx *ctx) @@ -329,7 +330,7 @@ cmd_current_session(struct cmd_ctx *ctx) ARRAY_ADD(&ss, s); } - s = cmd_newest_session(&ss); + s = cmd_choose_session(&ss); ARRAY_FREE(&ss); if (s != NULL) return (s); @@ -346,35 +347,35 @@ cmd_current_session(struct cmd_ctx *ctx) return (s); } - return (cmd_newest_session(&sessions)); + return (cmd_choose_session(&sessions)); } -/* Find the newest session. */ +/* Find the most recently used session from a list. */ struct session * -cmd_newest_session(struct sessions *ss) +cmd_choose_session(struct sessions *ss) { - struct session *s, *snewest; + struct session *s, *sbest; struct timeval *tv = NULL; u_int i; - snewest = NULL; + sbest = NULL; for (i = 0; i < ARRAY_LENGTH(ss); i++) { if ((s = ARRAY_ITEM(ss, i)) == NULL) continue; - if (tv == NULL || timercmp(&s->creation_time, tv, >)) { - snewest = s; - tv = &s->creation_time; + if (tv == NULL || timercmp(&s->activity_time, tv, >)) { + sbest = s; + tv = &s->activity_time; } } - return (snewest); + return (sbest); } /* * Find the current client. First try the current client if set, then pick the - * newest of the clients attached to the current session if any, then the - * newest client. + * most recently used of the clients attached to the current session if any, + * then of all clients. */ struct client * cmd_current_client(struct cmd_ctx *ctx) @@ -401,37 +402,37 @@ cmd_current_client(struct cmd_ctx *ctx) ARRAY_ADD(&cc, c); } - c = cmd_newest_client(&cc); + c = cmd_choose_client(&cc); ARRAY_FREE(&cc); if (c != NULL) return (c); } - return (cmd_newest_client(&clients)); + return (cmd_choose_client(&clients)); } -/* Find the newest client. */ +/* Choose the most recently used client from a list. */ struct client * -cmd_newest_client(struct clients *cc) +cmd_choose_client(struct clients *cc) { - struct client *c, *cnewest; + struct client *c, *cbest; struct timeval *tv = NULL; u_int i; - cnewest = NULL; + cbest = NULL; for (i = 0; i < ARRAY_LENGTH(cc); i++) { if ((c = ARRAY_ITEM(cc, i)) == NULL) continue; if (c->session == NULL) continue; - if (tv == NULL || timercmp(&c->creation_time, tv, >)) { - cnewest = c; - tv = &c->creation_time; + if (tv == NULL || timercmp(&c->activity_time, tv, >)) { + cbest = c; + tv = &c->activity_time; } } - return (cnewest); + return (cbest); } /* Find the target client or report an error and return NULL. */ diff --git a/server-client.c b/server-client.c index a337c6b2..3ff16e25 100644 --- a/server-client.c +++ b/server-client.c @@ -63,6 +63,7 @@ server_client_create(int fd) if (gettimeofday(&c->creation_time, NULL) != 0) fatal("gettimeofday failed"); + memcpy(&c->activity_time, &c->creation_time, sizeof c->activity_time); ARRAY_INIT(&c->prompt_hdata); @@ -287,6 +288,7 @@ server_client_handle_data(struct client *c) oo = &c->session->options; /* Update activity timer. */ + memcpy(&c->activity_time, &tv_now, sizeof c->activity_time); memcpy(&c->session->activity_time, &tv_now, sizeof c->session->activity_time); @@ -583,9 +585,13 @@ server_client_msg_dispatch(struct client *c) break; c->flags &= ~CLIENT_SUSPENDED; - if (c->session != NULL && - gettimeofday(&c->session->activity_time, NULL) != 0) - fatal("gettimeofday failed"); + if (gettimeofday(&c->activity_time, NULL) != 0) + fatal("gettimeofday"); + if (c->session != NULL) { + memcpy(&c->session->activity_time, + &c->activity_time, + sizeof c->session->activity_time); + } tty_start_tty(&c->tty); server_redraw_client(c); diff --git a/tmux.1 b/tmux.1 index 0014e6a0..bd346529 100644 --- a/tmux.1 +++ b/tmux.1 @@ -282,7 +282,7 @@ pattern. If a single match is found, it is used as the target session; multiple matches produce an error. If a session is omitted, the current session is used if available; if no -current session is available, the most recently created is chosen. +current session is available, the most recently used is chosen. .Pp .Ar target-window specifies a window in the form diff --git a/tmux.h b/tmux.h index bdbdf405..15bc04dc 100644 --- a/tmux.h +++ b/tmux.h @@ -1064,6 +1064,7 @@ struct client { struct imsgbuf ibuf; struct timeval creation_time; + struct timeval activity_time; struct environ environ; From d8332e637354a55ba4caa46f5030fc5d7e5898db Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 4 Nov 2009 08:35:11 +0000 Subject: [PATCH 0486/1180] Don't backoff based on suspended or deda clients as they are always likely to have data backed up. --- server-window.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/server-window.c b/server-window.c index 122ca092..3a74ead8 100644 --- a/server-window.c +++ b/server-window.c @@ -78,6 +78,8 @@ server_window_backoff(struct window_pane *wp) c = ARRAY_ITEM(&clients, i); if (c == NULL || c->session == NULL) continue; + if ((c->flags & (CLIENT_SUSPENDED|CLIENT_DEAD)) != 0) + continue; if (c->session->curw->window != wp->window) continue; if (BUFFER_USED(c->tty.out) > BACKOFF_THRESHOLD) From d2dfbef05a2162b7b48c6ed82459c9d998f643db Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 4 Nov 2009 12:41:43 +0000 Subject: [PATCH 0487/1180] Change declaration and use of malloc_options to be more standard, from Tim van der Molen. --- tmux.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tmux.c b/tmux.c index 51f8dbef..ba634c6a 100644 --- a/tmux.c +++ b/tmux.c @@ -31,7 +31,7 @@ #include "tmux.h" #ifdef DEBUG -const char *malloc_options = "AFGJPX"; +extern char *malloc_options; #endif volatile sig_atomic_t sigwinch; @@ -299,6 +299,10 @@ main(int argc, char **argv) size_t len; int nfds, retcode, opt, flags, cmdflags = 0; +#ifdef DEBUG + malloc_options = (char *) "AFGJPX"; +#endif + flags = 0; shellcmd = label = path = NULL; login_shell = (**argv == '-'); From a94535f318dc0c712327f5c7b3e96a62201ebcab Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 4 Nov 2009 13:34:26 +0000 Subject: [PATCH 0488/1180] Fix the reverse emulation when a terminal doesn't have setab to use the correct fg/bg (adjusted if spaces) and happen before attribute setting. --- tty.c | 42 ++++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/tty.c b/tty.c index 1010217d..1a6315e7 100644 --- a/tty.c +++ b/tty.c @@ -1121,7 +1121,7 @@ tty_attributes(struct tty *tty, const struct grid_cell *gc) { struct grid_cell *tc = &tty->cell, gc2; u_char changed; - u_int fg = gc->fg, bg = gc->bg, attr = gc->attr; + u_int new_attr; /* If the character is space, don't care about foreground. */ if (gc->data == ' ' && !(gc->flags & GRID_FLAG_UTF8)) { @@ -1137,34 +1137,40 @@ tty_attributes(struct tty *tty, const struct grid_cell *gc) gc = &gc2; } - /* If any bits are being cleared, reset everything. */ - if (tc->attr & ~attr) - tty_reset(tty); - - /* - * Set the colours. This may call tty_reset() (so it comes next) and - * may add to the desired attributes in attr. - */ - tty_colours(tty, gc, &attr); - /* * If no setab, try to use the reverse attribute as a best-effort for a * non-default background. This is a bit of a hack but it doesn't do * any serious harm and makes a couple of applications happier. */ if (!tty_term_has(tty->term, TTYC_SETAB)) { - if (attr & GRID_ATTR_REVERSE) { - if (fg != 7 && fg != 8) - attr &= ~GRID_ATTR_REVERSE; + if (gc != &gc2) { + memcpy(&gc2, gc, sizeof gc2); + gc = &gc2; + } + + if (gc->attr & GRID_ATTR_REVERSE) { + if (gc->fg != 7 && gc->fg != 8) + gc2.attr &= ~GRID_ATTR_REVERSE; } else { - if (bg != 0 && bg != 8) - attr |= GRID_ATTR_REVERSE; + if (gc->bg != 0 && gc->bg != 8) + gc2.attr |= GRID_ATTR_REVERSE; } } + /* If any bits are being cleared, reset everything. */ + if (tc->attr & ~gc->attr) + tty_reset(tty); + + /* + * Set the colours. This may call tty_reset() (so it comes next) and + * may add to (NOT remove) the desired attributes by changing new_attr. + */ + new_attr = gc->attr; + tty_colours(tty, gc, &new_attr); + /* Filter out attribute bits already set. */ - changed = attr & ~tc->attr; - tc->attr = attr; + changed = new_attr & ~tc->attr; + tc->attr = new_attr; /* Set the attributes. */ if (changed & GRID_ATTR_BRIGHT) From 10f58cb1bc0ec010cc692f504d52adcb6312b8fb Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 4 Nov 2009 15:59:27 +0000 Subject: [PATCH 0489/1180] Ignore the colour on space, /not/ the attributes. --- tty.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tty.c b/tty.c index 1a6315e7..0782e42d 100644 --- a/tty.c +++ b/tty.c @@ -1126,14 +1126,10 @@ tty_attributes(struct tty *tty, const struct grid_cell *gc) /* If the character is space, don't care about foreground. */ if (gc->data == ' ' && !(gc->flags & GRID_FLAG_UTF8)) { memcpy(&gc2, gc, sizeof gc2); - if (gc->attr & GRID_ATTR_REVERSE) gc2.bg = tc->bg; else gc2.fg = tc->fg; - gc2.attr = tc->attr & ~GRID_ATTR_REVERSE; - gc2.attr |= gc->attr & GRID_ATTR_REVERSE; - gc = &gc2; } From f575e39b0a367ae9b8a7cf54ceead865b8885eed Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 4 Nov 2009 20:35:19 +0000 Subject: [PATCH 0490/1180] Unused (but assigned to) variable, found by lint. --- status.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/status.c b/status.c index 643c30c6..21ca31a2 100644 --- a/status.c +++ b/status.c @@ -440,7 +440,7 @@ char * status_job(struct client *c, char **iptr) { struct job *job; - char *buf, *cmd; + char *cmd; int lastesc; size_t len; @@ -451,8 +451,6 @@ status_job(struct client *c, char **iptr) return (NULL); } - buf = NULL; - cmd = xmalloc(strlen(*iptr) + 1); len = 0; From abf3a5d50ec4003f58f460cc9ab3c00671c920f8 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 4 Nov 2009 20:50:11 +0000 Subject: [PATCH 0491/1180] Initial changes to move tmux to libevent. This moves the client-side loops are pretty much fully over to event-based only (tmux.c and client.c) but server-side (server.c and friends) treats libevent as a sort of clever poll, waking up after every event to run various things. Moving the server stuff over to bufferevents and timers and so on will come later. --- Makefile | 2 +- buffer-poll.c | 10 +- client.c | 214 ++++++++++------- cmd-kill-server.c | 2 +- cmd-pipe-pane.c | 2 +- job.c | 4 +- server-client.c | 36 +-- server-job.c | 10 +- server-window.c | 17 +- server.c | 601 +++++++++++++++++++++------------------------- tmux.c | 303 +++++++++++------------ tmux.h | 28 +-- window.c | 4 +- 13 files changed, 601 insertions(+), 632 deletions(-) diff --git a/Makefile b/Makefile index 68a34050..04102479 100644 --- a/Makefile +++ b/Makefile @@ -45,7 +45,7 @@ CDIAGFLAGS+= -Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations CDIAGFLAGS+= -Wwrite-strings -Wshadow -Wpointer-arith -Wsign-compare CDIAGFLAGS+= -Wundef -Wbad-function-cast -Winline -Wcast-align -LDADD= -lutil -lcurses +LDADD= -lutil -lcurses -levent DPADD= ${LIBUTIL} .include diff --git a/buffer-poll.c b/buffer-poll.c index cf70c04c..d95510c1 100644 --- a/buffer-poll.c +++ b/buffer-poll.c @@ -19,6 +19,7 @@ #include #include +#include #include #include "tmux.h" @@ -29,9 +30,7 @@ buffer_poll(int fd, int events, struct buffer *in, struct buffer *out) { ssize_t n; - if (events & (POLLERR|POLLNVAL)) - return (-1); - if (in != NULL && events & POLLIN) { + if (in != NULL && events & EV_READ) { buffer_ensure(in, BUFSIZ); n = read(fd, BUFFER_IN(in), BUFFER_FREE(in)); if (n == 0) @@ -41,9 +40,8 @@ buffer_poll(int fd, int events, struct buffer *in, struct buffer *out) return (-1); } else buffer_add(in, n); - } else if (events & POLLHUP) - return (-1); - if (out != NULL && BUFFER_USED(out) > 0 && events & POLLOUT) { + } + if (out != NULL && BUFFER_USED(out) > 0 && events & EV_WRITE) { n = write(fd, BUFFER_OUT(out), BUFFER_USED(out)); if (n == -1) { if (errno != EINTR && errno != EAGAIN) diff --git a/client.c b/client.c index 4d5fd696..60fef91a 100644 --- a/client.c +++ b/client.c @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -34,13 +35,15 @@ #include "tmux.h" struct imsgbuf client_ibuf; +struct event client_event; const char *client_exitmsg; -void client_send_identify(int); -void client_send_environ(void); -void client_write_server(enum msgtype, void *, size_t); -int client_dispatch(void); -void client_suspend(void); +void client_send_identify(int); +void client_send_environ(void); +void client_write_server(enum msgtype, void *, size_t); +void client_signal(int, short, void *); +void client_callback(int, short, void *); +int client_dispatch(void); struct imsgbuf * client_init(char *path, int cmdflags, int flags) @@ -154,76 +157,54 @@ client_write_server(enum msgtype type, void *buf, size_t len) __dead void client_main(void) { - struct pollfd pfd; - int n, nfds; - - siginit(); + struct event ev_sigcont, ev_sigterm, ev_sigwinch; + struct sigaction sigact; + short events; logfile("client"); + /* Note: event_init() has already been called. */ + + /* Set up signals. */ + memset(&sigact, 0, sizeof sigact); + sigemptyset(&sigact.sa_mask); + sigact.sa_flags = SA_RESTART; + sigact.sa_handler = SIG_IGN; + if (sigaction(SIGINT, &sigact, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGPIPE, &sigact, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGUSR1, &sigact, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGUSR2, &sigact, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGTSTP, &sigact, NULL) != 0) + fatal("sigaction failed"); + + signal_set(&ev_sigcont, SIGCONT, client_signal, NULL); + signal_add(&ev_sigcont, NULL); + signal_set(&ev_sigterm, SIGTERM, client_signal, NULL); + signal_add(&ev_sigterm, NULL); + signal_set(&ev_sigwinch, SIGWINCH, client_signal, NULL); + signal_add(&ev_sigwinch, NULL); + /* * imsg_read in the first client poll loop (before the terminal has - * been initialiased) may have read messages into the buffer after the - * MSG_READY switched to here. Process anything outstanding now so poll - * doesn't hang waiting for messages that have already arrived. + * been initialised) may have read messages into the buffer after the + * MSG_READY switched to here. Process anything outstanding now to + * avoid hanging waiting for messages that have already arrived. */ if (client_dispatch() != 0) goto out; - for (;;) { - if (sigterm) { - client_exitmsg = "terminated"; - client_write_server(MSG_EXITING, NULL, 0); - } - if (sigchld) { - sigchld = 0; - waitpid(WAIT_ANY, NULL, WNOHANG); - continue; - } - if (sigwinch) { - sigwinch = 0; - client_write_server(MSG_RESIZE, NULL, 0); - continue; - } - if (sigcont) { - sigcont = 0; - siginit(); - client_write_server(MSG_WAKEUP, NULL, 0); - continue; - } - - pfd.fd = client_ibuf.fd; - pfd.events = POLLIN; - if (client_ibuf.w.queued > 0) - pfd.events |= POLLOUT; - - if ((nfds = poll(&pfd, 1, INFTIM)) == -1) { - if (errno == EAGAIN || errno == EINTR) - continue; - fatal("poll failed"); - } - if (nfds == 0) - continue; - - if (pfd.revents & (POLLERR|POLLHUP|POLLNVAL)) - fatalx("socket error"); - - if (pfd.revents & POLLIN) { - if ((n = imsg_read(&client_ibuf)) == -1 || n == 0) { - client_exitmsg = "lost server"; - break; - } - if (client_dispatch() != 0) - break; - } - - if (pfd.revents & POLLOUT) { - if (msgbuf_write(&client_ibuf.w) < 0) { - client_exitmsg = "lost server"; - break; - } - } - } + /* Set up the client-server socket event. */ + events = EV_READ; + if (client_ibuf.w.queued > 0) + events |= EV_WRITE; + event_set(&client_event, client_ibuf.fd, events, client_callback, NULL); + event_add(&client_event, NULL); + + event_dispatch(); out: /* Print the exit message, if any, and exit. */ @@ -235,12 +216,78 @@ out: exit(0); } +void +client_signal(int sig, short events, unused void *data) +{ + struct sigaction sigact; + + switch (sig) { + case SIGTERM: + client_exitmsg = "terminated"; + client_write_server(MSG_EXITING, NULL, 0); + break; + case SIGWINCH: + client_write_server(MSG_RESIZE, NULL, 0); + break; + case SIGCONT: + memset(&sigact, 0, sizeof sigact); + sigemptyset(&sigact.sa_mask); + sigact.sa_flags = SA_RESTART; + sigact.sa_handler = SIG_IGN; + if (sigaction(SIGTSTP, &sigact, NULL) != 0) + fatal("sigaction failed"); + client_write_server(MSG_WAKEUP, NULL, 0); + break; + } + + event_del(&client_event); + events = EV_READ; + if (client_ibuf.w.queued > 0) + events |= EV_WRITE; + event_set(&client_event, client_ibuf.fd, events, client_callback, NULL); + event_add(&client_event, NULL); +} + +void +client_callback(unused int fd, short events, unused void *data) +{ + int n; + + if (events & EV_READ) { + if ((n = imsg_read(&client_ibuf)) == -1 || n == 0) + goto lost_server; + if (client_dispatch() != 0) { + event_loopexit(NULL); + return; + } + } + + if (events & EV_WRITE) { + if (msgbuf_write(&client_ibuf.w) < 0) + goto lost_server; + } + + event_del(&client_event); + events = EV_READ; + if (client_ibuf.w.queued > 0) + events |= EV_WRITE; + event_set(&client_event, client_ibuf.fd, events, client_callback, NULL); + event_add(&client_event, NULL); + + return; + +lost_server: + client_exitmsg = "lost server"; + event_loopexit(NULL); +} + int client_dispatch(void) { - struct imsg imsg; - struct msg_lock_data lockdata; - ssize_t n, datalen; + struct imsg imsg; + struct msg_lock_data lockdata; + struct sigaction sigact; + ssize_t n, datalen; for (;;) { if ((n = imsg_get(&client_ibuf, &imsg)) == -1) @@ -249,6 +296,7 @@ client_dispatch(void) return (0); datalen = imsg.hdr.len - IMSG_HEADER_SIZE; + log_debug("client got %d", imsg.hdr.type); switch (imsg.hdr.type) { case MSG_DETACH: if (datalen != 0) @@ -281,7 +329,13 @@ client_dispatch(void) if (datalen != 0) fatalx("bad MSG_SUSPEND size"); - client_suspend(); + memset(&sigact, 0, sizeof sigact); + sigemptyset(&sigact.sa_mask); + sigact.sa_flags = SA_RESTART; + sigact.sa_handler = SIG_DFL; + if (sigaction(SIGTSTP, &sigact, NULL) != 0) + fatal("sigaction failed"); + kill(getpid(), SIGTSTP); break; case MSG_LOCK: if (datalen != sizeof lockdata) @@ -299,23 +353,3 @@ client_dispatch(void) imsg_free(&imsg); } } - -void -client_suspend(void) -{ - struct sigaction act; - - memset(&act, 0, sizeof act); - sigemptyset(&act.sa_mask); - act.sa_flags = SA_RESTART; - - act.sa_handler = SIG_DFL; - if (sigaction(SIGTSTP, &act, NULL) != 0) - fatal("sigaction failed"); - - act.sa_handler = sighandler; - if (sigaction(SIGCONT, &act, NULL) != 0) - fatal("sigaction failed"); - - kill(getpid(), SIGTSTP); -} diff --git a/cmd-kill-server.c b/cmd-kill-server.c index 56aa47cf..d7033a06 100644 --- a/cmd-kill-server.c +++ b/cmd-kill-server.c @@ -43,7 +43,7 @@ const struct cmd_entry cmd_kill_server_entry = { int cmd_kill_server_exec(unused struct cmd *self, unused struct cmd_ctx *ctx) { - sigterm = 1; + kill(getpid(), SIGTERM); return (0); } diff --git a/cmd-pipe-pane.c b/cmd-pipe-pane.c index 4fa43184..10cd3323 100644 --- a/cmd-pipe-pane.c +++ b/cmd-pipe-pane.c @@ -88,7 +88,7 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx) case 0: /* Child process. */ close(pipe_fd[0]); - sigreset(); + server_signal_clear(); if (dup2(pipe_fd[1], STDIN_FILENO) == -1) _exit(1); diff --git a/job.c b/job.c index a638e3d8..fd91913f 100644 --- a/job.c +++ b/job.c @@ -87,6 +87,7 @@ job_add(struct jobs *jobs, int flags, struct client *c, const char *cmd, job->fd = -1; job->out = buffer_create(BUFSIZ); + memset(&job->event, 0, sizeof job->event); job->callbackfn = callbackfn; job->freefn = freefn; @@ -126,6 +127,7 @@ job_free(struct job *job) close(job->fd); if (job->out != NULL) buffer_destroy(job->out); + event_del(&job->event); xfree(job); } @@ -147,7 +149,7 @@ job_run(struct job *job) case -1: return (-1); case 0: /* child */ - sigreset(); + server_signal_clear(); /* XXX environ? */ if (dup2(out[1], STDOUT_FILENO) == -1) diff --git a/server-client.c b/server-client.c index 3ff16e25..64909d87 100644 --- a/server-client.c +++ b/server-client.c @@ -18,6 +18,7 @@ #include +#include #include #include #include @@ -134,7 +135,9 @@ server_client_lost(struct client *c) close(c->ibuf.fd); imsg_clear(&c->ibuf); - + event_del(&c->event); + event_del(&c->tty.event); + for (i = 0; i < ARRAY_LENGTH(&dead_clients); i++) { if (ARRAY_ITEM(&dead_clients, i) == NULL) { ARRAY_SET(&dead_clients, i, c); @@ -162,25 +165,31 @@ server_client_prepare(void) events = 0; if (!(c->flags & CLIENT_BAD)) - events |= POLLIN; + events |= EV_READ; if (c->ibuf.w.queued > 0) - events |= POLLOUT; - server_poll_add(c->ibuf.fd, events, server_client_callback, c); + events |= EV_WRITE; + event_del(&c->event); + event_set(&c->event, + c->ibuf.fd, events, server_client_callback, c); + event_add(&c->event, NULL); if (c->tty.fd == -1) continue; if (c->flags & CLIENT_SUSPENDED || c->session == NULL) continue; - events = POLLIN; + events = EV_READ; if (BUFFER_USED(c->tty.out) > 0) - events |= POLLOUT; - server_poll_add(c->tty.fd, events, server_client_callback, c); + events |= EV_WRITE; + event_del(&c->tty.event); + event_set(&c->tty.event, + c->tty.fd, events, server_client_callback, c); + event_add(&c->tty.event, NULL); } } /* Process a single client event. */ void -server_client_callback(int fd, int events, void *data) +server_client_callback(int fd, short events, void *data) { struct client *c = data; @@ -188,10 +197,7 @@ server_client_callback(int fd, int events, void *data) return; if (fd == c->ibuf.fd) { - if (events & (POLLERR|POLLNVAL|POLLHUP)) - goto client_lost; - - if (events & POLLOUT && msgbuf_write(&c->ibuf.w) < 0) + if (events & EV_WRITE && msgbuf_write(&c->ibuf.w) < 0) goto client_lost; if (c->flags & CLIENT_BAD) { @@ -200,7 +206,7 @@ server_client_callback(int fd, int events, void *data) return; } - if (events & POLLIN && server_client_msg_dispatch(c) != 0) + if (events & EV_READ && server_client_msg_dispatch(c) != 0) goto client_lost; } @@ -211,7 +217,7 @@ server_client_callback(int fd, int events, void *data) if (buffer_poll(fd, events, c->tty.in, c->tty.out) != 0) goto client_lost; } - + return; client_lost: @@ -424,7 +430,7 @@ server_client_check_redraw(struct client *c) if (c->flags & (CLIENT_REDRAW|CLIENT_STATUS)) { if (options_get_number(&s->options, "set-titles")) server_client_set_title(c); - + if (c->message_string != NULL) redraw = status_message_redraw(c); else if (c->prompt_string != NULL) diff --git a/server-job.c b/server-job.c index 6ff15860..5d83ff92 100644 --- a/server-job.c +++ b/server-job.c @@ -18,6 +18,7 @@ #include +#include #include #include "tmux.h" @@ -31,13 +32,16 @@ server_job_prepare(void) SLIST_FOREACH(job, &all_jobs, lentry) { if (job->fd == -1) continue; - server_poll_add(job->fd, POLLIN, server_job_callback, job); + event_del(&job->event); + event_set( + &job->event, job->fd, EV_READ, server_job_callback, job); + event_add(&job->event, NULL); } } /* Process a single job event. */ void -server_job_callback(int fd, int events, void *data) +server_job_callback(int fd, short events, void *data) { struct job *job = data; @@ -55,7 +59,7 @@ void server_job_loop(void) { struct job *job; - + restart: SLIST_FOREACH(job, &all_jobs, lentry) { if (job->flags & JOB_DONE || job->fd != -1 || job->pid != -1) diff --git a/server-window.c b/server-window.c index 3a74ead8..a6f2bba5 100644 --- a/server-window.c +++ b/server-window.c @@ -18,6 +18,7 @@ #include +#include #include #include "tmux.h" @@ -47,19 +48,23 @@ server_window_prepare(void) continue; events = 0; if (!server_window_backoff(wp)) - events |= POLLIN; + events = EV_READ; if (BUFFER_USED(wp->out) > 0) - events |= POLLOUT; - server_poll_add( + events |= EV_WRITE; + event_del(&wp->event); + event_set(&wp->event, wp->fd, events, server_window_callback, wp); + event_add(&wp->event, NULL); if (wp->pipe_fd == -1) continue; events = 0; if (BUFFER_USED(wp->pipe_buf) > 0) - events |= POLLOUT; - server_poll_add( + events |= EV_WRITE; + event_del(&wp->pipe_event); + event_set(&wp->pipe_event, wp->pipe_fd, events, server_window_callback, wp); + event_add(&wp->pipe_event, NULL); } } } @@ -90,7 +95,7 @@ server_window_backoff(struct window_pane *wp) /* Process a single window pane event. */ void -server_window_callback(int fd, int events, void *data) +server_window_callback(int fd, short events, void *data) { struct window_pane *wp = data; diff --git a/server.c b/server.c index 1113d4dc..236cd201 100644 --- a/server.c +++ b/server.c @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -45,112 +46,28 @@ struct clients clients; struct clients dead_clients; -/* Mapping of a pollfd to an fd independent of its position in the array. */ -struct poll_item { - int fd; - int events; - - void (*fn)(int, int, void *); - void *data; - - RB_ENTRY(poll_item) entry; -}; -RB_HEAD(poll_items, poll_item) poll_items; - -int server_poll_cmp(struct poll_item *, struct poll_item *); -struct poll_item*server_poll_lookup(int); -struct pollfd *server_poll_flatten(int *); -void server_poll_dispatch(struct pollfd *, int); -void server_poll_reset(void); -RB_PROTOTYPE(poll_items, poll_item, entry, server_poll_cmp); -RB_GENERATE(poll_items, poll_item, entry, server_poll_cmp); +int server_fd; +int server_shutdown; +struct event server_ev_accept; +struct event server_ev_sigterm; +struct event server_ev_sigusr1; +struct event server_ev_sigchld; +struct event server_ev_second; int server_create_socket(void); -void server_callback(int, int, void *); -int server_main(int); -void server_shutdown(void); +void server_loop(void); int server_should_shutdown(void); -void server_child_signal(void); +void server_send_shutdown(void); void server_clean_dead(void); -void server_second_timers(void); +int server_update_socket(void); +void server_accept_callback(int, short, void *); +void server_signal_callback(int, short, void *); +void server_child_signal(void); +void server_child_exited(pid_t, int); +void server_child_stopped(pid_t, int); +void server_second_callback(int, short, void *); void server_lock_server(void); void server_lock_sessions(void); -int server_update_socket(void); - -int -server_poll_cmp(struct poll_item *pitem1, struct poll_item *pitem2) -{ - return (pitem1->fd - pitem2->fd); -} - -void -server_poll_add(int fd, int events, void (*fn)(int, int, void *), void *data) -{ - struct poll_item *pitem; - - pitem = xmalloc(sizeof *pitem); - pitem->fd = fd; - pitem->events = events; - - pitem->fn = fn; - pitem->data = data; - - RB_INSERT(poll_items, &poll_items, pitem); -} - -struct poll_item * -server_poll_lookup(int fd) -{ - struct poll_item pitem; - - pitem.fd = fd; - return (RB_FIND(poll_items, &poll_items, &pitem)); -} - -struct pollfd * -server_poll_flatten(int *nfds) -{ - struct poll_item *pitem; - struct pollfd *pfds; - - pfds = NULL; - *nfds = 0; - RB_FOREACH(pitem, poll_items, &poll_items) { - pfds = xrealloc(pfds, (*nfds) + 1, sizeof *pfds); - pfds[*nfds].fd = pitem->fd; - pfds[*nfds].events = pitem->events; - (*nfds)++; - } - return (pfds); -} - -void -server_poll_dispatch(struct pollfd *pfds, int nfds) -{ - struct poll_item *pitem; - struct pollfd *pfd; - - while (nfds > 0) { - pfd = &pfds[--nfds]; - if (pfd->revents != 0) { - pitem = server_poll_lookup(pfd->fd); - pitem->fn(pitem->fd, pfd->revents, pitem->data); - } - } - xfree(pfds); -} - -void -server_poll_reset(void) -{ - struct poll_item *pitem; - - while (!RB_EMPTY(&poll_items)) { - pitem = RB_ROOT(&poll_items); - RB_REMOVE(poll_items, &poll_items, pitem); - xfree(pitem); - } -} /* Create server socket. */ int @@ -191,40 +108,14 @@ server_create_socket(void) return (fd); } -/* Callback for server socket. */ -void -server_callback(int fd, int events, unused void *data) -{ - struct sockaddr_storage sa; - socklen_t slen = sizeof sa; - int newfd; - - if (events & (POLLERR|POLLNVAL|POLLHUP)) - fatalx("lost server socket"); - if (!(events & POLLIN)) - return; - - newfd = accept(fd, (struct sockaddr *) &sa, &slen); - if (newfd == -1) { - if (errno == EAGAIN || errno == EINTR || errno == ECONNABORTED) - return; - fatal("accept failed"); - } - if (sigterm) { - close(newfd); - return; - } - server_client_create(newfd); -} - /* Fork new server. */ int server_start(char *path) { struct client *c; - int pair[2], srv_fd; - char *cause; - char rpathbuf[MAXPATHLEN]; + int pair[2]; + char *cause, rpathbuf[MAXPATHLEN]; + struct timeval tv; /* The first client is special and gets a socketpair; create it. */ if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) != 0) @@ -269,7 +160,7 @@ server_start(char *path) log_debug("socket path %s", socket_path); setproctitle("server (%s)", rpathbuf); - srv_fd = server_create_socket(); + server_fd = server_create_socket(); server_client_create(pair[1]); if (access(SYSTEM_CFG, R_OK) == 0) { @@ -282,7 +173,20 @@ server_start(char *path) if (cfg_file != NULL && load_cfg(cfg_file, NULL, &cause) != 0) goto error; - exit(server_main(srv_fd)); + event_init(); + + event_set(&server_ev_accept, + server_fd, EV_READ|EV_PERSIST, server_accept_callback, NULL); + event_add(&server_ev_accept, NULL); + + memset(&tv, 0, sizeof tv); + tv.tv_sec = 1; + evtimer_set(&server_ev_second, server_second_callback, NULL); + evtimer_add(&server_ev_second, &tv); + + server_signal_set(); + server_loop(); + exit(0); error: /* Write the error and shutdown the server. */ @@ -291,150 +195,39 @@ error: server_write_error(c, cause); xfree(cause); - sigterm = 1; - server_shutdown(); + server_shutdown = 1; - exit(server_main(srv_fd)); + server_signal_set(); + server_loop(); + exit(1); } /* Main server loop. */ -int -server_main(int srv_fd) +void +server_loop(void) { - struct pollfd *pfds; - int nfds, xtimeout; - u_int i; - time_t now, last; + struct timeval tv; - siginit(); - log_debug("server socket is %d", srv_fd); + memset(&tv, 0, sizeof tv); + tv.tv_usec = POLL_TIMEOUT * 1000; - last = time(NULL); + while (!server_should_shutdown()) { + server_update_socket(); - pfds = NULL; - for (;;) { - /* If sigterm, kill all windows and clients. */ - if (sigterm) - server_shutdown(); - - /* Stop if no sessions or clients left. */ - if (server_should_shutdown()) - break; - - /* Handle child exit. */ - if (sigchld) { - sigchld = 0; - server_child_signal(); - continue; - } - - /* Recreate socket on SIGUSR1. */ - if (sigusr1) { - sigusr1 = 0; - close(srv_fd); - srv_fd = server_create_socket(); - continue; - } - - /* Initialise pollfd array and add server socket. */ - server_poll_reset(); - server_poll_add(srv_fd, POLLIN, server_callback, NULL); - - /* Fill window and client sockets. */ server_job_prepare(); server_window_prepare(); server_client_prepare(); - - /* Update socket permissions. */ - xtimeout = INFTIM; - if (server_update_socket() != 0) - xtimeout = POLL_TIMEOUT; - /* Do the poll. */ - pfds = server_poll_flatten(&nfds); - if (poll(pfds, nfds, xtimeout) == -1) { - if (errno == EAGAIN || errno == EINTR) - continue; - fatal("poll failed"); - } - server_poll_dispatch(pfds, nfds); + event_loopexit(&tv); + event_loop(EVLOOP_ONCE); - /* Call second-based timers. */ - now = time(NULL); - if (now != last) { - last = now; - server_second_timers(); - } - - /* Run once-per-loop events. */ server_job_loop(); server_window_loop(); server_client_loop(); - /* Collect any unset key bindings. */ key_bindings_clean(); - - /* Collect dead clients and sessions. */ server_clean_dead(); - } - server_poll_reset(); - - for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { - if (ARRAY_ITEM(&sessions, i) != NULL) - session_destroy(ARRAY_ITEM(&sessions, i)); - } - ARRAY_FREE(&sessions); - - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - if (ARRAY_ITEM(&clients, i) != NULL) - server_client_lost(ARRAY_ITEM(&clients, i)); - } - ARRAY_FREE(&clients); - - mode_key_free_trees(); - key_bindings_free(); - - close(srv_fd); - - unlink(socket_path); - xfree(socket_path); - - options_free(&global_s_options); - options_free(&global_w_options); - - return (0); -} - -/* Kill all clients. */ -void -server_shutdown(void) -{ - struct session *s; - struct client *c; - u_int i, j; - - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - c = ARRAY_ITEM(&clients, i); - if (c != NULL) { - if (c->flags & (CLIENT_BAD|CLIENT_SUSPENDED)) - server_client_lost(c); - else - server_write_client(c, MSG_SHUTDOWN, NULL, 0); - } - } - - for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { - s = ARRAY_ITEM(&sessions, i); - for (j = 0; j < ARRAY_LENGTH(&clients); j++) { - c = ARRAY_ITEM(&clients, j); - if (c != NULL && c->session == s) { - s = NULL; - break; - } - } - if (s != NULL) - session_destroy(s); - } + } } /* Check if the server should be shutting down (no more clients or windows). */ @@ -454,49 +247,28 @@ server_should_shutdown(void) return (1); } -/* Handle SIGCHLD. */ +/* Shutdown the server by killing all clients and windows. */ void -server_child_signal(void) +server_send_shutdown(void) { - struct window *w; - struct window_pane *wp; - struct job *job; - int status; - pid_t pid; - u_int i; + struct client *c; + struct session *s; + u_int i; - for (;;) { - switch (pid = waitpid(WAIT_ANY, &status, WNOHANG|WUNTRACED)) { - case -1: - if (errno == ECHILD) - return; - fatal("waitpid failed"); - case 0: - return; + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c != NULL) { + if (c->flags & (CLIENT_BAD|CLIENT_SUSPENDED)) + server_client_lost(c); + else + server_write_client(c, MSG_SHUTDOWN, NULL, 0); + c->session = NULL; } - if (!WIFSTOPPED(status)) { - SLIST_FOREACH(job, &all_jobs, lentry) { - if (pid == job->pid) { - job->pid = -1; - job->status = status; - } - } - continue; - } - if (WSTOPSIG(status) == SIGTTIN || WSTOPSIG(status) == SIGTTOU) - continue; + } - for (i = 0; i < ARRAY_LENGTH(&windows); i++) { - w = ARRAY_ITEM(&windows, i); - if (w == NULL) - continue; - TAILQ_FOREACH(wp, &w->panes, entry) { - if (wp->pid == pid) { - if (killpg(pid, SIGCONT) != 0) - kill(pid, SIGCONT); - } - } - } + for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { + if ((s = ARRAY_ITEM(&sessions, i)) != NULL) + session_destroy(s); } } @@ -525,12 +297,215 @@ server_clean_dead(void) } } -/* Call any once-per-second timers. */ +/* Update socket execute permissions based on whether sessions are attached. */ +int +server_update_socket(void) +{ + struct session *s; + u_int i; + static int last = -1; + int n; + + n = 0; + for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { + s = ARRAY_ITEM(&sessions, i); + if (s != NULL && !(s->flags & SESSION_UNATTACHED)) { + n++; + break; + } + } + + if (n != last) { + last = n; + if (n != 0) + chmod(socket_path, S_IRWXU); + else + chmod(socket_path, S_IRUSR|S_IWUSR); + } + + return (n); +} + +/* Callback for server socket. */ void -server_second_timers(void) +server_accept_callback(int fd, short events, unused void *data) +{ + struct sockaddr_storage sa; + socklen_t slen = sizeof sa; + int newfd; + + if (!(events & EV_READ)) + return; + + newfd = accept(fd, (struct sockaddr *) &sa, &slen); + if (newfd == -1) { + if (errno == EAGAIN || errno == EINTR || errno == ECONNABORTED) + return; + fatal("accept failed"); + } + if (server_shutdown) { + close(newfd); + return; + } + server_client_create(newfd); + +} + +/* Set up server signal handling. */ +void +server_signal_set(void) +{ + struct sigaction sigact; + + memset(&sigact, 0, sizeof sigact); + sigemptyset(&sigact.sa_mask); + sigact.sa_flags = SA_RESTART; + sigact.sa_handler = SIG_IGN; + if (sigaction(SIGINT, &sigact, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGPIPE, &sigact, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGUSR2, &sigact, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGTSTP, &sigact, NULL) != 0) + fatal("sigaction failed"); + + signal_set(&server_ev_sigchld, SIGCHLD, server_signal_callback, NULL); + signal_add(&server_ev_sigchld, NULL); + signal_set(&server_ev_sigterm, SIGTERM, server_signal_callback, NULL); + signal_add(&server_ev_sigterm, NULL); + signal_set(&server_ev_sigusr1, SIGUSR1, server_signal_callback, NULL); + signal_add(&server_ev_sigusr1, NULL); +} + +/* Destroy server signal events. */ +void +server_signal_clear(void) +{ + struct sigaction sigact; + + memset(&sigact, 0, sizeof sigact); + sigemptyset(&sigact.sa_mask); + sigact.sa_flags = SA_RESTART; + sigact.sa_handler = SIG_DFL; + if (sigaction(SIGINT, &sigact, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGPIPE, &sigact, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGUSR2, &sigact, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGTSTP, &sigact, NULL) != 0) + fatal("sigaction failed"); + + signal_del(&server_ev_sigchld); + signal_del(&server_ev_sigterm); + signal_del(&server_ev_sigusr1); +} + +/* Signal handler. */ +void +server_signal_callback(int sig, unused short events, unused void *data) +{ + switch (sig) { + case SIGTERM: + server_shutdown = 1; + server_send_shutdown(); + break; + case SIGCHLD: + server_child_signal(); + break; + case SIGUSR1: + event_del(&server_ev_accept); + close(server_fd); + server_fd = server_create_socket(); + event_set(&server_ev_accept, server_fd, + EV_READ|EV_PERSIST, server_accept_callback, NULL); + event_add(&server_ev_accept, NULL); + break; + } +} + +/* Handle SIGCHLD. */ +void +server_child_signal(void) +{ + int status; + pid_t pid; + + for (;;) { + switch (pid = waitpid(WAIT_ANY, &status, WNOHANG|WUNTRACED)) { + case -1: + if (errno == ECHILD) + return; + fatal("waitpid failed"); + case 0: + return; + } + if (WIFSTOPPED(status)) + server_child_stopped(pid, status); + else if (WIFEXITED(status)) + server_child_exited(pid, status); + } +} + +/* Handle exited children. */ +void +server_child_exited(pid_t pid, int status) { struct window *w; struct window_pane *wp; + struct job *job; + u_int i; + + for (i = 0; i < ARRAY_LENGTH(&windows); i++) { + if ((w = ARRAY_ITEM(&windows, i)) == NULL) + continue; + TAILQ_FOREACH(wp, &w->panes, entry) { + if (wp->pid == pid) { + close(wp->fd); + wp->fd = -1; + } + } + } + + SLIST_FOREACH(job, &all_jobs, lentry) { + if (pid == job->pid) { + job->pid = -1; + job->status = status; + } + } +} + +/* Handle stopped children. */ +void +server_child_stopped(pid_t pid, int status) +{ + struct window *w; + struct window_pane *wp; + u_int i; + + if (WSTOPSIG(status) == SIGTTIN || WSTOPSIG(status) == SIGTTOU) + return; + + for (i = 0; i < ARRAY_LENGTH(&windows); i++) { + if ((w = ARRAY_ITEM(&windows, i)) == NULL) + continue; + TAILQ_FOREACH(wp, &w->panes, entry) { + if (wp->pid == pid) { + if (killpg(pid, SIGCONT) != 0) + kill(pid, SIGCONT); + } + } + } +} + +/* Handle once-per-second timer events. */ +void +server_second_callback(unused int fd, unused short events, unused void *arg) +{ + struct window *w; + struct window_pane *wp; + struct timeval tv; u_int i; if (options_get_number(&global_s_options, "lock-server")) @@ -548,6 +523,11 @@ server_second_timers(void) wp->mode->timer(wp); } } + + evtimer_del(&server_ev_second); + memset(&tv, 0, sizeof tv); + tv.tv_sec = 1; + evtimer_add(&server_ev_second, &tv); } /* Lock the server if ALL sessions have hit the time limit. */ @@ -606,32 +586,3 @@ server_lock_sessions(void) } } } - -/* Update socket execute permissions based on whether sessions are attached. */ -int -server_update_socket(void) -{ - struct session *s; - u_int i; - static int last = -1; - int n; - - n = 0; - for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { - s = ARRAY_ITEM(&sessions, i); - if (s != NULL && !(s->flags & SESSION_UNATTACHED)) { - n++; - break; - } - } - - if (n != last) { - last = n; - if (n != 0) - chmod(socket_path, S_IRWXU); - else - chmod(socket_path, S_IRUSR|S_IWUSR); - } - - return (n); -} diff --git a/tmux.c b/tmux.c index ba634c6a..fd7d1bfc 100644 --- a/tmux.c +++ b/tmux.c @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -34,13 +35,6 @@ extern char *malloc_options; #endif -volatile sig_atomic_t sigwinch; -volatile sig_atomic_t sigterm; -volatile sig_atomic_t sigcont; -volatile sig_atomic_t sigchld; -volatile sig_atomic_t sigusr1; -volatile sig_atomic_t sigusr2; - char *cfg_file; struct options global_s_options; /* session options */ struct options global_w_options; /* window options */ @@ -55,9 +49,18 @@ int login_shell; __dead void usage(void); void fill_session(struct msg_command_data *); char *makesockpath(const char *); -int dispatch_imsg(struct imsgbuf *, const char *, int *); __dead void shell_exec(const char *, const char *); +struct imsgbuf *main_ibuf; +struct event main_ev_sigterm; +int main_exitval; + +void main_set_signals(void); +void main_clear_signals(void); +void main_signal(int, short, unused void *); +void main_callback(int, short, void *); +void main_dispatch(const char *); + __dead void usage(void) { @@ -81,96 +84,6 @@ logfile(const char *name) } } -void -sighandler(int sig) -{ - int saved_errno; - - saved_errno = errno; - switch (sig) { - case SIGWINCH: - sigwinch = 1; - break; - case SIGTERM: - sigterm = 1; - break; - case SIGCHLD: - sigchld = 1; - break; - case SIGCONT: - sigcont = 1; - break; - case SIGUSR1: - sigusr1 = 1; - break; - case SIGUSR2: - sigusr2 = 1; - break; - } - errno = saved_errno; -} - -void -siginit(void) -{ - struct sigaction act; - - memset(&act, 0, sizeof act); - sigemptyset(&act.sa_mask); - act.sa_flags = SA_RESTART; - - act.sa_handler = SIG_IGN; - if (sigaction(SIGPIPE, &act, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGINT, &act, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGTSTP, &act, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGQUIT, &act, NULL) != 0) - fatal("sigaction failed"); - - act.sa_handler = sighandler; - if (sigaction(SIGWINCH, &act, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGTERM, &act, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGCHLD, &act, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGUSR1, &act, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGUSR2, &act, NULL) != 0) - fatal("sigaction failed"); -} - -void -sigreset(void) -{ - struct sigaction act; - - memset(&act, 0, sizeof act); - sigemptyset(&act.sa_mask); - - act.sa_handler = SIG_DFL; - if (sigaction(SIGPIPE, &act, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGUSR1, &act, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGUSR2, &act, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGINT, &act, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGTSTP, &act, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGQUIT, &act, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGWINCH, &act, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGTERM, &act, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGCHLD, &act, NULL) != 0) - fatal("sigaction failed"); -} - const char * getshell(void) { @@ -281,23 +194,43 @@ makesockpath(const char *label) return (path); } +__dead void +shell_exec(const char *shell, const char *shellcmd) +{ + const char *shellname, *ptr; + char *argv0; + + ptr = strrchr(shell, '/'); + if (ptr != NULL && *(ptr + 1) != '\0') + shellname = ptr + 1; + else + shellname = shell; + if (login_shell) + xasprintf(&argv0, "-%s", shellname); + else + xasprintf(&argv0, "%s", shellname); + setenv("SHELL", shell, 1); + + execl(shell, argv0, "-c", shellcmd, (char *) NULL); + fatal("execl failed"); +} + int main(int argc, char **argv) { struct cmd_list *cmdlist; struct cmd *cmd; - struct pollfd pfd; enum msgtype msg; struct passwd *pw; struct options *so, *wo; struct keylist *keylist; - struct imsgbuf *ibuf; struct msg_command_data cmddata; char *s, *shellcmd, *path, *label, *home, *cause; char cwd[MAXPATHLEN], **var; void *buf; size_t len; - int nfds, retcode, opt, flags, cmdflags = 0; + int opt, flags, cmdflags = 0; + short events; #ifdef DEBUG malloc_options = (char *) "AFGJPX"; @@ -359,7 +292,6 @@ main(int argc, char **argv) usage(); log_open_tty(debug_level); - siginit(); if (!(flags & IDENTIFY_UTF8)) { /* @@ -549,63 +481,121 @@ main(int argc, char **argv) cmd_list_free(cmdlist); } - if ((ibuf = client_init(path, cmdflags, flags)) == NULL) + if ((main_ibuf = client_init(path, cmdflags, flags)) == NULL) exit(1); xfree(path); - imsg_compose(ibuf, msg, PROTOCOL_VERSION, -1, -1, buf, len); + event_init(); - retcode = 0; - for (;;) { - pfd.fd = ibuf->fd; - pfd.events = POLLIN; - if (ibuf->w.queued != 0) - pfd.events |= POLLOUT; + imsg_compose(main_ibuf, msg, PROTOCOL_VERSION, -1, -1, buf, len); - if ((nfds = poll(&pfd, 1, INFTIM)) == -1) { - if (errno == EAGAIN || errno == EINTR) - continue; - fatal("poll failed"); - } - if (nfds == 0) - continue; + main_set_signals(); - if (pfd.revents & (POLLERR|POLLHUP|POLLNVAL)) - fatalx("socket error"); + events = EV_READ; + if (main_ibuf->w.queued > 0) + events |= EV_WRITE; + event_once(main_ibuf->fd, events, main_callback, shellcmd, NULL); - if (pfd.revents & POLLIN) { - if (dispatch_imsg(ibuf, shellcmd, &retcode) != 0) - break; - } + main_exitval = 0; + event_dispatch(); - if (pfd.revents & POLLOUT) { - if (msgbuf_write(&ibuf->w) < 0) - fatalx("msgbuf_write failed"); - } - } + main_clear_signals(); - options_free(&global_s_options); - options_free(&global_w_options); - - return (retcode); + client_main(); /* doesn't return */ } -int -dispatch_imsg(struct imsgbuf *ibuf, const char *shellcmd, int *retcode) + +void +main_set_signals(void) +{ + struct sigaction sigact; + + memset(&sigact, 0, sizeof sigact); + sigemptyset(&sigact.sa_mask); + sigact.sa_flags = SA_RESTART; + sigact.sa_handler = SIG_IGN; + if (sigaction(SIGINT, &sigact, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGPIPE, &sigact, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGUSR1, &sigact, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGUSR2, &sigact, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGTSTP, &sigact, NULL) != 0) + fatal("sigaction failed"); + + signal_set(&main_ev_sigterm, SIGTERM, main_signal, NULL); + signal_add(&main_ev_sigterm, NULL); +} + +void +main_clear_signals(void) +{ + struct sigaction sigact; + + memset(&sigact, 0, sizeof sigact); + sigemptyset(&sigact.sa_mask); + sigact.sa_flags = SA_RESTART; + sigact.sa_handler = SIG_DFL; + if (sigaction(SIGINT, &sigact, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGPIPE, &sigact, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGUSR1, &sigact, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGUSR2, &sigact, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGTSTP, &sigact, NULL) != 0) + fatal("sigaction failed"); + + event_del(&main_ev_sigterm); +} + +void +main_signal(int sig, unused short events, unused void *data) +{ + switch (sig) { + case SIGTERM: + exit(1); + } +} + +void +main_callback(unused int fd, short events, void *data) +{ + char *shellcmd = data; + + if (events & EV_READ) + main_dispatch(shellcmd); + + if (events & EV_WRITE) { + if (msgbuf_write(&main_ibuf->w) < 0) + fatalx("msgbuf_write failed"); + } + + events = EV_READ; + if (main_ibuf->w.queued > 0) + events |= EV_WRITE; + event_once(main_ibuf->fd, events, main_callback, shellcmd, NULL); +} + +void +main_dispatch(const char *shellcmd) { struct imsg imsg; ssize_t n, datalen; struct msg_print_data printdata; struct msg_shell_data shelldata; - if ((n = imsg_read(ibuf)) == -1 || n == 0) + if ((n = imsg_read(main_ibuf)) == -1 || n == 0) fatalx("imsg_read failed"); for (;;) { - if ((n = imsg_get(ibuf, &imsg)) == -1) + if ((n = imsg_get(main_ibuf, &imsg)) == -1) fatalx("imsg_get failed"); if (n == 0) - return (0); + return; datalen = imsg.hdr.len - IMSG_HEADER_SIZE; switch (imsg.hdr.type) { @@ -614,10 +604,8 @@ dispatch_imsg(struct imsgbuf *ibuf, const char *shellcmd, int *retcode) if (datalen != 0) fatalx("bad MSG_EXIT size"); - return (-1); + exit(main_exitval); case MSG_ERROR: - *retcode = 1; - /* FALLTHROUGH */ case MSG_PRINT: if (datalen != sizeof printdata) fatalx("bad MSG_PRINT size"); @@ -625,26 +613,30 @@ dispatch_imsg(struct imsgbuf *ibuf, const char *shellcmd, int *retcode) printdata.msg[(sizeof printdata.msg) - 1] = '\0'; log_info("%s", printdata.msg); + if (imsg.hdr.type == MSG_ERROR) + main_exitval = 1; break; case MSG_READY: if (datalen != 0) fatalx("bad MSG_READY size"); - client_main(); /* doesn't return */ + event_loopexit(NULL); /* move to client_main() */ + break; case MSG_VERSION: if (datalen != 0) fatalx("bad MSG_VERSION size"); log_warnx("protocol version mismatch (client %u, " "server %u)", PROTOCOL_VERSION, imsg.hdr.peerid); - *retcode = 1; - return (-1); + exit(1); case MSG_SHELL: if (datalen != sizeof shelldata) fatalx("bad MSG_SHELL size"); memcpy(&shelldata, imsg.data, sizeof shelldata); shelldata.shell[(sizeof shelldata.shell) - 1] = '\0'; - + + main_clear_signals(); + shell_exec(shelldata.shell, shellcmd); default: fatalx("unexpected message"); @@ -653,26 +645,3 @@ dispatch_imsg(struct imsgbuf *ibuf, const char *shellcmd, int *retcode) imsg_free(&imsg); } } - -__dead void -shell_exec(const char *shell, const char *shellcmd) -{ - const char *shellname, *ptr; - char *argv0; - - sigreset(); - - ptr = strrchr(shell, '/'); - if (ptr != NULL && *(ptr + 1) != '\0') - shellname = ptr + 1; - else - shellname = shell; - if (login_shell) - xasprintf(&argv0, "-%s", shellname); - else - xasprintf(&argv0, "%s", shellname); - setenv("SHELL", shell, 1); - - execl(shell, argv0, "-c", shellcmd, (char *) NULL); - fatal("execl failed"); -} diff --git a/tmux.h b/tmux.h index 15bc04dc..b72c0d8c 100644 --- a/tmux.h +++ b/tmux.h @@ -28,9 +28,9 @@ #include #include +#include #include #include -#include #include #include #include @@ -661,6 +661,7 @@ struct job { struct client *client; int fd; + struct event event; struct buffer *out; void (*callbackfn)(struct job *); @@ -796,14 +797,17 @@ struct window_pane { char *cwd; pid_t pid; - int fd; char tty[TTY_NAME_MAX]; + + int fd; + struct event event; struct buffer *in; struct buffer *out; struct input_ctx ictx; int pipe_fd; + struct event pipe_event; struct buffer *pipe_buf; size_t pipe_off; @@ -998,6 +1002,7 @@ struct tty { struct tty_term *term; int fd; + struct event event; struct buffer *in; struct buffer *out; @@ -1062,6 +1067,7 @@ struct mouse_event { /* Client connection. */ struct client { struct imsgbuf ibuf; + struct event event; struct timeval creation_time; struct timeval activity_time; @@ -1235,12 +1241,6 @@ extern const struct set_option_entry set_option_table[]; extern const struct set_option_entry set_window_option_table[]; /* tmux.c */ -extern volatile sig_atomic_t sigwinch; -extern volatile sig_atomic_t sigterm; -extern volatile sig_atomic_t sigcont; -extern volatile sig_atomic_t sigchld; -extern volatile sig_atomic_t sigusr1; -extern volatile sig_atomic_t sigusr2; extern struct options global_s_options; extern struct options global_w_options; extern struct environ global_environ; @@ -1251,9 +1251,6 @@ extern time_t start_time; extern char *socket_path; extern int login_shell; void logfile(const char *); -void siginit(void); -void sigreset(void); -void sighandler(int); const char *getshell(void); int checkshell(const char *); int areshell(const char *); @@ -1582,23 +1579,24 @@ const char *key_string_lookup_key(int); extern struct clients clients; extern struct clients dead_clients; int server_start(char *); -void server_poll_add(int, int, void (*)(int, int, void *), void *); +void server_signal_set(void); +void server_signal_clear(void); /* server-client.c */ void server_client_create(int); void server_client_lost(struct client *); void server_client_prepare(void); -void server_client_callback(int, int, void *); +void server_client_callback(int, short, void *); void server_client_loop(void); /* server-job.c */ void server_job_prepare(void); -void server_job_callback(int, int, void *); +void server_job_callback(int, short, void *); void server_job_loop(void); /* server-window.c */ void server_window_prepare(void); -void server_window_callback(int, int, void *); +void server_window_callback(int, short, void *); void server_window_loop(void); /* server-fn.c */ diff --git a/window.c b/window.c index 5d40cfc2..8f62c0e4 100644 --- a/window.c +++ b/window.c @@ -455,10 +455,12 @@ window_pane_destroy(struct window_pane *wp) if (wp->pipe_fd != -1) { buffer_destroy(wp->pipe_buf); close(wp->pipe_fd); + event_del(&wp->pipe_event); } buffer_destroy(wp->in); buffer_destroy(wp->out); + event_del(&wp->event); if (wp->cwd != NULL) xfree(wp->cwd); @@ -543,7 +545,7 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell, setenv(envent->name, envent->value, 1); } - sigreset(); + server_signal_clear(); log_close(); if (*wp->cmd != '\0') { From ea8c8c5f33e0dcbf563dc54615a6c172aea70518 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 4 Nov 2009 20:59:22 +0000 Subject: [PATCH 0492/1180] A couple of minor cosmetic changes. --- server-window.c | 2 +- tmux.c | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/server-window.c b/server-window.c index a6f2bba5..5eddb9bd 100644 --- a/server-window.c +++ b/server-window.c @@ -48,7 +48,7 @@ server_window_prepare(void) continue; events = 0; if (!server_window_backoff(wp)) - events = EV_READ; + events |= EV_READ; if (BUFFER_USED(wp->out) > 0) events |= EV_WRITE; event_del(&wp->event); diff --git a/tmux.c b/tmux.c index fd7d1bfc..d077aff6 100644 --- a/tmux.c +++ b/tmux.c @@ -504,7 +504,6 @@ main(int argc, char **argv) client_main(); /* doesn't return */ } - void main_set_signals(void) { From 4d6091379b4486b624070492d45ad390e7442382 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 4 Nov 2009 21:04:43 +0000 Subject: [PATCH 0493/1180] Switch jobs over to use a bufferevent. --- Makefile | 2 +- cmd-run-shell.c | 44 ++++++++++++++-------------- job.c | 51 +++++++++++++++++++++++++------- server-job.c | 77 ------------------------------------------------- server.c | 6 ++-- status.c | 21 ++++++++------ tmux.h | 12 ++------ 7 files changed, 81 insertions(+), 132 deletions(-) delete mode 100644 server-job.c diff --git a/Makefile b/Makefile index 04102479..e1b5b6c1 100644 --- a/Makefile +++ b/Makefile @@ -35,7 +35,7 @@ SRCS= attributes.c buffer-poll.c buffer.c cfg.c \ layout-set.c layout.c log.c job.c \ mode-key.c names.c options-cmd.c options.c paste.c procname.c \ resize.c screen-redraw.c screen-write.c screen.c session.c status.c \ - server-fn.c server.c server-client.c server-window.c server-job.c \ + server-fn.c server.c server-client.c server-window.c \ tmux.c tty-keys.c tty-term.c tty.c utf8.c \ window-choose.c window-clock.c window-copy.c window-more.c window.c \ xterm-keys.c xmalloc.c diff --git a/cmd-run-shell.c b/cmd-run-shell.c index 1a8e28f4..605b5dca 100644 --- a/cmd-run-shell.c +++ b/cmd-run-shell.c @@ -77,31 +77,33 @@ cmd_run_shell_callback(struct job *job) { struct cmd_run_shell_data *cdata = job->data; struct cmd_ctx *ctx = &cdata->ctx; - char *cmd, *msg, *line, *buf; - size_t off, len, llen; + char *cmd, *msg, *line; + size_t size; int retcode; + u_int lines; - buf = BUFFER_OUT(job->out); - len = BUFFER_USED(job->out); + lines = 0; + do { + if ((line = evbuffer_readline(job->event->input)) != NULL) { + ctx->print(ctx, "%s", line); + lines++; + } + } while (line != NULL); + + size = EVBUFFER_LENGTH(job->event->input); + if (size != 0) { + line = xmalloc(size + 1); + memcpy(line, EVBUFFER_DATA(job->event->input), size); + line[size] = '\0'; + + ctx->print(ctx, "%s", line); + lines++; + + xfree(line); + } cmd = cdata->cmd; - if (len != 0) { - line = buf; - for (off = 0; off < len; off++) { - if (buf[off] == '\n') { - llen = buf + off - line; - if (llen > INT_MAX) - break; - ctx->print(ctx, "%.*s", (int) llen, line); - line = buf + off + 1; - } - } - llen = buf + len - line; - if (llen > 0 && llen < INT_MAX) - ctx->print(ctx, "%.*s", (int) llen, line); - } - msg = NULL; if (WIFEXITED(job->status)) { if ((retcode = WEXITSTATUS(job->status)) != 0) @@ -111,7 +113,7 @@ cmd_run_shell_callback(struct job *job) xasprintf(&msg, "'%s' terminated by signal %d", cmd, retcode); } if (msg != NULL) { - if (len != 0) + if (lines != 0) ctx->print(ctx, "%s", msg); else ctx->info(ctx, "%s", msg); diff --git a/job.c b/job.c index fd91913f..15f93013 100644 --- a/job.c +++ b/job.c @@ -17,6 +17,7 @@ */ #include +#include #include #include @@ -35,6 +36,8 @@ struct joblist all_jobs = SLIST_HEAD_INITIALIZER(&all_jobs); RB_GENERATE(jobs, job, entry, job_cmp); +void job_callback(struct bufferevent *, short, void *); + int job_cmp(struct job *job1, struct job *job2) { @@ -86,14 +89,13 @@ job_add(struct jobs *jobs, int flags, struct client *c, const char *cmd, job->client = c; job->fd = -1; - job->out = buffer_create(BUFSIZ); - memset(&job->event, 0, sizeof job->event); + job->event = NULL; job->callbackfn = callbackfn; job->freefn = freefn; job->data = data; - job->flags = flags|JOB_DONE; + job->flags = flags; if (jobs != NULL) RB_INSERT(jobs, jobs, job); @@ -125,9 +127,9 @@ job_free(struct job *job) if (job->fd != -1) close(job->fd); - if (job->out != NULL) - buffer_destroy(job->out); - event_del(&job->event); + + if (job->event != NULL) + bufferevent_free(job->event); xfree(job); } @@ -138,11 +140,10 @@ job_run(struct job *job) { int nullfd, out[2], mode; - if (!(job->flags & JOB_DONE)) + if (job->fd != -1 || job->pid != -1) return (0); - job->flags &= ~JOB_DONE; - if (pipe(out) != 0) + if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, out) != 0) return (-1); switch (job->pid = fork()) { @@ -181,13 +182,41 @@ job_run(struct job *job) if (fcntl(job->fd, F_SETFD, FD_CLOEXEC) == -1) fatal("fcntl failed"); - if (BUFFER_USED(job->out) != 0) - buffer_remove(job->out, BUFFER_USED(job->out)); + if (job->event != NULL) + bufferevent_free(job->event); + job->event = + bufferevent_new(job->fd, NULL, NULL, job_callback, job); + bufferevent_enable(job->event, EV_READ); return (0); } } +/* Job buffer error callback. */ +void +job_callback(unused struct bufferevent *bufev, unused short events, void *data) +{ + struct job *job = data; + + bufferevent_disable(job->event, EV_READ); + close(job->fd); + job->fd = -1; + + if (job->pid == -1 && job->callbackfn != NULL) + job->callbackfn(job); +} + +/* Job died (waitpid() returned its pid). */ +void +job_died(struct job *job, int status) +{ + job->status = status; + job->pid = -1; + + if (job->fd == -1 && job->callbackfn != NULL) + job->callbackfn(job); +} + /* Kill a job. */ void job_kill(struct job *job) diff --git a/server-job.c b/server-job.c deleted file mode 100644 index 5d83ff92..00000000 --- a/server-job.c +++ /dev/null @@ -1,77 +0,0 @@ -/* $OpenBSD$ */ - -/* - * Copyright (c) 2009 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 "tmux.h" - -/* Register jobs for poll. */ -void -server_job_prepare(void) -{ - struct job *job; - - SLIST_FOREACH(job, &all_jobs, lentry) { - if (job->fd == -1) - continue; - event_del(&job->event); - event_set( - &job->event, job->fd, EV_READ, server_job_callback, job); - event_add(&job->event, NULL); - } -} - -/* Process a single job event. */ -void -server_job_callback(int fd, short events, void *data) -{ - struct job *job = data; - - if (job->fd == -1) - return; - - if (buffer_poll(fd, events, job->out, NULL) != 0) { - close(job->fd); - job->fd = -1; - } -} - -/* Job functions that happen once a loop. */ -void -server_job_loop(void) -{ - struct job *job; - -restart: - SLIST_FOREACH(job, &all_jobs, lentry) { - if (job->flags & JOB_DONE || job->fd != -1 || job->pid != -1) - continue; - job->flags |= JOB_DONE; - - if (job->callbackfn != NULL) { - job->callbackfn(job); - if ((!job->flags & JOB_PERSIST)) { - job_free(job); - goto restart; - } - } - } -} diff --git a/server.c b/server.c index 236cd201..680ac93f 100644 --- a/server.c +++ b/server.c @@ -214,14 +214,12 @@ server_loop(void) while (!server_should_shutdown()) { server_update_socket(); - server_job_prepare(); server_window_prepare(); server_client_prepare(); event_loopexit(&tv); event_loop(EVLOOP_ONCE); - server_job_loop(); server_window_loop(); server_client_loop(); @@ -470,8 +468,8 @@ server_child_exited(pid_t pid, int status) SLIST_FOREACH(job, &all_jobs, lentry) { if (pid == job->pid) { - job->pid = -1; - job->status = status; + job_died(job, status); /* might free job */ + break; } } } diff --git a/status.c b/status.c index 21ca31a2..4b0c81fb 100644 --- a/status.c +++ b/status.c @@ -486,23 +486,26 @@ status_job(struct client *c, char **iptr) void status_job_callback(struct job *job) { - char *buf; + char *line, *buf; size_t len; - len = BUFFER_USED(job->out); - buf = xmalloc(len + 1); - if (len != 0) - buffer_read(job->out, buf, len); - buf[len] = '\0'; - buf[strcspn(buf, "\n")] = '\0'; + buf = NULL; + if ((line = evbuffer_readline(job->event->input)) == NULL) { + len = EVBUFFER_LENGTH(job->event->input); + buf = xmalloc(len + 1); + if (len != 0) + memcpy(buf, EVBUFFER_DATA(job->event->input), len); + buf[len] = '\0'; + } if (job->data != NULL) xfree(job->data); else server_redraw_client(job->client); - job->data = xstrdup(buf); + job->data = xstrdup(line); - xfree(buf); + if (buf != NULL) + xfree(buf); } size_t diff --git a/tmux.h b/tmux.h index b72c0d8c..64a7d3bd 100644 --- a/tmux.h +++ b/tmux.h @@ -661,16 +661,14 @@ struct job { struct client *client; int fd; - struct event event; - struct buffer *out; + struct bufferevent *event; void (*callbackfn)(struct job *); void (*freefn)(void *); void *data; int flags; -#define JOB_DONE 0x1 -#define JOB_PERSIST 0x2 /* don't free after callback */ +#define JOB_PERSIST 0x1 /* don't free after callback */ RB_ENTRY(job) entry; SLIST_ENTRY(job) lentry; @@ -1306,6 +1304,7 @@ struct job *job_add(struct jobs *, int, struct client *, void job_remove(struct jobs *, struct job *); void job_free(struct job *); int job_run(struct job *); +void job_died(struct job *, int); void job_kill(struct job *); /* environ.c */ @@ -1589,11 +1588,6 @@ void server_client_prepare(void); void server_client_callback(int, short, void *); void server_client_loop(void); -/* server-job.c */ -void server_job_prepare(void); -void server_job_callback(int, short, void *); -void server_job_loop(void); - /* server-window.c */ void server_window_prepare(void); void server_window_callback(int, short, void *); From abb728684b00c82460ea439c8df16d3f1018c826 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 4 Nov 2009 21:10:49 +0000 Subject: [PATCH 0494/1180] Add back JOB_PERSIST checks that got lost. --- job.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/job.c b/job.c index 15f93013..d779057d 100644 --- a/job.c +++ b/job.c @@ -127,7 +127,6 @@ job_free(struct job *job) if (job->fd != -1) close(job->fd); - if (job->event != NULL) bufferevent_free(job->event); @@ -202,8 +201,12 @@ job_callback(unused struct bufferevent *bufev, unused short events, void *data) close(job->fd); job->fd = -1; - if (job->pid == -1 && job->callbackfn != NULL) - job->callbackfn(job); + if (job->pid == -1) { + if (job->callbackfn != NULL) + job->callbackfn(job); + if ((!job->flags & JOB_PERSIST)) + job_free(job); + } } /* Job died (waitpid() returned its pid). */ @@ -213,8 +216,12 @@ job_died(struct job *job, int status) job->status = status; job->pid = -1; - if (job->fd == -1 && job->callbackfn != NULL) - job->callbackfn(job); + if (job->fd == -1) { + if (job->callbackfn != NULL) + job->callbackfn(job); + if ((!job->flags & JOB_PERSIST)) + job_free(job); + } } /* Kill a job. */ From 7342615c7ddd9b99820bd9c03fda2afe7bc868d3 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 4 Nov 2009 21:47:42 +0000 Subject: [PATCH 0495/1180] Switch tty fds over to a bufferevent. --- server-client.c | 23 +---------------------- server-window.c | 3 ++- tmux.h | 4 +--- tty-keys.c | 23 +++++++++++++---------- tty.c | 30 +++++++++++++++++++++--------- 5 files changed, 38 insertions(+), 45 deletions(-) diff --git a/server-client.c b/server-client.c index 64909d87..f839c305 100644 --- a/server-client.c +++ b/server-client.c @@ -136,8 +136,7 @@ server_client_lost(struct client *c) close(c->ibuf.fd); imsg_clear(&c->ibuf); event_del(&c->event); - event_del(&c->tty.event); - + for (i = 0; i < ARRAY_LENGTH(&dead_clients); i++) { if (ARRAY_ITEM(&dead_clients, i) == NULL) { ARRAY_SET(&dead_clients, i, c); @@ -172,18 +171,6 @@ server_client_prepare(void) event_set(&c->event, c->ibuf.fd, events, server_client_callback, c); event_add(&c->event, NULL); - - if (c->tty.fd == -1) - continue; - if (c->flags & CLIENT_SUSPENDED || c->session == NULL) - continue; - events = EV_READ; - if (BUFFER_USED(c->tty.out) > 0) - events |= EV_WRITE; - event_del(&c->tty.event); - event_set(&c->tty.event, - c->tty.fd, events, server_client_callback, c); - event_add(&c->tty.event, NULL); } } @@ -209,14 +196,6 @@ server_client_callback(int fd, short events, void *data) if (events & EV_READ && server_client_msg_dispatch(c) != 0) goto client_lost; } - - if (c->tty.fd != -1 && fd == c->tty.fd) { - if (c->flags & CLIENT_SUSPENDED || c->session == NULL) - return; - - if (buffer_poll(fd, events, c->tty.in, c->tty.out) != 0) - goto client_lost; - } return; diff --git a/server-window.c b/server-window.c index 5eddb9bd..9e3c7522 100644 --- a/server-window.c +++ b/server-window.c @@ -87,7 +87,8 @@ server_window_backoff(struct window_pane *wp) continue; if (c->session->curw->window != wp->window) continue; - if (BUFFER_USED(c->tty.out) > BACKOFF_THRESHOLD) + + if (EVBUFFER_LENGTH(c->tty.event->output) > BACKOFF_THRESHOLD) return (1); } return (0); diff --git a/tmux.h b/tmux.h index 64a7d3bd..6ea98ae3 100644 --- a/tmux.h +++ b/tmux.h @@ -1000,9 +1000,7 @@ struct tty { struct tty_term *term; int fd; - struct event event; - struct buffer *in; - struct buffer *out; + struct bufferevent *event; int log_fd; diff --git a/tty-keys.c b/tty-keys.c index 2b7bae67..995f2994 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -299,18 +299,20 @@ tty_keys_next(struct tty *tty, int *key, struct mouse_event *mouse) struct tty_key *tk; struct timeval tv; char *buf; + u_char ch; size_t len, size; cc_t bspace; - buf = BUFFER_OUT(tty->in); - len = BUFFER_USED(tty->in); + buf = EVBUFFER_DATA(tty->event->input); + len = EVBUFFER_LENGTH(tty->event->input); if (len == 0) return (1); log_debug("keys are %zu (%.*s)", len, (int) len, buf); /* If a normal key, return it. */ if (*buf != '\033') { - *key = buffer_read8(tty->in); + bufferevent_read(tty->event, &ch, 1); + *key = ch; /* * Check for backspace key using termios VERASE - the terminfo @@ -326,7 +328,7 @@ tty_keys_next(struct tty *tty, int *key, struct mouse_event *mouse) /* Look for matching key string and return if found. */ tk = tty_keys_find(tty, buf + 1, len - 1, &size); if (tk != NULL) { - buffer_remove(tty->in, size + 1); + evbuffer_drain(tty->event->input, size + 1); *key = tk->key; goto found; } @@ -334,14 +336,14 @@ tty_keys_next(struct tty *tty, int *key, struct mouse_event *mouse) /* Not found. Is this a mouse key press? */ *key = tty_keys_mouse(buf, len, &size, mouse); if (*key != KEYC_NONE) { - buffer_remove(tty->in, size); + evbuffer_drain(tty->event->input, size); goto found; } /* Not found. Try to parse a key with an xterm-style modifier. */ *key = xterm_keys_find(buf, len, &size); if (*key != KEYC_NONE) { - buffer_remove(tty->in, size); + evbuffer_drain(tty->event->input, size); goto found; } @@ -363,8 +365,9 @@ tty_keys_next(struct tty *tty, int *key, struct mouse_event *mouse) /* Is there a normal key following? */ if (len != 0 && *buf != '\033') { - buffer_remove(tty->in, 1); - *key = buffer_read8(tty->in) | KEYC_ESCAPE; + evbuffer_drain(tty->event->input, 1); + bufferevent_read(tty->event, &ch, 1); + *key = ch | KEYC_ESCAPE; goto found; } @@ -372,7 +375,7 @@ tty_keys_next(struct tty *tty, int *key, struct mouse_event *mouse) if (len > 1) { tk = tty_keys_find(tty, buf + 1, len - 1, &size); if (tk != NULL) { - buffer_remove(tty->in, size + 2); + evbuffer_drain(tty->event->input, size + 2); *key = tk->key | KEYC_ESCAPE; goto found; } @@ -385,7 +388,7 @@ tty_keys_next(struct tty *tty, int *key, struct mouse_event *mouse) return (1); /* Give up and return the escape. */ - buffer_remove(tty->in, 1); + evbuffer_drain(tty->event->input, 1); *key = '\033'; found: diff --git a/tty.c b/tty.c index 0782e42d..e194febb 100644 --- a/tty.c +++ b/tty.c @@ -28,6 +28,8 @@ #include "tmux.h" +void tty_error_callback(struct bufferevent *, short, void *); + void tty_fill_acs(struct tty *); int tty_try_256(struct tty *, u_char, const char *); @@ -108,11 +110,11 @@ tty_open(struct tty *tty, const char *overrides, char **cause) } tty->flags |= TTY_OPENED; - tty->in = buffer_create(BUFSIZ); - tty->out = buffer_create(BUFSIZ); - tty->flags &= ~(TTY_NOCURSOR|TTY_FREEZE|TTY_ESCAPE); + tty->event = bufferevent_new( + tty->fd, NULL, NULL, tty_error_callback, tty); + tty_start_tty(tty); tty_keys_init(tty); @@ -122,6 +124,13 @@ tty_open(struct tty *tty, const char *overrides, char **cause) return (0); } +void +tty_error_callback( + unused struct bufferevent *bufev, unused short what, unused void *data) +{ + fatalx("lost terminal"); +} + void tty_start_tty(struct tty *tty) { @@ -136,6 +145,8 @@ tty_start_tty(struct tty *tty) if (fcntl(tty->fd, F_SETFL, mode|O_NONBLOCK) == -1) fatal("fcntl failed"); + bufferevent_enable(tty->event, EV_READ|EV_WRITE); + if (tcgetattr(tty->fd, &tty->tio) != 0) fatal("tcgetattr failed"); memcpy(&tio, &tty->tio, sizeof tio); @@ -187,6 +198,8 @@ tty_stop_tty(struct tty *tty) return; tty->flags &= ~TTY_STARTED; + bufferevent_disable(tty->event, EV_READ|EV_WRITE); + /* * Be flexible about error handling and try not kill the server just * because the fd is invalid. Things like ssh -t can easily leave us @@ -249,12 +262,11 @@ tty_close(struct tty *tty) tty_stop_tty(tty); if (tty->flags & TTY_OPENED) { + bufferevent_free(tty->event); + tty_term_free(tty->term); tty_keys_free(tty); - buffer_destroy(tty->in); - buffer_destroy(tty->out); - tty->flags &= ~TTY_OPENED; } @@ -308,7 +320,7 @@ tty_puts(struct tty *tty, const char *s) { if (*s == '\0') return; - buffer_write(tty->out, s, strlen(s)); + bufferevent_write(tty->event, s, strlen(s)); if (tty->log_fd != -1) write(tty->log_fd, s, strlen(s)); @@ -321,7 +333,7 @@ tty_putc(struct tty *tty, u_char ch) if (tty->cell.attr & GRID_ATTR_CHARSET) ch = tty_get_acs(tty, ch); - buffer_write8(tty->out, ch); + bufferevent_write(tty->event, &ch, 1); if (ch >= 0x20 && ch != 0x7f) { sx = tty->sx; @@ -348,7 +360,7 @@ tty_pututf8(struct tty *tty, const struct grid_utf8 *gu) for (i = 0; i < UTF8_SIZE; i++) { if (gu->data[i] == 0xff) break; - buffer_write8(tty->out, gu->data[i]); + bufferevent_write(tty->event, &gu->data[i], 1); if (tty->log_fd != -1) write(tty->log_fd, &gu->data[i], 1); } From 91ad830c8863ab66038226f9e16bc87cbbdb6d95 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 4 Nov 2009 22:02:38 +0000 Subject: [PATCH 0496/1180] Switch window pane pipe redirect fd over to a bufferevent. --- cmd-pipe-pane.c | 25 +++++++++++++++++++++---- server-window.c | 18 ------------------ tmux.h | 3 +-- window.c | 7 +++---- 4 files changed, 25 insertions(+), 28 deletions(-) diff --git a/cmd-pipe-pane.c b/cmd-pipe-pane.c index 10cd3323..4565174e 100644 --- a/cmd-pipe-pane.c +++ b/cmd-pipe-pane.c @@ -17,6 +17,7 @@ */ #include +#include #include #include @@ -32,6 +33,8 @@ int cmd_pipe_pane_exec(struct cmd *, struct cmd_ctx *); +void cmd_pipe_pane_error_callback(struct bufferevent *, short, void *); + const struct cmd_entry cmd_pipe_pane_entry = { "pipe-pane", "pipep", CMD_TARGET_PANE_USAGE "[-o] [command]", @@ -56,7 +59,7 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx) /* Destroy the old pipe. */ old_fd = wp->pipe_fd; if (wp->pipe_fd != -1) { - buffer_destroy(wp->pipe_buf); + bufferevent_free(wp->pipe_event); close(wp->pipe_fd); wp->pipe_fd = -1; } @@ -75,8 +78,8 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx) return (0); /* Open the new pipe. */ - if (pipe(pipe_fd) != 0) { - ctx->error(ctx, "pipe error: %s", strerror(errno)); + if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_fd) != 0) { + ctx->error(ctx, "socketpair error: %s", strerror(errno)); return (-1); } @@ -110,9 +113,12 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx) close(pipe_fd[1]); wp->pipe_fd = pipe_fd[0]; - wp->pipe_buf = buffer_create(BUFSIZ); wp->pipe_off = BUFFER_USED(wp->in); + wp->pipe_event = bufferevent_new(wp->pipe_fd, + NULL, NULL, cmd_pipe_pane_error_callback, wp); + bufferevent_enable(wp->pipe_event, EV_WRITE); + if ((mode = fcntl(wp->pipe_fd, F_GETFL)) == -1) fatal("fcntl failed"); if (fcntl(wp->pipe_fd, F_SETFL, mode|O_NONBLOCK) == -1) @@ -124,3 +130,14 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx) return (0); } + +void +cmd_pipe_pane_error_callback( + unused struct bufferevent *bufev, unused short what, void *data) +{ + struct window_pane *wp = data; + + bufferevent_free(wp->pipe_event); + close(wp->pipe_fd); + wp->pipe_fd = -1; +} diff --git a/server-window.c b/server-window.c index 9e3c7522..bc6f0b4f 100644 --- a/server-window.c +++ b/server-window.c @@ -55,16 +55,6 @@ server_window_prepare(void) event_set(&wp->event, wp->fd, events, server_window_callback, wp); event_add(&wp->event, NULL); - - if (wp->pipe_fd == -1) - continue; - events = 0; - if (BUFFER_USED(wp->pipe_buf) > 0) - events |= EV_WRITE; - event_del(&wp->pipe_event); - event_set(&wp->pipe_event, - wp->pipe_fd, events, server_window_callback, wp); - event_add(&wp->pipe_event, NULL); } } } @@ -110,14 +100,6 @@ server_window_callback(int fd, short events, void *data) } else window_pane_parse(wp); } - - if (fd == wp->pipe_fd) { - if (buffer_poll(fd, events, NULL, wp->pipe_buf) != 0) { - buffer_destroy(wp->pipe_buf); - close(wp->pipe_fd); - wp->pipe_fd = -1; - } - } } /* Window functions that need to happen every loop. */ diff --git a/tmux.h b/tmux.h index 6ea98ae3..3edc6ec8 100644 --- a/tmux.h +++ b/tmux.h @@ -805,8 +805,7 @@ struct window_pane { struct input_ctx ictx; int pipe_fd; - struct event pipe_event; - struct buffer *pipe_buf; + struct bufferevent *pipe_event; size_t pipe_off; struct screen *screen; diff --git a/window.c b/window.c index 8f62c0e4..293a1c63 100644 --- a/window.c +++ b/window.c @@ -426,8 +426,8 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit) wp->sy = sy; wp->pipe_fd = -1; - wp->pipe_buf = NULL; wp->pipe_off = 0; + wp->pipe_event = NULL; wp->saved_grid = NULL; @@ -453,9 +453,8 @@ window_pane_destroy(struct window_pane *wp) grid_destroy(wp->saved_grid); if (wp->pipe_fd != -1) { - buffer_destroy(wp->pipe_buf); close(wp->pipe_fd); - event_del(&wp->pipe_event); + bufferevent_free(wp->pipe_event); } buffer_destroy(wp->in); @@ -639,7 +638,7 @@ window_pane_parse(struct window_pane *wp) new_size = BUFFER_USED(wp->in) - wp->pipe_off; if (wp->pipe_fd != -1 && new_size > 0) - buffer_write(wp->pipe_buf, BUFFER_OUT(wp->in), new_size); + bufferevent_write(wp->pipe_event, BUFFER_OUT(wp->in), new_size); input_parse(wp); From 06ffed32169a6bf449f543803ee8b87c439ae94b Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 4 Nov 2009 22:40:36 +0000 Subject: [PATCH 0497/1180] Call event_init() before loading the config file, since potentially it could set up events. --- server.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server.c b/server.c index 680ac93f..bd6c28c3 100644 --- a/server.c +++ b/server.c @@ -163,6 +163,8 @@ server_start(char *path) server_fd = server_create_socket(); server_client_create(pair[1]); + event_init(); + if (access(SYSTEM_CFG, R_OK) == 0) { if (load_cfg(SYSTEM_CFG, NULL, &cause) != 0) goto error; @@ -173,8 +175,6 @@ server_start(char *path) if (cfg_file != NULL && load_cfg(cfg_file, NULL, &cause) != 0) goto error; - event_init(); - event_set(&server_ev_accept, server_fd, EV_READ|EV_PERSIST, server_accept_callback, NULL); event_add(&server_ev_accept, NULL); From a02c7e804c8c6b9984e9d09c305199ccec92763f Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 4 Nov 2009 22:43:11 +0000 Subject: [PATCH 0498/1180] Convert the window pane (pty master side) fd over to use a bufferevent. The evbuffer API is very similar to the existing tmux buffer API so this was remarkably painless. Not many possible ways to do it, I suppose. --- cmd-paste-buffer.c | 14 ++++++------ cmd-pipe-pane.c | 2 +- input-keys.c | 22 +++++++++++-------- input.c | 24 +++++++++++---------- server-window.c | 54 ++++++---------------------------------------- server.c | 1 - tmux.h | 6 +----- window.c | 51 ++++++++++++++++++++++++++++++++----------- 8 files changed, 81 insertions(+), 93 deletions(-) diff --git a/cmd-paste-buffer.c b/cmd-paste-buffer.c index 1d92557f..e8e638ef 100644 --- a/cmd-paste-buffer.c +++ b/cmd-paste-buffer.c @@ -27,7 +27,7 @@ */ int cmd_paste_buffer_exec(struct cmd *, struct cmd_ctx *); -void cmd_paste_buffer_lf2cr(struct buffer *, const char *, size_t); +void cmd_paste_buffer_lf2cr(struct window_pane *, const char *, size_t); const struct cmd_entry cmd_paste_buffer_entry = { "paste-buffer", "pasteb", @@ -65,9 +65,9 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) if (pb != NULL && *pb->data != '\0') { /* -r means raw data without LF->CR conversion. */ if (data->chflags & CMD_CHFLAG('r')) - buffer_write(wp->out, pb->data, pb->size); + bufferevent_write(wp->event, pb->data, pb->size); else - cmd_paste_buffer_lf2cr(wp->out, pb->data, pb->size); + cmd_paste_buffer_lf2cr(wp, pb->data, pb->size); } /* Delete the buffer if -d. */ @@ -83,18 +83,18 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) /* Add bytes to a buffer but change every '\n' to '\r'. */ void -cmd_paste_buffer_lf2cr(struct buffer *b, const char *data, size_t size) +cmd_paste_buffer_lf2cr(struct window_pane *wp, const char *data, size_t size) { const char *end = data + size; const char *lf; while ((lf = memchr(data, '\n', end - data)) != NULL) { if (lf != data) - buffer_write(b, data, lf - data); - buffer_write8(b, '\r'); + bufferevent_write(wp->event, data, lf - data); + bufferevent_write(wp->event, "\r", 1); data = lf + 1; } if (end != data) - buffer_write(b, data, end - data); + bufferevent_write(wp->event, data, end - data); } diff --git a/cmd-pipe-pane.c b/cmd-pipe-pane.c index 4565174e..d0b0fcca 100644 --- a/cmd-pipe-pane.c +++ b/cmd-pipe-pane.c @@ -113,7 +113,7 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx) close(pipe_fd[1]); wp->pipe_fd = pipe_fd[0]; - wp->pipe_off = BUFFER_USED(wp->in); + wp->pipe_off = EVBUFFER_LENGTH(wp->event->input); wp->pipe_event = bufferevent_new(wp->pipe_fd, NULL, NULL, cmd_pipe_pane_error_callback, wp); diff --git a/input-keys.c b/input-keys.c index 627b22cf..e8a163a0 100644 --- a/input-keys.c +++ b/input-keys.c @@ -163,6 +163,7 @@ input_key(struct window_pane *wp, int key) u_int i; size_t dlen; char *out; + u_char ch; log_debug2("writing key 0x%x", key); @@ -172,8 +173,10 @@ input_key(struct window_pane *wp, int key) */ if (key != KEYC_NONE && (key & ~KEYC_ESCAPE) < 0x100) { if (key & KEYC_ESCAPE) - buffer_write8(wp->out, '\033'); - buffer_write8(wp->out, (uint8_t) (key & ~KEYC_ESCAPE)); + ch = '\033'; + else + ch = key & ~KEYC_ESCAPE; + bufferevent_write(wp->event, &ch, 1); return; } @@ -183,7 +186,7 @@ input_key(struct window_pane *wp, int key) */ if (options_get_number(&wp->window->options, "xterm-keys")) { if ((out = xterm_keys_lookup(key)) != NULL) { - buffer_write(wp->out, out, strlen(out)); + bufferevent_write(wp->event, out, strlen(out)); xfree(out); return; } @@ -214,18 +217,19 @@ input_key(struct window_pane *wp, int key) /* Prefix a \033 for escape. */ if (key & KEYC_ESCAPE) - buffer_write8(wp->out, '\033'); - buffer_write(wp->out, ike->data, dlen); + bufferevent_write(wp->event, "\033", 1); + bufferevent_write(wp->event, ike->data, dlen); } /* Translate mouse and output. */ void input_mouse(struct window_pane *wp, struct mouse_event *m) { + char out[8]; + if (wp->screen->mode & MODE_MOUSE) { - buffer_write(wp->out, "\033[M", 3); - buffer_write8(wp->out, m->b + 32); - buffer_write8(wp->out, m->x + 33); - buffer_write8(wp->out, m->y + 33); + xsnprintf(out, sizeof out, + "\033[M%c%c%c", m->b + 32, m->x + 33, m->y + 33); + bufferevent_write(wp->event, out, strlen(out)); } } diff --git a/input.c b/input.c index f0a566e5..b846e060 100644 --- a/input.c +++ b/input.c @@ -256,12 +256,12 @@ input_parse(struct window_pane *wp) struct input_ctx *ictx = &wp->ictx; u_char ch; - if (BUFFER_USED(wp->in) == ictx->was) + if (EVBUFFER_LENGTH(wp->event->input) == ictx->was) return; wp->window->flags |= WINDOW_ACTIVITY; - ictx->buf = BUFFER_OUT(wp->in); - ictx->len = BUFFER_USED(wp->in); + ictx->buf = EVBUFFER_DATA(wp->event->input); + ictx->len = EVBUFFER_LENGTH(wp->event->input); ictx->off = 0; ictx->wp = wp; @@ -278,8 +278,8 @@ input_parse(struct window_pane *wp) screen_write_stop(&ictx->ctx); - buffer_remove(wp->in, ictx->len); - ictx->was = BUFFER_USED(wp->in); + evbuffer_drain(wp->event->input, ictx->len); + ictx->was = EVBUFFER_LENGTH(wp->event->input); } void @@ -932,7 +932,8 @@ input_handle_sequence_cbt(struct input_ctx *ictx) void input_handle_sequence_da(struct input_ctx *ictx) { - uint16_t n; + struct window_pane *wp = ictx->wp; + uint16_t n; if (ictx->private != '\0') return; @@ -944,7 +945,7 @@ input_handle_sequence_da(struct input_ctx *ictx) if (n != 0) return; - buffer_write(ictx->wp->out, "\033[?1;2c", (sizeof "\033[?1;2c") - 1); + bufferevent_write(wp->event, "\033[?1;2c", (sizeof "\033[?1;2c") - 1); } void @@ -1314,9 +1315,10 @@ input_handle_sequence_rm(struct input_ctx *ictx) void input_handle_sequence_dsr(struct input_ctx *ictx) { - struct screen *s = ictx->ctx.s; - uint16_t n; - char reply[32]; + struct window_pane *wp = ictx->wp; + struct screen *s = ictx->ctx.s; + uint16_t n; + char reply[32]; if (ARRAY_LENGTH(&ictx->args) > 1) return; @@ -1329,7 +1331,7 @@ input_handle_sequence_dsr(struct input_ctx *ictx) xsnprintf(reply, sizeof reply, "\033[%u;%uR", s->cy + 1, s->cx + 1); log_debug("cursor request, reply: %s", reply); - buffer_write(ictx->wp->out, reply, strlen(reply)); + bufferevent_write(wp->event, reply, strlen(reply)); break; } } diff --git a/server-window.c b/server-window.c index bc6f0b4f..d0eb7960 100644 --- a/server-window.c +++ b/server-window.c @@ -30,35 +30,6 @@ int server_window_check_content( struct session *, struct window *, struct window_pane *); void server_window_check_alive(struct window *); -/* Register windows for poll. */ -void -server_window_prepare(void) -{ - struct window *w; - struct window_pane *wp; - u_int i; - int events; - - for (i = 0; i < ARRAY_LENGTH(&windows); i++) { - if ((w = ARRAY_ITEM(&windows, i)) == NULL) - continue; - - TAILQ_FOREACH(wp, &w->panes, entry) { - if (wp->fd == -1) - continue; - events = 0; - if (!server_window_backoff(wp)) - events |= EV_READ; - if (BUFFER_USED(wp->out) > 0) - events |= EV_WRITE; - event_del(&wp->event); - event_set(&wp->event, - wp->fd, events, server_window_callback, wp); - event_add(&wp->event, NULL); - } - } -} - /* Check if this window should suspend reading. */ int server_window_backoff(struct window_pane *wp) @@ -84,24 +55,6 @@ server_window_backoff(struct window_pane *wp) return (0); } -/* Process a single window pane event. */ -void -server_window_callback(int fd, short events, void *data) -{ - struct window_pane *wp = data; - - if (wp->fd == -1) - return; - - if (fd == wp->fd) { - if (buffer_poll(fd, events, wp->in, wp->out) != 0) { - close(wp->fd); - wp->fd = -1; - } else - window_pane_parse(wp); - } -} - /* Window functions that need to happen every loop. */ void server_window_loop(void) @@ -116,6 +69,13 @@ server_window_loop(void) if (w == NULL) continue; + TAILQ_FOREACH(wp, &w->panes, entry) { + if (server_window_backoff(wp)) + bufferevent_disable(wp->event, EV_READ); + else + bufferevent_enable(wp->event, EV_READ); + } + for (j = 0; j < ARRAY_LENGTH(&sessions); j++) { s = ARRAY_ITEM(&sessions, j); if (s == NULL || !session_has(s, w)) diff --git a/server.c b/server.c index bd6c28c3..b4c5a8d2 100644 --- a/server.c +++ b/server.c @@ -214,7 +214,6 @@ server_loop(void) while (!server_should_shutdown()) { server_update_socket(); - server_window_prepare(); server_client_prepare(); event_loopexit(&tv); diff --git a/tmux.h b/tmux.h index 3edc6ec8..8940d381 100644 --- a/tmux.h +++ b/tmux.h @@ -798,9 +798,7 @@ struct window_pane { char tty[TTY_NAME_MAX]; int fd; - struct event event; - struct buffer *in; - struct buffer *out; + struct bufferevent *event; struct input_ctx ictx; @@ -1586,8 +1584,6 @@ void server_client_callback(int, short, void *); void server_client_loop(void); /* server-window.c */ -void server_window_prepare(void); -void server_window_callback(int, short, void *); void server_window_loop(void); /* server-fn.c */ diff --git a/window.c b/window.c index 293a1c63..fca94df8 100644 --- a/window.c +++ b/window.c @@ -56,6 +56,9 @@ /* Global window list. */ struct windows windows; +void window_pane_read_callback(struct bufferevent *, void *); +void window_pane_error_callback(struct bufferevent *, short, void *); + RB_GENERATE(winlinks, winlink, entry, winlink_cmp); int @@ -412,8 +415,7 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit) wp->cwd = NULL; wp->fd = -1; - wp->in = buffer_create(BUFSIZ); - wp->out = buffer_create(BUFSIZ); + wp->event = NULL; wp->mode = NULL; @@ -442,8 +444,10 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit) void window_pane_destroy(struct window_pane *wp) { - if (wp->fd != -1) + if (wp->fd != -1) { close(wp->fd); + bufferevent_free(wp->event); + } input_free(wp); @@ -457,10 +461,6 @@ window_pane_destroy(struct window_pane *wp) bufferevent_free(wp->pipe_event); } - buffer_destroy(wp->in); - buffer_destroy(wp->out); - event_del(&wp->event); - if (wp->cwd != NULL) xfree(wp->cwd); if (wp->shell != NULL) @@ -484,8 +484,10 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell, struct termios tio2; u_int i; - if (wp->fd != -1) + if (wp->fd != -1) { close(wp->fd); + bufferevent_free(wp->event); + } if (cmd != NULL) { if (wp->cmd != NULL) xfree(wp->cmd); @@ -574,10 +576,32 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell, fatal("fcntl failed"); if (fcntl(wp->fd, F_SETFD, FD_CLOEXEC) == -1) fatal("fcntl failed"); + wp->event = bufferevent_new(wp->fd, + window_pane_read_callback, NULL, window_pane_error_callback, wp); + bufferevent_enable(wp->event, EV_READ|EV_WRITE); return (0); } +void +window_pane_read_callback(unused struct bufferevent *bufev, void *data) +{ + struct window_pane *wp = data; + + window_pane_parse(wp); +} + +void +window_pane_error_callback( + unused struct bufferevent *bufev, unused short what, void *data) +{ + struct window_pane *wp = data; + + close(wp->fd); + bufferevent_free(wp->event); + wp->fd = -1; +} + void window_pane_resize(struct window_pane *wp, u_int sx, u_int sy) { @@ -631,18 +655,21 @@ window_pane_reset_mode(struct window_pane *wp) void window_pane_parse(struct window_pane *wp) { + char *data; size_t new_size; if (wp->mode != NULL) return; - new_size = BUFFER_USED(wp->in) - wp->pipe_off; - if (wp->pipe_fd != -1 && new_size > 0) - bufferevent_write(wp->pipe_event, BUFFER_OUT(wp->in), new_size); + new_size = EVBUFFER_LENGTH(wp->event->input) - wp->pipe_off; + if (wp->pipe_fd != -1 && new_size > 0) { + data = EVBUFFER_DATA(wp->event->input); + bufferevent_write(wp->pipe_event, data, new_size); + } input_parse(wp); - wp->pipe_off = BUFFER_USED(wp->in); + wp->pipe_off = EVBUFFER_LENGTH(wp->event->input); } void From 5bebbd81d76183be6f9384c5dada0e1732a58313 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 4 Nov 2009 22:44:53 +0000 Subject: [PATCH 0499/1180] Bye-bye buffer*.c. --- Makefile | 4 +- buffer-poll.c | 53 ------------------- buffer.c | 139 -------------------------------------------------- tmux.h | 29 ----------- 4 files changed, 2 insertions(+), 223 deletions(-) delete mode 100644 buffer-poll.c delete mode 100644 buffer.c diff --git a/Makefile b/Makefile index e1b5b6c1..88900fd8 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,8 @@ # $OpenBSD$ PROG= tmux -SRCS= attributes.c buffer-poll.c buffer.c cfg.c \ - client.c clock.c cmd-attach-session.c cmd-bind-key.c \ +SRCS= attributes.c cfg.c client.c clock.c \ + cmd-attach-session.c cmd-bind-key.c \ cmd-break-pane.c cmd-choose-session.c cmd-choose-window.c \ cmd-clear-history.c cmd-clock-mode.c cmd-command-prompt.c \ cmd-confirm-before.c cmd-copy-buffer.c cmd-copy-mode.c \ diff --git a/buffer-poll.c b/buffer-poll.c deleted file mode 100644 index d95510c1..00000000 --- a/buffer-poll.c +++ /dev/null @@ -1,53 +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 -#include -#include - -#include "tmux.h" - -/* Fill buffers from socket based on poll results. */ -int -buffer_poll(int fd, int events, struct buffer *in, struct buffer *out) -{ - ssize_t n; - - if (in != NULL && events & EV_READ) { - buffer_ensure(in, BUFSIZ); - n = read(fd, BUFFER_IN(in), BUFFER_FREE(in)); - if (n == 0) - return (-1); - if (n == -1) { - if (errno != EINTR && errno != EAGAIN) - return (-1); - } else - buffer_add(in, n); - } - if (out != NULL && BUFFER_USED(out) > 0 && events & EV_WRITE) { - n = write(fd, BUFFER_OUT(out), BUFFER_USED(out)); - if (n == -1) { - if (errno != EINTR && errno != EAGAIN) - return (-1); - } else - buffer_remove(out, n); - } - return (0); -} diff --git a/buffer.c b/buffer.c deleted file mode 100644 index 5505bf74..00000000 --- a/buffer.c +++ /dev/null @@ -1,139 +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 - -#include "tmux.h" - -/* Create a buffer. */ -struct buffer * -buffer_create(size_t size) -{ - struct buffer *b; - - if (size == 0) - fatalx("zero size"); - - b = xcalloc(1, sizeof *b); - - b->base = xmalloc(size); - b->space = size; - - return (b); -} - -/* Destroy a buffer. */ -void -buffer_destroy(struct buffer *b) -{ - xfree(b->base); - xfree(b); -} - -/* Ensure free space for size in buffer. */ -void -buffer_ensure(struct buffer *b, size_t size) -{ - if (size == 0) - fatalx("zero size"); - - if (BUFFER_FREE(b) >= size) - return; - - if (b->off > 0) { - if (b->size > 0) - memmove(b->base, b->base + b->off, b->size); - b->off = 0; - } - - if (SIZE_MAX - b->size < size) - fatalx("size too big"); - while (b->space < b->size + size) { - b->base = xrealloc(b->base, 2, b->space); - b->space *= 2; - } -} - -/* Adjust buffer after data appended. */ -void -buffer_add(struct buffer *b, size_t size) -{ - if (size == 0) - fatalx("zero size"); - if (size > b->space - b->size) - fatalx("overflow"); - - b->size += size; -} - -/* Adjust buffer after data removed. */ -void -buffer_remove(struct buffer *b, size_t size) -{ - if (size == 0) - fatalx("zero size"); - if (size > b->size) - fatalx("underflow"); - - b->size -= size; - b->off += size; -} - -/* Copy data into a buffer. */ -void -buffer_write(struct buffer *b, const void *data, size_t size) -{ - buffer_ensure(b, size); - memcpy(BUFFER_IN(b), data, size); - buffer_add(b, size); -} - -/* Copy data out of a buffer. */ -void -buffer_read(struct buffer *b, void *data, size_t size) -{ - if (size == 0) - fatalx("zero size"); - if (size > b->size) - fatalx("underflow"); - - memcpy(data, BUFFER_OUT(b), size); - buffer_remove(b, size); -} - -/* Store an 8-bit value. */ -void -buffer_write8(struct buffer *b, uint8_t n) -{ - buffer_ensure(b, 1); - BUFFER_IN(b)[0] = n; - b->size++; -} - -/* Extract an 8-bit value. */ -uint8_t -buffer_read8(struct buffer *b) -{ - uint8_t n; - - n = BUFFER_OUT(b)[0]; - buffer_remove(b, 1); - return (n); -} diff --git a/tmux.h b/tmux.h index 8940d381..f5056e1f 100644 --- a/tmux.h +++ b/tmux.h @@ -96,21 +96,6 @@ extern char **environ; #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) #endif -/* Buffer macros. */ -#define BUFFER_USED(b) ((b)->size) -#define BUFFER_FREE(b) ((b)->space - (b)->off - (b)->size) -#define BUFFER_IN(b) ((b)->base + (b)->off + (b)->size) -#define BUFFER_OUT(b) ((b)->base + (b)->off) - -/* Buffer structure. */ -struct buffer { - u_char *base; /* buffer start */ - size_t space; /* total size of buffer */ - - size_t size; /* size of data in buffer */ - size_t off; /* offset of data in buffer */ -}; - /* Bell option values. */ #define BELL_NONE 0 #define BELL_ANY 1 @@ -1908,20 +1893,6 @@ int utf8_append(struct utf8_data *, u_char); /* procname.c */ char *get_proc_name(int, char *); -/* buffer.c */ -struct buffer *buffer_create(size_t); -void buffer_destroy(struct buffer *); -void buffer_ensure(struct buffer *, size_t); -void buffer_add(struct buffer *, size_t); -void buffer_remove(struct buffer *, size_t); -void buffer_write(struct buffer *, const void *, size_t); -void buffer_read(struct buffer *, void *, size_t); -void buffer_write8(struct buffer *, uint8_t); -uint8_t buffer_read8(struct buffer *); - -/* buffer-poll.c */ -int buffer_poll(int, int, struct buffer *, struct buffer *); - /* log.c */ void log_open_tty(int); void log_open_file(int, const char *); From fde36fccc3a5da0a9b9e467c826403d2c5dfe75e Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 4 Nov 2009 22:47:34 +0000 Subject: [PATCH 0500/1180] Tell the client to exit on configuration file error. --- server.c | 1 + 1 file changed, 1 insertion(+) diff --git a/server.c b/server.c index b4c5a8d2..eb215009 100644 --- a/server.c +++ b/server.c @@ -193,6 +193,7 @@ error: c = ARRAY_FIRST(&clients); server_write_error(c, cause); + server_write_client(c, MSG_EXIT, NULL, 0); xfree(cause); server_shutdown = 1; From 862fe15c32d30cf2769592fd225507acfd49aad1 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 4 Nov 2009 22:57:49 +0000 Subject: [PATCH 0501/1180] Move some common code into a function. --- client.c | 41 +++++++++++++++++++---------------------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/client.c b/client.c index 60fef91a..afa48048 100644 --- a/client.c +++ b/client.c @@ -41,6 +41,7 @@ const char *client_exitmsg; void client_send_identify(int); void client_send_environ(void); void client_write_server(enum msgtype, void *, size_t); +void client_update_event(void); void client_signal(int, short, void *); void client_callback(int, short, void *); int client_dispatch(void); @@ -154,12 +155,24 @@ client_write_server(enum msgtype type, void *buf, size_t len) imsg_compose(&client_ibuf, type, PROTOCOL_VERSION, -1, -1, buf, len); } +void +client_update_event(void) +{ + short events; + + event_del(&client_event); + events = EV_READ; + if (client_ibuf.w.queued > 0) + events |= EV_WRITE; + event_set(&client_event, client_ibuf.fd, events, client_callback, NULL); + event_add(&client_event, NULL); +} + __dead void client_main(void) { struct event ev_sigcont, ev_sigterm, ev_sigwinch; struct sigaction sigact; - short events; logfile("client"); @@ -197,13 +210,8 @@ client_main(void) if (client_dispatch() != 0) goto out; - /* Set up the client-server socket event. */ - events = EV_READ; - if (client_ibuf.w.queued > 0) - events |= EV_WRITE; - event_set(&client_event, client_ibuf.fd, events, client_callback, NULL); - event_add(&client_event, NULL); - + /* Set the event and dispatch. */ + client_update_event(); event_dispatch(); out: @@ -217,7 +225,7 @@ out: } void -client_signal(int sig, short events, unused void *data) +client_signal(int sig, unused short events, unused void *data) { struct sigaction sigact; @@ -240,12 +248,7 @@ client_signal(int sig, short events, unused void *data) break; } - event_del(&client_event); - events = EV_READ; - if (client_ibuf.w.queued > 0) - events |= EV_WRITE; - event_set(&client_event, client_ibuf.fd, events, client_callback, NULL); - event_add(&client_event, NULL); + client_update_event(); } void @@ -267,13 +270,7 @@ client_callback(unused int fd, short events, unused void *data) goto lost_server; } - event_del(&client_event); - events = EV_READ; - if (client_ibuf.w.queued > 0) - events |= EV_WRITE; - event_set(&client_event, client_ibuf.fd, events, client_callback, NULL); - event_add(&client_event, NULL); - + client_update_event(); return; lost_server: From 6a6a42aa3a6ebfedc428288babfb9e0b856d5732 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 4 Nov 2009 23:00:22 +0000 Subject: [PATCH 0502/1180] It would help if I read my own comments... make alt keys work again by sending alt AND the key not alt instead of it. --- input-keys.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/input-keys.c b/input-keys.c index e8a163a0..35834571 100644 --- a/input-keys.c +++ b/input-keys.c @@ -173,9 +173,8 @@ input_key(struct window_pane *wp, int key) */ if (key != KEYC_NONE && (key & ~KEYC_ESCAPE) < 0x100) { if (key & KEYC_ESCAPE) - ch = '\033'; - else - ch = key & ~KEYC_ESCAPE; + bufferevent_write(wp->event, "\033", 1); + ch = key & ~KEYC_ESCAPE; bufferevent_write(wp->event, &ch, 1); return; } From b3c4956efeb62bae3c9ac64eab2371bb6384623a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 4 Nov 2009 23:12:43 +0000 Subject: [PATCH 0503/1180] Don't reenlist the client imsg event every loop, instead have a small function to it and call it after the event triggers or after a imsg is added. --- server-client.c | 28 +++------------------------- server-fn.c | 16 ++++++++++++++++ server.c | 6 ++---- tmux.h | 2 +- 4 files changed, 22 insertions(+), 30 deletions(-) diff --git a/server-client.c b/server-client.c index f839c305..2d5701f5 100644 --- a/server-client.c +++ b/server-client.c @@ -61,6 +61,7 @@ server_client_create(int fd) c = xcalloc(1, sizeof *c); c->references = 0; imsg_init(&c->ibuf, fd); + server_update_event(c); if (gettimeofday(&c->creation_time, NULL) != 0) fatal("gettimeofday failed"); @@ -150,30 +151,6 @@ server_client_lost(struct client *c) recalculate_sizes(); } -/* Register clients for poll. */ -void -server_client_prepare(void) -{ - struct client *c; - u_int i; - int events; - - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - if ((c = ARRAY_ITEM(&clients, i)) == NULL) - continue; - - events = 0; - if (!(c->flags & CLIENT_BAD)) - events |= EV_READ; - if (c->ibuf.w.queued > 0) - events |= EV_WRITE; - event_del(&c->event); - event_set(&c->event, - c->ibuf.fd, events, server_client_callback, c); - event_add(&c->event, NULL); - } -} - /* Process a single client event. */ void server_client_callback(int fd, short events, void *data) @@ -196,7 +173,8 @@ server_client_callback(int fd, short events, void *data) if (events & EV_READ && server_client_msg_dispatch(c) != 0) goto client_lost; } - + + server_update_event(c); return; client_lost: diff --git a/server-fn.c b/server-fn.c index f4f71980..66845b91 100644 --- a/server-fn.c +++ b/server-fn.c @@ -59,6 +59,7 @@ server_write_client( return; log_debug("writing %d to client %d", type, c->ibuf.fd); imsg_compose(ibuf, type, PROTOCOL_VERSION, -1, -1, (void *) buf, len); + server_update_event(c); } void @@ -371,3 +372,18 @@ server_clear_identify(struct client *c) server_redraw_client(c); } } + +void +server_update_event(struct client *c) +{ + short events; + + events = 0; + if (!(c->flags & CLIENT_BAD)) + events |= EV_READ; + if (c->ibuf.w.queued > 0) + events |= EV_WRITE; + event_del(&c->event); + event_set(&c->event, c->ibuf.fd, events, server_client_callback, c); + event_add(&c->event, NULL); +} diff --git a/server.c b/server.c index eb215009..4c1f9cea 100644 --- a/server.c +++ b/server.c @@ -160,11 +160,11 @@ server_start(char *path) log_debug("socket path %s", socket_path); setproctitle("server (%s)", rpathbuf); + event_init(); + server_fd = server_create_socket(); server_client_create(pair[1]); - event_init(); - if (access(SYSTEM_CFG, R_OK) == 0) { if (load_cfg(SYSTEM_CFG, NULL, &cause) != 0) goto error; @@ -215,8 +215,6 @@ server_loop(void) while (!server_should_shutdown()) { server_update_socket(); - server_client_prepare(); - event_loopexit(&tv); event_loop(EVLOOP_ONCE); diff --git a/tmux.h b/tmux.h index f5056e1f..4603af4d 100644 --- a/tmux.h +++ b/tmux.h @@ -1564,7 +1564,6 @@ void server_signal_clear(void); /* server-client.c */ void server_client_create(int); void server_client_lost(struct client *); -void server_client_prepare(void); void server_client_callback(int, short, void *); void server_client_loop(void); @@ -1598,6 +1597,7 @@ void server_destroy_session_group(struct session *); void server_destroy_session(struct session *); void server_set_identify(struct client *); void server_clear_identify(struct client *); +void server_update_event(struct client *); /* status.c */ int status_redraw(struct client *); From b1264a7416789dad8fad1b4b00a63f99b1ca25e5 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 4 Nov 2009 23:29:42 +0000 Subject: [PATCH 0504/1180] Use timeout events for the identify and message timers. --- server-client.c | 9 +++------ server-fn.c | 18 ++++++++++++++---- status.c | 17 +++++++++++++---- tmux.h | 4 ++-- 4 files changed, 32 insertions(+), 16 deletions(-) diff --git a/server-client.c b/server-client.c index 2d5701f5..ec243300 100644 --- a/server-client.c +++ b/server-client.c @@ -120,8 +120,11 @@ server_client_lost(struct client *c) if (c->title != NULL) xfree(c->title); + evtimer_del(&c->identify_timer); + if (c->message_string != NULL) xfree(c->message_string); + evtimer_del(&c->message_timer); if (c->prompt_string != NULL) xfree(c->prompt_string); @@ -448,12 +451,6 @@ server_client_check_timers(struct client *c) if (gettimeofday(&tv, NULL) != 0) fatal("gettimeofday failed"); - if (c->flags & CLIENT_IDENTIFY && timercmp(&tv, &c->identify_timer, >)) - server_clear_identify(c); - - if (c->message_string != NULL && timercmp(&tv, &c->message_timer, >)) - status_message_clear(c); - if (c->message_string != NULL || c->prompt_string != NULL) { /* * Don't need timed redraw for messages/prompts so bail now. diff --git a/server-fn.c b/server-fn.c index 66845b91..f31e1337 100644 --- a/server-fn.c +++ b/server-fn.c @@ -24,6 +24,8 @@ #include "tmux.h" +void server_callback_identify(int, short, void *); + void server_fill_environ(struct session *s, struct environ *env) { @@ -353,10 +355,10 @@ server_set_identify(struct client *c) delay = options_get_number(&c->session->options, "display-panes-time"); tv.tv_sec = delay / 1000; tv.tv_usec = (delay % 1000) * 1000L; - - if (gettimeofday(&c->identify_timer, NULL) != 0) - fatal("gettimeofday failed"); - timeradd(&c->identify_timer, &tv, &c->identify_timer); + + evtimer_del(&c->identify_timer); + evtimer_set(&c->identify_timer, server_callback_identify, c); + evtimer_add(&c->identify_timer, &tv); c->flags |= CLIENT_IDENTIFY; c->tty.flags |= (TTY_FREEZE|TTY_NOCURSOR); @@ -373,6 +375,14 @@ server_clear_identify(struct client *c) } } +void +server_callback_identify(unused int fd, unused short events, void *data) +{ + struct client *c = data; + + server_clear_identify(c); +} + void server_update_event(struct client *c) { diff --git a/status.c b/status.c index 4b0c81fb..deb3a621 100644 --- a/status.c +++ b/status.c @@ -33,6 +33,7 @@ char *status_job(struct client *, char **); void status_job_callback(struct job *); size_t status_width(struct winlink *); char *status_print(struct session *, struct winlink *, struct grid_cell *); +void status_message_callback(int, short, void *); void status_prompt_add_history(struct client *); char *status_prompt_complete(const char *); @@ -579,10 +580,10 @@ status_message_set(struct client *c, const char *fmt, ...) delay = options_get_number(&c->session->options, "display-time"); tv.tv_sec = delay / 1000; tv.tv_usec = (delay % 1000) * 1000L; - - if (gettimeofday(&c->message_timer, NULL) != 0) - fatal("gettimeofday failed"); - timeradd(&c->message_timer, &tv, &c->message_timer); + + evtimer_del(&c->message_timer); + evtimer_set(&c->message_timer, status_message_callback, c); + evtimer_add(&c->message_timer, &tv); c->tty.flags |= (TTY_NOCURSOR|TTY_FREEZE); c->flags |= CLIENT_STATUS; @@ -603,6 +604,14 @@ status_message_clear(struct client *c) screen_reinit(&c->status); } +void +status_message_callback(unused int fd, unused short event, void *data) +{ + struct client *c = data; + + status_message_clear(c); +} + /* Draw client message on status line of present else on last line. */ int status_message_redraw(struct client *c) diff --git a/tmux.h b/tmux.h index 4603af4d..d33cb634 100644 --- a/tmux.h +++ b/tmux.h @@ -1074,10 +1074,10 @@ struct client { #define CLIENT_DEAD 0x200 int flags; - struct timeval identify_timer; + struct event identify_timer; char *message_string; - struct timeval message_timer; + struct event message_timer; char *prompt_string; char *prompt_buffer; From 946ed972734f5c95f67e30aff99a58de0179b2d5 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 4 Nov 2009 23:42:51 +0000 Subject: [PATCH 0505/1180] Move status timer check into the global once-per-second timer, this could maybe be done better but one every second is better than once every 50 ms. --- server-client.c | 80 ++++++++++++++++++++++++------------------------- server.c | 2 ++ tmux.h | 1 + 3 files changed, 43 insertions(+), 40 deletions(-) diff --git a/server-client.c b/server-client.c index ec243300..f44dc02c 100644 --- a/server-client.c +++ b/server-client.c @@ -30,7 +30,6 @@ void server_client_handle_data(struct client *); void server_client_check_redraw(struct client *); void server_client_set_title(struct client *); -void server_client_check_timers(struct client *); int server_client_msg_dispatch(struct client *); void server_client_msg_command(struct client *, struct msg_command_data *); @@ -184,6 +183,45 @@ client_lost: server_client_lost(c); } +/* Handle client status timer. */ +void +server_client_status_timer(void) +{ + struct client *c; + struct session *s; + struct job *job; + struct timeval tv; + u_int i, interval; + + if (gettimeofday(&tv, NULL) != 0) + fatal("gettimeofday failed"); + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c == NULL || c->session == NULL) + continue; + if (c->message_string != NULL || c->prompt_string != NULL) { + /* + * Don't need timed redraw for messages/prompts so bail + * now. The status timer isn't reset when they are + * redrawn anyway. + */ + continue; + } + s = c->session; + + if (!options_get_number(&s->options, "status")) + continue; + interval = options_get_number(&s->options, "status-interval"); + + if (tv.tv_sec - c->status_timer.tv_sec >= interval) { + RB_FOREACH(job, jobs, &c->status_jobs) + job_run(job); + c->flags |= CLIENT_STATUS; + } + } +} + /* Client functions that need to happen every loop. */ void server_client_loop(void) @@ -199,10 +237,8 @@ server_client_loop(void) continue; server_client_handle_data(c); - if (c->session != NULL) { - server_client_check_timers(c); + if (c->session != NULL) server_client_check_redraw(c); - } } /* @@ -439,42 +475,6 @@ server_client_set_title(struct client *c) xfree(title); } -/* Check client timers. */ -void -server_client_check_timers(struct client *c) -{ - struct session *s = c->session; - struct job *job; - struct timeval tv; - u_int interval; - - if (gettimeofday(&tv, NULL) != 0) - fatal("gettimeofday failed"); - - if (c->message_string != NULL || c->prompt_string != NULL) { - /* - * Don't need timed redraw for messages/prompts so bail now. - * The status timer isn't reset when they are redrawn anyway. - */ - return; - - } - if (!options_get_number(&s->options, "status")) - return; - - /* Check timer; resolution is only a second so don't be too clever. */ - interval = options_get_number(&s->options, "status-interval"); - if (interval == 0) - return; - if (tv.tv_sec < c->status_timer.tv_sec || - ((u_int) tv.tv_sec) - c->status_timer.tv_sec >= interval) { - /* Run the jobs for this client and schedule for redraw. */ - RB_FOREACH(job, jobs, &c->status_jobs) - job_run(job); - c->flags |= CLIENT_STATUS; - } -} - /* Dispatch message from client. */ int server_client_msg_dispatch(struct client *c) diff --git a/server.c b/server.c index 4c1f9cea..a34d9b02 100644 --- a/server.c +++ b/server.c @@ -520,6 +520,8 @@ server_second_callback(unused int fd, unused short events, unused void *arg) } } + server_client_status_timer(); + evtimer_del(&server_ev_second); memset(&tv, 0, sizeof tv); tv.tv_sec = 1; diff --git a/tmux.h b/tmux.h index d33cb634..2839dd29 100644 --- a/tmux.h +++ b/tmux.h @@ -1565,6 +1565,7 @@ void server_signal_clear(void); void server_client_create(int); void server_client_lost(struct client *); void server_client_callback(int, short, void *); +void server_client_status_timer(void); void server_client_loop(void); /* server-window.c */ From 44d6a2c435ab68df25ed7b14473e6f69870e8a9a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 4 Nov 2009 23:54:57 +0000 Subject: [PATCH 0506/1180] Change window name change to use a timer event rather than a gettimeofday() check every loop. --- names.c | 101 +++++++++++++++++++++++------------------------- server-window.c | 2 - tmux.h | 4 +- window.c | 13 +++---- 4 files changed, 56 insertions(+), 64 deletions(-) diff --git a/names.c b/names.c index fe26938d..d9335ac5 100644 --- a/names.c +++ b/names.c @@ -25,67 +25,64 @@ #include "tmux.h" +void window_name_callback(unused int, unused short, void *); char *parse_window_name(const char *); void -set_window_names(void) +queue_window_name(struct window *w) { - struct window *w; - u_int i; + struct timeval tv; + + tv.tv_sec = 0; + tv.tv_usec = NAME_INTERVAL * 1000L; + + evtimer_del(&w->name_timer); + evtimer_set(&w->name_timer, window_name_callback, w); + evtimer_add(&w->name_timer, &tv); +} + +void +window_name_callback(unused int fd, unused short events, void *data) +{ + struct window *w = data; char *name, *wname; - struct timeval tv, tv2; - if (gettimeofday(&tv, NULL) != 0) - fatal("gettimeofday failed"); + queue_window_name(w); /* XXX even if the option is off? */ + if (!options_get_number(&w->options, "automatic-rename")) + return; - for (i = 0; i < ARRAY_LENGTH(&windows); i++) { - w = ARRAY_ITEM(&windows, i); - if (w == NULL || w->active == NULL) - continue; - - if (timercmp(&tv, &w->name_timer, <)) - continue; - memcpy(&w->name_timer, &tv, sizeof w->name_timer); - tv2.tv_sec = 0; - tv2.tv_usec = NAME_INTERVAL * 1000L; - timeradd(&w->name_timer, &tv2, &w->name_timer); - - if (!options_get_number(&w->options, "automatic-rename")) - continue; - - if (w->active->screen != &w->active->base) - name = NULL; + if (w->active->screen != &w->active->base) + name = NULL; + else + name = get_proc_name(w->active->fd, w->active->tty); + if (name == NULL) + wname = default_window_name(w); + else { + /* + * If tmux is using the default command, it will be a login + * shell and argv[0] may have a - prefix. Remove this if it is + * present. Ick. + */ + if (w->active->cmd != NULL && *w->active->cmd == '\0' && + name != NULL && name[0] == '-' && name[1] != '\0') + wname = parse_window_name(name + 1); else - name = get_proc_name(w->active->fd, w->active->tty); - if (name == NULL) - wname = default_window_name(w); - else { - /* - * If tmux is using the default command, it will be a - * login shell and argv[0] may have a - prefix. Remove - * this if it is present. Ick. - */ - if (w->active->cmd != NULL && *w->active->cmd == '\0' && - name != NULL && name[0] == '-' && name[1] != '\0') - wname = parse_window_name(name + 1); - else wname = parse_window_name(name); - xfree(name); - } - - if (w->active->fd == -1) { - xasprintf(&name, "%s[dead]", wname); - xfree(wname); - wname = name; - } - - if (strcmp(wname, w->name) == 0) - xfree(wname); - else { - xfree(w->name); - w->name = wname; - server_status_window(w); - } + xfree(name); + } + + if (w->active->fd == -1) { + xasprintf(&name, "%s[dead]", wname); + xfree(wname); + wname = name; + } + + if (strcmp(wname, w->name) == 0) + xfree(wname); + else { + xfree(w->name); + w->name = wname; + server_status_window(w); } } diff --git a/server-window.c b/server-window.c index d0eb7960..020af041 100644 --- a/server-window.c +++ b/server-window.c @@ -91,8 +91,6 @@ server_window_loop(void) server_window_check_alive(w); } - - set_window_names(); } /* Check for bell in window. */ diff --git a/tmux.h b/tmux.h index 2839dd29..39072a65 100644 --- a/tmux.h +++ b/tmux.h @@ -810,7 +810,7 @@ TAILQ_HEAD(window_panes, window_pane); /* Window structure. */ struct window { char *name; - struct timeval name_timer; + struct event name_timer; struct window_pane *active; struct window_panes panes; @@ -1851,7 +1851,7 @@ void window_choose_ready(struct window_pane *, u_int, void (*)(void *, int), void (*)(void *), void *); /* names.c */ -void set_window_names(void); +void queue_window_name(struct window *); char *default_window_name(struct window *); /* session.c */ diff --git a/window.c b/window.c index fca94df8..b550fc65 100644 --- a/window.c +++ b/window.c @@ -212,7 +212,7 @@ window_create1(u_int sx, u_int sy) struct window *w; u_int i; - w = xmalloc(sizeof *w); + w = xcalloc(1, sizeof *w); w->name = NULL; w->flags = 0; @@ -225,6 +225,8 @@ window_create1(u_int sx, u_int sy) w->sx = sx; w->sy = sy; + queue_window_name(w); + options_init(&w->options, &global_w_options); for (i = 0; i < ARRAY_LENGTH(&windows); i++) { @@ -278,6 +280,8 @@ window_destroy(struct window *w) if (w->layout_root != NULL) layout_free(w); + evtimer_del(&w->name_timer); + options_free(&w->options); window_destroy_panes(w); @@ -480,7 +484,6 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell, ARRAY_DECL(, char *) varlist; struct environ_entry *envent; const char *ptr; - struct timeval tv; struct termios tio2; u_int i; @@ -508,12 +511,6 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell, ws.ws_col = screen_size_x(&wp->base); ws.ws_row = screen_size_y(&wp->base); - if (gettimeofday(&wp->window->name_timer, NULL) != 0) - fatal("gettimeofday failed"); - tv.tv_sec = 0; - tv.tv_usec = NAME_INTERVAL * 1000L; - timeradd(&wp->window->name_timer, &tv, &wp->window->name_timer); - switch (wp->pid = forkpty(&wp->fd, wp->tty, NULL, &ws)) { case -1: wp->fd = -1; From 80444436f36724cc8ef306391b5b18be604109c8 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 5 Nov 2009 00:05:00 +0000 Subject: [PATCH 0507/1180] Convert the key repeat timer to an event. --- server-client.c | 31 +++++++++++++++++++++---------- tmux.h | 2 +- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/server-client.c b/server-client.c index f44dc02c..5c15d502 100644 --- a/server-client.c +++ b/server-client.c @@ -28,6 +28,7 @@ #include "tmux.h" void server_client_handle_data(struct client *); +void server_client_repeat_timer(int, short, void *); void server_client_check_redraw(struct client *); void server_client_set_title(struct client *); @@ -41,7 +42,6 @@ void printflike2 server_client_msg_error(struct cmd_ctx *, const char *, ...); void printflike2 server_client_msg_print(struct cmd_ctx *, const char *, ...); void printflike2 server_client_msg_info(struct cmd_ctx *, const char *, ...); - /* Create a new client. */ void server_client_create(int fd) @@ -84,6 +84,8 @@ server_client_create(int fd) c->prompt_buffer = NULL; c->prompt_index = 0; + evtimer_set(&c->repeat_timer, server_client_repeat_timer, c); + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { if (ARRAY_ITEM(&clients, i) == NULL) { ARRAY_SET(&clients, i, c); @@ -119,6 +121,8 @@ server_client_lost(struct client *c) if (c->title != NULL) xfree(c->title); + evtimer_del(&c->repeat_timer); + evtimer_del(&c->identify_timer); if (c->message_string != NULL) @@ -264,21 +268,17 @@ server_client_handle_data(struct client *c) struct window_pane *wp; struct screen *s; struct options *oo; - struct timeval tv_add, tv_now; + struct timeval tv, tv_now; struct key_binding *bd; struct keylist *keylist; struct mouse_event mouse; int key, status, xtimeout, mode, isprefix; u_int i; - /* Check and update repeat flag. */ + /* Get the time for the activity timer. */ if (gettimeofday(&tv_now, NULL) != 0) fatal("gettimeofday failed"); xtimeout = options_get_number(&c->session->options, "repeat-time"); - if (xtimeout != 0 && c->flags & CLIENT_REPEAT) { - if (timercmp(&tv_now, &c->repeat_timer, >)) - c->flags &= ~(CLIENT_PREFIX|CLIENT_REPEAT); - } /* Process keys. */ keylist = options_get_data(&c->session->options, "prefix"); @@ -371,9 +371,10 @@ server_client_handle_data(struct client *c) if (xtimeout != 0 && bd->can_repeat) { c->flags |= CLIENT_PREFIX|CLIENT_REPEAT; - tv_add.tv_sec = xtimeout / 1000; - tv_add.tv_usec = (xtimeout % 1000) * 1000L; - timeradd(&tv_now, &tv_add, &c->repeat_timer); + tv.tv_sec = xtimeout / 1000; + tv.tv_usec = (xtimeout % 1000) * 1000L; + evtimer_del(&c->repeat_timer); + evtimer_add(&c->repeat_timer, &tv); } /* Dispatch the command. */ @@ -412,6 +413,16 @@ server_client_handle_data(struct client *c) tty_reset(&c->tty); } +/* Repeat time callback. */ +void +server_client_repeat_timer(unused int fd, unused short events, void *data) +{ + struct client *c = data; + + if (c->flags & CLIENT_REPEAT) + c->flags &= ~(CLIENT_PREFIX|CLIENT_REPEAT); +} + /* Check for client redraws. */ void server_client_check_redraw(struct client *c) diff --git a/tmux.h b/tmux.h index 39072a65..f3263f4a 100644 --- a/tmux.h +++ b/tmux.h @@ -1056,7 +1056,7 @@ struct client { char *cwd; struct tty tty; - struct timeval repeat_timer; + struct event repeat_timer; struct timeval status_timer; struct jobs status_jobs; From b58bf49e913e61a4991c35257dd82e5dd4c907a2 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 5 Nov 2009 08:45:08 +0000 Subject: [PATCH 0508/1180] Switch tty key input over to happen on a read event. This is a bit more complicated because of escape input, but in that case instead of processing a key immediately, schedule a timer and reprocess the bufer when it expires. This currently assumes that keys will be atomic (ie that if eg F1 is pressed the entire sequence is present in the buffer). This is usually but not always true, a change in the tree format so it can differentiate potential (partial) key sequences will happens soon and will allow this to be fixed. --- server-client.c | 280 ++++++++++++++++++++++++------------------------ tmux.h | 6 +- tty-keys.c | 91 +++++++++------- tty.c | 13 ++- 4 files changed, 210 insertions(+), 180 deletions(-) diff --git a/server-client.c b/server-client.c index 5c15d502..dd386001 100644 --- a/server-client.c +++ b/server-client.c @@ -27,10 +27,11 @@ #include "tmux.h" -void server_client_handle_data(struct client *); +void server_client_handle_key(int, struct mouse_event *, void *); void server_client_repeat_timer(int, short, void *); void server_client_check_redraw(struct client *); void server_client_set_title(struct client *); +void server_client_reset_state(struct client *); int server_client_msg_dispatch(struct client *); void server_client_msg_command(struct client *, struct msg_command_data *); @@ -226,6 +227,127 @@ server_client_status_timer(void) } } +/* Handle data key input from client. */ +void +server_client_handle_key(int key, struct mouse_event *mouse, void *data) +{ + struct client *c = data; + struct session *s; + struct window *w; + struct window_pane *wp; + struct options *oo; + struct timeval tv; + struct key_binding *bd; + struct keylist *keylist; + int xtimeout, isprefix; + u_int i; + + /* Check the client is good to accept input. */ + if ((c->flags & (CLIENT_DEAD|CLIENT_SUSPENDED)) != 0) + return; + if (c->session == NULL) + return; + s = c->session; + + /* Update the activity timer. */ + if (gettimeofday(&c->activity_time, NULL) != 0) + fatal("gettimeofday failed"); + memcpy(&s->activity_time, &c->activity_time, sizeof s->activity_time); + + w = c->session->curw->window; + wp = w->active; + oo = &c->session->options; + + /* Special case: number keys jump to pane in identify mode. */ + if (c->flags & CLIENT_IDENTIFY && key >= '0' && key <= '9') { + wp = window_pane_at_index(w, key - '0'); + if (wp != NULL && window_pane_visible(wp)) + window_set_active_pane(w, wp); + server_clear_identify(c); + return; + } + + /* Handle status line. */ + status_message_clear(c); + server_clear_identify(c); + if (c->prompt_string != NULL) { + status_prompt_key(c, key); + return; + } + + /* Check for mouse keys. */ + if (key == KEYC_MOUSE) { + if (options_get_number(oo, "mouse-select-pane")) { + window_set_active_at(w, mouse->x, mouse->y); + wp = w->active; + } + window_pane_mouse(wp, c, mouse); + return; + } + + /* Is this a prefix key? */ + keylist = options_get_data(&c->session->options, "prefix"); + isprefix = 0; + for (i = 0; i < ARRAY_LENGTH(keylist); i++) { + if (key == ARRAY_ITEM(keylist, i)) { + isprefix = 1; + break; + } + } + + /* No previous prefix key. */ + if (!(c->flags & CLIENT_PREFIX)) { + if (isprefix) + c->flags |= CLIENT_PREFIX; + else { + /* Try as a non-prefix key binding. */ + if ((bd = key_bindings_lookup(key)) == NULL) + window_pane_key(wp, c, key); + else + key_bindings_dispatch(bd, c); + } + return; + } + + /* Prefix key already pressed. Reset prefix and lookup key. */ + c->flags &= ~CLIENT_PREFIX; + if ((bd = key_bindings_lookup(key | KEYC_PREFIX)) == NULL) { + /* If repeating, treat this as a key, else ignore. */ + if (c->flags & CLIENT_REPEAT) { + c->flags &= ~CLIENT_REPEAT; + if (isprefix) + c->flags |= CLIENT_PREFIX; + else + window_pane_key(wp, c, key); + } + return; + } + + /* If already repeating, but this key can't repeat, skip it. */ + if (c->flags & CLIENT_REPEAT && !bd->can_repeat) { + c->flags &= ~CLIENT_REPEAT; + if (isprefix) + c->flags |= CLIENT_PREFIX; + else + window_pane_key(wp, c, key); + return; + } + + /* If this key can repeat, reset the repeat flags and timer. */ + xtimeout = options_get_number(&c->session->options, "repeat-time"); + if (xtimeout != 0 && bd->can_repeat) { + c->flags |= CLIENT_PREFIX|CLIENT_REPEAT; + + tv.tv_sec = xtimeout / 1000; + tv.tv_usec = (xtimeout % 1000) * 1000L; + evtimer_del(&c->repeat_timer); + evtimer_add(&c->repeat_timer, &tv); + } + + /* Dispatch the command. */ + key_bindings_dispatch(bd, c); +} + /* Client functions that need to happen every loop. */ void server_client_loop(void) @@ -240,9 +362,8 @@ server_client_loop(void) if (c == NULL || c->session == NULL) continue; - server_client_handle_data(c); - if (c->session != NULL) - server_client_check_redraw(c); + server_client_check_redraw(c); + server_client_reset_state(c); } /* @@ -260,143 +381,24 @@ server_client_loop(void) } } -/* Handle data input or output from client. */ +/* + * Update cursor position and mode settings. The scroll region and attributes + * are cleared when idle (waiting for an event) as this is the most likely time + * a user may interrupt tmux, for example with ~^Z in ssh(1). This is a + * compromise between excessive resets and likelihood of an interrupt. + * + * tty_region/tty_reset/tty_update_mode already take care of not resetting + * things that are already in their default state. + */ void -server_client_handle_data(struct client *c) +server_client_reset_state(struct client *c) { - struct window *w; - struct window_pane *wp; - struct screen *s; - struct options *oo; - struct timeval tv, tv_now; - struct key_binding *bd; - struct keylist *keylist; - struct mouse_event mouse; - int key, status, xtimeout, mode, isprefix; - u_int i; + struct window *w = c->session->curw->window; + struct window_pane *wp = w->active; + struct screen *s = wp->screen; + struct options *oo = &c->session->options; + int status, mode; - /* Get the time for the activity timer. */ - if (gettimeofday(&tv_now, NULL) != 0) - fatal("gettimeofday failed"); - xtimeout = options_get_number(&c->session->options, "repeat-time"); - - /* Process keys. */ - keylist = options_get_data(&c->session->options, "prefix"); - while (tty_keys_next(&c->tty, &key, &mouse) == 0) { - if (c->session == NULL) - return; - w = c->session->curw->window; - wp = w->active; /* could die */ - oo = &c->session->options; - - /* Update activity timer. */ - memcpy(&c->activity_time, &tv_now, sizeof c->activity_time); - memcpy(&c->session->activity_time, - &tv_now, sizeof c->session->activity_time); - - /* Special case: number keys jump to pane in identify mode. */ - if (c->flags & CLIENT_IDENTIFY && key >= '0' && key <= '9') { - wp = window_pane_at_index(w, key - '0'); - if (wp != NULL && window_pane_visible(wp)) - window_set_active_pane(w, wp); - server_clear_identify(c); - continue; - } - - status_message_clear(c); - server_clear_identify(c); - if (c->prompt_string != NULL) { - status_prompt_key(c, key); - continue; - } - - /* Check for mouse keys. */ - if (key == KEYC_MOUSE) { - if (options_get_number(oo, "mouse-select-pane")) { - window_set_active_at(w, mouse.x, mouse.y); - wp = w->active; - } - window_pane_mouse(wp, c, &mouse); - continue; - } - - /* Is this a prefix key? */ - isprefix = 0; - for (i = 0; i < ARRAY_LENGTH(keylist); i++) { - if (key == ARRAY_ITEM(keylist, i)) { - isprefix = 1; - break; - } - } - - /* No previous prefix key. */ - if (!(c->flags & CLIENT_PREFIX)) { - if (isprefix) - c->flags |= CLIENT_PREFIX; - else { - /* Try as a non-prefix key binding. */ - if ((bd = key_bindings_lookup(key)) == NULL) - window_pane_key(wp, c, key); - else - key_bindings_dispatch(bd, c); - } - continue; - } - - /* Prefix key already pressed. Reset prefix and lookup key. */ - c->flags &= ~CLIENT_PREFIX; - if ((bd = key_bindings_lookup(key | KEYC_PREFIX)) == NULL) { - /* If repeating, treat this as a key, else ignore. */ - if (c->flags & CLIENT_REPEAT) { - c->flags &= ~CLIENT_REPEAT; - if (isprefix) - c->flags |= CLIENT_PREFIX; - else - window_pane_key(wp, c, key); - } - continue; - } - - /* If already repeating, but this key can't repeat, skip it. */ - if (c->flags & CLIENT_REPEAT && !bd->can_repeat) { - c->flags &= ~CLIENT_REPEAT; - if (isprefix) - c->flags |= CLIENT_PREFIX; - else - window_pane_key(wp, c, key); - continue; - } - - /* If this key can repeat, reset the repeat flags and timer. */ - if (xtimeout != 0 && bd->can_repeat) { - c->flags |= CLIENT_PREFIX|CLIENT_REPEAT; - - tv.tv_sec = xtimeout / 1000; - tv.tv_usec = (xtimeout % 1000) * 1000L; - evtimer_del(&c->repeat_timer); - evtimer_add(&c->repeat_timer, &tv); - } - - /* Dispatch the command. */ - key_bindings_dispatch(bd, c); - } - if (c->session == NULL) - return; - w = c->session->curw->window; - wp = w->active; - oo = &c->session->options; - s = wp->screen; - - /* - * Update cursor position and mode settings. The scroll region and - * attributes are cleared across poll(2) as this is the most likely - * time a user may interrupt tmux, for example with ~^Z in ssh(1). This - * is a compromise between excessive resets and likelihood of an - * interrupt. - * - * tty_region/tty_reset/tty_update_mode already take care of not - * resetting things that are already in their default state. - */ tty_region(&c->tty, 0, c->tty.sy - 1); status = options_get_number(oo, "status"); @@ -715,6 +717,8 @@ server_client_msg_identify( c->tty.term_flags |= TERM_256COLOURS; else if (data->flags & IDENTIFY_88COLOURS) c->tty.term_flags |= TERM_88COLOURS; + c->tty.key_callback = server_client_handle_key; + c->tty.key_data = c; tty_resize(&c->tty); diff --git a/tmux.h b/tmux.h index f3263f4a..f1b0f7ac 100644 --- a/tmux.h +++ b/tmux.h @@ -1002,7 +1002,9 @@ struct tty { int term_flags; - struct timeval key_timer; + void (*key_callback)(int, struct mouse_event *, void *); + void *key_data; + struct event key_timer; size_t ksize; /* maximum key size */ RB_HEAD(tty_keys, tty_key) ktree; @@ -1360,7 +1362,7 @@ int tty_keys_cmp(struct tty_key *, struct tty_key *); RB_PROTOTYPE(tty_keys, tty_key, entry, tty_keys_cmp); void tty_keys_init(struct tty *); void tty_keys_free(struct tty *); -int tty_keys_next(struct tty *, int *, struct mouse_event *); +int tty_keys_next(struct tty *); /* options-cmd.c */ const char *set_option_print( diff --git a/tty-keys.c b/tty-keys.c index 995f2994..c5c14541 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -30,6 +30,7 @@ */ void tty_keys_add(struct tty *, const char *, int, int); +void tty_keys_callback(int, short, void *); int tty_keys_mouse(char *, size_t, size_t *, struct mouse_event *); struct tty_key_ent { @@ -294,25 +295,27 @@ tty_keys_find(struct tty *tty, char *buf, size_t len, size_t *size) } int -tty_keys_next(struct tty *tty, int *key, struct mouse_event *mouse) +tty_keys_next(struct tty *tty) { - struct tty_key *tk; - struct timeval tv; - char *buf; - u_char ch; - size_t len, size; - cc_t bspace; + struct tty_key *tk; + struct timeval tv; + struct mouse_event mouse; + char *buf; + size_t len, size; + cc_t bspace; + int key; + u_char ch; buf = EVBUFFER_DATA(tty->event->input); len = EVBUFFER_LENGTH(tty->event->input); if (len == 0) - return (1); + return (0); log_debug("keys are %zu (%.*s)", len, (int) len, buf); /* If a normal key, return it. */ if (*buf != '\033') { bufferevent_read(tty->event, &ch, 1); - *key = ch; + key = ch; /* * Check for backspace key using termios VERASE - the terminfo @@ -320,8 +323,8 @@ tty_keys_next(struct tty *tty, int *key, struct mouse_event *mouse) * used. termios should have a better idea. */ bspace = tty->tio.c_cc[VERASE]; - if (bspace != _POSIX_VDISABLE && *key == bspace) - *key = KEYC_BSPACE; + if (bspace != _POSIX_VDISABLE && key == bspace) + key = KEYC_BSPACE; goto found; } @@ -329,36 +332,24 @@ tty_keys_next(struct tty *tty, int *key, struct mouse_event *mouse) tk = tty_keys_find(tty, buf + 1, len - 1, &size); if (tk != NULL) { evbuffer_drain(tty->event->input, size + 1); - *key = tk->key; + key = tk->key; goto found; } /* Not found. Is this a mouse key press? */ - *key = tty_keys_mouse(buf, len, &size, mouse); - if (*key != KEYC_NONE) { + key = tty_keys_mouse(buf, len, &size, &mouse); + if (key != KEYC_NONE) { evbuffer_drain(tty->event->input, size); goto found; } /* Not found. Try to parse a key with an xterm-style modifier. */ - *key = xterm_keys_find(buf, len, &size); - if (*key != KEYC_NONE) { + key = xterm_keys_find(buf, len, &size); + if (key != KEYC_NONE) { evbuffer_drain(tty->event->input, size); goto found; } - /* Escape but no key string. If the timer isn't started, start it. */ - if (!(tty->flags & TTY_ESCAPE)) { - tv.tv_sec = 0; - tv.tv_usec = ESCAPE_PERIOD * 1000L; - if (gettimeofday(&tty->key_timer, NULL) != 0) - fatal("gettimeofday failed"); - timeradd(&tty->key_timer, &tv, &tty->key_timer); - - tty->flags |= TTY_ESCAPE; - return (1); - } - /* Skip the escape. */ buf++; len--; @@ -367,7 +358,7 @@ tty_keys_next(struct tty *tty, int *key, struct mouse_event *mouse) if (len != 0 && *buf != '\033') { evbuffer_drain(tty->event->input, 1); bufferevent_read(tty->event, &ch, 1); - *key = ch | KEYC_ESCAPE; + key = ch | KEYC_ESCAPE; goto found; } @@ -376,24 +367,46 @@ tty_keys_next(struct tty *tty, int *key, struct mouse_event *mouse) tk = tty_keys_find(tty, buf + 1, len - 1, &size); if (tk != NULL) { evbuffer_drain(tty->event->input, size + 2); - *key = tk->key | KEYC_ESCAPE; + key = tk->key | KEYC_ESCAPE; goto found; } } - /* If the timer hasn't expired, keep waiting. */ - if (gettimeofday(&tv, NULL) != 0) - fatal("gettimeofday failed"); - if (timercmp(&tty->key_timer, &tv, >)) - return (1); + /* + * Escape but no key string. If have, already seen an escape, then the + * timer must have expired, so give up waiting and send the escape. + */ + if (tty->flags & TTY_ESCAPE) { + evbuffer_drain(tty->event->input, 1); + key = '\033'; + goto found; + } - /* Give up and return the escape. */ - evbuffer_drain(tty->event->input, 1); - *key = '\033'; + /* Start the timer and wait for expiry or more data. */ + tv.tv_sec = 0; + tv.tv_usec = ESCAPE_PERIOD * 1000L; + + evtimer_del(&tty->key_timer); + evtimer_set(&tty->key_timer, tty_keys_callback, tty); + evtimer_add(&tty->key_timer, &tv); + + tty->flags |= TTY_ESCAPE; + return (0); found: + evtimer_del(&tty->key_timer); + tty->key_callback(key, &mouse, tty->key_data); tty->flags &= ~TTY_ESCAPE; - return (0); + return (1); +} + +void +tty_keys_callback(unused int fd, unused short events, void *data) +{ + struct tty *tty = data; + + if (tty->flags & TTY_ESCAPE) + tty_keys_next(tty); } int diff --git a/tty.c b/tty.c index e194febb..6ab3a211 100644 --- a/tty.c +++ b/tty.c @@ -28,6 +28,7 @@ #include "tmux.h" +void tty_read_callback(struct bufferevent *, void *); void tty_error_callback(struct bufferevent *, short, void *); void tty_fill_acs(struct tty *); @@ -113,7 +114,7 @@ tty_open(struct tty *tty, const char *overrides, char **cause) tty->flags &= ~(TTY_NOCURSOR|TTY_FREEZE|TTY_ESCAPE); tty->event = bufferevent_new( - tty->fd, NULL, NULL, tty_error_callback, tty); + tty->fd, tty_read_callback, NULL, tty_error_callback, tty); tty_start_tty(tty); @@ -124,6 +125,15 @@ tty_open(struct tty *tty, const char *overrides, char **cause) return (0); } +void +tty_read_callback(unused struct bufferevent *bufev, void *data) +{ + struct tty *tty = data; + + while (tty_keys_next(tty)) + ; +} + void tty_error_callback( unused struct bufferevent *bufev, unused short what, unused void *data) @@ -259,6 +269,7 @@ tty_close(struct tty *tty) tty->log_fd = -1; } + evtimer_del(&tty->key_timer); tty_stop_tty(tty); if (tty->flags & TTY_OPENED) { From 38e13942ac3fea4f900a84b19d0a987889230c79 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 5 Nov 2009 08:48:15 +0000 Subject: [PATCH 0509/1180] Now all timers are events, there is no longer any need to wake up every 50 ms - only wake up when an event happens. --- server.c | 7 +------ tmux.h | 3 --- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/server.c b/server.c index a34d9b02..fe07f1a0 100644 --- a/server.c +++ b/server.c @@ -207,15 +207,10 @@ error: void server_loop(void) { - struct timeval tv; - - memset(&tv, 0, sizeof tv); - tv.tv_usec = POLL_TIMEOUT * 1000; - while (!server_should_shutdown()) { server_update_socket(); - event_loopexit(&tv); + event_loopexit(NULL); event_loop(EVLOOP_ONCE); server_window_loop(); diff --git a/tmux.h b/tmux.h index f1b0f7ac..40bd238b 100644 --- a/tmux.h +++ b/tmux.h @@ -62,9 +62,6 @@ extern char **environ; /* Escape timer period, in milliseconds. */ #define ESCAPE_PERIOD 500 -/* Maximum poll timeout (when attached). */ -#define POLL_TIMEOUT 50 - /* Maximum data to buffer for output before suspending reading from panes. */ #define BACKOFF_THRESHOLD 1024 From 25c604fb1c3806fdcb230b0eaac0c3120685f8a8 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 5 Nov 2009 08:50:32 +0000 Subject: [PATCH 0510/1180] EVLOOP_ONCE takes care of the wakeup, so no need to call event_loopexit(NULL). --- server.c | 1 - 1 file changed, 1 deletion(-) diff --git a/server.c b/server.c index fe07f1a0..09618d25 100644 --- a/server.c +++ b/server.c @@ -210,7 +210,6 @@ server_loop(void) while (!server_should_shutdown()) { server_update_socket(); - event_loopexit(NULL); event_loop(EVLOOP_ONCE); server_window_loop(); From a790e16fa25e0fce4fc0f8ac6e83147a83ede3e8 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 5 Nov 2009 10:44:36 +0000 Subject: [PATCH 0511/1180] Key flags are only used for initialisation so they are not needed in the main tty_key struct. --- tmux.h | 4 ---- tty-keys.c | 11 ++++++----- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/tmux.h b/tmux.h index 40bd238b..c2165287 100644 --- a/tmux.h +++ b/tmux.h @@ -939,10 +939,6 @@ struct tty_key { int key; char *string; - int flags; -#define TTYKEY_CTRL 0x1 -#define TTYKEY_RAW 0x2 - RB_ENTRY(tty_key) entry; }; diff --git a/tty-keys.c b/tty-keys.c index c5c14541..21d52091 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -29,7 +29,7 @@ * Handle keys input from the outside terminal. */ -void tty_keys_add(struct tty *, const char *, int, int); +void tty_keys_add(struct tty *, const char *, int); void tty_keys_callback(int, short, void *); int tty_keys_mouse(char *, size_t, size_t *, struct mouse_event *); @@ -39,6 +39,8 @@ struct tty_key_ent { int key; int flags; +#define TTYKEY_CTRL 0x1 +#define TTYKEY_RAW 0x2 }; struct tty_key_ent tty_keys[] = { @@ -195,14 +197,13 @@ tty_keys_cmp(struct tty_key *k1, struct tty_key *k2) } void -tty_keys_add(struct tty *tty, const char *s, int key, int flags) +tty_keys_add(struct tty *tty, const char *s, int key) { struct tty_key *tk, *tl; tk = xmalloc(sizeof *tk); tk->string = xstrdup(s); tk->key = key; - tk->flags = flags; if ((tl = RB_INSERT(tty_keys, &tty->ktree, tk)) != NULL) { xfree(tk->string); @@ -240,12 +241,12 @@ tty_keys_init(struct tty *tty) continue; } - tty_keys_add(tty, s + 1, tke->key, tke->flags); + tty_keys_add(tty, s + 1, tke->key); if (tke->flags & TTYKEY_CTRL) { if (strlcpy(tmp, s, sizeof tmp) >= sizeof tmp) continue; tmp[strlen(tmp) - 1] ^= 0x20; - tty_keys_add(tty, tmp + 1, tke->key | KEYC_CTRL, 0); + tty_keys_add(tty, tmp + 1, tke->key | KEYC_CTRL); } } } From 05855393f0e9c7c9228da3d6388c6d02a3083ef4 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 5 Nov 2009 12:04:50 +0000 Subject: [PATCH 0512/1180] key_string_lookup_key uses a static buffer, so copy its output into the working buffer before calling the command print function which can also use it (eg send-keys). --- cmd-list-keys.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/cmd-list-keys.c b/cmd-list-keys.c index db64e244..f4bd064a 100644 --- a/cmd-list-keys.c +++ b/cmd-list-keys.c @@ -47,7 +47,8 @@ cmd_list_keys_exec(struct cmd *self, struct cmd_ctx *ctx) struct cmd_target_data *data = self->data; struct key_binding *bd; const char *key; - char tmp[BUFSIZ], keytmp[64]; + char tmp[BUFSIZ]; + size_t used; int width, keywidth; if (data->target != NULL) @@ -70,14 +71,15 @@ cmd_list_keys_exec(struct cmd *self, struct cmd_ctx *ctx) key = key_string_lookup_key(bd->key & ~KEYC_PREFIX); if (key == NULL) continue; + if (!(bd->key & KEYC_PREFIX)) + used = xsnprintf(tmp, sizeof tmp, "[%s]: ", key); + else + used = xsnprintf(tmp, sizeof tmp, "%*s: ", width, key); + if (used >= sizeof tmp) + continue; - *tmp = '\0'; - cmd_list_print(bd->cmdlist, tmp, sizeof tmp); - if (!(bd->key & KEYC_PREFIX)) { - xsnprintf(keytmp, sizeof keytmp, "[%s]", key); - key = keytmp; - } - ctx->print(ctx, "%*s: %s", width, key, tmp); + cmd_list_print(bd->cmdlist, tmp + used, (sizeof tmp) - used); + ctx->print(ctx, "%s", tmp); } return (0); From 80e0158112b73029d27452bc08b18079df3f898c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 5 Nov 2009 19:29:41 +0000 Subject: [PATCH 0513/1180] Switch the tty key tree over to an (unbalanced) ternary tree which allows partial matches to be done (they wait for further data or a timer to expire, like a naked escape). Mouse and xterm-style keys still expect to be atomic. --- tmux.h | 13 ++- tty-keys.c | 248 ++++++++++++++++++++++++++++++++++------------------- 2 files changed, 168 insertions(+), 93 deletions(-) diff --git a/tmux.h b/tmux.h index c2165287..14890440 100644 --- a/tmux.h +++ b/tmux.h @@ -936,10 +936,13 @@ ARRAY_DECL(sessions, struct session *); /* TTY information. */ struct tty_key { + char ch; int key; - char *string; - RB_ENTRY(tty_key) entry; + struct tty_key *left; + struct tty_key *right; + + struct tty_key *next; }; struct tty_term { @@ -998,9 +1001,7 @@ struct tty { void (*key_callback)(int, struct mouse_event *, void *); void *key_data; struct event key_timer; - - size_t ksize; /* maximum key size */ - RB_HEAD(tty_keys, tty_key) ktree; + struct tty_key *key_tree; }; /* TTY command context and function pointer. */ @@ -1351,8 +1352,6 @@ int tty_term_number(struct tty_term *, enum tty_code_code); int tty_term_flag(struct tty_term *, enum tty_code_code); /* tty-keys.c */ -int tty_keys_cmp(struct tty_key *, struct tty_key *); -RB_PROTOTYPE(tty_keys, tty_key, entry, tty_keys_cmp); void tty_keys_init(struct tty *); void tty_keys_free(struct tty *); int tty_keys_next(struct tty *); diff --git a/tty-keys.c b/tty-keys.c index 21d52091..420140ff 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -26,12 +26,19 @@ #include "tmux.h" /* - * Handle keys input from the outside terminal. + * Handle keys input from the outside terminal. tty_keys[] is a base table of + * supported keys which are looked up in terminfo(5) and translated into a + * ternary tree (a binary tree of binary trees). */ -void tty_keys_add(struct tty *, const char *, int); -void tty_keys_callback(int, short, void *); -int tty_keys_mouse(char *, size_t, size_t *, struct mouse_event *); +void tty_keys_add1(struct tty_key **, const char *, int); +void tty_keys_add(struct tty *, const char *, int); +void tty_keys_free1(struct tty_key *); +struct tty_key *tty_keys_find1( + struct tty_key *, const char *, size_t, size_t *); +struct tty_key *tty_keys_find(struct tty *, const char *, size_t, size_t *); +void tty_keys_callback(int, short, void *); +int tty_keys_mouse(char *, size_t, size_t *, struct mouse_event *); struct tty_key_ent { enum tty_code_code code; @@ -43,6 +50,11 @@ struct tty_key_ent { #define TTYKEY_RAW 0x2 }; +/* + * Default key tables. Those flagged with TTYKEY_RAW are inserted directly, + * otherwise they are looked up in terminfo(5). Any keys marked TTYKEY_CTRL + * have their last byte twiddled and are inserted as a Ctrl key as well. + */ struct tty_key_ent tty_keys[] = { /* Function keys. */ { TTYC_KF1, NULL, KEYC_F1, TTYKEY_CTRL }, @@ -186,37 +198,56 @@ struct tty_key_ent tty_keys[] = { { TTYC_KUP7, NULL, KEYC_UP|KEYC_ESCAPE|KEYC_CTRL, 0 }, }; -RB_GENERATE(tty_keys, tty_key, entry, tty_keys_cmp); - -struct tty_key *tty_keys_find(struct tty *, char *, size_t, size_t *); - -int -tty_keys_cmp(struct tty_key *k1, struct tty_key *k2) -{ - return (strcmp(k1->string, k2->string)); -} - void tty_keys_add(struct tty *tty, const char *s, int key) { - struct tty_key *tk, *tl; + size_t size; - tk = xmalloc(sizeof *tk); - tk->string = xstrdup(s); - tk->key = key; - - if ((tl = RB_INSERT(tty_keys, &tty->ktree, tk)) != NULL) { - xfree(tk->string); - xfree(tk); - log_debug("key exists: %s (old %x, new %x)", s, tl->key, key); - return; + if (tty_keys_find(tty, s, strlen(s), &size) == NULL) { + log_debug("new key 0x%x: %s", key, s); + tty_keys_add1(&tty->key_tree, s, key); } - - if (strlen(tk->string) > tty->ksize) - tty->ksize = strlen(tk->string); - log_debug("new key %x: size now %zu (%s)", key, tty->ksize, tk->string); } +/* Add next node to the tree. */ +void +tty_keys_add1(struct tty_key **tkp, const char *s, int key) +{ + struct tty_key *tk; + + /* Allocate a tree entry if there isn't one already. */ + tk = *tkp; + if (tk == NULL) { + tk = *tkp = xcalloc(1, sizeof *tk); + tk->ch = *s; + tk->key = KEYC_NONE; + } + + /* Find the next entry. */ + if (*s == tk->ch) { + /* Move forward in string. */ + s++; + + /* If this is the end of the string, no more is necessary. */ + if (*s == '\0') { + tk->key = key; + return; + } + + /* Use the child tree for the next character. */ + tkp = &tk->next; + } else { + if (*s < tk->ch) + tkp = &tk->left; + else if (*s > tk->ch) + tkp = &tk->right; + } + + /* And recurse to add it. */ + tty_keys_add1(tkp, s, key); +} + +/* Initialise a key tree from the table. */ void tty_keys_init(struct tty *tty) { @@ -225,9 +256,7 @@ tty_keys_init(struct tty *tty) const char *s; char tmp[64]; - RB_INIT(&tty->ktree); - - tty->ksize = 0; + tty->key_tree = NULL; for (i = 0; i < nitems(tty_keys); i++) { tke = &tty_keys[i]; @@ -237,12 +266,12 @@ tty_keys_init(struct tty *tty) if (!tty_term_has(tty->term, tke->code)) continue; s = tty_term_string(tty->term, tke->code); - if (s[0] != '\033' || s[1] == '\0') - continue; } + if (s[0] != '\033' || s[1] == '\0') + continue; tty_keys_add(tty, s + 1, tke->key); - if (tke->flags & TTYKEY_CTRL) { + if (!(tke->flags & TTYKEY_CTRL)) { if (strlcpy(tmp, s, sizeof tmp) >= sizeof tmp) continue; tmp[strlen(tmp) - 1] ^= 0x20; @@ -251,61 +280,80 @@ tty_keys_init(struct tty *tty) } } +/* Free the entire key tree. */ void tty_keys_free(struct tty *tty) { - struct tty_key *tk; - - while (!RB_EMPTY(&tty->ktree)) { - tk = RB_ROOT(&tty->ktree); - RB_REMOVE(tty_keys, &tty->ktree, tk); - xfree(tk->string); - xfree(tk); - } + tty_keys_free1(tty->key_tree); } -struct tty_key * -tty_keys_find(struct tty *tty, char *buf, size_t len, size_t *size) +/* Free a single key. */ +void +tty_keys_free1(struct tty_key *tk) { - struct tty_key *tk, tl; - char *s; + if (tk->next != NULL) + tty_keys_free1(tk->next); + if (tk->left != NULL) + tty_keys_free1(tk->left); + if (tk->right != NULL) + tty_keys_free1(tk->right); + xfree(tk); + +} - if (len == 0) +/* Lookup a key in the tree. */ +struct tty_key * +tty_keys_find(struct tty *tty, const char *buf, size_t len, size_t *size) +{ + *size = 0; + return (tty_keys_find1(tty->key_tree, buf, len, size)); +} + +/* Find the next node. */ +struct tty_key * +tty_keys_find1(struct tty_key *tk, const char *buf, size_t len, size_t *size) +{ + /* If the node is NULL, this is the end of the tree. No match. */ + if (tk == NULL) return (NULL); - s = xmalloc(tty->ksize + 1); - for (*size = tty->ksize; (*size) > 0; (*size)--) { - if ((*size) > len) - continue; - memcpy(s, buf, *size); - s[*size] = '\0'; + /* Pick the next in the sequence. */ + if (tk->ch == *buf) { + /* Move forward in the string. */ + buf++; len--; + (*size)++; - log_debug2("looking for key: %s", s); - - tl.string = s; - tk = RB_FIND(tty_keys, &tty->ktree, &tl); - if (tk != NULL) { - log_debug2("got key: 0x%x", tk->key); - xfree(s); + /* At the end of the string, return the current node. */ + if (len == 0) return (tk); - } - } - xfree(s); - return (NULL); + /* Move into the next tree for the following character. */ + tk = tk->next; + } else { + if (*buf < tk->ch) + tk = tk->left; + else if (*buf > tk->ch) + tk = tk->right; + } + + /* Move to the next in the tree. */ + return (tty_keys_find1(tk, buf, len, size)); } +/* + * Process at least one key in the buffer and invoke tty->key_callback. Return + * 1 if there are no further keys, or 0 if there is more in the buffer. + */ int tty_keys_next(struct tty *tty) { struct tty_key *tk; struct timeval tv; struct mouse_event mouse; - char *buf; + char *buf, *ptr; size_t len, size; cc_t bspace; int key; - u_char ch; buf = EVBUFFER_DATA(tty->event->input); len = EVBUFFER_LENGTH(tty->event->input); @@ -315,8 +363,8 @@ tty_keys_next(struct tty *tty) /* If a normal key, return it. */ if (*buf != '\033') { - bufferevent_read(tty->event, &ch, 1); - key = ch; + key = *buf; + evbuffer_drain(tty->event->input, 1); /* * Check for backspace key using termios VERASE - the terminfo @@ -326,29 +374,28 @@ tty_keys_next(struct tty *tty) bspace = tty->tio.c_cc[VERASE]; if (bspace != _POSIX_VDISABLE && key == bspace) key = KEYC_BSPACE; - goto found; + goto handle_key; } /* Look for matching key string and return if found. */ tk = tty_keys_find(tty, buf + 1, len - 1, &size); if (tk != NULL) { - evbuffer_drain(tty->event->input, size + 1); key = tk->key; - goto found; + goto found_key; } /* Not found. Is this a mouse key press? */ key = tty_keys_mouse(buf, len, &size, &mouse); if (key != KEYC_NONE) { evbuffer_drain(tty->event->input, size); - goto found; + goto handle_key; } /* Not found. Try to parse a key with an xterm-style modifier. */ key = xterm_keys_find(buf, len, &size); if (key != KEYC_NONE) { evbuffer_drain(tty->event->input, size); - goto found; + goto handle_key; } /* Skip the escape. */ @@ -357,32 +404,37 @@ tty_keys_next(struct tty *tty) /* Is there a normal key following? */ if (len != 0 && *buf != '\033') { - evbuffer_drain(tty->event->input, 1); - bufferevent_read(tty->event, &ch, 1); - key = ch | KEYC_ESCAPE; - goto found; + key = *buf | KEYC_ESCAPE; + evbuffer_drain(tty->event->input, 2); + goto handle_key; } /* Or a key string? */ if (len > 1) { tk = tty_keys_find(tty, buf + 1, len - 1, &size); if (tk != NULL) { - evbuffer_drain(tty->event->input, size + 2); key = tk->key | KEYC_ESCAPE; - goto found; + size++; /* include escape */ + goto found_key; } } + /* Escape and then nothing useful - fall through. */ + +partial_key: /* - * Escape but no key string. If have, already seen an escape, then the + * Escape but no key string. If have already seen an escape, then the * timer must have expired, so give up waiting and send the escape. */ if (tty->flags & TTY_ESCAPE) { evbuffer_drain(tty->event->input, 1); key = '\033'; - goto found; + goto handle_key; } + /* Fall through to start the timer. */ + +start_timer: /* Start the timer and wait for expiry or more data. */ tv.tv_sec = 0; tv.tv_usec = ESCAPE_PERIOD * 1000L; @@ -394,22 +446,45 @@ tty_keys_next(struct tty *tty) tty->flags |= TTY_ESCAPE; return (0); -found: - evtimer_del(&tty->key_timer); +found_key: + if (tk->next != NULL) { + /* Partial key. Start the timer if not already expired. */ + if (!(tty->flags & TTY_ESCAPE)) + goto start_timer; + + /* Otherwise, if no key, send the escape alone. */ + if (tk->key == KEYC_NONE) + goto partial_key; + + /* Or fall through to send the partial key found. */ + } + evbuffer_drain(tty->event->input, size + 1); + + goto handle_key; + +handle_key: + evtimer_del(&tty->key_timer); + tty->key_callback(key, &mouse, tty->key_data); + tty->flags &= ~TTY_ESCAPE; return (1); } +/* Key timer callback. */ void tty_keys_callback(unused int fd, unused short events, void *data) { struct tty *tty = data; - if (tty->flags & TTY_ESCAPE) - tty_keys_next(tty); + if (!(tty->flags & TTY_ESCAPE)) + return; + + while (tty_keys_next(tty)) + ; } +/* Handle mouse key input. */ int tty_keys_mouse(char *buf, size_t len, size_t *size, struct mouse_event *m) { @@ -418,11 +493,12 @@ tty_keys_mouse(char *buf, size_t len, size_t *size, struct mouse_event *m) * buttons, X and Y, all based at 32 with 1,1 top-left. */ - log_debug("mouse input is: %.*s", (int) len, buf); if (len != 6 || memcmp(buf, "\033[M", 3) != 0) return (KEYC_NONE); *size = 6; + log_debug("mouse input is: %.*s", (int) len, buf); + m->b = buf[3]; m->x = buf[4]; m->y = buf[5]; From ff55eb5bfa4e6c4814fcf5e65ce388e2c53acbb8 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 5 Nov 2009 19:32:34 +0000 Subject: [PATCH 0514/1180] Unused variable. Aargh. --- tty-keys.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tty-keys.c b/tty-keys.c index 420140ff..8505900c 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -350,7 +350,7 @@ tty_keys_next(struct tty *tty) struct tty_key *tk; struct timeval tv; struct mouse_event mouse; - char *buf, *ptr; + char *buf; size_t len, size; cc_t bspace; int key; From 297ebb1160c7d338f19148f2fbce1c6753bbee3d Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 5 Nov 2009 19:35:16 +0000 Subject: [PATCH 0515/1180] Old xterm F1-F4 are \033O_P not \033[O_P. --- xterm-keys.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/xterm-keys.c b/xterm-keys.c index 9a9b3242..ca94a1f6 100644 --- a/xterm-keys.c +++ b/xterm-keys.c @@ -50,13 +50,13 @@ struct xterm_keys_entry { struct xterm_keys_entry xterm_keys_table[] = { { KEYC_F1, "\033[1;_P" }, - { KEYC_F1, "\033[O_P" }, + { KEYC_F1, "\033O_P" }, { KEYC_F2, "\033[1;_Q" }, - { KEYC_F2, "\033[O_Q" }, + { KEYC_F2, "\033O_Q" }, { KEYC_F3, "\033[1;_R" }, - { KEYC_F3, "\033[O_R" }, + { KEYC_F3, "\033O_R" }, { KEYC_F4, "\033[1;_S" }, - { KEYC_F4, "\033[O_S" }, + { KEYC_F4, "\033O_S" }, { KEYC_F5, "\033[15;_~" }, { KEYC_F6, "\033[17;_~" }, { KEYC_F7, "\033[18;_~" }, From bed8153ba00fef8ed2f618463fa631c71b8f51cf Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 5 Nov 2009 22:35:28 +0000 Subject: [PATCH 0516/1180] Clear to the end of the screen from the right starting point when drawing line-by-line (in panes or if ed not supported). Fixes problem spotted by Frank Terbeck. --- tty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tty.c b/tty.c index 6ab3a211..b4da9983 100644 --- a/tty.c +++ b/tty.c @@ -784,7 +784,7 @@ tty_cmd_clearendofscreen(struct tty *tty, const struct tty_ctx *ctx) } else { for (i = ctx->ocx; i < screen_size_x(s); i++) tty_putc(tty, ' '); - for (j = ctx->ocy; j < screen_size_y(s); j++) { + for (j = ctx->ocy + 1; j < screen_size_y(s); j++) { tty_cursor_pane(tty, ctx, 0, j); for (i = 0; i < screen_size_x(s); i++) tty_putc(tty, ' '); From f98d13e7dc2500d84a382d309f95dad9e7eec01a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 6 Nov 2009 10:42:06 +0000 Subject: [PATCH 0517/1180] Don't try enable/disable the event if the window pane is dead (fd == -1), as the event will have been freed. --- server-window.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/server-window.c b/server-window.c index 020af041..cb819dfe 100644 --- a/server-window.c +++ b/server-window.c @@ -70,10 +70,12 @@ server_window_loop(void) continue; TAILQ_FOREACH(wp, &w->panes, entry) { - if (server_window_backoff(wp)) - bufferevent_disable(wp->event, EV_READ); - else - bufferevent_enable(wp->event, EV_READ); + if (wp->fd != -1) { + if (server_window_backoff(wp)) + bufferevent_disable(wp->event, EV_READ); + else + bufferevent_enable(wp->event, EV_READ); + } } for (j = 0; j < ARRAY_LENGTH(&sessions); j++) { From daf150c38de726f75fc9229ec4f4c62498668bbb Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 9 Nov 2009 11:45:10 +0000 Subject: [PATCH 0518/1180] Constify buf. --- tty-keys.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tty-keys.c b/tty-keys.c index 8505900c..f30775fb 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -38,7 +38,8 @@ struct tty_key *tty_keys_find1( struct tty_key *, const char *, size_t, size_t *); struct tty_key *tty_keys_find(struct tty *, const char *, size_t, size_t *); void tty_keys_callback(int, short, void *); -int tty_keys_mouse(char *, size_t, size_t *, struct mouse_event *); +int tty_keys_mouse( + const char *, size_t, size_t *, struct mouse_event *); struct tty_key_ent { enum tty_code_code code; @@ -350,7 +351,7 @@ tty_keys_next(struct tty *tty) struct tty_key *tk; struct timeval tv; struct mouse_event mouse; - char *buf; + const char *buf; size_t len, size; cc_t bspace; int key; @@ -486,7 +487,7 @@ tty_keys_callback(unused int fd, unused short events, void *data) /* Handle mouse key input. */ int -tty_keys_mouse(char *buf, size_t len, size_t *size, struct mouse_event *m) +tty_keys_mouse(const char *buf, size_t len, size_t *size, struct mouse_event *m) { /* * Mouse sequences are \033[M followed by three characters indicating From 591fa23f6e6ed403457bf86bd69b6c10f93334be Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 9 Nov 2009 14:40:06 +0000 Subject: [PATCH 0519/1180] The input key should be a u_char. Fixes top-bit-set input problem reported by ajacoutot@. --- tty-keys.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tty-keys.c b/tty-keys.c index f30775fb..a456f563 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -364,7 +364,7 @@ tty_keys_next(struct tty *tty) /* If a normal key, return it. */ if (*buf != '\033') { - key = *buf; + key = (u_char) *buf; evbuffer_drain(tty->event->input, 1); /* From 6609093625b8c48a69af737e6a02ba2befd06adb Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 9 Nov 2009 22:50:29 +0000 Subject: [PATCH 0520/1180] Just ignore tty fd errors rather than dying, stops the server dying if the session is disconnected abrubtly (eg ssh ~.). --- tty.c | 1 - 1 file changed, 1 deletion(-) diff --git a/tty.c b/tty.c index b4da9983..f7b3ec03 100644 --- a/tty.c +++ b/tty.c @@ -138,7 +138,6 @@ void tty_error_callback( unused struct bufferevent *bufev, unused short what, unused void *data) { - fatalx("lost terminal"); } void From 9f47c6083a4d8c8dfd0d509f581f67dab8cf8e2c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 10 Nov 2009 15:47:48 +0000 Subject: [PATCH 0521/1180] Don't return 1 unless there was actually a problem (signal/lost server) rather than for all events (normal exit/detach/etc). --- client.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/client.c b/client.c index afa48048..d1bd7a64 100644 --- a/client.c +++ b/client.c @@ -37,6 +37,7 @@ struct imsgbuf client_ibuf; struct event client_event; const char *client_exitmsg; +int client_exitval; void client_send_identify(int); void client_send_environ(void); @@ -211,17 +212,14 @@ client_main(void) goto out; /* Set the event and dispatch. */ - client_update_event(); + client_update_event(); event_dispatch(); out: /* Print the exit message, if any, and exit. */ - if (client_exitmsg != NULL) { - if (!login_shell) - printf("[%s]\n", client_exitmsg); - exit(1); - } - exit(0); + if (client_exitmsg != NULL && !login_shell) + printf("[%s]\n", client_exitmsg); + exit(client_exitval); } void @@ -232,6 +230,7 @@ client_signal(int sig, unused short events, unused void *data) switch (sig) { case SIGTERM: client_exitmsg = "terminated"; + client_exitval = 1; client_write_server(MSG_EXITING, NULL, 0); break; case SIGWINCH: @@ -275,6 +274,7 @@ client_callback(unused int fd, short events, unused void *data) lost_server: client_exitmsg = "lost server"; + client_exitval = 1; event_loopexit(NULL); } @@ -321,6 +321,7 @@ client_dispatch(void) client_write_server(MSG_EXITING, NULL, 0); client_exitmsg = "server exited"; + client_exitval = 1; break; case MSG_SUSPEND: if (datalen != 0) From 38f64b3da3ab824f24685078789e2f16873a5d8b Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 10 Nov 2009 17:24:43 +0000 Subject: [PATCH 0522/1180] Lookup key as a named key (eg 'Space') before checking for single character keys, makes C-Space/M-Space etc resolve to the correct key code. --- key-string.c | 59 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 40 insertions(+), 19 deletions(-) diff --git a/key-string.c b/key-string.c index bfccb978..0c5c8269 100644 --- a/key-string.c +++ b/key-string.c @@ -87,6 +87,7 @@ struct { { "KP.", KEYC_KP_PERIOD }, }; +/* Find key string in table. */ int key_string_search_table(const char *string) { @@ -99,6 +100,7 @@ key_string_search_table(const char *string) return (KEYC_NONE); } +/* Lookup a string and convert to a key value, handling C-/M-/S- prefix. */ int key_string_lookup_string(const char *string) { @@ -118,20 +120,34 @@ key_string_lookup_string(const char *string) if (ptr != NULL) { if (ptr[0] == '\0') return (KEYC_NONE); - if (ptr[1] == '\0') { - if (ptr[0] == 32) - return (0); - if (ptr[0] == 63) - return (KEYC_BSPACE); - if (ptr[0] >= 64 && ptr[0] <= 95) - return (ptr[0] - 64); - if (ptr[0] >= 97 && ptr[0] <= 122) - return (ptr[0] - 96); - return (KEYC_NONE); - } + /* + * Lookup as a named key. If a function key (>= KEYC_BASE), + * return it with the ctrl modifier, otherwise fallthrough with + * the key value from the table (eg for C-Space). If not a + * named key, check for single character keys and try that. + */ key = key_string_search_table(ptr); - if (key != KEYC_NONE) - return (key | KEYC_CTRL); + if (key != KEYC_NONE) { + if (key >= KEYC_BASE) + return (key | KEYC_CTRL); + } else { + if (ptr[1] != '\0') + return (KEYC_NONE); + key = ptr[0]; + } + + /* + * Figure out if the single character in key is a valid ctrl + * key. + */ + if (key == 32) + return (0); + if (key == 63) + return (KEYC_BSPACE); + if (key >= 64 && key <= 95) + return (key - 64); + if (key >= 97 && key <= 122) + return (key - 96); return (KEYC_NONE); } @@ -139,13 +155,17 @@ key_string_lookup_string(const char *string) ptr = string + 2; if (ptr[0] == '\0') return (KEYC_NONE); - if (ptr[1] == '\0') { - if (ptr[0] < 32 || ptr[0] > 127) - return (KEYC_NONE); - return (ptr[0] | KEYC_ESCAPE); - } key = key_string_lookup_string(ptr); - if (key != KEYC_NONE) + if (key != KEYC_NONE) { + if (key >= KEYC_BASE) + return (key | KEYC_ESCAPE); + } else { + if (ptr[1] == '\0') + return (KEYC_NONE); + key = ptr[0]; + } + + if (key >= 32 && key <= 127) return (key | KEYC_ESCAPE); return (KEYC_NONE); } @@ -153,6 +173,7 @@ key_string_lookup_string(const char *string) return (key_string_search_table(string)); } +/* Convert a key code into string format, with prefix if necessary. */ const char * key_string_lookup_key(int key) { From b92fcf23fdaea625d31d5902f4fbb50b776d424b Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 10 Nov 2009 17:41:35 +0000 Subject: [PATCH 0523/1180] Whoops, this is needed for last commit as well. --- tmux.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tmux.h b/tmux.h index 14890440..d82363d0 100644 --- a/tmux.h +++ b/tmux.h @@ -98,17 +98,20 @@ extern char **environ; #define BELL_ANY 1 #define BELL_CURRENT 2 -/* Key codes. ncurses defines KEY_*. Grrr. */ +/* Special key codes. */ #define KEYC_NONE 0xfff -/* 0x1000 is base for special keys */ +#define KEYC_BASE 0x1000 + +/* Key modifier bits. */ #define KEYC_ESCAPE 0x2000 #define KEYC_CTRL 0x4000 #define KEYC_SHIFT 0x8000 #define KEYC_PREFIX 0x10000 +/* Other key codes. */ enum key_code { /* Mouse key. */ - KEYC_MOUSE = 0x1000, + KEYC_MOUSE = KEYC_BASE, /* Backspace key. */ KEYC_BSPACE, From 05831b52c45617ac7ad455609305c6d2246d6906 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 10 Nov 2009 17:59:34 +0000 Subject: [PATCH 0524/1180] Twiddling the last bit is an rxvtism, so do not support it in the table by default. --- tty-keys.c | 77 ++++++++++++++++++++++++------------------------------ 1 file changed, 34 insertions(+), 43 deletions(-) diff --git a/tty-keys.c b/tty-keys.c index a456f563..122d5fca 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -47,45 +47,43 @@ struct tty_key_ent { int key; int flags; -#define TTYKEY_CTRL 0x1 -#define TTYKEY_RAW 0x2 +#define TTYKEY_RAW 0x1 }; /* * Default key tables. Those flagged with TTYKEY_RAW are inserted directly, - * otherwise they are looked up in terminfo(5). Any keys marked TTYKEY_CTRL - * have their last byte twiddled and are inserted as a Ctrl key as well. + * otherwise they are looked up in terminfo(5). */ struct tty_key_ent tty_keys[] = { /* Function keys. */ - { TTYC_KF1, NULL, KEYC_F1, TTYKEY_CTRL }, - { TTYC_KF1, NULL, KEYC_F1, TTYKEY_CTRL }, - { TTYC_KF2, NULL, KEYC_F2, TTYKEY_CTRL }, - { TTYC_KF3, NULL, KEYC_F3, TTYKEY_CTRL }, - { TTYC_KF4, NULL, KEYC_F4, TTYKEY_CTRL }, - { TTYC_KF5, NULL, KEYC_F5, TTYKEY_CTRL }, - { TTYC_KF6, NULL, KEYC_F6, TTYKEY_CTRL }, - { TTYC_KF7, NULL, KEYC_F7, TTYKEY_CTRL }, - { TTYC_KF8, NULL, KEYC_F8, TTYKEY_CTRL }, - { TTYC_KF9, NULL, KEYC_F9, TTYKEY_CTRL }, - { TTYC_KF10, NULL, KEYC_F10, TTYKEY_CTRL }, - { TTYC_KF11, NULL, KEYC_F11, TTYKEY_CTRL }, - { TTYC_KF12, NULL, KEYC_F12, TTYKEY_CTRL }, - { TTYC_KF13, NULL, KEYC_F13, TTYKEY_CTRL }, - { TTYC_KF14, NULL, KEYC_F14, TTYKEY_CTRL }, - { TTYC_KF15, NULL, KEYC_F15, TTYKEY_CTRL }, - { TTYC_KF16, NULL, KEYC_F16, TTYKEY_CTRL }, - { TTYC_KF17, NULL, KEYC_F17, TTYKEY_CTRL }, - { TTYC_KF18, NULL, KEYC_F18, TTYKEY_CTRL }, - { TTYC_KF19, NULL, KEYC_F19, TTYKEY_CTRL }, - { TTYC_KF20, NULL, KEYC_F20, TTYKEY_CTRL }, - { TTYC_KICH1, NULL, KEYC_IC, TTYKEY_CTRL }, - { TTYC_KDCH1, NULL, KEYC_DC, TTYKEY_CTRL }, - { TTYC_KHOME, NULL, KEYC_HOME, TTYKEY_CTRL }, - { TTYC_KEND, NULL, KEYC_END, TTYKEY_CTRL }, - { TTYC_KNP, NULL, KEYC_NPAGE, TTYKEY_CTRL }, - { TTYC_KPP, NULL, KEYC_PPAGE, TTYKEY_CTRL }, - { TTYC_KCBT, NULL, KEYC_BTAB, TTYKEY_CTRL }, + { TTYC_KF1, NULL, KEYC_F1, 0 }, + { TTYC_KF1, NULL, KEYC_F1, 0 }, + { TTYC_KF2, NULL, KEYC_F2, 0 }, + { TTYC_KF3, NULL, KEYC_F3, 0 }, + { TTYC_KF4, NULL, KEYC_F4, 0 }, + { TTYC_KF5, NULL, KEYC_F5, 0 }, + { TTYC_KF6, NULL, KEYC_F6, 0 }, + { TTYC_KF7, NULL, KEYC_F7, 0 }, + { TTYC_KF8, NULL, KEYC_F8, 0 }, + { TTYC_KF9, NULL, KEYC_F9, 0 }, + { TTYC_KF10, NULL, KEYC_F10, 0 }, + { TTYC_KF11, NULL, KEYC_F11, 0 }, + { TTYC_KF12, NULL, KEYC_F12, 0 }, + { TTYC_KF13, NULL, KEYC_F13, 0 }, + { TTYC_KF14, NULL, KEYC_F14, 0 }, + { TTYC_KF15, NULL, KEYC_F15, 0 }, + { TTYC_KF16, NULL, KEYC_F16, 0 }, + { TTYC_KF17, NULL, KEYC_F17, 0 }, + { TTYC_KF18, NULL, KEYC_F18, 0 }, + { TTYC_KF19, NULL, KEYC_F19, 0 }, + { TTYC_KF20, NULL, KEYC_F20, 0 }, + { TTYC_KICH1, NULL, KEYC_IC, 0 }, + { TTYC_KDCH1, NULL, KEYC_DC, 0 }, + { TTYC_KHOME, NULL, KEYC_HOME, 0 }, + { TTYC_KEND, NULL, KEYC_END, 0 }, + { TTYC_KNP, NULL, KEYC_NPAGE, 0 }, + { TTYC_KPP, NULL, KEYC_PPAGE, 0 }, + { TTYC_KCBT, NULL, KEYC_BTAB, 0 }, /* Arrow keys. */ { 0, "\033OA", KEYC_UP, TTYKEY_RAW }, @@ -98,10 +96,10 @@ struct tty_key_ent tty_keys[] = { { 0, "\033[C", KEYC_RIGHT, TTYKEY_RAW }, { 0, "\033[D", KEYC_LEFT, TTYKEY_RAW }, - { TTYC_KCUU1, NULL, KEYC_UP, TTYKEY_CTRL }, - { TTYC_KCUD1, NULL, KEYC_DOWN, TTYKEY_CTRL }, - { TTYC_KCUB1, NULL, KEYC_LEFT, TTYKEY_CTRL }, - { TTYC_KCUF1, NULL, KEYC_RIGHT, TTYKEY_CTRL }, + { TTYC_KCUU1, NULL, KEYC_UP, 0 }, + { TTYC_KCUD1, NULL, KEYC_DOWN, 0 }, + { TTYC_KCUB1, NULL, KEYC_LEFT, 0 }, + { TTYC_KCUF1, NULL, KEYC_RIGHT, 0 }, /* Special-case arrow keys for rxvt until terminfo has kRIT5 etc. */ { 0, "\033Oa", KEYC_UP|KEYC_CTRL, TTYKEY_RAW }, @@ -255,7 +253,6 @@ tty_keys_init(struct tty *tty) struct tty_key_ent *tke; u_int i; const char *s; - char tmp[64]; tty->key_tree = NULL; for (i = 0; i < nitems(tty_keys); i++) { @@ -272,12 +269,6 @@ tty_keys_init(struct tty *tty) continue; tty_keys_add(tty, s + 1, tke->key); - if (!(tke->flags & TTYKEY_CTRL)) { - if (strlcpy(tmp, s, sizeof tmp) >= sizeof tmp) - continue; - tmp[strlen(tmp) - 1] ^= 0x20; - tty_keys_add(tty, tmp + 1, tke->key | KEYC_CTRL); - } } } From d9961f40bf13b776267cb5d13a8a72a7c4ee1c41 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 10 Nov 2009 18:48:03 +0000 Subject: [PATCH 0525/1180] Don't output rxvtisms either. --- input-keys.c | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/input-keys.c b/input-keys.c index 35834571..37a24bcd 100644 --- a/input-keys.c +++ b/input-keys.c @@ -50,49 +50,27 @@ struct input_key_ent input_keys[] = { { KEYC_F3, "\033OR", 0 }, { KEYC_F4, "\033OS", 0 }, { KEYC_F5, "\033[15~", 0 }, - { KEYC_F5|KEYC_CTRL, "\033[15^", 0 }, { KEYC_F6, "\033[17~", 0 }, - { KEYC_F6|KEYC_CTRL, "\033[17^", 0 }, { KEYC_F7, "\033[18~", 0 }, - { KEYC_F7|KEYC_CTRL, "\033[18^", 0 }, { KEYC_F8, "\033[19~", 0 }, - { KEYC_F8|KEYC_CTRL, "\033[19^", 0 }, { KEYC_F9, "\033[20~", 0 }, - { KEYC_F9|KEYC_CTRL, "\033[20^", 0 }, { KEYC_F10, "\033[21~", 0 }, - { KEYC_F10|KEYC_CTRL, "\033[21^", 0 }, { KEYC_F11, "\033[23~", 0 }, - { KEYC_F1|KEYC_CTRL, "\033[23^", 0 }, { KEYC_F12, "\033[24~", 0 }, - { KEYC_F12|KEYC_CTRL, "\033[24^", 0 }, { KEYC_F13, "\033[25~", 0 }, - { KEYC_F13|KEYC_CTRL, "\033[25^", 0 }, { KEYC_F14, "\033[26~", 0 }, - { KEYC_F14|KEYC_CTRL, "\033[26^", 0 }, { KEYC_F15, "\033[28~", 0 }, - { KEYC_F15|KEYC_CTRL, "\033[28^", 0 }, { KEYC_F16, "\033[29~", 0 }, - { KEYC_F16|KEYC_CTRL, "\033[29^", 0 }, { KEYC_F17, "\033[31~", 0 }, - { KEYC_F17|KEYC_CTRL, "\033[31^", 0 }, { KEYC_F18, "\033[32~", 0 }, - { KEYC_F18|KEYC_CTRL, "\033[32^", 0 }, { KEYC_F19, "\033[33~", 0 }, - { KEYC_F19|KEYC_CTRL, "\033[33^", 0 }, { KEYC_F20, "\033[34~", 0 }, - { KEYC_F20|KEYC_CTRL, "\033[34^", 0 }, { KEYC_IC, "\033[2~", 0 }, - { KEYC_IC|KEYC_CTRL, "\033[2^", 0 }, { KEYC_DC, "\033[3~", 0 }, - { KEYC_DC|KEYC_CTRL, "\033[3^", 0 }, { KEYC_HOME, "\033[1~", 0 }, - { KEYC_HOME|KEYC_CTRL, "\033[1^", 0 }, { KEYC_END, "\033[4~", 0 }, - { KEYC_END|KEYC_CTRL, "\033[4^", 0 }, { KEYC_NPAGE, "\033[6~", 0 }, - { KEYC_NPAGE|KEYC_CTRL, "\033[6^", 0 }, { KEYC_PPAGE, "\033[5~", 0 }, - { KEYC_PPAGE|KEYC_CTRL, "\033[5^", 0 }, { KEYC_BTAB, "\033[Z", 0 }, /* From 15b9946a4094d22f3bde6ef5af67fbb526807329 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 10 Nov 2009 18:53:11 +0000 Subject: [PATCH 0526/1180] There is no real standard for modifier plus function keys. Previously, tmux output some from rxvt but in other ways did the same as xterm or other terminals, but this is a bit inconsistent. xterm's method is fairly sensible and we already support it (xterm-keys), so enable it by default instead. --- tmux.1 | 1 + tmux.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/tmux.1 b/tmux.1 index bd346529..f62f00b2 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1788,6 +1788,7 @@ will generate .Xr xterm 1 -style function key sequences; these have a number included to indicate modifiers such as Shift, Alt or Ctrl. +The default is on. .El .It Xo Ic show-options .Op Fl g diff --git a/tmux.c b/tmux.c index d077aff6..30e1bc60 100644 --- a/tmux.c +++ b/tmux.c @@ -390,7 +390,7 @@ main(int argc, char **argv) options_set_number(wo, "window-status-current-bg", 8); options_set_number(wo, "window-status-current-fg", 8); options_set_number(wo, "window-status-fg", 8); - options_set_number(wo, "xterm-keys", 0); + options_set_number(wo, "xterm-keys", 1); options_set_number(wo, "remain-on-exit", 0); options_set_number(wo, "synchronize-panes", 0); From 2756437f4bd1c0def6877e3742f018b3fbb721da Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 11 Nov 2009 08:00:42 +0000 Subject: [PATCH 0527/1180] Only need to chmod +x or -x the socket when a client is created, lost or attached, rather than every event loop. --- cmd-attach-session.c | 1 + cmd-new-session.c | 1 + server-client.c | 1 + server.c | 9 +++------ tmux.h | 1 + 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/cmd-attach-session.c b/cmd-attach-session.c index 92be3085..59c2b479 100644 --- a/cmd-attach-session.c +++ b/cmd-attach-session.c @@ -101,6 +101,7 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx) server_redraw_client(ctx->cmdclient); } recalculate_sizes(); + server_update_socket(); return (1); /* 1 means don't tell command client to exit */ } diff --git a/cmd-new-session.c b/cmd-new-session.c index 4889ab4b..a9657a97 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -277,6 +277,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) } } recalculate_sizes(); + server_update_socket(); return (!detached); /* 1 means don't tell command client to exit */ } diff --git a/server-client.c b/server-client.c index dd386001..b5d29b7b 100644 --- a/server-client.c +++ b/server-client.c @@ -156,6 +156,7 @@ server_client_lost(struct client *c) c->flags |= CLIENT_DEAD; recalculate_sizes(); + server_update_socket(); } /* Process a single client event. */ diff --git a/server.c b/server.c index 09618d25..209fcd07 100644 --- a/server.c +++ b/server.c @@ -59,7 +59,6 @@ void server_loop(void); int server_should_shutdown(void); void server_send_shutdown(void); void server_clean_dead(void); -int server_update_socket(void); void server_accept_callback(int, short, void *); void server_signal_callback(int, short, void *); void server_child_signal(void); @@ -105,6 +104,8 @@ server_create_socket(void) if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) fatal("fcntl failed"); + server_update_socket(); + return (fd); } @@ -208,8 +209,6 @@ void server_loop(void) { while (!server_should_shutdown()) { - server_update_socket(); - event_loop(EVLOOP_ONCE); server_window_loop(); @@ -288,7 +287,7 @@ server_clean_dead(void) } /* Update socket execute permissions based on whether sessions are attached. */ -int +void server_update_socket(void) { struct session *s; @@ -312,8 +311,6 @@ server_update_socket(void) else chmod(socket_path, S_IRUSR|S_IWUSR); } - - return (n); } /* Callback for server socket. */ diff --git a/tmux.h b/tmux.h index d82363d0..96ad9460 100644 --- a/tmux.h +++ b/tmux.h @@ -1557,6 +1557,7 @@ extern struct clients dead_clients; int server_start(char *); void server_signal_set(void); void server_signal_clear(void); +void server_update_socket(void); /* server-client.c */ void server_client_create(int); From 08a8ccf46b46213d694b250287107712701431c3 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 11 Nov 2009 13:24:42 +0000 Subject: [PATCH 0528/1180] Free the pane bufferevent when the fd is closed (the signal could come before the error callback). --- server.c | 1 + 1 file changed, 1 insertion(+) diff --git a/server.c b/server.c index 209fcd07..d528319a 100644 --- a/server.c +++ b/server.c @@ -450,6 +450,7 @@ server_child_exited(pid_t pid, int status) TAILQ_FOREACH(wp, &w->panes, entry) { if (wp->pid == pid) { close(wp->fd); + bufferevent_free(wp->event); wp->fd = -1; } } From 9df4e7597d86160f747bdbaa6bce043bf81fdb1f Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 11 Nov 2009 18:53:21 +0000 Subject: [PATCH 0529/1180] Add an explicit zero-length check for UTF-8 input data, prompted by a report from parfait via deraadt. While here, add a statement to set the width when filling with _s if not enough space (width should never be high enough at the moment anyway), and wrap some long lines. --- screen-write.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/screen-write.c b/screen-write.c index 8f10976f..49041377 100644 --- a/screen-write.c +++ b/screen-write.c @@ -1039,6 +1039,8 @@ screen_write_cell(struct screen_write_ctx *ctx, /* Construct UTF-8 and write it. */ gu.width = utf8data->width; memset(gu.data, 0xff, sizeof gu.data); + if (utf8data->size == 0) + fatalx("UTF-8 data empty"); if (utf8data->size > sizeof gu.data) fatalx("UTF-8 data overflow"); memcpy(gu.data, utf8data->data, utf8data->size); @@ -1084,6 +1086,10 @@ screen_write_combine( if (s->cx == 0) return (-1); + /* Empty utf8data is out. */ + if (utf8data->size == 0) + fatalx("UTF-8 data empty"); + /* Retrieve the previous cell and convert to UTF-8 if not already. */ gc = grid_view_get_cell(gd, s->cx - 1, s->cy); if (!(gc->flags & GRID_FLAG_UTF8)) { @@ -1108,6 +1114,7 @@ screen_write_combine( gu->data[i] = '_'; if (i != UTF8_SIZE) gu->data[i] = 0xff; + gu->width = i; return (0); } @@ -1166,14 +1173,16 @@ screen_write_overwrite(struct screen_write_ctx *ctx) gu = grid_view_peek_utf8(gd, s->cx, s->cy); if (gu->width > 1) { /* - * An UTF-8 wide cell; overwrite following padding cells only. + * An UTF-8 wide cell; overwrite following padding + * cells only. */ xx = s->cx; while (++xx < screen_size_x(s)) { gc = grid_view_peek_cell(gd, xx, s->cy); if (!(gc->flags & GRID_FLAG_PADDING)) break; - grid_view_set_cell(gd, xx, s->cy, &grid_default_cell); + grid_view_set_cell( + gd, xx, s->cy, &grid_default_cell); } } } From 89763f2ace93af48ca98a9fb19d92eb1eeac792c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 11 Nov 2009 18:56:07 +0000 Subject: [PATCH 0530/1180] Rewrite a confusing loop when freeing the arg array on exit and move the check for argv being NULL, prompted by parfait via deraadt. Also fix some definite brokenness when assigning multiple environment variables in arguments (such as "X=1 Y=2"). --- cmd-string.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/cmd-string.c b/cmd-string.c index 06f01a54..7af34fb0 100644 --- a/cmd-string.c +++ b/cmd-string.c @@ -134,17 +134,15 @@ cmd_string_parse(const char *s, struct cmd_list **cmdlist, char **cause) if (ch != EOF) break; - if (argc == 0) - goto out; - for (i = 0; i < argc; i++) { - equals = strchr(argv[i], '='); - whitespace = argv[i] + strcspn(argv[i], " \t"); + while (argc != 0) { + equals = strchr(argv[0], '='); + whitespace = argv[0] + strcspn(argv[0], " \t"); if (equals == NULL || equals > whitespace) break; - environ_put(&global_environ, argv[i]); - memmove(&argv[i], &argv[i + 1], argc - i - 1); + environ_put(&global_environ, argv[0]); argc--; + memmove(argv, argv + 1, argc * (sizeof *argv)); } if (argc == 0) goto out; @@ -189,10 +187,11 @@ out: if (buf != NULL) xfree(buf); - while (--argc >= 0) - xfree(argv[argc]); - if (argv != NULL) + if (argv != NULL) { + for (i = 0; i < argc; i++) + xfree(argv[argc]); xfree(argv); + } return (rval); } From d9deb4b530e4030ad374ed679b715725d2b951f9 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 12 Nov 2009 08:01:02 +0000 Subject: [PATCH 0531/1180] Support rxvt-style keys again, but this time: support all the variations, put them in as raw escape sequences rather than fiddling with the values from terminfo, put them /after/ the terminfo values so the latter take precedence. --- tty-keys.c | 108 +++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 96 insertions(+), 12 deletions(-) diff --git a/tty-keys.c b/tty-keys.c index 122d5fca..03797994 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -57,7 +57,6 @@ struct tty_key_ent { struct tty_key_ent tty_keys[] = { /* Function keys. */ { TTYC_KF1, NULL, KEYC_F1, 0 }, - { TTYC_KF1, NULL, KEYC_F1, 0 }, { TTYC_KF2, NULL, KEYC_F2, 0 }, { TTYC_KF3, NULL, KEYC_F3, 0 }, { TTYC_KF4, NULL, KEYC_F4, 0 }, @@ -101,17 +100,6 @@ struct tty_key_ent tty_keys[] = { { TTYC_KCUB1, NULL, KEYC_LEFT, 0 }, { TTYC_KCUF1, NULL, KEYC_RIGHT, 0 }, - /* Special-case arrow keys for rxvt until terminfo has kRIT5 etc. */ - { 0, "\033Oa", KEYC_UP|KEYC_CTRL, TTYKEY_RAW }, - { 0, "\033Ob", KEYC_DOWN|KEYC_CTRL, TTYKEY_RAW }, - { 0, "\033Oc", KEYC_RIGHT|KEYC_CTRL, TTYKEY_RAW }, - { 0, "\033Od", KEYC_LEFT|KEYC_CTRL, TTYKEY_RAW }, - - { 0, "\033[a", KEYC_UP|KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[b", KEYC_DOWN|KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[c", KEYC_RIGHT|KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[d", KEYC_LEFT|KEYC_SHIFT, TTYKEY_RAW }, - /* * Numeric keypad. Just use the vt100 escape sequences here and always * put the terminal into keypad_xmit mode. Translation of numbers @@ -195,6 +183,102 @@ struct tty_key_ent tty_keys[] = { { TTYC_KUP5, NULL, KEYC_UP|KEYC_CTRL, 0 }, { TTYC_KUP6, NULL, KEYC_UP|KEYC_SHIFT|KEYC_CTRL, 0 }, { TTYC_KUP7, NULL, KEYC_UP|KEYC_ESCAPE|KEYC_CTRL, 0 }, + + /* rxvt-style arrow + modifier keys. */ + { 0, "\033Oa", KEYC_UP|KEYC_CTRL, TTYKEY_RAW }, + { 0, "\033Ob", KEYC_DOWN|KEYC_CTRL, TTYKEY_RAW }, + { 0, "\033Oc", KEYC_RIGHT|KEYC_CTRL, TTYKEY_RAW }, + { 0, "\033Od", KEYC_LEFT|KEYC_CTRL, TTYKEY_RAW }, + + { 0, "\033[a", KEYC_UP|KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[b", KEYC_DOWN|KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[c", KEYC_RIGHT|KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[d", KEYC_LEFT|KEYC_SHIFT, TTYKEY_RAW }, + + /* + * rxvt-style function + modifier keys: + * Ctrl = ^, Shift = $, Ctrl+Shift = @ + */ + { 0, "\033[11^", KEYC_F1|KEYC_CTRL, TTYKEY_RAW }, + { 0, "\033[12^", KEYC_F2|KEYC_CTRL, TTYKEY_RAW }, + { 0, "\033[13^", KEYC_F3|KEYC_CTRL, TTYKEY_RAW }, + { 0, "\033[14^", KEYC_F4|KEYC_CTRL, TTYKEY_RAW }, + { 0, "\033[15^", KEYC_F5|KEYC_CTRL, TTYKEY_RAW }, + { 0, "\033[17^", KEYC_F6|KEYC_CTRL, TTYKEY_RAW }, + { 0, "\033[18^", KEYC_F7|KEYC_CTRL, TTYKEY_RAW }, + { 0, "\033[19^", KEYC_F8|KEYC_CTRL, TTYKEY_RAW }, + { 0, "\033[20^", KEYC_F9|KEYC_CTRL, TTYKEY_RAW }, + { 0, "\033[21^", KEYC_F10|KEYC_CTRL, TTYKEY_RAW }, + { 0, "\033[23^", KEYC_F11|KEYC_CTRL, TTYKEY_RAW }, + { 0, "\033[24^", KEYC_F12|KEYC_CTRL, TTYKEY_RAW }, + { 0, "\033[25^", KEYC_F13|KEYC_CTRL, TTYKEY_RAW }, + { 0, "\033[26^", KEYC_F14|KEYC_CTRL, TTYKEY_RAW }, + { 0, "\033[28^", KEYC_F15|KEYC_CTRL, TTYKEY_RAW }, + { 0, "\033[29^", KEYC_F16|KEYC_CTRL, TTYKEY_RAW }, + { 0, "\033[31^", KEYC_F17|KEYC_CTRL, TTYKEY_RAW }, + { 0, "\033[32^", KEYC_F18|KEYC_CTRL, TTYKEY_RAW }, + { 0, "\033[33^", KEYC_F19|KEYC_CTRL, TTYKEY_RAW }, + { 0, "\033[34^", KEYC_F20|KEYC_CTRL, TTYKEY_RAW }, + { 0, "\033[2^", KEYC_IC|KEYC_CTRL, TTYKEY_RAW }, + { 0, "\033[3^", KEYC_DC|KEYC_CTRL, TTYKEY_RAW }, + { 0, "\033[7^", KEYC_HOME|KEYC_CTRL, TTYKEY_RAW }, + { 0, "\033[8^", KEYC_END|KEYC_CTRL, TTYKEY_RAW }, + { 0, "\033[6^", KEYC_NPAGE|KEYC_CTRL, TTYKEY_RAW }, + { 0, "\033[5^", KEYC_PPAGE|KEYC_CTRL, TTYKEY_RAW }, + + { 0, "\033[11$", KEYC_F1|KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[12$", KEYC_F2|KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[13$", KEYC_F3|KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[14$", KEYC_F4|KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[15$", KEYC_F5|KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[17$", KEYC_F6|KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[18$", KEYC_F7|KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[19$", KEYC_F8|KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[20$", KEYC_F9|KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[21$", KEYC_F10|KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[23$", KEYC_F11|KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[24$", KEYC_F12|KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[25$", KEYC_F13|KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[26$", KEYC_F14|KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[28$", KEYC_F15|KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[29$", KEYC_F16|KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[31$", KEYC_F17|KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[32$", KEYC_F18|KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[33$", KEYC_F19|KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[34$", KEYC_F20|KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[2$", KEYC_IC|KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[3$", KEYC_DC|KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[7$", KEYC_HOME|KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[8$", KEYC_END|KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[6$", KEYC_NPAGE|KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[5$", KEYC_PPAGE|KEYC_SHIFT, TTYKEY_RAW }, + + { 0, "\033[11@", KEYC_F1|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[12@", KEYC_F2|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[13@", KEYC_F3|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[14@", KEYC_F4|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[15@", KEYC_F5|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[17@", KEYC_F6|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[18@", KEYC_F7|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[19@", KEYC_F8|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[20@", KEYC_F9|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[21@", KEYC_F10|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[23@", KEYC_F11|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[24@", KEYC_F12|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[25@", KEYC_F13|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[26@", KEYC_F14|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[28@", KEYC_F15|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[29@", KEYC_F16|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[31@", KEYC_F17|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[32@", KEYC_F18|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[33@", KEYC_F19|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[34@", KEYC_F20|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[2@", KEYC_IC|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[3@", KEYC_DC|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[7@", KEYC_HOME|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[8@", KEYC_END|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[6@", KEYC_NPAGE|KEYC_CTRL|KEYC_SHIFT,TTYKEY_RAW }, + { 0, "\033[5@", KEYC_PPAGE|KEYC_CTRL|KEYC_SHIFT,TTYKEY_RAW }, }; void From 5ae542e7eed70cf37a658356f37a913a8c4aefef Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 12 Nov 2009 08:05:23 +0000 Subject: [PATCH 0532/1180] Emulate the ri (reverse index) capability: this allows tmux to at least start on Sun consoles (TERM=sun or sun-color), even if there appear to still be problems on some boxes (my Blade 100 is fine but edd's Blade 1000 shows odd screen corruption). --- tty-term.c | 4 ---- tty.c | 3 ++- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/tty-term.c b/tty-term.c index 22fdcb60..09ff9b1e 100644 --- a/tty-term.c +++ b/tty-term.c @@ -378,10 +378,6 @@ tty_term_find(char *name, int fd, const char *overrides, char **cause) xasprintf(cause, "terminal does not support clear"); goto error; } - if (!tty_term_has(term, TTYC_RI)) { - xasprintf(cause, "terminal does not support ri"); - goto error; - } if (!tty_term_has(term, TTYC_CUP)) { xasprintf(cause, "terminal does not support cup"); goto error; diff --git a/tty.c b/tty.c index f7b3ec03..8855a657 100644 --- a/tty.c +++ b/tty.c @@ -711,7 +711,8 @@ tty_cmd_reverseindex(struct tty *tty, const struct tty_ctx *ctx) return; if (wp->xoff != 0 || screen_size_x(s) < tty->sx || - !tty_term_has(tty->term, TTYC_CSR)) { + !tty_term_has(tty->term, TTYC_CSR) || + !tty_term_has(tty->term, TTYC_RI)) { tty_redraw_region(tty, ctx); return; } From 5d397462e45653965e1be64644a3c635eb8ef9cb Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 13 Nov 2009 07:00:54 +0000 Subject: [PATCH 0533/1180] Zap unused functions, prompted by deraadt. --- key-bindings.c | 14 -------------- mode-key.c | 15 --------------- tmux.h | 2 -- 3 files changed, 31 deletions(-) diff --git a/key-bindings.c b/key-bindings.c index d15e0186..5a0aeee0 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -187,20 +187,6 @@ key_bindings_init(void) } } -void -key_bindings_free(void) -{ - struct key_binding *bd; - - key_bindings_clean(); - while (!SPLAY_EMPTY(&key_bindings)) { - bd = SPLAY_ROOT(&key_bindings); - SPLAY_REMOVE(key_bindings, &key_bindings, bd); - cmd_list_free(bd->cmdlist); - xfree(bd); - } -} - void printflike2 key_bindings_error(struct cmd_ctx *ctx, const char *fmt, ...) { diff --git a/mode-key.c b/mode-key.c index d23c54d2..401d232f 100644 --- a/mode-key.c +++ b/mode-key.c @@ -370,21 +370,6 @@ mode_key_init_trees(void) } } -void -mode_key_free_trees(void) -{ - const struct mode_key_table *mtab; - struct mode_key_binding *mbind; - - for (mtab = mode_key_tables; mtab->name != NULL; mtab++) { - while (!SPLAY_EMPTY(mtab->tree)) { - mbind = SPLAY_ROOT(mtab->tree); - SPLAY_REMOVE(mode_key_tree, mtab->tree, mbind); - xfree(mbind); - } - } -} - void mode_key_init(struct mode_key_data *mdata, struct mode_key_tree *mtree) { diff --git a/tmux.h b/tmux.h index 96ad9460..b5f087b2 100644 --- a/tmux.h +++ b/tmux.h @@ -1249,7 +1249,6 @@ const char *mode_key_tostring(struct mode_key_cmdstr *r, enum mode_key_cmd); enum mode_key_cmd mode_key_fromstring(struct mode_key_cmdstr *, const char *); const struct mode_key_table *mode_key_findtable(const char *); void mode_key_init_trees(void); -void mode_key_free_trees(void); void mode_key_init(struct mode_key_data *, struct mode_key_tree *); enum mode_key_cmd mode_key_lookup(struct mode_key_data *, int); @@ -1541,7 +1540,6 @@ void key_bindings_add(int, int, struct cmd_list *); void key_bindings_remove(int); void key_bindings_clean(void); void key_bindings_init(void); -void key_bindings_free(void); void key_bindings_dispatch(struct key_binding *, struct client *); void printflike2 key_bindings_error(struct cmd_ctx *, const char *, ...); void printflike2 key_bindings_print(struct cmd_ctx *, const char *, ...); From 1415eb3dd249e7730b151a5cfd61c47a712a522f Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 13 Nov 2009 14:47:31 +0000 Subject: [PATCH 0534/1180] Use winlink_remove() to remove old winlinks when synchronizing grouped sessions rather than doing it manually and not adjusted the reference count. Fixes crash seen by Dan Harnett. --- session.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/session.c b/session.c index 8d22ac77..db2eb779 100644 --- a/session.c +++ b/session.c @@ -589,7 +589,6 @@ session_group_synchronize1(struct session *target, struct session *s) /* Then free the old winlinks list. */ while (!RB_EMPTY(&old_windows)) { wl = RB_ROOT(&old_windows); - RB_REMOVE(winlinks, &old_windows, wl); - xfree(wl); + winlink_remove(&old_windows, wl); } } From 8e479662255f480cabc45af5edc10098dc3f1819 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 13 Nov 2009 17:33:07 +0000 Subject: [PATCH 0535/1180] Destroy panes immediately rather than checking them all every loop. --- cmd-respawn-window.c | 1 + server-fn.c | 21 +++++++++++++++ server-window.c | 62 -------------------------------------------- server.c | 6 ++--- tmux.h | 1 + window.c | 4 +-- 6 files changed, 26 insertions(+), 69 deletions(-) diff --git a/cmd-respawn-window.c b/cmd-respawn-window.c index 540931aa..227754c1 100644 --- a/cmd-respawn-window.c +++ b/cmd-respawn-window.c @@ -80,6 +80,7 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_ctx *ctx) ctx->error(ctx, "respawn window failed: %s", cause); xfree(cause); environ_free(&env); + server_destroy_pane(wp); return (-1); } layout_init(w); diff --git a/server-fn.c b/server-fn.c index f31e1337..ae1340e7 100644 --- a/server-fn.c +++ b/server-fn.c @@ -316,6 +316,27 @@ server_unlink_window(struct session *s, struct winlink *wl) server_redraw_session_group(s); } +void +server_destroy_pane(struct window_pane *wp) +{ + struct window *w = wp->window; + + close(wp->fd); + bufferevent_free(wp->event); + wp->fd = -1; + + if (options_get_number(&w->options, "remain-on-exit")) + return; + + layout_close_pane(wp); + window_remove_pane(w, wp); + + if (TAILQ_EMPTY(&w->panes)) + server_kill_window(w); + else + server_redraw_window(w); +} + void server_destroy_session_group(struct session *s) { diff --git a/server-window.c b/server-window.c index cb819dfe..319c4478 100644 --- a/server-window.c +++ b/server-window.c @@ -28,7 +28,6 @@ int server_window_check_bell(struct session *, struct window *); int server_window_check_activity(struct session *, struct window *); int server_window_check_content( struct session *, struct window *, struct window_pane *); -void server_window_check_alive(struct window *); /* Check if this window should suspend reading. */ int @@ -90,8 +89,6 @@ server_window_loop(void) server_window_check_content(s, w, wp); } w->flags &= ~(WINDOW_BELL|WINDOW_ACTIVITY|WINDOW_CONTENT); - - server_window_check_alive(w); } } @@ -228,62 +225,3 @@ server_window_check_content( return (1); } - -/* Check if window still exists. */ -void -server_window_check_alive(struct window *w) -{ - struct window_pane *wp, *wq; - struct options *oo = &w->options; - struct session *s; - struct winlink *wl; - u_int i; - int destroyed; - - destroyed = 1; - - wp = TAILQ_FIRST(&w->panes); - while (wp != NULL) { - wq = TAILQ_NEXT(wp, entry); - /* - * If the pane has died and the remain-on-exit flag is not set, - * remove the pane; otherwise, if the flag is set, don't allow - * the window to be destroyed (or it'll close when the last - * pane dies). - */ - if (wp->fd == -1 && !options_get_number(oo, "remain-on-exit")) { - layout_close_pane(wp); - window_remove_pane(w, wp); - server_redraw_window(w); - } else - destroyed = 0; - wp = wq; - } - - if (!destroyed) - return; - - for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { - s = ARRAY_ITEM(&sessions, i); - if (s == NULL) - continue; - if (!session_has(s, w)) - continue; - - restart: - /* Detach window and either redraw or kill clients. */ - RB_FOREACH(wl, winlinks, &s->windows) { - if (wl->window != w) - continue; - if (session_detach(s, wl)) { - server_destroy_session_group(s); - break; - } - server_redraw_session(s); - server_status_session_group(s); - goto restart; - } - } - - recalculate_sizes(); -} diff --git a/server.c b/server.c index d528319a..afb5f6e9 100644 --- a/server.c +++ b/server.c @@ -335,7 +335,6 @@ server_accept_callback(int fd, short events, unused void *data) return; } server_client_create(newfd); - } /* Set up server signal handling. */ @@ -449,9 +448,8 @@ server_child_exited(pid_t pid, int status) continue; TAILQ_FOREACH(wp, &w->panes, entry) { if (wp->pid == pid) { - close(wp->fd); - bufferevent_free(wp->event); - wp->fd = -1; + server_destroy_pane(wp); + break; } } } diff --git a/tmux.h b/tmux.h index b5f087b2..f3fd0b3e 100644 --- a/tmux.h +++ b/tmux.h @@ -1590,6 +1590,7 @@ void server_kill_window(struct window *); int server_link_window(struct session *, struct winlink *, struct session *, int, int, int, char **); void server_unlink_window(struct session *, struct winlink *); +void server_destroy_pane(struct window_pane *); void server_destroy_session_group(struct session *); void server_destroy_session(struct session *); void server_set_identify(struct client *); diff --git a/window.c b/window.c index b550fc65..7e945129 100644 --- a/window.c +++ b/window.c @@ -594,9 +594,7 @@ window_pane_error_callback( { struct window_pane *wp = data; - close(wp->fd); - bufferevent_free(wp->event); - wp->fd = -1; + server_destroy_pane(wp); } void From a18a374d5157bf1b41096f5ecf94716b0002fe2d Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 13 Nov 2009 18:07:52 +0000 Subject: [PATCH 0536/1180] imsg_read returns ssize_t not int, pointed out by lint via deraadt. --- client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client.c b/client.c index d1bd7a64..6f054732 100644 --- a/client.c +++ b/client.c @@ -253,7 +253,7 @@ client_signal(int sig, unused short events, unused void *data) void client_callback(unused int fd, short events, unused void *data) { - int n; + ssize_t n; if (events & EV_READ) { if ((n = imsg_read(&client_ibuf)) == -1 || n == 0) From 390472566cf81fa195202c85d22946d6948d1801 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 13 Nov 2009 18:13:18 +0000 Subject: [PATCH 0537/1180] Tidy up and fix some types, prompted by lint via deraadt. --- server-client.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/server-client.c b/server-client.c index b5d29b7b..a9058594 100644 --- a/server-client.c +++ b/server-client.c @@ -197,7 +197,9 @@ server_client_status_timer(void) struct session *s; struct job *job; struct timeval tv; - u_int i, interval; + u_int i; + int interval; + time_t difference; if (gettimeofday(&tv, NULL) != 0) fatal("gettimeofday failed"); @@ -220,9 +222,10 @@ server_client_status_timer(void) continue; interval = options_get_number(&s->options, "status-interval"); - if (tv.tv_sec - c->status_timer.tv_sec >= interval) { + difference = tv.tv_sec - c->status_timer.tv_sec; + if (difference >= interval) { RB_FOREACH(job, jobs, &c->status_jobs) - job_run(job); + job_run(job); c->flags |= CLIENT_STATUS; } } From dafa0f022c573513f949c7c66ae83d063fa9a2ab Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 13 Nov 2009 18:59:14 +0000 Subject: [PATCH 0538/1180] Unreachable statement, found by lint. --- cmd-pipe-pane.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/cmd-pipe-pane.c b/cmd-pipe-pane.c index d0b0fcca..e66ec955 100644 --- a/cmd-pipe-pane.c +++ b/cmd-pipe-pane.c @@ -127,8 +127,6 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx) fatal("fcntl failed"); return (0); } - - return (0); } void From 76ef8770cd983e7ece581fbcfb3a7ad5e115aae5 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 13 Nov 2009 19:53:28 +0000 Subject: [PATCH 0539/1180] Get rid of the ugly CMD_CHFLAG macro and use a const string (eg "dDU") in the command entry structs and a couple of functions to check/set the flags. --- cmd-attach-session.c | 6 +-- cmd-bind-key.c | 2 +- cmd-break-pane.c | 4 +- cmd-choose-client.c | 2 +- cmd-choose-session.c | 2 +- cmd-choose-window.c | 2 +- cmd-clear-history.c | 2 +- cmd-clock-mode.c | 2 +- cmd-command-prompt.c | 2 +- cmd-confirm-before.c | 2 +- cmd-copy-buffer.c | 2 +- cmd-copy-mode.c | 6 +-- cmd-delete-buffer.c | 2 +- cmd-detach-client.c | 2 +- cmd-display-message.c | 2 +- cmd-display-panes.c | 2 +- cmd-down-pane.c | 2 +- cmd-find-window.c | 2 +- cmd-generic.c | 90 ++++++++++++++++++++------------------- cmd-has-session.c | 2 +- cmd-if-shell.c | 2 +- cmd-kill-pane.c | 4 +- cmd-kill-server.c | 2 +- cmd-kill-session.c | 2 +- cmd-kill-window.c | 2 +- cmd-last-window.c | 2 +- cmd-link-window.c | 6 +-- cmd-list-buffers.c | 2 +- cmd-list-clients.c | 2 +- cmd-list-commands.c | 2 +- cmd-list-keys.c | 2 +- cmd-list-panes.c | 2 +- cmd-list-sessions.c | 2 +- cmd-list-windows.c | 2 +- cmd-load-buffer.c | 2 +- cmd-lock-client.c | 2 +- cmd-lock-server.c | 2 +- cmd-lock-session.c | 2 +- cmd-move-window.c | 6 +-- cmd-new-session.c | 2 +- cmd-new-window.c | 2 +- cmd-next-layout.c | 2 +- cmd-next-window.c | 6 +-- cmd-paste-buffer.c | 6 +-- cmd-pipe-pane.c | 4 +- cmd-previous-layout.c | 2 +- cmd-previous-window.c | 6 +-- cmd-refresh-client.c | 2 +- cmd-rename-session.c | 2 +- cmd-rename-window.c | 2 +- cmd-resize-pane.c | 34 +++++++-------- cmd-respawn-window.c | 4 +- cmd-rotate-window.c | 6 +-- cmd-run-shell.c | 2 +- cmd-save-buffer.c | 4 +- cmd-select-layout.c | 2 +- cmd-select-pane.c | 2 +- cmd-select-prompt.c | 2 +- cmd-select-window.c | 2 +- cmd-send-keys.c | 2 +- cmd-send-prefix.c | 2 +- cmd-server-info.c | 2 +- cmd-set-buffer.c | 2 +- cmd-set-environment.c | 8 ++-- cmd-set-option.c | 10 ++--- cmd-set-window-option.c | 10 ++--- cmd-show-buffer.c | 2 +- cmd-show-environment.c | 4 +- cmd-show-options.c | 4 +- cmd-show-window-options.c | 4 +- cmd-source-file.c | 2 +- cmd-split-window.c | 2 +- cmd-start-server.c | 2 +- cmd-suspend-client.c | 2 +- cmd-swap-pane.c | 13 +++--- cmd-swap-window.c | 4 +- cmd-switch-client.c | 2 +- cmd-unbind-key.c | 2 +- cmd-unlink-window.c | 4 +- cmd-up-pane.c | 2 +- tmux.h | 7 ++- 81 files changed, 186 insertions(+), 186 deletions(-) diff --git a/cmd-attach-session.c b/cmd-attach-session.c index 59c2b479..be7adb3f 100644 --- a/cmd-attach-session.c +++ b/cmd-attach-session.c @@ -29,7 +29,7 @@ int cmd_attach_session_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_attach_session_entry = { "attach-session", "attach", "[-d] " CMD_TARGET_SESSION_USAGE, - CMD_CANTNEST|CMD_STARTSERVER|CMD_SENDENVIRON, CMD_CHFLAG('d'), + CMD_CANTNEST|CMD_STARTSERVER|CMD_SENDENVIRON, "d", cmd_target_init, cmd_target_parse, cmd_attach_session_exec, @@ -58,7 +58,7 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx) return (0); if (ctx->cmdclient == NULL) { - if (data->chflags & CMD_CHFLAG('d')) { + if (cmd_check_flag(data->chflags, 'd')) { /* * Can't use server_write_session in case attaching to * the same session as currently attached to. @@ -89,7 +89,7 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx) return (-1); } - if (data->chflags & CMD_CHFLAG('d')) + if (cmd_check_flag(data->chflags, 'd')) server_write_session(s, MSG_DETACH, NULL, 0); ctx->cmdclient->session = s; diff --git a/cmd-bind-key.c b/cmd-bind-key.c index 041f558d..eba5125b 100644 --- a/cmd-bind-key.c +++ b/cmd-bind-key.c @@ -46,7 +46,7 @@ struct cmd_bind_key_data { const struct cmd_entry cmd_bind_key_entry = { "bind-key", "bind", "[-cnr] [-t key-table] key command [arguments]", - 0, 0, + 0, "", NULL, cmd_bind_key_parse, cmd_bind_key_exec, diff --git a/cmd-break-pane.c b/cmd-break-pane.c index 58a93de2..d465f602 100644 --- a/cmd-break-pane.c +++ b/cmd-break-pane.c @@ -31,7 +31,7 @@ int cmd_break_pane_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_break_pane_entry = { "break-pane", "breakp", CMD_TARGET_PANE_USAGE " [-d]", - 0, CMD_CHFLAG('d'), + 0, "d", cmd_target_init, cmd_target_parse, cmd_break_pane_exec, @@ -74,7 +74,7 @@ cmd_break_pane_exec(struct cmd *self, struct cmd_ctx *ctx) base_idx = options_get_number(&s->options, "base-index"); wl = session_attach(s, w, -1 - base_idx, &cause); /* can't fail */ - if (!(data->chflags & CMD_CHFLAG('d'))) + if (!cmd_check_flag(data->chflags, 'd')) session_select(s, wl->idx); server_redraw_session(s); diff --git a/cmd-choose-client.c b/cmd-choose-client.c index 0aa66622..cd5ab9ea 100644 --- a/cmd-choose-client.c +++ b/cmd-choose-client.c @@ -34,7 +34,7 @@ void cmd_choose_client_free(void *); const struct cmd_entry cmd_choose_client_entry = { "choose-client", NULL, CMD_TARGET_WINDOW_USAGE " [template]", - CMD_ARG01, 0, + CMD_ARG01, "", cmd_target_init, cmd_target_parse, cmd_choose_client_exec, diff --git a/cmd-choose-session.c b/cmd-choose-session.c index b9c7c258..23228105 100644 --- a/cmd-choose-session.c +++ b/cmd-choose-session.c @@ -34,7 +34,7 @@ void cmd_choose_session_free(void *); const struct cmd_entry cmd_choose_session_entry = { "choose-session", NULL, CMD_TARGET_WINDOW_USAGE " [template]", - CMD_ARG01, 0, + CMD_ARG01, "", cmd_target_init, cmd_target_parse, cmd_choose_session_exec, diff --git a/cmd-choose-window.c b/cmd-choose-window.c index 9d6cd932..a1540f1d 100644 --- a/cmd-choose-window.c +++ b/cmd-choose-window.c @@ -34,7 +34,7 @@ void cmd_choose_window_free(void *); const struct cmd_entry cmd_choose_window_entry = { "choose-window", NULL, CMD_TARGET_WINDOW_USAGE " [template]", - CMD_ARG01, 0, + CMD_ARG01, "", cmd_target_init, cmd_target_parse, cmd_choose_window_exec, diff --git a/cmd-clear-history.c b/cmd-clear-history.c index a9271346..9241485a 100644 --- a/cmd-clear-history.c +++ b/cmd-clear-history.c @@ -29,7 +29,7 @@ int cmd_clear_history_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_clear_history_entry = { "clear-history", "clearhist", CMD_TARGET_PANE_USAGE, - 0, 0, + 0, "", cmd_target_init, cmd_target_parse, cmd_clear_history_exec, diff --git a/cmd-clock-mode.c b/cmd-clock-mode.c index b1f135a6..4df934f7 100644 --- a/cmd-clock-mode.c +++ b/cmd-clock-mode.c @@ -29,7 +29,7 @@ int cmd_clock_mode_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_clock_mode_entry = { "clock-mode", NULL, CMD_TARGET_PANE_USAGE, - 0, 0, + 0, "", cmd_target_init, cmd_target_parse, cmd_clock_mode_exec, diff --git a/cmd-command-prompt.c b/cmd-command-prompt.c index bcbde064..e3774256 100644 --- a/cmd-command-prompt.c +++ b/cmd-command-prompt.c @@ -39,7 +39,7 @@ void cmd_command_prompt_cfree(void *); const struct cmd_entry cmd_command_prompt_entry = { "command-prompt", NULL, CMD_TARGET_CLIENT_USAGE " [-p prompts] [template]", - 0, 0, + 0, "", cmd_command_prompt_init, cmd_command_prompt_parse, cmd_command_prompt_exec, diff --git a/cmd-confirm-before.c b/cmd-confirm-before.c index d0a2196a..cdde81ac 100644 --- a/cmd-confirm-before.c +++ b/cmd-confirm-before.c @@ -34,7 +34,7 @@ void cmd_confirm_before_free(void *); const struct cmd_entry cmd_confirm_before_entry = { "confirm-before", "confirm", CMD_TARGET_CLIENT_USAGE " command", - CMD_ARG1, 0, + CMD_ARG1, "", cmd_confirm_before_init, cmd_target_parse, cmd_confirm_before_exec, diff --git a/cmd-copy-buffer.c b/cmd-copy-buffer.c index 98166c4b..3a6a441e 100644 --- a/cmd-copy-buffer.c +++ b/cmd-copy-buffer.c @@ -43,7 +43,7 @@ struct cmd_copy_buffer_data { const struct cmd_entry cmd_copy_buffer_entry = { "copy-buffer", "copyb", "[-a src-index] [-b dst-index] [-s src-session] [-t dst-session]", - 0, 0, + 0, "", cmd_copy_buffer_init, cmd_copy_buffer_parse, cmd_copy_buffer_exec, diff --git a/cmd-copy-mode.c b/cmd-copy-mode.c index fda19efb..48cdd656 100644 --- a/cmd-copy-mode.c +++ b/cmd-copy-mode.c @@ -30,7 +30,7 @@ int cmd_copy_mode_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_copy_mode_entry = { "copy-mode", NULL, "[-u] " CMD_TARGET_PANE_USAGE, - 0, CMD_CHFLAG('u'), + 0, "u", cmd_copy_mode_init, cmd_target_parse, cmd_copy_mode_exec, @@ -48,7 +48,7 @@ cmd_copy_mode_init(struct cmd *self, int key) switch (key) { case KEYC_PPAGE: - data->chflags |= CMD_CHFLAG('u'); + cmd_set_flag(&data->chflags, 'u'); break; } } @@ -63,7 +63,7 @@ cmd_copy_mode_exec(struct cmd *self, struct cmd_ctx *ctx) return (-1); window_pane_set_mode(wp, &window_copy_mode); - if (wp->mode == &window_copy_mode && data->chflags & CMD_CHFLAG('u')) + if (wp->mode == &window_copy_mode && cmd_check_flag(data->chflags, 'u')) window_copy_pageup(wp); return (0); diff --git a/cmd-delete-buffer.c b/cmd-delete-buffer.c index b193438c..1a5b6d82 100644 --- a/cmd-delete-buffer.c +++ b/cmd-delete-buffer.c @@ -31,7 +31,7 @@ int cmd_delete_buffer_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_delete_buffer_entry = { "delete-buffer", "deleteb", CMD_BUFFER_SESSION_USAGE, - 0, 0, + 0, "", cmd_buffer_init, cmd_buffer_parse, cmd_delete_buffer_exec, diff --git a/cmd-detach-client.c b/cmd-detach-client.c index dd480226..4903281f 100644 --- a/cmd-detach-client.c +++ b/cmd-detach-client.c @@ -29,7 +29,7 @@ int cmd_detach_client_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_detach_client_entry = { "detach-client", "detach", CMD_TARGET_CLIENT_USAGE, - 0, 0, + 0, "", cmd_target_init, cmd_target_parse, cmd_detach_client_exec, diff --git a/cmd-display-message.c b/cmd-display-message.c index 71421ea2..1ff5718b 100644 --- a/cmd-display-message.c +++ b/cmd-display-message.c @@ -31,7 +31,7 @@ int cmd_display_message_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_display_message_entry = { "display-message", "display", CMD_TARGET_CLIENT_USAGE " [message]", - CMD_ARG01, 0, + CMD_ARG01, "", cmd_target_init, cmd_target_parse, cmd_display_message_exec, diff --git a/cmd-display-panes.c b/cmd-display-panes.c index 141e3436..42ecbb9b 100644 --- a/cmd-display-panes.c +++ b/cmd-display-panes.c @@ -29,7 +29,7 @@ int cmd_display_panes_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_display_panes_entry = { "display-panes", "displayp", CMD_TARGET_CLIENT_USAGE, - 0, 0, + 0, "", cmd_target_init, cmd_target_parse, cmd_display_panes_exec, diff --git a/cmd-down-pane.c b/cmd-down-pane.c index 242c6ac3..a0f771eb 100644 --- a/cmd-down-pane.c +++ b/cmd-down-pane.c @@ -29,7 +29,7 @@ int cmd_down_pane_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_down_pane_entry = { "down-pane", "downp", CMD_TARGET_WINDOW_USAGE, - 0, 0, + 0, "", cmd_target_init, cmd_target_parse, cmd_down_pane_exec, diff --git a/cmd-find-window.c b/cmd-find-window.c index 0a1c38da..49e29337 100644 --- a/cmd-find-window.c +++ b/cmd-find-window.c @@ -34,7 +34,7 @@ void cmd_find_window_callback(void *, int); const struct cmd_entry cmd_find_window_entry = { "find-window", "findw", CMD_TARGET_WINDOW_USAGE " match-string", - CMD_ARG1, 0, + CMD_ARG1, "", cmd_target_init, cmd_target_parse, cmd_find_window_exec, diff --git a/cmd-generic.c b/cmd-generic.c index 89dc2e25..59d9bbb7 100644 --- a/cmd-generic.c +++ b/cmd-generic.c @@ -23,8 +23,8 @@ #include "tmux.h" -int cmd_getopt(int, char **, const char *, uint64_t); -int cmd_flags(int, uint64_t, uint64_t *); +int cmd_getopt(int, char **, const char *, const char *); +int cmd_parse_flags(int, const char *, uint64_t *); size_t cmd_print_flags(char *, size_t, size_t, uint64_t); int cmd_fill_argument(int, char **, char **, int, char **); @@ -36,51 +36,53 @@ cmd_prarg(char *buf, size_t len, const char *prefix, char *arg) return (xsnprintf(buf, len, "%s%s", prefix, arg)); } -/* Prepend flags from chflags onto flagstr and call getopt. */ +/* Append two flag strings together and call getopt. */ int -cmd_getopt(int argc, char **argv, const char *flagstr, uint64_t chflags) +cmd_getopt(int argc, char **argv, const char *flagstr, const char *chflagstr) { - u_char ch; - char buf[128]; - size_t len, off; + char tmp[BUFSIZ]; - *buf = '\0'; - - len = sizeof buf; - off = 0; - - for (ch = 0; ch < 26; ch++) { - if (chflags & CMD_CHFLAG('a' + ch)) - off += xsnprintf(buf + off, len - off, "%c", 'a' + ch); - if (chflags & CMD_CHFLAG('A' + ch)) - off += xsnprintf(buf + off, len - off, "%c", 'A' + ch); - } - - strlcat(buf, flagstr, sizeof buf); - - return (getopt(argc, argv, buf)); + if (strlcpy(tmp, flagstr, sizeof tmp) >= sizeof tmp) + fatalx("strlcpy overflow"); + if (strlcat(tmp, chflagstr, sizeof tmp) >= sizeof tmp) + fatalx("strlcat overflow"); + return (getopt(argc, argv, tmp)); } -/* - * If this option is expected (in ichflags), set it in ochflags, otherwise - * return -1. - */ +/* Return if flag character is set. */ int -cmd_flags(int opt, uint64_t ichflags, uint64_t *ochflags) +cmd_check_flag(uint64_t chflags, int flag) { - u_char ch; + if (flag >= 'A' && flag <= 'Z') + flag = 26 + flag - 'A'; + else if (flag >= 'a' && flag <= 'z') + flag = flag - 'a'; + else + return (0); + return ((chflags & (1ULL << flag)) != 0); +} - for (ch = 0; ch < 26; ch++) { - if (opt == 'a' + ch && ichflags & CMD_CHFLAG(opt)) { - (*ochflags) |= CMD_CHFLAG(opt); - return (0); - } - if (opt == 'A' + ch && ichflags & CMD_CHFLAG(opt)) { - (*ochflags) |= CMD_CHFLAG(opt); - return (0); - } - } - return (-1); +/* Set flag character. */ +void +cmd_set_flag(uint64_t *chflags, int flag) +{ + if (flag >= 'A' && flag <= 'Z') + flag = 26 + flag - 'A'; + else if (flag >= 'a' && flag <= 'z') + flag = flag - 'a'; + else + return; + (*chflags) |= (1ULL << flag); +} + +/* If this option is expected, set it in chflags, otherwise return -1. */ +int +cmd_parse_flags(int opt, const char *chflagstr, uint64_t *chflags) +{ + if (strchr(chflagstr, opt) == NULL) + return (-1); + cmd_set_flag(chflags, opt); + return (0); } /* Print the flags supported in chflags. */ @@ -95,9 +97,9 @@ cmd_print_flags(char *buf, size_t len, size_t off, uint64_t chflags) off += xsnprintf(buf + off, len - off, " -"); for (ch = 0; ch < 26; ch++) { - if (chflags & CMD_CHFLAG('a' + ch)) + if (cmd_check_flag(chflags, 'a' + ch)) off += xsnprintf(buf + off, len - off, "%c", 'a' + ch); - if (chflags & CMD_CHFLAG('A' + ch)) + if (cmd_check_flag(chflags, 'A' + ch)) off += xsnprintf(buf + off, len - off, "%c", 'A' + ch); } return (off - boff); @@ -170,7 +172,7 @@ cmd_target_parse(struct cmd *self, int argc, char **argv, char **cause) data = self->data; while ((opt = cmd_getopt(argc, argv, "t:", entry->chflags)) != -1) { - if (cmd_flags(opt, entry->chflags, &data->chflags) == 0) + if (cmd_parse_flags(opt, entry->chflags, &data->chflags) == 0) continue; switch (opt) { case 't': @@ -253,7 +255,7 @@ cmd_srcdst_parse(struct cmd *self, int argc, char **argv, char **cause) data = self->data; while ((opt = cmd_getopt(argc, argv, "s:t:", entry->chflags)) != -1) { - if (cmd_flags(opt, entry->chflags, &data->chflags) == 0) + if (cmd_parse_flags(opt, entry->chflags, &data->chflags) == 0) continue; switch (opt) { case 's': @@ -345,7 +347,7 @@ cmd_buffer_parse(struct cmd *self, int argc, char **argv, char **cause) data = self->data; while ((opt = cmd_getopt(argc, argv, "b:t:", entry->chflags)) != -1) { - if (cmd_flags(opt, entry->chflags, &data->chflags) == 0) + if (cmd_parse_flags(opt, entry->chflags, &data->chflags) == 0) continue; switch (opt) { case 'b': diff --git a/cmd-has-session.c b/cmd-has-session.c index f279a730..00f171b7 100644 --- a/cmd-has-session.c +++ b/cmd-has-session.c @@ -29,7 +29,7 @@ int cmd_has_session_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_has_session_entry = { "has-session", "has", CMD_TARGET_SESSION_USAGE, - 0, 0, + 0, "", cmd_target_init, cmd_target_parse, cmd_has_session_exec, diff --git a/cmd-if-shell.c b/cmd-if-shell.c index 82da814a..1779486a 100644 --- a/cmd-if-shell.c +++ b/cmd-if-shell.c @@ -36,7 +36,7 @@ void cmd_if_shell_free(void *); const struct cmd_entry cmd_if_shell_entry = { "if-shell", "if", "shell-command command", - CMD_ARG2, 0, + CMD_ARG2, "", cmd_target_init, cmd_target_parse, cmd_if_shell_exec, diff --git a/cmd-kill-pane.c b/cmd-kill-pane.c index 351ef0c8..c48e4d4e 100644 --- a/cmd-kill-pane.c +++ b/cmd-kill-pane.c @@ -31,7 +31,7 @@ int cmd_kill_pane_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_kill_pane_entry = { "kill-pane", "killp", "[-a] " CMD_TARGET_PANE_USAGE, - 0, CMD_CHFLAG('a'), + 0, "a", cmd_target_init, cmd_target_parse, cmd_kill_pane_exec, @@ -56,7 +56,7 @@ cmd_kill_pane_exec(struct cmd *self, struct cmd_ctx *ctx) return (0); } - if (data->chflags & CMD_CHFLAG('a')) { + if (cmd_check_flag(data->chflags, 'a')) { loopwp = TAILQ_FIRST(&wl->window->panes); while (loopwp != NULL) { nextwp = TAILQ_NEXT(loopwp, entry); diff --git a/cmd-kill-server.c b/cmd-kill-server.c index d7033a06..cf206770 100644 --- a/cmd-kill-server.c +++ b/cmd-kill-server.c @@ -32,7 +32,7 @@ int cmd_kill_server_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_kill_server_entry = { "kill-server", NULL, "", - 0, 0, + 0, "", NULL, NULL, cmd_kill_server_exec, diff --git a/cmd-kill-session.c b/cmd-kill-session.c index 402b869b..ff0b95e3 100644 --- a/cmd-kill-session.c +++ b/cmd-kill-session.c @@ -32,7 +32,7 @@ int cmd_kill_session_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_kill_session_entry = { "kill-session", NULL, CMD_TARGET_SESSION_USAGE, - 0, 0, + 0, "", cmd_target_init, cmd_target_parse, cmd_kill_session_exec, diff --git a/cmd-kill-window.c b/cmd-kill-window.c index d213a90e..aae1cc85 100644 --- a/cmd-kill-window.c +++ b/cmd-kill-window.c @@ -29,7 +29,7 @@ int cmd_kill_window_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_kill_window_entry = { "kill-window", "killw", CMD_TARGET_WINDOW_USAGE, - 0, 0, + 0, "", cmd_target_init, cmd_target_parse, cmd_kill_window_exec, diff --git a/cmd-last-window.c b/cmd-last-window.c index 0f7a4571..5f065ccb 100644 --- a/cmd-last-window.c +++ b/cmd-last-window.c @@ -29,7 +29,7 @@ int cmd_last_window_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_last_window_entry = { "last-window", "last", CMD_TARGET_SESSION_USAGE, - 0, 0, + 0, "", cmd_target_init, cmd_target_parse, cmd_last_window_exec, diff --git a/cmd-link-window.c b/cmd-link-window.c index a0b81dcc..f8da27dd 100644 --- a/cmd-link-window.c +++ b/cmd-link-window.c @@ -31,7 +31,7 @@ int cmd_link_window_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_link_window_entry = { "link-window", "linkw", "[-dk] " CMD_SRCDST_WINDOW_USAGE, - 0, CMD_CHFLAG('d')|CMD_CHFLAG('k'), + 0, "dk", cmd_srcdst_init, cmd_srcdst_parse, cmd_link_window_exec, @@ -53,8 +53,8 @@ cmd_link_window_exec(struct cmd *self, struct cmd_ctx *ctx) if ((idx = cmd_find_index(ctx, data->dst, &dst)) == -2) return (-1); - kflag = data->chflags & CMD_CHFLAG('k'); - dflag = data->chflags & CMD_CHFLAG('d'); + kflag = cmd_check_flag(data->chflags, 'k'); + dflag = cmd_check_flag(data->chflags, 'd'); if (server_link_window(src, wl, dst, idx, kflag, !dflag, &cause) != 0) { ctx->error(ctx, "can't link window: %s", cause); xfree(cause); diff --git a/cmd-list-buffers.c b/cmd-list-buffers.c index bb0e6a64..ab08928e 100644 --- a/cmd-list-buffers.c +++ b/cmd-list-buffers.c @@ -32,7 +32,7 @@ int cmd_list_buffers_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_list_buffers_entry = { "list-buffers", "lsb", CMD_TARGET_SESSION_USAGE, - 0, 0, + 0, "", cmd_target_init, cmd_target_parse, cmd_list_buffers_exec, diff --git a/cmd-list-clients.c b/cmd-list-clients.c index 905edf94..4b7bc7b7 100644 --- a/cmd-list-clients.c +++ b/cmd-list-clients.c @@ -32,7 +32,7 @@ int cmd_list_clients_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_list_clients_entry = { "list-clients", "lsc", "", - 0, 0, + 0, "", NULL, NULL, cmd_list_clients_exec, diff --git a/cmd-list-commands.c b/cmd-list-commands.c index 9f2942ae..9b669b67 100644 --- a/cmd-list-commands.c +++ b/cmd-list-commands.c @@ -29,7 +29,7 @@ int cmd_list_commands_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_list_commands_entry = { "list-commands", "lscm", "", - 0, 0, + 0, "", NULL, NULL, cmd_list_commands_exec, diff --git a/cmd-list-keys.c b/cmd-list-keys.c index f4bd064a..b61951f9 100644 --- a/cmd-list-keys.c +++ b/cmd-list-keys.c @@ -33,7 +33,7 @@ int cmd_list_keys_table(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_list_keys_entry = { "list-keys", "lsk", "[-t key-table]", - 0, 0, + 0, "", cmd_target_init, cmd_target_parse, cmd_list_keys_exec, diff --git a/cmd-list-panes.c b/cmd-list-panes.c index 5a06eb7a..112a2835 100644 --- a/cmd-list-panes.c +++ b/cmd-list-panes.c @@ -31,7 +31,7 @@ int cmd_list_panes_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_list_panes_entry = { "list-panes", "lsp", CMD_TARGET_WINDOW_USAGE, - 0, 0, + 0, "", cmd_target_init, cmd_target_parse, cmd_list_panes_exec, diff --git a/cmd-list-sessions.c b/cmd-list-sessions.c index 908278d5..d0210552 100644 --- a/cmd-list-sessions.c +++ b/cmd-list-sessions.c @@ -31,7 +31,7 @@ int cmd_list_sessions_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_list_sessions_entry = { "list-sessions", "ls", "", - 0, 0, + 0, "", NULL, NULL, cmd_list_sessions_exec, diff --git a/cmd-list-windows.c b/cmd-list-windows.c index f8a46bcd..7e78c94e 100644 --- a/cmd-list-windows.c +++ b/cmd-list-windows.c @@ -31,7 +31,7 @@ int cmd_list_windows_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_list_windows_entry = { "list-windows", "lsw", CMD_TARGET_SESSION_USAGE, - 0, 0, + 0, "", cmd_target_init, cmd_target_parse, cmd_list_windows_exec, diff --git a/cmd-load-buffer.c b/cmd-load-buffer.c index a3f09ca4..354aa463 100644 --- a/cmd-load-buffer.c +++ b/cmd-load-buffer.c @@ -35,7 +35,7 @@ int cmd_load_buffer_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_load_buffer_entry = { "load-buffer", "loadb", CMD_BUFFER_SESSION_USAGE " path", - CMD_ARG1, 0, + CMD_ARG1, "", cmd_buffer_init, cmd_buffer_parse, cmd_load_buffer_exec, diff --git a/cmd-lock-client.c b/cmd-lock-client.c index e855d32c..607c9d22 100644 --- a/cmd-lock-client.c +++ b/cmd-lock-client.c @@ -29,7 +29,7 @@ int cmd_lock_client_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_lock_client_entry = { "lock-client", "lockc", CMD_TARGET_CLIENT_USAGE, - 0, 0, + 0, "", cmd_target_init, cmd_target_parse, cmd_lock_client_exec, diff --git a/cmd-lock-server.c b/cmd-lock-server.c index 55c19e38..1d8f80e4 100644 --- a/cmd-lock-server.c +++ b/cmd-lock-server.c @@ -33,7 +33,7 @@ int cmd_lock_server_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_lock_server_entry = { "lock-server", "lock", "", - 0, 0, + 0, "", NULL, NULL, cmd_lock_server_exec, diff --git a/cmd-lock-session.c b/cmd-lock-session.c index c0a6569c..279ab655 100644 --- a/cmd-lock-session.c +++ b/cmd-lock-session.c @@ -29,7 +29,7 @@ int cmd_lock_session_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_lock_session_entry = { "lock-session", "locks", CMD_TARGET_SESSION_USAGE, - 0, 0, + 0, "", cmd_target_init, cmd_target_parse, cmd_lock_session_exec, diff --git a/cmd-move-window.c b/cmd-move-window.c index 175e6576..6105812a 100644 --- a/cmd-move-window.c +++ b/cmd-move-window.c @@ -31,7 +31,7 @@ int cmd_move_window_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_move_window_entry = { "move-window", "movew", "[-dk] " CMD_SRCDST_WINDOW_USAGE, - 0, CMD_CHFLAG('d')|CMD_CHFLAG('k'), + 0, "dk", cmd_srcdst_init, cmd_srcdst_parse, cmd_move_window_exec, @@ -53,8 +53,8 @@ cmd_move_window_exec(struct cmd *self, struct cmd_ctx *ctx) if ((idx = cmd_find_index(ctx, data->dst, &dst)) == -2) return (-1); - kflag = data->chflags & CMD_CHFLAG('k'); - dflag = data->chflags & CMD_CHFLAG('d'); + kflag = cmd_check_flag(data->chflags, 'k'); + dflag = cmd_check_flag(data->chflags, 'd'); if (server_link_window(src, wl, dst, idx, kflag, !dflag, &cause) != 0) { ctx->error(ctx, "can't move window: %s", cause); xfree(cause); diff --git a/cmd-new-session.c b/cmd-new-session.c index a9657a97..8103392d 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -44,7 +44,7 @@ struct cmd_new_session_data { const struct cmd_entry cmd_new_session_entry = { "new-session", "new", "[-d] [-n window-name] [-s session-name] [-t target-session] [command]", - CMD_STARTSERVER|CMD_CANTNEST|CMD_SENDENVIRON, 0, + CMD_STARTSERVER|CMD_CANTNEST|CMD_SENDENVIRON, "", cmd_new_session_init, cmd_new_session_parse, cmd_new_session_exec, diff --git a/cmd-new-window.c b/cmd-new-window.c index 44fe6b5a..e251c8cb 100644 --- a/cmd-new-window.c +++ b/cmd-new-window.c @@ -43,7 +43,7 @@ struct cmd_new_window_data { const struct cmd_entry cmd_new_window_entry = { "new-window", "neww", "[-dk] [-n window-name] [-t target-window] [command]", - 0, 0, + 0, "", cmd_new_window_init, cmd_new_window_parse, cmd_new_window_exec, diff --git a/cmd-next-layout.c b/cmd-next-layout.c index 03459ffc..aa033a83 100644 --- a/cmd-next-layout.c +++ b/cmd-next-layout.c @@ -29,7 +29,7 @@ int cmd_next_layout_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_next_layout_entry = { "next-layout", "nextl", CMD_TARGET_WINDOW_USAGE, - 0, 0, + 0, "", cmd_target_init, cmd_target_parse, cmd_next_layout_exec, diff --git a/cmd-next-window.c b/cmd-next-window.c index 94c7b1ce..cc361b62 100644 --- a/cmd-next-window.c +++ b/cmd-next-window.c @@ -30,7 +30,7 @@ int cmd_next_window_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_next_window_entry = { "next-window", "next", "[-a] " CMD_TARGET_SESSION_USAGE, - 0, CMD_CHFLAG('a'), + 0, "a", cmd_next_window_init, cmd_target_parse, cmd_next_window_exec, @@ -47,7 +47,7 @@ cmd_next_window_init(struct cmd *self, int key) data = self->data; if (key == ('n' | KEYC_ESCAPE)) - data->chflags |= CMD_CHFLAG('a'); + cmd_set_flag(&data->chflags, 'a'); } int @@ -61,7 +61,7 @@ cmd_next_window_exec(struct cmd *self, struct cmd_ctx *ctx) return (-1); activity = 0; - if (data->chflags & CMD_CHFLAG('a')) + if (cmd_check_flag(data->chflags, 'a')) activity = 1; if (session_next(s, activity) == 0) diff --git a/cmd-paste-buffer.c b/cmd-paste-buffer.c index e8e638ef..11f70f1f 100644 --- a/cmd-paste-buffer.c +++ b/cmd-paste-buffer.c @@ -32,7 +32,7 @@ void cmd_paste_buffer_lf2cr(struct window_pane *, const char *, size_t); const struct cmd_entry cmd_paste_buffer_entry = { "paste-buffer", "pasteb", "[-dr] " CMD_BUFFER_WINDOW_USAGE, - 0, CMD_CHFLAG('d')|CMD_CHFLAG('r'), + 0, "dr", cmd_buffer_init, cmd_buffer_parse, cmd_paste_buffer_exec, @@ -64,14 +64,14 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) if (pb != NULL && *pb->data != '\0') { /* -r means raw data without LF->CR conversion. */ - if (data->chflags & CMD_CHFLAG('r')) + if (cmd_check_flag(data->chflags, 'r')) bufferevent_write(wp->event, pb->data, pb->size); else cmd_paste_buffer_lf2cr(wp, pb->data, pb->size); } /* Delete the buffer if -d. */ - if (data->chflags & CMD_CHFLAG('d')) { + if (cmd_check_flag(data->chflags, 'd')) { if (data->buffer == -1) paste_free_top(&s->buffers); else diff --git a/cmd-pipe-pane.c b/cmd-pipe-pane.c index e66ec955..135d3837 100644 --- a/cmd-pipe-pane.c +++ b/cmd-pipe-pane.c @@ -38,7 +38,7 @@ void cmd_pipe_pane_error_callback(struct bufferevent *, short, void *); const struct cmd_entry cmd_pipe_pane_entry = { "pipe-pane", "pipep", CMD_TARGET_PANE_USAGE "[-o] [command]", - CMD_ARG01, CMD_CHFLAG('o'), + CMD_ARG01, "o", cmd_target_init, cmd_target_parse, cmd_pipe_pane_exec, @@ -74,7 +74,7 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx) * * bind ^p pipep -o 'cat >>~/output' */ - if (data->chflags & CMD_CHFLAG('o') && old_fd != -1) + if (cmd_check_flag(data->chflags, 'o') && old_fd != -1) return (0); /* Open the new pipe. */ diff --git a/cmd-previous-layout.c b/cmd-previous-layout.c index dcdfdeae..083ac3e9 100644 --- a/cmd-previous-layout.c +++ b/cmd-previous-layout.c @@ -29,7 +29,7 @@ int cmd_previous_layout_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_previous_layout_entry = { "previous-layout", "prevl", CMD_TARGET_WINDOW_USAGE, - 0, 0, + 0, "", cmd_target_init, cmd_target_parse, cmd_previous_layout_exec, diff --git a/cmd-previous-window.c b/cmd-previous-window.c index 3aa1f6a3..0357e76d 100644 --- a/cmd-previous-window.c +++ b/cmd-previous-window.c @@ -30,7 +30,7 @@ int cmd_previous_window_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_previous_window_entry = { "previous-window", "prev", "[-a] " CMD_TARGET_SESSION_USAGE, - 0, CMD_CHFLAG('a'), + 0, "a", cmd_previous_window_init, cmd_target_parse, cmd_previous_window_exec, @@ -47,7 +47,7 @@ cmd_previous_window_init(struct cmd *self, int key) data = self->data; if (key == ('p' | KEYC_ESCAPE)) - data->chflags |= CMD_CHFLAG('a'); + cmd_set_flag(&data->chflags, 'a'); } int @@ -61,7 +61,7 @@ cmd_previous_window_exec(struct cmd *self, struct cmd_ctx *ctx) return (-1); activity = 0; - if (data->chflags & CMD_CHFLAG('a')) + if (cmd_check_flag(data->chflags, 'a')) activity = 1; if (session_previous(s, activity) == 0) diff --git a/cmd-refresh-client.c b/cmd-refresh-client.c index a3015f02..03662a85 100644 --- a/cmd-refresh-client.c +++ b/cmd-refresh-client.c @@ -29,7 +29,7 @@ int cmd_refresh_client_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_refresh_client_entry = { "refresh-client", "refresh", CMD_TARGET_CLIENT_USAGE, - 0, 0, + 0, "", cmd_target_init, cmd_target_parse, cmd_refresh_client_exec, diff --git a/cmd-rename-session.c b/cmd-rename-session.c index ae798717..679c6109 100644 --- a/cmd-rename-session.c +++ b/cmd-rename-session.c @@ -31,7 +31,7 @@ int cmd_rename_session_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_rename_session_entry = { "rename-session", "rename", CMD_TARGET_SESSION_USAGE " new-name", - CMD_ARG1, 0, + CMD_ARG1, "", cmd_target_init, cmd_target_parse, cmd_rename_session_exec, diff --git a/cmd-rename-window.c b/cmd-rename-window.c index 6f4f9ab8..112bd299 100644 --- a/cmd-rename-window.c +++ b/cmd-rename-window.c @@ -31,7 +31,7 @@ int cmd_rename_window_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_rename_window_entry = { "rename-window", "renamew", CMD_TARGET_WINDOW_USAGE " new-name", - CMD_ARG1, 0, + CMD_ARG1, "", cmd_target_init, cmd_target_parse, cmd_rename_window_exec, diff --git a/cmd-resize-pane.c b/cmd-resize-pane.c index 30fbc76a..e8d77176 100644 --- a/cmd-resize-pane.c +++ b/cmd-resize-pane.c @@ -31,9 +31,8 @@ int cmd_resize_pane_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_resize_pane_entry = { "resize-pane", "resizep", - "[-DU] " CMD_TARGET_PANE_USAGE " [adjustment]", - CMD_ARG01, - CMD_CHFLAG('D')|CMD_CHFLAG('L')|CMD_CHFLAG('R')|CMD_CHFLAG('U'), + "[-DLRU] " CMD_TARGET_PANE_USAGE " [adjustment]", + CMD_ARG01, "DLRU", cmd_resize_pane_init, cmd_target_parse, cmd_resize_pane_exec, @@ -50,28 +49,28 @@ cmd_resize_pane_init(struct cmd *self, int key) data = self->data; if (key == (KEYC_UP | KEYC_CTRL)) - data->chflags |= CMD_CHFLAG('U'); + cmd_set_flag(&data->chflags, 'U'); if (key == (KEYC_DOWN | KEYC_CTRL)) - data->chflags |= CMD_CHFLAG('D'); + cmd_set_flag(&data->chflags, 'D'); if (key == (KEYC_LEFT | KEYC_CTRL)) - data->chflags |= CMD_CHFLAG('L'); + cmd_set_flag(&data->chflags, 'L'); if (key == (KEYC_RIGHT | KEYC_CTRL)) - data->chflags |= CMD_CHFLAG('R'); + cmd_set_flag(&data->chflags, 'R'); if (key == (KEYC_UP | KEYC_ESCAPE)) { - data->chflags |= CMD_CHFLAG('U'); + cmd_set_flag(&data->chflags, 'U'); data->arg = xstrdup("5"); } if (key == (KEYC_DOWN | KEYC_ESCAPE)) { - data->chflags |= CMD_CHFLAG('D'); + cmd_set_flag(&data->chflags, 'D'); data->arg = xstrdup("5"); } if (key == (KEYC_LEFT | KEYC_ESCAPE)) { - data->chflags |= CMD_CHFLAG('L'); + cmd_set_flag(&data->chflags, 'L'); data->arg = xstrdup("5"); } if (key == (KEYC_RIGHT | KEYC_ESCAPE)) { - data->chflags |= CMD_CHFLAG('R'); + cmd_set_flag(&data->chflags, 'R'); data->arg = xstrdup("5"); } } @@ -98,15 +97,14 @@ cmd_resize_pane_exec(struct cmd *self, struct cmd_ctx *ctx) } } - if (data->chflags & (CMD_CHFLAG('L')|CMD_CHFLAG('R'))) { - if (data->chflags & CMD_CHFLAG('L')) - adjust = -adjust; + if (cmd_check_flag(data->chflags, 'L')) + layout_resize_pane(wp, LAYOUT_LEFTRIGHT, -adjust); + else if (cmd_check_flag(data->chflags, 'R')) layout_resize_pane(wp, LAYOUT_LEFTRIGHT, adjust); - } else { - if (data->chflags & CMD_CHFLAG('U')) - adjust = -adjust; + else if (cmd_check_flag(data->chflags, 'U')) + layout_resize_pane(wp, LAYOUT_TOPBOTTOM, -adjust); + else if (cmd_check_flag(data->chflags, 'D')) layout_resize_pane(wp, LAYOUT_TOPBOTTOM, adjust); - } server_redraw_window(wl->window); return (0); diff --git a/cmd-respawn-window.c b/cmd-respawn-window.c index 227754c1..2810ea6c 100644 --- a/cmd-respawn-window.c +++ b/cmd-respawn-window.c @@ -31,7 +31,7 @@ int cmd_respawn_window_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_respawn_window_entry = { "respawn-window", "respawnw", "[-k] " CMD_TARGET_WINDOW_USAGE " [command]", - CMD_ARG01, CMD_CHFLAG('k'), + CMD_ARG01, "k", cmd_target_init, cmd_target_parse, cmd_respawn_window_exec, @@ -54,7 +54,7 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_ctx *ctx) return (-1); w = wl->window; - if (!(data->chflags & CMD_CHFLAG('k'))) { + if (!cmd_check_flag(data->chflags, 'k')) { TAILQ_FOREACH(wp, &w->panes, entry) { if (wp->fd == -1) continue; diff --git a/cmd-rotate-window.c b/cmd-rotate-window.c index 71705a75..fbfba099 100644 --- a/cmd-rotate-window.c +++ b/cmd-rotate-window.c @@ -30,7 +30,7 @@ int cmd_rotate_window_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_rotate_window_entry = { "rotate-window", "rotatew", "[-DU] " CMD_TARGET_WINDOW_USAGE, - 0, CMD_CHFLAG('D')|CMD_CHFLAG('U'), + 0, "DU", cmd_rotate_window_init, cmd_target_parse, cmd_rotate_window_exec, @@ -47,7 +47,7 @@ cmd_rotate_window_init(struct cmd *self, int key) data = self->data; if (key == ('o' | KEYC_ESCAPE)) - data->chflags |= CMD_CHFLAG('D'); + cmd_set_flag(&data->chflags, 'D'); } int @@ -64,7 +64,7 @@ cmd_rotate_window_exec(struct cmd *self, struct cmd_ctx *ctx) return (-1); w = wl->window; - if (data->chflags & CMD_CHFLAG('D')) { + if (cmd_check_flag(data->chflags, 'D')) { wp = TAILQ_LAST(&w->panes, window_panes); TAILQ_REMOVE(&w->panes, wp, entry); TAILQ_INSERT_HEAD(&w->panes, wp, entry); diff --git a/cmd-run-shell.c b/cmd-run-shell.c index 605b5dca..f5e834f1 100644 --- a/cmd-run-shell.c +++ b/cmd-run-shell.c @@ -36,7 +36,7 @@ void cmd_run_shell_free(void *); const struct cmd_entry cmd_run_shell_entry = { "run-shell", "run", "command", - CMD_ARG1, 0, + CMD_ARG1, "", cmd_target_init, cmd_target_parse, cmd_run_shell_exec, diff --git a/cmd-save-buffer.c b/cmd-save-buffer.c index 33859fd6..22bc44f8 100644 --- a/cmd-save-buffer.c +++ b/cmd-save-buffer.c @@ -33,7 +33,7 @@ int cmd_save_buffer_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_save_buffer_entry = { "save-buffer", "saveb", "[-a] " CMD_BUFFER_SESSION_USAGE " path", - CMD_ARG1, CMD_CHFLAG('a'), + CMD_ARG1, "a", cmd_buffer_init, cmd_buffer_parse, cmd_save_buffer_exec, @@ -66,7 +66,7 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) } mask = umask(S_IRWXG | S_IRWXO); - if (data->chflags & CMD_CHFLAG('a')) + if (cmd_check_flag(data->chflags, 'a')) f = fopen(data->arg, "ab"); else f = fopen(data->arg, "wb"); diff --git a/cmd-select-layout.c b/cmd-select-layout.c index 3613514e..0dc126f4 100644 --- a/cmd-select-layout.c +++ b/cmd-select-layout.c @@ -30,7 +30,7 @@ int cmd_select_layout_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_select_layout_entry = { "select-layout", "selectl", CMD_TARGET_WINDOW_USAGE " [layout-name]", - CMD_ARG01, 0, + CMD_ARG01, "", cmd_select_layout_init, cmd_target_parse, cmd_select_layout_exec, diff --git a/cmd-select-pane.c b/cmd-select-pane.c index 3923ea73..890cebc6 100644 --- a/cmd-select-pane.c +++ b/cmd-select-pane.c @@ -29,7 +29,7 @@ int cmd_select_pane_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_select_pane_entry = { "select-pane", "selectp", CMD_TARGET_PANE_USAGE, - 0, 0, + 0, "", cmd_target_init, cmd_target_parse, cmd_select_pane_exec, diff --git a/cmd-select-prompt.c b/cmd-select-prompt.c index bead0619..12fe711d 100644 --- a/cmd-select-prompt.c +++ b/cmd-select-prompt.c @@ -33,7 +33,7 @@ int cmd_select_prompt_callback(void *, const char *); const struct cmd_entry cmd_select_prompt_entry = { "select-prompt", NULL, CMD_TARGET_CLIENT_USAGE, - 0, 0, + 0, "", cmd_target_init, cmd_target_parse, cmd_select_prompt_exec, diff --git a/cmd-select-window.c b/cmd-select-window.c index dba77c30..6aeaad22 100644 --- a/cmd-select-window.c +++ b/cmd-select-window.c @@ -32,7 +32,7 @@ int cmd_select_window_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_select_window_entry = { "select-window", "selectw", CMD_TARGET_WINDOW_USAGE, - 0, 0, + 0, "", cmd_select_window_init, cmd_target_parse, cmd_select_window_exec, diff --git a/cmd-send-keys.c b/cmd-send-keys.c index ff41c1ee..8b848e76 100644 --- a/cmd-send-keys.c +++ b/cmd-send-keys.c @@ -40,7 +40,7 @@ struct cmd_send_keys_data { const struct cmd_entry cmd_send_keys_entry = { "send-keys", "send", "[-t target-pane] key ...", - 0, 0, + 0, "", NULL, cmd_send_keys_parse, cmd_send_keys_exec, diff --git a/cmd-send-prefix.c b/cmd-send-prefix.c index a149fdac..ccc98151 100644 --- a/cmd-send-prefix.c +++ b/cmd-send-prefix.c @@ -29,7 +29,7 @@ int cmd_send_prefix_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_send_prefix_entry = { "send-prefix", NULL, CMD_TARGET_PANE_USAGE, - 0, 0, + 0, "", cmd_target_init, cmd_target_parse, cmd_send_prefix_exec, diff --git a/cmd-server-info.c b/cmd-server-info.c index 4bd6b67f..03cd2e95 100644 --- a/cmd-server-info.c +++ b/cmd-server-info.c @@ -36,7 +36,7 @@ int cmd_server_info_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_server_info_entry = { "server-info", "info", "", - 0, 0, + 0, "", NULL, NULL, cmd_server_info_exec, diff --git a/cmd-set-buffer.c b/cmd-set-buffer.c index 2f624040..4e50cc7a 100644 --- a/cmd-set-buffer.c +++ b/cmd-set-buffer.c @@ -31,7 +31,7 @@ int cmd_set_buffer_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_set_buffer_entry = { "set-buffer", "setb", CMD_BUFFER_SESSION_USAGE " data", - CMD_ARG1, 0, + CMD_ARG1, "", cmd_buffer_init, cmd_buffer_parse, cmd_set_buffer_exec, diff --git a/cmd-set-environment.c b/cmd-set-environment.c index 4ba66a07..fdd703c5 100644 --- a/cmd-set-environment.c +++ b/cmd-set-environment.c @@ -32,7 +32,7 @@ int cmd_set_environment_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_set_environment_entry = { "set-environment", "setenv", "[-gru] " CMD_TARGET_SESSION_USAGE " name [value]", - CMD_ARG12, CMD_CHFLAG('g')|CMD_CHFLAG('r')|CMD_CHFLAG('u'), + CMD_ARG12, "gru", NULL, cmd_target_parse, cmd_set_environment_exec, @@ -56,7 +56,7 @@ cmd_set_environment_exec(struct cmd *self, struct cmd_ctx *ctx) return (-1); } - if (data->chflags & CMD_CHFLAG('g')) + if (cmd_check_flag(data->chflags, 'g')) env = &global_environ; else { if ((s = cmd_find_session(ctx, data->target)) == NULL) @@ -64,13 +64,13 @@ cmd_set_environment_exec(struct cmd *self, struct cmd_ctx *ctx) env = &s->environ; } - if (data->chflags & CMD_CHFLAG('u')) { + if (cmd_check_flag(data->chflags, 'u')) { if (data->arg2 != NULL) { ctx->error(ctx, "can't specify a value with -u"); return (-1); } environ_unset(env, data->arg); - } else if (data->chflags & CMD_CHFLAG('r')) { + } else if (cmd_check_flag(data->chflags, 'r')) { if (data->arg2 != NULL) { ctx->error(ctx, "can't specify a value with -r"); return (-1); diff --git a/cmd-set-option.c b/cmd-set-option.c index 536b623b..2e00c8d7 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -32,7 +32,7 @@ int cmd_set_option_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_set_option_entry = { "set-option", "set", "[-agu] " CMD_TARGET_SESSION_USAGE " option [value]", - CMD_ARG12, CMD_CHFLAG('a')|CMD_CHFLAG('g')|CMD_CHFLAG('u'), + CMD_ARG12, "agu", NULL, cmd_target_parse, cmd_set_option_exec, @@ -113,7 +113,7 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) u_int i; int try_again; - if (data->chflags & CMD_CHFLAG('g')) + if (cmd_check_flag(data->chflags, 'g')) oo = &global_s_options; else { if ((s = cmd_find_session(ctx, data->target)) == NULL) @@ -145,8 +145,8 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) return (-1); } - if (data->chflags & CMD_CHFLAG('u')) { - if (data->chflags & CMD_CHFLAG('g')) { + if (cmd_check_flag(data->chflags, 'u')) { + if (cmd_check_flag(data->chflags, 'g')) { ctx->error(ctx, "can't unset global option: %s", entry->name); return (-1); @@ -163,7 +163,7 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) switch (entry->type) { case SET_OPTION_STRING: set_option_string(ctx, oo, entry, - data->arg2, data->chflags & CMD_CHFLAG('a')); + data->arg2, cmd_check_flag(data->chflags, 'a')); break; case SET_OPTION_NUMBER: set_option_number(ctx, oo, entry, data->arg2); diff --git a/cmd-set-window-option.c b/cmd-set-window-option.c index 1ac62147..1d7b8cc5 100644 --- a/cmd-set-window-option.c +++ b/cmd-set-window-option.c @@ -32,7 +32,7 @@ int cmd_set_window_option_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_set_window_option_entry = { "set-window-option", "setw", "[-agu] " CMD_TARGET_WINDOW_USAGE " option [value]", - CMD_ARG12, CMD_CHFLAG('a')|CMD_CHFLAG('g')|CMD_CHFLAG('u'), + CMD_ARG12, "agu", NULL, cmd_target_parse, cmd_set_window_option_exec, @@ -86,7 +86,7 @@ cmd_set_window_option_exec(struct cmd *self, struct cmd_ctx *ctx) const struct set_option_entry *entry, *opt; u_int i; - if (data->chflags & CMD_CHFLAG('g')) + if (cmd_check_flag(data->chflags, 'g')) oo = &global_w_options; else { if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) @@ -118,8 +118,8 @@ cmd_set_window_option_exec(struct cmd *self, struct cmd_ctx *ctx) return (-1); } - if (data->chflags & CMD_CHFLAG('u')) { - if (data->chflags & CMD_CHFLAG('g')) { + if (cmd_check_flag(data->chflags, 'u')) { + if (cmd_check_flag(data->chflags, 'g')) { ctx->error(ctx, "can't unset global option: %s", entry->name); return (-1); @@ -136,7 +136,7 @@ cmd_set_window_option_exec(struct cmd *self, struct cmd_ctx *ctx) switch (entry->type) { case SET_OPTION_STRING: set_option_string(ctx, oo, entry, - data->arg2, data->chflags & CMD_CHFLAG('a')); + data->arg2, cmd_check_flag(data->chflags, 'a')); break; case SET_OPTION_NUMBER: set_option_number(ctx, oo, entry, data->arg2); diff --git a/cmd-show-buffer.c b/cmd-show-buffer.c index 151fc2ae..d4484f08 100644 --- a/cmd-show-buffer.c +++ b/cmd-show-buffer.c @@ -31,7 +31,7 @@ int cmd_show_buffer_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_show_buffer_entry = { "show-buffer", "showb", CMD_BUFFER_SESSION_USAGE, - 0, 0, + 0, "", cmd_buffer_init, cmd_buffer_parse, cmd_show_buffer_exec, diff --git a/cmd-show-environment.c b/cmd-show-environment.c index 6a86ec67..6d0f364c 100644 --- a/cmd-show-environment.c +++ b/cmd-show-environment.c @@ -32,7 +32,7 @@ int cmd_show_environment_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_show_environment_entry = { "show-environment", "showenv", "[-g] " CMD_TARGET_SESSION_USAGE, - 0, CMD_CHFLAG('g'), + 0, "g", cmd_target_init, cmd_target_parse, cmd_show_environment_exec, @@ -48,7 +48,7 @@ cmd_show_environment_exec(struct cmd *self, struct cmd_ctx *ctx) struct environ *env; struct environ_entry *envent; - if (data->chflags & CMD_CHFLAG('g')) + if (cmd_check_flag(data->chflags, 'g')) env = &global_environ; else { if ((s = cmd_find_session(ctx, data->target)) == NULL) diff --git a/cmd-show-options.c b/cmd-show-options.c index 9e84c64a..9e7fd7db 100644 --- a/cmd-show-options.c +++ b/cmd-show-options.c @@ -32,7 +32,7 @@ int cmd_show_options_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_show_options_entry = { "show-options", "show", "[-g] " CMD_TARGET_SESSION_USAGE, - 0, CMD_CHFLAG('g'), + 0, "g", cmd_target_init, cmd_target_parse, cmd_show_options_exec, @@ -50,7 +50,7 @@ cmd_show_options_exec(struct cmd *self, struct cmd_ctx *ctx) const struct set_option_entry *entry; const char *optval; - if (data->chflags & CMD_CHFLAG('g')) + if (cmd_check_flag(data->chflags, 'g')) oo = &global_s_options; else { if ((s = cmd_find_session(ctx, data->target)) == NULL) diff --git a/cmd-show-window-options.c b/cmd-show-window-options.c index 04477233..2609cfab 100644 --- a/cmd-show-window-options.c +++ b/cmd-show-window-options.c @@ -32,7 +32,7 @@ int cmd_show_window_options_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_show_window_options_entry = { "show-window-options", "showw", "[-g] " CMD_TARGET_WINDOW_USAGE, - 0, CMD_CHFLAG('g'), + 0, "g", cmd_target_init, cmd_target_parse, cmd_show_window_options_exec, @@ -50,7 +50,7 @@ cmd_show_window_options_exec(struct cmd *self, struct cmd_ctx *ctx) const struct set_option_entry *entry; const char *optval; - if (data->chflags & CMD_CHFLAG('g')) + if (cmd_check_flag(data->chflags, 'g')) oo = &global_w_options; else { if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) diff --git a/cmd-source-file.c b/cmd-source-file.c index 2cb47c6e..a53a1cb8 100644 --- a/cmd-source-file.c +++ b/cmd-source-file.c @@ -37,7 +37,7 @@ struct cmd_source_file_data { const struct cmd_entry cmd_source_file_entry = { "source-file", "source", "path", - 0, 0, + 0, "", cmd_source_file_init, cmd_source_file_parse, cmd_source_file_exec, diff --git a/cmd-split-window.c b/cmd-split-window.c index a1a012a2..4dd03055 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -46,7 +46,7 @@ struct cmd_split_window_data { const struct cmd_entry cmd_split_window_entry = { "split-window", "splitw", "[-dhv] [-p percentage|-l size] [-t target-window] [command]", - 0, 0, + 0, "", cmd_split_window_init, cmd_split_window_parse, cmd_split_window_exec, diff --git a/cmd-start-server.c b/cmd-start-server.c index 0fa5bc49..382ae48d 100644 --- a/cmd-start-server.c +++ b/cmd-start-server.c @@ -29,7 +29,7 @@ int cmd_start_server_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_start_server_entry = { "start-server", "start", "", - CMD_STARTSERVER, 0, + CMD_STARTSERVER, "", NULL, NULL, cmd_start_server_exec, diff --git a/cmd-suspend-client.c b/cmd-suspend-client.c index f1fc6109..5c166c37 100644 --- a/cmd-suspend-client.c +++ b/cmd-suspend-client.c @@ -37,7 +37,7 @@ struct cmd_suspend_client_data { const struct cmd_entry cmd_suspend_client_entry = { "suspend-client", "suspendc", "[-c target-client]", - 0, 0, + 0, "", cmd_target_init, cmd_target_parse, cmd_suspend_client_exec, diff --git a/cmd-swap-pane.c b/cmd-swap-pane.c index a49e064a..a1bd3de9 100644 --- a/cmd-swap-pane.c +++ b/cmd-swap-pane.c @@ -32,7 +32,7 @@ int cmd_swap_pane_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_swap_pane_entry = { "swap-pane", "swapp", "[-dDU] " CMD_SRCDST_PANE_USAGE, - 0, CMD_CHFLAG('d')|CMD_CHFLAG('D')|CMD_CHFLAG('U'), + 0, "dDU", cmd_swap_pane_init, cmd_srcdst_parse, cmd_swap_pane_exec, @@ -49,11 +49,12 @@ cmd_swap_pane_init(struct cmd *self, int key) data = self->data; if (key == '{') - data->chflags |= CMD_CHFLAG('U'); + cmd_set_flag(&data->chflags, 'U'); else if (key == '}') - data->chflags |= CMD_CHFLAG('D'); + cmd_set_flag(&data->chflags, 'D'); } + int cmd_swap_pane_exec(struct cmd *self, struct cmd_ctx *ctx) { @@ -73,11 +74,11 @@ cmd_swap_pane_exec(struct cmd *self, struct cmd_ctx *ctx) if (data->src == NULL) { src_w = dst_w; - if (data->chflags & CMD_CHFLAG('D')) { + if (cmd_check_flag(data->chflags, 'D')) { src_wp = TAILQ_NEXT(dst_wp, entry); if (src_wp == NULL) src_wp = TAILQ_FIRST(&dst_w->panes); - } else if (data->chflags & CMD_CHFLAG('U')) { + } else if (cmd_check_flag(data->chflags, 'U')) { src_wp = TAILQ_PREV(dst_wp, window_panes, entry); if (src_wp == NULL) src_wp = TAILQ_LAST(&dst_w->panes, window_panes); @@ -120,7 +121,7 @@ cmd_swap_pane_exec(struct cmd *self, struct cmd_ctx *ctx) dst_wp->xoff = xoff; dst_wp->yoff = yoff; window_pane_resize(dst_wp, sx, sy); - if (!(data->chflags & CMD_CHFLAG('d'))) { + if (!cmd_check_flag(data->chflags, 'd')) { if (src_w != dst_w) { window_set_active_pane(src_w, dst_wp); window_set_active_pane(dst_w, src_wp); diff --git a/cmd-swap-window.c b/cmd-swap-window.c index f164f234..ab532eb0 100644 --- a/cmd-swap-window.c +++ b/cmd-swap-window.c @@ -31,7 +31,7 @@ int cmd_swap_window_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_swap_window_entry = { "swap-window", "swapw", "[-d] " CMD_SRCDST_WINDOW_USAGE, - 0, CMD_CHFLAG('d'), + 0, "d", cmd_srcdst_init, cmd_srcdst_parse, cmd_swap_window_exec, @@ -68,7 +68,7 @@ cmd_swap_window_exec(struct cmd *self, struct cmd_ctx *ctx) wl_dst->window = wl_src->window; wl_src->window = w; - if (!(data->chflags & CMD_CHFLAG('d'))) { + if (!cmd_check_flag(data->chflags, 'd')) { session_select(dst, wl_dst->idx); if (src != dst) session_select(src, wl_src->idx); diff --git a/cmd-switch-client.c b/cmd-switch-client.c index 80c4dc5d..9ff1c081 100644 --- a/cmd-switch-client.c +++ b/cmd-switch-client.c @@ -40,7 +40,7 @@ struct cmd_switch_client_data { const struct cmd_entry cmd_switch_client_entry = { "switch-client", "switchc", "[-c target-client] [-t target-session]", - 0, 0, + 0, "", NULL, cmd_switch_client_parse, cmd_switch_client_exec, diff --git a/cmd-unbind-key.c b/cmd-unbind-key.c index 8f5e794e..4633274d 100644 --- a/cmd-unbind-key.c +++ b/cmd-unbind-key.c @@ -40,7 +40,7 @@ struct cmd_unbind_key_data { const struct cmd_entry cmd_unbind_key_entry = { "unbind-key", "unbind", "[-cn] [-t key-table] key", - 0, 0, + 0, "", NULL, cmd_unbind_key_parse, cmd_unbind_key_exec, diff --git a/cmd-unlink-window.c b/cmd-unlink-window.c index e38b6e1e..15bafc08 100644 --- a/cmd-unlink-window.c +++ b/cmd-unlink-window.c @@ -29,7 +29,7 @@ int cmd_unlink_window_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_unlink_window_entry = { "unlink-window", "unlinkw", "[-k] " CMD_TARGET_WINDOW_USAGE, - 0, CMD_CHFLAG('k'), + 0, "k", cmd_target_init, cmd_target_parse, cmd_unlink_window_exec, @@ -59,7 +59,7 @@ cmd_unlink_window_exec(struct cmd *self, struct cmd_ctx *ctx) } else references = 1; - if (!(data->chflags & CMD_CHFLAG('k')) && w->references == references) { + if (!cmd_check_flag(data->chflags, 'k') && w->references == references) { ctx->error(ctx, "window is only linked to one session"); return (-1); } diff --git a/cmd-up-pane.c b/cmd-up-pane.c index 966952d6..49ab49a7 100644 --- a/cmd-up-pane.c +++ b/cmd-up-pane.c @@ -29,7 +29,7 @@ int cmd_up_pane_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_up_pane_entry = { "up-pane", "upp", CMD_TARGET_WINDOW_USAGE, - 0, 0, + 0, "", cmd_target_init, cmd_target_parse, cmd_up_pane_exec, diff --git a/tmux.h b/tmux.h index f3fd0b3e..7613460e 100644 --- a/tmux.h +++ b/tmux.h @@ -1150,10 +1150,7 @@ struct cmd_entry { #define CMD_ARG12 0x40 int flags; -#define CMD_CHFLAG(flag) \ - ((flag) >= 'a' && (flag) <= 'z' ? 1ULL << ((flag) - 'a') : \ - (flag) >= 'A' && (flag) <= 'Z' ? 1ULL << (26 + (flag) - 'A') : 0) - uint64_t chflags; + const char *chflags; void (*init)(struct cmd *, int); int (*parse)(struct cmd *, int, char **, char **); @@ -1502,6 +1499,8 @@ int cmd_string_parse(const char *, struct cmd_list **, char **); /* cmd-generic.c */ size_t cmd_prarg(char *, size_t, const char *, char *); +int cmd_check_flag(uint64_t, int); +void cmd_set_flag(uint64_t *, int); #define CMD_TARGET_PANE_USAGE "[-t target-pane]" #define CMD_TARGET_WINDOW_USAGE "[-t target-window]" #define CMD_TARGET_SESSION_USAGE "[-t target-session]" From 10e05f9867f8129c24596ca929952136e1bd496e Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 13 Nov 2009 19:58:32 +0000 Subject: [PATCH 0540/1180] Tweak a comment and add some spacing. --- cmd-generic.c | 2 +- tmux.h | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/cmd-generic.c b/cmd-generic.c index 59d9bbb7..5232bc98 100644 --- a/cmd-generic.c +++ b/cmd-generic.c @@ -85,7 +85,7 @@ cmd_parse_flags(int opt, const char *chflagstr, uint64_t *chflags) return (0); } -/* Print the flags supported in chflags. */ +/* Print the flags present in chflags. */ size_t cmd_print_flags(char *buf, size_t len, size_t off, uint64_t chflags) { diff --git a/tmux.h b/tmux.h index 7613460e..55c720ad 100644 --- a/tmux.h +++ b/tmux.h @@ -1162,23 +1162,29 @@ struct cmd_entry { /* Generic command data. */ struct cmd_target_data { uint64_t chflags; + char *target; + char *arg; char *arg2; }; struct cmd_srcdst_data { uint64_t chflags; + char *src; char *dst; + char *arg; char *arg2; }; struct cmd_buffer_data { uint64_t chflags; + char *target; int buffer; + char *arg; char *arg2; }; From 9f6d685c05c9f71ba842f65fb2139ebbd30bd606 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 16 Nov 2009 11:15:44 +0000 Subject: [PATCH 0541/1180] I made a complete horlicks of the last change, fix it so it doesn't either lead to a double free or free the item after the end of the array. --- cmd-string.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/cmd-string.c b/cmd-string.c index 7af34fb0..1a380e50 100644 --- a/cmd-string.c +++ b/cmd-string.c @@ -151,10 +151,6 @@ cmd_string_parse(const char *s, struct cmd_list **cmdlist, char **cause) if (*cmdlist == NULL) goto out; - do - xfree(argv[argc - 1]); - while (--argc > 0); - rval = 0; goto out; case '~': @@ -189,7 +185,7 @@ out: if (argv != NULL) { for (i = 0; i < argc; i++) - xfree(argv[argc]); + xfree(argv[i]); xfree(argv); } From 5d7bff40519f6e000cedfabce4ff0f5e6b8bcd98 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 16 Nov 2009 13:40:45 +0000 Subject: [PATCH 0542/1180] A screen can be one cell wide; don't crash if that is the case. --- screen-write.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/screen-write.c b/screen-write.c index 49041377..81231c2e 100644 --- a/screen-write.c +++ b/screen-write.c @@ -427,8 +427,8 @@ screen_write_initctx( return; /* Save the last cell on the screen. */ - gc = NULL; - for (xx = 1; xx < screen_size_x(s); xx++) { + gc = &grid_default_cell; + for (xx = 1; xx <= screen_size_x(s); xx++) { gc = grid_view_peek_cell(gd, screen_size_x(s) - xx, s->cy); if (!(gc->flags & GRID_FLAG_PADDING)) break; From 67bf0933e2f85267f46cf7e348ba48d504bc0344 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 17 Nov 2009 13:06:11 +0000 Subject: [PATCH 0543/1180] In choose mode, assign each item a number or lowercase letter from those available and accept that as a shortcut key for the item. --- window-choose.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 59 insertions(+), 3 deletions(-) diff --git a/window-choose.c b/window-choose.c index c44fe88d..a0f66b81 100644 --- a/window-choose.c +++ b/window-choose.c @@ -64,6 +64,9 @@ struct window_choose_mode_data { void *data; }; +int window_choose_key_index(struct window_choose_mode_data *, u_int); +int window_choose_index_key(struct window_choose_mode_data *, int); + void window_choose_vadd(struct window_pane *wp, int idx, const char *fmt, va_list ap) { @@ -173,7 +176,8 @@ window_choose_key(struct window_pane *wp, unused struct client *c, int key) struct screen *s = &data->screen; struct screen_write_ctx ctx; struct window_choose_mode_item *item; - u_int items; + u_int items; + int idx; items = ARRAY_LENGTH(&data->list); @@ -259,6 +263,14 @@ window_choose_key(struct window_pane *wp, unused struct client *c, int key) window_choose_redraw_screen(wp); break; default: + idx = window_choose_index_key(data, key); + if (idx < 0 || (u_int) idx >= ARRAY_LENGTH(&data->list)) + break; + data->selected = idx; + + item = &ARRAY_ITEM(&data->list, data->selected); + data->callbackfn(data->data, item->idx); + window_pane_reset_mode(wp); break; } } @@ -299,6 +311,7 @@ window_choose_write_line( struct screen *s = &data->screen; struct grid_cell gc; int utf8flag; + char key; if (data->callbackfn == NULL) fatalx("called before callback assigned"); @@ -314,13 +327,56 @@ window_choose_write_line( screen_write_cursormove(ctx, 0, py); if (data->top + py < ARRAY_LENGTH(&data->list)) { item = &ARRAY_ITEM(&data->list, data->top + py); - screen_write_nputs( - ctx, screen_size_x(s) - 1, &gc, utf8flag, "%s", item->name); + key = window_choose_key_index(data, data->top + py); + if (key != -1) { + screen_write_nputs(ctx, screen_size_x(s) - 1, + &gc, utf8flag, "(%c) %s", key, item->name); + } else { + screen_write_nputs(ctx, screen_size_x(s) - 1, + &gc, utf8flag, " %s", item->name); + } + } while (s->cx < screen_size_x(s)) screen_write_putc(ctx, &gc, ' '); } +int +window_choose_key_index(struct window_choose_mode_data *data, u_int idx) +{ + static const char keys[] = "0123456789abcdefghijklmnopqrstuvwxyz"; + const char *ptr; + int mkey; + + for (ptr = keys; *ptr != '\0'; ptr++) { + mkey = mode_key_lookup(&data->mdata, *ptr); + if (mkey != MODEKEY_NONE && mkey != MODEKEY_OTHER) + continue; + if (idx-- == 0) + return (*ptr); + } + return (-1); +} + +int +window_choose_index_key(struct window_choose_mode_data *data, int key) +{ + static const char keys[] = "0123456789abcdefghijklmnopqrstuvwxyz"; + const char *ptr; + int mkey; + u_int idx = 0; + + for (ptr = keys; *ptr != '\0'; ptr++) { + mkey = mode_key_lookup(&data->mdata, *ptr); + if (mkey != MODEKEY_NONE && mkey != MODEKEY_OTHER) + continue; + if (key == *ptr) + return (idx); + idx++; + } + return (-1); +} + void window_choose_redraw_screen(struct window_pane *wp) { From a9ca8df8e3c477560dc6455cd4c73e582b89aef5 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 17 Nov 2009 13:30:07 +0000 Subject: [PATCH 0544/1180] Permit top-bit-set characters to be entered in the status line. They could already be set from the shell and are just passed through when printing (so invisible characters or displaying on terminals with different character sets may cause problems). Note that entering UTF-8 may not work and in any case currently the status line cannot display it correctly (outside of status-left/status-right). --- status.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/status.c b/status.c index deb3a621..c030e777 100644 --- a/status.c +++ b/status.c @@ -976,7 +976,7 @@ status_prompt_key(struct client *c, int key) status_prompt_clear(c); break; case MODEKEY_OTHER: - if (key < 32 || key > 126) + if (key < 32 || key == 127) break; c->prompt_buffer = xrealloc(c->prompt_buffer, 1, size + 2); From 68f5c9c72da0c4430733de2094fbb8bc4d1e0474 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 18 Nov 2009 10:18:25 +0000 Subject: [PATCH 0545/1180] Mark -n keys with (no prefix) rather than []. --- cmd-list-keys.c | 10 ++++++---- tmux.1 | 3 ++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/cmd-list-keys.c b/cmd-list-keys.c index b61951f9..13785fac 100644 --- a/cmd-list-keys.c +++ b/cmd-list-keys.c @@ -71,13 +71,15 @@ cmd_list_keys_exec(struct cmd *self, struct cmd_ctx *ctx) key = key_string_lookup_key(bd->key & ~KEYC_PREFIX); if (key == NULL) continue; - if (!(bd->key & KEYC_PREFIX)) - used = xsnprintf(tmp, sizeof tmp, "[%s]: ", key); - else - used = xsnprintf(tmp, sizeof tmp, "%*s: ", width, key); + used = xsnprintf(tmp, sizeof tmp, "%*s: ", width, key); if (used >= sizeof tmp) continue; + if (!(bd->key & KEYC_PREFIX)) { + used = strlcat(tmp, "(no prefix) ", sizeof tmp); + if (used >= sizeof tmp) + continue; + } cmd_list_print(bd->cmdlist, tmp + used, (sizeof tmp) - used); ctx->print(ctx, "%s", tmp); } diff --git a/tmux.1 b/tmux.1 index f62f00b2..412b70b0 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1114,7 +1114,8 @@ are printed. Keys bound without the prefix key (see .Ic bind-key .Fl n ) -are enclosed in square brackets. +are marked with +.Ql (no prefix) . .Pp With .Fl t , From 8db145da1ed40d471e9ecff0e788ced26a43fc92 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 18 Nov 2009 13:16:33 +0000 Subject: [PATCH 0546/1180] Add a per-client log of status line messages displayed while that client exists. A new message-limit session option sets the maximum number of entries and a command, show-messages, shows the log (bound to ~ by default). This (and prompt history) might be better as a single global log but until there are global options it is easier for them to be per client. --- Makefile | 2 +- cmd-set-option.c | 1 + cmd-show-messages.c | 65 +++++++++++++++++++++++++++++++++++++++++++++ cmd.c | 1 + key-bindings.c | 11 ++++---- server-client.c | 9 ++++++- status.c | 26 +++++++++++++++--- tmux.1 | 14 ++++++++++ tmux.c | 1 + tmux.h | 8 ++++++ 10 files changed, 127 insertions(+), 11 deletions(-) create mode 100644 cmd-show-messages.c diff --git a/Makefile b/Makefile index 88900fd8..0f6f2707 100644 --- a/Makefile +++ b/Makefile @@ -22,7 +22,7 @@ SRCS= attributes.c cfg.c client.c clock.c \ cmd-select-layout.c cmd-select-pane.c \ cmd-select-prompt.c cmd-select-window.c cmd-send-keys.c \ cmd-send-prefix.c cmd-server-info.c cmd-set-buffer.c cmd-set-option.c \ - cmd-set-window-option.c cmd-show-buffer.c \ + cmd-set-window-option.c cmd-show-buffer.c cmd-show-messages.c \ cmd-show-options.c cmd-show-window-options.c cmd-source-file.c \ cmd-split-window.c cmd-start-server.c cmd-string.c cmd-if-shell.c \ cmd-run-shell.c cmd-suspend-client.c cmd-swap-pane.c cmd-swap-window.c \ diff --git a/cmd-set-option.c b/cmd-set-option.c index 2e00c8d7..0a06c620 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -67,6 +67,7 @@ const struct set_option_entry set_option_table[] = { { "message-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL }, { "message-bg", SET_OPTION_COLOUR, 0, 0, NULL }, { "message-fg", SET_OPTION_COLOUR, 0, 0, NULL }, + { "message-limit", SET_OPTION_NUMBER, 0, INT_MAX, NULL }, { "mouse-select-pane", SET_OPTION_FLAG, 0, 0, NULL }, { "prefix", SET_OPTION_KEYS, 0, 0, NULL }, { "repeat-time", SET_OPTION_NUMBER, 0, SHRT_MAX, NULL }, diff --git a/cmd-show-messages.c b/cmd-show-messages.c new file mode 100644 index 00000000..c624af54 --- /dev/null +++ b/cmd-show-messages.c @@ -0,0 +1,65 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2009 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 "tmux.h" + +/* + * Show client message log. + */ + +int cmd_show_messages_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_show_messages_entry = { + "show-messages", "showmsgs", + CMD_TARGET_CLIENT_USAGE, + 0, "", + cmd_target_init, + cmd_target_parse, + cmd_show_messages_exec, + cmd_target_free, + cmd_target_print +}; + +int +cmd_show_messages_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_target_data *data = self->data; + struct client *c; + struct message_entry *msg; + char *tim; + u_int i; + + if ((c = cmd_find_client(ctx, data->target)) == NULL) + return (-1); + + for (i = 0; i < ARRAY_LENGTH(&c->message_log); i++) { + msg = &ARRAY_ITEM(&c->message_log, i); + + tim = ctime(&msg->msg_time); + *strchr(tim, '\n') = '\0'; + + ctx->print(ctx, "%s %s", tim, msg->msg); + } + + return (0); +} diff --git a/cmd.c b/cmd.c index 9008a532..10e25225 100644 --- a/cmd.c +++ b/cmd.c @@ -95,6 +95,7 @@ const struct cmd_entry *cmd_table[] = { &cmd_set_window_option_entry, &cmd_show_buffer_entry, &cmd_show_environment_entry, + &cmd_show_messages_entry, &cmd_show_options_entry, &cmd_show_window_options_entry, &cmd_source_file_entry, diff --git a/key-bindings.c b/key-bindings.c index 5a0aeee0..e3045ec0 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -105,8 +105,8 @@ key_bindings_init(void) { ' ', 0, &cmd_next_layout_entry }, { '!', 0, &cmd_break_pane_entry }, { '"', 0, &cmd_split_window_entry }, - { '%', 0, &cmd_split_window_entry }, { '#', 0, &cmd_list_buffers_entry }, + { '%', 0, &cmd_split_window_entry }, { '&', 0, &cmd_confirm_before_entry }, { ',', 0, &cmd_command_prompt_entry }, { '-', 0, &cmd_delete_buffer_entry }, @@ -123,13 +123,15 @@ key_bindings_init(void) { '9', 0, &cmd_select_window_entry }, { ':', 0, &cmd_command_prompt_entry }, { '?', 0, &cmd_list_keys_entry }, + { 'D', 0, &cmd_choose_client_entry }, { '[', 0, &cmd_copy_mode_entry }, { '\'', 0, &cmd_select_prompt_entry }, + { '\002', /* C-b */ 0, &cmd_send_prefix_entry }, + { '\017', /* C-o */ 0, &cmd_rotate_window_entry }, { '\032', /* C-z */ 0, &cmd_suspend_client_entry }, { ']', 0, &cmd_paste_buffer_entry }, { 'c', 0, &cmd_new_window_entry }, { 'd', 0, &cmd_detach_client_entry }, - { 'D', 0, &cmd_choose_client_entry }, { 'f', 0, &cmd_command_prompt_entry }, { 'i', 0, &cmd_display_message_entry }, { 'l', 0, &cmd_last_window_entry }, @@ -144,13 +146,14 @@ key_bindings_init(void) { 'x', 0, &cmd_confirm_before_entry }, { '{', 0, &cmd_swap_pane_entry }, { '}', 0, &cmd_swap_pane_entry }, - { '\002', /* C-b */ 0, &cmd_send_prefix_entry }, + { '~', 0, &cmd_show_messages_entry }, { '1' | KEYC_ESCAPE, 0, &cmd_select_layout_entry }, { '2' | KEYC_ESCAPE, 0, &cmd_select_layout_entry }, { '3' | KEYC_ESCAPE, 0, &cmd_select_layout_entry }, { '4' | KEYC_ESCAPE, 0, &cmd_select_layout_entry }, { KEYC_PPAGE, 0, &cmd_copy_mode_entry }, { 'n' | KEYC_ESCAPE, 0, &cmd_next_window_entry }, + { 'o' | KEYC_ESCAPE, 0, &cmd_rotate_window_entry }, { 'p' | KEYC_ESCAPE, 0, &cmd_previous_window_entry }, { KEYC_UP, 0, &cmd_up_pane_entry }, { KEYC_DOWN, 0, &cmd_down_pane_entry }, @@ -162,8 +165,6 @@ key_bindings_init(void) { KEYC_DOWN | KEYC_CTRL, 1, &cmd_resize_pane_entry }, { KEYC_LEFT | KEYC_CTRL, 1, &cmd_resize_pane_entry }, { KEYC_RIGHT | KEYC_CTRL, 1, &cmd_resize_pane_entry }, - { 'o' | KEYC_ESCAPE, 0, &cmd_rotate_window_entry }, - { '\017', /* C-o */ 0, &cmd_rotate_window_entry }, }; u_int i; struct cmd *cmd; diff --git a/server-client.c b/server-client.c index a9058594..8ff71223 100644 --- a/server-client.c +++ b/server-client.c @@ -80,6 +80,7 @@ server_client_create(int fd) job_tree_init(&c->status_jobs); c->message_string = NULL; + ARRAY_INIT(&c->message_log); c->prompt_string = NULL; c->prompt_buffer = NULL; @@ -101,7 +102,8 @@ server_client_create(int fd) void server_client_lost(struct client *c) { - u_int i; + struct message_entry *msg; + u_int i; for (i = 0; i < ARRAY_LENGTH(&clients); i++) { if (ARRAY_ITEM(&clients, i) == c) @@ -129,6 +131,11 @@ server_client_lost(struct client *c) if (c->message_string != NULL) xfree(c->message_string); evtimer_del(&c->message_timer); + for (i = 0; i < ARRAY_LENGTH(&c->message_log); i++) { + msg = &ARRAY_ITEM(&c->message_log, i); + xfree(msg->msg); + } + ARRAY_FREE(&c->message_log); if (c->prompt_string != NULL) xfree(c->prompt_string); diff --git a/status.c b/status.c index c030e777..a5716d1a 100644 --- a/status.c +++ b/status.c @@ -566,9 +566,12 @@ status_print(struct session *s, struct winlink *wl, struct grid_cell *gc) void printflike2 status_message_set(struct client *c, const char *fmt, ...) { - struct timeval tv; - va_list ap; - int delay; + struct timeval tv; + struct session *s = c->session; + struct message_entry *msg; + va_list ap; + int delay; + u_int i, limit; status_prompt_clear(c); status_message_clear(c); @@ -577,10 +580,25 @@ status_message_set(struct client *c, const char *fmt, ...) xvasprintf(&c->message_string, fmt, ap); va_end(ap); + ARRAY_EXPAND(&c->message_log, 1); + msg = &ARRAY_LAST(&c->message_log); + msg->msg_time = time(NULL); + msg->msg = xstrdup(c->message_string); + + if (s == NULL) + limit = 0; + else + limit = options_get_number(&s->options, "message-limit"); + for (i = ARRAY_LENGTH(&c->message_log); i > limit; i--) { + msg = &ARRAY_ITEM(&c->message_log, i - 1); + xfree(msg->msg); + ARRAY_REMOVE(&c->message_log, i - 1); + } + delay = options_get_number(&c->session->options, "display-time"); tv.tv_sec = delay / 1000; tv.tv_usec = (delay % 1000) * 1000L; - + evtimer_del(&c->message_timer); evtimer_set(&c->message_timer, status_message_callback, c); evtimer_add(&c->message_timer, &tv); diff --git a/tmux.1 b/tmux.1 index 412b70b0..2fb559e3 100644 --- a/tmux.1 +++ b/tmux.1 @@ -454,6 +454,16 @@ with .D1 (alias: Ic rename ) Rename the session to .Ar new-name . +.It Xo Ic show-messages +.Op Fl t Ar target-client +.Xc +.D1 (alias: Ic showmsgs ) +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 +.Ar target-client . .It Ic source-file Ar path .D1 (alias: Ic source ) Execute commands from @@ -1373,6 +1383,10 @@ from the 256-colour palette, or .Ic default . .It Ic message-fg Ar colour Set status line message foreground colour. +.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 Xo Ic mouse-select-pane .Op Ic on | off .Xc diff --git a/tmux.c b/tmux.c index 30e1bc60..de2f3d12 100644 --- a/tmux.c +++ b/tmux.c @@ -332,6 +332,7 @@ main(int argc, char **argv) options_set_number(so, "message-attr", 0); options_set_number(so, "message-bg", 3); options_set_number(so, "message-fg", 0); + options_set_number(so, "message-limit", 20); options_set_number(so, "mouse-select-pane", 0); options_set_number(so, "repeat-time", 500); options_set_number(so, "set-remain-on-exit", 0); diff --git a/tmux.h b/tmux.h index 55c720ad..c03b21d9 100644 --- a/tmux.h +++ b/tmux.h @@ -1041,6 +1041,12 @@ struct mouse_event { u_char y; }; +/* Saved message entry. */ +struct message_entry { + char *msg; + time_t msg_time; +}; + /* Client connection. */ struct client { struct imsgbuf ibuf; @@ -1077,6 +1083,7 @@ struct client { char *message_string; struct event message_timer; + ARRAY_DECL(, struct message_entry) message_log; char *prompt_string; char *prompt_buffer; @@ -1481,6 +1488,7 @@ extern const struct cmd_entry cmd_set_option_entry; extern const struct cmd_entry cmd_set_window_option_entry; extern const struct cmd_entry cmd_show_buffer_entry; extern const struct cmd_entry cmd_show_environment_entry; +extern const struct cmd_entry cmd_show_messages_entry; extern const struct cmd_entry cmd_show_options_entry; extern const struct cmd_entry cmd_show_window_options_entry; extern const struct cmd_entry cmd_source_file_entry; From a78cc98c8bd79cecbb8574a9dff4c9867a8308d9 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 18 Nov 2009 17:02:17 +0000 Subject: [PATCH 0547/1180] Cleanup by moving various (mostly horrible) little bits handling UTF-8 grid data into functions in a new file, grid-utf8.c, and use sizeof intead of UTF8_DATA. Also nuke trailing whitespace from tmux.1, reminded by jmc. --- Makefile | 2 +- grid-utf8.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++ grid.c | 16 ++++----- screen-write.c | 66 ++++++++++++++-------------------- tmux.1 | 2 +- tmux.h | 16 +++++++-- tty.c | 14 +++----- window-copy.c | 15 ++++---- 8 files changed, 157 insertions(+), 70 deletions(-) create mode 100644 grid-utf8.c diff --git a/Makefile b/Makefile index 0f6f2707..b0caca92 100644 --- a/Makefile +++ b/Makefile @@ -30,7 +30,7 @@ SRCS= attributes.c cfg.c client.c clock.c \ cmd-set-environment.c cmd-show-environment.c cmd-choose-client.c \ cmd-up-pane.c cmd-display-message.c cmd-display-panes.c \ cmd-pipe-pane.c cmd.c \ - colour.c environ.c grid-view.c grid.c input-keys.c \ + colour.c environ.c grid-view.c grid-utf8.c grid.c input-keys.c \ imsg.c imsg-buffer.c input.c key-bindings.c key-string.c \ layout-set.c layout.c log.c job.c \ mode-key.c names.c options-cmd.c options.c paste.c procname.c \ diff --git a/grid-utf8.c b/grid-utf8.c new file mode 100644 index 00000000..5e5cad74 --- /dev/null +++ b/grid-utf8.c @@ -0,0 +1,96 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2009 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 "tmux.h" + +/* + * Grid UTF-8 utility functions. + */ + +/* Calculate UTF-8 grid cell size. Data is terminated by 0xff. */ +size_t +grid_utf8_size(const struct grid_utf8 *gu) +{ + size_t size; + + for (size = 0; size < sizeof gu->data; size++) { + if (gu->data[size] == 0xff) + break; + } + return (size); +} + +/* Copy UTF-8 out into a buffer. */ +size_t +grid_utf8_copy(const struct grid_utf8 *gu, char *buf, size_t len) +{ + size_t size; + + size = grid_utf8_size(gu); + if (size > len) + fatalx("UTF-8 copy overflow"); + memcpy(buf, gu->data, size); + return (size); +} + +/* Set UTF-8 grid data from input UTF-8. */ +void +grid_utf8_set(struct grid_utf8 *gu, const struct utf8_data *utf8data) +{ + if (utf8data->size == 0) + fatalx("UTF-8 data empty"); + if (utf8data->size > sizeof gu->data) + fatalx("UTF-8 data too long"); + memcpy(gu->data, utf8data->data, utf8data->size); + if (utf8data->size != sizeof gu->data) + gu->data[utf8data->size] = 0xff; + gu->width = utf8data->width; +} + +/* Append UTF-8 character onto the cell data (for combined characters). */ +int +grid_utf8_append(struct grid_utf8 *gu, const struct utf8_data *utf8data) +{ + size_t old_size; + + old_size = grid_utf8_size(gu); + if (old_size + utf8data->size > sizeof gu->data) + return (-1); + memcpy(gu->data + old_size, utf8data->data, utf8data->size); + if (old_size + utf8data->size != sizeof gu->data) + gu->data[old_size + utf8data->size] = 0xff; + return (0); +} + +/* Compare two UTF-8 cells. */ +int +grid_utf8_compare(const struct grid_utf8 *gu1, const struct grid_utf8 *gu2) +{ + size_t size; + + size = grid_utf8_size(gu1); + if (size != grid_utf8_size(gu2)) + return (0); + if (memcmp(gu1->data, gu2->data, size) != 0) + return (0); + return (1); +} diff --git a/grid.c b/grid.c index 1041528d..a49c06bd 100644 --- a/grid.c +++ b/grid.c @@ -502,8 +502,8 @@ grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx) const struct grid_cell *gc; const struct grid_utf8 *gu; char *buf; - size_t len, off; - u_int xx, i; + size_t len, off, size; + u_int xx; GRID_DEBUG(gd, "px=%u, py=%u, nx=%u", px, py, nx); @@ -517,17 +517,15 @@ grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx) continue; if (gc->flags & GRID_FLAG_UTF8) { - while (len < off + UTF8_SIZE + 1) { + gu = grid_peek_utf8(gd, xx, py); + + size = grid_utf8_size(gu); + while (len < off + size + 1) { buf = xrealloc(buf, 2, len); len *= 2; } - gu = grid_peek_utf8(gd, xx, py); - for (i = 0; i < UTF8_SIZE; i++) { - if (gu->data[i] == 0xff) - break; - buf[off++] = gu->data[i]; - } + off += grid_utf8_copy(gu, buf + off, len - off); } else { while (len < off + 2) { buf = xrealloc(buf, 2, len); diff --git a/screen-write.c b/screen-write.c index 81231c2e..8afffa4b 100644 --- a/screen-write.c +++ b/screen-write.c @@ -354,7 +354,7 @@ screen_write_copy(struct screen_write_ctx *ctx, const struct grid_cell *gc; const struct grid_utf8 *gu; struct utf8_data utf8data; - u_int xx, yy, cx, cy, ax, bx, i; + u_int xx, yy, cx, cy, ax, bx; cx = s->cx; cy = s->cy; @@ -381,18 +381,15 @@ screen_write_copy(struct screen_write_ctx *ctx, gc = &grid_default_cell; else gc = &gl->celldata[xx]; - if (gc->flags & GRID_FLAG_UTF8) { - gu = &gl->utf8data[xx]; - memcpy(utf8data.data, - gu->data, sizeof utf8data.data); - utf8data.width = gu->width; - utf8data.size = 0; - for (i = 0; i < UTF8_SIZE; i++) { - if (gu->data[i] == 0xff) - break; - utf8data.size++; - } + if (!(gc->flags & GRID_FLAG_UTF8)) { + screen_write_cell(ctx, gc, NULL); + continue; } + /* Reinject the UTF-8 sequence. */ + gu = &gl->utf8data[xx]; + utf8data.size = grid_utf8_copy( + gu, utf8data.data, sizeof utf8data.data); + utf8data.width = gu->width; screen_write_cell(ctx, gc, &utf8data); } if (px + nx == gd->sx && px + nx > gl->cellsize) @@ -1037,13 +1034,7 @@ screen_write_cell(struct screen_write_ctx *ctx, grid_view_set_cell(gd, s->cx, s->cy, gc); if (gc->flags & GRID_FLAG_UTF8) { /* Construct UTF-8 and write it. */ - gu.width = utf8data->width; - memset(gu.data, 0xff, sizeof gu.data); - if (utf8data->size == 0) - fatalx("UTF-8 data empty"); - if (utf8data->size > sizeof gu.data) - fatalx("UTF-8 data overflow"); - memcpy(gu.data, utf8data->data, utf8data->size); + grid_utf8_set(&gu, utf8data); grid_view_set_utf8(gd, s->cx, s->cy, &gu); } @@ -1080,7 +1071,7 @@ screen_write_combine( struct grid *gd = s->grid; struct grid_cell *gc; struct grid_utf8 *gu, tmp_gu; - u_int i, old_size; + u_int i; /* Can't combine if at 0. */ if (s->cx == 0) @@ -1093,35 +1084,30 @@ screen_write_combine( /* Retrieve the previous cell and convert to UTF-8 if not already. */ gc = grid_view_get_cell(gd, s->cx - 1, s->cy); if (!(gc->flags & GRID_FLAG_UTF8)) { - memset(&tmp_gu.data, 0xff, sizeof tmp_gu.data); - *tmp_gu.data = gc->data; + tmp_gu.data[0] = gc->data; + tmp_gu.data[1] = 0xff; tmp_gu.width = 1; grid_view_set_utf8(gd, s->cx - 1, s->cy, &tmp_gu); gc->flags |= GRID_FLAG_UTF8; } - /* Get the previous cell's UTF-8 data and its size. */ + /* Append the current cell. */ gu = grid_view_get_utf8(gd, s->cx - 1, s->cy); - for (old_size = 0; old_size < UTF8_SIZE; old_size++) { - if (gu->data[old_size] == 0xff) - break; + if (grid_utf8_append(gu, utf8data) != 0) { + /* Failed: scrap this character and replace with underscores. */ + if (gu->width == 1) { + gc->data = '_'; + gc->flags &= ~GRID_FLAG_UTF8; + } else { + for (i = 0; i < gu->width && i != sizeof gu->data; i++) + gu->data[i] = '_'; + if (i != sizeof gu->data) + gu->data[i] = 0xff; + gu->width = i; + } } - /* If there isn't space, scrap this character. */ - if (old_size + utf8data->size > UTF8_SIZE) { - for (i = 0; i < gu->width && i != UTF8_SIZE; i++) - gu->data[i] = '_'; - if (i != UTF8_SIZE) - gu->data[i] = 0xff; - gu->width = i; - return (0); - } - - /* Otherwise save the character. */ - memcpy(gu->data + old_size, utf8data->data, utf8data->size); - if (old_size + utf8data->size != UTF8_SIZE) - gu->data[old_size + utf8data->size] = 0xff; return (0); } diff --git a/tmux.1 b/tmux.1 index 2fb559e3..2b356db1 100644 --- a/tmux.1 +++ b/tmux.1 @@ -454,7 +454,7 @@ with .D1 (alias: Ic rename ) Rename the session to .Ar new-name . -.It Xo Ic show-messages +.It Xo Ic show-messages .Op Fl t Ar target-client .Xc .D1 (alias: Ic showmsgs ) diff --git a/tmux.h b/tmux.h index c03b21d9..517fe9d4 100644 --- a/tmux.h +++ b/tmux.h @@ -74,6 +74,12 @@ extern char **environ; #define PRINT_LENGTH 512 /* printed error/message size */ #define ENVIRON_LENGTH 1024 /* environment variable length */ +/* + * UTF-8 data size. This must be big enough to hold combined characters as well + * as single. + */ +#define UTF8_SIZE 9 + /* Fatal errors. */ #define fatal(msg) log_fatal("%s: %s", __func__, msg); #define fatalx(msg) log_fatalx("%s: %s", __func__, msg); @@ -525,13 +531,12 @@ struct mode_key_table { #define MODE_MOUSE 0x10 /* - * A single UTF-8 character. + * A single UTF-8 character. * * The data member in this must be UTF8_SIZE to allow screen_write_copy to * reinject stored UTF-8 data back into screen_write_cell after combining (ugh * XXX XXX). */ -#define UTF8_SIZE 9 struct utf8_data { u_char data[UTF8_SIZE]; @@ -1675,6 +1680,13 @@ char *grid_string_cells(struct grid *, u_int, u_int, u_int); void grid_duplicate_lines( struct grid *, u_int, struct grid *, u_int, u_int); +/* grid-utf8.c */ +size_t grid_utf8_size(const struct grid_utf8 *); +size_t grid_utf8_copy(const struct grid_utf8 *, char *, size_t); +void grid_utf8_set(struct grid_utf8 *, const struct utf8_data *); +int grid_utf8_append(struct grid_utf8 *, const struct utf8_data *); +int grid_utf8_compare(const struct grid_utf8 *, const struct grid_utf8 *); + /* grid-view.c */ const struct grid_cell *grid_view_peek_cell(struct grid *, u_int, u_int); struct grid_cell *grid_view_get_cell(struct grid *, u_int, u_int); diff --git a/tty.c b/tty.c index 8855a657..a3aeda5d 100644 --- a/tty.c +++ b/tty.c @@ -365,16 +365,12 @@ tty_putc(struct tty *tty, u_char ch) void tty_pututf8(struct tty *tty, const struct grid_utf8 *gu) { - u_int i; - - for (i = 0; i < UTF8_SIZE; i++) { - if (gu->data[i] == 0xff) - break; - bufferevent_write(tty->event, &gu->data[i], 1); - if (tty->log_fd != -1) - write(tty->log_fd, &gu->data[i], 1); - } + size_t size; + size = grid_utf8_size(gu); + bufferevent_write(tty->event, gu->data, size); + if (tty->log_fd != -1) + write(tty->log_fd, gu->data, size); tty->cx += gu->width; } diff --git a/window-copy.c b/window-copy.c index 499ead33..25f73634 100644 --- a/window-copy.c +++ b/window-copy.c @@ -486,6 +486,7 @@ window_copy_search_compare( { const struct grid_cell *gc, *sgc; const struct grid_utf8 *gu, *sgu; + size_t size; gc = grid_peek_cell(gd, px, py); sgc = grid_peek_cell(sgd, spx, 0); @@ -496,7 +497,7 @@ window_copy_search_compare( if (gc->flags & GRID_FLAG_UTF8) { gu = grid_peek_utf8(gd, px, py); sgu = grid_peek_utf8(sgd, spx, 0); - if (memcmp(gu->data, sgu->data, UTF8_SIZE) == 0) + if (grid_utf8_compare(gu, sgu)) return (1); } else { if (gc->data == sgc->data) @@ -895,7 +896,8 @@ window_copy_copy_line(struct window_pane *wp, const struct grid_cell *gc; const struct grid_utf8 *gu; struct grid_line *gl; - u_int i, j, xx, wrapped = 0; + u_int i, xx, wrapped = 0; + size_t size; if (sx > ex) return; @@ -928,12 +930,9 @@ window_copy_copy_line(struct window_pane *wp, (*buf)[(*off)++] = gc->data; } else { gu = grid_peek_utf8(gd, i, sy); - *buf = xrealloc(*buf, 1, (*off) + UTF8_SIZE); - for (j = 0; j < UTF8_SIZE; j++) { - if (gu->data[j] == 0xff) - break; - (*buf)[(*off)++] = gu->data[j]; - } + size = grid_utf8_size(gu); + *buf = xrealloc(*buf, 1, (*off) + size); + *off += grid_utf8_copy(gu, *buf + *off, size); } } } From 8d4eae56626a40b24ce3964e2e2560b23082bde4 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 18 Nov 2009 17:03:16 +0000 Subject: [PATCH 0548/1180] Missed an unused variable :-/. --- window-copy.c | 1 - 1 file changed, 1 deletion(-) diff --git a/window-copy.c b/window-copy.c index 25f73634..dba57256 100644 --- a/window-copy.c +++ b/window-copy.c @@ -486,7 +486,6 @@ window_copy_search_compare( { const struct grid_cell *gc, *sgc; const struct grid_utf8 *gu, *sgu; - size_t size; gc = grid_peek_cell(gd, px, py); sgc = grid_peek_cell(sgd, spx, 0); From ac5b7d518e78ed21ed8a9757f5ea3f49f407d232 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 19 Nov 2009 10:22:06 +0000 Subject: [PATCH 0549/1180] Don't interpret #() for display-message, it usually doesn't make sense and may leak commands. --- cmd-display-message.c | 2 +- server-client.c | 2 +- status.c | 30 ++++++++++++++++++++++-------- tmux.1 | 9 +++++---- tmux.h | 2 +- 5 files changed, 30 insertions(+), 15 deletions(-) diff --git a/cmd-display-message.c b/cmd-display-message.c index 1ff5718b..be39857d 100644 --- a/cmd-display-message.c +++ b/cmd-display-message.c @@ -55,7 +55,7 @@ cmd_display_message_exec(struct cmd *self, struct cmd_ctx *ctx) else template = data->arg; - msg = status_replace(c, template, time(NULL)); + msg = status_replace(c, template, time(NULL), 0); status_message_set(c, "%s", msg); xfree(msg); diff --git a/server-client.c b/server-client.c index 8ff71223..7334d4b4 100644 --- a/server-client.c +++ b/server-client.c @@ -489,7 +489,7 @@ server_client_set_title(struct client *c) template = options_get_string(&s->options, "set-titles-string"); - title = status_replace(c, template, time(NULL)); + title = status_replace(c, template, time(NULL), 1); if (c->title == NULL || strcmp(title, c->title) != 0) { if (c->title != NULL) xfree(c->title); diff --git a/status.c b/status.c index a5716d1a..968f3634 100644 --- a/status.c +++ b/status.c @@ -107,14 +107,14 @@ status_redraw(struct client *c) /* Work out the left and right strings. */ left = status_replace(c, options_get_string( - &s->options, "status-left"), c->status_timer.tv_sec); + &s->options, "status-left"), c->status_timer.tv_sec, 1); llen = options_get_number(&s->options, "status-left-length"); llen2 = screen_write_cstrlen(utf8flag, "%s", left); if (llen2 < llen) llen = llen2; right = status_replace(c, options_get_string( - &s->options, "status-right"), c->status_timer.tv_sec); + &s->options, "status-right"), c->status_timer.tv_sec, 1); rlen = options_get_number(&s->options, "status-right-length"); rlen2 = screen_write_cstrlen(utf8flag, "%s", right); if (rlen2 < rlen) @@ -319,7 +319,7 @@ out: } char * -status_replace(struct client *c, const char *fmt, time_t t) +status_replace(struct client *c, const char *fmt, time_t t, int run_jobs) { struct session *s = c->session; struct winlink *wl = s->curw; @@ -355,11 +355,25 @@ status_replace(struct client *c, const char *fmt, time_t t) ptr = NULL; switch (*iptr++) { case '(': - if (ptr == NULL) { - ptr = status_job(c, &iptr); - if (ptr == NULL) - break; - savedptr = ptr; + if (run_jobs) { + if (ptr == NULL) { + ptr = status_job(c, &iptr); + if (ptr == NULL) + break; + savedptr = ptr; + } + } else { + /* Don't run jobs. Copy to ). */ + *optr++ = '#'; + + iptr--; /* include [ */ + while (*iptr != ')' && *iptr != '\0') { + if (optr >= + out + (sizeof out) - 1) + break; + *optr++ = *iptr++; + } + break; } /* FALLTHROUGH */ case 'H': diff --git a/tmux.1 b/tmux.1 index 2b356db1..3c550876 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1992,10 +1992,11 @@ This command works only from inside .Op Ar message .Xc .D1 (alias: Ic display ) -Display a message (see the -.Ic status-left -option below) -in the status line. +Display a message in the status line. +The format of +.Ar message is as for +.Ic status-left , +with the exception that #() are not handled. .It Ic select-prompt Op Fl t Ar target-client Open a prompt inside .Ar target-client diff --git a/tmux.h b/tmux.h index 517fe9d4..78869274 100644 --- a/tmux.h +++ b/tmux.h @@ -1617,7 +1617,7 @@ void server_update_event(struct client *); /* status.c */ int status_redraw(struct client *); -char *status_replace(struct client *, const char *, time_t); +char *status_replace(struct client *, const char *, time_t, int); void printflike2 status_message_set(struct client *, const char *, ...); void status_message_clear(struct client *); int status_message_redraw(struct client *); From ed781e84eed90217f39c763bf43838598d23c611 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 19 Nov 2009 11:38:54 +0000 Subject: [PATCH 0550/1180] Tidy up by breaking the # replacement code into a separate function, also add a few comments. --- status.c | 225 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 115 insertions(+), 110 deletions(-) diff --git a/status.c b/status.c index 968f3634..134e8717 100644 --- a/status.c +++ b/status.c @@ -33,6 +33,8 @@ char *status_job(struct client *, char **); void status_job_callback(struct job *); size_t status_width(struct winlink *); char *status_print(struct session *, struct winlink *, struct grid_cell *); +void status_replace1( + struct client *, char **, char **, char *, size_t, int); void status_message_callback(int, short, void *); void status_prompt_add_history(struct client *); @@ -318,139 +320,133 @@ out: return (1); } -char * -status_replace(struct client *c, const char *fmt, time_t t, int run_jobs) +/* Replace a single special sequence (prefixed by #). */ +void +status_replace1(struct client *c, + char **iptr, char **optr, char *out, size_t outsize, int jobsflag) { struct session *s = c->session; struct winlink *wl = s->curw; - static char out[BUFSIZ]; - char in[BUFSIZ], tmp[256], ch, *iptr, *optr, *ptr, *endptr; - char *savedptr; /* freed at end of each loop */ - size_t len; - long n; + char ch, tmp[256], *ptr, *endptr, *freeptr; + size_t ptrlen; + long limit; + + errno = 0; + limit = strtol(*iptr, &endptr, 10); + if ((limit == 0 && errno != EINVAL) || + (limit == LONG_MIN && errno != ERANGE) || + (limit == LONG_MAX && errno != ERANGE) || + limit != 0) + *iptr = endptr; + if (limit <= 0) + limit = LONG_MAX; + + freeptr = NULL; + + switch (*(*iptr)++) { + case '(': + if (!jobsflag) { + ch = ')'; + goto skip_to; + } + if ((ptr = status_job(c, iptr)) == NULL) + return; + freeptr = ptr; + goto do_replace; + case 'H': + if (gethostname(tmp, sizeof tmp) != 0) + fatal("gethostname failed"); + ptr = tmp; + goto do_replace; + case 'I': + xsnprintf(tmp, sizeof tmp, "%d", wl->idx); + ptr = tmp; + goto do_replace; + case 'P': + xsnprintf(tmp, sizeof tmp, "%u", + window_pane_index(wl->window, wl->window->active)); + ptr = tmp; + goto do_replace; + case 'S': + ptr = s->name; + goto do_replace; + case 'T': + ptr = wl->window->active->base.title; + goto do_replace; + case 'W': + ptr = wl->window->name; + goto do_replace; + case '[': + /* + * Embedded style, handled at display time. Leave present and + * skip input until ]. + */ + ch = ']'; + goto skip_to; + case '#': + *(*optr++) = '#'; + break; + } + + return; +do_replace: + ptrlen = strlen(ptr); + if ((size_t) limit < ptrlen) + ptrlen = limit; + + if (*optr + ptrlen >= out + outsize - 1) + return; + while (ptrlen > 0 && *ptr != '\0') { + *(*optr)++ = *ptr++; + ptrlen--; + } + + if (freeptr != NULL) + xfree(freeptr); + return; + +skip_to: + *(*optr)++ = '#'; + + (*iptr)--; /* include ch */ + while (**iptr != ch && **iptr != '\0') { + if (*optr >= out + outsize - 1) + break; + *(*optr)++ = *(*iptr)++; + } +} + +/* Replace special sequences in fmt. */ +char * +status_replace(struct client *c, const char *fmt, time_t t, int jobsflag) +{ + static char out[BUFSIZ]; + char in[BUFSIZ], ch, *iptr, *optr; strftime(in, sizeof in, fmt, localtime(&t)); in[(sizeof in) - 1] = '\0'; iptr = in; optr = out; - savedptr = NULL; while (*iptr != '\0') { if (optr >= out + (sizeof out) - 1) break; - switch (ch = *iptr++) { - case '#': - errno = 0; - n = strtol(iptr, &endptr, 10); - if ((n == 0 && errno != EINVAL) || - (n == LONG_MIN && errno != ERANGE) || - (n == LONG_MAX && errno != ERANGE) || - n != 0) - iptr = endptr; - if (n <= 0) - n = LONG_MAX; + ch = *iptr++; - ptr = NULL; - switch (*iptr++) { - case '(': - if (run_jobs) { - if (ptr == NULL) { - ptr = status_job(c, &iptr); - if (ptr == NULL) - break; - savedptr = ptr; - } - } else { - /* Don't run jobs. Copy to ). */ - *optr++ = '#'; - - iptr--; /* include [ */ - while (*iptr != ')' && *iptr != '\0') { - if (optr >= - out + (sizeof out) - 1) - break; - *optr++ = *iptr++; - } - break; - } - /* FALLTHROUGH */ - case 'H': - if (ptr == NULL) { - if (gethostname(tmp, sizeof tmp) != 0) - fatal("gethostname failed"); - ptr = tmp; - } - /* FALLTHROUGH */ - case 'I': - if (ptr == NULL) { - xsnprintf(tmp, sizeof tmp, "%d", wl->idx); - ptr = tmp; - } - /* FALLTHROUGH */ - case 'P': - if (ptr == NULL) { - xsnprintf(tmp, sizeof tmp, "%u", - window_pane_index(wl->window, - wl->window->active)); - ptr = tmp; - } - /* FALLTHROUGH */ - case 'S': - if (ptr == NULL) - ptr = s->name; - /* FALLTHROUGH */ - case 'T': - if (ptr == NULL) - ptr = wl->window->active->base.title; - /* FALLTHROUGH */ - case 'W': - if (ptr == NULL) - ptr = wl->window->name; - len = strlen(ptr); - if ((size_t) n < len) - len = n; - if (optr + len >= out + (sizeof out) - 1) - break; - while (len > 0 && *ptr != '\0') { - *optr++ = *ptr++; - len--; - } - break; - case '[': - /* - * Embedded style, handled at display time. - * Leave present and skip input until ]. - */ - *optr++ = '#'; - - iptr--; /* include [ */ - while (*iptr != ']' && *iptr != '\0') { - if (optr >= out + (sizeof out) - 1) - break; - *optr++ = *iptr++; - } - break; - case '#': - *optr++ = '#'; - break; - } - if (savedptr != NULL) { - xfree(savedptr); - savedptr = NULL; - } - break; - default: + if (ch != '#') { *optr++ = ch; - break; + continue; } + status_replace1(c, &iptr, &optr, out, sizeof out, jobsflag); } *optr = '\0'; return (xstrdup(out)); } +/* Figure out job name and get its result, starting it off if necessary. */ char * status_job(struct client *c, char **iptr) { @@ -498,6 +494,7 @@ status_job(struct client *c, char **iptr) return (xstrdup(job->data)); } +/* Job has finished: save its result. */ void status_job_callback(struct job *job) { @@ -523,12 +520,14 @@ status_job_callback(struct job *job) xfree(buf); } +/* Calculate winlink status line entry width. */ size_t status_width(struct winlink *wl) { return (xsnprintf(NULL, 0, "%d:%s ", wl->idx, wl->window->name)); } +/* Return winlink status line entry and adjust gc as necessary. */ char * status_print(struct session *s, struct winlink *wl, struct grid_cell *gc) { @@ -577,6 +576,7 @@ status_print(struct session *s, struct winlink *wl, struct grid_cell *gc) return (text); } +/* Set a status line message. */ void printflike2 status_message_set(struct client *c, const char *fmt, ...) { @@ -621,6 +621,7 @@ status_message_set(struct client *c, const char *fmt, ...) c->flags |= CLIENT_STATUS; } +/* Clear status line message. */ void status_message_clear(struct client *c) { @@ -636,6 +637,7 @@ status_message_clear(struct client *c) screen_reinit(&c->status); } +/* Clear status line message after timer expires. */ void status_message_callback(unused int fd, unused short event, void *data) { @@ -685,6 +687,7 @@ status_message_redraw(struct client *c) return (1); } +/* Enable status line prompt. */ void status_prompt_set(struct client *c, const char *msg, int (*callbackfn)(void *, const char *), void (*freefn)(void *), @@ -718,6 +721,7 @@ status_prompt_set(struct client *c, const char *msg, c->flags |= CLIENT_STATUS; } +/* Remove status line prompt. */ void status_prompt_clear(struct client *c) { @@ -739,6 +743,7 @@ status_prompt_clear(struct client *c) screen_reinit(&c->status); } +/* Update status line prompt with a new prompt string. */ void status_prompt_update(struct client *c, const char *msg) { From 4a3818934924090cc0a5800cc38bf89fa8f2ea53 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 19 Nov 2009 14:06:33 +0000 Subject: [PATCH 0551/1180] Revert to xterm-keys off by default. It was on as an experiment to see if the option could be removed, but it affects vi, so we have to keep the option, and a conservative default is better. --- tmux.1 | 2 +- tmux.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tmux.1 b/tmux.1 index 3c550876..6aedb51c 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1803,7 +1803,7 @@ will generate .Xr xterm 1 -style function key sequences; these have a number included to indicate modifiers such as Shift, Alt or Ctrl. -The default is on. +The default is off. .El .It Xo Ic show-options .Op Fl g diff --git a/tmux.c b/tmux.c index de2f3d12..f3f764e1 100644 --- a/tmux.c +++ b/tmux.c @@ -391,7 +391,7 @@ main(int argc, char **argv) options_set_number(wo, "window-status-current-bg", 8); options_set_number(wo, "window-status-current-fg", 8); options_set_number(wo, "window-status-fg", 8); - options_set_number(wo, "xterm-keys", 1); + options_set_number(wo, "xterm-keys", 0); options_set_number(wo, "remain-on-exit", 0); options_set_number(wo, "synchronize-panes", 0); From 8b8a2111852e9c2ce0cbc5e867d29ca78d4948a5 Mon Sep 17 00:00:00 2001 From: Jason McIntyre Date: Thu, 19 Nov 2009 15:00:32 +0000 Subject: [PATCH 0552/1180] tweak previous; --- tmux.1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tmux.1 b/tmux.1 index 6aedb51c..de86a728 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1994,7 +1994,8 @@ This command works only from inside .D1 (alias: Ic display ) Display a message in the status line. The format of -.Ar message is as for +.Ar message +is as for .Ic status-left , with the exception that #() are not handled. .It Ic select-prompt Op Fl t Ar target-client From 543fb99bc60a82eeb8c1e3fa47cdcb86a1e2fb33 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 19 Nov 2009 16:22:10 +0000 Subject: [PATCH 0553/1180] Two new options, window-status-format and window-status-current-format, which allow the format of each window in the status line window list to be controlled using similar # sequences as status-left/right. This diff also moves part of the way towards UTF-8 support in window names but it isn't quite there yet. --- cmd-display-message.c | 2 +- cmd-set-window-option.c | 34 +++++++++++++ server-client.c | 2 +- status.c | 107 ++++++++++++++++++++++++++-------------- tmux.1 | 23 ++++++++- tmux.c | 2 + tmux.h | 3 +- 7 files changed, 131 insertions(+), 42 deletions(-) diff --git a/cmd-display-message.c b/cmd-display-message.c index be39857d..aa4fd5db 100644 --- a/cmd-display-message.c +++ b/cmd-display-message.c @@ -55,7 +55,7 @@ cmd_display_message_exec(struct cmd *self, struct cmd_ctx *ctx) else template = data->arg; - msg = status_replace(c, template, time(NULL), 0); + msg = status_replace(c, NULL, template, time(NULL), 0); status_message_set(c, "%s", msg); xfree(msg); diff --git a/cmd-set-window-option.c b/cmd-set-window-option.c index 1d7b8cc5..0ad1025e 100644 --- a/cmd-set-window-option.c +++ b/cmd-set-window-option.c @@ -71,7 +71,9 @@ const struct set_option_entry set_window_option_table[] = { { "window-status-current-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL }, { "window-status-current-bg", SET_OPTION_COLOUR, 0, 0, NULL }, { "window-status-current-fg", SET_OPTION_COLOUR, 0, 0, NULL }, + { "window-status-current-format", SET_OPTION_STRING, 0, 0, NULL }, { "window-status-fg", SET_OPTION_COLOUR, 0, 0, NULL }, + { "window-status-format", SET_OPTION_STRING, 0, 0, NULL }, { "xterm-keys", SET_OPTION_FLAG, 0, 0, NULL }, { NULL, 0, 0, 0, NULL } }; @@ -84,7 +86,10 @@ cmd_set_window_option_exec(struct cmd *self, struct cmd_ctx *ctx) struct client *c; struct options *oo; const struct set_option_entry *entry, *opt; + struct jobs *jobs; + struct job *job, *nextjob; u_int i; + int try_again; if (cmd_check_flag(data->chflags, 'g')) oo = &global_w_options; @@ -166,5 +171,34 @@ cmd_set_window_option_exec(struct cmd *self, struct cmd_ctx *ctx) server_redraw_client(c); } + /* + * Special-case: kill all persistent jobs if window-status-format has + * changed. Persistent jobs are only used by the status line at the + * moment so this works XXX. + */ + if (strcmp(entry->name, "window-status-format") == 0) { + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c == NULL || c->session == NULL) + continue; + + jobs = &c->status_jobs; + do { + try_again = 0; + job = RB_ROOT(jobs); + while (job != NULL) { + nextjob = RB_NEXT(jobs, jobs, job); + if (job->flags & JOB_PERSIST) { + job_remove(jobs, job); + try_again = 1; + break; + } + job = nextjob; + } + } while (try_again); + server_redraw_client(c); + } + } + return (0); } diff --git a/server-client.c b/server-client.c index 7334d4b4..e6560931 100644 --- a/server-client.c +++ b/server-client.c @@ -489,7 +489,7 @@ server_client_set_title(struct client *c) template = options_get_string(&s->options, "set-titles-string"); - title = status_replace(c, template, time(NULL), 1); + title = status_replace(c, NULL, template, time(NULL), 1); if (c->title == NULL || strcmp(title, c->title) != 0) { if (c->title != NULL) xfree(c->title); diff --git a/status.c b/status.c index 134e8717..39e824c1 100644 --- a/status.c +++ b/status.c @@ -31,10 +31,11 @@ char *status_job(struct client *, char **); void status_job_callback(struct job *); -size_t status_width(struct winlink *); -char *status_print(struct session *, struct winlink *, struct grid_cell *); -void status_replace1( - struct client *, char **, char **, char *, size_t, int); +size_t status_width(struct client *, struct winlink *, time_t); +char *status_print( + struct client *, struct winlink *, time_t, struct grid_cell *); +void status_replace1(struct client *, + struct winlink *, char **, char **, char *, size_t, int); void status_message_callback(int, short, void *); void status_prompt_add_history(struct client *); @@ -108,14 +109,14 @@ status_redraw(struct client *c) utf8flag = options_get_number(&s->options, "status-utf8"); /* Work out the left and right strings. */ - left = status_replace(c, options_get_string( + left = status_replace(c, NULL, options_get_string( &s->options, "status-left"), c->status_timer.tv_sec, 1); llen = options_get_number(&s->options, "status-left-length"); llen2 = screen_write_cstrlen(utf8flag, "%s", left); if (llen2 < llen) llen = llen2; - right = status_replace(c, options_get_string( + right = status_replace(c, NULL, options_get_string( &s->options, "status-right"), c->status_timer.tv_sec, 1); rlen = options_get_number(&s->options, "status-right-length"); rlen2 = screen_write_cstrlen(utf8flag, "%s", right); @@ -141,7 +142,7 @@ status_redraw(struct client *c) */ width = offset = 0; RB_FOREACH(wl, winlinks, &s->windows) { - size = status_width(wl) + 1; + size = status_width(c, wl, c->status_timer.tv_sec) + 1; if (wl == s->curw) offset = width; width += size; @@ -153,7 +154,7 @@ status_redraw(struct client *c) goto draw; /* Find size of current window text. */ - size = status_width(s->curw); + size = status_width(c, s->curw, c->status_timer.tv_sec); /* * If the offset is already on screen, we're good to draw from the @@ -226,7 +227,7 @@ draw: offset = 0; RB_FOREACH(wl, winlinks, &s->windows) { memcpy(&gc, &stdgc, sizeof gc); - text = status_print(s, wl, &gc); + text = status_print(c, wl, c->status_timer.tv_sec, &gc); if (larrow == 1 && offset < start) { if (session_alert_has(s, wl, WINDOW_ACTIVITY)) @@ -237,10 +238,13 @@ draw: larrow = -1; } - for (ptr = text; *ptr != '\0'; ptr++) { - if (offset >= start && offset < start + width) - screen_write_putc(&ctx, &gc, *ptr); - offset++; + ptr = text; + for (; offset < start; offset++) + ptr++; /* XXX should skip UTF-8 characters */ + if (offset < start + width) { + screen_write_cnputs(&ctx, + start + width - offset, &gc, utf8flag, "%s", text); + offset += screen_write_cstrlen(utf8flag, "%s", text); } if (rarrow == 1 && offset > start + width) { @@ -322,15 +326,17 @@ out: /* Replace a single special sequence (prefixed by #). */ void -status_replace1(struct client *c, +status_replace1(struct client *c,struct winlink *wl, char **iptr, char **optr, char *out, size_t outsize, int jobsflag) { struct session *s = c->session; - struct winlink *wl = s->curw; char ch, tmp[256], *ptr, *endptr, *freeptr; size_t ptrlen; long limit; + if (wl == NULL) + wl = s->curw; + errno = 0; limit = strtol(*iptr, &endptr, 10); if ((limit == 0 && errno != EINVAL) || @@ -376,6 +382,21 @@ status_replace1(struct client *c, case 'W': ptr = wl->window->name; goto do_replace; + case 'F': + tmp[0] = ' '; + if (session_alert_has(s, wl, WINDOW_CONTENT)) + tmp[0] = '+'; + else if (session_alert_has(s, wl, WINDOW_BELL)) + tmp[0] = '!'; + else if (session_alert_has(s, wl, WINDOW_ACTIVITY)) + tmp[0] = '#'; + else if (wl == s->curw) + tmp[0] = '*'; + else if (wl == TAILQ_FIRST(&s->lastw)) + tmp[0] = '-'; + tmp[1] = '\0'; + ptr = tmp; + goto do_replace; case '[': /* * Embedded style, handled at display time. Leave present and @@ -419,11 +440,12 @@ skip_to: /* Replace special sequences in fmt. */ char * -status_replace(struct client *c, const char *fmt, time_t t, int jobsflag) +status_replace(struct client *c, + struct winlink *wl, const char *fmt, time_t t, int jobsflag) { static char out[BUFSIZ]; char in[BUFSIZ], ch, *iptr, *optr; - + strftime(in, sizeof in, fmt, localtime(&t)); in[(sizeof in) - 1] = '\0'; @@ -439,7 +461,7 @@ status_replace(struct client *c, const char *fmt, time_t t, int jobsflag) *optr++ = ch; continue; } - status_replace1(c, &iptr, &optr, out, sizeof out, jobsflag); + status_replace1(c, wl, &iptr, &optr, out, sizeof out, jobsflag); } *optr = '\0'; @@ -522,17 +544,37 @@ status_job_callback(struct job *job) /* Calculate winlink status line entry width. */ size_t -status_width(struct winlink *wl) +status_width(struct client *c, struct winlink *wl, time_t t) { - return (xsnprintf(NULL, 0, "%d:%s ", wl->idx, wl->window->name)); + struct options *oo = &wl->window->options; + struct session *s = c->session; + const char *fmt; + char *text; + size_t size; + int utf8flag; + + utf8flag = options_get_number(&s->options, "status-utf8"); + + fmt = options_get_string(&wl->window->options, "window-status-format"); + if (wl == s->curw) + fmt = options_get_string(oo, "window-status-current-format"); + + text = status_replace(c, wl, fmt, t, 1); + size = screen_write_cstrlen(utf8flag, "%s", text); + xfree(text); + + return (size); } /* Return winlink status line entry and adjust gc as necessary. */ char * -status_print(struct session *s, struct winlink *wl, struct grid_cell *gc) +status_print( + struct client *c, struct winlink *wl, time_t t, struct grid_cell *gc) { struct options *oo = &wl->window->options; - char *text, flag; + struct session *s = c->session; + const char *fmt; + char *text; u_char fg, bg, attr; fg = options_get_number(oo, "window-status-fg"); @@ -544,10 +586,7 @@ status_print(struct session *s, struct winlink *wl, struct grid_cell *gc) attr = options_get_number(oo, "window-status-attr"); if (attr != 0) gc->attr = attr; - - flag = ' '; - if (wl == TAILQ_FIRST(&s->lastw)) - flag = '-'; + fmt = options_get_string(oo, "window-status-format"); if (wl == s->curw) { fg = options_get_number(oo, "window-status-current-fg"); if (fg != 8) @@ -558,21 +597,15 @@ status_print(struct session *s, struct winlink *wl, struct grid_cell *gc) attr = options_get_number(oo, "window-status-current-attr"); if (attr != 0) gc->attr = attr; - flag = '*'; + fmt = options_get_string(oo, "window-status-current-format"); } - if (session_alert_has(s, wl, WINDOW_ACTIVITY)) { - flag = '#'; + if (session_alert_has(s, wl, WINDOW_ACTIVITY) || + session_alert_has(s, wl, WINDOW_BELL) || + session_alert_has(s, wl, WINDOW_CONTENT)) gc->attr ^= GRID_ATTR_REVERSE; - } else if (session_alert_has(s, wl, WINDOW_BELL)) { - flag = '!'; - gc->attr ^= GRID_ATTR_REVERSE; - } else if (session_alert_has(s, wl, WINDOW_CONTENT)) { - flag = '+'; - gc->attr ^= GRID_ATTR_REVERSE; - } - xasprintf(&text, "%d:%s%c", wl->idx, wl->window->name, flag); + text = status_replace(c, wl, fmt, t, 1); return (text); } diff --git a/tmux.1 b/tmux.1 index de86a728..0a34712e 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1477,6 +1477,7 @@ may contain any of the following special character sequences: .It Li "#(command)" Ta "First line of command's output" .It Li "#[attributes]" Ta "Colour or attribute change" .It Li "#H" Ta "Hostname of local host" +.It Li "#F" Ta "Current window flag" .It Li "#I" Ta "Current window index" .It Li "#P" Ta "Current pane index" .It Li "#S" Ta "Session name" @@ -1785,6 +1786,14 @@ Set status line background colour for a single window. .It Ic window-status-fg Ar colour Set status line foreground colour for a single window. .Pp +.It Ic window-status-format Ar string +Set the format in which the window is displayed in the status line window list. +See the +.Ar status-left +option for details of special character sequences available. +The default is +.Ql #I:#W#F . +.Pp .It Ic window-status-current-attr Ar attributes Set status line attributes for the currently active window. .Pp @@ -1794,6 +1803,11 @@ Set status line background colour for the currently active window. .It Ic window-status-current-fg Ar colour Set status line foreground colour for the currently active window. .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 Xo Ic xterm-keys .Op Ic on | off .Xc @@ -1900,8 +1914,13 @@ command, see the and .Ic status-right-length options below), and a central window list. -The window list shows the index, name and (if any) flag of the windows -present in the current session in ascending numerical order. +By default, the window list shows the index, name and (if any) flag of the +windows present in the current session in ascending numerical order. +It may be customised with the +.Ar window-status-format +and +.Ar window-status-current-format +options. The flag is one of the following symbols appended to the window name: .Bl -column "Symbol" "Meaning" -offset indent .It Sy "Symbol" Ta Sy "Meaning" diff --git a/tmux.c b/tmux.c index f3f764e1..f339b729 100644 --- a/tmux.c +++ b/tmux.c @@ -391,6 +391,8 @@ main(int argc, char **argv) options_set_number(wo, "window-status-current-bg", 8); options_set_number(wo, "window-status-current-fg", 8); options_set_number(wo, "window-status-fg", 8); + options_set_string(wo, "window-status-format", "#I:#W#F"); + options_set_string(wo, "window-status-current-format", "#I:#W#F"); options_set_number(wo, "xterm-keys", 0); options_set_number(wo, "remain-on-exit", 0); options_set_number(wo, "synchronize-panes", 0); diff --git a/tmux.h b/tmux.h index 78869274..0dda8cff 100644 --- a/tmux.h +++ b/tmux.h @@ -1617,7 +1617,8 @@ void server_update_event(struct client *); /* status.c */ int status_redraw(struct client *); -char *status_replace(struct client *, const char *, time_t, int); +char *status_replace( + struct client *, struct winlink *, const char *, time_t, int); void printflike2 status_message_set(struct client *, const char *, ...); void status_message_clear(struct client *); int status_message_redraw(struct client *); From 33b337f6185aba3b59962db17de9b08af48de301 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 19 Nov 2009 19:47:28 +0000 Subject: [PATCH 0554/1180] Change status line drawing to create the window list in a separate screen and then copy it into the status line screen. This allows UTF-8 in window names and fixes some problems with #[] in window-status-format. --- status.c | 388 ++++++++++++++++++++++++++++--------------------------- tmux.h | 4 + window.c | 2 + 3 files changed, 207 insertions(+), 187 deletions(-) diff --git a/status.c b/status.c index 39e824c1..742d4495 100644 --- a/status.c +++ b/status.c @@ -29,6 +29,10 @@ #include "tmux.h" +char *status_redraw_get_left( + struct client *, time_t, int, struct grid_cell *, size_t *); +char *status_redraw_get_right( + struct client *, time_t, int, struct grid_cell *, size_t *); char *status_job(struct client *, char **); void status_job_callback(struct job *); size_t status_width(struct client *, struct winlink *, time_t); @@ -41,195 +45,211 @@ void status_message_callback(int, short, void *); void status_prompt_add_history(struct client *); char *status_prompt_complete(const char *); +/* Retrieve options for left string. */ +char * +status_redraw_get_left(struct client *c, + time_t t, int utf8flag, struct grid_cell *gc, size_t *size) +{ + struct session *s = c->session; + char *left; + u_char 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; + + left = status_replace( + c, NULL, options_get_string(&s->options, "status-left"), t, 1); + + *size = options_get_number(&s->options, "status-left-length"); + leftlen = screen_write_cstrlen(utf8flag, "%s", left); + if (leftlen < *size) + *size = leftlen; + return (left); +} + +/* Retrieve options for right string. */ +char * +status_redraw_get_right(struct client *c, + time_t t, int utf8flag, struct grid_cell *gc, size_t *size) +{ + struct session *s = c->session; + char *right; + u_char 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; + + right = status_replace( + c, NULL, options_get_string(&s->options, "status-right"), t, 1); + + *size = options_get_number(&s->options, "status-right-length"); + rightlen = screen_write_cstrlen(utf8flag, "%s", right); + if (rightlen < *size) + *size = rightlen; + return (right); +} + /* Draw status for client on the last lines of given context. */ int status_redraw(struct client *c) { - struct screen_write_ctx ctx; - struct session *s = c->session; - struct winlink *wl; - struct screen old_status; - char *left, *right, *text, *ptr; - size_t llen, llen2, rlen, rlen2, offset; - size_t ox, xx, yy, size, start, width; - struct grid_cell stdgc, sl_stdgc, sr_stdgc, gc; - int larrow, rarrow, utf8flag; - int sl_fg, sl_bg, sr_fg, sr_bg; - int sl_attr, sr_attr; - - left = right = NULL; + struct screen_write_ctx ctx; + struct session *s = c->session; + struct winlink *wl; + struct screen old_status, window_list; + struct grid_cell stdgc, lgc, rgc, gc; + time_t t; + char *left, *right; + u_int offset, needed; + u_int wlstart, wlwidth, wlavailable, wloffset, wlsize; + size_t llen, rlen; + int larrow, rarrow, utf8flag; /* No status line?*/ if (c->tty.sy == 0 || !options_get_number(&s->options, "status")) return (1); + left = right = NULL; larrow = rarrow = 0; - /* Create the target screen. */ - memcpy(&old_status, &c->status, sizeof old_status); - screen_init(&c->status, c->tty.sx, 1, 0); - + /* Update status timer. */ if (gettimeofday(&c->status_timer, NULL) != 0) fatal("gettimeofday failed"); + 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"); - /* - * Set the status-left and status-right parts to the default status - * line options and only change them where they differ from the - * defaults. - */ - memcpy(&sl_stdgc, &stdgc, sizeof sl_stdgc); - memcpy(&sr_stdgc, &stdgc, sizeof sr_stdgc); - sl_fg = options_get_number(&s->options, "status-left-fg"); - if (sl_fg != 8) - colour_set_fg(&sl_stdgc, sl_fg); - sl_bg = options_get_number(&s->options, "status-left-bg"); - if (sl_bg != 8) - colour_set_bg(&sl_stdgc, sl_bg); - sl_attr = options_get_number(&s->options, "status-left-attr"); - if (sl_attr != 0) - sl_stdgc.attr = sl_attr; - sr_fg = options_get_number(&s->options, "status-right-fg"); - if (sr_fg != 8) - colour_set_fg(&sr_stdgc, sr_fg); - sr_bg = options_get_number(&s->options, "status-right-bg"); - if (sr_bg != 8) - colour_set_bg(&sr_stdgc, sr_bg); - sr_attr = options_get_number(&s->options, "status-right-attr"); - if (sr_attr != 0) - sr_stdgc.attr = sr_attr; + /* Create the target screen. */ + memcpy(&old_status, &c->status, sizeof old_status); + screen_init(&c->status, c->tty.sx, 1, 0); + screen_write_start(&ctx, NULL, &c->status); + for (offset = 0; offset < c->tty.sx; offset++) + screen_write_putc(&ctx, &stdgc, ' '); + screen_write_stop(&ctx); - yy = c->tty.sy - 1; - if (yy == 0) - goto blank; + /* If the height is one line, blank status line. */ + if (c->tty.sy <= 1) + goto out; - /* Caring about UTF-8 in status line? */ + /* Get UTF-8 flag. */ utf8flag = options_get_number(&s->options, "status-utf8"); - /* Work out the left and right strings. */ - left = status_replace(c, NULL, options_get_string( - &s->options, "status-left"), c->status_timer.tv_sec, 1); - llen = options_get_number(&s->options, "status-left-length"); - llen2 = screen_write_cstrlen(utf8flag, "%s", left); - if (llen2 < llen) - llen = llen2; - - right = status_replace(c, NULL, options_get_string( - &s->options, "status-right"), c->status_timer.tv_sec, 1); - rlen = options_get_number(&s->options, "status-right-length"); - rlen2 = screen_write_cstrlen(utf8flag, "%s", right); - if (rlen2 < rlen) - rlen = rlen2; + /* Work out left and right strings. */ + memcpy(&lgc, &stdgc, sizeof lgc); + left = status_redraw_get_left(c, t, utf8flag, &lgc, &llen); + memcpy(&rgc, &stdgc, sizeof rgc); + right = status_redraw_get_right(c, t, utf8flag, &rgc, &rlen); /* - * Figure out how much space we have for the window list. If there isn't - * enough space, just wimp out. + * Figure out how much space we have for the window list. If there + * isn't enough space, just show a blank status line. */ - xx = 0; + needed = 0; if (llen != 0) - xx += llen + 1; + needed += llen + 1; if (rlen != 0) - xx += rlen + 1; - if (c->tty.sx == 0 || c->tty.sx <= xx) - goto blank; - xx = c->tty.sx - xx; + needed += rlen + 1; + if (c->tty.sx == 0 || c->tty.sx <= needed) + goto out; + wlavailable = c->tty.sx - needed; - /* - * Right. We have xx characters to fill. Find out how much is to go in - * them and the offset of the current window (it must be on screen). - */ - width = offset = 0; + /* Calculate the total size needed for the window list. */ + wlstart = wloffset = wlwidth = 0; RB_FOREACH(wl, winlinks, &s->windows) { - size = status_width(c, wl, c->status_timer.tv_sec) + 1; - if (wl == s->curw) - offset = width; - width += size; - } - start = 0; + if (wl->status_text != NULL) + xfree(wl->status_text); + memcpy(&wl->status_cell, &stdgc, sizeof wl->status_cell); + wl->status_text = status_print(c, wl, t, &wl->status_cell); + wl->status_width = + screen_write_cstrlen(utf8flag, "%s", wl->status_text); - /* If there is enough space for the total width, all is gravy. */ - if (width <= xx) + if (wl == s->curw) + wloffset = wlwidth; + wlwidth += wl->status_width + 1; + } + + /* Create a new screen for the window list. */ + screen_init(&window_list, wlwidth, 1, 0); + + /* And draw the window list into it. */ + screen_write_start(&ctx, NULL, &window_list); + RB_FOREACH(wl, winlinks, &s->windows) { + screen_write_cnputs(&ctx, + -1, &wl->status_cell, utf8flag, "%s", wl->status_text); + screen_write_putc(&ctx, &stdgc, ' '); + } + screen_write_stop(&ctx); + + /* If there is enough space for the total width, skip to draw now. */ + if (wlwidth <= wlavailable) goto draw; /* Find size of current window text. */ - size = status_width(c, s->curw, c->status_timer.tv_sec); + wlsize = s->curw->status_width; /* - * If the offset is already on screen, we're good to draw from the + * If the current window is already on screen, good to draw from the * start and just leave off the end. */ - if (offset + size < xx) { - if (xx > 0) { + if (wloffset + wlsize < wlavailable) { + if (wlavailable > 0) { rarrow = 1; - xx--; + wlavailable--; } + wlwidth = wlavailable; + } else { + /* + * Work out how many characters we need to omit from the + * start. There are wlavailable characters to fill, and + * wloffset + wlsize must be the last. So, the start character + * is wloffset + wlsize - wlavailable. + */ + if (wlavailable > 0) { + larrow = 1; + wlavailable--; + } + + wlstart = wloffset + wlsize - wlavailable; + if (wlavailable > 0 && wlwidth > wlstart + wlavailable + 1) { + rarrow = 1; + wlstart++; + wlavailable--; + } + wlwidth = wlavailable; + } - width = xx; - goto draw; + /* Bail if anything is now too small too. */ + if (wlwidth == 0 || wlavailable == 0) { + screen_free(&window_list); + goto out; } /* - * Work out how many characters we need to omit from the start. There - * are xx characters to fill, and offset + size must be the last. So, - * the start character is offset + size - xx. + * Now the start position is known, work out the state of the left and + * right arrows. */ - if (xx > 0) { - larrow = 1; - xx--; - } - - start = offset + size - xx; - if (xx > 0 && width > start + xx + 1) { /* + 1, eh? */ - rarrow = 1; - start++; - xx--; - } - width = xx; - -draw: - /* Bail here if anything is too small too. XXX. */ - if (width == 0 || xx == 0) - goto blank; - - /* Begin drawing and move to the starting position. */ - screen_write_start(&ctx, NULL, &c->status); - if (llen != 0) { - screen_write_cursormove(&ctx, 0, yy); - screen_write_cnputs(&ctx, llen, &sl_stdgc, utf8flag, "%s", left); - screen_write_putc(&ctx, &stdgc, ' '); - if (larrow) - screen_write_putc(&ctx, &stdgc, ' '); - } else { - if (larrow) - screen_write_cursormove(&ctx, 1, yy); - else - screen_write_cursormove(&ctx, 0, yy); - } - - ox = 0; - if (width < xx) { - switch (options_get_number(&s->options, "status-justify")) { - case 1: /* centered */ - ox = 1 + (xx - width) / 2; - break; - case 2: /* right */ - ox = 1 + (xx - width); - break; - } - xx -= ox; - while (ox-- > 0) - screen_write_putc(&ctx, &stdgc, ' '); - } - - /* Draw each character in succession. */ offset = 0; RB_FOREACH(wl, winlinks, &s->windows) { - memcpy(&gc, &stdgc, sizeof gc); - text = status_print(c, wl, c->status_timer.tv_sec, &gc); - - if (larrow == 1 && offset < start) { + if (larrow == 1 && offset < wlstart) { if (session_alert_has(s, wl, WINDOW_ACTIVITY)) larrow = -1; else if (session_alert_has(s, wl, WINDOW_BELL)) @@ -238,16 +258,9 @@ draw: larrow = -1; } - ptr = text; - for (; offset < start; offset++) - ptr++; /* XXX should skip UTF-8 characters */ - if (offset < start + width) { - screen_write_cnputs(&ctx, - start + width - offset, &gc, utf8flag, "%s", text); - offset += screen_write_cstrlen(utf8flag, "%s", text); - } + offset += wl->status_width; - if (rarrow == 1 && offset > start + width) { + if (rarrow == 1 && offset > wlstart + wlwidth) { if (session_alert_has(s, wl, WINDOW_ACTIVITY)) rarrow = -1; else if (session_alert_has(s, wl, WINDOW_BELL)) @@ -255,62 +268,63 @@ draw: else if (session_alert_has(s, wl, WINDOW_CONTENT)) rarrow = -1; } - - if (offset < start + width) { - if (offset >= start) { - screen_write_putc(&ctx, &stdgc, ' '); - } - offset++; - } - - xfree(text); } - /* Fill the remaining space if any. */ - while (offset++ < xx) - screen_write_putc(&ctx, &stdgc, ' '); +draw: + /* Begin drawing. */ + screen_write_start(&ctx, NULL, &c->status); - /* Draw the last item. */ - if (rlen != 0) { - screen_write_cursormove(&ctx, c->tty.sx - rlen - 1, yy); + /* Draw the left string and arrow. */ + screen_write_cursormove(&ctx, 0, 0); + if (llen != 0) { + screen_write_cnputs(&ctx, llen, &lgc, utf8flag, "%s", left); screen_write_putc(&ctx, &stdgc, ' '); - screen_write_cnputs(&ctx, rlen, &sr_stdgc, utf8flag, "%s", right); } - - /* Draw the arrows. */ if (larrow != 0) { memcpy(&gc, &stdgc, sizeof gc); if (larrow == -1) gc.attr ^= GRID_ATTR_REVERSE; - if (llen != 0) - screen_write_cursormove(&ctx, llen + 1, yy); - else - screen_write_cursormove(&ctx, 0, yy); screen_write_putc(&ctx, &gc, '<'); } + + /* Draw the right string and arrow. */ if (rarrow != 0) { + screen_write_cursormove(&ctx, c->tty.sx - rlen - 2, 0); memcpy(&gc, &stdgc, sizeof gc); if (rarrow == -1) gc.attr ^= GRID_ATTR_REVERSE; - if (rlen != 0) - screen_write_cursormove(&ctx, c->tty.sx - rlen - 2, yy); - else - screen_write_cursormove(&ctx, c->tty.sx - 1, yy); screen_write_putc(&ctx, &gc, '>'); + } else + screen_write_cursormove(&ctx, c->tty.sx - rlen - 1, 0); + if (rlen != 0) { + screen_write_putc(&ctx, &stdgc, ' '); + screen_write_cnputs(&ctx, rlen, &rgc, utf8flag, "%s", right); } - goto out; + /* Figure out the offset for the window list. */ + wloffset = 1; + if (wlwidth < wlavailable) { + switch (options_get_number(&s->options, "status-justify")) { + case 1: /* centered */ + wloffset = 1 + (wlavailable - wlwidth) / 2; + break; + case 2: /* right */ + wloffset = 1 + (wlavailable - wlwidth); + break; + } + } + wloffset += llen; + if (larrow != 0) + wloffset++; -blank: - /* Just draw the whole line as blank. */ - screen_write_start(&ctx, NULL, &c->status); - screen_write_cursormove(&ctx, 0, yy); - for (offset = 0; offset < c->tty.sx; offset++) - screen_write_putc(&ctx, &stdgc, ' '); + /* Copy the window list. */ + screen_write_cursormove(&ctx, wloffset, 0); + screen_write_copy(&ctx, &window_list, wlstart, 0, wlwidth, 1); + screen_free(&window_list); -out: screen_write_stop(&ctx); +out: if (left != NULL) xfree(left); if (right != NULL) diff --git a/tmux.h b/tmux.h index 0dda8cff..852203ee 100644 --- a/tmux.h +++ b/tmux.h @@ -844,6 +844,10 @@ struct winlink { int idx; struct window *window; + size_t status_width; + struct grid_cell status_cell; + char *status_text; + RB_ENTRY(winlink) entry; TAILQ_ENTRY(winlink) sentry; }; diff --git a/window.c b/window.c index 7e945129..be61e73c 100644 --- a/window.c +++ b/window.c @@ -149,6 +149,8 @@ winlink_remove(struct winlinks *wwl, struct winlink *wl) struct window *w = wl->window; RB_REMOVE(winlinks, wwl, wl); + if (wl->status_text != NULL) + xfree(wl->status_text); xfree(wl); if (w->references == 0) From 2cea9433c27dc21d3f5215cb90ab66c905a88098 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 19 Nov 2009 21:30:53 +0000 Subject: [PATCH 0555/1180] Get some brackets in the right place so ## works. Also fix a space in a comment. --- status.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/status.c b/status.c index 742d4495..31e25215 100644 --- a/status.c +++ b/status.c @@ -121,7 +121,7 @@ status_redraw(struct client *c) size_t llen, rlen; int larrow, rarrow, utf8flag; - /* No status line?*/ + /* No status line? */ if (c->tty.sy == 0 || !options_get_number(&s->options, "status")) return (1); left = right = NULL; @@ -419,7 +419,7 @@ status_replace1(struct client *c,struct winlink *wl, ch = ']'; goto skip_to; case '#': - *(*optr++) = '#'; + *(*optr)++ = '#'; break; } From 070e3b4178ebcc23be88e37beac11a902fd085ce Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 20 Nov 2009 06:33:26 +0000 Subject: [PATCH 0556/1180] Remove oldest messages from log when limit is hit, not newest. --- status.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/status.c b/status.c index 31e25215..bff7afe9 100644 --- a/status.c +++ b/status.c @@ -650,10 +650,13 @@ status_message_set(struct client *c, const char *fmt, ...) limit = 0; else limit = options_get_number(&s->options, "message-limit"); - for (i = ARRAY_LENGTH(&c->message_log); i > limit; i--) { - msg = &ARRAY_ITEM(&c->message_log, i - 1); - xfree(msg->msg); - ARRAY_REMOVE(&c->message_log, i - 1); + if (ARRAY_LENGTH(&c->message_log) > limit) { + limit = ARRAY_LENGTH(&c->message_log) - limit; + for (i = 0; i < limit; i++) { + msg = &ARRAY_FIRST(&c->message_log); + xfree(msg->msg); + ARRAY_REMOVE(&c->message_log, 0); + } } delay = options_get_number(&c->session->options, "display-time"); From 5d56225d95490fac96bc9ba00c6ce320ca2d8624 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 20 Nov 2009 07:01:12 +0000 Subject: [PATCH 0557/1180] Display UTF-8 properly in status line messages and prompt. Cursor handling is still way off though. --- status.c | 49 +++++++++++++++++++++++++------------------------ 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/status.c b/status.c index bff7afe9..4236d54b 100644 --- a/status.c +++ b/status.c @@ -705,13 +705,16 @@ status_message_redraw(struct client *c) struct screen old_status; size_t len; struct grid_cell gc; + int utf8flag; if (c->tty.sx == 0 || c->tty.sy == 0) return (0); memcpy(&old_status, &c->status, sizeof old_status); screen_init(&c->status, c->tty.sx, 1, 0); - len = strlen(c->message_string); + utf8flag = options_get_number(&s->options, "status-utf8"); + + len = screen_write_strlen(utf8flag, "%s", c->message_string); if (len > c->tty.sx) len = c->tty.sx; @@ -723,7 +726,7 @@ status_message_redraw(struct client *c) screen_write_start(&ctx, NULL, &c->status); screen_write_cursormove(&ctx, 0, 0); - screen_write_puts(&ctx, &gc, "%.*s", (int) len, c->message_string); + screen_write_nputs(&ctx, len, &gc, utf8flag, "%s", c->message_string); for (; len < c->tty.sx; len++) screen_write_putc(&ctx, &gc, ' '); @@ -812,22 +815,24 @@ status_prompt_update(struct client *c, const char *msg) int status_prompt_redraw(struct client *c) { - struct screen_write_ctx ctx; + struct screen_write_ctx ctx; struct session *s = c->session; struct screen old_status; size_t i, size, left, len, off; - char ch; - struct grid_cell gc; + struct grid_cell gc, *gcp; + int utf8flag; if (c->tty.sx == 0 || c->tty.sy == 0) return (0); memcpy(&old_status, &c->status, sizeof old_status); screen_init(&c->status, c->tty.sx, 1, 0); - off = 0; - len = strlen(c->prompt_string); + utf8flag = options_get_number(&s->options, "status-utf8"); + + len = screen_write_strlen(utf8flag, "%s", c->prompt_string); if (len > c->tty.sx) len = c->tty.sx; + off = 0; memcpy(&gc, &grid_default_cell, sizeof gc); colour_set_fg(&gc, options_get_number(&s->options, "message-fg")); @@ -837,35 +842,31 @@ status_prompt_redraw(struct client *c) screen_write_start(&ctx, NULL, &c->status); screen_write_cursormove(&ctx, 0, 0); - screen_write_puts(&ctx, &gc, "%.*s", (int) len, c->prompt_string); + screen_write_nputs(&ctx, len, &gc, utf8flag, "%s", c->prompt_string); left = c->tty.sx - len; if (left != 0) { - if (c->prompt_index < left) - size = strlen(c->prompt_buffer); - else { + size = screen_write_strlen(utf8flag, "%s", c->prompt_buffer); + if (c->prompt_index >= left) { off = c->prompt_index - left + 1; - if (c->prompt_index == strlen(c->prompt_buffer)) + if (c->prompt_index == size) left--; size = left; } - screen_write_puts( - &ctx, &gc, "%.*s", (int) left, c->prompt_buffer + off); + screen_write_nputs( + &ctx, left, &gc, utf8flag, "%s", c->prompt_buffer + off); - for (i = len + size; i < c->tty.sx; i++) - screen_write_putc(&ctx, &gc, ' '); - - /* Draw a fake cursor. */ - ch = ' '; - screen_write_cursormove(&ctx, len + c->prompt_index - off, 0); - if (c->prompt_index < strlen(c->prompt_buffer)) - ch = c->prompt_buffer[c->prompt_index]; - gc.attr ^= GRID_ATTR_REVERSE; - screen_write_putc(&ctx, &gc, ch); + for (i = len + size; i < c->tty.sx; i++) + screen_write_putc(&ctx, &gc, ' '); } screen_write_stop(&ctx); + /* Apply fake cursor. */ + off = len + c->prompt_index - off; + gcp = grid_view_get_cell(c->status.grid, off, 0); + gcp->attr ^= GRID_ATTR_REVERSE; + if (grid_compare(c->status.grid, old_status.grid) == 0) { screen_free(&old_status); return (0); From 58688c48aa78173406c4037a6e8c0591ca3af591 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 20 Nov 2009 19:12:39 +0000 Subject: [PATCH 0558/1180] When -h and -p are given to split-window, calculate the percentage size using the width instead of the height. --- cmd-split-window.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/cmd-split-window.c b/cmd-split-window.c index 4dd03055..ebe0ffef 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -174,17 +174,21 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) else cwd = ctx->cmdclient->cwd; - size = -1; - if (data->size != -1) - size = data->size; - else if (data->percentage != -1) - size = (w->active->sy * data->percentage) / 100; - hlimit = options_get_number(&s->options, "history-limit"); - type = LAYOUT_TOPBOTTOM; if (data->flag_horizontal) type = LAYOUT_LEFTRIGHT; + size = -1; + if (data->size != -1) + size = data->size; + else if (data->percentage != -1) { + if (type == LAYOUT_TOPBOTTOM) + size = (w->active->sy * data->percentage) / 100; + else + size = (w->active->sx * data->percentage) / 100; + } + hlimit = options_get_number(&s->options, "history-limit"); + shell = options_get_string(&s->options, "default-shell"); if (*shell == '\0' || areshell(shell)) shell = _PATH_BSHELL; From 9b9d26f80e2057488c1a8fe93dc729fdf6a9e9be Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 21 Nov 2009 17:52:18 +0000 Subject: [PATCH 0559/1180] Use home from struct passwd if HOME is empty as well as if it is NULL, and fix a style nit. Both from Tiago Cunha. --- cmd-string.c | 2 +- cmd.c | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/cmd-string.c b/cmd-string.c index 1a380e50..9cb48466 100644 --- a/cmd-string.c +++ b/cmd-string.c @@ -332,7 +332,7 @@ cmd_string_expand_tilde(const char *s, size_t *p) home = NULL; if (cmd_string_getc(s, p) == '/') { - if ((home = getenv("HOME")) == NULL) { + if ((home = getenv("HOME")) == NULL || *home == '\0') { if ((pw = getpwuid(getuid())) != NULL) home = pw->pw_dir; } diff --git a/cmd.c b/cmd.c index 10e25225..902c390f 100644 --- a/cmd.c +++ b/cmd.c @@ -278,9 +278,8 @@ cmd_free(struct cmd *cmd) size_t cmd_print(struct cmd *cmd, char *buf, size_t len) { - if (cmd->entry->print == NULL) { + if (cmd->entry->print == NULL) return (xsnprintf(buf, len, "%s", cmd->entry->name)); - } return (cmd->entry->print(cmd, buf, len)); } From fce47e2e6368055e8fdebcfe95a920d953d2f09c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 22 Nov 2009 22:52:39 +0000 Subject: [PATCH 0560/1180] Add cursor keys to the key names list. --- tmux.1 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tmux.1 b/tmux.1 index 0a34712e..9183b351 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1044,6 +1044,10 @@ or and Alt (meta) with .Ql M- . In addition, the following special key names are accepted: +.Em Up , +.Em Down , +.Em Left , +.Em Right , .Em BSpace , .Em BTab , .Em DC From 87821fce0e3f8d55657fdc4fba39cc1186e2ed3c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 24 Nov 2009 19:16:11 +0000 Subject: [PATCH 0561/1180] Add a -p flag to display-message to print the output rather than displaying in the status line, this allows things like "display -p '#W'" to find the current window index. --- cmd-display-message.c | 9 ++++++--- tmux.1 | 8 +++++++- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/cmd-display-message.c b/cmd-display-message.c index aa4fd5db..8c42ee6d 100644 --- a/cmd-display-message.c +++ b/cmd-display-message.c @@ -30,8 +30,8 @@ int cmd_display_message_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_display_message_entry = { "display-message", "display", - CMD_TARGET_CLIENT_USAGE " [message]", - CMD_ARG01, "", + "[-p] " CMD_TARGET_CLIENT_USAGE " [message]", + CMD_ARG01, "p", cmd_target_init, cmd_target_parse, cmd_display_message_exec, @@ -56,7 +56,10 @@ cmd_display_message_exec(struct cmd *self, struct cmd_ctx *ctx) template = data->arg; msg = status_replace(c, NULL, template, time(NULL), 0); - status_message_set(c, "%s", msg); + if (cmd_check_flag(data->chflags, 'p')) + ctx->print(ctx, "%s", msg); + else + status_message_set(c, "%s", msg); xfree(msg); return (0); diff --git a/tmux.1 b/tmux.1 index 9183b351..d3c61bd7 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2011,11 +2011,17 @@ Ask for confirmation before executing This command works only from inside .Nm . .It Xo Ic display-message +.Op Fl p .Op Fl t Ar target-client .Op Ar message .Xc .D1 (alias: Ic display ) -Display a message in the status line. +Display a message. +If +.Fl p +is given, the output is printed to stdout, otherwise it is displayed in the +.Ar target-client +status line. The format of .Ar message is as for From 094bca5ac3024957700ff5c0af74fbec18a79172 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 25 Nov 2009 12:24:31 +0000 Subject: [PATCH 0562/1180] Output the right keys for application and number keypad modes (they were the wrong way round). --- input-keys.c | 64 ++++++++++++++++++++++++++-------------------------- tmux.h | 2 +- 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/input-keys.c b/input-keys.c index 37a24bcd..cab3af79 100644 --- a/input-keys.c +++ b/input-keys.c @@ -98,39 +98,39 @@ struct input_key_ent input_keys[] = { { KEYC_LEFT, "\033[D", 0 }, /* Keypad keys. Keypad versions must come first. */ - { KEYC_KP_SLASH, "/", INPUTKEY_KEYPAD }, - { KEYC_KP_STAR, "*", INPUTKEY_KEYPAD }, - { KEYC_KP_MINUS, "-", INPUTKEY_KEYPAD }, - { KEYC_KP_SEVEN, "7", INPUTKEY_KEYPAD }, - { KEYC_KP_EIGHT, "8", INPUTKEY_KEYPAD }, - { KEYC_KP_NINE, "9", INPUTKEY_KEYPAD }, - { KEYC_KP_PLUS, "+", INPUTKEY_KEYPAD }, - { KEYC_KP_FOUR, "4", INPUTKEY_KEYPAD }, - { KEYC_KP_FIVE, "5", INPUTKEY_KEYPAD }, - { KEYC_KP_SIX, "6", INPUTKEY_KEYPAD }, - { KEYC_KP_ONE, "1", INPUTKEY_KEYPAD }, - { KEYC_KP_TWO, "2", INPUTKEY_KEYPAD }, - { KEYC_KP_THREE, "3", INPUTKEY_KEYPAD }, - { KEYC_KP_ENTER, "\n", INPUTKEY_KEYPAD }, - { KEYC_KP_ZERO, "0", INPUTKEY_KEYPAD }, - { KEYC_KP_PERIOD, ".", INPUTKEY_KEYPAD }, + { KEYC_KP_SLASH, "\033Oo", INPUTKEY_KEYPAD }, + { KEYC_KP_STAR, "\033Oj", INPUTKEY_KEYPAD }, + { KEYC_KP_MINUS, "\033Om", INPUTKEY_KEYPAD }, + { KEYC_KP_SEVEN, "\033Ow", INPUTKEY_KEYPAD }, + { KEYC_KP_EIGHT, "\033Ox", INPUTKEY_KEYPAD }, + { KEYC_KP_NINE, "\033Oy", INPUTKEY_KEYPAD }, + { KEYC_KP_PLUS, "\033Ok", INPUTKEY_KEYPAD }, + { KEYC_KP_FOUR, "\033Ot", INPUTKEY_KEYPAD }, + { KEYC_KP_FIVE, "\033Ou", INPUTKEY_KEYPAD }, + { KEYC_KP_SIX, "\033Ov", INPUTKEY_KEYPAD }, + { KEYC_KP_ONE, "\033Oq", INPUTKEY_KEYPAD }, + { KEYC_KP_TWO, "\033Or", INPUTKEY_KEYPAD }, + { KEYC_KP_THREE, "\033Os", INPUTKEY_KEYPAD }, + { KEYC_KP_ENTER, "\033OM", INPUTKEY_KEYPAD }, + { KEYC_KP_ZERO, "\033Op", INPUTKEY_KEYPAD }, + { KEYC_KP_PERIOD, "\033On", INPUTKEY_KEYPAD }, - { KEYC_KP_SLASH, "\033Oo", 0 }, - { KEYC_KP_STAR, "\033Oj", 0 }, - { KEYC_KP_MINUS, "\033Om", 0 }, - { KEYC_KP_SEVEN, "\033Ow", 0 }, - { KEYC_KP_EIGHT, "\033Ox", 0 }, - { KEYC_KP_NINE, "\033Oy", 0 }, - { KEYC_KP_PLUS, "\033Ok", 0 }, - { KEYC_KP_FOUR, "\033Ot", 0 }, - { KEYC_KP_FIVE, "\033Ou", 0 }, - { KEYC_KP_SIX, "\033Ov", 0 }, - { KEYC_KP_ONE, "\033Oq", 0 }, - { KEYC_KP_TWO, "\033Or", 0 }, - { KEYC_KP_THREE, "\033Os", 0 }, - { KEYC_KP_ENTER, "\033OM", 0 }, - { KEYC_KP_ZERO, "\033Op", 0 }, - { KEYC_KP_PERIOD, "\033On", 0 }, + { KEYC_KP_SLASH, "/", 0 }, + { KEYC_KP_STAR, "*", 0 }, + { KEYC_KP_MINUS, "-", 0 }, + { KEYC_KP_SEVEN, "7", 0 }, + { KEYC_KP_EIGHT, "8", 0 }, + { KEYC_KP_NINE, "9", 0 }, + { KEYC_KP_PLUS, "+", 0 }, + { KEYC_KP_FOUR, "4", 0 }, + { KEYC_KP_FIVE, "5", 0 }, + { KEYC_KP_SIX, "6", 0 }, + { KEYC_KP_ONE, "1", 0 }, + { KEYC_KP_TWO, "2", 0 }, + { KEYC_KP_THREE, "3", 0 }, + { KEYC_KP_ENTER, "\n", 0 }, + { KEYC_KP_ZERO, "0", 0 }, + { KEYC_KP_PERIOD, ".", 0 }, }; /* Translate a key code into an output key sequence. */ diff --git a/tmux.h b/tmux.h index 852203ee..61921ae2 100644 --- a/tmux.h +++ b/tmux.h @@ -527,7 +527,7 @@ struct mode_key_table { #define MODE_CURSOR 0x1 #define MODE_INSERT 0x2 #define MODE_KCURSOR 0x4 -#define MODE_KKEYPAD 0x8 +#define MODE_KKEYPAD 0x8 /* set = application, clear = number */ #define MODE_MOUSE 0x10 /* From d31d4c05cff725db571d4463da4106638304e29b Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 26 Nov 2009 14:46:08 +0000 Subject: [PATCH 0563/1180] Emulate il1, dl1, ich1 to run (albeit slowly) with vt100 feature set. --- tty-term.c | 15 --------------- tty.c | 12 ++++++++---- 2 files changed, 8 insertions(+), 19 deletions(-) diff --git a/tty-term.c b/tty-term.c index 09ff9b1e..0c22b527 100644 --- a/tty-term.c +++ b/tty-term.c @@ -388,21 +388,6 @@ tty_term_find(char *name, int fd, const char *overrides, char **cause) xasprintf(cause, "terminal does not support cud1 or cud"); goto error; } - if (!tty_term_has(term, TTYC_IL1) && !tty_term_has(term, TTYC_IL)) { - xasprintf(cause, "terminal does not support il1 or il"); - goto error; - } - if (!tty_term_has(term, TTYC_DL1) && !tty_term_has(term, TTYC_DL)) { - xasprintf(cause, "terminal does not support dl1 or dl"); - goto error; - } - if (!tty_term_has(term, TTYC_ICH1) && - !tty_term_has(term, TTYC_ICH) && (!tty_term_has(term, TTYC_SMIR) || - !tty_term_has(term, TTYC_RMIR))) { - xasprintf(cause, - "terminal does not support ich1 or ich or smir and rmir"); - goto error; - } /* Figure out if we have 256 or 88 colours. */ if (tty_term_number(term, TTYC_COLORS) == 256) diff --git a/tty.c b/tty.c index a3aeda5d..84931e78 100644 --- a/tty.c +++ b/tty.c @@ -569,12 +569,14 @@ tty_cmd_insertcharacter(struct tty *tty, const struct tty_ctx *ctx) if (tty_term_has(tty->term, TTYC_ICH) || tty_term_has(tty->term, TTYC_ICH1)) tty_emulate_repeat(tty, TTYC_ICH, TTYC_ICH1, ctx->num); - else { + else if (tty_term_has(tty->term, TTYC_SMIR) && + tty_term_has(tty->term, TTYC_RMIR)) { tty_putcode(tty, TTYC_SMIR); for (i = 0; i < ctx->num; i++) tty_putc(tty, ' '); tty_putcode(tty, TTYC_RMIR); - } + } else + tty_draw_line(tty, wp->screen, ctx->ocy, wp->xoff, wp->yoff); } void @@ -606,7 +608,8 @@ tty_cmd_insertline(struct tty *tty, const struct tty_ctx *ctx) struct screen *s = wp->screen; if (wp->xoff != 0 || screen_size_x(s) < tty->sx || - !tty_term_has(tty->term, TTYC_CSR)) { + !tty_term_has(tty->term, TTYC_CSR) || + !tty_term_has(tty->term, TTYC_IL1)) { tty_redraw_region(tty, ctx); return; } @@ -626,7 +629,8 @@ tty_cmd_deleteline(struct tty *tty, const struct tty_ctx *ctx) struct screen *s = wp->screen; if (wp->xoff != 0 || screen_size_x(s) < tty->sx || - !tty_term_has(tty->term, TTYC_CSR)) { + !tty_term_has(tty->term, TTYC_CSR) || + !tty_term_has(tty->term, TTYC_DL1)) { tty_redraw_region(tty, ctx); return; } From 9c0147915e3724af59f718ef11936ad319c54c54 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 26 Nov 2009 15:14:03 +0000 Subject: [PATCH 0564/1180] Handle the possibility of partial mouse reads, and fix a comment while here. --- tty-keys.c | 45 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/tty-keys.c b/tty-keys.c index 03797994..d44583c4 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -418,7 +418,7 @@ tty_keys_find1(struct tty_key *tk, const char *buf, size_t len, size_t *size) /* * Process at least one key in the buffer and invoke tty->key_callback. Return - * 1 if there are no further keys, or 0 if there is more in the buffer. + * 0 if there are no further keys, or 1 if there could be more in the buffer. */ int tty_keys_next(struct tty *tty) @@ -461,12 +461,19 @@ tty_keys_next(struct tty *tty) } /* Not found. Is this a mouse key press? */ - key = tty_keys_mouse(buf, len, &size, &mouse); - if (key != KEYC_NONE) { + switch (tty_keys_mouse(buf, len, &size, &mouse)) { + case 0: /* yes */ evbuffer_drain(tty->event->input, size); + key = KEYC_MOUSE; goto handle_key; + case -1: /* no, or not valid */ + evbuffer_drain(tty->event->input, size); + return (1); + case 1: /* partial */ + goto partial_key; } + /* Not found. Try to parse a key with an xterm-style modifier. */ key = xterm_keys_find(buf, len, &size); if (key != KEYC_NONE) { @@ -560,7 +567,10 @@ tty_keys_callback(unused int fd, unused short events, void *data) ; } -/* Handle mouse key input. */ +/* + * Handle mouse key input. Returns 0 for success, -1 for failure, 1 for partial + * (probably a mouse sequence but need more data). + */ int tty_keys_mouse(const char *buf, size_t len, size_t *size, struct mouse_event *m) { @@ -569,19 +579,36 @@ tty_keys_mouse(const char *buf, size_t len, size_t *size, struct mouse_event *m) * buttons, X and Y, all based at 32 with 1,1 top-left. */ - if (len != 6 || memcmp(buf, "\033[M", 3) != 0) - return (KEYC_NONE); + *size = 0; + + if (buf[0] != '\033') + return (-1); + if (len == 1) + return (1); + + if (buf[1] != '[') + return (-1); + if (len == 2) + return (1); + + if (buf[2] != 'M') + return (-1); + if (len == 3) + return (1); + + if (len < 6) + return (1); *size = 6; - log_debug("mouse input is: %.*s", (int) len, buf); + log_debug("mouse input is: %.6s", buf); m->b = buf[3]; m->x = buf[4]; m->y = buf[5]; if (m->b < 32 || m->x < 33 || m->y < 33) - return (KEYC_NONE); + return (-1); m->b -= 32; m->x -= 33; m->y -= 33; - return (KEYC_MOUSE); + return (0); } From 3e147967e2197accb2549c6b57ffb392030616d8 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 26 Nov 2009 21:14:30 +0000 Subject: [PATCH 0565/1180] Get a u_char from the string, otherwise it isn't possible to enter \0377 as it is mistaken for EOF (doh). Also drop an unused argument. --- cmd-string.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/cmd-string.c b/cmd-string.c index 9cb48466..8e2ec1bf 100644 --- a/cmd-string.c +++ b/cmd-string.c @@ -32,7 +32,7 @@ */ int cmd_string_getc(const char *, size_t *); -void cmd_string_ungetc(const char *, size_t *); +void cmd_string_ungetc(size_t *); char *cmd_string_string(const char *, size_t *, char, int); char *cmd_string_variable(const char *, size_t *); char *cmd_string_expand_tilde(const char *, size_t *); @@ -40,13 +40,15 @@ char *cmd_string_expand_tilde(const char *, size_t *); int cmd_string_getc(const char *s, size_t *p) { - if (s[*p] == '\0') + const u_char *ucs = s; + + if (ucs[*p] == '\0') return (EOF); - return (s[(*p)++]); + return (ucs[(*p)++]); } void -cmd_string_ungetc(unused const char *s, size_t *p) +cmd_string_ungetc(size_t *p) { (*p)--; } @@ -306,7 +308,7 @@ cmd_string_variable(const char *s, size_t *p) if (fch == '{' && ch != '}') goto error; if (ch != EOF && fch != '{') - cmd_string_ungetc(s, p); /* ch */ + cmd_string_ungetc(p); /* ch */ buf = xrealloc(buf, 1, len + 1); buf[len] = '\0'; @@ -337,7 +339,7 @@ cmd_string_expand_tilde(const char *s, size_t *p) home = pw->pw_dir; } } else { - cmd_string_ungetc(s, p); + cmd_string_ungetc(p); if ((username = cmd_string_string(s, p, '/', 0)) == NULL) return (NULL); if ((pw = getpwnam(username)) != NULL) From 621dabd44e36c4bfdcd56e9e9730a9e10677e2bd Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 26 Nov 2009 21:22:31 +0000 Subject: [PATCH 0566/1180] Rename a variable to something more helpful. --- attributes.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/attributes.c b/attributes.c index 36b34ff1..0e42c787 100644 --- a/attributes.c +++ b/attributes.c @@ -23,29 +23,29 @@ #include "tmux.h" const char * -attributes_tostring(u_char ch) +attributes_tostring(u_char attr) { static char buf[128]; - if (ch == 0) + if (attr == 0) return ("default"); buf[0] = '\0'; - if (ch & GRID_ATTR_BRIGHT) + if (attr & GRID_ATTR_BRIGHT) strlcat(buf, "bright,", sizeof (buf)); - if (ch & GRID_ATTR_DIM) + if (attr & GRID_ATTR_DIM) strlcat(buf, "dim,", sizeof (buf)); - if (ch & GRID_ATTR_UNDERSCORE) + if (attr & GRID_ATTR_UNDERSCORE) strlcat(buf, "underscore,", sizeof (buf)); - if (ch & GRID_ATTR_BLINK) + if (attr & GRID_ATTR_BLINK) strlcat(buf, "blink,", sizeof (buf)); - if (ch & GRID_ATTR_REVERSE) + if (attr & GRID_ATTR_REVERSE) strlcat(buf, "reverse,", sizeof (buf)); - if (ch & GRID_ATTR_HIDDEN) + if (attr & GRID_ATTR_HIDDEN) strlcat(buf, "hidden,", sizeof (buf)); - if (ch & GRID_ATTR_ITALICS) + if (attr & GRID_ATTR_ITALICS) strlcat(buf, "italics,", sizeof (buf)); - if (*buf) + if (*buf != '\0') *(strrchr(buf, ',')) = '\0'; return (buf); @@ -55,7 +55,7 @@ int attributes_fromstring(const char *str) { const char delimiters[] = " ,|"; - u_char ch; + u_char attr; size_t end; if (*str == '\0' || strcspn(str, delimiters) == 0) @@ -66,28 +66,28 @@ attributes_fromstring(const char *str) if (strcasecmp(str, "default") == 0) return (0); - ch = 0; + attr = 0; do { end = strcspn(str, delimiters); if ((end == 6 && strncasecmp(str, "bright", end) == 0) || (end == 4 && strncasecmp(str, "bold", end) == 0)) - ch |= GRID_ATTR_BRIGHT; + attr |= GRID_ATTR_BRIGHT; else if (end == 3 && strncasecmp(str, "dim", end) == 0) - ch |= GRID_ATTR_DIM; + attr |= GRID_ATTR_DIM; else if (end == 10 && strncasecmp(str, "underscore", end) == 0) - ch |= GRID_ATTR_UNDERSCORE; + attr |= GRID_ATTR_UNDERSCORE; else if (end == 5 && strncasecmp(str, "blink", end) == 0) - ch |= GRID_ATTR_BLINK; + attr |= GRID_ATTR_BLINK; else if (end == 7 && strncasecmp(str, "reverse", end) == 0) - ch |= GRID_ATTR_REVERSE; + attr |= GRID_ATTR_REVERSE; else if (end == 6 && strncasecmp(str, "hidden", end) == 0) - ch |= GRID_ATTR_HIDDEN; + attr |= GRID_ATTR_HIDDEN; else if (end == 7 && strncasecmp(str, "italics", end) == 0) - ch |= GRID_ATTR_ITALICS; + attr |= GRID_ATTR_ITALICS; else return (-1); str += end + strspn(str + end, delimiters); } while (*str != '\0'); - return (ch); + return (attr); } From 4ca857e0e922d0afeb7896ff62e9f47c0c36c535 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 26 Nov 2009 21:37:13 +0000 Subject: [PATCH 0567/1180] Remove a couple of unused arguments where possible, and add /* ARGSUSED */ to the rest to reduce lint output. --- cfg.c | 2 ++ client.c | 2 ++ cmd-copy-buffer.c | 1 + cmd-generic.c | 3 +++ cmd-kill-server.c | 1 + cmd-list-clients.c | 1 + cmd-list-commands.c | 1 + cmd-list-sessions.c | 1 + cmd-lock-server.c | 1 + cmd-new-session.c | 1 + cmd-new-window.c | 1 + cmd-pipe-pane.c | 1 + cmd-server-info.c | 1 + cmd-source-file.c | 1 + cmd-start-server.c | 1 + job.c | 1 + names.c | 1 + screen-write.c | 1 + server-client.c | 1 + server-fn.c | 1 + server.c | 3 +++ session.c | 8 ++++---- status.c | 1 + tmux.c | 2 ++ tmux.h | 4 ++-- tty-keys.c | 1 + tty.c | 8 +++++--- window-choose.c | 2 ++ window-clock.c | 1 + window-copy.c | 1 + window-more.c | 1 + window.c | 6 ++++-- 32 files changed, 51 insertions(+), 11 deletions(-) diff --git a/cfg.c b/cfg.c index 5f314b7b..05588336 100644 --- a/cfg.c +++ b/cfg.c @@ -35,11 +35,13 @@ void printflike2 cfg_error(struct cmd_ctx *, const char *, ...); char *cfg_cause; +/* ARGSUSED */ void printflike2 cfg_print(unused struct cmd_ctx *ctx, unused const char *fmt, ...) { } +/* ARGSUSED */ void printflike2 cfg_error(unused struct cmd_ctx *ctx, const char *fmt, ...) { diff --git a/client.c b/client.c index 6f054732..91c2f6c5 100644 --- a/client.c +++ b/client.c @@ -222,6 +222,7 @@ out: exit(client_exitval); } +/* ARGSUSED */ void client_signal(int sig, unused short events, unused void *data) { @@ -250,6 +251,7 @@ client_signal(int sig, unused short events, unused void *data) client_update_event(); } +/* ARGSUSED */ void client_callback(unused int fd, short events, unused void *data) { diff --git a/cmd-copy-buffer.c b/cmd-copy-buffer.c index 3a6a441e..5f407e0c 100644 --- a/cmd-copy-buffer.c +++ b/cmd-copy-buffer.c @@ -51,6 +51,7 @@ const struct cmd_entry cmd_copy_buffer_entry = { cmd_copy_buffer_print }; +/* ARGSUSED */ void cmd_copy_buffer_init(struct cmd *self, unused int arg) { diff --git a/cmd-generic.c b/cmd-generic.c index 5232bc98..9961c19f 100644 --- a/cmd-generic.c +++ b/cmd-generic.c @@ -148,6 +148,7 @@ cmd_fill_argument(int flags, char **arg, char **arg2, int argc, char **argv) return (0); } +/* ARGSUSED */ void cmd_target_init(struct cmd *self, unused int key) { @@ -231,6 +232,7 @@ cmd_target_print(struct cmd *self, char *buf, size_t len) return (off); } +/* ARGSUSED */ void cmd_srcdst_init(struct cmd *self, unused int key) { @@ -322,6 +324,7 @@ cmd_srcdst_print(struct cmd *self, char *buf, size_t len) return (off); } +/* ARGSUSED */ void cmd_buffer_init(struct cmd *self, unused int key) { diff --git a/cmd-kill-server.c b/cmd-kill-server.c index cf206770..9e6ddb21 100644 --- a/cmd-kill-server.c +++ b/cmd-kill-server.c @@ -40,6 +40,7 @@ const struct cmd_entry cmd_kill_server_entry = { NULL }; +/* ARGSUSED */ int cmd_kill_server_exec(unused struct cmd *self, unused struct cmd_ctx *ctx) { diff --git a/cmd-list-clients.c b/cmd-list-clients.c index 4b7bc7b7..9c941b45 100644 --- a/cmd-list-clients.c +++ b/cmd-list-clients.c @@ -40,6 +40,7 @@ const struct cmd_entry cmd_list_clients_entry = { NULL }; +/* ARGSUSED */ int cmd_list_clients_exec(unused struct cmd *self, struct cmd_ctx *ctx) { diff --git a/cmd-list-commands.c b/cmd-list-commands.c index 9b669b67..a5c98ea7 100644 --- a/cmd-list-commands.c +++ b/cmd-list-commands.c @@ -37,6 +37,7 @@ const struct cmd_entry cmd_list_commands_entry = { NULL }; +/* ARGSUSED */ int cmd_list_commands_exec(unused struct cmd *self, struct cmd_ctx *ctx) { diff --git a/cmd-list-sessions.c b/cmd-list-sessions.c index d0210552..774c599b 100644 --- a/cmd-list-sessions.c +++ b/cmd-list-sessions.c @@ -39,6 +39,7 @@ const struct cmd_entry cmd_list_sessions_entry = { NULL }; +/* ARGSUSED */ int cmd_list_sessions_exec(unused struct cmd *self, struct cmd_ctx *ctx) { diff --git a/cmd-lock-server.c b/cmd-lock-server.c index 1d8f80e4..b588e2b2 100644 --- a/cmd-lock-server.c +++ b/cmd-lock-server.c @@ -41,6 +41,7 @@ const struct cmd_entry cmd_lock_server_entry = { NULL, }; +/* ARGSUSED */ int cmd_lock_server_exec(unused struct cmd *self, unused struct cmd_ctx *ctx) { diff --git a/cmd-new-session.c b/cmd-new-session.c index 8103392d..25a054bc 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -52,6 +52,7 @@ const struct cmd_entry cmd_new_session_entry = { cmd_new_session_print }; +/* ARGSUSED */ void cmd_new_session_init(struct cmd *self, unused int arg) { diff --git a/cmd-new-window.c b/cmd-new-window.c index e251c8cb..4cba8883 100644 --- a/cmd-new-window.c +++ b/cmd-new-window.c @@ -51,6 +51,7 @@ const struct cmd_entry cmd_new_window_entry = { cmd_new_window_print }; +/* ARGSUSED */ void cmd_new_window_init(struct cmd *self, unused int arg) { diff --git a/cmd-pipe-pane.c b/cmd-pipe-pane.c index 135d3837..a88d7ea8 100644 --- a/cmd-pipe-pane.c +++ b/cmd-pipe-pane.c @@ -129,6 +129,7 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx) } } +/* ARGSUSED */ void cmd_pipe_pane_error_callback( unused struct bufferevent *bufev, unused short what, void *data) diff --git a/cmd-server-info.c b/cmd-server-info.c index 03cd2e95..f0728608 100644 --- a/cmd-server-info.c +++ b/cmd-server-info.c @@ -44,6 +44,7 @@ const struct cmd_entry cmd_server_info_entry = { NULL }; +/* ARGSUSED */ int cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx) { diff --git a/cmd-source-file.c b/cmd-source-file.c index a53a1cb8..f9ca9993 100644 --- a/cmd-source-file.c +++ b/cmd-source-file.c @@ -45,6 +45,7 @@ const struct cmd_entry cmd_source_file_entry = { cmd_source_file_print }; +/* ARGSUSED */ void cmd_source_file_init(struct cmd *self, unused int arg) { diff --git a/cmd-start-server.c b/cmd-start-server.c index 382ae48d..b93c9e6c 100644 --- a/cmd-start-server.c +++ b/cmd-start-server.c @@ -37,6 +37,7 @@ const struct cmd_entry cmd_start_server_entry = { NULL }; +/* ARGSUSED */ int cmd_start_server_exec(unused struct cmd *self, unused struct cmd_ctx *ctx) { diff --git a/job.c b/job.c index d779057d..ba8f33f0 100644 --- a/job.c +++ b/job.c @@ -192,6 +192,7 @@ job_run(struct job *job) } /* Job buffer error callback. */ +/* ARGSUSED */ void job_callback(unused struct bufferevent *bufev, unused short events, void *data) { diff --git a/names.c b/names.c index d9335ac5..a468b59b 100644 --- a/names.c +++ b/names.c @@ -41,6 +41,7 @@ queue_window_name(struct window *w) evtimer_add(&w->name_timer, &tv); } +/* ARGSUSED */ void window_name_callback(unused int fd, unused short events, void *data) { diff --git a/screen-write.c b/screen-write.c index 8afffa4b..93c239a6 100644 --- a/screen-write.c +++ b/screen-write.c @@ -40,6 +40,7 @@ screen_write_start( } /* Finish writing. */ +/* ARGSUSED */ void screen_write_stop(unused struct screen_write_ctx *ctx) { diff --git a/server-client.c b/server-client.c index e6560931..e0fcfd04 100644 --- a/server-client.c +++ b/server-client.c @@ -427,6 +427,7 @@ server_client_reset_state(struct client *c) } /* Repeat time callback. */ +/* ARGSUSED */ void server_client_repeat_timer(unused int fd, unused short events, void *data) { diff --git a/server-fn.c b/server-fn.c index ae1340e7..90cf9ae1 100644 --- a/server-fn.c +++ b/server-fn.c @@ -396,6 +396,7 @@ server_clear_identify(struct client *c) } } +/* ARGSUSED */ void server_callback_identify(unused int fd, unused short events, void *data) { diff --git a/server.c b/server.c index afb5f6e9..b3979596 100644 --- a/server.c +++ b/server.c @@ -314,6 +314,7 @@ server_update_socket(void) } /* Callback for server socket. */ +/* ARGSUSED */ void server_accept_callback(int fd, short events, unused void *data) { @@ -389,6 +390,7 @@ server_signal_clear(void) } /* Signal handler. */ +/* ARGSUSED */ void server_signal_callback(int sig, unused short events, unused void *data) { @@ -486,6 +488,7 @@ server_child_stopped(pid_t pid, int status) } /* Handle once-per-second timer events. */ +/* ARGSUSED */ void server_second_callback(unused int fd, unused short events, unused void *arg) { diff --git a/session.c b/session.c index db2eb779..116969be 100644 --- a/session.c +++ b/session.c @@ -319,7 +319,7 @@ session_next_activity(struct session *s, struct winlink *wl) break; if (session_alert_has(s, wl, WINDOW_CONTENT)) break; - wl = winlink_next(&s->windows, wl); + wl = winlink_next(wl); } return (wl); } @@ -333,7 +333,7 @@ session_next(struct session *s, int activity) if (s->curw == NULL) return (-1); - wl = winlink_next(&s->windows, s->curw); + wl = winlink_next(s->curw); if (activity) wl = session_next_activity(s, wl); if (wl == NULL) { @@ -360,7 +360,7 @@ session_previous_activity(struct session *s, struct winlink *wl) break; if (session_alert_has(s, wl, WINDOW_CONTENT)) break; - wl = winlink_previous(&s->windows, wl); + wl = winlink_previous(wl); } return (wl); } @@ -374,7 +374,7 @@ session_previous(struct session *s, int activity) if (s->curw == NULL) return (-1); - wl = winlink_previous(&s->windows, s->curw); + wl = winlink_previous(s->curw); if (activity) wl = session_previous_activity(s, wl); if (wl == NULL) { diff --git a/status.c b/status.c index 4236d54b..3ab7a90e 100644 --- a/status.c +++ b/status.c @@ -688,6 +688,7 @@ status_message_clear(struct client *c) } /* Clear status line message after timer expires. */ +/* ARGSUSED */ void status_message_callback(unused int fd, unused short event, void *data) { diff --git a/tmux.c b/tmux.c index f339b729..1a77c832 100644 --- a/tmux.c +++ b/tmux.c @@ -554,6 +554,7 @@ main_clear_signals(void) event_del(&main_ev_sigterm); } +/* ARGSUSED */ void main_signal(int sig, unused short events, unused void *data) { @@ -563,6 +564,7 @@ main_signal(int sig, unused short events, unused void *data) } } +/* ARGSUSED */ void main_callback(unused int fd, short events, void *data) { diff --git a/tmux.h b/tmux.h index 61921ae2..90943516 100644 --- a/tmux.h +++ b/tmux.h @@ -1790,8 +1790,8 @@ int winlink_next_index(struct winlinks *, int); u_int winlink_count(struct winlinks *); struct winlink *winlink_add(struct winlinks *, struct window *, int); void winlink_remove(struct winlinks *, struct winlink *); -struct winlink *winlink_next(struct winlinks *, struct winlink *); -struct winlink *winlink_previous(struct winlinks *, struct winlink *); +struct winlink *winlink_next(struct winlink *); +struct winlink *winlink_previous(struct winlink *); void winlink_stack_push(struct winlink_stack *, struct winlink *); void winlink_stack_remove(struct winlink_stack *, struct winlink *); int window_index(struct window *, u_int *); diff --git a/tty-keys.c b/tty-keys.c index d44583c4..a64c29b0 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -555,6 +555,7 @@ handle_key: } /* Key timer callback. */ +/* ARGSUSED */ void tty_keys_callback(unused int fd, unused short events, void *data) { diff --git a/tty.c b/tty.c index 84931e78..999c3919 100644 --- a/tty.c +++ b/tty.c @@ -38,7 +38,7 @@ int tty_try_88(struct tty *, u_char, const char *); void tty_colours(struct tty *, const struct grid_cell *, int *); void tty_colours_fg(struct tty *, const struct grid_cell *, int *); -void tty_colours_bg(struct tty *, const struct grid_cell *, int *); +void tty_colours_bg(struct tty *, const struct grid_cell *); void tty_redraw_region(struct tty *, const struct tty_ctx *); void tty_emulate_repeat( @@ -125,6 +125,7 @@ tty_open(struct tty *tty, const char *overrides, char **cause) return (0); } +/* ARGSUSED */ void tty_read_callback(unused struct bufferevent *bufev, void *data) { @@ -134,6 +135,7 @@ tty_read_callback(unused struct bufferevent *bufev, void *data) ; } +/* ARGSUSED */ void tty_error_callback( unused struct bufferevent *bufev, unused short what, unused void *data) @@ -1278,7 +1280,7 @@ tty_colours(struct tty *tty, const struct grid_cell *gc, int *attr) */ if (!bg_default && (bg != tc->bg || ((flags & GRID_FLAG_BG256) != (tc->flags & GRID_FLAG_BG256)))) - tty_colours_bg(tty, gc, attr); + tty_colours_bg(tty, gc); } void @@ -1315,7 +1317,7 @@ save_fg: } void -tty_colours_bg(struct tty *tty, const struct grid_cell *gc, unused int *attr) +tty_colours_bg(struct tty *tty, const struct grid_cell *gc) { struct grid_cell *tc = &tty->cell; u_char bg = gc->bg; diff --git a/window-choose.c b/window-choose.c index a0f66b81..fc012d9e 100644 --- a/window-choose.c +++ b/window-choose.c @@ -169,6 +169,7 @@ window_choose_resize(struct window_pane *wp, u_int sx, u_int sy) window_choose_redraw_screen(wp); } +/* ARGSUSED */ void window_choose_key(struct window_pane *wp, unused struct client *c, int key) { @@ -275,6 +276,7 @@ window_choose_key(struct window_pane *wp, unused struct client *c, int key) } } +/* ARGSUSED */ void window_choose_mouse( struct window_pane *wp, unused struct client *c, struct mouse_event *m) diff --git a/window-clock.c b/window-clock.c index 49239180..d45d6cdd 100644 --- a/window-clock.c +++ b/window-clock.c @@ -82,6 +82,7 @@ window_clock_resize(struct window_pane *wp, u_int sx, u_int sy) window_clock_draw_screen(wp); } +/* ARGSUSED */ void window_clock_key( struct window_pane *wp, unused struct client *c, unused int key) diff --git a/window-copy.c b/window-copy.c index dba57256..ec1d8e4a 100644 --- a/window-copy.c +++ b/window-copy.c @@ -435,6 +435,7 @@ window_copy_key_input(struct window_pane *wp, int key) return (0); } +/* ARGSUSED */ void window_copy_mouse( struct window_pane *wp, unused struct client *c, struct mouse_event *m) diff --git a/window-more.c b/window-more.c index 94a08f1e..ec705795 100644 --- a/window-more.c +++ b/window-more.c @@ -123,6 +123,7 @@ window_more_resize(struct window_pane *wp, u_int sx, u_int sy) window_more_redraw_screen(wp); } +/* ARGSUSED */ void window_more_key(struct window_pane *wp, unused struct client *c, int key) { diff --git a/window.c b/window.c index be61e73c..3b7702fd 100644 --- a/window.c +++ b/window.c @@ -161,13 +161,13 @@ winlink_remove(struct winlinks *wwl, struct winlink *wl) } struct winlink * -winlink_next(unused struct winlinks *wwl, struct winlink *wl) +winlink_next(struct winlink *wl) { return (RB_NEXT(winlinks, wwl, wl)); } struct winlink * -winlink_previous(unused struct winlinks *wwl, struct winlink *wl) +winlink_previous(struct winlink *wl) { return (RB_PREV(winlinks, wwl, wl)); } @@ -582,6 +582,7 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell, return (0); } +/* ARGSUSED */ void window_pane_read_callback(unused struct bufferevent *bufev, void *data) { @@ -590,6 +591,7 @@ window_pane_read_callback(unused struct bufferevent *bufev, void *data) window_pane_parse(wp); } +/* ARGSUSED */ void window_pane_error_callback( unused struct bufferevent *bufev, unused short what, void *data) From ba5404d93e40e61176ffb150b66ddc3b349603a7 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 26 Nov 2009 22:26:51 +0000 Subject: [PATCH 0568/1180] Continue rather than returning if not a mouse key, to avoid hanging on any function key... --- tty-keys.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tty-keys.c b/tty-keys.c index a64c29b0..8f90b6ec 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -467,8 +467,7 @@ tty_keys_next(struct tty *tty) key = KEYC_MOUSE; goto handle_key; case -1: /* no, or not valid */ - evbuffer_drain(tty->event->input, size); - return (1); + break; case 1: /* partial */ goto partial_key; } From 8cb410c63cbec58dc736e160ffe88a67af46e4c9 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 26 Nov 2009 22:28:24 +0000 Subject: [PATCH 0569/1180] Tidy up various bits of the paste code, make the data buffer char * and add comments. --- cmd-list-buffers.c | 2 +- cmd-load-buffer.c | 35 +++++++++++++++++++++-------------- cmd-paste-buffer.c | 2 +- cmd-set-buffer.c | 2 +- paste.c | 28 +++++++++++++++++++++++++--- status.c | 4 +++- tmux.h | 6 +++--- 7 files changed, 55 insertions(+), 24 deletions(-) diff --git a/cmd-list-buffers.c b/cmd-list-buffers.c index ab08928e..30235295 100644 --- a/cmd-list-buffers.c +++ b/cmd-list-buffers.c @@ -64,7 +64,7 @@ cmd_list_buffers_exec(struct cmd *self, struct cmd_ctx *ctx) strvisx(tmp, pb->data, len, VIS_OCTAL|VIS_TAB|VIS_NL); /* - * If the first 50 characterswere encoded as a longer string, + * If the first 50 characters were encoded as a longer string, * or there is definitely more data, add "...". */ if (size > 50 || strlen(tmp) > 50) { diff --git a/cmd-load-buffer.c b/cmd-load-buffer.c index 354aa463..944c1237 100644 --- a/cmd-load-buffer.c +++ b/cmd-load-buffer.c @@ -50,7 +50,8 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) struct session *s; struct stat sb; FILE *f; - u_char *buf; + char *pdata = NULL; + size_t psize; u_int limit; if ((s = cmd_find_session(ctx, data->target)) == NULL) @@ -63,39 +64,45 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) if (fstat(fileno(f), &sb) < 0) { ctx->error(ctx, "%s: %s", data->arg, strerror(errno)); - fclose(f); - return (-1); + goto error; } + if (sb.st_size > SIZE_MAX) { + ctx->error(ctx, "%s: file too large", data->arg); + goto error; + } + psize = (size_t) sb.st_size; /* * We don't want to die due to memory exhaustion, hence xmalloc can't * be used here. */ - if ((buf = malloc(sb.st_size + 1)) == NULL) { + if ((pdata = malloc(psize)) == NULL) { ctx->error(ctx, "malloc error: %s", strerror(errno)); - fclose(f); - return (-1); + goto error; } - if (fread(buf, 1, sb.st_size, f) != (size_t) sb.st_size) { + if (fread(pdata, 1, psize, f) != psize) { ctx->error(ctx, "%s: fread error", data->arg); - xfree(buf); - fclose(f); - return (-1); + goto error; } fclose(f); limit = options_get_number(&s->options, "buffer-limit"); if (data->buffer == -1) { - paste_add(&s->buffers, buf, sb.st_size, limit); + paste_add(&s->buffers, pdata, psize, limit); return (0); } - if (paste_replace(&s->buffers, data->buffer, buf, sb.st_size) != 0) { + if (paste_replace(&s->buffers, data->buffer, pdata, psize) != 0) { ctx->error(ctx, "no buffer %d", data->buffer); - xfree(buf); - return (-1); + goto error; } return (0); + +error: + if (pdata != NULL) + xfree(pdata); + fclose(f); + return (-1); } diff --git a/cmd-paste-buffer.c b/cmd-paste-buffer.c index 11f70f1f..7d13ae0a 100644 --- a/cmd-paste-buffer.c +++ b/cmd-paste-buffer.c @@ -62,7 +62,7 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) } } - if (pb != NULL && *pb->data != '\0') { + if (pb != NULL) { /* -r means raw data without LF->CR conversion. */ if (cmd_check_flag(data->chflags, 'r')) bufferevent_write(wp->event, pb->data, pb->size); diff --git a/cmd-set-buffer.c b/cmd-set-buffer.c index 4e50cc7a..a93a0adf 100644 --- a/cmd-set-buffer.c +++ b/cmd-set-buffer.c @@ -45,7 +45,7 @@ cmd_set_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) struct cmd_buffer_data *data = self->data; struct session *s; u_int limit; - u_char *pdata; + char *pdata; size_t psize; if ((s = cmd_find_session(ctx, data->target)) == NULL) diff --git a/paste.c b/paste.c index 142e46cf..81dad57f 100644 --- a/paste.c +++ b/paste.c @@ -23,6 +23,11 @@ #include "tmux.h" +/* + * Stack of paste buffers. Note that paste buffer data is not necessarily a C + * string! + */ + void paste_init_stack(struct paste_stack *ps) { @@ -36,6 +41,7 @@ paste_free_stack(struct paste_stack *ps) ; } +/* Return each item of the stack in turn. */ struct paste_buffer * paste_walk_stack(struct paste_stack *ps, uint *idx) { @@ -46,6 +52,7 @@ paste_walk_stack(struct paste_stack *ps, uint *idx) return (pb); } +/* Get the top item on the stack. */ struct paste_buffer * paste_get_top(struct paste_stack *ps) { @@ -54,6 +61,7 @@ paste_get_top(struct paste_stack *ps) return (ARRAY_FIRST(ps)); } +/* Get an item by its index. */ struct paste_buffer * paste_get_index(struct paste_stack *ps, u_int idx) { @@ -62,6 +70,7 @@ paste_get_index(struct paste_stack *ps, u_int idx) return (ARRAY_ITEM(ps, idx)); } +/* Free the top item on the stack. */ int paste_free_top(struct paste_stack *ps) { @@ -79,6 +88,7 @@ paste_free_top(struct paste_stack *ps) return (0); } +/* Free an item by index. */ int paste_free_index(struct paste_stack *ps, u_int idx) { @@ -96,12 +106,16 @@ paste_free_index(struct paste_stack *ps, u_int idx) return (0); } +/* + * Add an item onto the top of the stack, freeing the bottom if at limit. Note + * that the caller is responsible for allocating data. + */ void -paste_add(struct paste_stack *ps, u_char *data, size_t size, u_int limit) +paste_add(struct paste_stack *ps, char *data, size_t size, u_int limit) { struct paste_buffer *pb; - if (*data == '\0') + if (size == 0) return; while (ARRAY_LENGTH(ps) >= limit) { @@ -118,11 +132,19 @@ paste_add(struct paste_stack *ps, u_char *data, size_t size, u_int limit) pb->size = size; } + +/* + * Replace an item on the stack. Note that the caller is responsible for + * allocating data. + */ int -paste_replace(struct paste_stack *ps, u_int idx, u_char *data, size_t size) +paste_replace(struct paste_stack *ps, u_int idx, char *data, size_t size) { struct paste_buffer *pb; + if (size == 0) + return (0); + if (idx >= ARRAY_LENGTH(ps)) return (-1); diff --git a/status.c b/status.c index 3ab7a90e..fa452d53 100644 --- a/status.c +++ b/status.c @@ -882,6 +882,7 @@ status_prompt_key(struct client *c, int key) { struct paste_buffer *pb; char *s, *first, *last, word[64], swapc; + u_char ch; size_t size, n, off, idx; size = strlen(c->prompt_buffer); @@ -1023,7 +1024,8 @@ status_prompt_key(struct client *c, int key) if ((pb = paste_get_top(&c->session->buffers)) == NULL) break; for (n = 0; n < pb->size; n++) { - if (pb->data[n] < 32 || pb->data[n] == 127) + ch = (u_char) pb->data[n]; + if (ch < 32 || ch == 127) break; } diff --git a/tmux.h b/tmux.h index 90943516..d99972c1 100644 --- a/tmux.h +++ b/tmux.h @@ -884,7 +884,7 @@ struct layout_cell { /* Paste buffer. */ struct paste_buffer { - char *data; + char *data; size_t size; }; ARRAY_DECL(paste_stack, struct paste_buffer *); @@ -1403,8 +1403,8 @@ struct paste_buffer *paste_get_top(struct paste_stack *); struct paste_buffer *paste_get_index(struct paste_stack *, u_int); int paste_free_top(struct paste_stack *); int paste_free_index(struct paste_stack *, u_int); -void paste_add(struct paste_stack *, u_char *, size_t, u_int); -int paste_replace(struct paste_stack *, u_int, u_char *, size_t); +void paste_add(struct paste_stack *, char *, size_t, u_int); +int paste_replace(struct paste_stack *, u_int, char *, size_t); /* clock.c */ extern const char clock_table[14][5][5]; From c2eb869f7276ad3832d3111542a859f3e96772b2 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 26 Nov 2009 22:32:00 +0000 Subject: [PATCH 0570/1180] Change paranoia check to check for <= 0 and to avoid warning. --- cmd-load-buffer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd-load-buffer.c b/cmd-load-buffer.c index 944c1237..b6386b83 100644 --- a/cmd-load-buffer.c +++ b/cmd-load-buffer.c @@ -66,8 +66,8 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) ctx->error(ctx, "%s: %s", data->arg, strerror(errno)); goto error; } - if (sb.st_size > SIZE_MAX) { - ctx->error(ctx, "%s: file too large", data->arg); + if (sb.st_size <= 0 || (uintmax_t) sb.st_size > SIZE_MAX) { + ctx->error(ctx, "%s: file empty or too large", data->arg); goto error; } psize = (size_t) sb.st_size; From e7f4319ac6c1341c0a31582693de54a02458a2b9 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 26 Nov 2009 22:47:14 +0000 Subject: [PATCH 0571/1180] Fix type - attributes should be u_char not int. --- tty.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/tty.c b/tty.c index 999c3919..1ed965ff 100644 --- a/tty.c +++ b/tty.c @@ -36,8 +36,8 @@ void tty_fill_acs(struct tty *); int tty_try_256(struct tty *, u_char, const char *); int tty_try_88(struct tty *, u_char, const char *); -void tty_colours(struct tty *, const struct grid_cell *, int *); -void tty_colours_fg(struct tty *, const struct grid_cell *, int *); +void tty_colours(struct tty *, const struct grid_cell *, u_char *); +void tty_colours_fg(struct tty *, const struct grid_cell *, u_char *); void tty_colours_bg(struct tty *, const struct grid_cell *); void tty_redraw_region(struct tty *, const struct tty_ctx *); @@ -1145,8 +1145,7 @@ void tty_attributes(struct tty *tty, const struct grid_cell *gc) { struct grid_cell *tc = &tty->cell, gc2; - u_char changed; - u_int new_attr; + u_char changed, new_attr; /* If the character is space, don't care about foreground. */ if (gc->data == ' ' && !(gc->flags & GRID_FLAG_UTF8)) { @@ -1217,7 +1216,7 @@ tty_attributes(struct tty *tty, const struct grid_cell *gc) } void -tty_colours(struct tty *tty, const struct grid_cell *gc, int *attr) +tty_colours(struct tty *tty, const struct grid_cell *gc, u_char *attr) { struct grid_cell *tc = &tty->cell; u_char fg = gc->fg, bg = gc->bg, flags = gc->flags; @@ -1284,7 +1283,7 @@ tty_colours(struct tty *tty, const struct grid_cell *gc, int *attr) } void -tty_colours_fg(struct tty *tty, const struct grid_cell *gc, int *attr) +tty_colours_fg(struct tty *tty, const struct grid_cell *gc, u_char *attr) { struct grid_cell *tc = &tty->cell; u_char fg = gc->fg; From 1acf066fb97226bf178177f2521b35eb08261d7e Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 26 Nov 2009 22:56:59 +0000 Subject: [PATCH 0572/1180] Make types clearer and lint happier. --- key-string.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/key-string.c b/key-string.c index 0c5c8269..857d31d6 100644 --- a/key-string.c +++ b/key-string.c @@ -105,12 +105,12 @@ int key_string_lookup_string(const char *string) { int key; - const u_char *ptr; + const char *ptr; if (string[0] == '\0') return (KEYC_NONE); if (string[1] == '\0') - return (string[0]); + return ((u_char) string[0]); ptr = NULL; if ((string[0] == 'C' || string[0] == 'c') && string[1] == '-') @@ -133,7 +133,7 @@ key_string_lookup_string(const char *string) } else { if (ptr[1] != '\0') return (KEYC_NONE); - key = ptr[0]; + key = (u_char) ptr[0]; } /* @@ -162,7 +162,7 @@ key_string_lookup_string(const char *string) } else { if (ptr[1] == '\0') return (KEYC_NONE); - key = ptr[0]; + key = (u_char) ptr[0]; } if (key >= 32 && key <= 127) @@ -209,7 +209,7 @@ key_string_lookup_key(int key) } if (key >= 32 && key <= 255) { - tmp[0] = key; + tmp[0] = (char) key; tmp[1] = '\0'; return (tmp); } From 106ee8f30a27d60aa4e113e17ba48792cfc64e50 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 26 Nov 2009 23:13:47 +0000 Subject: [PATCH 0573/1180] This doesn't need to be u_int. --- clock.c | 2 +- tmux.h | 2 +- window-clock.c | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/clock.c b/clock.c index 5711b441..b630cf84 100644 --- a/clock.c +++ b/clock.c @@ -97,7 +97,7 @@ const char clock_table[14][5][5] = { }; void -clock_draw(struct screen_write_ctx *ctx, u_int colour, int style) +clock_draw(struct screen_write_ctx *ctx, int colour, int style) { struct screen *s = ctx->s; struct grid_cell gc; diff --git a/tmux.h b/tmux.h index d99972c1..62f753da 100644 --- a/tmux.h +++ b/tmux.h @@ -1408,7 +1408,7 @@ int paste_replace(struct paste_stack *, u_int, char *, size_t); /* clock.c */ extern const char clock_table[14][5][5]; -void clock_draw(struct screen_write_ctx *, u_int, int); +void clock_draw(struct screen_write_ctx *, int, int); /* cmd.c */ int cmd_pack_argv(int, char **, char *, size_t); diff --git a/window-clock.c b/window-clock.c index d45d6cdd..27fe56cd 100644 --- a/window-clock.c +++ b/window-clock.c @@ -113,8 +113,7 @@ window_clock_draw_screen(struct window_pane *wp) { struct window_clock_mode_data *data = wp->modedata; struct screen_write_ctx ctx; - u_int colour; - int style; + int colour, style; colour = options_get_number(&wp->window->options, "clock-mode-colour"); style = options_get_number(&wp->window->options, "clock-mode-style"); From 2182e1badcc161c6e6f1ef6dec21a57cc510299e Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 27 Nov 2009 09:41:03 +0000 Subject: [PATCH 0574/1180] Add a couple of comments. --- input.c | 1 + tty.c | 1 + 2 files changed, 2 insertions(+) diff --git a/input.c b/input.c index b846e060..1f529df0 100644 --- a/input.c +++ b/input.c @@ -266,6 +266,7 @@ input_parse(struct window_pane *wp) ictx->wp = wp; + /* If there is a mode set, don't want to update the screen. */ if (wp->mode == NULL) screen_write_start(&ictx->ctx, wp, &wp->base); else diff --git a/tty.c b/tty.c index 1ed965ff..07b744cb 100644 --- a/tty.c +++ b/tty.c @@ -529,6 +529,7 @@ tty_write(void (*cmdfn)( struct client *c; u_int i; + /* wp can be NULL if updating the screen but not the terminal. */ if (wp == NULL) return; From 29a5931c6a352f12fe4bcc1cb72cb96e073ddca6 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 30 Nov 2009 16:44:03 +0000 Subject: [PATCH 0575/1180] Handle partial xterm function key sequences. --- tmux.h | 2 +- tty-keys.c | 9 ++++++--- xterm-keys.c | 37 +++++++++++++++++++++++++------------ 3 files changed, 32 insertions(+), 16 deletions(-) diff --git a/tmux.h b/tmux.h index 62f753da..e29bb015 100644 --- a/tmux.h +++ b/tmux.h @@ -1647,7 +1647,7 @@ void input_mouse(struct window_pane *, struct mouse_event *); /* xterm-keys.c */ char *xterm_keys_lookup(int); -int xterm_keys_find(const char *, size_t, size_t *); +int xterm_keys_find(const char *, size_t, size_t *, int *); /* colour.c */ void colour_set_fg(struct grid_cell *, int); diff --git a/tty-keys.c b/tty-keys.c index 8f90b6ec..1319e09f 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -472,12 +472,15 @@ tty_keys_next(struct tty *tty) goto partial_key; } - /* Not found. Try to parse a key with an xterm-style modifier. */ - key = xterm_keys_find(buf, len, &size); - if (key != KEYC_NONE) { + switch (xterm_keys_find(buf, len, &size, &key)) { + case 0: /* found */ evbuffer_drain(tty->event->input, size); goto handle_key; + case -1: /* not found */ + break; + case 1: + goto partial_key; } /* Skip the escape. */ diff --git a/xterm-keys.c b/xterm-keys.c index ca94a1f6..f0fbf802 100644 --- a/xterm-keys.c +++ b/xterm-keys.c @@ -85,22 +85,28 @@ struct xterm_keys_entry xterm_keys_table[] = { { KEYC_DC, "\033[3;_~" }, }; -/* Match key against buffer, treating _ as a wildcard. */ +/* + * Match key against buffer, treating _ as a wildcard. Return -1 for no match, + * 0 for match, 1 if the end of the buffer is reached (need more data). + */ int xterm_keys_match(const char *template, const char *buf, size_t len) { size_t pos; - if (len == 0 || len < strlen(template)) + if (len == 0) return (0); pos = 0; do { if (*template != '_' && buf[pos] != *template) - return (0); + return (-1); } while (pos++ != len && *++template != '\0'); - return (1); + if (*template != '\0') /* partial */ + return (1); + + return (0); } /* Find modifiers based on template. */ @@ -131,22 +137,29 @@ xterm_keys_modifiers(const char *template, const char *buf, size_t len) return (0); } -/* Lookup key from buffer against table. */ +/* + * Lookup key from a buffer against the table. Returns 0 for found (and the + * key), -1 for not found, 1 for partial match. + */ int -xterm_keys_find(const char *buf, size_t len, size_t *size) +xterm_keys_find(const char *buf, size_t len, size_t *size, int *key) { struct xterm_keys_entry *entry; u_int i; for (i = 0; i < nitems(xterm_keys_table); i++) { entry = &xterm_keys_table[i]; - if (xterm_keys_match(entry->template, buf, len)) - break; + switch (xterm_keys_match(entry->template, buf, len)) { + case 0: + *size = strlen(entry->template); + *key = entry->key; + *key |= xterm_keys_modifiers(entry->template, buf, len); + return (0); + case 1: + return (1); + } } - if (i == nitems(xterm_keys_table)) - return (KEYC_NONE); - *size = strlen(entry->template); - return (entry->key | xterm_keys_modifiers(entry->template, buf, len)); + return (-1); } /* Lookup a key number from the table. */ From f27fefd7b84633be67b7702c616ed398c87e8ec6 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 1 Dec 2009 07:59:40 +0000 Subject: [PATCH 0576/1180] Look for mice and xterm keys before standard function keys as they are less likely to be partial versions. --- tty-keys.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tty-keys.c b/tty-keys.c index 1319e09f..deb2b317 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -453,14 +453,7 @@ tty_keys_next(struct tty *tty) goto handle_key; } - /* Look for matching key string and return if found. */ - tk = tty_keys_find(tty, buf + 1, len - 1, &size); - if (tk != NULL) { - key = tk->key; - goto found_key; - } - - /* Not found. Is this a mouse key press? */ + /* Is this a mouse key press? */ switch (tty_keys_mouse(buf, len, &size, &mouse)) { case 0: /* yes */ evbuffer_drain(tty->event->input, size); @@ -472,7 +465,7 @@ tty_keys_next(struct tty *tty) goto partial_key; } - /* Not found. Try to parse a key with an xterm-style modifier. */ + /* Try to parse a key with an xterm-style modifier. */ switch (xterm_keys_find(buf, len, &size, &key)) { case 0: /* found */ evbuffer_drain(tty->event->input, size); @@ -483,6 +476,13 @@ tty_keys_next(struct tty *tty) goto partial_key; } + /* Look for matching key string and return if found. */ + tk = tty_keys_find(tty, buf + 1, len - 1, &size); + if (tk != NULL) { + key = tk->key; + goto found_key; + } + /* Skip the escape. */ buf++; len--; From 0926a2301443fad7280d1ed5ced73587faa815c8 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 1 Dec 2009 18:42:38 +0000 Subject: [PATCH 0577/1180] New command, capture-pane, which copies the entire pane contents to a paste buffer. From Jonathan Alvarado. --- Makefile | 2 +- cmd-capture-pane.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++ cmd.c | 1 + tmux.1 | 7 ++++ tmux.h | 1 + 5 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 cmd-capture-pane.c diff --git a/Makefile b/Makefile index b0caca92..b4b0ef56 100644 --- a/Makefile +++ b/Makefile @@ -29,7 +29,7 @@ SRCS= attributes.c cfg.c client.c clock.c \ cmd-switch-client.c cmd-unbind-key.c cmd-unlink-window.c \ cmd-set-environment.c cmd-show-environment.c cmd-choose-client.c \ cmd-up-pane.c cmd-display-message.c cmd-display-panes.c \ - cmd-pipe-pane.c cmd.c \ + cmd-pipe-pane.c cmd-capture-pane.c cmd.c \ colour.c environ.c grid-view.c grid-utf8.c grid.c input-keys.c \ imsg.c imsg-buffer.c input.c key-bindings.c key-string.c \ layout-set.c layout.c log.c job.c \ diff --git a/cmd-capture-pane.c b/cmd-capture-pane.c new file mode 100644 index 00000000..7444b90c --- /dev/null +++ b/cmd-capture-pane.c @@ -0,0 +1,81 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2009 Jonathan Alvarado + * + * 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 "tmux.h" + +/* + * Write the entire contents of a pane to a buffer. + */ + +int cmd_capture_pane_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_capture_pane_entry = { + "capture-pane", "capturep", + CMD_BUFFER_PANE_USAGE, + 0, "", + cmd_buffer_init, + cmd_buffer_parse, + cmd_capture_pane_exec, + cmd_buffer_free, + cmd_buffer_print +}; + +int +cmd_capture_pane_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_buffer_data *data = self->data; + struct window_pane *wp; + char *buf, *line; + struct screen *s; + struct session *sess; + u_int i, limit; + size_t len, linelen; + + if (cmd_find_pane(ctx, data->target, &sess, &wp) == NULL) + return (-1); + s = &wp->base; + + buf = NULL; + len = 0; + + for (i = 0; i < screen_size_y(s); i++) { + line = grid_view_string_cells(s->grid, 0, i, screen_size_x(s)); + linelen = strlen(line); + + buf = xrealloc(buf, 1, len + linelen + 1); + memcpy(buf + len, line, linelen); + len += linelen; + buf[len++] = '\n'; + } + + limit = options_get_number(&sess->options, "buffer-limit"); + if (data->buffer == -1) { + paste_add(&sess->buffers, buf, len, limit); + return (0); + } + if (paste_replace(&sess->buffers, data->buffer, buf, len) != 0) { + ctx->error(ctx, "no buffer %d", data->buffer); + xfree(buf); + return (-1); + } + return (0); +} diff --git a/cmd.c b/cmd.c index 902c390f..733f4013 100644 --- a/cmd.c +++ b/cmd.c @@ -31,6 +31,7 @@ const struct cmd_entry *cmd_table[] = { &cmd_attach_session_entry, &cmd_bind_key_entry, &cmd_break_pane_entry, + &cmd_capture_pane_entry, &cmd_choose_client_entry, &cmd_choose_session_entry, &cmd_choose_window_entry, diff --git a/tmux.1 b/tmux.1 index d3c61bd7..46734315 100644 --- a/tmux.1 +++ b/tmux.1 @@ -664,6 +664,13 @@ off from its containing window to make it the only pane in a new window. If .Fl d is given, the new window does not become the current window. +.It Xo Ic capture-pane +.Op Fl b Ar buffer-index +.Op Fl t Ar target-pane +.Xc +.D1 (alias: Ic capturep ) +Capture the contents of a pane to the specified buffer, or a new buffer if none +is specified. .It Xo .Ic choose-client .Op Fl t Ar target-window diff --git a/tmux.h b/tmux.h index e29bb015..59b3ec1f 100644 --- a/tmux.h +++ b/tmux.h @@ -1433,6 +1433,7 @@ 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; extern const struct cmd_entry cmd_break_pane_entry; +extern const struct cmd_entry cmd_capture_pane_entry; extern const struct cmd_entry cmd_choose_client_entry; extern const struct cmd_entry cmd_choose_session_entry; extern const struct cmd_entry cmd_choose_window_entry; From 459e9de81a5168a9474cbd9e55583da7e8b19788 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 2 Dec 2009 15:06:14 +0000 Subject: [PATCH 0578/1180] Close the pane if the process died due to a signal, not just if it exited normally. --- server.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server.c b/server.c index b3979596..60090d5e 100644 --- a/server.c +++ b/server.c @@ -431,7 +431,7 @@ server_child_signal(void) } if (WIFSTOPPED(status)) server_child_stopped(pid, status); - else if (WIFEXITED(status)) + else if (WIFEXITED(status) || WIFSIGNALED(status)) server_child_exited(pid, status); } } From 6bbc92a6f5799f0c3d9ce4fc8c10c161598757be Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 2 Dec 2009 22:13:15 +0000 Subject: [PATCH 0579/1180] Reflect the keypad mode of the application so that numlock works. --- tty.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tty.c b/tty.c index 07b744cb..ac6a2cf7 100644 --- a/tty.c +++ b/tty.c @@ -180,7 +180,7 @@ tty_start_tty(struct tty *tty) tty_putcode(tty, TTYC_SGR0); memcpy(&tty->cell, &grid_default_cell, sizeof tty->cell); - tty_putcode(tty, TTYC_SMKX); + tty_putcode(tty, TTYC_RMKX); tty_putcode(tty, TTYC_ENACS); tty_putcode(tty, TTYC_CLEAR); @@ -410,6 +410,12 @@ tty_update_mode(struct tty *tty, int mode) else tty_puts(tty, "\033[?1000l"); } + if (changed & MODE_KKEYPAD) { + if (mode & MODE_KKEYPAD) + tty_putcode(tty, TTYC_SMKX); + else + tty_putcode(tty, TTYC_RMKX); + } tty->mode = mode; } From 6c9862662fd2cccdc55be9d447a27b10f33ed8ea Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 3 Dec 2009 17:44:02 +0000 Subject: [PATCH 0580/1180] Eliminate duplicate code and ease the passage for server-wide options by adding a -w flag to set-option and show-options and making setw and showw aliases to set -w and show -w. Note: setw and showw are still there, but now aliases for set -w and show -w. --- Makefile | 2 +- cmd-set-option.c | 354 ++++++++++++++++++++++++++++++++++++-- cmd-set-window-option.c | 163 +----------------- cmd-show-options.c | 38 ++-- cmd-show-window-options.c | 25 +-- options-cmd.c | 263 ---------------------------- status.c | 14 +- tmux.1 | 22 ++- tmux.h | 26 +-- 9 files changed, 401 insertions(+), 506 deletions(-) delete mode 100644 options-cmd.c diff --git a/Makefile b/Makefile index b4b0ef56..e5a84a9d 100644 --- a/Makefile +++ b/Makefile @@ -33,7 +33,7 @@ SRCS= attributes.c cfg.c client.c clock.c \ colour.c environ.c grid-view.c grid-utf8.c grid.c input-keys.c \ imsg.c imsg-buffer.c input.c key-bindings.c key-string.c \ layout-set.c layout.c log.c job.c \ - mode-key.c names.c options-cmd.c options.c paste.c procname.c \ + mode-key.c names.c options.c paste.c procname.c \ resize.c screen-redraw.c screen-write.c screen.c session.c status.c \ server-fn.c server.c server-client.c server-window.c \ tmux.c tty-keys.c tty-term.c tty.c utf8.c \ diff --git a/cmd-set-option.c b/cmd-set-option.c index 0a06c620..e58ac7d2 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -29,10 +29,27 @@ int cmd_set_option_exec(struct cmd *, struct cmd_ctx *); +const char *cmd_set_option_print( + const struct set_option_entry *, struct options_entry *); +void cmd_set_option_string(struct cmd_ctx *, + struct options *, const struct set_option_entry *, char *, int); +void cmd_set_option_number(struct cmd_ctx *, + struct options *, const struct set_option_entry *, char *); +void cmd_set_option_keys(struct cmd_ctx *, + struct options *, const struct set_option_entry *, char *); +void cmd_set_option_colour(struct cmd_ctx *, + struct options *, const struct set_option_entry *, char *); +void cmd_set_option_attributes(struct cmd_ctx *, + struct options *, const struct set_option_entry *, char *); +void cmd_set_option_flag(struct cmd_ctx *, + struct options *, const struct set_option_entry *, char *); +void cmd_set_option_choice(struct cmd_ctx *, + struct options *, const struct set_option_entry *, char *); + const struct cmd_entry cmd_set_option_entry = { "set-option", "set", - "[-agu] " CMD_TARGET_SESSION_USAGE " option [value]", - CMD_ARG12, "agu", + "[-aguw] [-t target-session|target-window] option [value]", + CMD_ARG12, "aguw", NULL, cmd_target_parse, cmd_set_option_exec, @@ -40,6 +57,12 @@ const struct cmd_entry cmd_set_option_entry = { cmd_target_print }; +const char *set_option_mode_keys_list[] = { + "emacs", "vi", NULL +}; +const char *set_option_clock_mode_style_list[] = { + "12", "24", NULL +}; const char *set_option_status_keys_list[] = { "emacs", "vi", NULL }; @@ -49,7 +72,8 @@ const char *set_option_status_justify_list[] = { const char *set_option_bell_action_list[] = { "none", "any", "current", NULL }; -const struct set_option_entry set_option_table[] = { + +const struct set_option_entry set_session_option_table[] = { { "base-index", SET_OPTION_NUMBER, 0, INT_MAX, NULL }, { "bell-action", SET_OPTION_CHOICE, 0, 0, set_option_bell_action_list }, { "buffer-limit", SET_OPTION_NUMBER, 1, INT_MAX, NULL }, @@ -101,11 +125,45 @@ const struct set_option_entry set_option_table[] = { { NULL, 0, 0, 0, NULL } }; +const struct set_option_entry set_window_option_table[] = { + { "aggressive-resize", SET_OPTION_FLAG, 0, 0, NULL }, + { "automatic-rename", SET_OPTION_FLAG, 0, 0, NULL }, + { "clock-mode-colour", SET_OPTION_COLOUR, 0, 0, NULL }, + { "clock-mode-style", + SET_OPTION_CHOICE, 0, 0, set_option_clock_mode_style_list }, + { "force-height", SET_OPTION_NUMBER, 0, INT_MAX, NULL }, + { "force-width", SET_OPTION_NUMBER, 0, INT_MAX, NULL }, + { "main-pane-height", SET_OPTION_NUMBER, 1, INT_MAX, NULL }, + { "main-pane-width", SET_OPTION_NUMBER, 1, INT_MAX, NULL }, + { "mode-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL }, + { "mode-bg", SET_OPTION_COLOUR, 0, 0, NULL }, + { "mode-fg", SET_OPTION_COLOUR, 0, 0, NULL }, + { "mode-keys", SET_OPTION_CHOICE, 0, 0, set_option_mode_keys_list }, + { "mode-mouse", SET_OPTION_FLAG, 0, 0, NULL }, + { "monitor-activity", SET_OPTION_FLAG, 0, 0, NULL }, + { "monitor-content", SET_OPTION_STRING, 0, 0, NULL }, + { "remain-on-exit", SET_OPTION_FLAG, 0, 0, NULL }, + { "synchronize-panes", SET_OPTION_FLAG, 0, 0, NULL }, + { "utf8", SET_OPTION_FLAG, 0, 0, NULL }, + { "window-status-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL }, + { "window-status-bg", SET_OPTION_COLOUR, 0, 0, NULL }, + { "window-status-current-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL }, + { "window-status-current-bg", SET_OPTION_COLOUR, 0, 0, NULL }, + { "window-status-current-fg", SET_OPTION_COLOUR, 0, 0, NULL }, + { "window-status-current-format", SET_OPTION_STRING, 0, 0, NULL }, + { "window-status-fg", SET_OPTION_COLOUR, 0, 0, NULL }, + { "window-status-format", SET_OPTION_STRING, 0, 0, NULL }, + { "xterm-keys", SET_OPTION_FLAG, 0, 0, NULL }, + { NULL, 0, 0, 0, NULL } +}; + int cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) { struct cmd_target_data *data = self->data; + const struct set_option_entry *table; struct session *s; + struct winlink *wl; struct client *c; struct options *oo; const struct set_option_entry *entry, *opt; @@ -114,12 +172,26 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) u_int i; int try_again; - if (cmd_check_flag(data->chflags, 'g')) - oo = &global_s_options; - else { - if ((s = cmd_find_session(ctx, data->target)) == NULL) - return (-1); - oo = &s->options; + if (cmd_check_flag(data->chflags, 'w')) { + table = set_window_option_table; + if (cmd_check_flag(data->chflags, 'g')) + oo = &global_w_options; + else { + wl = cmd_find_window(ctx, data->target, NULL); + if (wl == NULL) + return (-1); + oo = &wl->window->options; + } + } else { + table = set_session_option_table; + if (cmd_check_flag(data->chflags, 'g')) + oo = &global_s_options; + else { + s = cmd_find_session(ctx, data->target); + if (s == NULL) + return (-1); + oo = &s->options; + } } if (*data->arg == '\0') { @@ -128,7 +200,7 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) } entry = NULL; - for (opt = set_option_table; opt->name != NULL; opt++) { + for (opt = table; opt->name != NULL; opt++) { if (strncmp(opt->name, data->arg, strlen(data->arg)) != 0) continue; if (entry != NULL) { @@ -163,31 +235,36 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) } else { switch (entry->type) { case SET_OPTION_STRING: - set_option_string(ctx, oo, entry, + cmd_set_option_string(ctx, oo, entry, data->arg2, cmd_check_flag(data->chflags, 'a')); break; case SET_OPTION_NUMBER: - set_option_number(ctx, oo, entry, data->arg2); + cmd_set_option_number(ctx, oo, entry, data->arg2); break; case SET_OPTION_KEYS: - set_option_keys(ctx, oo, entry, data->arg2); + cmd_set_option_keys(ctx, oo, entry, data->arg2); break; case SET_OPTION_COLOUR: - set_option_colour(ctx, oo, entry, data->arg2); + cmd_set_option_colour(ctx, oo, entry, data->arg2); break; case SET_OPTION_ATTRIBUTES: - set_option_attributes(ctx, oo, entry, data->arg2); + cmd_set_option_attributes(ctx, oo, entry, data->arg2); break; case SET_OPTION_FLAG: - set_option_flag(ctx, oo, entry, data->arg2); + cmd_set_option_flag(ctx, oo, entry, data->arg2); break; case SET_OPTION_CHOICE: - set_option_choice(ctx, oo, entry, data->arg2); + cmd_set_option_choice(ctx, oo, entry, data->arg2); break; } } recalculate_sizes(); + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c != NULL && c->session != NULL) + server_redraw_client(c); + } /* * Special-case: kill all persistent jobs if status-left, status-right @@ -196,7 +273,8 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) */ if (strcmp(entry->name, "status-left") == 0 || strcmp(entry->name, "status-right") == 0 || - strcmp(entry->name, "set-titles-string") == 0) { + strcmp(entry->name, "set-titles-string") == 0 || + strcmp(entry->name, "window-status-format") == 0) { for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); if (c == NULL || c->session == NULL) @@ -222,3 +300,243 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) return (0); } + +const char * +cmd_set_option_print( + const struct set_option_entry *entry, struct options_entry *o) +{ + static char out[BUFSIZ]; + const char *s; + struct keylist *keylist; + u_int i; + + *out = '\0'; + switch (entry->type) { + case SET_OPTION_STRING: + xsnprintf(out, sizeof out, "\"%s\"", o->str); + break; + case SET_OPTION_NUMBER: + xsnprintf(out, sizeof out, "%lld", o->num); + break; + case SET_OPTION_KEYS: + keylist = o->data; + for (i = 0; i < ARRAY_LENGTH(keylist); i++) { + strlcat(out, key_string_lookup_key( + ARRAY_ITEM(keylist, i)), sizeof out); + if (i != ARRAY_LENGTH(keylist) - 1) + strlcat(out, ",", sizeof out); + } + break; + case SET_OPTION_COLOUR: + s = colour_tostring(o->num); + xsnprintf(out, sizeof out, "%s", s); + break; + case SET_OPTION_ATTRIBUTES: + s = attributes_tostring(o->num); + xsnprintf(out, sizeof out, "%s", s); + break; + case SET_OPTION_FLAG: + if (o->num) + strlcpy(out, "on", sizeof out); + else + strlcpy(out, "off", sizeof out); + break; + case SET_OPTION_CHOICE: + s = entry->choices[o->num]; + xsnprintf(out, sizeof out, "%s", s); + break; + } + return (out); +} + +void +cmd_set_option_string(struct cmd_ctx *ctx, struct options *oo, + const struct set_option_entry *entry, char *value, int append) +{ + struct options_entry *o; + char *oldvalue, *newvalue; + + if (value == NULL) { + ctx->error(ctx, "empty value"); + return; + } + + if (append) { + oldvalue = options_get_string(oo, entry->name); + xasprintf(&newvalue, "%s%s", oldvalue, value); + } else + newvalue = value; + + o = options_set_string(oo, entry->name, "%s", newvalue); + ctx->info(ctx, + "set option: %s -> %s", o->name, cmd_set_option_print(entry, o)); + + if (newvalue != value) + xfree(newvalue); +} + +void +cmd_set_option_number(struct cmd_ctx *ctx, struct options *oo, + const struct set_option_entry *entry, char *value) +{ + struct options_entry *o; + long long number; + const char *errstr; + + if (value == NULL) { + ctx->error(ctx, "empty value"); + return; + } + + number = strtonum(value, entry->minimum, entry->maximum, &errstr); + if (errstr != NULL) { + ctx->error(ctx, "value is %s: %s", errstr, value); + return; + } + + o = options_set_number(oo, entry->name, number); + ctx->info(ctx, + "set option: %s -> %s", o->name, cmd_set_option_print(entry, o)); +} + +void +cmd_set_option_keys(struct cmd_ctx *ctx, struct options *oo, + const struct set_option_entry *entry, char *value) +{ + struct options_entry *o; + struct keylist *keylist; + char *copyvalue, *ptr, *str; + int key; + + if (value == NULL) { + ctx->error(ctx, "empty value"); + return; + } + + keylist = xmalloc(sizeof *keylist); + ARRAY_INIT(keylist); + + ptr = copyvalue = xstrdup(value); + while ((str = strsep(&ptr, ",")) != NULL) { + if ((key = key_string_lookup_string(str)) == KEYC_NONE) { + xfree(keylist); + ctx->error(ctx, "unknown key: %s", str); + xfree(copyvalue); + return; + } + ARRAY_ADD(keylist, key); + } + xfree(copyvalue); + + o = options_set_data(oo, entry->name, keylist, xfree); + ctx->info(ctx, + "set option: %s -> %s", o->name, cmd_set_option_print(entry, o)); +} + +void +cmd_set_option_colour(struct cmd_ctx *ctx, struct options *oo, + const struct set_option_entry *entry, char *value) +{ + struct options_entry *o; + int colour; + + if (value == NULL) { + ctx->error(ctx, "empty value"); + return; + } + + if ((colour = colour_fromstring(value)) == -1) { + ctx->error(ctx, "bad colour: %s", value); + return; + } + + o = options_set_number(oo, entry->name, colour); + ctx->info(ctx, + "set option: %s -> %s", o->name, cmd_set_option_print(entry, o)); +} + +void +cmd_set_option_attributes(struct cmd_ctx *ctx, struct options *oo, + const struct set_option_entry *entry, char *value) +{ + struct options_entry *o; + int attr; + + if (value == NULL) { + ctx->error(ctx, "empty value"); + return; + } + + if ((attr = attributes_fromstring(value)) == -1) { + ctx->error(ctx, "bad attributes: %s", value); + return; + } + + o = options_set_number(oo, entry->name, attr); + ctx->info(ctx, + "set option: %s -> %s", o->name, cmd_set_option_print(entry, o)); +} + +void +cmd_set_option_flag(struct cmd_ctx *ctx, struct options *oo, + const struct set_option_entry *entry, char *value) +{ + struct options_entry *o; + int flag; + + if (value == NULL || *value == '\0') + flag = !options_get_number(oo, entry->name); + else { + if ((value[0] == '1' && value[1] == '\0') || + strcasecmp(value, "on") == 0 || + strcasecmp(value, "yes") == 0) + flag = 1; + else if ((value[0] == '0' && value[1] == '\0') || + strcasecmp(value, "off") == 0 || + strcasecmp(value, "no") == 0) + flag = 0; + else { + ctx->error(ctx, "bad value: %s", value); + return; + } + } + + o = options_set_number(oo, entry->name, flag); + ctx->info(ctx, + "set option: %s -> %s", o->name, cmd_set_option_print(entry, o)); +} + +void +cmd_set_option_choice(struct cmd_ctx *ctx, struct options *oo, + const struct set_option_entry *entry, char *value) +{ + struct options_entry *o; + const char **choicep; + int n, choice = -1; + + if (value == NULL) { + ctx->error(ctx, "empty value"); + return; + } + + n = 0; + for (choicep = entry->choices; *choicep != NULL; choicep++) { + n++; + if (strncmp(*choicep, value, strlen(value)) != 0) + continue; + + if (choice != -1) { + ctx->error(ctx, "ambiguous option value: %s", value); + return; + } + choice = n - 1; + } + if (choice == -1) { + ctx->error(ctx, "unknown option value: %s", value); + return; + } + + o = options_set_number(oo, entry->name, choice); + ctx->info(ctx, + "set option: %s -> %s", o->name, cmd_set_option_print(entry, o)); +} diff --git a/cmd-set-window-option.c b/cmd-set-window-option.c index 0ad1025e..559d6485 100644 --- a/cmd-set-window-option.c +++ b/cmd-set-window-option.c @@ -18,13 +18,10 @@ #include -#include -#include - #include "tmux.h" /* - * Set a window option. + * Set a window option. This is just an alias for set-option -w. */ int cmd_set_window_option_exec(struct cmd *, struct cmd_ctx *); @@ -40,165 +37,11 @@ const struct cmd_entry cmd_set_window_option_entry = { cmd_target_print }; -const char *set_option_mode_keys_list[] = { - "emacs", "vi", NULL -}; -const char *set_option_clock_mode_style_list[] = { - "12", "24", NULL -}; -const struct set_option_entry set_window_option_table[] = { - { "aggressive-resize", SET_OPTION_FLAG, 0, 0, NULL }, - { "automatic-rename", SET_OPTION_FLAG, 0, 0, NULL }, - { "clock-mode-colour", SET_OPTION_COLOUR, 0, 0, NULL }, - { "clock-mode-style", - SET_OPTION_CHOICE, 0, 0, set_option_clock_mode_style_list }, - { "force-height", SET_OPTION_NUMBER, 0, INT_MAX, NULL }, - { "force-width", SET_OPTION_NUMBER, 0, INT_MAX, NULL }, - { "main-pane-height", SET_OPTION_NUMBER, 1, INT_MAX, NULL }, - { "main-pane-width", SET_OPTION_NUMBER, 1, INT_MAX, NULL }, - { "mode-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL }, - { "mode-bg", SET_OPTION_COLOUR, 0, 0, NULL }, - { "mode-fg", SET_OPTION_COLOUR, 0, 0, NULL }, - { "mode-keys", SET_OPTION_CHOICE, 0, 0, set_option_mode_keys_list }, - { "mode-mouse", SET_OPTION_FLAG, 0, 0, NULL }, - { "monitor-activity", SET_OPTION_FLAG, 0, 0, NULL }, - { "monitor-content", SET_OPTION_STRING, 0, 0, NULL }, - { "remain-on-exit", SET_OPTION_FLAG, 0, 0, NULL }, - { "synchronize-panes", SET_OPTION_FLAG, 0, 0, NULL }, - { "utf8", SET_OPTION_FLAG, 0, 0, NULL }, - { "window-status-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL }, - { "window-status-bg", SET_OPTION_COLOUR, 0, 0, NULL }, - { "window-status-current-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL }, - { "window-status-current-bg", SET_OPTION_COLOUR, 0, 0, NULL }, - { "window-status-current-fg", SET_OPTION_COLOUR, 0, 0, NULL }, - { "window-status-current-format", SET_OPTION_STRING, 0, 0, NULL }, - { "window-status-fg", SET_OPTION_COLOUR, 0, 0, NULL }, - { "window-status-format", SET_OPTION_STRING, 0, 0, NULL }, - { "xterm-keys", SET_OPTION_FLAG, 0, 0, NULL }, - { NULL, 0, 0, 0, NULL } -}; - int cmd_set_window_option_exec(struct cmd *self, struct cmd_ctx *ctx) { struct cmd_target_data *data = self->data; - struct winlink *wl; - struct client *c; - struct options *oo; - const struct set_option_entry *entry, *opt; - struct jobs *jobs; - struct job *job, *nextjob; - u_int i; - int try_again; - if (cmd_check_flag(data->chflags, 'g')) - oo = &global_w_options; - else { - if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) - return (-1); - oo = &wl->window->options; - } - - if (*data->arg == '\0') { - ctx->error(ctx, "invalid option"); - return (-1); - } - - entry = NULL; - for (opt = set_window_option_table; opt->name != NULL; opt++) { - if (strncmp(opt->name, data->arg, strlen(data->arg)) != 0) - continue; - if (entry != NULL) { - ctx->error(ctx, "ambiguous option: %s", data->arg); - return (-1); - } - entry = opt; - - /* Bail now if an exact match. */ - if (strcmp(entry->name, data->arg) == 0) - break; - } - if (entry == NULL) { - ctx->error(ctx, "unknown option: %s", data->arg); - return (-1); - } - - if (cmd_check_flag(data->chflags, 'u')) { - if (cmd_check_flag(data->chflags, 'g')) { - ctx->error(ctx, - "can't unset global option: %s", entry->name); - return (-1); - } - if (data->arg2 != NULL) { - ctx->error(ctx, - "value passed to unset option: %s", entry->name); - return (-1); - } - - options_remove(oo, entry->name); - ctx->info(ctx, "unset option: %s", entry->name); - } else { - switch (entry->type) { - case SET_OPTION_STRING: - set_option_string(ctx, oo, entry, - data->arg2, cmd_check_flag(data->chflags, 'a')); - break; - case SET_OPTION_NUMBER: - set_option_number(ctx, oo, entry, data->arg2); - break; - case SET_OPTION_KEYS: - set_option_keys(ctx, oo, entry, data->arg2); - break; - case SET_OPTION_COLOUR: - set_option_colour(ctx, oo, entry, data->arg2); - break; - case SET_OPTION_ATTRIBUTES: - set_option_attributes(ctx, oo, entry, data->arg2); - break; - case SET_OPTION_FLAG: - set_option_flag(ctx, oo, entry, data->arg2); - break; - case SET_OPTION_CHOICE: - set_option_choice(ctx, oo, entry, data->arg2); - break; - } - } - - recalculate_sizes(); - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - c = ARRAY_ITEM(&clients, i); - if (c != NULL && c->session != NULL) - server_redraw_client(c); - } - - /* - * Special-case: kill all persistent jobs if window-status-format has - * changed. Persistent jobs are only used by the status line at the - * moment so this works XXX. - */ - if (strcmp(entry->name, "window-status-format") == 0) { - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - c = ARRAY_ITEM(&clients, i); - if (c == NULL || c->session == NULL) - continue; - - jobs = &c->status_jobs; - do { - try_again = 0; - job = RB_ROOT(jobs); - while (job != NULL) { - nextjob = RB_NEXT(jobs, jobs, job); - if (job->flags & JOB_PERSIST) { - job_remove(jobs, job); - try_again = 1; - break; - } - job = nextjob; - } - } while (try_again); - server_redraw_client(c); - } - } - - return (0); + cmd_set_flag(&data->chflags, 'w'); + return (cmd_set_option_entry.exec(self, ctx)); } diff --git a/cmd-show-options.c b/cmd-show-options.c index 9e7fd7db..3374c64e 100644 --- a/cmd-show-options.c +++ b/cmd-show-options.c @@ -31,8 +31,8 @@ int cmd_show_options_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_show_options_entry = { "show-options", "show", - "[-g] " CMD_TARGET_SESSION_USAGE, - 0, "g", + "[-gw] [-t target-session|target-window]", + 0, "gw", cmd_target_init, cmd_target_parse, cmd_show_options_exec, @@ -43,25 +43,41 @@ const struct cmd_entry cmd_show_options_entry = { int cmd_show_options_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; + struct cmd_target_data *data = self->data; + const struct set_option_entry *table; struct session *s; + struct winlink *wl; struct options *oo; struct options_entry *o; const struct set_option_entry *entry; const char *optval; - if (cmd_check_flag(data->chflags, 'g')) - oo = &global_s_options; - else { - if ((s = cmd_find_session(ctx, data->target)) == NULL) - return (-1); - oo = &s->options; + if (cmd_check_flag(data->chflags, 'w')) { + table = set_window_option_table; + if (cmd_check_flag(data->chflags, 'g')) + oo = &global_w_options; + else { + wl = cmd_find_window(ctx, data->target, NULL); + if (wl == NULL) + return (-1); + oo = &wl->window->options; + } + } else { + table = set_session_option_table; + if (cmd_check_flag(data->chflags, 'g')) + oo = &global_s_options; + else { + s = cmd_find_session(ctx, data->target); + if (s == NULL) + return (-1); + oo = &s->options; + } } - for (entry = set_option_table; entry->name != NULL; entry++) { + for (entry = table; entry->name != NULL; entry++) { if ((o = options_find1(oo, entry->name)) == NULL) continue; - optval = set_option_print(entry, o); + optval = cmd_set_option_print(entry, o); ctx->print(ctx, "%s %s", entry->name, optval); } diff --git a/cmd-show-window-options.c b/cmd-show-window-options.c index 2609cfab..b81f887c 100644 --- a/cmd-show-window-options.c +++ b/cmd-show-window-options.c @@ -24,7 +24,7 @@ #include "tmux.h" /* - * Show window options. + * Show window options. This is an alias for show-options -w. */ int cmd_show_window_options_exec(struct cmd *, struct cmd_ctx *); @@ -44,26 +44,7 @@ int cmd_show_window_options_exec(struct cmd *self, struct cmd_ctx *ctx) { struct cmd_target_data *data = self->data; - struct winlink *wl; - struct options *oo; - struct options_entry *o; - const struct set_option_entry *entry; - const char *optval; - if (cmd_check_flag(data->chflags, 'g')) - oo = &global_w_options; - else { - if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) - return (-1); - oo = &wl->window->options; - } - - for (entry = set_window_option_table; entry->name != NULL; entry++) { - if ((o = options_find1(oo, entry->name)) == NULL) - continue; - optval = set_option_print(entry, o); - ctx->print(ctx, "%s %s", entry->name, optval); - } - - return (0); + cmd_set_flag(&data->chflags, 'w'); + return (cmd_show_options_entry.exec(self, ctx)); } diff --git a/options-cmd.c b/options-cmd.c deleted file mode 100644 index 8c0e0d1a..00000000 --- a/options-cmd.c +++ /dev/null @@ -1,263 +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 "tmux.h" - -const char * -set_option_print(const struct set_option_entry *entry, struct options_entry *o) -{ - static char out[BUFSIZ]; - const char *s; - struct keylist *keylist; - u_int i; - - *out = '\0'; - switch (entry->type) { - case SET_OPTION_STRING: - xsnprintf(out, sizeof out, "\"%s\"", o->str); - break; - case SET_OPTION_NUMBER: - xsnprintf(out, sizeof out, "%lld", o->num); - break; - case SET_OPTION_KEYS: - keylist = o->data; - for (i = 0; i < ARRAY_LENGTH(keylist); i++) { - strlcat(out, key_string_lookup_key( - ARRAY_ITEM(keylist, i)), sizeof out); - if (i != ARRAY_LENGTH(keylist) - 1) - strlcat(out, ",", sizeof out); - } - break; - case SET_OPTION_COLOUR: - s = colour_tostring(o->num); - xsnprintf(out, sizeof out, "%s", s); - break; - case SET_OPTION_ATTRIBUTES: - s = attributes_tostring(o->num); - xsnprintf(out, sizeof out, "%s", s); - break; - case SET_OPTION_FLAG: - if (o->num) - strlcpy(out, "on", sizeof out); - else - strlcpy(out, "off", sizeof out); - break; - case SET_OPTION_CHOICE: - s = entry->choices[o->num]; - xsnprintf(out, sizeof out, "%s", s); - break; - } - return (out); -} - -void -set_option_string(struct cmd_ctx *ctx, struct options *oo, - const struct set_option_entry *entry, char *value, int append) -{ - struct options_entry *o; - char *oldvalue, *newvalue; - - if (value == NULL) { - ctx->error(ctx, "empty value"); - return; - } - - if (append) { - oldvalue = options_get_string(oo, entry->name); - xasprintf(&newvalue, "%s%s", oldvalue, value); - } else - newvalue = value; - - o = options_set_string(oo, entry->name, "%s", newvalue); - ctx->info( - ctx, "set option: %s -> %s", o->name, set_option_print(entry, o)); - - if (newvalue != value) - xfree(newvalue); -} - -void -set_option_number(struct cmd_ctx *ctx, struct options *oo, - const struct set_option_entry *entry, char *value) -{ - struct options_entry *o; - long long number; - const char *errstr; - - if (value == NULL) { - ctx->error(ctx, "empty value"); - return; - } - - number = strtonum(value, entry->minimum, entry->maximum, &errstr); - if (errstr != NULL) { - ctx->error(ctx, "value is %s: %s", errstr, value); - return; - } - - o = options_set_number(oo, entry->name, number); - ctx->info( - ctx, "set option: %s -> %s", o->name, set_option_print(entry, o)); -} - -void -set_option_keys(struct cmd_ctx *ctx, struct options *oo, - const struct set_option_entry *entry, char *value) -{ - struct options_entry *o; - struct keylist *keylist; - char *copyvalue, *ptr, *str; - int key; - - if (value == NULL) { - ctx->error(ctx, "empty value"); - return; - } - - keylist = xmalloc(sizeof *keylist); - ARRAY_INIT(keylist); - - ptr = copyvalue = xstrdup(value); - while ((str = strsep(&ptr, ",")) != NULL) { - if ((key = key_string_lookup_string(str)) == KEYC_NONE) { - xfree(keylist); - ctx->error(ctx, "unknown key: %s", str); - xfree(copyvalue); - return; - } - ARRAY_ADD(keylist, key); - } - xfree(copyvalue); - - o = options_set_data(oo, entry->name, keylist, xfree); - ctx->info( - ctx, "set option: %s -> %s", o->name, set_option_print(entry, o)); -} - -void -set_option_colour(struct cmd_ctx *ctx, struct options *oo, - const struct set_option_entry *entry, char *value) -{ - struct options_entry *o; - int colour; - - if (value == NULL) { - ctx->error(ctx, "empty value"); - return; - } - - if ((colour = colour_fromstring(value)) == -1) { - ctx->error(ctx, "bad colour: %s", value); - return; - } - - o = options_set_number(oo, entry->name, colour); - ctx->info( - ctx, "set option: %s -> %s", o->name, set_option_print(entry, o)); -} - -void -set_option_attributes(struct cmd_ctx *ctx, struct options *oo, - const struct set_option_entry *entry, char *value) -{ - struct options_entry *o; - int attr; - - if (value == NULL) { - ctx->error(ctx, "empty value"); - return; - } - - if ((attr = attributes_fromstring(value)) == -1) { - ctx->error(ctx, "bad attributes: %s", value); - return; - } - - o = options_set_number(oo, entry->name, attr); - ctx->info( - ctx, "set option: %s -> %s", o->name, set_option_print(entry, o)); -} - -void -set_option_flag(struct cmd_ctx *ctx, struct options *oo, - const struct set_option_entry *entry, char *value) -{ - struct options_entry *o; - int flag; - - if (value == NULL || *value == '\0') - flag = !options_get_number(oo, entry->name); - else { - if ((value[0] == '1' && value[1] == '\0') || - strcasecmp(value, "on") == 0 || - strcasecmp(value, "yes") == 0) - flag = 1; - else if ((value[0] == '0' && value[1] == '\0') || - strcasecmp(value, "off") == 0 || - strcasecmp(value, "no") == 0) - flag = 0; - else { - ctx->error(ctx, "bad value: %s", value); - return; - } - } - - o = options_set_number(oo, entry->name, flag); - ctx->info( - ctx, "set option: %s -> %s", o->name, set_option_print(entry, o)); -} - -void -set_option_choice(struct cmd_ctx *ctx, struct options *oo, - const struct set_option_entry *entry, char *value) -{ - struct options_entry *o; - const char **choicep; - int n, choice = -1; - - if (value == NULL) { - ctx->error(ctx, "empty value"); - return; - } - - n = 0; - for (choicep = entry->choices; *choicep != NULL; choicep++) { - n++; - if (strncmp(*choicep, value, strlen(value)) != 0) - continue; - - if (choice != -1) { - ctx->error(ctx, "ambiguous option: %s", value); - return; - } - choice = n - 1; - } - if (choice == -1) { - ctx->error(ctx, "unknown option: %s", value); - return; - } - - o = options_set_number(oo, entry->name, choice); - ctx->info( - ctx, "set option: %s -> %s", o->name, set_option_print(entry, o)); -} diff --git a/status.c b/status.c index fa452d53..bc8dc716 100644 --- a/status.c +++ b/status.c @@ -1115,7 +1115,7 @@ char * status_prompt_complete(const char *s) { const struct cmd_entry **cmdent; - const struct set_option_entry *optent; + const struct set_option_entry *entry; ARRAY_DECL(, const char *) list; char *prefix, *s2; u_int i; @@ -1130,13 +1130,13 @@ status_prompt_complete(const char *s) if (strncmp((*cmdent)->name, s, strlen(s)) == 0) ARRAY_ADD(&list, (*cmdent)->name); } - for (optent = set_option_table; optent->name != NULL; optent++) { - if (strncmp(optent->name, s, strlen(s)) == 0) - ARRAY_ADD(&list, optent->name); + for (entry = set_session_option_table; entry->name != NULL; entry++) { + if (strncmp(entry->name, s, strlen(s)) == 0) + ARRAY_ADD(&list, entry->name); } - for (optent = set_window_option_table; optent->name != NULL; optent++) { - if (strncmp(optent->name, s, strlen(s)) == 0) - ARRAY_ADD(&list, optent->name); + for (entry = set_window_option_table; entry->name != NULL; entry++) { + if (strncmp(entry->name, s, strlen(s)) == 0) + ARRAY_ADD(&list, entry->name); } /* If none, bail now. */ diff --git a/tmux.1 b/tmux.1 index 46734315..97881320 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1230,8 +1230,8 @@ command. Commands which set options are as follows: .Bl -tag -width Ds .It Xo Ic set-option -.Op Fl agu -.Op Fl t Ar target-session +.Op Fl aguw +.Op Fl t Ar target-session | Ar target-window .Ar option Ar value .Xc .D1 (alias: Ic set ) @@ -1249,6 +1249,13 @@ The flag unsets an option, so a session inherits the option from the global options - it is not possible to unset a global option. .Pp +With +.Fl w , +this command is equivalent to +.Ic set-window-option +with +.Ar target-window . +.Pp Available session options are: .Bl -tag -width Ds .It Ic base-index Ar index @@ -1831,14 +1838,21 @@ as Shift, Alt or Ctrl. The default is off. .El .It Xo Ic show-options -.Op Fl g -.Op Fl t Ar target-session +.Op Fl gw +.Op Fl t Ar target-session | Ar target-window .Xc .D1 (alias: Ic show ) Show the session options for .Ar target session , or the global session options with .Fl g . +.Pp +If +.Fl w +is used, this command is equivalent to +.Ic show-window-options +with +.Ar target-window . .It Xo Ic show-window-options .Op Fl g .Op Fl t Ar target-window diff --git a/tmux.h b/tmux.h index 59b3ec1f..7549c702 100644 --- a/tmux.h +++ b/tmux.h @@ -1233,8 +1233,6 @@ struct set_option_entry { const char **choices; }; -extern const struct set_option_entry set_option_table[]; -extern const struct set_option_entry set_window_option_table[]; /* tmux.c */ extern struct options global_s_options; @@ -1377,24 +1375,6 @@ void tty_keys_init(struct tty *); void tty_keys_free(struct tty *); int tty_keys_next(struct tty *); -/* options-cmd.c */ -const char *set_option_print( - const struct set_option_entry *, struct options_entry *); -void set_option_string(struct cmd_ctx *, - struct options *, const struct set_option_entry *, char *, int); -void set_option_number(struct cmd_ctx *, - struct options *, const struct set_option_entry *, char *); -void set_option_keys(struct cmd_ctx *, - struct options *, const struct set_option_entry *, char *); -void set_option_colour(struct cmd_ctx *, - struct options *, const struct set_option_entry *, char *); -void set_option_attributes(struct cmd_ctx *, - struct options *, const struct set_option_entry *, char *); -void set_option_flag(struct cmd_ctx *, - struct options *, const struct set_option_entry *, char *); -void set_option_choice(struct cmd_ctx *, - struct options *, const struct set_option_entry *, char *); - /* paste.c */ void paste_init_stack(struct paste_stack *); void paste_free_stack(struct paste_stack *); @@ -1410,6 +1390,12 @@ int paste_replace(struct paste_stack *, u_int, char *, size_t); extern const char clock_table[14][5][5]; void clock_draw(struct screen_write_ctx *, int, int); +/* cmd-set-option.c */ +extern const struct set_option_entry set_session_option_table[]; +extern const struct set_option_entry set_window_option_table[]; +const char *cmd_set_option_print( + const struct set_option_entry *, struct options_entry *); + /* cmd.c */ int cmd_pack_argv(int, char **, char *, size_t); int cmd_unpack_argv(char *, size_t, int, char ***); From 15a64b805e46584d37cc6745383709632e287999 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 3 Dec 2009 22:50:09 +0000 Subject: [PATCH 0581/1180] Massive spaces->tabs and trailing whitespace cleanup, hopefully for the last time now I've configured emacs to make them displayed in really annoying colours... --- client.c | 14 ++--- clock.c | 8 +-- cmd-attach-session.c | 6 +- cmd-bind-key.c | 2 +- cmd-break-pane.c | 16 +++--- cmd-capture-pane.c | 2 +- cmd-choose-window.c | 6 +- cmd-generic.c | 14 ++--- cmd-kill-session.c | 2 +- cmd-list-buffers.c | 2 +- cmd-list-keys.c | 2 +- cmd-list-panes.c | 6 +- cmd-new-session.c | 10 ++-- cmd-new-window.c | 2 +- cmd-paste-buffer.c | 2 +- cmd-pipe-pane.c | 8 +-- cmd-previous-layout.c | 2 +- cmd-resize-pane.c | 2 +- cmd-respawn-window.c | 2 +- cmd-select-layout.c | 4 +- cmd-send-keys.c | 2 +- cmd-server-info.c | 8 +-- cmd-set-option.c | 24 ++++---- cmd-show-buffer.c | 10 ++-- cmd-show-messages.c | 2 +- cmd-show-options.c | 2 +- cmd-split-window.c | 2 +- cmd-string.c | 2 +- cmd-swap-pane.c | 2 +- cmd-unlink-window.c | 2 +- cmd.c | 22 ++++---- grid-utf8.c | 2 +- grid-view.c | 6 +- grid.c | 26 ++++----- input-keys.c | 6 +- input.c | 18 +++--- job.c | 6 +- key-bindings.c | 14 ++--- key-string.c | 4 +- layout-set.c | 20 +++---- layout.c | 46 +++++++-------- log.c | 2 +- mode-key.c | 14 ++--- names.c | 6 +- paste.c | 4 +- screen-redraw.c | 10 ++-- screen-write.c | 14 ++--- screen.c | 8 +-- server-client.c | 16 +++--- server-fn.c | 16 +++--- server-window.c | 16 +++--- server.c | 6 +- session.c | 8 +-- status.c | 40 ++++++------- tmux.1 | 4 +- tmux.c | 22 ++++---- tmux.h | 128 +++++++++++++++++++++--------------------- tty-keys.c | 18 +++--- tty-term.c | 10 ++-- tty.c | 80 +++++++++++++------------- window-choose.c | 10 ++-- window-clock.c | 2 +- window-copy.c | 30 +++++----- window-more.c | 6 +- window.c | 10 ++-- xterm-keys.c | 16 +++--- 66 files changed, 418 insertions(+), 416 deletions(-) diff --git a/client.c b/client.c index 91c2f6c5..69d5bd7b 100644 --- a/client.c +++ b/client.c @@ -125,7 +125,7 @@ client_send_identify(int flags) if (getcwd(data.cwd, sizeof data.cwd) == NULL) *data.cwd = '\0'; - + term = getenv("TERM"); if (term == NULL || strlcpy(data.term, term, sizeof data.term) >= sizeof data.term) @@ -143,7 +143,7 @@ client_send_environ(void) struct msg_environ_data data; char **var; - for (var = environ; *var != NULL; var++) { + for (var = environ; *var != NULL; var++) { if (strlcpy(data.var, *var, sizeof data.var) >= sizeof data.var) continue; client_write_server(MSG_ENVIRON, &data, sizeof data); @@ -153,7 +153,7 @@ client_send_environ(void) void client_write_server(enum msgtype type, void *buf, size_t len) { - imsg_compose(&client_ibuf, type, PROTOCOL_VERSION, -1, -1, buf, len); + imsg_compose(&client_ibuf, type, PROTOCOL_VERSION, -1, -1, buf, len); } void @@ -179,7 +179,7 @@ client_main(void) /* Note: event_init() has already been called. */ - /* Set up signals. */ + /* Set up signals. */ memset(&sigact, 0, sizeof sigact); sigemptyset(&sigact.sa_mask); sigact.sa_flags = SA_RESTART; @@ -263,9 +263,9 @@ client_callback(unused int fd, short events, unused void *data) if (client_dispatch() != 0) { event_loopexit(NULL); return; - } + } } - + if (events & EV_WRITE) { if (msgbuf_write(&client_ibuf.w) < 0) goto lost_server; @@ -341,7 +341,7 @@ client_dispatch(void) if (datalen != sizeof lockdata) fatalx("bad MSG_LOCK size"); memcpy(&lockdata, imsg.data, sizeof lockdata); - + lockdata.cmd[(sizeof lockdata.cmd) - 1] = '\0'; system(lockdata.cmd); client_write_server(MSG_UNLOCK, NULL, 0); diff --git a/clock.c b/clock.c index b630cf84..00d818be 100644 --- a/clock.c +++ b/clock.c @@ -134,13 +134,13 @@ clock_draw(struct screen_write_ctx *ctx, int colour, int style) for (ptr = tim; *ptr != '\0'; ptr++) { if (*ptr >= '0' && *ptr <= '9') idx = *ptr - '0'; - else if (*ptr == ':') + else if (*ptr == ':') idx = 10; - else if (*ptr == 'A') + else if (*ptr == 'A') idx = 11; - else if (*ptr == 'P') + else if (*ptr == 'P') idx = 12; - else if (*ptr == 'M') + else if (*ptr == 'M') idx = 13; else { x += 6; diff --git a/cmd-attach-session.c b/cmd-attach-session.c index be7adb3f..c8f01633 100644 --- a/cmd-attach-session.c +++ b/cmd-attach-session.c @@ -29,7 +29,7 @@ int cmd_attach_session_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_attach_session_entry = { "attach-session", "attach", "[-d] " CMD_TARGET_SESSION_USAGE, - CMD_CANTNEST|CMD_STARTSERVER|CMD_SENDENVIRON, "d", + CMD_CANTNEST|CMD_STARTSERVER|CMD_SENDENVIRON, "d", cmd_target_init, cmd_target_parse, cmd_attach_session_exec, @@ -59,7 +59,7 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx) if (ctx->cmdclient == NULL) { if (cmd_check_flag(data->chflags, 'd')) { - /* + /* * Can't use server_write_session in case attaching to * the same session as currently attached to. */ @@ -72,7 +72,7 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx) server_write_client(c, MSG_DETACH, NULL, 0); } } - + ctx->curclient->session = s; server_redraw_client(ctx->curclient); } else { diff --git a/cmd-bind-key.c b/cmd-bind-key.c index eba5125b..4ed84ac3 100644 --- a/cmd-bind-key.c +++ b/cmd-bind-key.c @@ -152,7 +152,7 @@ cmd_bind_key_table(struct cmd *self, struct cmd_ctx *ctx) ctx->error(ctx, "unknown command: %s", data->modecmd); return (-1); } - + mtmp.key = data->key & ~KEYC_PREFIX; mtmp.mode = data->command_key ? 1 : 0; if ((mbind = SPLAY_FIND(mode_key_tree, mtab->tree, &mtmp)) != NULL) { diff --git a/cmd-break-pane.c b/cmd-break-pane.c index d465f602..d5f847fb 100644 --- a/cmd-break-pane.c +++ b/cmd-break-pane.c @@ -64,18 +64,18 @@ cmd_break_pane_exec(struct cmd *self, struct cmd_ctx *ctx) if (wl->window->active == NULL) wl->window->active = TAILQ_NEXT(wp, entry); } - layout_close_pane(wp); + layout_close_pane(wp); - w = wp->window = window_create1(s->sx, s->sy); - TAILQ_INSERT_HEAD(&w->panes, wp, entry); - w->active = wp; - w->name = default_window_name(w); + w = wp->window = window_create1(s->sx, s->sy); + TAILQ_INSERT_HEAD(&w->panes, wp, entry); + w->active = wp; + w->name = default_window_name(w); layout_init(w); base_idx = options_get_number(&s->options, "base-index"); - wl = session_attach(s, w, -1 - base_idx, &cause); /* can't fail */ - if (!cmd_check_flag(data->chflags, 'd')) - session_select(s, wl->idx); + wl = session_attach(s, w, -1 - base_idx, &cause); /* can't fail */ + if (!cmd_check_flag(data->chflags, 'd')) + session_select(s, wl->idx); server_redraw_session(s); server_status_session_group(s); diff --git a/cmd-capture-pane.c b/cmd-capture-pane.c index 7444b90c..4909531d 100644 --- a/cmd-capture-pane.c +++ b/cmd-capture-pane.c @@ -48,7 +48,7 @@ cmd_capture_pane_exec(struct cmd *self, struct cmd_ctx *ctx) struct screen *s; struct session *sess; u_int i, limit; - size_t len, linelen; + size_t len, linelen; if (cmd_find_pane(ctx, data->target, &sess, &wp) == NULL) return (-1); diff --git a/cmd-choose-window.c b/cmd-choose-window.c index a1540f1d..18b08751 100644 --- a/cmd-choose-window.c +++ b/cmd-choose-window.c @@ -116,10 +116,10 @@ cmd_choose_window_exec(struct cmd *self, struct cmd_ctx *ctx) cdata->client = ctx->curclient; cdata->client->references++; - window_choose_ready(wl->window->active, + window_choose_ready(wl->window->active, cur, cmd_choose_window_callback, cmd_choose_window_free, cdata); - return (0); + return (0); } void @@ -133,7 +133,7 @@ cmd_choose_window_callback(void *data, int idx) if (idx == -1) return; if (cdata->client->flags & CLIENT_DEAD) - return; + return; if (cdata->session->flags & SESSION_DEAD) return; if (cdata->client->session != cdata->session) diff --git a/cmd-generic.c b/cmd-generic.c index 9961c19f..8b536fa0 100644 --- a/cmd-generic.c +++ b/cmd-generic.c @@ -141,7 +141,7 @@ cmd_fill_argument(int flags, char **arg, char **arg2, int argc, char **argv) if (argc == 2) *arg2 = xstrdup(argv[1]); return (0); - } + } if (argc != 0) return (-1); @@ -225,9 +225,9 @@ cmd_target_print(struct cmd *self, char *buf, size_t len) off += cmd_print_flags(buf, len, off, data->chflags); if (off < len && data->target != NULL) off += cmd_prarg(buf + off, len - off, " -t ", data->target); - if (off < len && data->arg != NULL) + if (off < len && data->arg != NULL) off += cmd_prarg(buf + off, len - off, " ", data->arg); - if (off < len && data->arg2 != NULL) + if (off < len && data->arg2 != NULL) off += cmd_prarg(buf + off, len - off, " ", data->arg2); return (off); } @@ -317,9 +317,9 @@ cmd_srcdst_print(struct cmd *self, char *buf, size_t len) off += xsnprintf(buf + off, len - off, " -s %s", data->src); if (off < len && data->dst != NULL) off += xsnprintf(buf + off, len - off, " -t %s", data->dst); - if (off < len && data->arg != NULL) + if (off < len && data->arg != NULL) off += cmd_prarg(buf + off, len - off, " ", data->arg); - if (off < len && data->arg2 != NULL) + if (off < len && data->arg2 != NULL) off += cmd_prarg(buf + off, len - off, " ", data->arg2); return (off); } @@ -415,9 +415,9 @@ cmd_buffer_print(struct cmd *self, char *buf, size_t len) off += xsnprintf(buf + off, len - off, " -b %d", data->buffer); if (off < len && data->target != NULL) off += cmd_prarg(buf + off, len - off, " -t ", data->target); - if (off < len && data->arg != NULL) + if (off < len && data->arg != NULL) off += cmd_prarg(buf + off, len - off, " ", data->arg); - if (off < len && data->arg2 != NULL) + if (off < len && data->arg2 != NULL) off += cmd_prarg(buf + off, len - off, " ", data->arg2); return (off); } diff --git a/cmd-kill-session.c b/cmd-kill-session.c index ff0b95e3..26331b79 100644 --- a/cmd-kill-session.c +++ b/cmd-kill-session.c @@ -45,7 +45,7 @@ cmd_kill_session_exec(struct cmd *self, struct cmd_ctx *ctx) { struct cmd_target_data *data = self->data; struct session *s; - struct client *c; + struct client *c; u_int i; if ((s = cmd_find_session(ctx, data->target)) == NULL) diff --git a/cmd-list-buffers.c b/cmd-list-buffers.c index 30235295..0416dfe7 100644 --- a/cmd-list-buffers.c +++ b/cmd-list-buffers.c @@ -71,7 +71,7 @@ cmd_list_buffers_exec(struct cmd *self, struct cmd_ctx *ctx) tmp[50 - 3] = '\0'; strlcat(tmp, "...", sizeof tmp); } - + ctx->print(ctx, "%u: %zu bytes: \"%s\"", idx - 1, size, tmp); } diff --git a/cmd-list-keys.c b/cmd-list-keys.c index 13785fac..d41f890b 100644 --- a/cmd-list-keys.c +++ b/cmd-list-keys.c @@ -75,7 +75,7 @@ cmd_list_keys_exec(struct cmd *self, struct cmd_ctx *ctx) if (used >= sizeof tmp) continue; - if (!(bd->key & KEYC_PREFIX)) { + if (!(bd->key & KEYC_PREFIX)) { used = strlcat(tmp, "(no prefix) ", sizeof tmp); if (used >= sizeof tmp) continue; diff --git a/cmd-list-panes.c b/cmd-list-panes.c index 112a2835..ffb89787 100644 --- a/cmd-list-panes.c +++ b/cmd-list-panes.c @@ -23,7 +23,7 @@ #include "tmux.h" /* - * List panes on given window.. + * List panes on given window. */ int cmd_list_panes_exec(struct cmd *, struct cmd_ctx *); @@ -56,7 +56,7 @@ cmd_list_panes_exec(struct cmd *self, struct cmd_ctx *ctx) n = 0; TAILQ_FOREACH(wp, &wl->window->panes, entry) { gd = wp->base.grid; - + size = 0; for (i = 0; i < gd->hsize; i++) { gl = &gd->linedata[i]; @@ -64,7 +64,7 @@ cmd_list_panes_exec(struct cmd *self, struct cmd_ctx *ctx) size += gl->utf8size * sizeof *gl->utf8data; } size += gd->hsize * sizeof *gd->linedata; - + ctx->print(ctx, "%u: [%ux%u] [history %u/%u, %llu bytes]", n, wp->sx, wp->sy, gd->hsize, gd->hlimit, size); n++; diff --git a/cmd-new-session.c b/cmd-new-session.c index 25a054bc..461e0391 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -184,8 +184,8 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) ctx->error(ctx, "not a terminal"); return (-1); } - - overrides = + + overrides = options_get_string(&global_s_options, "terminal-overrides"); if (tty_open(&ctx->cmdclient->tty, overrides, &cause) != 0) { ctx->error(ctx, "open terminal failed: %s", cause); @@ -267,13 +267,13 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) * Set the client to the new session. If a command client exists, it is * taking this session and needs to get MSG_READY and stay around. */ - if (!detached) { + if (!detached) { if (ctx->cmdclient != NULL) { server_write_client(ctx->cmdclient, MSG_READY, NULL, 0); - ctx->cmdclient->session = s; + ctx->cmdclient->session = s; server_redraw_client(ctx->cmdclient); } else { - ctx->curclient->session = s; + ctx->curclient->session = s; server_redraw_client(ctx->curclient); } } diff --git a/cmd-new-window.c b/cmd-new-window.c index 4cba8883..d7b59b8b 100644 --- a/cmd-new-window.c +++ b/cmd-new-window.c @@ -166,7 +166,7 @@ cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx) if (!data->flag_detached) { session_select(s, wl->idx); server_redraw_session_group(s); - } else + } else server_status_session_group(s); return (0); diff --git a/cmd-paste-buffer.c b/cmd-paste-buffer.c index 7d13ae0a..1abf09a7 100644 --- a/cmd-paste-buffer.c +++ b/cmd-paste-buffer.c @@ -78,7 +78,7 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) paste_free_index(&s->buffers, data->buffer); } - return (0); + return (0); } /* Add bytes to a buffer but change every '\n' to '\r'. */ diff --git a/cmd-pipe-pane.c b/cmd-pipe-pane.c index a88d7ea8..efe79a38 100644 --- a/cmd-pipe-pane.c +++ b/cmd-pipe-pane.c @@ -87,7 +87,7 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx) switch (fork()) { case -1: ctx->error(ctx, "fork error: %s", strerror(errno)); - return (-1); + return (-1); case 0: /* Child process. */ close(pipe_fd[0]); @@ -114,17 +114,17 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx) wp->pipe_fd = pipe_fd[0]; wp->pipe_off = EVBUFFER_LENGTH(wp->event->input); - + wp->pipe_event = bufferevent_new(wp->pipe_fd, NULL, NULL, cmd_pipe_pane_error_callback, wp); bufferevent_enable(wp->pipe_event, EV_WRITE); - + if ((mode = fcntl(wp->pipe_fd, F_GETFL)) == -1) fatal("fcntl failed"); if (fcntl(wp->pipe_fd, F_SETFL, mode|O_NONBLOCK) == -1) fatal("fcntl failed"); if (fcntl(wp->pipe_fd, F_SETFD, FD_CLOEXEC) == -1) - fatal("fcntl failed"); + fatal("fcntl failed"); return (0); } } diff --git a/cmd-previous-layout.c b/cmd-previous-layout.c index 083ac3e9..77e3ebbb 100644 --- a/cmd-previous-layout.c +++ b/cmd-previous-layout.c @@ -43,7 +43,7 @@ cmd_previous_layout_exec(struct cmd *self, struct cmd_ctx *ctx) struct cmd_target_data *data = self->data; struct winlink *wl; u_int layout; - + if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) return (-1); diff --git a/cmd-resize-pane.c b/cmd-resize-pane.c index e8d77176..73a5f820 100644 --- a/cmd-resize-pane.c +++ b/cmd-resize-pane.c @@ -56,7 +56,7 @@ cmd_resize_pane_init(struct cmd *self, int key) cmd_set_flag(&data->chflags, 'L'); if (key == (KEYC_RIGHT | KEYC_CTRL)) cmd_set_flag(&data->chflags, 'R'); - + if (key == (KEYC_UP | KEYC_ESCAPE)) { cmd_set_flag(&data->chflags, 'U'); data->arg = xstrdup("5"); diff --git a/cmd-respawn-window.c b/cmd-respawn-window.c index 2810ea6c..4c8235e7 100644 --- a/cmd-respawn-window.c +++ b/cmd-respawn-window.c @@ -72,7 +72,7 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_ctx *ctx) wp = TAILQ_FIRST(&w->panes); TAILQ_REMOVE(&w->panes, wp, entry); layout_free(w); - window_destroy_panes(w); + window_destroy_panes(w); TAILQ_INSERT_HEAD(&w->panes, wp, entry); window_pane_resize(wp, w->sx, w->sy); if (window_pane_spawn( diff --git a/cmd-select-layout.c b/cmd-select-layout.c index 0dc126f4..2988a44f 100644 --- a/cmd-select-layout.c +++ b/cmd-select-layout.c @@ -52,7 +52,7 @@ cmd_select_layout_init(struct cmd *self, int key) break; case ('2' | KEYC_ESCAPE): data->arg = xstrdup("even-vertical"); - break; + break; case ('3' | KEYC_ESCAPE): data->arg = xstrdup("main-horizontal"); break; @@ -80,7 +80,7 @@ cmd_select_layout_exec(struct cmd *self, struct cmd_ctx *ctx) ctx->error(ctx, "unknown layout or ambiguous: %s", data->arg); return (-1); } - + layout = layout_set_select(wl->window, layout); ctx->info(ctx, "arranging in: %s", layout_set_name(layout)); diff --git a/cmd-send-keys.c b/cmd-send-keys.c index 8b848e76..204d497d 100644 --- a/cmd-send-keys.c +++ b/cmd-send-keys.c @@ -33,7 +33,7 @@ size_t cmd_send_keys_print(struct cmd *, char *, size_t); struct cmd_send_keys_data { char *target; - u_int nkeys; + u_int nkeys; int *keys; }; diff --git a/cmd-server-info.c b/cmd-server-info.c index f0728608..8c85b2c3 100644 --- a/cmd-server-info.c +++ b/cmd-server-info.c @@ -94,12 +94,12 @@ cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx) ctx->print(ctx, "%2d: %s (%d, %d): %s [%ux%u %s] " "[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->flags, + c->tty.sx, c->tty.sy, c->tty.termname, c->flags, c->tty.flags, c->references); } ctx->print(ctx, "%s", ""); - ctx->print(ctx, "Sessions: [%zu/%zu]", + ctx->print(ctx, "Sessions: [%zu/%zu]", sizeof (struct grid_cell), sizeof (struct grid_utf8)); for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { s = ARRAY_ITEM(&sessions, i); @@ -148,7 +148,7 @@ cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx) } ctx->print(ctx, "%s", ""); - ctx->print(ctx, "Terminals:"); + ctx->print(ctx, "Terminals:"); SLIST_FOREACH(term, &tty_terms, entry) { ctx->print(ctx, "%s [references=%u, flags=0x%x]:", term->name, term->references, term->flags); @@ -180,7 +180,7 @@ cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx) } ctx->print(ctx, "%s", ""); - ctx->print(ctx, "Jobs:"); + ctx->print(ctx, "Jobs:"); SLIST_FOREACH(job, &all_jobs, lentry) { ctx->print(ctx, "%s [fd=%d, pid=%d, status=%d, flags=0x%x]", job->cmd, job->fd, job->pid, job->status, job->flags); diff --git a/cmd-set-option.c b/cmd-set-option.c index e58ac7d2..0cd7dca6 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -34,17 +34,17 @@ const char *cmd_set_option_print( void cmd_set_option_string(struct cmd_ctx *, struct options *, const struct set_option_entry *, char *, int); void cmd_set_option_number(struct cmd_ctx *, - struct options *, const struct set_option_entry *, char *); + struct options *, const struct set_option_entry *, char *); void cmd_set_option_keys(struct cmd_ctx *, - struct options *, const struct set_option_entry *, char *); + struct options *, const struct set_option_entry *, char *); void cmd_set_option_colour(struct cmd_ctx *, - struct options *, const struct set_option_entry *, char *); + struct options *, const struct set_option_entry *, char *); void cmd_set_option_attributes(struct cmd_ctx *, - struct options *, const struct set_option_entry *, char *); + struct options *, const struct set_option_entry *, char *); void cmd_set_option_flag(struct cmd_ctx *, - struct options *, const struct set_option_entry *, char *); + struct options *, const struct set_option_entry *, char *); void cmd_set_option_choice(struct cmd_ctx *, - struct options *, const struct set_option_entry *, char *); + struct options *, const struct set_option_entry *, char *); const struct cmd_entry cmd_set_option_entry = { "set-option", "set", @@ -103,7 +103,7 @@ const struct set_option_entry set_session_option_table[] = { { "status-bg", SET_OPTION_COLOUR, 0, 0, NULL }, { "status-fg", SET_OPTION_COLOUR, 0, 0, NULL }, { "status-interval", SET_OPTION_NUMBER, 0, INT_MAX, NULL }, - { "status-justify", + { "status-justify", SET_OPTION_CHOICE, 0, 0, set_option_status_justify_list }, { "status-keys", SET_OPTION_CHOICE, 0, 0, set_option_status_keys_list }, { "status-left", SET_OPTION_STRING, 0, 0, NULL }, @@ -116,11 +116,11 @@ const struct set_option_entry set_session_option_table[] = { { "status-right-bg", SET_OPTION_COLOUR, 0, 0, NULL }, { "status-right-fg", SET_OPTION_COLOUR, 0, 0, NULL }, { "status-right-length", SET_OPTION_NUMBER, 0, SHRT_MAX, NULL }, - { "status-utf8", SET_OPTION_FLAG, 0, 0, NULL }, + { "status-utf8", SET_OPTION_FLAG, 0, 0, NULL }, { "terminal-overrides", SET_OPTION_STRING, 0, 0, NULL }, { "update-environment", SET_OPTION_STRING, 0, 0, NULL }, { "visual-activity", SET_OPTION_FLAG, 0, 0, NULL }, - { "visual-bell", SET_OPTION_FLAG, 0, 0, NULL }, + { "visual-bell", SET_OPTION_FLAG, 0, 0, NULL }, { "visual-content", SET_OPTION_FLAG, 0, 0, NULL }, { NULL, 0, 0, 0, NULL } }; @@ -266,7 +266,7 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) server_redraw_client(c); } - /* + /* * Special-case: kill all persistent jobs if status-left, status-right * or set-titles-string have changed. Persistent jobs are only used by * the status line at the moment so this works XXX. @@ -282,7 +282,7 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) jobs = &c->status_jobs; do { - try_again = 0; + try_again = 0; job = RB_ROOT(jobs); while (job != NULL) { nextjob = RB_NEXT(jobs, jobs, job); @@ -366,7 +366,7 @@ cmd_set_option_string(struct cmd_ctx *ctx, struct options *oo, xasprintf(&newvalue, "%s%s", oldvalue, value); } else newvalue = value; - + o = options_set_string(oo, entry->name, "%s", newvalue); ctx->info(ctx, "set option: %s -> %s", o->name, cmd_set_option_print(entry, o)); diff --git a/cmd-show-buffer.c b/cmd-show-buffer.c index d4484f08..b8c3c05d 100644 --- a/cmd-show-buffer.c +++ b/cmd-show-buffer.c @@ -73,24 +73,24 @@ cmd_show_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) width = s->sx; if (ctx->cmdclient != NULL) width = ctx->cmdclient->tty.sx; - + buf = xmalloc(width + 1); len = 0; - + ptr = in; do { buf[len++] = *ptr++; - + if (len == width || buf[len - 1] == '\n') { if (buf[len - 1] == '\n') len--; buf[len] = '\0'; - ctx->print(ctx, "%s", buf); + ctx->print(ctx, "%s", buf); len = 0; } } while (*ptr != '\0'); - + if (len != 0) { buf[len] = '\0'; ctx->print(ctx, "%s", buf); diff --git a/cmd-show-messages.c b/cmd-show-messages.c index c624af54..84c2d6ce 100644 --- a/cmd-show-messages.c +++ b/cmd-show-messages.c @@ -57,7 +57,7 @@ cmd_show_messages_exec(struct cmd *self, struct cmd_ctx *ctx) tim = ctime(&msg->msg_time); *strchr(tim, '\n') = '\0'; - + ctx->print(ctx, "%s %s", tim, msg->msg); } diff --git a/cmd-show-options.c b/cmd-show-options.c index 3374c64e..d725464c 100644 --- a/cmd-show-options.c +++ b/cmd-show-options.c @@ -43,7 +43,7 @@ const struct cmd_entry cmd_show_options_entry = { int cmd_show_options_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; + struct cmd_target_data *data = self->data; const struct set_option_entry *table; struct session *s; struct winlink *wl; diff --git a/cmd-split-window.c b/cmd-split-window.c index ebe0ffef..6a9c4c9f 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -70,7 +70,7 @@ cmd_split_window_init(struct cmd *self, int key) switch (key) { case '%': data->flag_horizontal = 1; - break; + break; case '"': data->flag_horizontal = 0; break; diff --git a/cmd-string.c b/cmd-string.c index 8e2ec1bf..27b051b1 100644 --- a/cmd-string.c +++ b/cmd-string.c @@ -121,7 +121,7 @@ cmd_string_parse(const char *s, struct cmd_list **cmdlist, char **cause) case EOF: case ' ': case '\t': - if (have_arg) { + if (have_arg) { buf = xrealloc(buf, 1, len + 1); buf[len] = '\0'; diff --git a/cmd-swap-pane.c b/cmd-swap-pane.c index a1bd3de9..bf4b048e 100644 --- a/cmd-swap-pane.c +++ b/cmd-swap-pane.c @@ -110,7 +110,7 @@ cmd_swap_pane_exec(struct cmd *self, struct cmd_ctx *ctx) dst_wp->layout_cell = src_lc; dst_lc->wp = src_wp; src_wp->layout_cell = dst_lc; - + src_wp->window = dst_w; dst_wp->window = src_w; diff --git a/cmd-unlink-window.c b/cmd-unlink-window.c index 15bafc08..a7ca23da 100644 --- a/cmd-unlink-window.c +++ b/cmd-unlink-window.c @@ -63,7 +63,7 @@ cmd_unlink_window_exec(struct cmd *self, struct cmd_ctx *ctx) ctx->error(ctx, "window is only linked to one session"); return (-1); } - + server_unlink_window(s, wl); recalculate_sizes(); diff --git a/cmd.c b/cmd.c index 733f4013..d094427b 100644 --- a/cmd.c +++ b/cmd.c @@ -169,7 +169,7 @@ cmd_free_argv(int argc, char **argv) int i; if (argc == 0) - return; + return; for (i = 0; i < argc; i++) { if (argv[i] != NULL) xfree(argv[i]); @@ -510,7 +510,7 @@ cmd_lookup_session(const char *name, int *ambiguous) * be unique so an exact match can't be ambigious and can just be * returned. */ - for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { + for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { if ((s = ARRAY_ITEM(&sessions, i)) == NULL) continue; if (strcmp(name, s->name) == 0) @@ -522,7 +522,7 @@ cmd_lookup_session(const char *name, int *ambiguous) * be ambiguous. */ sfound = NULL; - for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { + for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { if ((s = ARRAY_ITEM(&sessions, i)) == NULL) continue; if (strncmp(name, s->name, strlen(name)) == 0 || @@ -534,7 +534,7 @@ cmd_lookup_session(const char *name, int *ambiguous) sfound = s; } } - return (sfound); + return (sfound); } /* @@ -558,7 +558,7 @@ cmd_lookup_window(struct session *s, const char *name, int *ambiguous) if ((wl = winlink_find_by_index(&s->windows, idx)) != NULL) return (wl); } - + /* Look for exact matches, error if more than one. */ wlfound = NULL; RB_FOREACH(wl, winlinks, &s->windows) { @@ -584,7 +584,7 @@ cmd_lookup_window(struct session *s, const char *name, int *ambiguous) } wlfound = wl; } - } + } if (wlfound != NULL) return (wlfound); @@ -707,7 +707,7 @@ cmd_find_window(struct cmd_ctx *ctx, const char *arg, struct session **sp) wl = s->curw; else if ((wl = cmd_lookup_window(s, winptr, &ambiguous)) == NULL) goto not_found; - + if (sessptr != NULL) xfree(sessptr); return (wl); @@ -808,7 +808,7 @@ cmd_find_index(struct cmd_ctx *ctx, const char *arg, struct session **sp) ctx->error(ctx, "invalid index: %s", arg); idx = -2; } - + if (sessptr != NULL) xfree(sessptr); return (idx); @@ -830,7 +830,7 @@ no_colon: no_session: if (ambiguous) - ctx->error(ctx, "multiple sessions: %s", arg); + ctx->error(ctx, "multiple sessions: %s", arg); else ctx->error(ctx, "session not found: %s", arg); if (sessptr != NULL) @@ -918,7 +918,7 @@ no_period: /* Try index in the current session and window. */ if ((*wpp = window_pane_at_index(s->curw->window, idx)) == NULL) goto lookup_window; - + return (s->curw); lookup_window: @@ -926,7 +926,7 @@ lookup_window: if ((wl = cmd_find_window(ctx, arg, sp)) != NULL) *wpp = wl->window->active; return (wl); - + error: xfree(winptr); return (NULL); diff --git a/grid-utf8.c b/grid-utf8.c index 5e5cad74..0c829711 100644 --- a/grid-utf8.c +++ b/grid-utf8.c @@ -92,5 +92,5 @@ grid_utf8_compare(const struct grid_utf8 *gu1, const struct grid_utf8 *gu2) return (0); if (memcmp(gu1->data, gu2->data, size) != 0) return (0); - return (1); + return (1); } diff --git a/grid-view.c b/grid-view.c index f6bde853..ba142a1c 100644 --- a/grid-view.c +++ b/grid-view.c @@ -149,7 +149,7 @@ grid_view_insert_lines_region(struct grid *gd, u_int rlower, u_int py, u_int ny) ny2 = rlower + 1 - py - ny; grid_move_lines(gd, rlower + 1 - ny2, py, ny2); - grid_clear(gd, 0, py + ny2, gd->sx, ny - ny2); + grid_clear(gd, 0, py + ny2, gd->sx, ny - ny2); } /* Delete lines. */ @@ -165,7 +165,7 @@ grid_view_delete_lines(struct grid *gd, u_int py, u_int ny) sy = grid_view_y(gd, gd->sy); grid_move_lines(gd, py, py + ny, sy - py - ny); - grid_clear(gd, 0, sy - ny, gd->sx, py + ny - (sy - ny)); + grid_clear(gd, 0, sy - ny, gd->sx, py + ny - (sy - ny)); } /* Delete lines inside scroll region. */ @@ -182,7 +182,7 @@ grid_view_delete_lines_region(struct grid *gd, u_int rlower, u_int py, u_int ny) ny2 = rlower + 1 - py - ny; grid_move_lines(gd, py, py + ny, ny2); - grid_clear(gd, 0, py + ny2, gd->sx, ny - ny2); + grid_clear(gd, 0, py + ny2, gd->sx, ny - ny2); } /* Insert characters. */ diff --git a/grid.c b/grid.c index a49c06bd..b7fa2783 100644 --- a/grid.c +++ b/grid.c @@ -170,7 +170,7 @@ grid_collect_history(struct grid *gd) { u_int yy; - GRID_DEBUG(gd, ""); + GRID_DEBUG(gd, ""); if (gd->hsize < gd->hlimit) return; @@ -183,7 +183,7 @@ grid_collect_history(struct grid *gd) gd->hsize -= yy; } -/* +/* * Scroll the entire visible screen, moving one line into the history. Just * allocate a new line at the bottom and move the history size indicator. */ @@ -192,12 +192,12 @@ grid_scroll_history(struct grid *gd) { u_int yy; - GRID_DEBUG(gd, ""); + GRID_DEBUG(gd, ""); yy = gd->hsize + gd->sy; gd->linedata = xrealloc(gd->linedata, yy + 1, sizeof *gd->linedata); memset(&gd->linedata[yy], 0, sizeof gd->linedata[yy]); - + gd->hsize++; } @@ -208,7 +208,7 @@ grid_scroll_history_region(struct grid *gd, u_int upper, u_int lower) struct grid_line *gl_history, *gl_upper, *gl_lower; u_int yy; - GRID_DEBUG(gd, "upper=%u, lower=%u", upper, lower); + GRID_DEBUG(gd, "upper=%u, lower=%u", upper, lower); /* Create a space for a new line. */ yy = gd->hsize + gd->sy; @@ -354,7 +354,7 @@ grid_clear(struct grid *gd, u_int px, u_int py, u_int nx, u_int ny) { u_int xx, yy; - GRID_DEBUG(gd, "px=%u, py=%u, nx=%u, ny=%u", px, py, nx, ny); + GRID_DEBUG(gd, "px=%u, py=%u, nx=%u, ny=%u", px, py, nx, ny); if (nx == 0 || ny == 0) return; @@ -395,7 +395,7 @@ grid_clear_lines(struct grid *gd, u_int py, u_int ny) struct grid_line *gl; u_int yy; - GRID_DEBUG(gd, "py=%u, ny=%u", py, ny); + GRID_DEBUG(gd, "py=%u, ny=%u", py, ny); if (ny == 0) return; @@ -421,7 +421,7 @@ grid_move_lines(struct grid *gd, u_int dy, u_int py, u_int ny) { u_int yy; - GRID_DEBUG(gd, "dy=%u, py=%u, ny=%u", dy, py, ny); + GRID_DEBUG(gd, "dy=%u, py=%u, ny=%u", dy, py, ny); if (ny == 0 || py == dy) return; @@ -460,7 +460,7 @@ grid_move_cells(struct grid *gd, u_int dx, u_int px, u_int py, u_int nx) struct grid_line *gl; u_int xx; - GRID_DEBUG(gd, "dx=%u, px=%u, py=%u, nx=%u", dx, px, py, nx); + GRID_DEBUG(gd, "dx=%u, px=%u, py=%u, nx=%u", dx, px, py, nx); if (nx == 0 || px == dx) return; @@ -499,8 +499,8 @@ grid_move_cells(struct grid *gd, u_int dx, u_int px, u_int py, u_int nx) char * grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx) { - const struct grid_cell *gc; - const struct grid_utf8 *gu; + const struct grid_cell *gc; + const struct grid_utf8 *gu; char *buf; size_t len, off, size; u_int xx; @@ -535,14 +535,14 @@ grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx) buf[off++] = gc->data; } } - + while (off > 0 && buf[off - 1] == ' ') off--; buf[off] = '\0'; return (buf); } -/* +/* * Duplicate a set of lines between two grids. If there aren't enough lines in * either source or destination, the number of lines is limited to the number * available. diff --git a/input-keys.c b/input-keys.c index cab3af79..b731f6dc 100644 --- a/input-keys.c +++ b/input-keys.c @@ -81,7 +81,7 @@ struct input_key_ent input_keys[] = { { KEYC_DOWN|KEYC_CTRL, "\033[B", INPUTKEY_CURSOR }, { KEYC_RIGHT|KEYC_CTRL, "\033[C", INPUTKEY_CURSOR }, { KEYC_LEFT|KEYC_CTRL, "\033[D", INPUTKEY_CURSOR }, - + { KEYC_UP, "\033OA", INPUTKEY_CURSOR }, { KEYC_DOWN, "\033OB", INPUTKEY_CURSOR }, { KEYC_RIGHT, "\033OC", INPUTKEY_CURSOR }, @@ -122,7 +122,7 @@ struct input_key_ent input_keys[] = { { KEYC_KP_EIGHT, "8", 0 }, { KEYC_KP_NINE, "9", 0 }, { KEYC_KP_PLUS, "+", 0 }, - { KEYC_KP_FOUR, "4", 0 }, + { KEYC_KP_FOUR, "4", 0 }, { KEYC_KP_FIVE, "5", 0 }, { KEYC_KP_SIX, "6", 0 }, { KEYC_KP_ONE, "1", 0 }, @@ -157,7 +157,7 @@ input_key(struct window_pane *wp, int key) return; } - /* + /* * Then try to look this up as an xterm key, if the flag to output them * is set. */ diff --git a/input.c b/input.c index 1f529df0..29d0f254 100644 --- a/input.c +++ b/input.c @@ -230,7 +230,7 @@ input_init(struct window_pane *wp) ictx->string_len = 0; ictx->string_buf = NULL; - memcpy(&ictx->cell, &grid_default_cell, sizeof ictx->cell); + memcpy(&ictx->cell, &grid_default_cell, sizeof ictx->cell); memcpy(&ictx->saved_cell, &grid_default_cell, sizeof ictx->saved_cell); ictx->saved_cx = 0; @@ -297,7 +297,7 @@ input_state_first(u_char ch, struct input_ctx *ictx) } #if 0 - if (INPUT_C1CONTROL(ch)) { + if (INPUT_C1CONTROL(ch)) { ch -= 0x40; if (ch == '[') input_state(ictx, input_state_sequence_first); @@ -591,7 +591,7 @@ input_handle_character(u_char ch, struct input_ctx *ictx) if (ch > 0x7f && options_get_number(&wp->window->options, "utf8")) { if (utf8_open(&ictx->utf8data, ch)) { - log_debug2("-- utf8 size %zu: %zu: %hhu (%c)", + log_debug2("-- utf8 size %zu: %zu: %hhu (%c)", ictx->utf8data.size, ictx->off, ch, ch); input_state(ictx, input_state_utf8); return; @@ -945,7 +945,7 @@ input_handle_sequence_da(struct input_ctx *ictx) return; if (n != 0) return; - + bufferevent_write(wp->event, "\033[?1;2c", (sizeof "\033[?1;2c") - 1); } @@ -1164,7 +1164,7 @@ input_handle_sequence_sm(struct input_ctx *ictx) log_debug("kcursor on"); break; case 3: /* DECCOLM */ - screen_write_cursormove(&ictx->ctx, 0, 0); + screen_write_cursormove(&ictx->ctx, 0, 0); screen_write_clearscreen(&ictx->ctx); break; case 25: /* TCEM */ @@ -1240,7 +1240,7 @@ input_handle_sequence_rm(struct input_ctx *ictx) log_debug("kcursor off"); break; case 3: /* DECCOLM */ - screen_write_cursormove(&ictx->ctx, 0, 0); + screen_write_cursormove(&ictx->ctx, 0, 0); screen_write_clearscreen(&ictx->ctx); break; case 25: /* TCEM */ @@ -1257,7 +1257,7 @@ input_handle_sequence_rm(struct input_ctx *ictx) sx = screen_size_x(s); sy = screen_size_y(s); - /* + /* * Exit alternative screen mode and restore the copied * grid. */ @@ -1284,7 +1284,7 @@ input_handle_sequence_rm(struct input_ctx *ictx) * Turn history back on (so resize can use it) and then * resize back to the current size. */ - wp->base.grid->flags |= GRID_HISTORY; + wp->base.grid->flags |= GRID_HISTORY; if (sy > wp->saved_grid->sy) screen_resize(s, sx, sy); @@ -1372,7 +1372,7 @@ input_handle_sequence_sgr(struct input_ctx *ictx) if (ARRAY_LENGTH(&ictx->args) == 0) { attr = gc->attr; memcpy(gc, &grid_default_cell, sizeof *gc); - gc->attr |= (attr & GRID_ATTR_CHARSET); + gc->attr |= (attr & GRID_ATTR_CHARSET); return; } diff --git a/job.c b/job.c index ba8f33f0..28ba3e72 100644 --- a/job.c +++ b/job.c @@ -80,7 +80,7 @@ job_add(struct jobs *jobs, int flags, struct client *c, const char *cmd, void (*callbackfn)(struct job *), void (*freefn)(void *), void *data) { struct job *job; - + job = xmalloc(sizeof *job); job->cmd = xstrdup(cmd); job->pid = -1; @@ -183,7 +183,7 @@ job_run(struct job *job) if (job->event != NULL) bufferevent_free(job->event); - job->event = + job->event = bufferevent_new(job->fd, NULL, NULL, job_callback, job); bufferevent_enable(job->event, EV_READ); @@ -216,7 +216,7 @@ job_died(struct job *job, int status) { job->status = status; job->pid = -1; - + if (job->fd == -1) { if (job->callbackfn != NULL) job->callbackfn(job); diff --git a/key-bindings.c b/key-bindings.c index e3045ec0..29dedbb2 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -61,11 +61,11 @@ key_bindings_add(int key, int can_repeat, struct cmd_list *cmdlist) struct key_binding *bd; key_bindings_remove(key); - + bd = xmalloc(sizeof *bd); bd->key = key; SPLAY_INSERT(key_bindings, &key_bindings, bd); - + bd->can_repeat = can_repeat; bd->cmdlist = cmdlist; } @@ -104,9 +104,9 @@ key_bindings_init(void) } table[] = { { ' ', 0, &cmd_next_layout_entry }, { '!', 0, &cmd_break_pane_entry }, - { '"', 0, &cmd_split_window_entry }, + { '"', 0, &cmd_split_window_entry }, { '#', 0, &cmd_list_buffers_entry }, - { '%', 0, &cmd_split_window_entry }, + { '%', 0, &cmd_split_window_entry }, { '&', 0, &cmd_confirm_before_entry }, { ',', 0, &cmd_command_prompt_entry }, { '-', 0, &cmd_delete_buffer_entry }, @@ -162,7 +162,7 @@ key_bindings_init(void) { KEYC_LEFT | KEYC_ESCAPE, 1, &cmd_resize_pane_entry }, { KEYC_RIGHT | KEYC_ESCAPE, 1, &cmd_resize_pane_entry }, { KEYC_UP | KEYC_CTRL, 1, &cmd_resize_pane_entry }, - { KEYC_DOWN | KEYC_CTRL, 1, &cmd_resize_pane_entry }, + { KEYC_DOWN | KEYC_CTRL, 1, &cmd_resize_pane_entry }, { KEYC_LEFT | KEYC_CTRL, 1, &cmd_resize_pane_entry }, { KEYC_RIGHT | KEYC_CTRL, 1, &cmd_resize_pane_entry }, }; @@ -199,7 +199,7 @@ key_bindings_error(struct cmd_ctx *ctx, const char *fmt, ...) va_end(ap); *msg = toupper((u_char) *msg); - status_message_set(ctx->curclient, "%s", msg); + status_message_set(ctx->curclient, "%s", msg); xfree(msg); } @@ -232,7 +232,7 @@ key_bindings_info(struct cmd_ctx *ctx, const char *fmt, ...) va_end(ap); *msg = toupper((u_char) *msg); - status_message_set(ctx->curclient, "%s", msg); + status_message_set(ctx->curclient, "%s", msg); xfree(msg); } diff --git a/key-string.c b/key-string.c index 857d31d6..37b4928f 100644 --- a/key-string.c +++ b/key-string.c @@ -136,7 +136,7 @@ key_string_lookup_string(const char *string) key = (u_char) ptr[0]; } - /* + /* * Figure out if the single character in key is a valid ctrl * key. */ @@ -150,7 +150,7 @@ key_string_lookup_string(const char *string) return (key - 96); return (KEYC_NONE); } - + if ((string[0] == 'M' || string[0] == 'm') && string[1] == '-') { ptr = string + 2; if (ptr[0] == '\0') diff --git a/layout-set.c b/layout-set.c index 8c54a166..2436a0f5 100644 --- a/layout-set.c +++ b/layout-set.c @@ -295,7 +295,7 @@ layout_set_main_h(struct window *w) continue; } - /* Add in the columns. */ + /* Add in the columns. */ layout_make_node(lcrow, LAYOUT_LEFTRIGHT); for (i = 0; i < columns; i++) { /* Create and add a pane cell. */ @@ -312,11 +312,11 @@ layout_set_main_h(struct window *w) /* Adjust the row to fit the full width if necessary. */ if (i == columns) i--; - used = ((i + 1) * width) - 1; - if (w->sx <= used) - continue; - lcchild = TAILQ_LAST(&lcrow->cells, layout_cells); - layout_resize_adjust(lcchild, LAYOUT_LEFTRIGHT, w->sx - used); + used = ((i + 1) * width) - 1; + if (w->sx <= used) + continue; + lcchild = TAILQ_LAST(&lcrow->cells, layout_cells); + layout_resize_adjust(lcchild, LAYOUT_LEFTRIGHT, w->sx - used); } /* Adjust the last row height to fit if necessary. */ @@ -422,10 +422,10 @@ layout_set_main_v(struct window *w) if (i == rows) i--; used = ((i + 1) * height) - 1; - if (w->sy <= used) - continue; - lcchild = TAILQ_LAST(&lccolumn->cells, layout_cells); - layout_resize_adjust(lcchild, LAYOUT_TOPBOTTOM, w->sy - used); + if (w->sy <= used) + continue; + lcchild = TAILQ_LAST(&lccolumn->cells, layout_cells); + layout_resize_adjust(lcchild, LAYOUT_TOPBOTTOM, w->sy - used); } /* Adjust the last column width to fit if necessary. */ diff --git a/layout.c b/layout.c index 0cf6e387..7835e3f9 100644 --- a/layout.c +++ b/layout.c @@ -45,13 +45,13 @@ layout_create_cell(struct layout_cell *lcparent) lc->parent = lcparent; TAILQ_INIT(&lc->cells); - + lc->sx = UINT_MAX; lc->sy = UINT_MAX; - + lc->xoff = UINT_MAX; lc->yoff = UINT_MAX; - + lc->wp = NULL; return (lc); @@ -201,8 +201,8 @@ layout_fix_panes(struct window *w, u_int wsx, u_int wsy) if (sx < 1) sx = lc->sx; } - - /* + + /* * Similarly for the vertical size; the minimum vertical size * is two because scroll regions cannot be one line. */ @@ -231,7 +231,7 @@ layout_resize_check(struct layout_cell *lc, enum layout_type type) available = lc->sx; else available = lc->sy; - + if (available > PANE_MINIMUM) available -= PANE_MINIMUM; else @@ -269,7 +269,7 @@ layout_resize_adjust(struct layout_cell *lc, enum layout_type type, int change) lc->sx += change; else lc->sy += change; - + /* If this is a leaf cell, that is all that is necessary. */ if (type == LAYOUT_WINDOWPANE) return; @@ -281,8 +281,8 @@ layout_resize_adjust(struct layout_cell *lc, enum layout_type type, int change) return; } - /* - * Child cell runs in the same direction. Adjust each child equally + /* + * Child cell runs in the same direction. Adjust each child equally * until no further change is possible. */ while (change != 0) { @@ -327,10 +327,10 @@ layout_resize(struct window *w, u_int sx, u_int sy) struct layout_cell *lc = w->layout_root; int xlimit, ylimit, xchange, ychange; - /* + /* * Adjust horizontally. Do not attempt to reduce the layout lower than * the minimum (more than the amount returned by layout_resize_check). - * + * * This can mean that the window size is smaller than the total layout * size: redrawing this is handled at a higher level, but it does leave * a problem with growing the window size here: if the current size is @@ -366,7 +366,7 @@ layout_resize(struct window *w, u_int sx, u_int sy) } if (ychange != 0) layout_resize_adjust(lc, LAYOUT_TOPBOTTOM, ychange); - + /* Fix cell offsets. */ layout_fix_offsets(lc); layout_fix_panes(w, sx, sy); @@ -408,7 +408,7 @@ layout_resize_pane(struct window_pane *wp, enum layout_type type, int change) if (size == 0) /* no more change possible */ break; } - + /* Fix cell offsets. */ layout_fix_offsets(wp->window->layout_root); layout_fix_panes(wp->window, wp->window->sx, wp->window->sy); @@ -423,14 +423,14 @@ layout_resize_pane_grow( /* Growing. Always add to the current cell. */ lcadd = lc; - + /* Look towards the tail for a suitable cell for reduction. */ lcremove = TAILQ_NEXT(lc, entry); while (lcremove != NULL) { size = layout_resize_check(lcremove, type); if (size > 0) break; - lcremove = TAILQ_NEXT(lcremove, entry); + lcremove = TAILQ_NEXT(lcremove, entry); } /* If none found, look towards the head. */ @@ -514,7 +514,7 @@ layout_split_pane(struct window_pane *wp, default: fatalx("bad layout type"); } - + if (lc->parent != NULL && lc->parent->type == type) { /* * If the parent exists and is of the same type as the split, @@ -528,7 +528,7 @@ layout_split_pane(struct window_pane *wp, /* * Otherwise create a new parent and insert it. */ - + /* Create and insert the replacement parent. */ lcparent = layout_create_cell(lc->parent); layout_make_node(lcparent, type); @@ -537,11 +537,11 @@ layout_split_pane(struct window_pane *wp, wp->window->layout_root = lcparent; else TAILQ_REPLACE(&lc->parent->cells, lc, lcparent, entry); - + /* Insert the old cell. */ lc->parent = lcparent; TAILQ_INSERT_HEAD(&lcparent->cells, lc, entry); - + /* Create the new child cell. */ lcnew = layout_create_cell(lcparent); TAILQ_INSERT_TAIL(&lcparent->cells, lcnew, entry); @@ -554,7 +554,7 @@ layout_split_pane(struct window_pane *wp, case LAYOUT_LEFTRIGHT: if (size < 0) size2 = ((sx + 1) / 2) - 1; - else + else size2 = size; if (size2 < PANE_MINIMUM) size2 = PANE_MINIMUM; @@ -600,7 +600,7 @@ layout_close_pane(struct window_pane *wp) lc = wp->layout_cell; lcparent = lc->parent; - /* + /* * If no parent, this is the last pane so window close is imminent and * there is no need to resize anything. */ @@ -623,8 +623,8 @@ layout_close_pane(struct window_pane *wp) /* Remove this from the parent's list. */ TAILQ_REMOVE(&lcparent->cells, lc, entry); layout_free_cell(lc); - - /* + + /* * If the parent now has one cell, remove the parent from the tree and * replace it by that cell. */ diff --git a/log.c b/log.c index 3aeec59f..35728855 100644 --- a/log.c +++ b/log.c @@ -183,7 +183,7 @@ log_vfatal(const char *msg, va_list ap) log_vwrite(LOG_CRIT, fmt, ap); } else { if (asprintf(&fmt, "fatal: %s", msg) == -1) - exit(1); + exit(1); log_vwrite(LOG_CRIT, fmt, ap); } free(fmt); diff --git a/mode-key.c b/mode-key.c index 401d232f..f91f9c64 100644 --- a/mode-key.c +++ b/mode-key.c @@ -42,7 +42,7 @@ /* Edit keys command strings. */ struct mode_key_cmdstr mode_key_cmdstr_edit[] = { { MODEKEYEDIT_BACKSPACE, "backspace" }, - { MODEKEYEDIT_CANCEL, "cancel" }, + { MODEKEYEDIT_CANCEL, "cancel" }, { MODEKEYEDIT_COMPLETE, "complete" }, { MODEKEYEDIT_CURSORLEFT, "cursor-left" }, { MODEKEYEDIT_CURSORRIGHT, "cursor-right" }, @@ -61,7 +61,7 @@ struct mode_key_cmdstr mode_key_cmdstr_edit[] = { { 0, NULL } }; - + /* Choice keys command strings. */ struct mode_key_cmdstr mode_key_cmdstr_choice[] = { { MODEKEYCHOICE_CANCEL, "cancel" }, @@ -195,14 +195,14 @@ const struct mode_key_entry mode_key_vi_copy[] = { { KEYC_RIGHT, 0, MODEKEYCOPY_RIGHT }, { KEYC_UP | KEYC_CTRL, 0, MODEKEYCOPY_SCROLLUP }, { KEYC_UP, 0, MODEKEYCOPY_UP }, - + { 0, -1, 0 } }; struct mode_key_tree mode_key_tree_vi_copy; /* emacs editing keys. */ const struct mode_key_entry mode_key_emacs_edit[] = { - { '\001' /* C-a */, 0, MODEKEYEDIT_STARTOFLINE }, + { '\001' /* C-a */, 0, MODEKEYEDIT_STARTOFLINE }, { '\002' /* C-b */, 0, MODEKEYEDIT_CURSORLEFT }, { '\003' /* C-c */, 0, MODEKEYEDIT_CANCEL }, { '\004' /* C-d */, 0, MODEKEYEDIT_DELETE }, @@ -218,7 +218,7 @@ const struct mode_key_entry mode_key_emacs_edit[] = { { '\031' /* C-y */, 0, MODEKEYEDIT_PASTE }, { '\033' /* Escape */, 0, MODEKEYEDIT_CANCEL }, { '\r', 0, MODEKEYEDIT_ENTER }, - { 'm' | KEYC_ESCAPE, 0, MODEKEYEDIT_STARTOFLINE }, + { 'm' | KEYC_ESCAPE, 0, MODEKEYEDIT_STARTOFLINE }, { KEYC_BSPACE, 0, MODEKEYEDIT_BACKSPACE }, { KEYC_DC, 0, MODEKEYEDIT_DELETE }, { KEYC_DOWN, 0, MODEKEYEDIT_HISTORYDOWN }, @@ -287,7 +287,7 @@ const struct mode_key_entry mode_key_emacs_copy[] = { { KEYC_UP | KEYC_ESCAPE, 0, MODEKEYCOPY_HALFPAGEUP }, { KEYC_UP, 0, MODEKEYCOPY_UP }, - { 0, -1, 0 } + { 0, -1, 0 } }; struct mode_key_tree mode_key_tree_emacs_copy; @@ -343,7 +343,7 @@ const struct mode_key_table * mode_key_findtable(const char *name) { const struct mode_key_table *mtab; - + for (mtab = mode_key_tables; mtab->name != NULL; mtab++) { if (strcasecmp(name, mtab->name) == 0) return (mtab); diff --git a/names.c b/names.c index a468b59b..0bdcbe3e 100644 --- a/names.c +++ b/names.c @@ -59,7 +59,7 @@ window_name_callback(unused int fd, unused short events, void *data) if (name == NULL) wname = default_window_name(w); else { - /* + /* * If tmux is using the default command, it will be a login * shell and argv[0] may have a - prefix. Remove this if it is * present. Ick. @@ -71,13 +71,13 @@ window_name_callback(unused int fd, unused short events, void *data) wname = parse_window_name(name); xfree(name); } - + if (w->active->fd == -1) { xasprintf(&name, "%s[dead]", wname); xfree(wname); wname = name; } - + if (strcmp(wname, w->name) == 0) xfree(wname); else { diff --git a/paste.c b/paste.c index 81dad57f..4596ce95 100644 --- a/paste.c +++ b/paste.c @@ -106,7 +106,7 @@ paste_free_index(struct paste_stack *ps, u_int idx) return (0); } -/* +/* * Add an item onto the top of the stack, freeing the bottom if at limit. Note * that the caller is responsible for allocating data. */ @@ -133,7 +133,7 @@ paste_add(struct paste_stack *ps, char *data, size_t size, u_int limit) } -/* +/* * Replace an item on the stack. Note that the caller is responsible for * allocating data. */ diff --git a/screen-redraw.c b/screen-redraw.c index 105cd4f4..03dd52db 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -67,7 +67,7 @@ screen_redraw_cell_border(struct client *c, u_int px, u_int py) } /* Top/bottom borders. */ - if ((wp->xoff == 0 || px >= wp->xoff - 1) && + if ((wp->xoff == 0 || px >= wp->xoff - 1) && px <= wp->xoff + wp->sx) { if (wp->yoff != 0 && py == wp->yoff - 1) return (1); @@ -105,7 +105,7 @@ screen_redraw_check_cell(struct client *c, u_int px, u_int py) if (!screen_redraw_cell_border(c, px, py)) return (CELL_INSIDE); - /* + /* * Construct a bitmask of whether the cells to the left (bit * 4), right, top, and bottom (bit 1) of this cell are borders. */ @@ -119,7 +119,7 @@ screen_redraw_check_cell(struct client *c, u_int px, u_int py) if (py <= w->sy && screen_redraw_cell_border(c, px, py + 1)) borders |= 1; - /* + /* * Figure out what kind of border this cell is. Only one bit * set doesn't make sense (can't have a border cell with no * others connected). @@ -263,7 +263,7 @@ screen_redraw_draw_number(struct client *c, struct window_pane *wp) tty_puts(tty, buf); return; } - + px -= len * 3; py -= 2; @@ -275,7 +275,7 @@ screen_redraw_draw_number(struct client *c, struct window_pane *wp) if (*ptr < '0' || *ptr > '9') continue; idx = *ptr - '0'; - + for (j = 0; j < 5; j++) { for (i = px; i < px + 5; i++) { tty_cursor(tty, xoff + i, yoff + py + j); diff --git a/screen-write.c b/screen-write.c index 93c239a6..e26959fd 100644 --- a/screen-write.c +++ b/screen-write.c @@ -183,7 +183,7 @@ screen_write_vnputs(struct screen_write_ctx *ctx, ssize_t maxlen, break; } size += utf8data.width; - + gc->flags |= GRID_FLAG_UTF8; screen_write_cell(ctx, gc, &utf8data); gc->flags &= ~GRID_FLAG_UTF8; @@ -376,7 +376,7 @@ screen_write_copy(struct screen_write_ctx *ctx, bx = gl->cellsize; else bx = px + nx; - + for (xx = ax; xx < bx; xx++) { if (xx >= gl->cellsize) gc = &grid_default_cell; @@ -646,7 +646,7 @@ screen_write_insertline(struct screen_write_ctx *ctx, u_int ny) ny = s->rlower + 1 - s->cy; if (ny == 0) return; - + screen_write_initctx(ctx, &ttyctx, 0); if (s->cy < s->rupper || s->cy > s->rlower) @@ -682,7 +682,7 @@ screen_write_deleteline(struct screen_write_ctx *ctx, u_int ny) tty_write(tty_cmd_deleteline, &ttyctx); return; } - + if (ny > s->rlower + 1 - s->cy) ny = s->rlower + 1 - s->cy; if (ny == 0) @@ -728,7 +728,7 @@ screen_write_clearendofline(struct screen_write_ctx *ctx) if (s->cx <= sx - 1) grid_view_clear(s->grid, s->cx, s->cy, sx - s->cx, 1); - tty_write(tty_cmd_clearendofline, &ttyctx); + tty_write(tty_cmd_clearendofline, &ttyctx); } /* Clear to start of line from cursor. */ @@ -863,7 +863,7 @@ screen_write_linefeed(struct screen_write_ctx *ctx, int wrapped) s->cy++; ttyctx.num = wrapped; - tty_write(tty_cmd_linefeed, &ttyctx); + tty_write(tty_cmd_linefeed, &ttyctx); } /* Carriage return (cursor to start of line). */ @@ -988,7 +988,7 @@ screen_write_cell(struct screen_write_ctx *ctx, /* * If the width is zero, combine onto the previous character, if - * there is space. + * there is space. */ if (width == 0) { if (screen_write_combine(ctx, utf8data) == 0) { diff --git a/screen.c b/screen.c index bcf52099..a9fa81ec 100644 --- a/screen.c +++ b/screen.c @@ -51,7 +51,7 @@ screen_reinit(struct screen *s) s->rlower = screen_size_y(s) - 1; s->mode = MODE_CURSOR; - + screen_reset_tabs(s); grid_clear_lines(s->grid, s->grid->hsize, s->grid->sy); @@ -152,12 +152,12 @@ screen_resize_y(struct screen *s, u_int sy) fatalx("zero size"); oldy = screen_size_y(s); - /* + /* * When resizing: * * If the height is decreasing, delete lines from the bottom until * hitting the cursor, then push lines from the top into the history. - * + * * When increasing, pull as many lines as possible from the history to * the top, then fill the remaining with blanks at the bottom. */ @@ -191,7 +191,7 @@ screen_resize_y(struct screen *s, u_int sy) grid_view_delete_lines(gd, 0, available); } s->cy -= needed; - } + } /* Resize line arrays. */ gd->linedata = xrealloc( diff --git a/server-client.c b/server-client.c index e0fcfd04..80b4429c 100644 --- a/server-client.c +++ b/server-client.c @@ -36,7 +36,7 @@ void server_client_reset_state(struct client *); int server_client_msg_dispatch(struct client *); void server_client_msg_command(struct client *, struct msg_command_data *); void server_client_msg_identify( - struct client *, struct msg_identify_data *, int); + struct client *, struct msg_identify_data *, int); void server_client_msg_shell(struct client *); void printflike2 server_client_msg_error(struct cmd_ctx *, const char *, ...); @@ -62,7 +62,7 @@ server_client_create(int fd) c->references = 0; imsg_init(&c->ibuf, fd); server_update_event(c); - + if (gettimeofday(&c->creation_time, NULL) != 0) fatal("gettimeofday failed"); memcpy(&c->activity_time, &c->creation_time, sizeof c->activity_time); @@ -189,7 +189,7 @@ server_client_callback(int fd, short events, void *data) goto client_lost; } - server_update_event(c); + server_update_event(c); return; client_lost: @@ -270,7 +270,7 @@ server_client_handle_key(int key, struct mouse_event *mouse, void *data) oo = &c->session->options; /* Special case: number keys jump to pane in identify mode. */ - if (c->flags & CLIENT_IDENTIFY && key >= '0' && key <= '9') { + if (c->flags & CLIENT_IDENTIFY && key >= '0' && key <= '9') { wp = window_pane_at_index(w, key - '0'); if (wp != NULL && window_pane_visible(wp)) window_set_active_pane(w, wp); @@ -348,7 +348,7 @@ server_client_handle_key(int key, struct mouse_event *mouse, void *data) xtimeout = options_get_number(&c->session->options, "repeat-time"); if (xtimeout != 0 && bd->can_repeat) { c->flags |= CLIENT_PREFIX|CLIENT_REPEAT; - + tv.tv_sec = xtimeout / 1000; tv.tv_usec = (xtimeout % 1000) * 1000L; evtimer_del(&c->repeat_timer); @@ -489,7 +489,7 @@ server_client_set_title(struct client *c) char *title; template = options_get_string(&s->options, "set-titles-string"); - + title = status_replace(c, NULL, template, time(NULL), 1); if (c->title == NULL || strcmp(title, c->title) != 0) { if (c->title != NULL) @@ -743,14 +743,14 @@ server_client_msg_shell(struct client *c) { struct msg_shell_data data; const char *shell; - + shell = options_get_string(&global_s_options, "default-shell"); if (*shell == '\0' || areshell(shell)) shell = _PATH_BSHELL; if (strlcpy(data.shell, shell, sizeof data.shell) >= sizeof data.shell) strlcpy(data.shell, _PATH_BSHELL, sizeof data.shell); - + server_write_client(c, MSG_SHELL, &data, sizeof data); c->flags |= CLIENT_BAD; /* it will die after exec */ } diff --git a/server-fn.c b/server-fn.c index 90cf9ae1..b8207ca2 100644 --- a/server-fn.c +++ b/server-fn.c @@ -61,7 +61,7 @@ server_write_client( return; log_debug("writing %d to client %d", type, c->ibuf.fd); imsg_compose(ibuf, type, PROTOCOL_VERSION, -1, -1, (void *) buf, len); - server_update_event(c); + server_update_event(c); } void @@ -208,7 +208,7 @@ server_lock_session(struct session *s) if (c == NULL || c->session == NULL || c->session != s) continue; server_lock_client(c); - } + } } void @@ -225,7 +225,7 @@ server_lock_client(struct client *c) cmdlen = strlcpy(lockdata.cmd, cmd, sizeof lockdata.cmd); if (cmdlen >= sizeof lockdata.cmd) return; - + tty_stop_tty(&c->tty); tty_raw(&c->tty, tty_term_string(c->tty.term, TTYC_SMCUP)); tty_raw(&c->tty, tty_term_string(c->tty.term, TTYC_CLEAR)); @@ -240,14 +240,14 @@ server_kill_window(struct window *w) struct session *s; struct winlink *wl; u_int i; - + for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { s = ARRAY_ITEM(&sessions, i); if (s == NULL || !session_has(s, w)) continue; if ((wl = winlink_find_by_window(&s->windows, w)) == NULL) continue; - + if (session_detach(s, wl)) server_destroy_session_group(s); else { @@ -357,7 +357,7 @@ server_destroy_session(struct session *s) { struct client *c; u_int i; - + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); if (c == NULL || c->session != s) @@ -376,7 +376,7 @@ server_set_identify(struct client *c) delay = options_get_number(&c->session->options, "display-panes-time"); tv.tv_sec = delay / 1000; tv.tv_usec = (delay % 1000) * 1000L; - + evtimer_del(&c->identify_timer); evtimer_set(&c->identify_timer, server_callback_identify, c); evtimer_add(&c->identify_timer, &tv); @@ -417,5 +417,5 @@ server_update_event(struct client *c) events |= EV_WRITE; event_del(&c->event); event_set(&c->event, c->ibuf.fd, events, server_client_callback, c); - event_add(&c->event, NULL); + event_add(&c->event, NULL); } diff --git a/server-window.c b/server-window.c index 319c4478..048077e0 100644 --- a/server-window.c +++ b/server-window.c @@ -81,7 +81,7 @@ server_window_loop(void) s = ARRAY_ITEM(&sessions, j); if (s == NULL || !session_has(s, w)) continue; - + if (server_window_check_bell(s, w) || server_window_check_activity(s, w)) server_status_session(s); @@ -121,7 +121,7 @@ server_window_check_bell(struct session *s, struct window *w) tty_putcode(&c->tty, TTYC_BEL); continue; } - if (c->session->curw->window == w) { + if (c->session->curw->window == w) { status_message_set(c, "Bell in current window"); continue; } @@ -137,7 +137,7 @@ server_window_check_bell(struct session *s, struct window *w) c = ARRAY_ITEM(&clients, i); if (c == NULL || c->session != s) continue; - if (c->session->curw->window != w) + if (c->session->curw->window != w) continue; if (!visual) { tty_putcode(&c->tty, TTYC_BEL); @@ -163,7 +163,7 @@ server_window_check_activity(struct session *s, struct window *w) if (s->curw->window == w) return (0); - if (!options_get_number(&w->options, "monitor-activity")) + if (!options_get_number(&w->options, "monitor-activity")) return (0); if (session_alert_has_window(s, w, WINDOW_ACTIVITY)) @@ -172,7 +172,7 @@ server_window_check_activity(struct session *s, struct window *w) if (s->flags & SESSION_UNATTACHED) return (0); - if (options_get_number(&s->options, "visual-activity")) { + if (options_get_number(&s->options, "visual-activity")) { for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); if (c == NULL || c->session != s) @@ -193,7 +193,7 @@ server_window_check_content( struct client *c; u_int i; char *found, *ptr; - + if (!(w->flags & WINDOW_ACTIVITY)) /* activity for new content */ return (0); if (s->curw->window == w) @@ -208,12 +208,12 @@ server_window_check_content( if ((found = window_pane_search(wp, ptr, NULL)) == NULL) return (0); - xfree(found); + xfree(found); session_alert_add(s, w, WINDOW_CONTENT); if (s->flags & SESSION_UNATTACHED) return (0); - if (options_get_number(&s->options, "visual-content")) { + if (options_get_number(&s->options, "visual-content")) { for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); if (c == NULL || c->session != s) diff --git a/server.c b/server.c index 60090d5e..4eb78d60 100644 --- a/server.c +++ b/server.c @@ -216,7 +216,7 @@ server_loop(void) key_bindings_clean(); server_clean_dead(); - } + } } /* Check if the server should be shutting down (no more clients or windows). */ @@ -454,7 +454,7 @@ server_child_exited(pid_t pid, int status) break; } } - } + } SLIST_FOREACH(job, &all_jobs, lentry) { if (pid == job->pid) { @@ -554,7 +554,7 @@ server_lock_server(void) void server_lock_sessions(void) { - struct session *s; + struct session *s; u_int i; int timeout; time_t t; diff --git a/session.c b/session.c index 116969be..457d3fd2 100644 --- a/session.c +++ b/session.c @@ -165,7 +165,7 @@ session_create(const char *name, const char *cmd, const char *cwd, s->name = xstrdup(name); else xasprintf(&s->name, "%u", i); - + if (cmd != NULL) { if (session_new(s, NULL, cmd, cwd, idx, cause) == NULL) { session_destroy(s); @@ -208,7 +208,7 @@ session_destroy(struct session *s) winlink_remove(&s->windows, RB_ROOT(&s->windows)); xfree(s->name); - + for (i = 0; i < ARRAY_LENGTH(&dead_sessions); i++) { if (ARRAY_ITEM(&dead_sessions, i) == NULL) { ARRAY_SET(&dead_sessions, i, s); @@ -233,7 +233,7 @@ session_index(struct session *s, u_int *i) /* Create a new window on a session. */ struct winlink * -session_new(struct session *s, +session_new(struct session *s, const char *name, const char *cmd, const char *cwd, int idx, char **cause) { struct window *w; @@ -463,7 +463,7 @@ session_group_index(struct session_group *sg) /* * Add a session to the session group containing target, creating it if - * necessary. + * necessary. */ void session_group_add(struct session *target, struct session *s) diff --git a/status.c b/status.c index bc8dc716..42382578 100644 --- a/status.c +++ b/status.c @@ -37,9 +37,9 @@ char *status_job(struct client *, char **); void status_job_callback(struct job *); size_t status_width(struct client *, struct winlink *, time_t); char *status_print( - struct client *, struct winlink *, time_t, struct grid_cell *); + struct client *, struct winlink *, time_t, struct grid_cell *); void status_replace1(struct client *, - struct winlink *, char **, char **, char *, size_t, int); + struct winlink *, char **, char **, char *, size_t, int); void status_message_callback(int, short, void *); void status_prompt_add_history(struct client *); @@ -163,7 +163,7 @@ status_redraw(struct client *c) * Figure out how much space we have for the window list. If there * isn't enough space, just show a blank status line. */ - needed = 0; + needed = 0; if (llen != 0) needed += llen + 1; if (rlen != 0) @@ -179,7 +179,7 @@ status_redraw(struct client *c) xfree(wl->status_text); memcpy(&wl->status_cell, &stdgc, sizeof wl->status_cell); wl->status_text = status_print(c, wl, t, &wl->status_cell); - wl->status_width = + wl->status_width = screen_write_cstrlen(utf8flag, "%s", wl->status_text); if (wl == s->curw) @@ -193,7 +193,7 @@ status_redraw(struct client *c) /* And draw the window list into it. */ screen_write_start(&ctx, NULL, &window_list); RB_FOREACH(wl, winlinks, &s->windows) { - screen_write_cnputs(&ctx, + screen_write_cnputs(&ctx, -1, &wl->status_cell, utf8flag, "%s", wl->status_text); screen_write_putc(&ctx, &stdgc, ' '); } @@ -227,7 +227,7 @@ status_redraw(struct client *c) larrow = 1; wlavailable--; } - + wlstart = wloffset + wlsize - wlavailable; if (wlavailable > 0 && wlwidth > wlstart + wlavailable + 1) { rarrow = 1; @@ -271,7 +271,7 @@ status_redraw(struct client *c) } draw: - /* Begin drawing. */ + /* Begin drawing. */ screen_write_start(&ctx, NULL, &c->status); /* Draw the left string and arrow. */ @@ -320,7 +320,7 @@ draw: /* Copy the window list. */ screen_write_cursormove(&ctx, wloffset, 0); screen_write_copy(&ctx, &window_list, wlstart, 0, wlwidth, 1); - screen_free(&window_list); + screen_free(&window_list); screen_write_stop(&ctx); @@ -355,7 +355,7 @@ status_replace1(struct client *c,struct winlink *wl, limit = strtol(*iptr, &endptr, 10); if ((limit == 0 && errno != EINVAL) || (limit == LONG_MIN && errno != ERANGE) || - (limit == LONG_MAX && errno != ERANGE) || + (limit == LONG_MAX && errno != ERANGE) || limit != 0) *iptr = endptr; if (limit <= 0) @@ -412,7 +412,7 @@ status_replace1(struct client *c,struct winlink *wl, ptr = tmp; goto do_replace; case '[': - /* + /* * Embedded style, handled at display time. Leave present and * skip input until ]. */ @@ -424,7 +424,7 @@ status_replace1(struct client *c,struct winlink *wl, } return; - + do_replace: ptrlen = strlen(ptr); if ((size_t) limit < ptrlen) @@ -779,7 +779,7 @@ status_prompt_set(struct client *c, const char *msg, void status_prompt_clear(struct client *c) { - if (c->prompt_string == NULL) + if (c->prompt_string == NULL) return; if (c->prompt_freefn != NULL && c->prompt_data != NULL) @@ -857,8 +857,8 @@ status_prompt_redraw(struct client *c) screen_write_nputs( &ctx, left, &gc, utf8flag, "%s", c->prompt_buffer + off); - for (i = len + size; i < c->tty.sx; i++) - screen_write_putc(&ctx, &gc, ' '); + for (i = len + size; i < c->tty.sx; i++) + screen_write_putc(&ctx, &gc, ' '); } screen_write_stop(&ctx); @@ -949,12 +949,12 @@ status_prompt_key(struct client *c, int key) size -= last - first; /* Insert the new word. */ - size += strlen(s); + size += strlen(s); off = first - c->prompt_buffer; - c->prompt_buffer = xrealloc(c->prompt_buffer, 1, size + 1); + c->prompt_buffer = xrealloc(c->prompt_buffer, 1, size + 1); first = c->prompt_buffer + off; - memmove(first + strlen(s), first, n); - memcpy(first, s, strlen(s)); + memmove(first + strlen(s), first, n); + memcpy(first, s, strlen(s)); c->prompt_index = (first - c->prompt_buffer) + strlen(s); xfree(s); @@ -974,7 +974,7 @@ status_prompt_key(struct client *c, int key) c->flags |= CLIENT_STATUS; } break; - case MODEKEYEDIT_DELETE: + case MODEKEYEDIT_DELETE: if (c->prompt_index != size) { memmove(c->prompt_buffer + c->prompt_index, c->prompt_buffer + c->prompt_index + 1, @@ -1056,7 +1056,7 @@ status_prompt_key(struct client *c, int key) c->flags |= CLIENT_STATUS; } break; - case MODEKEYEDIT_ENTER: + case MODEKEYEDIT_ENTER: if (*c->prompt_buffer != '\0') status_prompt_add_history(c); if (c->prompt_callbackfn(c->prompt_data, c->prompt_buffer) == 0) diff --git a/tmux.1 b/tmux.1 index 97881320..ff3f09ef 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1252,7 +1252,7 @@ options - it is not possible to unset a global option. With .Fl w , this command is equivalent to -.Ic set-window-option +.Ic set-window-option with .Ar target-window . .Pp @@ -1850,7 +1850,7 @@ or the global session options with If .Fl w is used, this command is equivalent to -.Ic show-window-options +.Ic show-window-options with .Ar target-window . .It Xo Ic show-window-options diff --git a/tmux.c b/tmux.c index 1a77c832..eaad683b 100644 --- a/tmux.c +++ b/tmux.c @@ -219,7 +219,7 @@ int main(int argc, char **argv) { struct cmd_list *cmdlist; - struct cmd *cmd; + struct cmd *cmd; enum msgtype msg; struct passwd *pw; struct options *so, *wo; @@ -311,7 +311,7 @@ main(int argc, char **argv) } environ_init(&global_environ); - for (var = environ; *var != NULL; var++) + for (var = environ; *var != NULL; var++) environ_put(&global_environ, *var); options_init(&global_s_options, NULL); @@ -394,10 +394,10 @@ main(int argc, char **argv) options_set_string(wo, "window-status-format", "#I:#W#F"); options_set_string(wo, "window-status-current-format", "#I:#W#F"); options_set_number(wo, "xterm-keys", 0); - options_set_number(wo, "remain-on-exit", 0); + options_set_number(wo, "remain-on-exit", 0); options_set_number(wo, "synchronize-panes", 0); - if (flags & IDENTIFY_UTF8) { + if (flags & IDENTIFY_UTF8) { options_set_number(so, "status-utf8", 1); options_set_number(wo, "utf8", 1); } else { @@ -432,7 +432,7 @@ main(int argc, char **argv) exit(1); } } - + if (label == NULL) label = xstrdup("default"); if (path == NULL && (path = makesockpath(label)) == NULL) { @@ -447,14 +447,14 @@ main(int argc, char **argv) len = 0; } else { fill_session(&cmddata); - + cmddata.argc = argc; if (cmd_pack_argv( argc, argv, cmddata.argv, sizeof cmddata.argv) != 0) { log_warnx("command too long"); exit(1); } - + msg = MSG_COMMAND; buf = &cmddata; len = sizeof cmddata; @@ -490,7 +490,7 @@ main(int argc, char **argv) event_init(); - imsg_compose(main_ibuf, msg, PROTOCOL_VERSION, -1, -1, buf, len); + imsg_compose(main_ibuf, msg, PROTOCOL_VERSION, -1, -1, buf, len); main_set_signals(); @@ -526,7 +526,7 @@ main_set_signals(void) fatal("sigaction failed"); if (sigaction(SIGTSTP, &sigact, NULL) != 0) fatal("sigaction failed"); - + signal_set(&main_ev_sigterm, SIGTERM, main_signal, NULL); signal_add(&main_ev_sigterm, NULL); } @@ -550,7 +550,7 @@ main_clear_signals(void) fatal("sigaction failed"); if (sigaction(SIGTSTP, &sigact, NULL) != 0) fatal("sigaction failed"); - + event_del(&main_ev_sigterm); } @@ -572,7 +572,7 @@ main_callback(unused int fd, short events, void *data) if (events & EV_READ) main_dispatch(shellcmd); - + if (events & EV_WRITE) { if (msgbuf_write(&main_ibuf->w) < 0) fatalx("msgbuf_write failed"); diff --git a/tmux.h b/tmux.h index 7549c702..d73483a8 100644 --- a/tmux.h +++ b/tmux.h @@ -340,9 +340,9 @@ enum tty_code_type { struct tty_code { enum tty_code_type type; union { - char *string; - int number; - int flag; + char *string; + int number; + int flag; } value; }; @@ -404,15 +404,15 @@ struct msg_identify_data { }; struct msg_lock_data { - char cmd[COMMAND_LENGTH]; + char cmd[COMMAND_LENGTH]; }; struct msg_environ_data { - char var[ENVIRON_LENGTH]; + char var[ENVIRON_LENGTH]; }; struct msg_shell_data { - char shell[MAXPATHLEN]; + char shell[MAXPATHLEN]; }; /* Mode key commands. */ @@ -438,7 +438,7 @@ enum mode_key_cmd { MODEKEYEDIT_SWITCHMODE, MODEKEYEDIT_SWITCHMODEAPPEND, MODEKEYEDIT_TRANSPOSECHARS, - + /* Menu (choice) keys. */ MODEKEYCHOICE_CANCEL, MODEKEYCHOICE_CHOOSE, @@ -511,13 +511,13 @@ SPLAY_HEAD(mode_key_tree, mode_key_binding); /* Command to string mapping. */ struct mode_key_cmdstr { - enum mode_key_cmd cmd; + enum mode_key_cmd cmd; const char *name; }; /* Named mode key table description. */ struct mode_key_table { - const char *name; + const char *name; struct mode_key_cmdstr *cmdstr; struct mode_key_tree *tree; const struct mode_key_entry *table; /* default entries */ @@ -683,7 +683,7 @@ struct screen_sel { struct screen { char *title; - struct grid *grid; /* grid data */ + struct grid *grid; /* grid data */ u_int cx; /* cursor x */ u_int cy; /* cursor y */ @@ -693,7 +693,7 @@ struct screen { int mode; - bitstr_t *tabs; + bitstr_t *tabs; struct screen_sel sel; }; @@ -743,7 +743,7 @@ struct input_ctx { struct utf8_data utf8data; u_char intermediate; - void *(*state)(u_char, struct input_ctx *); + void *(*state)(u_char, struct input_ctx *); u_char private; ARRAY_DECL(, struct input_arg) args; @@ -762,7 +762,7 @@ struct window_mode { void (*resize)(struct window_pane *, u_int, u_int); void (*key)(struct window_pane *, struct client *, int); void (*mouse)(struct window_pane *, - struct client *, struct mouse_event *); + struct client *, struct mouse_event *); void (*timer)(struct window_pane *); }; @@ -800,8 +800,8 @@ struct window_pane { struct screen base; /* Saved in alternative screen mode. */ - u_int saved_cx; - u_int saved_cy; + u_int saved_cx; + u_int saved_cy; struct grid *saved_grid; struct grid_cell saved_cell; @@ -949,7 +949,7 @@ ARRAY_DECL(sessions, struct session *); /* TTY information. */ struct tty_key { char ch; - int key; + int key; struct tty_key *left; struct tty_key *right; @@ -975,8 +975,8 @@ SLIST_HEAD(tty_terms, tty_term); struct tty { char *path; - u_int sx; - u_int sy; + u_int sx; + u_int sy; u_int cx; u_int cy; @@ -994,7 +994,7 @@ struct tty { int log_fd; - struct termios tio; + struct termios tio; struct grid_cell cell; @@ -1006,7 +1006,7 @@ struct tty { #define TTY_UTF8 0x8 #define TTY_STARTED 0x10 #define TTY_OPENED 0x20 - int flags; + int flags; int term_flags; @@ -1069,7 +1069,7 @@ struct client { char *title; char *cwd; - struct tty tty; + struct tty tty; struct event repeat_timer; struct timeval status_timer; @@ -1146,7 +1146,7 @@ struct cmd_ctx { struct cmd { const struct cmd_entry *entry; - void *data; + void *data; TAILQ_ENTRY(cmd) qentry; }; @@ -1172,7 +1172,7 @@ struct cmd_entry { int (*parse)(struct cmd *, int, char **, char **); int (*exec)(struct cmd *, struct cmd_ctx *); void (*free)(struct cmd *); - size_t (*print)(struct cmd *, char *, size_t); + size_t (*print)(struct cmd *, char *, size_t); }; /* Generic command data. */ @@ -1242,7 +1242,7 @@ extern char *cfg_file; extern int debug_level; extern int be_quiet; extern time_t start_time; -extern char *socket_path; +extern char *socket_path; extern int login_shell; void logfile(const char *); const char *getshell(void); @@ -1278,13 +1278,13 @@ 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 *, 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 *, const char *, long long); long long options_get_number(struct options *, const char *); struct options_entry *options_set_data( - struct options *, const char *, void *, void (*)(void *)); + struct options *, const char *, void *, void (*)(void *)); void *options_get_data(struct options *, const char *); /* job.c */ @@ -1312,7 +1312,7 @@ struct environ_entry *environ_find(struct environ *, const char *); void environ_set(struct environ *, const char *, const char *); void environ_put(struct environ *, const char *); void environ_unset(struct environ *, const char *); -void environ_update(const char *, struct environ *, struct environ *); +void environ_update(const char *, struct environ *, struct environ *); /* tty.c */ void tty_raw(struct tty *, const char *); @@ -1361,12 +1361,12 @@ void tty_cmd_reverseindex(struct tty *, const struct tty_ctx *); extern struct tty_terms tty_terms; extern struct tty_term_code_entry tty_term_codes[NTTYCODE]; struct tty_term *tty_term_find(char *, int, const char *, char **); -void tty_term_free(struct tty_term *); +void tty_term_free(struct tty_term *); int tty_term_has(struct tty_term *, enum tty_code_code); const char *tty_term_string(struct tty_term *, enum tty_code_code); const char *tty_term_string1(struct tty_term *, enum tty_code_code, int); const char *tty_term_string2( - struct tty_term *, enum tty_code_code, int, int); + struct tty_term *, enum tty_code_code, int, int); int tty_term_number(struct tty_term *, enum tty_code_code); int tty_term_flag(struct tty_term *, enum tty_code_code); @@ -1381,7 +1381,7 @@ void paste_free_stack(struct paste_stack *); struct paste_buffer *paste_walk_stack(struct paste_stack *, uint *); struct paste_buffer *paste_get_top(struct paste_stack *); struct paste_buffer *paste_get_index(struct paste_stack *, u_int); -int paste_free_top(struct paste_stack *); +int paste_free_top(struct paste_stack *); int paste_free_index(struct paste_stack *, u_int); void paste_add(struct paste_stack *, char *, size_t, u_int); int paste_replace(struct paste_stack *, u_int, char *, size_t); @@ -1393,7 +1393,7 @@ void clock_draw(struct screen_write_ctx *, int, int); /* cmd-set-option.c */ extern const struct set_option_entry set_session_option_table[]; extern const struct set_option_entry set_window_option_table[]; -const char *cmd_set_option_print( +const char *cmd_set_option_print( const struct set_option_entry *, struct options_entry *); /* cmd.c */ @@ -1508,7 +1508,7 @@ size_t cmd_list_print(struct cmd_list *, char *, size_t); int cmd_string_parse(const char *, struct cmd_list **, char **); /* cmd-generic.c */ -size_t cmd_prarg(char *, size_t, const char *, char *); +size_t cmd_prarg(char *, size_t, const char *, char *); int cmd_check_flag(uint64_t, int); void cmd_set_flag(uint64_t *, int); #define CMD_TARGET_PANE_USAGE "[-t target-pane]" @@ -1580,9 +1580,9 @@ void server_window_loop(void); void server_fill_environ(struct session *, struct environ *); void server_write_error(struct client *, const char *); void server_write_client( - struct client *, enum msgtype, const void *, size_t); + struct client *, enum msgtype, const void *, size_t); void server_write_session( - struct session *, enum msgtype, const void *, size_t); + struct session *, enum msgtype, const void *, size_t); void server_redraw_client(struct client *); void server_status_client(struct client *); void server_redraw_session(struct session *); @@ -1609,12 +1609,12 @@ void server_update_event(struct client *); /* status.c */ int status_redraw(struct client *); char *status_replace( - struct client *, struct winlink *, const char *, time_t, int); + struct client *, struct winlink *, const char *, time_t, int); void printflike2 status_message_set(struct client *, const char *, ...); void status_message_clear(struct client *); int status_message_redraw(struct client *); void status_prompt_set(struct client *, const char *, - int (*)(void *, const char *), void (*)(void *), void *, int); + int (*)(void *, const char *), void (*)(void *), void *, int); void status_prompt_clear(struct client *); int status_prompt_redraw(struct client *); void status_prompt_key(struct client *, int); @@ -1633,7 +1633,7 @@ void input_key(struct window_pane *, int); void input_mouse(struct window_pane *, struct mouse_event *); /* xterm-keys.c */ -char *xterm_keys_lookup(int); +char *xterm_keys_lookup(int); int xterm_keys_find(const char *, size_t, size_t *, int *); /* colour.c */ @@ -1670,7 +1670,7 @@ void grid_move_lines(struct grid *, u_int, u_int, u_int); void grid_move_cells(struct grid *, u_int, u_int, u_int, u_int); char *grid_string_cells(struct grid *, u_int, u_int, u_int); void grid_duplicate_lines( - struct grid *, u_int, struct grid *, u_int, u_int); + struct grid *, u_int, struct grid *, u_int, u_int); /* grid-utf8.c */ size_t grid_utf8_size(const struct grid_utf8 *); @@ -1683,11 +1683,11 @@ int grid_utf8_compare(const struct grid_utf8 *, const struct grid_utf8 *); const struct grid_cell *grid_view_peek_cell(struct grid *, u_int, u_int); struct grid_cell *grid_view_get_cell(struct grid *, u_int, u_int); void grid_view_set_cell( - struct grid *, u_int, u_int, const struct grid_cell *); + struct grid *, u_int, u_int, const struct grid_cell *); const struct grid_utf8 *grid_view_peek_utf8(struct grid *, u_int, u_int); struct grid_utf8 *grid_view_get_utf8(struct grid *, u_int, u_int); void grid_view_set_utf8( - struct grid *, u_int, u_int, const struct grid_utf8 *); + struct grid *, u_int, u_int, const struct grid_utf8 *); void grid_view_clear(struct grid *, u_int, u_int, u_int, u_int); void grid_view_scroll_region_up(struct grid *, u_int, u_int); void grid_view_scroll_region_down(struct grid *, u_int, u_int); @@ -1701,22 +1701,22 @@ char *grid_view_string_cells(struct grid *, u_int, u_int, u_int); /* screen-write.c */ void screen_write_start( - struct screen_write_ctx *, struct window_pane *, struct screen *); + struct screen_write_ctx *, struct window_pane *, struct screen *); void screen_write_stop(struct screen_write_ctx *); size_t printflike2 screen_write_cstrlen(int, const char *, ...); void printflike5 screen_write_cnputs(struct screen_write_ctx *, - ssize_t, struct grid_cell *, int, const char *, ...); + ssize_t, struct grid_cell *, int, const char *, ...); size_t printflike2 screen_write_strlen(int, const char *, ...); void printflike3 screen_write_puts(struct screen_write_ctx *, - struct grid_cell *, const char *, ...); + struct grid_cell *, const char *, ...); void printflike5 screen_write_nputs(struct screen_write_ctx *, - ssize_t, struct grid_cell *, int, const char *, ...); + 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 *); + struct grid_cell *, struct grid_cell *, const char *); void screen_write_putc( - struct screen_write_ctx *, struct grid_cell *, u_char); + struct screen_write_ctx *, struct grid_cell *, u_char); void screen_write_copy(struct screen_write_ctx *, struct screen *, u_int, u_int, u_int, u_int); void screen_write_backspace(struct screen_write_ctx *); @@ -1747,7 +1747,7 @@ void screen_write_clearendofscreen(struct screen_write_ctx *); void screen_write_clearstartofscreen(struct screen_write_ctx *); void screen_write_clearscreen(struct screen_write_ctx *); void screen_write_cell(struct screen_write_ctx *, - const struct grid_cell *, const struct utf8_data *); + const struct grid_cell *, const struct utf8_data *); /* screen-redraw.c */ void screen_redraw_screen(struct client *, int); @@ -1772,7 +1772,7 @@ int winlink_cmp(struct winlink *, struct winlink *); RB_PROTOTYPE(windows, window, entry, window_cmp); RB_PROTOTYPE(winlinks, winlink, entry, winlink_cmp); struct winlink *winlink_find_by_index(struct winlinks *, int); -struct winlink *winlink_find_by_window(struct winlinks *, struct window *); +struct winlink *winlink_find_by_window(struct winlinks *, struct window *); int winlink_next_index(struct winlinks *, int); u_int winlink_count(struct winlinks *); struct winlink *winlink_add(struct winlinks *, struct window *, int); @@ -1781,11 +1781,11 @@ struct winlink *winlink_next(struct winlink *); struct winlink *winlink_previous(struct winlink *); void winlink_stack_push(struct winlink_stack *, struct winlink *); void winlink_stack_remove(struct winlink_stack *, struct winlink *); -int window_index(struct window *, u_int *); +int window_index(struct window *, u_int *); struct window *window_create1(u_int, u_int); struct window *window_create(const char *, const char *, const char *, const char *, struct environ *, struct termios *, - u_int, u_int, u_int, char **); + u_int, u_int, u_int, char **); void window_destroy(struct window *); void window_set_active_at(struct window *, u_int, u_int); void window_set_active_pane(struct window *, struct window_pane *); @@ -1808,10 +1808,10 @@ void window_pane_reset_mode(struct window_pane *); void window_pane_parse(struct window_pane *); void window_pane_key(struct window_pane *, struct client *, int); void window_pane_mouse(struct window_pane *, - struct client *, struct mouse_event *); + struct client *, struct mouse_event *); int window_pane_visible(struct window_pane *); char *window_pane_search( - struct window_pane *, const char *, u_int *); + struct window_pane *, const char *, u_int *); /* layout.c */ struct layout_cell *layout_create_cell(struct layout_cell *); @@ -1831,7 +1831,7 @@ void layout_init(struct window *); void layout_free(struct window *); void layout_resize(struct window *, u_int, u_int); void layout_resize_pane( - struct window_pane *, enum layout_type, int); + struct window_pane *, enum layout_type, int); int layout_split_pane(struct window_pane *, enum layout_type, int, struct window_pane *); void layout_close_pane(struct window_pane *); @@ -1849,24 +1849,24 @@ extern const struct window_mode window_clock_mode; /* window-copy.c */ extern const struct window_mode window_copy_mode; -void window_copy_pageup(struct window_pane *); +void window_copy_pageup(struct window_pane *); /* window-more.c */ extern const struct window_mode window_more_mode; -void window_more_vadd(struct window_pane *, const char *, va_list); +void window_more_vadd(struct window_pane *, const char *, va_list); /* window-choose.c */ extern const struct window_mode window_choose_mode; -void window_choose_vadd( - struct window_pane *, int, const char *, va_list); +void window_choose_vadd( + struct window_pane *, int, const char *, va_list); void printflike3 window_choose_add( - struct window_pane *, int, const char *, ...); + struct window_pane *, int, const char *, ...); void window_choose_ready(struct window_pane *, u_int, void (*)(void *, int), void (*)(void *), void *); /* names.c */ void queue_window_name(struct window *); -char *default_window_name(struct window *); +char *default_window_name(struct window *); /* session.c */ extern struct sessions sessions; @@ -1880,12 +1880,12 @@ struct session *session_find(const char *); struct session *session_create(const char *, const char *, const char *, struct environ *, struct termios *, int, u_int, u_int, char **); -void session_destroy(struct session *); -int session_index(struct session *, u_int *); +void session_destroy(struct session *); +int session_index(struct session *, u_int *); struct winlink *session_new(struct session *, - const char *, const char *, const char *, int, char **); + const char *, const char *, const char *, int, char **); struct winlink *session_attach( - struct session *, struct window *, int, char **); + struct session *, struct window *, int, char **); int session_detach(struct session *, struct winlink *); int session_has(struct session *, struct window *); int session_next(struct session *, int); diff --git a/tty-keys.c b/tty-keys.c index deb2b317..a88f9542 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -35,7 +35,7 @@ void tty_keys_add1(struct tty_key **, const char *, int); void tty_keys_add(struct tty *, const char *, int); void tty_keys_free1(struct tty_key *); struct tty_key *tty_keys_find1( - struct tty_key *, const char *, size_t, size_t *); + struct tty_key *, const char *, size_t, size_t *); struct tty_key *tty_keys_find(struct tty *, const char *, size_t, size_t *); void tty_keys_callback(int, short, void *); int tty_keys_mouse( @@ -50,7 +50,7 @@ struct tty_key_ent { #define TTYKEY_RAW 0x1 }; -/* +/* * Default key tables. Those flagged with TTYKEY_RAW are inserted directly, * otherwise they are looked up in terminfo(5). */ @@ -319,7 +319,7 @@ tty_keys_add1(struct tty_key **tkp, const char *s, int key) /* Use the child tree for the next character. */ tkp = &tk->next; - } else { + } else { if (*s < tk->ch) tkp = &tk->left; else if (*s > tk->ch) @@ -374,7 +374,7 @@ tty_keys_free1(struct tty_key *tk) if (tk->right != NULL) tty_keys_free1(tk->right); xfree(tk); - + } /* Lookup a key in the tree. */ @@ -523,11 +523,11 @@ start_timer: /* Start the timer and wait for expiry or more data. */ tv.tv_sec = 0; tv.tv_usec = ESCAPE_PERIOD * 1000L; - + evtimer_del(&tty->key_timer); evtimer_set(&tty->key_timer, tty_keys_callback, tty); evtimer_add(&tty->key_timer, &tv); - + tty->flags |= TTY_ESCAPE; return (0); @@ -548,7 +548,7 @@ found_key: goto handle_key; handle_key: - evtimer_del(&tty->key_timer); + evtimer_del(&tty->key_timer); tty->key_callback(key, &mouse, tty->key_data); @@ -570,7 +570,7 @@ tty_keys_callback(unused int fd, unused short events, void *data) ; } -/* +/* * Handle mouse key input. Returns 0 for success, -1 for failure, 1 for partial * (probably a mouse sequence but need more data). */ @@ -593,7 +593,7 @@ tty_keys_mouse(const char *buf, size_t len, size_t *size, struct mouse_event *m) return (-1); if (len == 2) return (1); - + if (buf[2] != 'M') return (-1); if (len == 3) diff --git a/tty-term.c b/tty-term.c index 0c22b527..2338b42c 100644 --- a/tty-term.c +++ b/tty-term.c @@ -227,7 +227,7 @@ tty_term_override(struct tty_term *term, const char *overrides) termnext = s; while ((termstr = strsep(&termnext, ",")) != NULL) { entnext = termstr; - + entstr = strsep(&entnext, ":"); if (entstr == NULL || entnext == NULL) continue; @@ -239,7 +239,7 @@ tty_term_override(struct tty_term *term, const char *overrides) val = NULL; removeflag = 0; - if ((ptr = strchr(entstr, '=')) != NULL) { + if ((ptr = strchr(entstr, '=')) != NULL) { *ptr++ = '\0'; val = xstrdup(ptr); if (strunvis(val, ptr) == -1) { @@ -321,10 +321,12 @@ tty_term_find(char *name, int fd, const char *overrides, char **cause) if (setupterm(name, fd, &error) != OK) { switch (error) { case 1: - xasprintf(cause, "can't use hardcopy terminal: %s", name); + xasprintf( + cause, "can't use hardcopy terminal: %s", name); break; case 0: - xasprintf(cause, "missing or unsuitable terminal: %s", name); + xasprintf( + cause, "missing or unsuitable terminal: %s", name); break; case -1: xasprintf(cause, "can't find terminfo database"); diff --git a/tty.c b/tty.c index ac6a2cf7..b1026a97 100644 --- a/tty.c +++ b/tty.c @@ -44,7 +44,7 @@ void tty_redraw_region(struct tty *, const struct tty_ctx *); void tty_emulate_repeat( struct tty *, enum tty_code_code, enum tty_code_code, u_int); void tty_cell(struct tty *, - const struct grid_cell *, const struct grid_utf8 *); + const struct grid_cell *, const struct grid_utf8 *); void tty_init(struct tty *tty, int fd, char *term) @@ -502,7 +502,7 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int py, u_int ox, u_int oy) if (screen_check_selection(s, i, py)) { memcpy(&tmpgc, &s->sel.cell, sizeof tmpgc); tmpgc.data = gc->data; - tmpgc.flags = gc->flags & + tmpgc.flags = gc->flags & ~(GRID_FLAG_FG256|GRID_FLAG_BG256); tmpgc.flags |= s->sel.cell.flags & (GRID_FLAG_FG256|GRID_FLAG_BG256); @@ -562,7 +562,7 @@ tty_write(void (*cmdfn)( void tty_cmd_insertcharacter(struct tty *tty, const struct tty_ctx *ctx) { - struct window_pane *wp = ctx->wp; + struct window_pane *wp = ctx->wp; struct screen *s = wp->screen; u_int i; @@ -573,12 +573,12 @@ tty_cmd_insertcharacter(struct tty *tty, const struct tty_ctx *ctx) tty_reset(tty); - tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); + tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); if (tty_term_has(tty->term, TTYC_ICH) || tty_term_has(tty->term, TTYC_ICH1)) tty_emulate_repeat(tty, TTYC_ICH, TTYC_ICH1, ctx->num); - else if (tty_term_has(tty->term, TTYC_SMIR) && + else if (tty_term_has(tty->term, TTYC_SMIR) && tty_term_has(tty->term, TTYC_RMIR)) { tty_putcode(tty, TTYC_SMIR); for (i = 0; i < ctx->num; i++) @@ -591,7 +591,7 @@ tty_cmd_insertcharacter(struct tty *tty, const struct tty_ctx *ctx) void tty_cmd_deletecharacter(struct tty *tty, const struct tty_ctx *ctx) { - struct window_pane *wp = ctx->wp; + struct window_pane *wp = ctx->wp; struct screen *s = wp->screen; if (wp->xoff != 0 || screen_size_x(s) < tty->sx || @@ -603,7 +603,7 @@ tty_cmd_deletecharacter(struct tty *tty, const struct tty_ctx *ctx) tty_reset(tty); - tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); + tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); if (tty_term_has(tty->term, TTYC_DCH) || tty_term_has(tty->term, TTYC_DCH1)) @@ -613,11 +613,11 @@ tty_cmd_deletecharacter(struct tty *tty, const struct tty_ctx *ctx) void tty_cmd_insertline(struct tty *tty, const struct tty_ctx *ctx) { - struct window_pane *wp = ctx->wp; + struct window_pane *wp = ctx->wp; struct screen *s = wp->screen; - if (wp->xoff != 0 || screen_size_x(s) < tty->sx || - !tty_term_has(tty->term, TTYC_CSR) || + if (wp->xoff != 0 || screen_size_x(s) < tty->sx || + !tty_term_has(tty->term, TTYC_CSR) || !tty_term_has(tty->term, TTYC_IL1)) { tty_redraw_region(tty, ctx); return; @@ -625,8 +625,8 @@ tty_cmd_insertline(struct tty *tty, const struct tty_ctx *ctx) tty_reset(tty); - tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower); - tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); + tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower); + tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); tty_emulate_repeat(tty, TTYC_IL, TTYC_IL1, ctx->num); } @@ -634,10 +634,10 @@ tty_cmd_insertline(struct tty *tty, const struct tty_ctx *ctx) void tty_cmd_deleteline(struct tty *tty, const struct tty_ctx *ctx) { - struct window_pane *wp = ctx->wp; + struct window_pane *wp = ctx->wp; struct screen *s = wp->screen; - if (wp->xoff != 0 || screen_size_x(s) < tty->sx || + if (wp->xoff != 0 || screen_size_x(s) < tty->sx || !tty_term_has(tty->term, TTYC_CSR) || !tty_term_has(tty->term, TTYC_DL1)) { tty_redraw_region(tty, ctx); @@ -646,8 +646,8 @@ tty_cmd_deleteline(struct tty *tty, const struct tty_ctx *ctx) tty_reset(tty); - tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower); - tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); + tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower); + tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); tty_emulate_repeat(tty, TTYC_DL, TTYC_DL1, ctx->num); } @@ -655,13 +655,13 @@ tty_cmd_deleteline(struct tty *tty, const struct tty_ctx *ctx) void tty_cmd_clearline(struct tty *tty, const struct tty_ctx *ctx) { - struct window_pane *wp = ctx->wp; + struct window_pane *wp = ctx->wp; struct screen *s = wp->screen; u_int i; tty_reset(tty); - tty_cursor_pane(tty, ctx, 0, ctx->ocy); + tty_cursor_pane(tty, ctx, 0, ctx->ocy); if (wp->xoff == 0 && screen_size_x(s) >= tty->sx && tty_term_has(tty->term, TTYC_EL)) { @@ -675,7 +675,7 @@ tty_cmd_clearline(struct tty *tty, const struct tty_ctx *ctx) void tty_cmd_clearendofline(struct tty *tty, const struct tty_ctx *ctx) { - struct window_pane *wp = ctx->wp; + struct window_pane *wp = ctx->wp; struct screen *s = wp->screen; u_int i; @@ -695,7 +695,7 @@ tty_cmd_clearendofline(struct tty *tty, const struct tty_ctx *ctx) void tty_cmd_clearstartofline(struct tty *tty, const struct tty_ctx *ctx) { - struct window_pane *wp = ctx->wp; + struct window_pane *wp = ctx->wp; u_int i; tty_reset(tty); @@ -713,13 +713,13 @@ tty_cmd_clearstartofline(struct tty *tty, const struct tty_ctx *ctx) void tty_cmd_reverseindex(struct tty *tty, const struct tty_ctx *ctx) { - struct window_pane *wp = ctx->wp; + struct window_pane *wp = ctx->wp; struct screen *s = wp->screen; if (ctx->ocy != ctx->orupper) return; - if (wp->xoff != 0 || screen_size_x(s) < tty->sx || + if (wp->xoff != 0 || screen_size_x(s) < tty->sx || !tty_term_has(tty->term, TTYC_CSR) || !tty_term_has(tty->term, TTYC_RI)) { tty_redraw_region(tty, ctx); @@ -727,23 +727,23 @@ tty_cmd_reverseindex(struct tty *tty, const struct tty_ctx *ctx) } tty_reset(tty); - + tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower); tty_cursor_pane(tty, ctx, ctx->ocx, ctx->orupper); - + tty_putcode(tty, TTYC_RI); } void tty_cmd_linefeed(struct tty *tty, const struct tty_ctx *ctx) { - struct window_pane *wp = ctx->wp; + struct window_pane *wp = ctx->wp; struct screen *s = wp->screen; if (ctx->ocy != ctx->orlower) return; - if (wp->xoff != 0 || screen_size_x(s) < tty->sx || + if (wp->xoff != 0 || screen_size_x(s) < tty->sx || !tty_term_has(tty->term, TTYC_CSR)) { tty_redraw_region(tty, ctx); return; @@ -758,17 +758,17 @@ tty_cmd_linefeed(struct tty *tty, const struct tty_ctx *ctx) return; tty_reset(tty); - + tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower); tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); - + tty_putc(tty, '\n'); } void tty_cmd_clearendofscreen(struct tty *tty, const struct tty_ctx *ctx) { - struct window_pane *wp = ctx->wp; + struct window_pane *wp = ctx->wp; struct screen *s = wp->screen; u_int i, j; @@ -804,7 +804,7 @@ tty_cmd_clearendofscreen(struct tty *tty, const struct tty_ctx *ctx) void tty_cmd_clearstartofscreen(struct tty *tty, const struct tty_ctx *ctx) { - struct window_pane *wp = ctx->wp; + struct window_pane *wp = ctx->wp; struct screen *s = wp->screen; u_int i, j; @@ -834,7 +834,7 @@ tty_cmd_clearstartofscreen(struct tty *tty, const struct tty_ctx *ctx) void tty_cmd_clearscreen(struct tty *tty, const struct tty_ctx *ctx) { - struct window_pane *wp = ctx->wp; + struct window_pane *wp = ctx->wp; struct screen *s = wp->screen; u_int i, j; @@ -921,7 +921,7 @@ tty_cmd_utf8character(struct tty *tty, const struct tty_ctx *ctx) * Cannot rely on not being a partial character, so just redraw the * whole line. */ - tty_draw_line(tty, wp->screen, ctx->ocy, wp->xoff, wp->yoff); + tty_draw_line(tty, wp->screen, ctx->ocy, wp->xoff, wp->yoff); } void @@ -980,7 +980,7 @@ void tty_region_pane( struct tty *tty, const struct tty_ctx *ctx, u_int rupper, u_int rlower) { - struct window_pane *wp = ctx->wp; + struct window_pane *wp = ctx->wp; tty_region(tty, wp->yoff + rupper, wp->yoff + rlower); } @@ -1016,7 +1016,7 @@ tty_region(struct tty *tty, u_int rupper, u_int rlower) void tty_cursor_pane(struct tty *tty, const struct tty_ctx *ctx, u_int cx, u_int cy) { - struct window_pane *wp = ctx->wp; + struct window_pane *wp = ctx->wp; tty_cursor(tty, wp->xoff + cx, wp->yoff + cy); } @@ -1028,7 +1028,7 @@ tty_cursor(struct tty *tty, u_int cx, u_int cy) struct tty_term *term = tty->term; u_int thisx, thisy; int change; - + if (cx > tty->sx - 1) cx = tty->sx - 1; @@ -1103,7 +1103,7 @@ tty_cursor(struct tty *tty, u_int cx, u_int cy) */ /* One above. */ - if (thisy != tty->rupper && + if (thisy != tty->rupper && cy == thisy - 1 && tty_term_has(term, TTYC_CUU1)) { tty_putcode(tty, TTYC_CUU1); goto out; @@ -1120,8 +1120,8 @@ tty_cursor(struct tty *tty, u_int cx, u_int cy) change = thisy - cy; /* +ve up, -ve down */ /* - * Try to use VPA if change is larger than absolute or if this change - * would cross the scroll region, otherwise use CUU/CUD. + * Try to use VPA if change is larger than absolute or if this + * change would cross the scroll region, otherwise use CUU/CUD. */ if (abs(change) > cy || (change < 0 && cy - change > tty->rlower) || @@ -1265,7 +1265,7 @@ tty_colours(struct tty *tty, const struct grid_cell *gc, u_char *attr) } if (bg_default && bg != tc->bg && !(tc->flags & GRID_FLAG_BG256)) { - if (have_ax) + if (have_ax) tty_puts(tty, "\033[49m"); else if (tc->bg != 0) tty_putcode1(tty, TTYC_SETAB, 0); @@ -1315,7 +1315,7 @@ tty_colours_fg(struct tty *tty, const struct grid_cell *gc, u_char *attr) /* Otherwise set the foreground colour. */ tty_putcode1(tty, TTYC_SETAF, fg); -save_fg: +save_fg: /* Save the new values in the terminal current cell. */ tc->fg = fg; tc->flags &= ~GRID_FLAG_FG256; diff --git a/window-choose.c b/window-choose.c index fc012d9e..c4af4b43 100644 --- a/window-choose.c +++ b/window-choose.c @@ -27,11 +27,11 @@ void window_choose_free(struct window_pane *); void window_choose_resize(struct window_pane *, u_int, u_int); void window_choose_key(struct window_pane *, struct client *, int); void window_choose_mouse( - struct window_pane *, struct client *, struct mouse_event *); + struct window_pane *, struct client *, struct mouse_event *); void window_choose_redraw_screen(struct window_pane *); void window_choose_write_line( - struct window_pane *, struct screen_write_ctx *, u_int); + struct window_pane *, struct screen_write_ctx *, u_int); void window_choose_scroll_up(struct window_pane *); void window_choose_scroll_down(struct window_pane *); @@ -247,7 +247,7 @@ window_choose_key(struct window_pane *wp, unused struct client *c, int key) else data->top -= screen_size_y(s); } - window_choose_redraw_screen(wp); + window_choose_redraw_screen(wp); break; case MODEKEYCHOICE_PAGEDOWN: data->selected += screen_size_y(s); @@ -268,7 +268,7 @@ window_choose_key(struct window_pane *wp, unused struct client *c, int key) if (idx < 0 || (u_int) idx >= ARRAY_LENGTH(&data->list)) break; data->selected = idx; - + item = &ARRAY_ITEM(&data->list, data->selected); data->callbackfn(data->data, item->idx); window_pane_reset_mode(wp); @@ -312,7 +312,7 @@ window_choose_write_line( struct options *oo = &wp->window->options; struct screen *s = &data->screen; struct grid_cell gc; - int utf8flag; + int utf8flag; char key; if (data->callbackfn == NULL) diff --git a/window-clock.c b/window-clock.c index 27fe56cd..bc9cf81d 100644 --- a/window-clock.c +++ b/window-clock.c @@ -78,7 +78,7 @@ window_clock_resize(struct window_pane *wp, u_int sx, u_int sy) struct window_clock_mode_data *data = wp->modedata; struct screen *s = &data->screen; - screen_resize(s, sx, sy); + screen_resize(s, sx, sy); window_clock_draw_screen(wp); } diff --git a/window-copy.c b/window-copy.c index ec1d8e4a..d6e026ff 100644 --- a/window-copy.c +++ b/window-copy.c @@ -29,14 +29,14 @@ void window_copy_resize(struct window_pane *, u_int, u_int); void window_copy_key(struct window_pane *, struct client *, int); int window_copy_key_input(struct window_pane *, int); void window_copy_mouse( - struct window_pane *, struct client *, struct mouse_event *); + struct window_pane *, struct client *, struct mouse_event *); void window_copy_redraw_lines(struct window_pane *, u_int, u_int); void window_copy_redraw_screen(struct window_pane *); void window_copy_write_line( - struct window_pane *, struct screen_write_ctx *, u_int); + struct window_pane *, struct screen_write_ctx *, u_int); void window_copy_write_lines( - struct window_pane *, struct screen_write_ctx *, u_int, u_int); + struct window_pane *, struct screen_write_ctx *, u_int, u_int); void window_copy_scroll_to(struct window_pane *, u_int, u_int); int window_copy_search_compare( @@ -195,7 +195,7 @@ window_copy_resize(struct window_pane *wp, u_int sx, u_int sy) struct screen_write_ctx ctx; screen_resize(s, sx, sy); - + if (data->cy > sy - 1) data->cy = sy - 1; if (data->cx > sx) @@ -233,7 +233,7 @@ window_copy_key(struct window_pane *wp, struct client *c, int key) return; case MODEKEYCOPY_RIGHT: window_copy_cursor_right(wp); - return; + return; case MODEKEYCOPY_UP: window_copy_cursor_up(wp, 0); return; @@ -297,7 +297,7 @@ window_copy_key(struct window_pane *wp, struct client *c, int key) window_copy_redraw_screen(wp); break; case MODEKEYCOPY_STARTSELECTION: - window_copy_start_selection(wp); + window_copy_start_selection(wp); window_copy_redraw_screen(wp); break; case MODEKEYCOPY_CLEARSELECTION: @@ -422,7 +422,7 @@ window_copy_key_input(struct window_pane *wp, int key) if (key < 32 || key > 126) break; inputlen = strlen(data->inputstr) + 2; - + data->inputstr = xrealloc(data->inputstr, 1, inputlen); data->inputstr[inputlen - 2] = key; data->inputstr[inputlen - 1] = '\0'; @@ -452,7 +452,7 @@ window_copy_mouse( window_copy_update_cursor(wp, m->x, m->y); if (window_copy_update_selection(wp)) - window_copy_redraw_screen(wp); + window_copy_redraw_screen(wp); } void @@ -476,7 +476,7 @@ window_copy_scroll_to(struct window_pane *wp, u_int px, u_int py) offset = py + gap - gd->sy; data->cy = py - offset; } - data->oy = gd->hsize - offset; + data->oy = gd->hsize - offset; window_copy_redraw_screen(wp); } @@ -490,7 +490,7 @@ window_copy_search_compare( gc = grid_peek_cell(gd, px, py); sgc = grid_peek_cell(sgd, spx, 0); - + if ((gc->flags & GRID_FLAG_UTF8) != (sgc->flags & GRID_FLAG_UTF8)) return (0); @@ -674,7 +674,7 @@ window_copy_goto_line(struct window_pane *wp, const char *linestr) lineno = strtonum(linestr, 0, screen_hsize(&wp->base), &errstr); if (errstr != NULL) return; - + data->oy = lineno; window_copy_redraw_screen(wp); } @@ -893,8 +893,8 @@ window_copy_copy_line(struct window_pane *wp, char **buf, size_t *off, u_int sy, u_int sx, u_int ex) { struct grid *gd = wp->base.grid; - const struct grid_cell *gc; - const struct grid_utf8 *gu; + const struct grid_cell *gc; + const struct grid_utf8 *gu; struct grid_line *gl; u_int i, xx, wrapped = 0; size_t size; @@ -907,7 +907,7 @@ window_copy_copy_line(struct window_pane *wp, * on screen. */ gl = &gd->linedata[sy]; - if (gl->flags & GRID_LINE_WRAPPED && gl->cellsize <= gd->sx) + if (gl->flags & GRID_LINE_WRAPPED && gl->cellsize <= gd->sx) wrapped = 1; /* If the line was wrapped, don't strip spaces (use the full length). */ @@ -938,7 +938,7 @@ window_copy_copy_line(struct window_pane *wp, } /* Only add a newline if the line wasn't wrapped. */ - if (!wrapped) { + if (!wrapped) { *buf = xrealloc(*buf, 1, (*off) + 1); (*buf)[(*off)++] = '\n'; } diff --git a/window-more.c b/window-more.c index ec705795..49d19a7c 100644 --- a/window-more.c +++ b/window-more.c @@ -29,7 +29,7 @@ void window_more_key(struct window_pane *, struct client *, int); void window_more_redraw_screen(struct window_pane *); void window_more_write_line( - struct window_pane *, struct screen_write_ctx *, u_int); + struct window_pane *, struct screen_write_ctx *, u_int); void window_more_scroll_up(struct window_pane *); void window_more_scroll_down(struct window_pane *); @@ -165,11 +165,11 @@ window_more_write_line( { struct window_more_mode_data *data = wp->modedata; struct screen *s = &data->screen; - struct options *oo = &wp->window->options; + struct options *oo = &wp->window->options; struct grid_cell gc; char *msg, hdr[32]; size_t size; - int utf8flag; + int utf8flag; utf8flag = options_get_number(&wp->window->options, "utf8"); memcpy(&gc, &grid_default_cell, sizeof gc); diff --git a/window.c b/window.c index 3b7702fd..5494142e 100644 --- a/window.c +++ b/window.c @@ -189,7 +189,7 @@ winlink_stack_remove(struct winlink_stack *stack, struct winlink *wl) if (wl == NULL) return; - + TAILQ_FOREACH(wl2, stack, sentry) { if (wl2 == wl) { TAILQ_REMOVE(stack, wl, sentry); @@ -223,7 +223,7 @@ window_create1(u_int sx, u_int sy) w->lastlayout = -1; w->layout_root = NULL; - + w->sx = sx; w->sy = sy; @@ -428,7 +428,7 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit) wp->layout_cell = NULL; wp->xoff = 0; - wp->yoff = 0; + wp->yoff = 0; wp->sx = sx; wp->sy = sy; @@ -513,7 +513,7 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell, ws.ws_col = screen_size_x(&wp->base); ws.ws_row = screen_size_y(&wp->base); - switch (wp->pid = forkpty(&wp->fd, wp->tty, NULL, &ws)) { + switch (wp->pid = forkpty(&wp->fd, wp->tty, NULL, &ws)) { case -1: wp->fd = -1; xasprintf(cause, "%s: %s", cmd, strerror(errno)); @@ -665,7 +665,7 @@ window_pane_parse(struct window_pane *wp) data = EVBUFFER_DATA(wp->event->input); bufferevent_write(wp->pipe_event, data, new_size); } - + input_parse(wp); wp->pipe_off = EVBUFFER_LENGTH(wp->event->input); diff --git a/xterm-keys.c b/xterm-keys.c index f0fbf802..e4cb25d1 100644 --- a/xterm-keys.c +++ b/xterm-keys.c @@ -27,11 +27,11 @@ * character: * * 2 Shift - * 3 Alt - * 4 Shift + Alt - * 5 Ctrl - * 6 Shift + Ctrl - * 7 Alt + Ctrl + * 3 Alt + * 4 Shift + Alt + * 5 Ctrl + * 6 Shift + Ctrl + * 7 Alt + Ctrl * 8 Shift + Alt + Ctrl * * Rather than parsing them, just match against a table. @@ -85,7 +85,7 @@ struct xterm_keys_entry xterm_keys_table[] = { { KEYC_DC, "\033[3;_~" }, }; -/* +/* * Match key against buffer, treating _ as a wildcard. Return -1 for no match, * 0 for match, 1 if the end of the buffer is reached (need more data). */ @@ -132,7 +132,7 @@ xterm_keys_modifiers(const char *template, const char *buf, size_t len) case '7': return (KEYC_ESCAPE|KEYC_CTRL); case '8': - return (KEYC_SHIFT|KEYC_ESCAPE|KEYC_CTRL); + return (KEYC_SHIFT|KEYC_ESCAPE|KEYC_CTRL); } return (0); } @@ -206,7 +206,7 @@ xterm_keys_lookup(int key) } if (i == nitems(xterm_keys_table)) return (NULL); - + /* Copy the template and replace the modifier. */ out = xstrdup(entry->template); out[strcspn(out, "_")] = '0' + modifiers; From e755475475a170237d617e7d15af404124eb69c4 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 3 Dec 2009 22:54:34 +0000 Subject: [PATCH 0582/1180] Wrap at 80 columns. --- tmux.1 | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/tmux.1 b/tmux.1 index ff3f09ef..bee32920 100644 --- a/tmux.1 +++ b/tmux.1 @@ -627,7 +627,8 @@ command or cycled with .Ic next-layout (bound to .Ql C-space -by default); once a layout is chosen, panes within it may be moved and resized as normal. +by default); once a layout is chosen, panes within it may be moved and resized +as normal. .Pp The following layouts are supported: .Bl -tag -width Ds @@ -636,8 +637,8 @@ Panes are spread out evenly from left to right across the window. .It Ic even-vertical Panes are spread evenly from top to bottom. .It Ic main-horizontal -A large (main) pane is shown at the top of the window and the remaining panes are -spread from left to right in the leftover space at the bottom. +A large (main) pane is shown at the top of the window and the remaining panes +are spread from left to right in the leftover space at the bottom. Use the .Em main-pane-height window option to specify the height of the top pane. @@ -1518,7 +1519,8 @@ 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 +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 @@ -1964,8 +1966,8 @@ window options. The window name is printed in inverted colours if an alert (bell, activity or content) is present. .Pp -The colour and attributes of the status line may be configured, the entire status line using -the +The colour and attributes of the status line may be configured, the entire +status line using the .Ic status-attr , .Ic status-fg and @@ -1977,8 +1979,8 @@ and .Ic window-status-bg window options. .Pp -The status line is automatically refreshed at interval if it has changed, the interval may be -controlled with the +The status line is automatically refreshed at interval if it has changed, the +interval may be controlled with the .Ic status-interval session option. .Pp From 796eb522ac6534510b22c34296cbd172f8fab3ae Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 4 Dec 2009 11:01:29 +0000 Subject: [PATCH 0583/1180] vte is buggy and doesn't home the cursor after changing the scroll region. Several people are hitting this, so add a workaround. --- tty.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tty.c b/tty.c index b1026a97..32ee197c 100644 --- a/tty.c +++ b/tty.c @@ -1006,10 +1006,8 @@ tty_region(struct tty *tty, u_int rupper, u_int rlower) if (tty->cx >= tty->sx) tty_cursor(tty, 0, tty->cy); - tty->cx = 0; - tty->cy = 0; - tty_putcode2(tty, TTYC_CSR, tty->rupper, tty->rlower); + tty_cursor(tty, 0, 0); } /* Move cursor inside pane. */ From 6311bd119ed728117fd6f0073792a76c2a6b842b Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 8 Dec 2009 07:49:31 +0000 Subject: [PATCH 0584/1180] Permit panes to be referred to as "top", "bottom", "top-left" etc, if the right pane can be identified. --- Makefile | 2 +- cmd.c | 41 ++++++++---- layout-string.c | 167 ++++++++++++++++++++++++++++++++++++++++++++++++ tmux.1 | 10 +++ tmux.h | 3 + 5 files changed, 208 insertions(+), 15 deletions(-) create mode 100644 layout-string.c diff --git a/Makefile b/Makefile index e5a84a9d..a1dda3d2 100644 --- a/Makefile +++ b/Makefile @@ -32,7 +32,7 @@ SRCS= attributes.c cfg.c client.c clock.c \ cmd-pipe-pane.c cmd-capture-pane.c cmd.c \ colour.c environ.c grid-view.c grid-utf8.c grid.c input-keys.c \ imsg.c imsg-buffer.c input.c key-bindings.c key-string.c \ - layout-set.c layout.c log.c job.c \ + layout-set.c layout-string.c layout.c log.c job.c \ mode-key.c names.c options.c paste.c procname.c \ resize.c screen-redraw.c screen-write.c screen.c session.c status.c \ server-fn.c server.c server-client.c server-window.c \ diff --git a/cmd.c b/cmd.c index d094427b..5ad87c23 100644 --- a/cmd.c +++ b/cmd.c @@ -856,12 +856,12 @@ struct winlink * cmd_find_pane(struct cmd_ctx *ctx, const char *arg, struct session **sp, struct window_pane **wpp) { - struct session *s; - struct winlink *wl; - const char *period; - char *winptr, *paneptr; - const char *errstr; - u_int idx; + struct session *s; + struct winlink *wl; + struct layout_cell *lc; + const char *period, *errstr; + char *winptr, *paneptr; + u_int idx; /* Get the current session. */ if ((s = cmd_current_session(ctx)) == NULL) { @@ -895,20 +895,27 @@ cmd_find_pane(struct cmd_ctx *ctx, *wpp = wl->window->active; else { idx = strtonum(paneptr, 0, INT_MAX, &errstr); - if (errstr != NULL) { - ctx->error(ctx, "pane %s: %s", errstr, paneptr); - goto error; - } + if (errstr != NULL) + goto lookup_string; *wpp = window_pane_at_index(wl->window, idx); - if (*wpp == NULL) { - ctx->error(ctx, "no such pane: %u", idx); - goto error; - } + if (*wpp == NULL) + goto lookup_string; } xfree(winptr); return (wl); +lookup_string: + /* Try pane string description. */ + if ((lc = layout_find_string(s->curw->window, paneptr)) == NULL) { + ctx->error(ctx, "can't find pane: %s", paneptr); + goto error; + } + *wpp = lc->wp; + + xfree(winptr); + return (s->curw); + no_period: /* Try as a pane number alone. */ idx = strtonum(arg, 0, INT_MAX, &errstr); @@ -922,6 +929,12 @@ no_period: return (s->curw); lookup_window: + /* Try pane string description. */ + if ((lc = layout_find_string(s->curw->window, arg)) != NULL) { + *wpp = lc->wp; + return (s->curw); + } + /* Try as a window and use the active pane. */ if ((wl = cmd_find_window(ctx, arg, sp)) != NULL) *wpp = wl->window->active; diff --git a/layout-string.c b/layout-string.c new file mode 100644 index 00000000..acaf09e4 --- /dev/null +++ b/layout-string.c @@ -0,0 +1,167 @@ +/* $Id$ */ + +/* + * Copyright (c) 2009 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 "tmux.h" + +/* + * Figure out the pane position based on a description. Fairly simple right + * now, just understands a set of strings: left, right, top, bottom, top-left + * top-right, bottom-left, bottom-right. + */ + +struct layout_cell *layout_find_top(struct layout_cell *); +struct layout_cell *layout_find_bottom(struct layout_cell *); +struct layout_cell *layout_find_left(struct layout_cell *); +struct layout_cell *layout_find_right(struct layout_cell *); +struct layout_cell *layout_find_topleft(struct layout_cell *); +struct layout_cell *layout_find_topright(struct layout_cell *); +struct layout_cell *layout_find_bottomleft(struct layout_cell *); +struct layout_cell *layout_find_bottomright(struct layout_cell *); + +/* Find the cell; returns NULL if string not understood. */ +struct layout_cell * +layout_find_string(struct window *w, const char *s) +{ + struct layout_cell *lc = w->layout_root; + + if (strcasecmp(s, "top") == 0) + lc = layout_find_top(lc); + else if (strcasecmp(s, "bottom") == 0) + lc = layout_find_bottom(lc); + else if (strcasecmp(s, "left") == 0) + lc = layout_find_left(lc); + else if (strcasecmp(s, "right") == 0) + lc = layout_find_right(lc); + else if (strcasecmp(s, "top-left") == 0) + lc = layout_find_topleft(lc); + else if (strcasecmp(s, "top-right") == 0) + lc = layout_find_topright(lc); + else if (strcasecmp(s, "bottom-left") == 0) + lc = layout_find_bottomleft(lc); + else if (strcasecmp(s, "bottom-right") == 0) + lc = layout_find_bottomright(lc); + + if (lc == NULL || lc->type != LAYOUT_WINDOWPANE) + return (NULL); + return (lc); +} + +/* + * Find the top cell. Because splits in the same direction are stored as a + * list, this is just the first in the list. Return NULL if no topmost cell. + * For an unnested cell (not split), the top cell is always itself. + */ +struct layout_cell * +layout_find_top(struct layout_cell *lc) +{ + if (lc->type == LAYOUT_WINDOWPANE) + return (lc); + else if (lc->type == LAYOUT_TOPBOTTOM) + return (TAILQ_FIRST(&lc->cells)); + return (NULL); +} + +/* + * Find the bottom cell. Similarly to the top cell, this is just the last in + * the list. + */ +struct layout_cell * +layout_find_bottom(struct layout_cell *lc) +{ + if (lc->type == LAYOUT_WINDOWPANE) + return (lc); + else if (lc->type == LAYOUT_TOPBOTTOM) + return (TAILQ_LAST(&lc->cells, layout_cells)); + return (NULL); +} + +/* Find the left cell. */ +struct layout_cell * +layout_find_left(struct layout_cell *lc) +{ + if (lc->type == LAYOUT_WINDOWPANE) + return (lc); + else if (lc->type == LAYOUT_LEFTRIGHT) + return (TAILQ_FIRST(&lc->cells)); + return (NULL); +} + +/* Find the right cell. */ +struct layout_cell * +layout_find_right(struct layout_cell *lc) +{ + if (lc->type == LAYOUT_WINDOWPANE) + return (lc); + else if (lc->type == LAYOUT_LEFTRIGHT) + return (TAILQ_LAST(&lc->cells, layout_cells)); + return (NULL); +} + +/* + * Find the top-left cell. This means recursing until there are no more moves + * to be made. + */ +struct layout_cell * +layout_find_topleft(struct layout_cell *lc) +{ + if (lc->type == LAYOUT_WINDOWPANE) + return (lc); + lc = TAILQ_FIRST(&lc->cells); + return (layout_find_topleft(lc)); +} + +/* Find the top-right cell. */ +struct layout_cell * +layout_find_topright(struct layout_cell *lc) +{ + if (lc->type == LAYOUT_WINDOWPANE) + return (lc); + if (lc->type == LAYOUT_LEFTRIGHT) + lc = TAILQ_LAST(&lc->cells, layout_cells); + else + lc = TAILQ_FIRST(&lc->cells); + return (layout_find_topright(lc)); +} + +/* Find the bottom-left cell. */ +struct layout_cell * +layout_find_bottomleft(struct layout_cell *lc) +{ + if (lc->type == LAYOUT_WINDOWPANE) + return (lc); + if (lc->type == LAYOUT_LEFTRIGHT) + lc = TAILQ_FIRST(&lc->cells); + else + lc = TAILQ_LAST(&lc->cells, layout_cells); + return (layout_find_bottomleft(lc)); +} + +/* Find the bottom-right cell. */ +struct layout_cell * +layout_find_bottomright(struct layout_cell *lc) +{ + if (lc->type == LAYOUT_WINDOWPANE) + return (lc); + lc = TAILQ_LAST(&lc->cells, layout_cells); + return (layout_find_bottomright(lc)); +} diff --git a/tmux.1 b/tmux.1 index bee32920..a188feaf 100644 --- a/tmux.1 +++ b/tmux.1 @@ -323,6 +323,16 @@ If neither a colon nor period appears, first attempts to use the argument as a pane index; if that fails, it is looked up as for .Ar target-window . +One of the strings +.Em top , +.Em bottom , +.Em left , +.Em right , +.Em top-left , +.Em top-right , +.Em bottom-left or +.Em bottom-right +may be used instead of a pane index. .Pp Multiple commands may be specified together as part of a .Em command sequence . diff --git a/tmux.h b/tmux.h index d73483a8..cf42a85c 100644 --- a/tmux.h +++ b/tmux.h @@ -1844,6 +1844,9 @@ u_int layout_set_next(struct window *); u_int layout_set_previous(struct window *); void layout_set_active_changed(struct window *); +/* layout-string.c */ +struct layout_cell *layout_find_string(struct window *, const char *); + /* window-clock.c */ extern const struct window_mode window_clock_mode; From a4c9a80dacf405623698acfc971d636bbc0e43c7 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 10 Dec 2009 09:16:52 +0000 Subject: [PATCH 0585/1180] Add "server options" which are server-wide and not bound to a session or window. Set and displayed with "set -s" and "show -s". Currently the only option is "quiet" (like command-line -q, allowing it to be set from .tmux.conf), but others will come along. --- cmd-server-info.c | 4 +-- cmd-set-option.c | 13 +++++-- cmd-show-options.c | 9 +++-- key-bindings.c | 2 +- server-client.c | 2 +- tmux.1 | 85 ++++++++++++++++++++++++++++++---------------- tmux.c | 12 ++++--- tmux.h | 2 ++ 8 files changed, 86 insertions(+), 43 deletions(-) diff --git a/cmd-server-info.c b/cmd-server-info.c index 8c85b2c3..60acbdf8 100644 --- a/cmd-server-info.c +++ b/cmd-server-info.c @@ -70,8 +70,8 @@ cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx) tim = ctime(&start_time); *strchr(tim, '\n') = '\0'; ctx->print(ctx, "pid %ld, started %s", (long) getpid(), tim); - ctx->print(ctx, "socket path %s, debug level %d%s", - socket_path, debug_level, be_quiet ? ", quiet" : ""); + ctx->print( + ctx, "socket path %s, debug level %d", socket_path, debug_level); if (uname(&un) == 0) { ctx->print(ctx, "system is %s %s %s %s", un.sysname, un.release, un.version, un.machine); diff --git a/cmd-set-option.c b/cmd-set-option.c index 0cd7dca6..64b78448 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -48,8 +48,8 @@ void cmd_set_option_choice(struct cmd_ctx *, const struct cmd_entry cmd_set_option_entry = { "set-option", "set", - "[-aguw] [-t target-session|target-window] option [value]", - CMD_ARG12, "aguw", + "[-agsuw] [-t target-session|target-window] option [value]", + CMD_ARG12, "agsuw", NULL, cmd_target_parse, cmd_set_option_exec, @@ -73,6 +73,10 @@ const char *set_option_bell_action_list[] = { "none", "any", "current", NULL }; +const struct set_option_entry set_option_table[] = { + { "quiet", SET_OPTION_FLAG, 0, 0, NULL }, +}; + const struct set_option_entry set_session_option_table[] = { { "base-index", SET_OPTION_NUMBER, 0, INT_MAX, NULL }, { "bell-action", SET_OPTION_CHOICE, 0, 0, set_option_bell_action_list }, @@ -172,7 +176,10 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) u_int i; int try_again; - if (cmd_check_flag(data->chflags, 'w')) { + if (cmd_check_flag(data->chflags, 's')) { + oo = &global_options; + table = set_option_table; + } else if (cmd_check_flag(data->chflags, 'w')) { table = set_window_option_table; if (cmd_check_flag(data->chflags, 'g')) oo = &global_w_options; diff --git a/cmd-show-options.c b/cmd-show-options.c index d725464c..23838e4c 100644 --- a/cmd-show-options.c +++ b/cmd-show-options.c @@ -31,8 +31,8 @@ int cmd_show_options_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_show_options_entry = { "show-options", "show", - "[-gw] [-t target-session|target-window]", - 0, "gw", + "[-gsw] [-t target-session|target-window]", + 0, "gsw", cmd_target_init, cmd_target_parse, cmd_show_options_exec, @@ -52,7 +52,10 @@ cmd_show_options_exec(struct cmd *self, struct cmd_ctx *ctx) const struct set_option_entry *entry; const char *optval; - if (cmd_check_flag(data->chflags, 'w')) { + if (cmd_check_flag(data->chflags, 's')) { + oo = &global_options; + table = set_option_table; + } else if (cmd_check_flag(data->chflags, 'w')) { table = set_window_option_table; if (cmd_check_flag(data->chflags, 'g')) oo = &global_w_options; diff --git a/key-bindings.c b/key-bindings.c index 29dedbb2..d536af11 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -224,7 +224,7 @@ key_bindings_info(struct cmd_ctx *ctx, const char *fmt, ...) va_list ap; char *msg; - if (be_quiet) + if (options_get_number(&global_options, "quiet")) return; va_start(ap, fmt); diff --git a/server-client.c b/server-client.c index 80b4429c..02edabc6 100644 --- a/server-client.c +++ b/server-client.c @@ -640,7 +640,7 @@ server_client_msg_info(struct cmd_ctx *ctx, const char *fmt, ...) struct msg_print_data data; va_list ap; - if (be_quiet) + if (options_get_number(&global_options, "quiet")) return; va_start(ap, fmt); diff --git a/tmux.1 b/tmux.1 index a188feaf..fbbfe79e 100644 --- a/tmux.1 +++ b/tmux.1 @@ -151,8 +151,9 @@ signal may be sent to the .Nm server process to recreate it. .It Fl q -Prevent the server sending various informational messages, for example when -window flags are altered. +Set the +.Ic quiet +server option to prevent the server sending various informational messages. .It Fl S Ar socket-path Specify a full alternative path to the server socket. If @@ -1209,13 +1210,26 @@ or for normal mode without. The appearance and behaviour of .Nm may be modified by changing the value of various options. -There are two types of option: +There are three types of option: +.Em server options , .Em session options and .Em window options . .Pp -Each individual session may have a set of session options, and there is a -separate set of global session options. +The +.Nm +server has a set of global options which do not apply to any particular +window or session. +These are altered with the +.Ic set-option +.Fl s +command, or displayed with the +.Ic show-options +.Fl s +command. +.Pp +In addition, each individual session may have a set of session options, and +there is a separate set of global session options. Sessions which do not have a particular option configured inherit the value from the global session options. Session options are set or unset with the @@ -1223,7 +1237,7 @@ Session options are set or unset with the command and may be listed with the .Ic show-options command. -The available session options are listed under the +The available server and session options are listed under the .Ic set-option command. .Pp @@ -1241,31 +1255,44 @@ command. Commands which set options are as follows: .Bl -tag -width Ds .It Xo Ic set-option -.Op Fl aguw +.Op Fl agsuw .Op Fl t Ar target-session | Ar target-window .Ar option Ar value .Xc .D1 (alias: Ic set ) -Set a session option. +Set a window option with +.Fl w +(equivalent to the +.Ic set-window-option +command), +a server option with +.Fl s , +otherwise a session option. +.Pp +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. -If -.Fl g -is specified, the global session option is set. The .Fl u flag unsets an option, so a session inherits the option from the global -options - it is not possible to unset a global option. +options. +It is not possible to unset a global option. .Pp -With -.Fl w , -this command is equivalent to -.Ic set-window-option -with -.Ar target-window . +Available window options are listed under +.Ic set-window-option . +.Pp +Available server options are: +.Bl -tag -width Ds +.It Ic quiet +Enable of disable the display of various informational messages (see also the +.Fl q +command line flag). +.El .Pp Available session options are: .Bl -tag -width Ds @@ -1850,21 +1877,21 @@ as Shift, Alt or Ctrl. The default is off. .El .It Xo Ic show-options -.Op Fl gw +.Op Fl gsw .Op Fl t Ar target-session | Ar target-window .Xc .D1 (alias: Ic show ) -Show the session options for -.Ar target session , -or the global session options with -.Fl g . -.Pp -If +Show the window options with .Fl w -is used, this command is equivalent to -.Ic show-window-options -with -.Ar target-window . +(equivalent to +.Ic show-window-options ), +the server options with +.Fl s , +otherwise the session options for +.Ar target session . +Global session or window options are listed if +.Fl g +is used. .It Xo Ic show-window-options .Op Fl g .Op Fl t Ar target-window diff --git a/tmux.c b/tmux.c index eaad683b..209042af 100644 --- a/tmux.c +++ b/tmux.c @@ -36,12 +36,12 @@ extern char *malloc_options; #endif char *cfg_file; +struct options global_options; /* server options */ struct options global_s_options; /* session options */ struct options global_w_options; /* window options */ struct environ global_environ; int debug_level; -int be_quiet; time_t start_time; char *socket_path; int login_shell; @@ -222,14 +222,14 @@ main(int argc, char **argv) struct cmd *cmd; enum msgtype msg; struct passwd *pw; - struct options *so, *wo; + struct options *oo, *so, *wo; struct keylist *keylist; struct msg_command_data cmddata; char *s, *shellcmd, *path, *label, *home, *cause; char cwd[MAXPATHLEN], **var; void *buf; size_t len; - int opt, flags, cmdflags = 0; + int opt, flags, quiet, cmdflags = 0; short events; #ifdef DEBUG @@ -268,7 +268,7 @@ main(int argc, char **argv) label = xstrdup(optarg); break; case 'q': - be_quiet = 1; + quiet = 1; break; case 'S': if (path != NULL) @@ -314,6 +314,10 @@ main(int argc, char **argv) for (var = environ; *var != NULL; var++) environ_put(&global_environ, *var); + options_init(&global_options, NULL); + oo = &global_options; + options_set_number(oo, "quiet", 0); + options_init(&global_s_options, NULL); so = &global_s_options; options_set_number(so, "base-index", 0); diff --git a/tmux.h b/tmux.h index cf42a85c..e9d11f65 100644 --- a/tmux.h +++ b/tmux.h @@ -1235,6 +1235,7 @@ struct set_option_entry { }; /* tmux.c */ +extern struct options global_options; extern struct options global_s_options; extern struct options global_w_options; extern struct environ global_environ; @@ -1391,6 +1392,7 @@ extern const char clock_table[14][5][5]; void clock_draw(struct screen_write_ctx *, int, int); /* cmd-set-option.c */ +extern const struct set_option_entry set_option_table[]; extern const struct set_option_entry set_session_option_table[]; extern const struct set_option_entry set_window_option_table[]; const char *cmd_set_option_print( From 3f58cbaae91ac941c34bad3cb2447d6bcc541a2d Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 11 Dec 2009 13:58:48 +0000 Subject: [PATCH 0586/1180] Use quiet variable, and add missing sentinel to options array. --- cmd-set-option.c | 1 + tmux.c | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/cmd-set-option.c b/cmd-set-option.c index 64b78448..1a4df533 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -75,6 +75,7 @@ const char *set_option_bell_action_list[] = { const struct set_option_entry set_option_table[] = { { "quiet", SET_OPTION_FLAG, 0, 0, NULL }, + { NULL, 0, 0, 0, NULL } }; const struct set_option_entry set_session_option_table[] = { diff --git a/tmux.c b/tmux.c index 209042af..540c6f9f 100644 --- a/tmux.c +++ b/tmux.c @@ -229,7 +229,7 @@ main(int argc, char **argv) char cwd[MAXPATHLEN], **var; void *buf; size_t len; - int opt, flags, quiet, cmdflags = 0; + int opt, flags, quiet = 0, cmdflags = 0; short events; #ifdef DEBUG @@ -316,7 +316,7 @@ main(int argc, char **argv) options_init(&global_options, NULL); oo = &global_options; - options_set_number(oo, "quiet", 0); + options_set_number(oo, "quiet", quiet); options_init(&global_s_options, NULL); so = &global_s_options; From 30962cb2008a5f699bdf3e1da01a2554c53b8062 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 14 Dec 2009 10:43:41 +0000 Subject: [PATCH 0587/1180] New server option, escape-time, to set the timeout used to detect if escapes are alone or part of a function key or meta sequence. --- cmd-set-option.c | 1 + tmux.1 | 10 ++++++++-- tmux.c | 1 + tmux.h | 5 +---- tty-keys.c | 7 ++++--- 5 files changed, 15 insertions(+), 9 deletions(-) diff --git a/cmd-set-option.c b/cmd-set-option.c index 1a4df533..b445e537 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -74,6 +74,7 @@ const char *set_option_bell_action_list[] = { }; const struct set_option_entry set_option_table[] = { + { "escape-time", SET_OPTION_NUMBER, 0, INT_MAX, NULL }, { "quiet", SET_OPTION_FLAG, 0, 0, NULL }, { NULL, 0, 0, 0, NULL } }; diff --git a/tmux.1 b/tmux.1 index fbbfe79e..79e65af6 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1288,8 +1288,14 @@ Available window options are listed under .Pp Available server options are: .Bl -tag -width Ds +.It Ic escape-time +Set the time in milliseconds for which +.Nm +waits after an escape is input to determine if it is part of a function or meta +key sequences. +The default is 500 milliseconds. .It Ic quiet -Enable of disable the display of various informational messages (see also the +Enable or disable the display of various informational messages (see also the .Fl q command line flag). .El @@ -1884,7 +1890,7 @@ The default is off. Show the window options with .Fl w (equivalent to -.Ic show-window-options ), +.Ic show-window-options ) , the server options with .Fl s , otherwise the session options for diff --git a/tmux.c b/tmux.c index 540c6f9f..0e080306 100644 --- a/tmux.c +++ b/tmux.c @@ -317,6 +317,7 @@ main(int argc, char **argv) options_init(&global_options, NULL); oo = &global_options; options_set_number(oo, "quiet", quiet); + options_set_number(oo, "escape-time", 500); options_init(&global_s_options, NULL); so = &global_s_options; diff --git a/tmux.h b/tmux.h index e9d11f65..c68e560a 100644 --- a/tmux.h +++ b/tmux.h @@ -50,7 +50,7 @@ extern char **environ; /* Default prompt history length. */ #define PROMPT_HISTORY 100 -/* +/* * Minimum layout cell size, NOT including separator line. The scroll region * cannot be one line in height so this must be at least two. */ @@ -59,9 +59,6 @@ extern char **environ; /* Automatic name refresh interval, in milliseconds. */ #define NAME_INTERVAL 500 -/* Escape timer period, in milliseconds. */ -#define ESCAPE_PERIOD 500 - /* Maximum data to buffer for output before suspending reading from panes. */ #define BACKOFF_THRESHOLD 1024 diff --git a/tty-keys.c b/tty-keys.c index a88f9542..0ac1b43d 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -429,7 +429,7 @@ tty_keys_next(struct tty *tty) const char *buf; size_t len, size; cc_t bspace; - int key; + int key, delay; buf = EVBUFFER_DATA(tty->event->input); len = EVBUFFER_LENGTH(tty->event->input); @@ -521,8 +521,9 @@ partial_key: start_timer: /* Start the timer and wait for expiry or more data. */ - tv.tv_sec = 0; - tv.tv_usec = ESCAPE_PERIOD * 1000L; + delay = options_get_number(&global_options, "escape-time"); + tv.tv_sec = delay / 1000; + tv.tv_usec = (delay % 1000) * 1000L; evtimer_del(&tty->key_timer); evtimer_set(&tty->key_timer, tty_keys_callback, tty); From 84d2e6c8a0f7c501c3d326eb2bcbbbd8caa1658b Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 14 Dec 2009 10:47:11 +0000 Subject: [PATCH 0588/1180] Add server options to completion as well. --- status.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/status.c b/status.c index 42382578..535044ad 100644 --- a/status.c +++ b/status.c @@ -1130,6 +1130,10 @@ status_prompt_complete(const char *s) if (strncmp((*cmdent)->name, s, strlen(s)) == 0) ARRAY_ADD(&list, (*cmdent)->name); } + for (entry = set_option_table; entry->name != NULL; entry++) { + if (strncmp(entry->name, s, strlen(s)) == 0) + ARRAY_ADD(&list, entry->name); + } for (entry = set_session_option_table; entry->name != NULL; entry++) { if (strncmp(entry->name, s, strlen(s)) == 0) ARRAY_ADD(&list, entry->name); From 0dda866679009385d4973d18a123943f606c49ad Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 14 Dec 2009 21:33:38 +0000 Subject: [PATCH 0589/1180] Pass through the aixterm bright colours if the terminal supports them (>= 16 colours). --- input.c | 6 ++---- tty.c | 27 +++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/input.c b/input.c index 29d0f254..294cd522 100644 --- a/input.c +++ b/input.c @@ -1481,8 +1481,7 @@ input_handle_sequence_sgr(struct input_ctx *ictx) case 95: case 96: case 97: - gc->flags |= GRID_FLAG_FG256; - gc->fg = m - 82; + gc->fg = m; break; case 100: case 101: @@ -1492,8 +1491,7 @@ input_handle_sequence_sgr(struct input_ctx *ictx) case 105: case 106: case 107: - gc->flags |= GRID_FLAG_BG256; - gc->bg = m - 92; + gc->bg = m; break; } } diff --git a/tty.c b/tty.c index 32ee197c..c06a4dde 100644 --- a/tty.c +++ b/tty.c @@ -1231,6 +1231,7 @@ tty_colours(struct tty *tty, const struct grid_cell *gc, u_char *attr) if (fg == tc->fg && bg == tc->bg && ((flags ^ tc->flags) & (GRID_FLAG_FG256|GRID_FLAG_BG256)) == 0) return; + log_debug("fg was %hhu, now %hhu", tc->fg, fg); /* * Is either the default colour? This is handled specially because the @@ -1292,6 +1293,7 @@ tty_colours_fg(struct tty *tty, const struct grid_cell *gc, u_char *attr) { struct grid_cell *tc = &tty->cell; u_char fg = gc->fg; + char s[32]; /* Is this a 256-colour colour? */ if (gc->flags & GRID_FLAG_FG256) { @@ -1310,6 +1312,18 @@ tty_colours_fg(struct tty *tty, const struct grid_cell *gc, u_char *attr) tty_reset(tty); /* turn off bold */ } + /* Is this an aixterm bright colour? */ + if (fg >= 90 && fg <= 97) { + /* 16 colour terminals or above only. */ + if (tty_term_number(tty->term, TTYC_COLORS) >= 16) { + xsnprintf(s, sizeof s, "\033[%dm", fg); + tty_puts(tty, s); + goto save_fg; + } + fg -= 90; + (*attr) |= GRID_ATTR_BRIGHT; + } + /* Otherwise set the foreground colour. */ tty_putcode1(tty, TTYC_SETAF, fg); @@ -1325,6 +1339,7 @@ tty_colours_bg(struct tty *tty, const struct grid_cell *gc) { struct grid_cell *tc = &tty->cell; u_char bg = gc->bg; + char s[32]; /* Is this a 256-colour colour? */ if (gc->flags & GRID_FLAG_BG256) { @@ -1343,6 +1358,18 @@ tty_colours_bg(struct tty *tty, const struct grid_cell *gc) bg &= 7; } + /* Is this an aixterm bright colour? */ + if (bg >= 100 && bg <= 107) { + /* 16 colour terminals or above only. */ + if (tty_term_number(tty->term, TTYC_COLORS) >= 16) { + xsnprintf(s, sizeof s, "\033[%dm", bg); + tty_puts(tty, s); + goto save_bg; + } + bg -= 100; + /* no such thing as a bold background */ + } + /* Otherwise set the background colour. */ tty_putcode1(tty, TTYC_SETAB, bg); From 19ea306606b6386ea457838353e1aea759d47f19 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 17 Dec 2009 17:39:56 +0000 Subject: [PATCH 0590/1180] Allow keys to be replaced and reorder the table so that terminfo-defined keys (or terminal-overrides) take precedence over internally defined. --- tmux.h | 4 +- tty-keys.c | 260 +++++++++++++++++++++++++++-------------------------- 2 files changed, 136 insertions(+), 128 deletions(-) diff --git a/tmux.h b/tmux.h index c68e560a..8ffdf06a 100644 --- a/tmux.h +++ b/tmux.h @@ -1021,9 +1021,9 @@ struct tty_ctx { const struct grid_utf8 *utf8; u_int num; - void *ptr; + void *ptr; - /* + /* * Cursor and region position before the screen was updated - this is * where the command should be applied; the values in the screen have * already been updated. diff --git a/tty-keys.c b/tty-keys.c index 0ac1b43d..9404ef0a 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -55,134 +55,38 @@ struct tty_key_ent { * otherwise they are looked up in terminfo(5). */ struct tty_key_ent tty_keys[] = { - /* Function keys. */ - { TTYC_KF1, NULL, KEYC_F1, 0 }, - { TTYC_KF2, NULL, KEYC_F2, 0 }, - { TTYC_KF3, NULL, KEYC_F3, 0 }, - { TTYC_KF4, NULL, KEYC_F4, 0 }, - { TTYC_KF5, NULL, KEYC_F5, 0 }, - { TTYC_KF6, NULL, KEYC_F6, 0 }, - { TTYC_KF7, NULL, KEYC_F7, 0 }, - { TTYC_KF8, NULL, KEYC_F8, 0 }, - { TTYC_KF9, NULL, KEYC_F9, 0 }, - { TTYC_KF10, NULL, KEYC_F10, 0 }, - { TTYC_KF11, NULL, KEYC_F11, 0 }, - { TTYC_KF12, NULL, KEYC_F12, 0 }, - { TTYC_KF13, NULL, KEYC_F13, 0 }, - { TTYC_KF14, NULL, KEYC_F14, 0 }, - { TTYC_KF15, NULL, KEYC_F15, 0 }, - { TTYC_KF16, NULL, KEYC_F16, 0 }, - { TTYC_KF17, NULL, KEYC_F17, 0 }, - { TTYC_KF18, NULL, KEYC_F18, 0 }, - { TTYC_KF19, NULL, KEYC_F19, 0 }, - { TTYC_KF20, NULL, KEYC_F20, 0 }, - { TTYC_KICH1, NULL, KEYC_IC, 0 }, - { TTYC_KDCH1, NULL, KEYC_DC, 0 }, - { TTYC_KHOME, NULL, KEYC_HOME, 0 }, - { TTYC_KEND, NULL, KEYC_END, 0 }, - { TTYC_KNP, NULL, KEYC_NPAGE, 0 }, - { TTYC_KPP, NULL, KEYC_PPAGE, 0 }, - { TTYC_KCBT, NULL, KEYC_BTAB, 0 }, - - /* Arrow keys. */ - { 0, "\033OA", KEYC_UP, TTYKEY_RAW }, - { 0, "\033OB", KEYC_DOWN, TTYKEY_RAW }, - { 0, "\033OC", KEYC_RIGHT, TTYKEY_RAW }, - { 0, "\033OD", KEYC_LEFT, TTYKEY_RAW }, - - { 0, "\033[A", KEYC_UP, TTYKEY_RAW }, - { 0, "\033[B", KEYC_DOWN, TTYKEY_RAW }, - { 0, "\033[C", KEYC_RIGHT, TTYKEY_RAW }, - { 0, "\033[D", KEYC_LEFT, TTYKEY_RAW }, - - { TTYC_KCUU1, NULL, KEYC_UP, 0 }, - { TTYC_KCUD1, NULL, KEYC_DOWN, 0 }, - { TTYC_KCUB1, NULL, KEYC_LEFT, 0 }, - { TTYC_KCUF1, NULL, KEYC_RIGHT, 0 }, - /* * Numeric keypad. Just use the vt100 escape sequences here and always * put the terminal into keypad_xmit mode. Translation of numbers * mode/applications mode is done in input-keys.c. */ - { 0, "\033Oo", KEYC_KP_SLASH, TTYKEY_RAW }, - { 0, "\033Oj", KEYC_KP_STAR, TTYKEY_RAW }, - { 0, "\033Om", KEYC_KP_MINUS, TTYKEY_RAW }, - { 0, "\033Ow", KEYC_KP_SEVEN, TTYKEY_RAW }, - { 0, "\033Ox", KEYC_KP_EIGHT, TTYKEY_RAW }, - { 0, "\033Oy", KEYC_KP_NINE, TTYKEY_RAW }, - { 0, "\033Ok", KEYC_KP_PLUS, TTYKEY_RAW }, - { 0, "\033Ot", KEYC_KP_FOUR, TTYKEY_RAW }, - { 0, "\033Ou", KEYC_KP_FIVE, TTYKEY_RAW }, - { 0, "\033Ov", KEYC_KP_SIX, TTYKEY_RAW }, - { 0, "\033Oq", KEYC_KP_ONE, TTYKEY_RAW }, - { 0, "\033Or", KEYC_KP_TWO, TTYKEY_RAW }, - { 0, "\033Os", KEYC_KP_THREE, TTYKEY_RAW }, - { 0, "\033OM", KEYC_KP_ENTER, TTYKEY_RAW }, - { 0, "\033Op", KEYC_KP_ZERO, TTYKEY_RAW }, - { 0, "\033On", KEYC_KP_PERIOD, TTYKEY_RAW }, + { 0, "\033Oo", KEYC_KP_SLASH, TTYKEY_RAW }, + { 0, "\033Oj", KEYC_KP_STAR, TTYKEY_RAW }, + { 0, "\033Om", KEYC_KP_MINUS, TTYKEY_RAW }, + { 0, "\033Ow", KEYC_KP_SEVEN, TTYKEY_RAW }, + { 0, "\033Ox", KEYC_KP_EIGHT, TTYKEY_RAW }, + { 0, "\033Oy", KEYC_KP_NINE, TTYKEY_RAW }, + { 0, "\033Ok", KEYC_KP_PLUS, TTYKEY_RAW }, + { 0, "\033Ot", KEYC_KP_FOUR, TTYKEY_RAW }, + { 0, "\033Ou", KEYC_KP_FIVE, TTYKEY_RAW }, + { 0, "\033Ov", KEYC_KP_SIX, TTYKEY_RAW }, + { 0, "\033Oq", KEYC_KP_ONE, TTYKEY_RAW }, + { 0, "\033Or", KEYC_KP_TWO, TTYKEY_RAW }, + { 0, "\033Os", KEYC_KP_THREE, TTYKEY_RAW }, + { 0, "\033OM", KEYC_KP_ENTER, TTYKEY_RAW }, + { 0, "\033Op", KEYC_KP_ZERO, TTYKEY_RAW }, + { 0, "\033On", KEYC_KP_PERIOD, TTYKEY_RAW }, - /* Key and modifier capabilities. */ - { TTYC_KDC2, NULL, KEYC_DC|KEYC_SHIFT, 0 }, - { TTYC_KDC3, NULL, KEYC_DC|KEYC_ESCAPE, 0 }, - { TTYC_KDC4, NULL, KEYC_DC|KEYC_SHIFT|KEYC_ESCAPE, 0 }, - { TTYC_KDC5, NULL, KEYC_DC|KEYC_CTRL, 0 }, - { TTYC_KDC6, NULL, KEYC_DC|KEYC_SHIFT|KEYC_CTRL, 0 }, - { TTYC_KDC7, NULL, KEYC_DC|KEYC_ESCAPE|KEYC_CTRL, 0 }, - { TTYC_KDN2, NULL, KEYC_DOWN|KEYC_SHIFT, 0 }, - { TTYC_KDN3, NULL, KEYC_DOWN|KEYC_ESCAPE, 0 }, - { TTYC_KDN4, NULL, KEYC_DOWN|KEYC_SHIFT|KEYC_ESCAPE, 0 }, - { TTYC_KDN5, NULL, KEYC_DOWN|KEYC_CTRL, 0 }, - { TTYC_KDN6, NULL, KEYC_DOWN|KEYC_SHIFT|KEYC_CTRL, 0 }, - { TTYC_KDN7, NULL, KEYC_DOWN|KEYC_ESCAPE|KEYC_CTRL, 0 }, - { TTYC_KEND2, NULL, KEYC_END|KEYC_SHIFT, 0 }, - { TTYC_KEND3, NULL, KEYC_END|KEYC_ESCAPE, 0 }, - { TTYC_KEND4, NULL, KEYC_END|KEYC_SHIFT|KEYC_ESCAPE, 0 }, - { TTYC_KEND5, NULL, KEYC_END|KEYC_CTRL, 0 }, - { TTYC_KEND6, NULL, KEYC_END|KEYC_SHIFT|KEYC_CTRL, 0 }, - { TTYC_KEND7, NULL, KEYC_END|KEYC_ESCAPE|KEYC_CTRL, 0 }, - { TTYC_KHOM2, NULL, KEYC_HOME|KEYC_SHIFT, 0 }, - { TTYC_KHOM3, NULL, KEYC_HOME|KEYC_ESCAPE, 0 }, - { TTYC_KHOM4, NULL, KEYC_HOME|KEYC_SHIFT|KEYC_ESCAPE, 0 }, - { TTYC_KHOM5, NULL, KEYC_HOME|KEYC_CTRL, 0 }, - { TTYC_KHOM6, NULL, KEYC_HOME|KEYC_SHIFT|KEYC_CTRL, 0 }, - { TTYC_KHOM7, NULL, KEYC_HOME|KEYC_ESCAPE|KEYC_CTRL, 0 }, - { TTYC_KIC2, NULL, KEYC_IC|KEYC_SHIFT, 0 }, - { TTYC_KIC3, NULL, KEYC_IC|KEYC_ESCAPE, 0 }, - { TTYC_KIC4, NULL, KEYC_IC|KEYC_SHIFT|KEYC_ESCAPE, 0 }, - { TTYC_KIC5, NULL, KEYC_IC|KEYC_CTRL, 0 }, - { TTYC_KIC6, NULL, KEYC_IC|KEYC_SHIFT|KEYC_CTRL, 0 }, - { TTYC_KIC7, NULL, KEYC_IC|KEYC_ESCAPE|KEYC_CTRL, 0 }, - { TTYC_KLFT2, NULL, KEYC_LEFT|KEYC_SHIFT, 0 }, - { TTYC_KLFT3, NULL, KEYC_LEFT|KEYC_ESCAPE, 0 }, - { TTYC_KLFT4, NULL, KEYC_LEFT|KEYC_SHIFT|KEYC_ESCAPE, 0 }, - { TTYC_KLFT5, NULL, KEYC_LEFT|KEYC_CTRL, 0 }, - { TTYC_KLFT6, NULL, KEYC_LEFT|KEYC_SHIFT|KEYC_CTRL, 0 }, - { TTYC_KLFT7, NULL, KEYC_LEFT|KEYC_ESCAPE|KEYC_CTRL, 0 }, - { TTYC_KNXT2, NULL, KEYC_NPAGE|KEYC_SHIFT, 0 }, - { TTYC_KNXT3, NULL, KEYC_NPAGE|KEYC_ESCAPE, 0 }, - { TTYC_KNXT4, NULL, KEYC_NPAGE|KEYC_SHIFT|KEYC_ESCAPE, 0 }, - { TTYC_KNXT5, NULL, KEYC_NPAGE|KEYC_CTRL, 0 }, - { TTYC_KNXT6, NULL, KEYC_NPAGE|KEYC_SHIFT|KEYC_CTRL, 0 }, - { TTYC_KNXT7, NULL, KEYC_NPAGE|KEYC_ESCAPE|KEYC_CTRL, 0 }, - { TTYC_KPRV2, NULL, KEYC_PPAGE|KEYC_SHIFT, 0 }, - { TTYC_KPRV3, NULL, KEYC_PPAGE|KEYC_ESCAPE, 0 }, - { TTYC_KPRV4, NULL, KEYC_PPAGE|KEYC_SHIFT|KEYC_ESCAPE, 0 }, - { TTYC_KPRV5, NULL, KEYC_PPAGE|KEYC_CTRL, 0 }, - { TTYC_KPRV6, NULL, KEYC_PPAGE|KEYC_SHIFT|KEYC_CTRL, 0 }, - { TTYC_KPRV7, NULL, KEYC_PPAGE|KEYC_ESCAPE|KEYC_CTRL, 0 }, - { TTYC_KRIT2, NULL, KEYC_RIGHT|KEYC_SHIFT, 0 }, - { TTYC_KRIT3, NULL, KEYC_RIGHT|KEYC_ESCAPE, 0 }, - { TTYC_KRIT4, NULL, KEYC_RIGHT|KEYC_SHIFT|KEYC_ESCAPE, 0 }, - { TTYC_KRIT5, NULL, KEYC_RIGHT|KEYC_CTRL, 0 }, - { TTYC_KRIT6, NULL, KEYC_RIGHT|KEYC_SHIFT|KEYC_CTRL, 0 }, - { TTYC_KRIT7, NULL, KEYC_RIGHT|KEYC_ESCAPE|KEYC_CTRL, 0 }, - { TTYC_KUP2, NULL, KEYC_UP|KEYC_SHIFT, 0 }, - { TTYC_KUP3, NULL, KEYC_UP|KEYC_ESCAPE, 0 }, - { TTYC_KUP4, NULL, KEYC_UP|KEYC_SHIFT|KEYC_ESCAPE, 0 }, - { TTYC_KUP5, NULL, KEYC_UP|KEYC_CTRL, 0 }, - { TTYC_KUP6, NULL, KEYC_UP|KEYC_SHIFT|KEYC_CTRL, 0 }, - { TTYC_KUP7, NULL, KEYC_UP|KEYC_ESCAPE|KEYC_CTRL, 0 }, + /* Arrow keys. */ + { 0, "\033OA", KEYC_UP, TTYKEY_RAW }, + { 0, "\033OB", KEYC_DOWN, TTYKEY_RAW }, + { 0, "\033OC", KEYC_RIGHT, TTYKEY_RAW }, + { 0, "\033OD", KEYC_LEFT, TTYKEY_RAW }, + + { 0, "\033[A", KEYC_UP, TTYKEY_RAW }, + { 0, "\033[B", KEYC_DOWN, TTYKEY_RAW }, + { 0, "\033[C", KEYC_RIGHT, TTYKEY_RAW }, + { 0, "\033[D", KEYC_LEFT, TTYKEY_RAW }, /* rxvt-style arrow + modifier keys. */ { 0, "\033Oa", KEYC_UP|KEYC_CTRL, TTYKEY_RAW }, @@ -279,16 +183,121 @@ struct tty_key_ent tty_keys[] = { { 0, "\033[8@", KEYC_END|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW }, { 0, "\033[6@", KEYC_NPAGE|KEYC_CTRL|KEYC_SHIFT,TTYKEY_RAW }, { 0, "\033[5@", KEYC_PPAGE|KEYC_CTRL|KEYC_SHIFT,TTYKEY_RAW }, + + /* terminfo lookups below this line so they can override raw keys. */ + + /* Function keys. */ + { TTYC_KF1, NULL, KEYC_F1, 0 }, + { TTYC_KF2, NULL, KEYC_F2, 0 }, + { TTYC_KF3, NULL, KEYC_F3, 0 }, + { TTYC_KF4, NULL, KEYC_F4, 0 }, + { TTYC_KF5, NULL, KEYC_F5, 0 }, + { TTYC_KF6, NULL, KEYC_F6, 0 }, + { TTYC_KF7, NULL, KEYC_F7, 0 }, + { TTYC_KF8, NULL, KEYC_F8, 0 }, + { TTYC_KF9, NULL, KEYC_F9, 0 }, + { TTYC_KF10, NULL, KEYC_F10, 0 }, + { TTYC_KF11, NULL, KEYC_F11, 0 }, + { TTYC_KF12, NULL, KEYC_F12, 0 }, + { TTYC_KF13, NULL, KEYC_F13, 0 }, + { TTYC_KF14, NULL, KEYC_F14, 0 }, + { TTYC_KF15, NULL, KEYC_F15, 0 }, + { TTYC_KF16, NULL, KEYC_F16, 0 }, + { TTYC_KF17, NULL, KEYC_F17, 0 }, + { TTYC_KF18, NULL, KEYC_F18, 0 }, + { TTYC_KF19, NULL, KEYC_F19, 0 }, + { TTYC_KF20, NULL, KEYC_F20, 0 }, + { TTYC_KICH1, NULL, KEYC_IC, 0 }, + { TTYC_KDCH1, NULL, KEYC_DC, 0 }, + { TTYC_KHOME, NULL, KEYC_HOME, 0 }, + { TTYC_KEND, NULL, KEYC_END, 0 }, + { TTYC_KNP, NULL, KEYC_NPAGE, 0 }, + { TTYC_KPP, NULL, KEYC_PPAGE, 0 }, + { TTYC_KCBT, NULL, KEYC_BTAB, 0 }, + + /* Arrow keys from terminfo. */ + { TTYC_KCUU1, NULL, KEYC_UP, 0 }, + { TTYC_KCUD1, NULL, KEYC_DOWN, 0 }, + { TTYC_KCUB1, NULL, KEYC_LEFT, 0 }, + { TTYC_KCUF1, NULL, KEYC_RIGHT, 0 }, + + /* Key and modifier capabilities. */ + { TTYC_KDC2, NULL, KEYC_DC|KEYC_SHIFT, 0 }, + { TTYC_KDC3, NULL, KEYC_DC|KEYC_ESCAPE, 0 }, + { TTYC_KDC4, NULL, KEYC_DC|KEYC_SHIFT|KEYC_ESCAPE, 0 }, + { TTYC_KDC5, NULL, KEYC_DC|KEYC_CTRL, 0 }, + { TTYC_KDC6, NULL, KEYC_DC|KEYC_SHIFT|KEYC_CTRL, 0 }, + { TTYC_KDC7, NULL, KEYC_DC|KEYC_ESCAPE|KEYC_CTRL, 0 }, + { TTYC_KDN2, NULL, KEYC_DOWN|KEYC_SHIFT, 0 }, + { TTYC_KDN3, NULL, KEYC_DOWN|KEYC_ESCAPE, 0 }, + { TTYC_KDN4, NULL, KEYC_DOWN|KEYC_SHIFT|KEYC_ESCAPE, 0 }, + { TTYC_KDN5, NULL, KEYC_DOWN|KEYC_CTRL, 0 }, + { TTYC_KDN6, NULL, KEYC_DOWN|KEYC_SHIFT|KEYC_CTRL, 0 }, + { TTYC_KDN7, NULL, KEYC_DOWN|KEYC_ESCAPE|KEYC_CTRL, 0 }, + { TTYC_KEND2, NULL, KEYC_END|KEYC_SHIFT, 0 }, + { TTYC_KEND3, NULL, KEYC_END|KEYC_ESCAPE, 0 }, + { TTYC_KEND4, NULL, KEYC_END|KEYC_SHIFT|KEYC_ESCAPE, 0 }, + { TTYC_KEND5, NULL, KEYC_END|KEYC_CTRL, 0 }, + { TTYC_KEND6, NULL, KEYC_END|KEYC_SHIFT|KEYC_CTRL, 0 }, + { TTYC_KEND7, NULL, KEYC_END|KEYC_ESCAPE|KEYC_CTRL, 0 }, + { TTYC_KHOM2, NULL, KEYC_HOME|KEYC_SHIFT, 0 }, + { TTYC_KHOM3, NULL, KEYC_HOME|KEYC_ESCAPE, 0 }, + { TTYC_KHOM4, NULL, KEYC_HOME|KEYC_SHIFT|KEYC_ESCAPE, 0 }, + { TTYC_KHOM5, NULL, KEYC_HOME|KEYC_CTRL, 0 }, + { TTYC_KHOM6, NULL, KEYC_HOME|KEYC_SHIFT|KEYC_CTRL, 0 }, + { TTYC_KHOM7, NULL, KEYC_HOME|KEYC_ESCAPE|KEYC_CTRL, 0 }, + { TTYC_KIC2, NULL, KEYC_IC|KEYC_SHIFT, 0 }, + { TTYC_KIC3, NULL, KEYC_IC|KEYC_ESCAPE, 0 }, + { TTYC_KIC4, NULL, KEYC_IC|KEYC_SHIFT|KEYC_ESCAPE, 0 }, + { TTYC_KIC5, NULL, KEYC_IC|KEYC_CTRL, 0 }, + { TTYC_KIC6, NULL, KEYC_IC|KEYC_SHIFT|KEYC_CTRL, 0 }, + { TTYC_KIC7, NULL, KEYC_IC|KEYC_ESCAPE|KEYC_CTRL, 0 }, + { TTYC_KLFT2, NULL, KEYC_LEFT|KEYC_SHIFT, 0 }, + { TTYC_KLFT3, NULL, KEYC_LEFT|KEYC_ESCAPE, 0 }, + { TTYC_KLFT4, NULL, KEYC_LEFT|KEYC_SHIFT|KEYC_ESCAPE, 0 }, + { TTYC_KLFT5, NULL, KEYC_LEFT|KEYC_CTRL, 0 }, + { TTYC_KLFT6, NULL, KEYC_LEFT|KEYC_SHIFT|KEYC_CTRL, 0 }, + { TTYC_KLFT7, NULL, KEYC_LEFT|KEYC_ESCAPE|KEYC_CTRL, 0 }, + { TTYC_KNXT2, NULL, KEYC_NPAGE|KEYC_SHIFT, 0 }, + { TTYC_KNXT3, NULL, KEYC_NPAGE|KEYC_ESCAPE, 0 }, + { TTYC_KNXT4, NULL, KEYC_NPAGE|KEYC_SHIFT|KEYC_ESCAPE, 0 }, + { TTYC_KNXT5, NULL, KEYC_NPAGE|KEYC_CTRL, 0 }, + { TTYC_KNXT6, NULL, KEYC_NPAGE|KEYC_SHIFT|KEYC_CTRL, 0 }, + { TTYC_KNXT7, NULL, KEYC_NPAGE|KEYC_ESCAPE|KEYC_CTRL, 0 }, + { TTYC_KPRV2, NULL, KEYC_PPAGE|KEYC_SHIFT, 0 }, + { TTYC_KPRV3, NULL, KEYC_PPAGE|KEYC_ESCAPE, 0 }, + { TTYC_KPRV4, NULL, KEYC_PPAGE|KEYC_SHIFT|KEYC_ESCAPE, 0 }, + { TTYC_KPRV5, NULL, KEYC_PPAGE|KEYC_CTRL, 0 }, + { TTYC_KPRV6, NULL, KEYC_PPAGE|KEYC_SHIFT|KEYC_CTRL, 0 }, + { TTYC_KPRV7, NULL, KEYC_PPAGE|KEYC_ESCAPE|KEYC_CTRL, 0 }, + { TTYC_KRIT2, NULL, KEYC_RIGHT|KEYC_SHIFT, 0 }, + { TTYC_KRIT3, NULL, KEYC_RIGHT|KEYC_ESCAPE, 0 }, + { TTYC_KRIT4, NULL, KEYC_RIGHT|KEYC_SHIFT|KEYC_ESCAPE, 0 }, + { TTYC_KRIT5, NULL, KEYC_RIGHT|KEYC_CTRL, 0 }, + { TTYC_KRIT6, NULL, KEYC_RIGHT|KEYC_SHIFT|KEYC_CTRL, 0 }, + { TTYC_KRIT7, NULL, KEYC_RIGHT|KEYC_ESCAPE|KEYC_CTRL, 0 }, + { TTYC_KUP2, NULL, KEYC_UP|KEYC_SHIFT, 0 }, + { TTYC_KUP3, NULL, KEYC_UP|KEYC_ESCAPE, 0 }, + { TTYC_KUP4, NULL, KEYC_UP|KEYC_SHIFT|KEYC_ESCAPE, 0 }, + { TTYC_KUP5, NULL, KEYC_UP|KEYC_CTRL, 0 }, + { TTYC_KUP6, NULL, KEYC_UP|KEYC_SHIFT|KEYC_CTRL, 0 }, + { TTYC_KUP7, NULL, KEYC_UP|KEYC_ESCAPE|KEYC_CTRL, 0 }, }; void tty_keys_add(struct tty *tty, const char *s, int key) { - size_t size; + struct tty_key *tk; + size_t size; + const char *keystr; - if (tty_keys_find(tty, s, strlen(s), &size) == NULL) { - log_debug("new key 0x%x: %s", key, s); + keystr = key_string_lookup_key(key); + if ((tk = tty_keys_find(tty, s, strlen(s), &size)) == NULL) { + log_debug("new key %s: 0x%x (%s)", s, key, keystr); tty_keys_add1(&tty->key_tree, s, key); + } else { + log_debug("replacing key %s: 0x%x (%s)", s, key, keystr); + tk->key = key; } } @@ -374,7 +383,6 @@ tty_keys_free1(struct tty_key *tk) if (tk->right != NULL) tty_keys_free1(tk->right); xfree(tk); - } /* Lookup a key in the tree. */ From 4feee126b86d59e29886407cd5c534b6e1cb2ba1 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 22 Dec 2009 10:20:08 +0000 Subject: [PATCH 0591/1180] Fix a couple of problems with grouped sessions reported by danh: redraw properly and choose the correct last window after a window is killed. --- server-fn.c | 6 ++---- session.c | 8 ++++---- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/server-fn.c b/server-fn.c index b8207ca2..df6aa134 100644 --- a/server-fn.c +++ b/server-fn.c @@ -250,10 +250,8 @@ server_kill_window(struct window *w) if (session_detach(s, wl)) server_destroy_session_group(s); - else { - server_redraw_session(s); - server_status_session_group(s); - } + else + server_redraw_session_group(s); } } diff --git a/session.c b/session.c index 457d3fd2..20656957 100644 --- a/session.c +++ b/session.c @@ -549,10 +549,10 @@ session_group_synchronize1(struct session *target, struct session *s) return; /* If the current window has vanished, move to the next now. */ - if (s->curw != NULL) { - while (winlink_find_by_index(ww, s->curw->idx) == NULL) - session_next(s, 0); - } + if (s->curw != NULL && + winlink_find_by_index(ww, s->curw->idx) == NULL && + session_last(s) != 0 && session_previous(s, 0) != 0) + session_next(s, 0); /* Save the old pointer and reset it. */ memcpy(&old_windows, &s->windows, sizeof old_windows); From a3715e786722bd64506b885e9a33d78134d02dfa Mon Sep 17 00:00:00 2001 From: Philip Guenther Date: Thu, 24 Dec 2009 22:29:15 +0000 Subject: [PATCH 0592/1180] Use sysctl() KERN_PROC2 instead of KERN_PROC, as the latter's ABI is sensitive to changes in struct proc. fixes for warnings and ok nicm@ --- procname.c | 30 +++++++++++------------------- 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/procname.c b/procname.c index 85d5212e..064e0db2 100644 --- a/procname.c +++ b/procname.c @@ -34,14 +34,12 @@ #define is_stopped(p) \ ((p)->p_stat == SSTOP || (p)->p_stat == SZOMB || (p)->p_stat == SDEAD) -struct proc *cmp_procs(struct proc *, struct proc *); +struct kinfo_proc2 *cmp_procs(struct kinfo_proc2 *, struct kinfo_proc2 *); char *get_proc_name(int, char *); -struct proc * -cmp_procs(struct proc *p1, struct proc *p2) +struct kinfo_proc2 * +cmp_procs(struct kinfo_proc2 *p1, struct kinfo_proc2 *p2) { - void *ptr1, *ptr2; - if (is_runnable(p1) && !is_runnable(p2)) return (p1); if (!is_runnable(p1) && is_runnable(p2)) @@ -67,13 +65,6 @@ cmp_procs(struct proc *p1, struct proc *p2) if (!(p1->p_flag & P_SINTR) && (p2->p_flag & P_SINTR)) return (p2); - ptr1 = LIST_FIRST(&p1->p_children); - ptr2 = LIST_FIRST(&p2->p_children); - if (ptr1 == NULL && ptr2 != NULL) - return (p1); - if (ptr1 != NULL && ptr2 == NULL) - return (p2); - if (strcmp(p1->p_comm, p2->p_comm) < 0) return (p1); if (strcmp(p1->p_comm, p2->p_comm) > 0) @@ -87,11 +78,11 @@ cmp_procs(struct proc *p1, struct proc *p2) char * get_proc_name(int fd, char *tty) { - int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PGRP, 0 }; + int mib[6] = { CTL_KERN, KERN_PROC2, KERN_PROC_PGRP, 0, + sizeof(struct kinfo_proc2), 0 }; struct stat sb; size_t len; - struct kinfo_proc *buf, *newbuf; - struct proc *bestp; + struct kinfo_proc2 *buf, *newbuf, *bestp; u_int i; char *name; @@ -111,6 +102,7 @@ retry: goto error; buf = newbuf; + mib[5] = (int)(len / sizeof(struct kinfo_proc2)); if (sysctl(mib, nitems(mib), buf, &len, NULL, 0) == -1) { if (errno == ENOMEM) goto retry; @@ -118,13 +110,13 @@ retry: } bestp = NULL; - for (i = 0; i < len / sizeof (struct kinfo_proc); i++) { - if (buf[i].kp_eproc.e_tdev != sb.st_rdev) + for (i = 0; i < len / sizeof (struct kinfo_proc2); i++) { + if ((dev_t)buf[i].p_tdev != sb.st_rdev) continue; if (bestp == NULL) - bestp = &buf[i].kp_proc; + bestp = &buf[i]; else - bestp = cmp_procs(&buf[i].kp_proc, bestp); + bestp = cmp_procs(&buf[i], bestp); } name = NULL; From cd9b1b1fd399479ed58feb51201c2bc1db55faa5 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 26 Dec 2009 10:39:02 +0000 Subject: [PATCH 0593/1180] Nuke some stray debugging. --- tty.c | 1 - 1 file changed, 1 deletion(-) diff --git a/tty.c b/tty.c index c06a4dde..43f1701a 100644 --- a/tty.c +++ b/tty.c @@ -1231,7 +1231,6 @@ tty_colours(struct tty *tty, const struct grid_cell *gc, u_char *attr) if (fg == tc->fg && bg == tc->bg && ((flags ^ tc->flags) & (GRID_FLAG_FG256|GRID_FLAG_BG256)) == 0) return; - log_debug("fg was %hhu, now %hhu", tc->fg, fg); /* * Is either the default colour? This is handled specially because the From a775107f5f346e66e92652fb2cbfabebe83de570 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 26 Dec 2009 11:02:32 +0000 Subject: [PATCH 0594/1180] Fix the logic so that transition from a 256 colour to default works properly. --- tty.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tty.c b/tty.c index 43f1701a..a66c71a9 100644 --- a/tty.c +++ b/tty.c @@ -1253,19 +1253,21 @@ tty_colours(struct tty *tty, const struct grid_cell *gc, u_char *attr) tty_reset(tty); else { if (fg_default && - fg != tc->fg && !(tc->flags & GRID_FLAG_FG256)) { + (tc->fg != 8 || tc->flags & GRID_FLAG_FG256)) { if (have_ax) tty_puts(tty, "\033[39m"); - else if (tc->fg != 7) + else if (tc->fg != 7 || + tc->flags & GRID_FLAG_FG256) tty_putcode1(tty, TTYC_SETAF, 7); tc->fg = 8; tc->flags &= ~GRID_FLAG_FG256; } if (bg_default && - bg != tc->bg && !(tc->flags & GRID_FLAG_BG256)) { + (tc->bg != 8 || tc->flags & GRID_FLAG_BG256)) { if (have_ax) tty_puts(tty, "\033[49m"); - else if (tc->bg != 0) + else if (tc->bg != 0 || + tc->flags & GRID_FLAG_BG256) tty_putcode1(tty, TTYC_SETAB, 0); tc->bg = 8; tc->flags &= ~GRID_FLAG_BG256; From 9ee979167a433fe8a0fb76735cd220a37ee994f2 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 1 Jan 2010 14:29:18 +0000 Subject: [PATCH 0595/1180] Use tcflush(3) instead of TIOCFLUSH, from Ed Schouten. --- tty.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/tty.c b/tty.c index a66c71a9..a84d8def 100644 --- a/tty.c +++ b/tty.c @@ -146,7 +146,7 @@ void tty_start_tty(struct tty *tty) { struct termios tio; - int what, mode; + int mode; if (tty->fd == -1) return; @@ -170,10 +170,7 @@ tty_start_tty(struct tty *tty) tio.c_cc[VTIME] = 0; if (tcsetattr(tty->fd, TCSANOW, &tio) != 0) fatal("tcsetattr failed"); - - what = 0; - if (ioctl(tty->fd, TIOCFLUSH, &what) != 0) - fatal("ioctl(TIOCFLUSH)"); + tcflush(tty->fd, TCIOFLUSH); tty_putcode(tty, TTYC_SMCUP); From 121ba57b55adc9aff5b131cfac310ac41c0491ba Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 2 Jan 2010 22:50:02 +0000 Subject: [PATCH 0596/1180] Use the target print function for copy-mode, spotted by Tiago Cunha. --- cmd-copy-mode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd-copy-mode.c b/cmd-copy-mode.c index 48cdd656..ed95105a 100644 --- a/cmd-copy-mode.c +++ b/cmd-copy-mode.c @@ -35,7 +35,7 @@ const struct cmd_entry cmd_copy_mode_entry = { cmd_target_parse, cmd_copy_mode_exec, cmd_target_free, - NULL + cmd_target_print }; void From 7e4f8b45b64b0cbe889c5846806038c4c45c36e8 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 3 Jan 2010 12:51:05 +0000 Subject: [PATCH 0597/1180] Options to set the colour of the pane borders, with different colours for the active pane. --- cmd-down-pane.c | 1 + cmd-select-pane.c | 1 + cmd-set-option.c | 4 ++ cmd-up-pane.c | 1 + screen-redraw.c | 97 +++++++++++++++++++++++++++++++---------------- server-client.c | 11 ++++-- server-fn.c | 15 ++++++++ tmux.1 | 6 +++ tmux.c | 4 ++ tmux.h | 4 +- 10 files changed, 106 insertions(+), 38 deletions(-) diff --git a/cmd-down-pane.c b/cmd-down-pane.c index a0f771eb..a065a6e9 100644 --- a/cmd-down-pane.c +++ b/cmd-down-pane.c @@ -54,6 +54,7 @@ cmd_down_pane_exec(struct cmd *self, struct cmd_ctx *ctx) w->active = TAILQ_FIRST(&w->panes); } while (!window_pane_visible(w->active)); server_status_window(wl->window); + server_redraw_window_borders(wl->window); return (0); } diff --git a/cmd-select-pane.c b/cmd-select-pane.c index 890cebc6..956ed912 100644 --- a/cmd-select-pane.c +++ b/cmd-select-pane.c @@ -53,6 +53,7 @@ cmd_select_pane_exec(struct cmd *self, struct cmd_ctx *ctx) } window_set_active_pane(wl->window, wp); server_status_window(wl->window); + server_redraw_window_borders(wl->window); return (0); } diff --git a/cmd-set-option.c b/cmd-set-option.c index b445e537..06535e0d 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -99,6 +99,10 @@ const struct set_option_entry set_session_option_table[] = { { "message-fg", SET_OPTION_COLOUR, 0, 0, NULL }, { "message-limit", SET_OPTION_NUMBER, 0, INT_MAX, NULL }, { "mouse-select-pane", SET_OPTION_FLAG, 0, 0, NULL }, + { "pane-active-border-bg", SET_OPTION_COLOUR, 0, 0, NULL }, + { "pane-active-border-fg", SET_OPTION_COLOUR, 0, 0, NULL }, + { "pane-border-bg", SET_OPTION_COLOUR, 0, 0, NULL }, + { "pane-border-fg", SET_OPTION_COLOUR, 0, 0, NULL }, { "prefix", SET_OPTION_KEYS, 0, 0, NULL }, { "repeat-time", SET_OPTION_NUMBER, 0, SHRT_MAX, NULL }, { "set-remain-on-exit", SET_OPTION_FLAG, 0, 0, NULL }, diff --git a/cmd-up-pane.c b/cmd-up-pane.c index 49ab49a7..62fe76be 100644 --- a/cmd-up-pane.c +++ b/cmd-up-pane.c @@ -54,6 +54,7 @@ cmd_up_pane_exec(struct cmd *self, struct cmd_ctx *ctx) w->active = TAILQ_LAST(&w->panes, window_panes); } while (!window_pane_visible(w->active)); server_status_window(wl->window); + server_redraw_window_borders(wl->window); return (0); } diff --git a/screen-redraw.c b/screen-redraw.c index 03dd52db..83eafa62 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -22,6 +22,7 @@ #include "tmux.h" +int screen_redraw_cell_border1(struct window_pane *, u_int, u_int); int screen_redraw_cell_border(struct client *, u_int, u_int); int screen_redraw_check_cell(struct client *, u_int, u_int); void screen_redraw_draw_number(struct client *, struct window_pane *); @@ -40,40 +41,49 @@ void screen_redraw_draw_number(struct client *, struct window_pane *); #define CELL_JOIN 11 #define CELL_OUTSIDE 12 +/* Check if cell is on the border of a particular pane. */ +int +screen_redraw_cell_border1(struct window_pane *wp, u_int px, u_int py) +{ + /* Inside pane. */ + if (px >= wp->xoff && px < wp->xoff + wp->sx && + py >= wp->yoff && py < wp->yoff + wp->sy) + return (0); + + /* Left/right borders. */ + if ((wp->yoff == 0 || py >= wp->yoff - 1) && py <= wp->yoff + wp->sy) { + if (wp->xoff != 0 && px == wp->xoff - 1) + return (1); + if (px == wp->xoff + wp->sx) + return (1); + } + + /* Top/bottom borders. */ + if ((wp->xoff == 0 || px >= wp->xoff - 1) && px <= wp->xoff + wp->sx) { + if (wp->yoff != 0 && py == wp->yoff - 1) + return (1); + if (py == wp->yoff + wp->sy) + return (1); + } + + /* Outside pane. */ + return (-1); +} + /* Check if a cell is on the pane border. */ int screen_redraw_cell_border(struct client *c, u_int px, u_int py) { struct window *w = c->session->curw->window; struct window_pane *wp; + int retval; /* Check all the panes. */ TAILQ_FOREACH(wp, &w->panes, entry) { if (!window_pane_visible(wp)) continue; - - /* Inside pane. */ - if (px >= wp->xoff && px < wp->xoff + wp->sx && - py >= wp->yoff && py < wp->yoff + wp->sy) - return (0); - - /* Left/right borders. */ - if ((wp->yoff == 0 || py >= wp->yoff - 1) && - py <= wp->yoff + wp->sy) { - if (wp->xoff != 0 && px == wp->xoff - 1) - return (1); - if (px == wp->xoff + wp->sx) - return (1); - } - - /* Top/bottom borders. */ - if ((wp->xoff == 0 || px >= wp->xoff - 1) && - px <= wp->xoff + wp->sx) { - if (wp->yoff != 0 && py == wp->yoff - 1) - return (1); - if (py == wp->yoff + wp->sy) - return (1); - } + if ((retval = screen_redraw_cell_border1(wp, px, py)) != -1) + return (retval); } return (0); @@ -155,13 +165,14 @@ screen_redraw_check_cell(struct client *c, u_int px, u_int py) /* Redraw entire screen. */ void -screen_redraw_screen(struct client *c, int status_only) +screen_redraw_screen(struct client *c, int status_only, int borders_only) { struct window *w = c->session->curw->window; struct tty *tty = &c->tty; struct window_pane *wp; + struct grid_cell active_gc, other_gc; u_int i, j, type; - int status; + int status, fg, bg; const u_char *base, *ptr; u_char ch, border[20]; @@ -178,8 +189,20 @@ screen_redraw_screen(struct client *c, int status_only) return; } + /* Set up pane border attributes. */ + memcpy(&other_gc, &grid_default_cell, sizeof other_gc); + memcpy(&active_gc, &grid_default_cell, sizeof active_gc); + active_gc.data = other_gc.data = 'x'; /* not space */ + fg = options_get_number(&c->session->options, "pane-border-fg"); + colour_set_fg(&other_gc, fg); + bg = options_get_number(&c->session->options, "pane-border-bg"); + colour_set_bg(&other_gc, bg); + fg = options_get_number(&c->session->options, "pane-active-border-fg"); + colour_set_fg(&active_gc, fg); + bg = options_get_number(&c->session->options, "pane-active-border-bg"); + colour_set_bg(&active_gc, bg); + /* Draw background and borders. */ - tty_reset(tty); strlcpy(border, " |-....--||+.", sizeof border); if (tty_term_has(tty->term, TTYC_ACSC)) { base = " xqlkmjwvtun~"; @@ -187,22 +210,30 @@ screen_redraw_screen(struct client *c, int status_only) if ((ch = tty_get_acs(tty, *ptr)) != '\0') border[ptr - base] = ch; } - tty_putcode(tty, TTYC_SMACS); + other_gc.attr |= GRID_ATTR_CHARSET; + active_gc.attr |= GRID_ATTR_CHARSET; } for (j = 0; j < tty->sy - status; j++) { if (status_only && j != tty->sy - 1) continue; for (i = 0; i < tty->sx; i++) { type = screen_redraw_check_cell(c, i, j); - if (type != CELL_INSIDE) { - tty_cursor(tty, i, j); - tty_putc(tty, border[type]); - } + if (type == CELL_INSIDE) + continue; + if (screen_redraw_cell_border1(w->active, i, j) == 1) + tty_attributes(tty, &active_gc); + else + tty_attributes(tty, &other_gc); + tty_cursor(tty, i, j); + tty_putc(tty, border[type]); } } - tty_putcode(tty, TTYC_RMACS); - /* Draw the panes. */ + /* 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; diff --git a/server-client.c b/server-client.c index 02edabc6..c321a4c2 100644 --- a/server-client.c +++ b/server-client.c @@ -463,8 +463,8 @@ server_client_check_redraw(struct client *c) } if (c->flags & CLIENT_REDRAW) { - screen_redraw_screen(c, 0); - c->flags &= ~CLIENT_STATUS; + screen_redraw_screen(c, 0, 0); + c->flags &= ~(CLIENT_STATUS|CLIENT_BORDERS); } else { TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry) { if (wp->flags & PANE_REDRAW) @@ -472,12 +472,15 @@ server_client_check_redraw(struct client *c) } } + if (c->flags & CLIENT_BORDERS) + screen_redraw_screen(c, 0, 1); + if (c->flags & CLIENT_STATUS) - screen_redraw_screen(c, 1); + screen_redraw_screen(c, 1, 0); c->tty.flags |= flags; - c->flags &= ~(CLIENT_REDRAW|CLIENT_STATUS); + c->flags &= ~(CLIENT_REDRAW|CLIENT_STATUS|CLIENT_BORDERS); } /* Set client title. */ diff --git a/server-fn.c b/server-fn.c index df6aa134..ce5e518d 100644 --- a/server-fn.c +++ b/server-fn.c @@ -164,6 +164,21 @@ server_redraw_window(struct window *w) w->flags |= WINDOW_REDRAW; } +void +server_redraw_window_borders(struct window *w) +{ + struct client *c; + u_int i; + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c == NULL || c->session == NULL) + continue; + if (c->session->curw->window == w) + c->flags |= CLIENT_BORDERS; + } +} + void server_status_window(struct window *w) { diff --git a/tmux.1 b/tmux.1 index 79e65af6..41b28d46 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1457,6 +1457,12 @@ If on, captures the mouse and when a window is split into multiple panes the mouse may be used to select the current pane. The mouse click is also passed through to the application as normal. +.It Ic pane-border-fg Ar colour +.It Ic pane-border-bg Ar colour +Set the pane border colour for panes aside from the active pane. +.It Ic pane-active-border-fg Ar colour +.It Ic pane-active-border-bg Ar colour +Set the pane border colour for the currently active pane. .It Ic prefix Ar keys Set the keys accepted as a prefix key. .Ar keys diff --git a/tmux.c b/tmux.c index 0e080306..24aa24f6 100644 --- a/tmux.c +++ b/tmux.c @@ -339,6 +339,10 @@ main(int argc, char **argv) options_set_number(so, "message-fg", 0); options_set_number(so, "message-limit", 20); options_set_number(so, "mouse-select-pane", 0); + options_set_number(so, "pane-active-border-bg", 2); + options_set_number(so, "pane-active-border-fg", 8); + options_set_number(so, "pane-border-bg", 8); + options_set_number(so, "pane-border-fg", 8); options_set_number(so, "repeat-time", 500); options_set_number(so, "set-remain-on-exit", 0); options_set_number(so, "set-titles", 0); diff --git a/tmux.h b/tmux.h index 8ffdf06a..56ef4aac 100644 --- a/tmux.h +++ b/tmux.h @@ -1083,6 +1083,7 @@ struct client { #define CLIENT_BAD 0x80 #define CLIENT_IDENTIFY 0x100 #define CLIENT_DEAD 0x200 +#define CLIENT_BORDERS 0x400 int flags; struct event identify_timer; @@ -1589,6 +1590,7 @@ void server_redraw_session_group(struct session *); void server_status_session(struct session *); void server_status_session_group(struct session *); void server_redraw_window(struct window *); +void server_redraw_window_borders(struct window *); void server_status_window(struct window *); void server_lock(void); void server_lock_session(struct session *); @@ -1749,7 +1751,7 @@ void screen_write_cell(struct screen_write_ctx *, const struct grid_cell *, const struct utf8_data *); /* screen-redraw.c */ -void screen_redraw_screen(struct client *, int); +void screen_redraw_screen(struct client *, int, int); void screen_redraw_pane(struct client *, struct window_pane *); /* screen.c */ From 739b937b74547038615996749143a69f0707b0c0 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 3 Jan 2010 17:12:04 +0000 Subject: [PATCH 0598/1180] Fix selection behaviour when the cursor is moved backwards (ie so the selection start is after the end). --- screen.c | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/screen.c b/screen.c index a9fa81ec..0d4f6e73 100644 --- a/screen.c +++ b/screen.c @@ -234,11 +234,31 @@ screen_set_selection(struct screen *s, struct screen_sel *sel = &s->sel; memcpy(&sel->cell, gc, sizeof sel->cell); - sel->flag = 1; - if (ey < sy || (sy == ey && ex < sx)) { + + /* starting line < ending line -- downward selection. */ + if (sy < ey) { + sel->sx = sx; sel->sy = sy; + sel->ex = ex; sel->ey = ey; + return; + } + + /* starting line > ending line -- upward selection. */ + if (sy > ey) { + if (sx > 0) { + sel->sx = ex; sel->sy = ey; + sel->ex = sx - 1; sel->ey = sy; + } else { + sel->sx = ex; sel->sy = ey; + sel->ex = -1; sel->ey = sy - 1; + } + return; + } + + /* starting line == ending line. */ + if (ex < sx) { sel->sx = ex; sel->sy = ey; - sel->ex = sx; sel->ey = sy; + sel->ex = sx - 1; sel->ey = sy; } else { sel->sx = sx; sel->sy = sy; sel->ex = ex; sel->ey = ey; From ad8509f361fc6b68bfc6220aa79ab36e03460705 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 6 Jan 2010 23:13:52 +0000 Subject: [PATCH 0599/1180] Correctly clear 256-colour flag for aixterm colours. --- input.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/input.c b/input.c index 294cd522..cfa42406 100644 --- a/input.c +++ b/input.c @@ -1481,6 +1481,7 @@ input_handle_sequence_sgr(struct input_ctx *ictx) case 95: case 96: case 97: + gc->flags &= ~GRID_FLAG_FG256; gc->fg = m; break; case 100: @@ -1491,6 +1492,7 @@ input_handle_sequence_sgr(struct input_ctx *ictx) case 105: case 106: case 107: + gc->flags &= ~GRID_FLAG_BG256; gc->bg = m; break; } From 462a11301aaf06dab52b06a9c52ed12d99537c5f Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 7 Jan 2010 19:47:10 +0000 Subject: [PATCH 0600/1180] Change split-window to accept a pane target (it should be split-pane but renaming the command would be annoying). --- cmd-split-window.c | 18 +++++++++--------- tmux.1 | 9 +++++---- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/cmd-split-window.c b/cmd-split-window.c index 6a9c4c9f..2941e2bf 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -45,7 +45,7 @@ struct cmd_split_window_data { const struct cmd_entry cmd_split_window_entry = { "split-window", "splitw", - "[-dhv] [-p percentage|-l size] [-t target-window] [command]", + "[-dhv] [-p percentage|-l size] [-t target-pane] [command]", 0, "", cmd_split_window_init, cmd_split_window_parse, @@ -149,7 +149,7 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) struct session *s; struct winlink *wl; struct window *w; - struct window_pane *wp; + struct window_pane *wp, *new_wp; struct environ env; char *cmd, *cwd, *cause; const char *shell; @@ -157,7 +157,7 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) int size; enum layout_type type; - if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL) + if ((wl = cmd_find_pane(ctx, data->target, &s, &wp)) == NULL) return (-1); w = wl->window; @@ -193,10 +193,10 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) if (*shell == '\0' || areshell(shell)) shell = _PATH_BSHELL; - wp = window_add_pane(w, hlimit); - if (window_pane_spawn(wp, cmd, shell, cwd, &env, s->tio, &cause) != 0) + new_wp = window_add_pane(w, hlimit); + if (window_pane_spawn(new_wp, cmd, shell, cwd, &env, s->tio, &cause) != 0) goto error; - if (layout_split_pane(w->active, type, size, wp) != 0) { + if (layout_split_pane(wp, type, size, new_wp) != 0) { cause = xstrdup("pane too small"); goto error; } @@ -204,7 +204,7 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) server_redraw_window(w); if (!data->flag_detached) { - window_set_active_pane(w, wp); + window_set_active_pane(w, new_wp); session_select(s, wl->idx); server_redraw_session(s); } else @@ -215,8 +215,8 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) error: environ_free(&env); - if (wp != NULL) - window_remove_pane(w, wp); + if (new_wp != NULL) + window_remove_pane(w, new_wp); ctx->error(ctx, "create pane failed: %s", cause); xfree(cause); return (-1); diff --git a/tmux.1 b/tmux.1 index 41b28d46..7f091c60 100644 --- a/tmux.1 +++ b/tmux.1 @@ -984,11 +984,12 @@ Select the window at .Oo Fl l .Ar size | .Fl p Ar percentage Oc -.Op Fl t Ar target-window +.Op Fl t Ar target-pane .Op Ar command .Xc .D1 (alias: splitw ) -Creates a new pane by splitting the active pane: +Create a new pane by splitting +.Ar target-pane : .Fl h does a horizontal split and .Fl v @@ -999,9 +1000,9 @@ The .Fl l and .Fl p -options specify the size of the new window in lines (for vertical split) or in +options specify the size of the new pane in lines (for vertical split) or in cells (for horizontal split), or as a percentage, respectively. -All other options have the same meaning as in the +All other options have the same meaning as for the .Ic new-window command. .It Xo Ic swap-pane From 526bb6f3e949fb2c530cd14b87869e693147463e Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 7 Jan 2010 20:02:01 +0000 Subject: [PATCH 0601/1180] Use the specified pane for size calculations. Doh. --- cmd-split-window.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd-split-window.c b/cmd-split-window.c index 2941e2bf..c159a714 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -183,9 +183,9 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) size = data->size; else if (data->percentage != -1) { if (type == LAYOUT_TOPBOTTOM) - size = (w->active->sy * data->percentage) / 100; + size = (wp->sy * data->percentage) / 100; else - size = (w->active->sx * data->percentage) / 100; + size = (wp->sx * data->percentage) / 100; } hlimit = options_get_number(&s->options, "history-limit"); From ac46e876851c2180566583084d85f2c5327f0ab6 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 7 Jan 2010 20:28:01 +0000 Subject: [PATCH 0602/1180] Don't return the root cell if the string doesn't match. --- layout-string.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/layout-string.c b/layout-string.c index acaf09e4..8955fd29 100644 --- a/layout-string.c +++ b/layout-string.c @@ -42,7 +42,9 @@ struct layout_cell *layout_find_bottomright(struct layout_cell *); struct layout_cell * layout_find_string(struct window *w, const char *s) { - struct layout_cell *lc = w->layout_root; + struct layout_cell *lc; + + lc = NULL; if (strcasecmp(s, "top") == 0) lc = layout_find_top(lc); From 519c6fc7e760dcd608d24dfeb9dc947c6331685b Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 7 Jan 2010 20:30:02 +0000 Subject: [PATCH 0603/1180] Fix this properly. --- layout-string.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/layout-string.c b/layout-string.c index 8955fd29..67f1d32a 100644 --- a/layout-string.c +++ b/layout-string.c @@ -47,21 +47,21 @@ layout_find_string(struct window *w, const char *s) lc = NULL; if (strcasecmp(s, "top") == 0) - lc = layout_find_top(lc); + lc = layout_find_top(w->layout_root); else if (strcasecmp(s, "bottom") == 0) - lc = layout_find_bottom(lc); + lc = layout_find_bottom(w->layout_root); else if (strcasecmp(s, "left") == 0) - lc = layout_find_left(lc); + lc = layout_find_left(w->layout_root); else if (strcasecmp(s, "right") == 0) - lc = layout_find_right(lc); + lc = layout_find_right(w->layout_root); else if (strcasecmp(s, "top-left") == 0) - lc = layout_find_topleft(lc); + lc = layout_find_topleft(w->layout_root); else if (strcasecmp(s, "top-right") == 0) - lc = layout_find_topright(lc); + lc = layout_find_topright(w->layout_root); else if (strcasecmp(s, "bottom-left") == 0) - lc = layout_find_bottomleft(lc); + lc = layout_find_bottomleft(w->layout_root); else if (strcasecmp(s, "bottom-right") == 0) - lc = layout_find_bottomright(lc); + lc = layout_find_bottomright(w->layout_root); if (lc == NULL || lc->type != LAYOUT_WINDOWPANE) return (NULL); From 6a45fab608a7430757db38c3bf3ab67a042b7abb Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 7 Jan 2010 20:52:18 +0000 Subject: [PATCH 0604/1180] New command, join-pane, to split and move an existing pane into the space (like splitw then movep, or the reverse of breakp). --- Makefile | 2 +- cmd-join-pane.c | 257 +++++++++++++++++++++++++++++++++++++++++++++ cmd-split-window.c | 13 ++- cmd.c | 1 + layout.c | 28 +++-- tmux.1 | 18 ++++ tmux.h | 6 +- 7 files changed, 306 insertions(+), 19 deletions(-) create mode 100644 cmd-join-pane.c diff --git a/Makefile b/Makefile index a1dda3d2..a3c3af6a 100644 --- a/Makefile +++ b/Makefile @@ -12,7 +12,7 @@ SRCS= attributes.c cfg.c client.c clock.c \ cmd-last-window.c cmd-link-window.c cmd-list-buffers.c \ cmd-list-clients.c cmd-list-commands.c cmd-list-keys.c \ cmd-list-sessions.c cmd-list-windows.c cmd-list-panes.c \ - cmd-list.c cmd-load-buffer.c \ + cmd-list.c cmd-load-buffer.c cmd-join-pane.c \ cmd-lock-server.c cmd-lock-client.c cmd-lock-session.c \ cmd-move-window.c cmd-new-session.c cmd-new-window.c \ cmd-next-layout.c cmd-next-window.c cmd-paste-buffer.c \ diff --git a/cmd-join-pane.c b/cmd-join-pane.c new file mode 100644 index 00000000..425fe92a --- /dev/null +++ b/cmd-join-pane.c @@ -0,0 +1,257 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2009 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 "tmux.h" + +/* + * Join a pane into another (like split/swap/kill). + */ + +int cmd_join_pane_parse(struct cmd *, int, char **, char **); +int cmd_join_pane_exec(struct cmd *, struct cmd_ctx *); +void cmd_join_pane_free(struct cmd *); +void cmd_join_pane_init(struct cmd *, int); +size_t cmd_join_pane_print(struct cmd *, char *, size_t); + +struct cmd_join_pane_data { + char *src; + char *dst; + int flag_detached; + int flag_horizontal; + int percentage; + int size; +}; + +const struct cmd_entry cmd_join_pane_entry = { + "join-pane", "joinp", + "[-dhv] [-p percentage|-l size] [-t src-pane] [-t dst-pane] [command]", + 0, "", + cmd_join_pane_init, + cmd_join_pane_parse, + cmd_join_pane_exec, + cmd_join_pane_free, + cmd_join_pane_print +}; + +void +cmd_join_pane_init(struct cmd *self, int key) +{ + struct cmd_join_pane_data *data; + + self->data = data = xmalloc(sizeof *data); + data->src = NULL; + data->dst = NULL; + data->flag_detached = 0; + data->flag_horizontal = 0; + data->percentage = -1; + data->size = -1; + + switch (key) { + case '%': + data->flag_horizontal = 1; + break; + case '"': + data->flag_horizontal = 0; + break; + } +} + +int +cmd_join_pane_parse(struct cmd *self, int argc, char **argv, char **cause) +{ + struct cmd_join_pane_data *data; + int opt; + const char *errstr; + + self->entry->init(self, KEYC_NONE); + data = self->data; + + while ((opt = getopt(argc, argv, "dhl:p:s:t:v")) != -1) { + switch (opt) { + case 'd': + data->flag_detached = 1; + break; + case 'h': + data->flag_horizontal = 1; + break; + case 's': + if (data->src == NULL) + data->src = xstrdup(optarg); + break; + case 't': + if (data->dst == NULL) + data->dst = xstrdup(optarg); + break; + case 'l': + if (data->percentage != -1 || data->size != -1) + break; + data->size = strtonum(optarg, 1, INT_MAX, &errstr); + if (errstr != NULL) { + xasprintf(cause, "size %s", errstr); + goto error; + } + break; + case 'p': + if (data->size != -1 || data->percentage != -1) + break; + data->percentage = strtonum(optarg, 1, 100, &errstr); + if (errstr != NULL) { + xasprintf(cause, "percentage %s", errstr); + goto error; + } + break; + case 'v': + data->flag_horizontal = 0; + break; + default: + goto usage; + } + } + argc -= optind; + argv += optind; + if (argc != 0) + goto usage; + + return (0); + +usage: + xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); + +error: + self->entry->free(self); + return (-1); +} + +int +cmd_join_pane_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_join_pane_data *data = self->data; + struct session *dst_s; + struct winlink *src_wl, *dst_wl; + struct window *src_w, *dst_w; + struct window_pane *src_wp, *dst_wp; + int size; + enum layout_type type; + struct layout_cell *lc; + + if ((dst_wl = cmd_find_pane(ctx, data->dst, &dst_s, &dst_wp)) == NULL) + return (-1); + dst_w = dst_wl->window; + + if ((src_wl = cmd_find_pane(ctx, data->src, NULL, &src_wp)) == NULL) + return (-1); + src_w = src_wl->window; + + if (src_w == dst_w) { + ctx->error(ctx, "can't join a pane to its own window"); + return (-1); + } + + type = LAYOUT_TOPBOTTOM; + if (data->flag_horizontal) + type = LAYOUT_LEFTRIGHT; + + size = -1; + if (data->size != -1) + size = data->size; + else if (data->percentage != -1) { + if (type == LAYOUT_TOPBOTTOM) + size = (dst_wp->sy * data->percentage) / 100; + else + size = (dst_wp->sx * data->percentage) / 100; + } + + if ((lc = layout_split_pane(dst_wp, type, size)) == NULL) { + ctx->error(ctx, "create pane failed: pane too small"); + return (-1); + } + + layout_close_pane(src_wp); + + if (src_w->active == src_wp) { + src_w->active = TAILQ_PREV(src_wp, window_panes, entry); + if (src_w->active == NULL) + src_w->active = TAILQ_NEXT(src_wp, entry); + } + TAILQ_REMOVE(&src_w->panes, src_wp, entry); + + if (window_count_panes(src_w) == 0) + server_kill_window(src_w); + + src_wp->window = dst_w; + TAILQ_INSERT_AFTER(&dst_w->panes, dst_wp, src_wp, entry); + layout_assign_pane(lc, src_wp); + + recalculate_sizes(); + + server_redraw_window(src_w); + server_redraw_window(dst_w); + + if (!data->flag_detached) { + window_set_active_pane(dst_w, src_wp); + session_select(dst_s, dst_wl->idx); + server_redraw_session(dst_s); + } else + server_status_session(dst_s); + + return (0); +} + +void +cmd_join_pane_free(struct cmd *self) +{ + struct cmd_join_pane_data *data = self->data; + + if (data->src != NULL) + xfree(data->src); + if (data->dst != NULL) + xfree(data->dst); + xfree(data); +} + +size_t +cmd_join_pane_print(struct cmd *self, char *buf, size_t len) +{ + struct cmd_join_pane_data *data = self->data; + size_t off = 0; + + off += xsnprintf(buf, len, "%s", self->entry->name); + if (data == NULL) + return (off); + if (off < len && data->flag_detached) + off += xsnprintf(buf + off, len - off, " -d"); + if (off < len && data->flag_horizontal) + off += xsnprintf(buf + off, len - off, " -h"); + if (off < len && data->size > 0) + off += xsnprintf(buf + off, len - off, " -l %d", data->size); + if (off < len && data->percentage > 0) { + off += xsnprintf( + buf + off, len - off, " -p %d", data->percentage); + } + if (off < len && data->src != NULL) + off += cmd_prarg(buf + off, len - off, " -s ", data->src); + if (off < len && data->dst != NULL) + off += cmd_prarg(buf + off, len - off, " -t ", data->dst); + return (off); +} diff --git a/cmd-split-window.c b/cmd-split-window.c index c159a714..f4bfe4e2 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -149,13 +149,14 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) struct session *s; struct winlink *wl; struct window *w; - struct window_pane *wp, *new_wp; + struct window_pane *wp, *new_wp = NULL; struct environ env; char *cmd, *cwd, *cause; const char *shell; u_int hlimit; int size; enum layout_type type; + struct layout_cell *lc; if ((wl = cmd_find_pane(ctx, data->target, &s, &wp)) == NULL) return (-1); @@ -193,13 +194,15 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) if (*shell == '\0' || areshell(shell)) shell = _PATH_BSHELL; - new_wp = window_add_pane(w, hlimit); - if (window_pane_spawn(new_wp, cmd, shell, cwd, &env, s->tio, &cause) != 0) - goto error; - if (layout_split_pane(wp, type, size, new_wp) != 0) { + if ((lc = layout_split_pane(wp, type, size)) == NULL) { cause = xstrdup("pane too small"); goto error; } + new_wp = window_add_pane(w, hlimit); + if (window_pane_spawn( + new_wp, cmd, shell, cwd, &env, s->tio, &cause) != 0) + goto error; + layout_assign_pane(lc, new_wp); server_redraw_window(w); diff --git a/cmd.c b/cmd.c index 5ad87c23..72fec848 100644 --- a/cmd.c +++ b/cmd.c @@ -49,6 +49,7 @@ const struct cmd_entry *cmd_table[] = { &cmd_find_window_entry, &cmd_has_session_entry, &cmd_if_shell_entry, + &cmd_join_pane_entry, &cmd_kill_pane_entry, &cmd_kill_server_entry, &cmd_kill_session_entry, diff --git a/layout.c b/layout.c index 7835e3f9..2d7fd596 100644 --- a/layout.c +++ b/layout.c @@ -485,10 +485,20 @@ layout_resize_pane_shrink( return (size); } -/* Split a pane into two. size is a hint, or -1 for default half/half split. */ -int -layout_split_pane(struct window_pane *wp, - enum layout_type type, int size, struct window_pane *new_wp) +/* Assign window pane to newly split cell. */ +void +layout_assign_pane(struct layout_cell *lc, struct window_pane *wp) +{ + layout_make_leaf(lc, wp); + layout_fix_panes(wp->window, wp->window->sx, wp->window->sy); +} + +/* + * Split a pane into two. size is a hint, or -1 for default half/half + * split. This must be followed by layout_assign_pane before much else happens! + **/ +struct layout_cell * +layout_split_pane(struct window_pane *wp, enum layout_type type, int size) { struct layout_cell *lc, *lcparent, *lcnew; u_int sx, sy, xoff, yoff, size1, size2; @@ -505,11 +515,11 @@ layout_split_pane(struct window_pane *wp, switch (type) { case LAYOUT_LEFTRIGHT: if (sx < PANE_MINIMUM * 2 + 1) - return (-1); + return (NULL); break; case LAYOUT_TOPBOTTOM: if (sy < PANE_MINIMUM * 2 + 1) - return (-1); + return (NULL); break; default: fatalx("bad layout type"); @@ -583,12 +593,8 @@ layout_split_pane(struct window_pane *wp, /* Assign the panes. */ layout_make_leaf(lc, wp); - layout_make_leaf(lcnew, new_wp); - /* Fix pane offsets and sizes. */ - layout_fix_panes(wp->window, wp->window->sx, wp->window->sy); - - return (0); + return (lcnew); } /* Destroy the layout associated with a pane and redistribute the space. */ diff --git a/tmux.1 b/tmux.1 index 7f091c60..71391e94 100644 --- a/tmux.1 +++ b/tmux.1 @@ -767,6 +767,24 @@ If only one window is matched, it'll be automatically selected, otherwise a choice list is shown. This command only works from inside .Nm . +.It Xo Ic join-pane +.Op Fl dhv +.Oo Fl l +.Ar size | +.Fl p Ar percentage Oc +.Op Fl s Ar src-pane +.Op Fl t Ar dst-pane +.Xc +.D1 (alias: Ic joinp ) +Like +.Ic split-window , +but instead of splitting +.Ar dst-pane +and creating a new pane, split it and move +.Ar src-pane +into the space. +This can be used to reverse +.Ic break-pane . .It Xo Ic kill-pane .Op Fl a .Op Fl t Ar target-pane diff --git a/tmux.h b/tmux.h index 56ef4aac..e9b08e90 100644 --- a/tmux.h +++ b/tmux.h @@ -1437,6 +1437,7 @@ extern const struct cmd_entry cmd_down_pane_entry; extern const struct cmd_entry cmd_find_window_entry; extern const struct cmd_entry cmd_has_session_entry; extern const struct cmd_entry cmd_if_shell_entry; +extern const struct cmd_entry cmd_join_pane_entry; extern const struct cmd_entry cmd_kill_pane_entry; extern const struct cmd_entry cmd_kill_server_entry; extern const struct cmd_entry cmd_kill_session_entry; @@ -1833,8 +1834,9 @@ void layout_free(struct window *); void layout_resize(struct window *, u_int, u_int); void layout_resize_pane( struct window_pane *, enum layout_type, int); -int layout_split_pane(struct window_pane *, - enum layout_type, int, struct window_pane *); +void layout_assign_pane(struct layout_cell *, struct window_pane *); +struct layout_cell *layout_split_pane( + struct window_pane *, enum layout_type, int); void layout_close_pane(struct window_pane *); /* layout-set.c */ From 6789088dce8b98c0cefcc87bc0b0efbc4e47a075 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 8 Jan 2010 09:14:15 +0000 Subject: [PATCH 0605/1180] mouse-select-pane has to redraw the borders now too. --- server-client.c | 1 + 1 file changed, 1 insertion(+) diff --git a/server-client.c b/server-client.c index c321a4c2..34b99514 100644 --- a/server-client.c +++ b/server-client.c @@ -290,6 +290,7 @@ server_client_handle_key(int key, struct mouse_event *mouse, void *data) if (key == KEYC_MOUSE) { if (options_get_number(oo, "mouse-select-pane")) { window_set_active_at(w, mouse->x, mouse->y); + server_redraw_window_borders(w); wp = w->active; } window_pane_mouse(wp, c, mouse); From 3211bc5f23887f34139335d8f1b2c45eeabbaf47 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 8 Jan 2010 17:44:27 +0000 Subject: [PATCH 0606/1180] $OpenBSD$ not $Id$ --- layout-string.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/layout-string.c b/layout-string.c index 67f1d32a..f3abe8f9 100644 --- a/layout-string.c +++ b/layout-string.c @@ -1,4 +1,4 @@ -/* $Id$ */ +/* $OpenBSD$ */ /* * Copyright (c) 2009 Nicholas Marriott From 8f301ed62d2cdd25e9bf8f731d9aabb7e028be48 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 11 Jan 2010 23:46:22 +0000 Subject: [PATCH 0607/1180] key should be an int not a char. --- window-choose.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/window-choose.c b/window-choose.c index c4af4b43..15226607 100644 --- a/window-choose.c +++ b/window-choose.c @@ -312,8 +312,7 @@ window_choose_write_line( struct options *oo = &wp->window->options; struct screen *s = &data->screen; struct grid_cell gc; - int utf8flag; - char key; + int utf8flag, key; if (data->callbackfn == NULL) fatalx("called before callback assigned"); From d5d0a36f66fd1b537830268b0d94cb7eb16d93ea Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 14 Jan 2010 21:53:40 +0000 Subject: [PATCH 0608/1180] Permit S- prefix on keys for shift. Relatively few terminals support this (basically xterm only) and even fewer have them in terminfo (kLFT2 and kRIT2). --- key-string.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/key-string.c b/key-string.c index 37b4928f..5c01d062 100644 --- a/key-string.c +++ b/key-string.c @@ -170,6 +170,25 @@ key_string_lookup_string(const char *string) return (KEYC_NONE); } + if ((string[0] == 'S' || string[0] == 's') && string[1] == '-') { + ptr = string + 2; + if (ptr[0] == '\0') + return (KEYC_NONE); + key = key_string_lookup_string(ptr); + if (key != KEYC_NONE) { + if (key >= KEYC_BASE) + return (key | KEYC_SHIFT); + } else { + if (ptr[1] == '\0') + return (KEYC_NONE); + key = (u_char) ptr[0]; + } + + if (key >= 32 && key <= 127) + return (key | KEYC_SHIFT); + return (KEYC_NONE); + } + return (key_string_search_table(string)); } From a4ebd9af33dfb3782b919d491c9c6abd0df16b2c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 14 Jan 2010 22:10:47 +0000 Subject: [PATCH 0609/1180] Document swap-pane -d. --- tmux.1 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tmux.1 b/tmux.1 index 71391e94..43751246 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1038,6 +1038,10 @@ is used and no source pane is specified with is swapped with the previous pane (before it numerically); .Fl D swaps with the next pane (after it numerically). +.Fl d +instructs +.Nm +not to change the active pane. .It Xo Ic swap-window .Op Fl d .Op Fl s Ar src-window From f569950664b79b1a3fff2382f9bec218a476c53b Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 18 Jan 2010 19:16:04 +0000 Subject: [PATCH 0610/1180] Missing Pp, from Tiago Cunha. --- tmux.1 | 1 + 1 file changed, 1 insertion(+) diff --git a/tmux.1 b/tmux.1 index 43751246..409b6bb0 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1862,6 +1862,7 @@ command. .Xc Duplicate input to any pane to all other panes in the same window, except for panes that are not in output mode. +.Pp .It Xo Ic utf8 .Op Ic on | off .Xc From 7d75dbbdda237f0d7551d47a903cd04a58b29d42 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 19 Jan 2010 21:27:47 +0000 Subject: [PATCH 0611/1180] Permit !, + and - to be used for window targets to specify last window (!), or next and previous window by number (+ and -). Also tidy an if in cmd-new-window.c. --- cmd-new-window.c | 26 +++++++++----------- cmd.c | 64 ++++++++++++++++++++++++++++++++++++++++++------ tmux.1 | 7 ++++++ 3 files changed, 75 insertions(+), 22 deletions(-) diff --git a/cmd-new-window.c b/cmd-new-window.c index d7b59b8b..ea3cff4a 100644 --- a/cmd-new-window.c +++ b/cmd-new-window.c @@ -129,21 +129,19 @@ cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx) wl = NULL; if (idx != -1) wl = winlink_find_by_index(&s->windows, idx); - if (wl != NULL) { - if (data->flag_kill) { - /* - * Can't use session_detach as it will destroy session - * if this makes it empty. - */ - session_alert_cancel(s, wl); - winlink_stack_remove(&s->lastw, wl); - winlink_remove(&s->windows, wl); + if (wl != NULL && data->flag_kill) { + /* + * Can't use session_detach as it will destroy session if this + * makes it empty. + */ + session_alert_cancel(s, wl); + winlink_stack_remove(&s->lastw, wl); + winlink_remove(&s->windows, wl); - /* Force select/redraw if current. */ - if (wl == s->curw) { - data->flag_detached = 0; - s->curw = NULL; - } + /* Force select/redraw if current. */ + if (wl == s->curw) { + data->flag_detached = 0; + s->curw = NULL; } } diff --git a/cmd.c b/cmd.c index 72fec848..6163d78a 100644 --- a/cmd.c +++ b/cmd.c @@ -702,11 +702,19 @@ cmd_find_window(struct cmd_ctx *ctx, const char *arg, struct session **sp) /* * Then work out the window. An empty string is the current window, - * otherwise try to look it up in the session. + * otherwise try special cases then to look it up in the session. */ if (*winptr == '\0') wl = s->curw; - else if ((wl = cmd_lookup_window(s, winptr, &ambiguous)) == NULL) + else if (winptr[0] == '!' && winptr[1] == '\0') + wl = TAILQ_FIRST(&s->lastw); + else if (winptr[0] == '+' && winptr[1] == '\0') + wl = winlink_next(s->curw); + else if (winptr[0] == '-' && winptr[1] == '\0') + wl = winlink_previous(s->curw); + else + wl = cmd_lookup_window(s, winptr, &ambiguous); + if (wl == NULL) goto not_found; if (sessptr != NULL) @@ -714,8 +722,20 @@ cmd_find_window(struct cmd_ctx *ctx, const char *arg, struct session **sp) return (wl); no_colon: - /* No colon in the string, first try as a window then as a session. */ - if ((wl = cmd_lookup_window(s, arg, &ambiguous)) == NULL) { + /* + * No colon in the string, first try special cases, then as a window + * and lastly as a session. + */ + if (arg[0] == '!' && arg[1] == '\0') { + if ((wl = TAILQ_FIRST(&s->lastw)) == NULL) + goto not_found; + } else if (arg[0] == '+' && arg[1] == '\0') { + if ((wl = winlink_next(s->curw)) == NULL) + goto not_found; + } else if (arg[0] == '-' && arg[1] == '\0') { + if ((wl = winlink_previous(s->curw)) == NULL) + goto not_found; + } else if ((wl = cmd_lookup_window(s, arg, &ambiguous)) == NULL) { if (ambiguous) goto not_found; if ((s = cmd_lookup_session(arg, &ambiguous)) == NULL) @@ -757,6 +777,7 @@ int cmd_find_index(struct cmd_ctx *ctx, const char *arg, struct session **sp) { struct session *s; + struct winlink *wl; const char *winptr; char *sessptr = NULL; int idx, ambiguous = 0; @@ -802,8 +823,20 @@ cmd_find_index(struct cmd_ctx *ctx, const char *arg, struct session **sp) * try to look it up in the session. */ if (*winptr == '\0') - idx = -1; - else if ((idx = cmd_lookup_index(s, winptr, &ambiguous)) == -1) { + idx = -1; + else if (winptr[0] == '!' && winptr[1] == '\0') { + if ((wl = TAILQ_FIRST(&s->lastw)) == NULL) + goto not_found; + idx = wl->idx; + } else if (winptr[0] == '+' && winptr[1] == '\0') { + if (s->curw->idx == INT_MAX) + goto not_found; + idx = s->curw->idx + 1; + } else if (winptr[0] == '-' && winptr[1] == '\0') { + if (s->curw->idx == 0) + goto not_found; + idx = s->curw->idx - 1; + } else if ((idx = cmd_lookup_index(s, winptr, &ambiguous)) == -1) { if (ambiguous) goto not_found; ctx->error(ctx, "invalid index: %s", arg); @@ -815,8 +848,23 @@ cmd_find_index(struct cmd_ctx *ctx, const char *arg, struct session **sp) return (idx); no_colon: - /* No colon in the string, first try as a window then as a session. */ - if ((idx = cmd_lookup_index(s, arg, &ambiguous)) == -1) { + /* + * No colon in the string, first try special cases, then as a window + * and lastly as a session. + */ + if (arg[0] == '!' && arg[1] == '\0') { + if ((wl = TAILQ_FIRST(&s->lastw)) == NULL) + goto not_found; + idx = wl->idx; + } else if (arg[0] == '+' && arg[1] == '\0') { + if (s->curw->idx == INT_MAX) + goto not_found; + idx = s->curw->idx + 1; + } else if (arg[0] == '-' && arg[1] == '\0') { + if (s->curw->idx == 0) + goto not_found; + idx = s->curw->idx - 1; + } else if ((idx = cmd_lookup_index(s, arg, &ambiguous)) == -1) { if (ambiguous) goto not_found; if ((s = cmd_lookup_session(arg, &ambiguous)) == NULL) diff --git a/tmux.1 b/tmux.1 index 409b6bb0..befc0cc8 100644 --- a/tmux.1 +++ b/tmux.1 @@ -307,6 +307,13 @@ commands) otherwise the current window in .Em session is chosen. +The special character +.Ql \&! +uses the last (previously current) window, or +.Ql + +and +.Ql - +are the next window or the previous window by number. When the argument does not contain a colon, .Nm first attempts to parse it as window; if that fails, an attempt is made to From 097a501414b3278b048887fca174b65a2b2f5718 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 20 Jan 2010 18:30:20 +0000 Subject: [PATCH 0612/1180] Don't leak line, from Tiago Cunha. --- cmd-capture-pane.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmd-capture-pane.c b/cmd-capture-pane.c index 4909531d..4d551706 100644 --- a/cmd-capture-pane.c +++ b/cmd-capture-pane.c @@ -65,6 +65,8 @@ cmd_capture_pane_exec(struct cmd *self, struct cmd_ctx *ctx) memcpy(buf + len, line, linelen); len += linelen; buf[len++] = '\n'; + + xfree(line); } limit = options_get_number(&sess->options, "buffer-limit"); From 8865eb2866971d1f82876546154f3032e915348b Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 23 Jan 2010 17:49:21 +0000 Subject: [PATCH 0613/1180] Use C-e and C-y for scrolling in vi mode, from Micah Cowan. --- mode-key.c | 2 ++ tmux.1 | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/mode-key.c b/mode-key.c index f91f9c64..e51b18ed 100644 --- a/mode-key.c +++ b/mode-key.c @@ -172,9 +172,11 @@ const struct mode_key_entry mode_key_vi_copy[] = { { '\002' /* C-b */, 0, MODEKEYCOPY_PREVIOUSPAGE }, { '\003' /* C-c */, 0, MODEKEYCOPY_CANCEL }, { '\004' /* C-d */, 0, MODEKEYCOPY_HALFPAGEDOWN }, + { '\005' /* C-e */, 0, MODEKEYCOPY_SCROLLDOWN }, { '\006' /* C-f */, 0, MODEKEYCOPY_NEXTPAGE }, { '\010' /* C-h */, 0, MODEKEYCOPY_LEFT }, { '\025' /* C-u */, 0, MODEKEYCOPY_HALFPAGEUP }, + { '\031' /* C-y */, 0, MODEKEYCOPY_SCROLLUP }, { '\033' /* Escape */, 0, MODEKEYCOPY_CLEARSELECTION }, { '\r', 0, MODEKEYCOPY_COPYSELECTION }, { '^', 0, MODEKEYCOPY_BACKTOINDENTATION }, diff --git a/tmux.1 b/tmux.1 index befc0cc8..f30c0d14 100644 --- a/tmux.1 +++ b/tmux.1 @@ -535,7 +535,7 @@ The keys available depend on whether emacs or vi mode is selected .Ic mode-keys option). The following keys are supported as appropriate for the mode: -.Bl -column "FunctionXXXXXXXXXXXX" "viXXXXXXXXX" "emacs" -offset indent +.Bl -column "FunctionXXXXXXXXXXXX" "viXXXXXXXXXX" "emacs" -offset indent .It Sy "Function" Ta Sy "vi" Ta Sy "emacs" .It Li "Back to indentation" Ta "^" Ta "M-m" .It Li "Clear selection" Ta "Escape" Ta "C-g" @@ -559,8 +559,8 @@ The following keys are supported as appropriate for the mode: .It Li "Previous page" Ta "C-b" Ta "Page up" .It Li "Previous word" Ta "b" Ta "M-b" .It Li "Quit mode" Ta "q" Ta "Escape" -.It Li "Scroll down" Ta "C-Down or J" Ta "C-Down" -.It Li "Scroll up" Ta "C-Up or K" Ta "C-Up" +.It Li "Scroll down" Ta "C-Down or C-e" Ta "C-Down" +.It Li "Scroll up" Ta "C-Up or C-y" Ta "C-Up" .It Li "Search again" Ta "n" Ta "n" .It Li "Search backward" Ta "?" Ta "C-r" .It Li "Search forward" Ta "/" Ta "C-s" From c0d3e4315c4465d2c665ab2a9151ac31e72f6882 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 23 Jan 2010 17:50:56 +0000 Subject: [PATCH 0614/1180] Don't leak if arguments appear multiple times, from Tiago Cunha. --- cmd-bind-key.c | 3 ++- cmd-switch-client.c | 6 ++++-- cmd-unbind-key.c | 3 ++- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/cmd-bind-key.c b/cmd-bind-key.c index 4ed84ac3..c535612f 100644 --- a/cmd-bind-key.c +++ b/cmd-bind-key.c @@ -79,7 +79,8 @@ cmd_bind_key_parse(struct cmd *self, int argc, char **argv, char **cause) data->can_repeat = 1; break; case 't': - data->tablename = xstrdup(optarg); + if (data->tablename == NULL) + data->tablename = xstrdup(optarg); break; default: goto usage; diff --git a/cmd-switch-client.c b/cmd-switch-client.c index 9ff1c081..03cb7c8d 100644 --- a/cmd-switch-client.c +++ b/cmd-switch-client.c @@ -61,10 +61,12 @@ cmd_switch_client_parse(struct cmd *self, int argc, char **argv, char **cause) while ((opt = getopt(argc, argv, "c:t:")) != -1) { switch (opt) { case 'c': - data->name = xstrdup(optarg); + if (data->name == NULL) + data->name = xstrdup(optarg); break; case 't': - data->target = xstrdup(optarg); + if (data->target == NULL) + data->target = xstrdup(optarg); break; default: goto usage; diff --git a/cmd-unbind-key.c b/cmd-unbind-key.c index 4633274d..c5a97301 100644 --- a/cmd-unbind-key.c +++ b/cmd-unbind-key.c @@ -67,7 +67,8 @@ cmd_unbind_key_parse(struct cmd *self, int argc, char **argv, char **cause) no_prefix = 1; break; case 't': - data->tablename = xstrdup(optarg); + if (data->tablename == NULL) + data->tablename = xstrdup(optarg); break; default: goto usage; From b9ade6e6bb54538dd1164e3a16d261b6580ba4a9 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 23 Jan 2010 21:07:31 +0000 Subject: [PATCH 0615/1180] When a window is destroyed, remove all links to it from each session rather than just the first. Reported by Robin Lee Powell. --- server-fn.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/server-fn.c b/server-fn.c index ce5e518d..3c7277bd 100644 --- a/server-fn.c +++ b/server-fn.c @@ -260,13 +260,13 @@ server_kill_window(struct window *w) s = ARRAY_ITEM(&sessions, i); if (s == NULL || !session_has(s, w)) continue; - if ((wl = winlink_find_by_window(&s->windows, w)) == NULL) - continue; - - if (session_detach(s, wl)) - server_destroy_session_group(s); - else - server_redraw_session_group(s); + while ((wl = winlink_find_by_window(&s->windows, w)) != NULL) { + if (session_detach(s, wl)) { + server_destroy_session_group(s); + break; + } else + server_redraw_session_group(s); + } } } From 75e13c89776b103172ed5813f2198a2b75e3503f Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 24 Jan 2010 21:05:12 +0000 Subject: [PATCH 0616/1180] Redraw properly when scrolling backward and the cursor is on the last line. Based on a fix from Micah Cowan. --- window-copy.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/window-copy.c b/window-copy.c index d6e026ff..3b170a9d 100644 --- a/window-copy.c +++ b/window-copy.c @@ -1075,6 +1075,7 @@ void window_copy_cursor_up(struct window_pane *wp, int scroll_only) { struct window_copy_mode_data *data = wp->modedata; + struct screen *s = &data->screen; u_int ox, oy, px, py; oy = screen_hsize(&wp->base) + data->cy - data->oy; @@ -1087,12 +1088,20 @@ window_copy_cursor_up(struct window_pane *wp, int scroll_only) data->cx = data->lastcx; if (scroll_only || data->cy == 0) { window_copy_scroll_down(wp, 1); - if (scroll_only) - window_copy_redraw_lines(wp, data->cy, 2); + if (scroll_only) { + if (data->cy == screen_size_y(s) - 1) + window_copy_redraw_lines(wp, data->cy, 1); + else + window_copy_redraw_lines(wp, data->cy, 2); + } } else { window_copy_update_cursor(wp, data->cx, data->cy - 1); - if (window_copy_update_selection(wp)) - window_copy_redraw_lines(wp, data->cy, 2); + if (window_copy_update_selection(wp)) { + if (data->cy == screen_size_y(s) - 1) + window_copy_redraw_lines(wp, data->cy, 1); + else + window_copy_redraw_lines(wp, data->cy, 2); + } } py = screen_hsize(&wp->base) + data->cy - data->oy; From 1e5a94fdb5e9fd50ed0d5c5b0a404fa8dc661060 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 25 Jan 2010 21:33:39 +0000 Subject: [PATCH 0617/1180] Top/bottom of history mode keys, diff from Micah Cowan, tweaked by me. --- mode-key.c | 10 ++++++++-- tmux.1 | 4 +++- tmux.h | 2 ++ window-copy.c | 14 ++++++++++++++ 4 files changed, 27 insertions(+), 3 deletions(-) diff --git a/mode-key.c b/mode-key.c index e51b18ed..06e9ef8e 100644 --- a/mode-key.c +++ b/mode-key.c @@ -84,6 +84,8 @@ struct mode_key_cmdstr mode_key_cmdstr_copy[] = { { MODEKEYCOPY_DOWN, "cursor-down" }, { MODEKEYCOPY_ENDOFLINE, "end-of-line" }, { MODEKEYCOPY_GOTOLINE, "goto-line" }, + { MODEKEYCOPY_HISTORYBOTTOM, "history-bottom" }, + { MODEKEYCOPY_HISTORYTOP, "history-top" }, { MODEKEYCOPY_LEFT, "cursor-left" }, { MODEKEYCOPY_MIDDLELINE, "middle-line" }, { MODEKEYCOPY_NEXTPAGE, "page-down" }, @@ -116,13 +118,13 @@ const struct mode_key_entry mode_key_vi_edit[] = { { '$', 1, MODEKEYEDIT_ENDOFLINE }, { '0', 1, MODEKEYEDIT_STARTOFLINE }, - { 'd', 1, MODEKEYEDIT_DELETELINE }, { 'D', 1, MODEKEYEDIT_DELETETOENDOFLINE }, { '\003' /* C-c */, 1, MODEKEYEDIT_CANCEL }, { '\010' /* C-h */, 1, MODEKEYEDIT_BACKSPACE }, { '\r', 1, MODEKEYEDIT_ENTER }, { '^', 1, MODEKEYEDIT_STARTOFLINE }, { 'a', 1, MODEKEYEDIT_SWITCHMODEAPPEND }, + { 'd', 1, MODEKEYEDIT_DELETELINE }, { 'h', 1, MODEKEYEDIT_CURSORLEFT }, { 'i', 1, MODEKEYEDIT_SWITCHMODE }, { 'j', 1, MODEKEYEDIT_HISTORYDOWN }, @@ -164,6 +166,7 @@ const struct mode_key_entry mode_key_vi_copy[] = { { '0', 0, MODEKEYCOPY_STARTOFLINE }, { ':', 0, MODEKEYCOPY_GOTOLINE }, { '?', 0, MODEKEYCOPY_SEARCHUP }, + { 'G', 0, MODEKEYCOPY_HISTORYBOTTOM }, { 'H', 0, MODEKEYCOPY_TOPLINE }, { 'J', 0, MODEKEYCOPY_SCROLLDOWN }, { 'K', 0, MODEKEYCOPY_SCROLLUP }, @@ -181,6 +184,7 @@ const struct mode_key_entry mode_key_vi_copy[] = { { '\r', 0, MODEKEYCOPY_COPYSELECTION }, { '^', 0, MODEKEYCOPY_BACKTOINDENTATION }, { 'b', 0, MODEKEYCOPY_PREVIOUSWORD }, + { 'g', 0, MODEKEYCOPY_HISTORYTOP }, { 'h', 0, MODEKEYCOPY_LEFT }, { 'j', 0, MODEKEYCOPY_DOWN }, { 'k', 0, MODEKEYCOPY_UP }, @@ -254,6 +258,9 @@ struct mode_key_tree mode_key_tree_emacs_choice; /* emacs copy mode keys. */ const struct mode_key_entry mode_key_emacs_copy[] = { { ' ', 0, MODEKEYCOPY_NEXTPAGE }, + { '<' | KEYC_ESCAPE,0, MODEKEYCOPY_HISTORYTOP }, + { '>' | KEYC_ESCAPE, 0, MODEKEYCOPY_HISTORYBOTTOM }, + { 'R' | KEYC_ESCAPE, 0, MODEKEYCOPY_TOPLINE }, { '\000' /* C-Space */, 0, MODEKEYCOPY_STARTSELECTION }, { '\001' /* C-a */, 0, MODEKEYCOPY_STARTOFLINE }, { '\002' /* C-b */, 0, MODEKEYCOPY_LEFT }, @@ -275,7 +282,6 @@ const struct mode_key_entry mode_key_emacs_copy[] = { { 'n', 0, MODEKEYCOPY_SEARCHAGAIN }, { 'q', 0, MODEKEYCOPY_CANCEL }, { 'r' | KEYC_ESCAPE, 0, MODEKEYCOPY_MIDDLELINE }, - { 'R' | KEYC_ESCAPE, 0, MODEKEYCOPY_TOPLINE }, { 'v' | KEYC_ESCAPE, 0, MODEKEYCOPY_PREVIOUSPAGE }, { 'w' | KEYC_ESCAPE, 0, MODEKEYCOPY_COPYSELECTION }, { KEYC_DOWN | KEYC_CTRL,0, MODEKEYCOPY_SCROLLDOWN }, diff --git a/tmux.1 b/tmux.1 index f30c0d14..e78e837f 100644 --- a/tmux.1 +++ b/tmux.1 @@ -538,6 +538,7 @@ The following keys are supported as appropriate for the mode: .Bl -column "FunctionXXXXXXXXXXXX" "viXXXXXXXXXX" "emacs" -offset indent .It Sy "Function" Ta Sy "vi" Ta Sy "emacs" .It Li "Back to indentation" Ta "^" Ta "M-m" +.It Li "Bottom of history" Ta "G" Ta "M-<" .It Li "Clear selection" Ta "Escape" Ta "C-g" .It Li "Copy selection" Ta "Enter" Ta "M-w" .It Li "Cursor down" Ta "j" Ta "Down" @@ -550,7 +551,7 @@ The following keys are supported as appropriate for the mode: .It Li "Delete entire line" Ta "d" Ta "C-u" .It Li "Delete to end of line" Ta "D" Ta "C-k" .It Li "End of line" Ta "$" Ta "C-e" -.It Li "Goto line" Ta ":" Ta "g" +.It Li "Go to line" Ta ":" Ta "g" .It Li "Half page down" Ta "C-d" Ta "M-Down" .It Li "Half page up" Ta "C-u" Ta "M-Up" .It Li "Next page" Ta "C-f" Ta "Page down" @@ -566,6 +567,7 @@ The following keys are supported as appropriate for the mode: .It Li "Search forward" Ta "/" Ta "C-s" .It Li "Start of line" Ta "0" Ta "C-a" .It Li "Start selection" Ta "Space" Ta "C-Space" +.It Li "Top of history" Ta "g" Ta "M->" .It Li "Transpose chars" Ta "" Ta "C-t" .El .Pp diff --git a/tmux.h b/tmux.h index e9b08e90..54ed91a0 100644 --- a/tmux.h +++ b/tmux.h @@ -455,6 +455,8 @@ enum mode_key_cmd { MODEKEYCOPY_GOTOLINE, MODEKEYCOPY_HALFPAGEDOWN, MODEKEYCOPY_HALFPAGEUP, + MODEKEYCOPY_HISTORYBOTTOM, + MODEKEYCOPY_HISTORYTOP, MODEKEYCOPY_LEFT, MODEKEYCOPY_MIDDLELINE, MODEKEYCOPY_NEXTPAGE, diff --git a/window-copy.c b/window-copy.c index 3b170a9d..db464646 100644 --- a/window-copy.c +++ b/window-copy.c @@ -296,6 +296,20 @@ window_copy_key(struct window_pane *wp, struct client *c, int key) window_copy_update_selection(wp); window_copy_redraw_screen(wp); break; + case MODEKEYCOPY_HISTORYTOP: + data->cx = 0; + data->cy = 0; + data->oy = screen_hsize(&wp->base); + window_copy_update_selection(wp); + window_copy_redraw_screen(wp); + break; + case MODEKEYCOPY_HISTORYBOTTOM: + data->cx = 0; + data->cy = screen_size_y(s) - 1; + data->oy = 0; + window_copy_update_selection(wp); + window_copy_redraw_screen(wp); + break; case MODEKEYCOPY_STARTSELECTION: window_copy_start_selection(wp); window_copy_redraw_screen(wp); From e31480cf44312c0e6a8c7de76f384b877aa01f2c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 25 Jan 2010 21:37:40 +0000 Subject: [PATCH 0618/1180] Update the selection properly after goto line or searching. --- window-copy.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/window-copy.c b/window-copy.c index db464646..85217239 100644 --- a/window-copy.c +++ b/window-copy.c @@ -492,6 +492,7 @@ window_copy_scroll_to(struct window_pane *wp, u_int px, u_int py) } data->oy = gd->hsize - offset; + window_copy_update_selection(wp); window_copy_redraw_screen(wp); } @@ -690,6 +691,7 @@ window_copy_goto_line(struct window_pane *wp, const char *linestr) return; data->oy = lineno; + window_copy_update_selection(wp); window_copy_redraw_screen(wp); } From f26312ffbf627af3aa9d4a85dd69148b63d36766 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 25 Jan 2010 22:34:11 +0000 Subject: [PATCH 0619/1180] Hugely simplify window_copy_cursor_next_word, which was way overcomplicated. --- window-copy.c | 62 ++++++++++++++++----------------------------------- 1 file changed, 19 insertions(+), 43 deletions(-) diff --git a/window-copy.c b/window-copy.c index 85217239..1cb808fb 100644 --- a/window-copy.c +++ b/window-copy.c @@ -1161,56 +1161,33 @@ void window_copy_cursor_next_word(struct window_pane *wp) { struct window_copy_mode_data *data = wp->modedata; - struct screen *s = &data->screen; - u_int px, py, xx, skip; + struct screen *base_s = &wp->base; + u_int px, py, xx, yy; px = data->cx; - py = screen_hsize(&wp->base) + data->cy - data->oy; + py = screen_hsize(base_s) + data->cy - data->oy; xx = window_copy_find_length(wp, py); + yy = screen_hsize(base_s) + screen_size_y(base_s) - 1; - skip = 1; - if (px < xx) { - /* If currently on a space, skip space. */ - if (window_copy_is_space(wp, px, py)) - skip = 0; - } else - skip = 0; - for (;;) { - if (px >= xx) { - if (skip) { - px = xx; - break; - } + /* Are we on spaces? Skip 'em! */ + while (px > xx || window_copy_is_space(wp, px, py)) { + /* Nothing but spaces past the end of the line, so move down. */ + if (px > xx) { + if (py == yy) + return; + window_copy_cursor_down(wp, 0); + px = 0; - while (px >= xx) { - if (data->cy == screen_size_y(s) - 1) { - if (data->oy == 0) - goto out; - } - - px = 0; - window_copy_cursor_down(wp, 0); - - py =screen_hsize( - &wp->base) + data->cy - data->oy; - xx = window_copy_find_length(wp, py); - } + py = screen_hsize(base_s) + data->cy - data->oy; + xx = window_copy_find_length(wp, py); } - - if (skip) { - /* Currently skipping non-space (until space). */ - if (window_copy_is_space(wp, px, py)) - break; - } else { - /* Currently skipping space (until non-space). */ - if (!window_copy_is_space(wp, px, py)) - skip = 1; - } - px++; } -out: + /* Find the end of this word. */ + while (!window_copy_is_space(wp, px, py)) + px++; + window_copy_update_cursor(wp, px, data->cy); if (window_copy_update_selection(wp)) window_copy_redraw_lines(wp, data->cy, 1); @@ -1239,8 +1216,7 @@ window_copy_cursor_previous_word(struct window_pane *wp) goto out; window_copy_cursor_up(wp, 0); - py = screen_hsize( - &wp->base) + data->cy - data->oy; + py = screen_hsize(&wp->base) + data->cy - data->oy; px = window_copy_find_length(wp, py); } } From ba6dedbbbdf38e962b819a5ce085354a831c9204 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 26 Jan 2010 21:36:53 +0000 Subject: [PATCH 0620/1180] Actually use the copy made when no newline is found, from martynas@. --- status.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/status.c b/status.c index 535044ad..ee8f2390 100644 --- a/status.c +++ b/status.c @@ -550,10 +550,11 @@ status_job_callback(struct job *job) xfree(job->data); else server_redraw_client(job->client); - job->data = xstrdup(line); - if (buf != NULL) - xfree(buf); + if (line == NULL) + job->data = buf; + else + job->data = xstrdup(line); } /* Calculate winlink status line entry width. */ From 3e2cc2d2c4c443cc99086927c83547d50cb07369 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 27 Jan 2010 20:18:52 +0000 Subject: [PATCH 0621/1180] Alter next-word to have vi-like movement behaviour, and add next-word-end with the existing emacs behaviour. From Micah Cowan. --- mode-key.c | 3 ++- tmux.1 | 3 ++- tmux.h | 1 + window-copy.c | 40 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 45 insertions(+), 2 deletions(-) diff --git a/mode-key.c b/mode-key.c index 06e9ef8e..fcbdea4e 100644 --- a/mode-key.c +++ b/mode-key.c @@ -90,6 +90,7 @@ struct mode_key_cmdstr mode_key_cmdstr_copy[] = { { MODEKEYCOPY_MIDDLELINE, "middle-line" }, { MODEKEYCOPY_NEXTPAGE, "page-down" }, { MODEKEYCOPY_NEXTWORD, "next-word" }, + { MODEKEYCOPY_NEXTWORDEND, "next-word-end" }, { MODEKEYCOPY_PREVIOUSPAGE, "page-up" }, { MODEKEYCOPY_PREVIOUSWORD, "previous-word" }, { MODEKEYCOPY_RIGHT, "cursor-right" }, @@ -276,7 +277,7 @@ const struct mode_key_entry mode_key_emacs_copy[] = { { '\027' /* C-w */, 0, MODEKEYCOPY_COPYSELECTION }, { '\033' /* Escape */, 0, MODEKEYCOPY_CANCEL }, { 'b' | KEYC_ESCAPE, 0, MODEKEYCOPY_PREVIOUSWORD }, - { 'f' | KEYC_ESCAPE, 0, MODEKEYCOPY_NEXTWORD }, + { 'f' | KEYC_ESCAPE, 0, MODEKEYCOPY_NEXTWORDEND }, { 'g', 0, MODEKEYCOPY_GOTOLINE }, { 'm' | KEYC_ESCAPE, 0, MODEKEYCOPY_BACKTOINDENTATION }, { 'n', 0, MODEKEYCOPY_SEARCHAGAIN }, diff --git a/tmux.1 b/tmux.1 index e78e837f..84344fbb 100644 --- a/tmux.1 +++ b/tmux.1 @@ -555,7 +555,8 @@ The following keys are supported as appropriate for the mode: .It Li "Half page down" Ta "C-d" Ta "M-Down" .It Li "Half page up" Ta "C-u" Ta "M-Up" .It Li "Next page" Ta "C-f" Ta "Page down" -.It Li "Next word" Ta "w" Ta "M-f" +.It Li "Next word" Ta "w" Ta "" +.It Li "Next word end" Ta "e" Ta "M-f" .It Li "Paste buffer" Ta "p" Ta "C-y" .It Li "Previous page" Ta "C-b" Ta "Page up" .It Li "Previous word" Ta "b" Ta "M-b" diff --git a/tmux.h b/tmux.h index 54ed91a0..84784757 100644 --- a/tmux.h +++ b/tmux.h @@ -461,6 +461,7 @@ enum mode_key_cmd { MODEKEYCOPY_MIDDLELINE, MODEKEYCOPY_NEXTPAGE, MODEKEYCOPY_NEXTWORD, + MODEKEYCOPY_NEXTWORDEND, MODEKEYCOPY_PREVIOUSPAGE, MODEKEYCOPY_PREVIOUSWORD, MODEKEYCOPY_RIGHT, diff --git a/window-copy.c b/window-copy.c index 1cb808fb..fd50339e 100644 --- a/window-copy.c +++ b/window-copy.c @@ -64,6 +64,7 @@ void window_copy_cursor_right(struct window_pane *); void window_copy_cursor_up(struct window_pane *, int); void window_copy_cursor_down(struct window_pane *, int); void window_copy_cursor_next_word(struct window_pane *); +void window_copy_cursor_next_word_end(struct window_pane *); void window_copy_cursor_previous_word(struct window_pane *); void window_copy_scroll_up(struct window_pane *, u_int); void window_copy_scroll_down(struct window_pane *, u_int); @@ -336,6 +337,9 @@ window_copy_key(struct window_pane *wp, struct client *c, int key) case MODEKEYCOPY_NEXTWORD: window_copy_cursor_next_word(wp); break; + case MODEKEYCOPY_NEXTWORDEND: + window_copy_cursor_next_word_end(wp); + break; case MODEKEYCOPY_PREVIOUSWORD: window_copy_cursor_previous_word(wp); break; @@ -1169,6 +1173,42 @@ window_copy_cursor_next_word(struct window_pane *wp) xx = window_copy_find_length(wp, py); yy = screen_hsize(base_s) + screen_size_y(base_s) - 1; + /* Are we in a word? Skip it! */ + while (!window_copy_is_space(wp, px, py)) + px++; + + /* Find the start of a word. */ + while (px > xx || window_copy_is_space(wp, px, py)) { + /* Past the end of the line? Nothing but spaces. */ + if (px > xx) { + if (py == yy) + return; + window_copy_cursor_down(wp, 0); + px = 0; + + py = screen_hsize(base_s) + data->cy - data->oy; + xx = window_copy_find_length(wp, py); + } + px++; + } + + window_copy_update_cursor(wp, px, data->cy); + if (window_copy_update_selection(wp)) + window_copy_redraw_lines(wp, data->cy, 1); +} + +void +window_copy_cursor_next_word_end(struct window_pane *wp) +{ + struct window_copy_mode_data *data = wp->modedata; + struct screen *base_s = &wp->base; + u_int px, py, xx, yy; + + px = data->cx; + py = screen_hsize(base_s) + data->cy - data->oy; + xx = window_copy_find_length(wp, py); + yy = screen_hsize(base_s) + screen_size_y(base_s) - 1; + /* Are we on spaces? Skip 'em! */ while (px > xx || window_copy_is_space(wp, px, py)) { /* Nothing but spaces past the end of the line, so move down. */ From 05213e4c8cb083669382e0287481df994827352f Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 27 Jan 2010 20:26:42 +0000 Subject: [PATCH 0622/1180] Calculate offset correctly, fixes incorrect offset and prevents crash when status-left is empty. From Micah Cowan. --- status.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/status.c b/status.c index ee8f2390..5576cff9 100644 --- a/status.c +++ b/status.c @@ -302,18 +302,20 @@ draw: } /* Figure out the offset for the window list. */ - wloffset = 1; + if (llen != 0) + wloffset = llen + 1; + else + wloffset = 0; if (wlwidth < wlavailable) { switch (options_get_number(&s->options, "status-justify")) { case 1: /* centered */ - wloffset = 1 + (wlavailable - wlwidth) / 2; + wloffset += (wlavailable - wlwidth) / 2; break; case 2: /* right */ - wloffset = 1 + (wlavailable - wlwidth); + wloffset += (wlavailable - wlwidth); break; } } - wloffset += llen; if (larrow != 0) wloffset++; From f941879c15fa59646a3cc687fe9244641afa2460 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 27 Jan 2010 23:26:14 +0000 Subject: [PATCH 0623/1180] Actually bind the new key to e. --- mode-key.c | 1 + 1 file changed, 1 insertion(+) diff --git a/mode-key.c b/mode-key.c index fcbdea4e..8436ac2e 100644 --- a/mode-key.c +++ b/mode-key.c @@ -185,6 +185,7 @@ const struct mode_key_entry mode_key_vi_copy[] = { { '\r', 0, MODEKEYCOPY_COPYSELECTION }, { '^', 0, MODEKEYCOPY_BACKTOINDENTATION }, { 'b', 0, MODEKEYCOPY_PREVIOUSWORD }, + { 'e', 0, MODEKEYCOPY_NEXTWORDEND }, { 'g', 0, MODEKEYCOPY_HISTORYTOP }, { 'h', 0, MODEKEYCOPY_LEFT }, { 'j', 0, MODEKEYCOPY_DOWN }, From 6abd9846080ea43a5c7a006bfc8d94696389b26f Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 28 Jan 2010 19:09:12 +0000 Subject: [PATCH 0624/1180] Typo, from Micah Cowan. --- tmux.1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tmux.1 b/tmux.1 index 84344fbb..286d9613 100644 --- a/tmux.1 +++ b/tmux.1 @@ -581,7 +581,7 @@ for keys used when line editing at the command prompt; and .Em emacs-choice for keys used when choosing from lists (such as produced by the -.Ic window-choose +.Ic choose-window command) or in output mode; and .Em vi-copy and From 65c9004550e03cad0250ae999594806962275002 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 30 Jan 2010 19:05:18 +0000 Subject: [PATCH 0625/1180] Ignore SIGHUP as well. --- server.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/server.c b/server.c index 4eb78d60..ef8fa755 100644 --- a/server.c +++ b/server.c @@ -356,6 +356,8 @@ server_signal_set(void) fatal("sigaction failed"); if (sigaction(SIGTSTP, &sigact, NULL) != 0) fatal("sigaction failed"); + if (sigaction(SIGHUP, &sigact, NULL) != 0) + fatal("sigaction failed"); signal_set(&server_ev_sigchld, SIGCHLD, server_signal_callback, NULL); signal_add(&server_ev_sigchld, NULL); @@ -383,6 +385,8 @@ server_signal_clear(void) fatal("sigaction failed"); if (sigaction(SIGTSTP, &sigact, NULL) != 0) fatal("sigaction failed"); + if (sigaction(SIGHUP, &sigact, NULL) != 0) + fatal("sigaction failed"); signal_del(&server_ev_sigchld); signal_del(&server_ev_sigterm); From 8a37a1cc2d67c3ef9c3c42ddaa3b5dd1d57788ff Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 30 Jan 2010 19:08:47 +0000 Subject: [PATCH 0626/1180] Don't stop parsing command sequences when a command requests the client to stick around (attach-session/new-session). --- cmd-list.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/cmd-list.c b/cmd-list.c index 16fe5921..9adf7f76 100644 --- a/cmd-list.c +++ b/cmd-list.c @@ -77,13 +77,32 @@ int cmd_list_exec(struct cmd_list *cmdlist, struct cmd_ctx *ctx) { struct cmd *cmd; - int n; + int n, retval; + retval = 0; TAILQ_FOREACH(cmd, cmdlist, qentry) { - if ((n = cmd_exec(cmd, ctx)) != 0) - return (n); + if ((n = cmd_exec(cmd, ctx)) == -1) + return (-1); + + /* + * A 1 return value means the command client is being attached + * (sent MSG_READY). + */ + if (n == 1) { + retval = 1; + + /* + * The command client has been attached, so mangle the + * context to treat any following commands as if they + * were called from inside. + */ + if (ctx->curclient == NULL) { + ctx->curclient = ctx->cmdclient; + ctx->cmdclient = NULL; + } + } } - return (0); + return (retval); } void From 383c682563b839f57555be656b3ca2612da79f99 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 31 Jan 2010 11:11:28 +0000 Subject: [PATCH 0627/1180] Fix DPADD, from Brad. --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index a3c3af6a..574f4b48 100644 --- a/Makefile +++ b/Makefile @@ -46,6 +46,6 @@ CDIAGFLAGS+= -Wwrite-strings -Wshadow -Wpointer-arith -Wsign-compare CDIAGFLAGS+= -Wundef -Wbad-function-cast -Winline -Wcast-align LDADD= -lutil -lcurses -levent -DPADD= ${LIBUTIL} +DPADD= ${LIBUTIL} ${LIBCURSES} ${LIBEVENT} .include From c29bfd2ff30016faa970e903fcbb488a86335d88 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 31 Jan 2010 18:47:03 +0000 Subject: [PATCH 0628/1180] Remove unnecessary comparison, pointed out by Tiago Cunha. --- cmd-string.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cmd-string.c b/cmd-string.c index 27b051b1..a5dabb56 100644 --- a/cmd-string.c +++ b/cmd-string.c @@ -344,8 +344,7 @@ cmd_string_expand_tilde(const char *s, size_t *p) return (NULL); if ((pw = getpwnam(username)) != NULL) home = pw->pw_dir; - if (username != NULL) - xfree(username); + xfree(username); } if (home == NULL) return (NULL); From 06ce9da32ad2331791d63a18846d6e0f51a73d5c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 1 Feb 2010 22:15:51 +0000 Subject: [PATCH 0629/1180] Add scroll-up/scroll-down for choose/more mode, from Micah Cowan. --- mode-key.c | 10 ++++++++++ tmux.h | 2 ++ window-choose.c | 33 +++++++++++++++++++++++++++++---- window-more.c | 2 ++ 4 files changed, 43 insertions(+), 4 deletions(-) diff --git a/mode-key.c b/mode-key.c index 8436ac2e..a8d9aef7 100644 --- a/mode-key.c +++ b/mode-key.c @@ -69,6 +69,8 @@ struct mode_key_cmdstr mode_key_cmdstr_choice[] = { { MODEKEYCHOICE_DOWN, "down" }, { MODEKEYCHOICE_PAGEDOWN, "page-down" }, { MODEKEYCHOICE_PAGEUP, "page-up" }, + { MODEKEYCHOICE_SCROLLDOWN, "scroll-down" }, + { MODEKEYCHOICE_SCROLLUP, "scroll-up" }, { MODEKEYCHOICE_UP, "up" }, { 0, NULL } @@ -145,14 +147,20 @@ struct mode_key_tree mode_key_tree_vi_edit; /* vi choice selection keys. */ const struct mode_key_entry mode_key_vi_choice[] = { + { '\002' /* C-b */, 0, MODEKEYCHOICE_PAGEUP }, { '\003' /* C-c */, 0, MODEKEYCHOICE_CANCEL }, + { '\005' /* C-e */, 0, MODEKEYCHOICE_SCROLLDOWN }, + { '\006' /* C-f */, 0, MODEKEYCHOICE_PAGEDOWN }, + { '\031' /* C-y */, 0, MODEKEYCHOICE_SCROLLUP }, { '\r', 0, MODEKEYCHOICE_CHOOSE }, { 'j', 0, MODEKEYCHOICE_DOWN }, { 'k', 0, MODEKEYCHOICE_UP }, { 'q', 0, MODEKEYCHOICE_CANCEL }, + { KEYC_DOWN | KEYC_CTRL,0, MODEKEYCHOICE_SCROLLDOWN }, { KEYC_DOWN, 0, MODEKEYCHOICE_DOWN }, { KEYC_NPAGE, 0, MODEKEYCHOICE_PAGEDOWN }, { KEYC_PPAGE, 0, MODEKEYCHOICE_PAGEUP }, + { KEYC_UP | KEYC_CTRL, 0, MODEKEYCHOICE_SCROLLUP }, { KEYC_UP, 0, MODEKEYCHOICE_UP }, { 0, -1, 0 } @@ -248,9 +256,11 @@ const struct mode_key_entry mode_key_emacs_choice[] = { { '\r', 0, MODEKEYCHOICE_CHOOSE }, { 'q', 0, MODEKEYCHOICE_CANCEL }, { 'v' | KEYC_ESCAPE, 0, MODEKEYCHOICE_PAGEUP }, + { KEYC_DOWN | KEYC_CTRL,0, MODEKEYCHOICE_SCROLLDOWN }, { KEYC_DOWN, 0, MODEKEYCHOICE_DOWN }, { KEYC_NPAGE, 0, MODEKEYCHOICE_PAGEDOWN }, { KEYC_PPAGE, 0, MODEKEYCHOICE_PAGEUP }, + { KEYC_UP | KEYC_CTRL, 0, MODEKEYCHOICE_SCROLLUP }, { KEYC_UP, 0, MODEKEYCHOICE_UP }, { 0, -1, 0 } diff --git a/tmux.h b/tmux.h index 84784757..7bceb667 100644 --- a/tmux.h +++ b/tmux.h @@ -442,6 +442,8 @@ enum mode_key_cmd { MODEKEYCHOICE_DOWN, MODEKEYCHOICE_PAGEDOWN, MODEKEYCHOICE_PAGEUP, + MODEKEYCHOICE_SCROLLDOWN, + MODEKEYCHOICE_SCROLLUP, MODEKEYCHOICE_UP, /* Copy keys. */ diff --git a/window-choose.c b/window-choose.c index 15226607..87f08f33 100644 --- a/window-choose.c +++ b/window-choose.c @@ -225,16 +225,41 @@ window_choose_key(struct window_pane *wp, unused struct client *c, int key) } data->selected++; - if (data->selected >= data->top + screen_size_y(&data->screen)) - window_choose_scroll_down(wp); - else { + if (data->selected < data->top + screen_size_y(s)) { screen_write_start(&ctx, wp, NULL); window_choose_write_line( wp, &ctx, data->selected - data->top); window_choose_write_line( wp, &ctx, data->selected - 1 - data->top); screen_write_stop(&ctx); - } + } else + window_choose_scroll_down(wp); + break; + case MODEKEYCHOICE_SCROLLUP: + if (items == 0 || data->top == 0) + break; + if (data->selected == data->top + screen_size_y(s) - 1) { + data->selected--; + window_choose_scroll_up(wp); + screen_write_start(&ctx, wp, NULL); + window_choose_write_line( + wp, &ctx, screen_size_y(s) - 1); + screen_write_stop(&ctx); + } else + window_choose_scroll_up(wp); + break; + case MODEKEYCHOICE_SCROLLDOWN: + if (items == 0 || + data->top + screen_size_y(&data->screen) >= items) + break; + if (data->selected == data->top) { + data->selected++; + window_choose_scroll_down(wp); + screen_write_start(&ctx, wp, NULL); + window_choose_write_line(wp, &ctx, 0); + screen_write_stop(&ctx); + } else + window_choose_scroll_down(wp); break; case MODEKEYCHOICE_PAGEUP: if (data->selected < screen_size_y(s)) { diff --git a/window-more.c b/window-more.c index 49d19a7c..28423e1a 100644 --- a/window-more.c +++ b/window-more.c @@ -135,9 +135,11 @@ window_more_key(struct window_pane *wp, unused struct client *c, int key) window_pane_reset_mode(wp); break; case MODEKEYCHOICE_UP: + case MODEKEYCHOICE_SCROLLUP: window_more_scroll_up(wp); break; case MODEKEYCHOICE_DOWN: + case MODEKEYCHOICE_SCROLLDOWN: window_more_scroll_down(wp); break; case MODEKEYCHOICE_PAGEUP: From 9ffe549ab199b6af8cd5e7b8ac3611fdba1d6b62 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 1 Feb 2010 23:06:24 +0000 Subject: [PATCH 0630/1180] If redrawing line 0 of the screen onto the tty, there can't be a wrap flag on the previous line, so move the cursor. Fixes status line redraw issues when resizing in choose mode and hopefully at other times as well. --- tty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tty.c b/tty.c index a84d8def..02ceb54e 100644 --- a/tty.c +++ b/tty.c @@ -484,7 +484,7 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int py, u_int ox, u_int oy) gl = NULL; if (py != 0) gl = &s->grid->linedata[s->grid->hsize + py - 1]; - if (oy + py == 0 || (gl != NULL && !(gl->flags & GRID_LINE_WRAPPED)) || + if (oy + py == 0 || gl == NULL || !(gl->flags & GRID_LINE_WRAPPED) || tty->cx < tty->sx || ox != 0 || (oy + py != tty->cy + 1 && tty->cy != s->rlower + oy)) tty_cursor(tty, ox, oy + py); From d6bd9c0e7f6f891774fd9d083bdff2c0e56231dd Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 3 Feb 2010 22:24:34 +0000 Subject: [PATCH 0631/1180] Fix divide by zero on small windows with main-* layouts. --- layout-set.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/layout-set.c b/layout-set.c index 2436a0f5..e74a1931 100644 --- a/layout-set.c +++ b/layout-set.c @@ -244,6 +244,8 @@ layout_set_main_h(struct window *w) /* How many rows and columns will be needed? */ columns = w->sx / (PANE_MINIMUM + 1); /* maximum columns */ + if (columns == 0) + columns = 1; rows = 1 + (n - 1) / columns; columns = 1 + (n - 1) / rows; width = w->sx / columns; @@ -353,6 +355,8 @@ layout_set_main_v(struct window *w) /* How many rows and columns will be needed? */ rows = w->sy / (PANE_MINIMUM + 1); /* maximum rows */ + if (rows == 0) + rows = 1; columns = 1 + (n - 1) / rows; rows = 1 + (n - 1) / columns; height = w->sy / rows; From 604b02cfaa59cf65623b828baf310b5998674cd0 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 4 Feb 2010 18:20:16 +0000 Subject: [PATCH 0632/1180] Option to display the active pane in a different colour with the display-panes command. From Paul Hoffman, thanks. --- cmd-set-option.c | 1 + screen-redraw.c | 19 ++++++++++++++----- tmux.1 | 15 ++++++++++----- tmux.c | 1 + 4 files changed, 26 insertions(+), 10 deletions(-) diff --git a/cmd-set-option.c b/cmd-set-option.c index 06535e0d..63e646e0 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -88,6 +88,7 @@ const struct set_option_entry set_session_option_table[] = { { "default-shell", SET_OPTION_STRING, 0, 0, NULL }, { "default-terminal", SET_OPTION_STRING, 0, 0, NULL }, { "display-panes-colour", SET_OPTION_COLOUR, 0, 0, NULL }, + { "display-panes-active-colour", SET_OPTION_COLOUR, 0, 0, NULL }, { "display-panes-time", SET_OPTION_NUMBER, 1, INT_MAX, NULL }, { "display-time", SET_OPTION_NUMBER, 1, INT_MAX, NULL }, { "history-limit", SET_OPTION_NUMBER, 0, INT_MAX, NULL }, diff --git a/screen-redraw.c b/screen-redraw.c index 83eafa62..bd3010cb 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -269,18 +269,21 @@ screen_redraw_draw_number(struct client *c, struct window_pane *wp) { struct tty *tty = &c->tty; struct session *s = c->session; + struct options *oo = &s->options; + struct window *w = wp->window; struct grid_cell gc; u_int idx, px, py, i, j, xoff, yoff; - int colour; + int colour, active_colour; char buf[16], *ptr; size_t len; - idx = window_pane_index(wp->window, wp); + idx = window_pane_index(w, wp); len = xsnprintf(buf, sizeof buf, "%u", idx); if (wp->sx < len) return; - colour = options_get_number(&s->options, "display-panes-colour"); + colour = options_get_number(oo, "display-panes-colour"); + active_colour = options_get_number(oo, "display-panes-active-colour"); px = wp->sx / 2; py = wp->sy / 2; xoff = wp->xoff; yoff = wp->yoff; @@ -289,7 +292,10 @@ screen_redraw_draw_number(struct client *c, struct window_pane *wp) tty_cursor(tty, xoff + px - len / 2, yoff + py); memcpy(&gc, &grid_default_cell, sizeof gc); gc.data = '_'; /* not space */ - colour_set_fg(&gc, colour); + if (w->active == wp) + colour_set_fg(&gc, active_colour); + else + colour_set_fg(&gc, colour); tty_attributes(tty, &gc); tty_puts(tty, buf); return; @@ -300,7 +306,10 @@ screen_redraw_draw_number(struct client *c, struct window_pane *wp) memcpy(&gc, &grid_default_cell, sizeof gc); gc.data = '_'; /* not space */ - colour_set_bg(&gc, colour); + if (w->active == wp) + colour_set_bg(&gc, active_colour); + else + colour_set_bg(&gc, colour); tty_attributes(tty, &gc); for (ptr = buf; *ptr != '\0'; ptr++) { if (*ptr < '0' || *ptr > '9') diff --git a/tmux.1 b/tmux.1 index 286d9613..b80e8580 100644 --- a/tmux.1 +++ b/tmux.1 @@ -751,9 +751,10 @@ This command works only from inside Display a visible indicator of each pane shown by .Ar target-client . See the -.Ic display-panes-time +.Ic display-panes-time , +.Ic display-panes-colour , and -.Ic display-panes-colour +.Ic display-panes-active-colour session options. While the indicator is on screen, a pane may be selected with the .Ql 0 @@ -1398,10 +1399,14 @@ to work correctly, this be set to .Ql screen or a derivative of it. -.It Ic display-panes-colour Ar colour -Set the colour used for the +.It Ic display-panes-active-colour Ar colour +Set the colour used by the .Ic display-panes -command. +command to show the indicator for the active pane. +.It Ic display-panes-colour Ar colour +Set the colour used by the +.Ic display-panes +command to show the indicators for inactive panes. .It Ic display-panes-time Ar time Set the time in milliseconds for which the indicators shown by the .Ic display-panes diff --git a/tmux.c b/tmux.c index 24aa24f6..d003ff21 100644 --- a/tmux.c +++ b/tmux.c @@ -328,6 +328,7 @@ main(int argc, char **argv) options_set_string(so, "default-shell", "%s", getshell()); options_set_string(so, "default-terminal", "screen"); options_set_number(so, "display-panes-colour", 4); + options_set_number(so, "display-panes-active-colour", 1); options_set_number(so, "display-panes-time", 1000); options_set_number(so, "display-time", 750); options_set_number(so, "history-limit", 2000); From e7c6f81016f304241d11e9c4313f2d7257d6ef24 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 4 Feb 2010 18:27:06 +0000 Subject: [PATCH 0633/1180] Read the path from $TMUX if it is present and -L and -S are not given. Based on a diff from Micah Cowan. --- tmux.c | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/tmux.c b/tmux.c index d003ff21..758ad842 100644 --- a/tmux.c +++ b/tmux.c @@ -443,13 +443,30 @@ main(int argc, char **argv) } } - if (label == NULL) - label = xstrdup("default"); - if (path == NULL && (path = makesockpath(label)) == NULL) { - log_warn("can't create socket"); - exit(1); + /* + * Figure out the socket path. If specified on the command-line with + * -S or -L, use it, otherwise try $TMUX or assume -L default. + */ + if (path == NULL) { + /* No -L. Try $TMUX, or default. */ + if (label == NULL) { + if ((path = getenv("TMUX")) != NULL) { + path = xstrdup(path); + path[strcspn(path, ",")] = '\0'; + } else + label = xstrdup("default"); + } + + /* -L or default set. */ + if (label != NULL) { + if ((path = makesockpath(label)) == NULL) { + log_warn("can't create socket"); + exit(1); + } + } } - xfree(label); + if (label != NULL) + xfree(label); if (shellcmd != NULL) { msg = MSG_SHELL; From 5e6a7c85ccdbabda01e7c05a10f7bd8dcee47e70 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 4 Feb 2010 20:00:26 +0000 Subject: [PATCH 0634/1180] vi-style B, W and E keys in copy mode to navigate between words treating only spaces as word separators. Also add . to the list of word separators for standard word navigation. From Micah Cowan, tweaked slightly by me. --- mode-key.c | 6 ++++++ tmux.1 | 17 ++++++++++++++++- tmux.h | 3 +++ window-copy.c | 51 ++++++++++++++++++++++++++++----------------------- 4 files changed, 53 insertions(+), 24 deletions(-) diff --git a/mode-key.c b/mode-key.c index a8d9aef7..175a2a04 100644 --- a/mode-key.c +++ b/mode-key.c @@ -91,9 +91,12 @@ struct mode_key_cmdstr mode_key_cmdstr_copy[] = { { MODEKEYCOPY_LEFT, "cursor-left" }, { MODEKEYCOPY_MIDDLELINE, "middle-line" }, { MODEKEYCOPY_NEXTPAGE, "page-down" }, + { MODEKEYCOPY_NEXTSPACE, "next-space" }, + { MODEKEYCOPY_NEXTSPACEEND, "next-space-end" }, { MODEKEYCOPY_NEXTWORD, "next-word" }, { MODEKEYCOPY_NEXTWORDEND, "next-word-end" }, { MODEKEYCOPY_PREVIOUSPAGE, "page-up" }, + { MODEKEYCOPY_PREVIOUSSPACE, "previous-space" }, { MODEKEYCOPY_PREVIOUSWORD, "previous-word" }, { MODEKEYCOPY_RIGHT, "cursor-right" }, { MODEKEYCOPY_SCROLLDOWN, "scroll-down" }, @@ -175,12 +178,15 @@ const struct mode_key_entry mode_key_vi_copy[] = { { '0', 0, MODEKEYCOPY_STARTOFLINE }, { ':', 0, MODEKEYCOPY_GOTOLINE }, { '?', 0, MODEKEYCOPY_SEARCHUP }, + { 'B', 0, MODEKEYCOPY_PREVIOUSSPACE }, + { 'E', 0, MODEKEYCOPY_NEXTSPACEEND }, { 'G', 0, MODEKEYCOPY_HISTORYBOTTOM }, { 'H', 0, MODEKEYCOPY_TOPLINE }, { 'J', 0, MODEKEYCOPY_SCROLLDOWN }, { 'K', 0, MODEKEYCOPY_SCROLLUP }, { 'L', 0, MODEKEYCOPY_BOTTOMLINE }, { 'M', 0, MODEKEYCOPY_MIDDLELINE }, + { 'W', 0, MODEKEYCOPY_NEXTSPACE }, { '\002' /* C-b */, 0, MODEKEYCOPY_PREVIOUSPAGE }, { '\003' /* C-c */, 0, MODEKEYCOPY_CANCEL }, { '\004' /* C-d */, 0, MODEKEYCOPY_HALFPAGEDOWN }, diff --git a/tmux.1 b/tmux.1 index b80e8580..a759c82b 100644 --- a/tmux.1 +++ b/tmux.1 @@ -535,7 +535,7 @@ The keys available depend on whether emacs or vi mode is selected .Ic mode-keys option). The following keys are supported as appropriate for the mode: -.Bl -column "FunctionXXXXXXXXXXXX" "viXXXXXXXXXX" "emacs" -offset indent +.Bl -column "FunctionXXXXXXXXXXXXXX" "viXXXXXXXXXX" "emacs" -offset indent .It Sy "Function" Ta Sy "vi" Ta Sy "emacs" .It Li "Back to indentation" Ta "^" Ta "M-m" .It Li "Bottom of history" Ta "G" Ta "M-<" @@ -555,11 +555,14 @@ The following keys are supported as appropriate for the mode: .It Li "Half page down" Ta "C-d" Ta "M-Down" .It Li "Half page up" Ta "C-u" Ta "M-Up" .It Li "Next page" Ta "C-f" Ta "Page down" +.It Li "Next space" Ta "W" Ta "" +.It Li "Next space, end of word" Ta "E" Ta "" .It Li "Next word" Ta "w" Ta "" .It Li "Next word end" Ta "e" Ta "M-f" .It Li "Paste buffer" Ta "p" Ta "C-y" .It Li "Previous page" Ta "C-b" Ta "Page up" .It Li "Previous word" Ta "b" Ta "M-b" +.It Li "Previous space" Ta "B" Ta "" .It Li "Quit mode" Ta "q" Ta "Escape" .It Li "Scroll down" Ta "C-Down or C-e" Ta "C-Down" .It Li "Scroll up" Ta "C-Up or C-y" Ta "C-Up" @@ -572,6 +575,18 @@ The following keys are supported as appropriate for the mode: .It Li "Transpose chars" Ta "" Ta "C-t" .El .Pp +The next and previous word keys use space and the +.Ql - , +.Ql _ , +.Ql \&" +and +.Ql @ +characters as word delimiters. +Next word moves to the start of the next word, next word end to the end of the +next word and previous word to the start of the previous word. +The three next and previous space keys work similarly but use a space alone as +the word separator. +.Pp These key bindings are defined in a set of named tables: .Em vi-edit and diff --git a/tmux.h b/tmux.h index 7bceb667..c6bb8457 100644 --- a/tmux.h +++ b/tmux.h @@ -462,9 +462,12 @@ enum mode_key_cmd { MODEKEYCOPY_LEFT, MODEKEYCOPY_MIDDLELINE, MODEKEYCOPY_NEXTPAGE, + MODEKEYCOPY_NEXTSPACE, + MODEKEYCOPY_NEXTSPACEEND, MODEKEYCOPY_NEXTWORD, MODEKEYCOPY_NEXTWORDEND, MODEKEYCOPY_PREVIOUSPAGE, + MODEKEYCOPY_PREVIOUSSPACE, MODEKEYCOPY_PREVIOUSWORD, MODEKEYCOPY_RIGHT, MODEKEYCOPY_SCROLLDOWN, diff --git a/window-copy.c b/window-copy.c index fd50339e..e2f15735 100644 --- a/window-copy.c +++ b/window-copy.c @@ -54,7 +54,7 @@ int window_copy_update_selection(struct window_pane *); void window_copy_copy_selection(struct window_pane *, struct client *); void window_copy_copy_line( struct window_pane *, char **, size_t *, u_int, u_int, u_int); -int window_copy_is_space(struct window_pane *, u_int, u_int); +int window_copy_in_set(struct window_pane *, u_int, u_int, const char *); u_int window_copy_find_length(struct window_pane *, u_int); void window_copy_cursor_start_of_line(struct window_pane *); void window_copy_cursor_back_to_indentation(struct window_pane *); @@ -63,9 +63,9 @@ void window_copy_cursor_left(struct window_pane *); void window_copy_cursor_right(struct window_pane *); void window_copy_cursor_up(struct window_pane *, int); void window_copy_cursor_down(struct window_pane *, int); -void window_copy_cursor_next_word(struct window_pane *); -void window_copy_cursor_next_word_end(struct window_pane *); -void window_copy_cursor_previous_word(struct window_pane *); +void window_copy_cursor_next_word(struct window_pane *, const char *); +void window_copy_cursor_next_word_end(struct window_pane *, const char *); +void window_copy_cursor_previous_word(struct window_pane *, const char *); void window_copy_scroll_up(struct window_pane *, u_int); void window_copy_scroll_down(struct window_pane *, u_int); @@ -214,6 +214,7 @@ window_copy_resize(struct window_pane *wp, u_int sx, u_int sy) void window_copy_key(struct window_pane *wp, struct client *c, int key) { + const char *word_separators = " -_@"; struct window_copy_mode_data *data = wp->modedata; struct screen *s = &data->screen; u_int n; @@ -334,14 +335,23 @@ window_copy_key(struct window_pane *wp, struct client *c, int key) case MODEKEYCOPY_ENDOFLINE: window_copy_cursor_end_of_line(wp); break; + case MODEKEYCOPY_NEXTSPACE: + window_copy_cursor_next_word(wp, " "); + break; + case MODEKEYCOPY_NEXTSPACEEND: + window_copy_cursor_next_word_end(wp, " "); + break; case MODEKEYCOPY_NEXTWORD: - window_copy_cursor_next_word(wp); + window_copy_cursor_next_word(wp, word_separators); break; case MODEKEYCOPY_NEXTWORDEND: - window_copy_cursor_next_word_end(wp); + window_copy_cursor_next_word_end(wp, word_separators); + break; + case MODEKEYCOPY_PREVIOUSSPACE: + window_copy_cursor_previous_word(wp, " "); break; case MODEKEYCOPY_PREVIOUSWORD: - window_copy_cursor_previous_word(wp); + window_copy_cursor_previous_word(wp, word_separators); break; case MODEKEYCOPY_SEARCHUP: data->inputtype = WINDOW_COPY_SEARCHUP; @@ -965,17 +975,16 @@ window_copy_copy_line(struct window_pane *wp, } int -window_copy_is_space(struct window_pane *wp, u_int px, u_int py) +window_copy_in_set(struct window_pane *wp, u_int px, u_int py, const char *set) { const struct grid_cell *gc; - const char *spaces = " -_@"; gc = grid_peek_cell(wp->base.grid, px, py); if (gc->flags & (GRID_FLAG_PADDING|GRID_FLAG_UTF8)) return (0); if (gc->data == 0x00 || gc->data == 0x7f) return (0); - return (strchr(spaces, gc->data) != NULL); + return (strchr(set, gc->data) != NULL); } u_int @@ -1025,10 +1034,6 @@ window_copy_cursor_back_to_indentation(struct window_pane *wp) py = screen_hsize(&wp->base) + data->cy - data->oy; xx = window_copy_find_length(wp, py); - /* - * Don't use window_copy_is_space because that treats some word - * delimiters as spaces. - */ while (px < xx) { gc = grid_peek_cell(wp->base.grid, px, py); if (gc->flags & GRID_FLAG_UTF8) @@ -1162,7 +1167,7 @@ window_copy_cursor_down(struct window_pane *wp, int scroll_only) } void -window_copy_cursor_next_word(struct window_pane *wp) +window_copy_cursor_next_word(struct window_pane *wp, const char *separators) { struct window_copy_mode_data *data = wp->modedata; struct screen *base_s = &wp->base; @@ -1174,11 +1179,11 @@ window_copy_cursor_next_word(struct window_pane *wp) yy = screen_hsize(base_s) + screen_size_y(base_s) - 1; /* Are we in a word? Skip it! */ - while (!window_copy_is_space(wp, px, py)) + while (!window_copy_in_set(wp, px, py, separators)) px++; /* Find the start of a word. */ - while (px > xx || window_copy_is_space(wp, px, py)) { + while (px > xx || window_copy_in_set(wp, px, py, separators)) { /* Past the end of the line? Nothing but spaces. */ if (px > xx) { if (py == yy) @@ -1198,7 +1203,7 @@ window_copy_cursor_next_word(struct window_pane *wp) } void -window_copy_cursor_next_word_end(struct window_pane *wp) +window_copy_cursor_next_word_end(struct window_pane *wp, const char *separators) { struct window_copy_mode_data *data = wp->modedata; struct screen *base_s = &wp->base; @@ -1210,7 +1215,7 @@ window_copy_cursor_next_word_end(struct window_pane *wp) yy = screen_hsize(base_s) + screen_size_y(base_s) - 1; /* Are we on spaces? Skip 'em! */ - while (px > xx || window_copy_is_space(wp, px, py)) { + while (px > xx || window_copy_in_set(wp, px, py, separators)) { /* Nothing but spaces past the end of the line, so move down. */ if (px > xx) { if (py == yy) @@ -1225,7 +1230,7 @@ window_copy_cursor_next_word_end(struct window_pane *wp) } /* Find the end of this word. */ - while (!window_copy_is_space(wp, px, py)) + while (!window_copy_in_set(wp, px, py, separators)) px++; window_copy_update_cursor(wp, px, data->cy); @@ -1235,7 +1240,7 @@ window_copy_cursor_next_word_end(struct window_pane *wp) /* Move to the previous place where a word begins. */ void -window_copy_cursor_previous_word(struct window_pane *wp) +window_copy_cursor_previous_word(struct window_pane *wp, const char *separators) { struct window_copy_mode_data *data = wp->modedata; u_int px, py; @@ -1247,7 +1252,7 @@ window_copy_cursor_previous_word(struct window_pane *wp) for (;;) { if (px > 0) { px--; - if (!window_copy_is_space(wp, px, py)) + if (!window_copy_in_set(wp, px, py, separators)) break; } else { if (data->cy == 0 && @@ -1262,7 +1267,7 @@ window_copy_cursor_previous_word(struct window_pane *wp) } /* Move back to the beginning of this word. */ - while (px > 0 && !window_copy_is_space(wp, px - 1, py)) + while (px > 0 && !window_copy_in_set(wp, px - 1, py, separators)) px--; out: From 8aba77b7be489a93dc843d7ef4378bd73b5385b1 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 6 Feb 2010 17:15:33 +0000 Subject: [PATCH 0635/1180] Instead of bailing out on the first configuration file error, carry on, collecting all the errors, then start with the active window in more mode displaying them. --- cfg.c | 57 +++++++++++++++++++++++++++++++---------------- cmd-new-session.c | 18 ++++++++++++++- cmd-source-file.c | 16 ++++++++----- server.c | 55 ++++++++++++++++++++++++--------------------- tmux.c | 7 +----- tmux.h | 7 +++++- window-more.c | 10 +++++++++ window.c | 3 --- 8 files changed, 112 insertions(+), 61 deletions(-) diff --git a/cfg.c b/cfg.c index 05588336..074f5f8b 100644 --- a/cfg.c +++ b/cfg.c @@ -34,6 +34,9 @@ void printflike2 cfg_print(struct cmd_ctx *, const char *, ...); void printflike2 cfg_error(struct cmd_ctx *, const char *, ...); char *cfg_cause; +int cfg_finished; +char **cfg_causes; +u_int cfg_ncauses; /* ARGSUSED */ void printflike2 @@ -52,19 +55,38 @@ cfg_error(unused struct cmd_ctx *ctx, const char *fmt, ...) va_end(ap); } +void printflike3 +cfg_add_cause(u_int *ncauses, char ***causes, const char *fmt, ...) +{ + char *cause; + va_list ap; + + va_start(ap, fmt); + xvasprintf(&cause, fmt, ap); + va_end(ap); + + *causes = xrealloc(*causes, *ncauses + 1, sizeof **causes); + (*causes)[(*ncauses)++] = cause; +} + +/* + * Load configuration file. Returns -1 for an error with a list of messages in + * causes. Note that causes and ncauses must be initialised by the caller! + */ int -load_cfg(const char *path, struct cmd_ctx *ctxin, char **cause) +load_cfg( + const char *path, struct cmd_ctx *ctxin, u_int *ncauses, char ***causes) { FILE *f; u_int n; - char *buf, *line, *ptr; + char *buf, *line, *cause; size_t len; struct cmd_list *cmdlist; struct cmd_ctx ctx; if ((f = fopen(path, "rb")) == NULL) { - xasprintf(cause, "%s: %s", path, strerror(errno)); - return (1); + cfg_add_cause(ncauses, causes, "%s: %s", path, strerror(errno)); + return (-1); } n = 0; @@ -80,10 +102,13 @@ load_cfg(const char *path, struct cmd_ctx *ctxin, char **cause) } n++; - if (cmd_string_parse(buf, &cmdlist, cause) != 0) { - if (*cause == NULL) + if (cmd_string_parse(buf, &cmdlist, &cause) != 0) { + if (cause == NULL) continue; - goto error; + cfg_add_cause( + ncauses, causes, "%s: %u: %s", path, n, cause); + xfree(cause); + continue; } if (cmdlist == NULL) continue; @@ -107,23 +132,17 @@ load_cfg(const char *path, struct cmd_ctx *ctxin, char **cause) cmd_list_exec(cmdlist, &ctx); cmd_list_free(cmdlist); if (cfg_cause != NULL) { - *cause = cfg_cause; - goto error; + cfg_add_cause( + ncauses, causes, "%s: %d: %s", path, n, cfg_cause); + xfree(cfg_cause); + continue; } } if (line != NULL) xfree(line); fclose(f); + if (*ncauses != 0) + return (-1); return (0); - -error: - if (line != NULL) - xfree(line); - fclose(f); - - xasprintf(&ptr, "%s: %s at line %u", path, *cause, n); - xfree(*cause); - *cause = ptr; - return (1); } diff --git a/cmd-new-session.c b/cmd-new-session.c index 461e0391..20ef8d65 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -122,12 +122,13 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) struct cmd_new_session_data *data = self->data; struct session *s, *groupwith; struct window *w; + struct window_pane *wp; struct environ env; struct termios tio, *tiop; const char *update; char *overrides, *cmd, *cwd, *cause; int detached, idx; - u_int sx, sy; + u_int sx, sy, i; if (data->newname != NULL && session_find(data->newname) != NULL) { ctx->error(ctx, "duplicate session: %s", data->newname); @@ -280,6 +281,21 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) recalculate_sizes(); server_update_socket(); + /* + * If there are still configuration file errors to display, put the new + * session's current window into more mode and display them now. + */ + if (cfg_finished && cfg_ncauses != 0) { + wp = s->curw->window->active; + window_pane_set_mode(wp, &window_more_mode); + for (i = 0; i < cfg_ncauses; i++) { + window_more_add(wp, "%s", cfg_causes[i]); + xfree(cfg_causes[i]); + } + xfree(cfg_causes); + cfg_ncauses = 0; + } + return (!detached); /* 1 means don't tell command client to exit */ } diff --git a/cmd-source-file.c b/cmd-source-file.c index f9ca9993..69a27e88 100644 --- a/cmd-source-file.c +++ b/cmd-source-file.c @@ -89,12 +89,18 @@ int cmd_source_file_exec(struct cmd *self, struct cmd_ctx *ctx) { struct cmd_source_file_data *data = self->data; - char *cause; + char **causes; + u_int i, ncauses; - if (load_cfg(data->path, ctx, &cause) != 0) { - ctx->error(ctx, "%s", cause); - xfree(cause); - return (-1); + causes = NULL; + ncauses = 0; + + if (load_cfg(data->path, ctx, &ncauses, &causes) != 0) { + for (i = 0; i < ncauses; i++) { + ctx->print(ctx, "%s", causes[i]); + xfree(causes[i]); + } + xfree(causes); } return (0); diff --git a/server.c b/server.c index ef8fa755..999389cc 100644 --- a/server.c +++ b/server.c @@ -113,10 +113,11 @@ server_create_socket(void) int server_start(char *path) { - struct client *c; - int pair[2]; - char *cause, rpathbuf[MAXPATHLEN]; - struct timeval tv; + struct window_pane *wp; + int pair[2], retval; + char rpathbuf[MAXPATHLEN]; + struct timeval tv; + u_int i; /* The first client is special and gets a socketpair; create it. */ if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) != 0) @@ -166,15 +167,31 @@ server_start(char *path) server_fd = server_create_socket(); server_client_create(pair[1]); - if (access(SYSTEM_CFG, R_OK) == 0) { - if (load_cfg(SYSTEM_CFG, NULL, &cause) != 0) - goto error; - } else if (errno != ENOENT) { - xasprintf(&cause, "%s: %s", strerror(errno), SYSTEM_CFG); - goto error; + retval = 0; + if (access(SYSTEM_CFG, R_OK) == 0) + load_cfg(SYSTEM_CFG, NULL, &cfg_ncauses, &cfg_causes); + else if (errno != ENOENT) { + cfg_add_cause(&cfg_ncauses, &cfg_causes, + "%s: %s", strerror(errno), SYSTEM_CFG); } - if (cfg_file != NULL && load_cfg(cfg_file, NULL, &cause) != 0) - goto error; + if (cfg_file != NULL) + load_cfg(cfg_file, NULL, &cfg_ncauses, &cfg_causes); + + /* + * If there is a session already, put the current window and pane into + * more mode. + */ + if (!ARRAY_EMPTY(&sessions) && cfg_ncauses != 0) { + wp = ARRAY_FIRST(&sessions)->curw->window->active; + window_pane_set_mode(wp, &window_more_mode); + for (i = 0; i < cfg_ncauses; i++) { + window_more_add(wp, "%s", cfg_causes[i]); + xfree(cfg_causes[i]); + } + xfree(cfg_causes); + cfg_ncauses = 0; + } + cfg_finished = 1; event_set(&server_ev_accept, server_fd, EV_READ|EV_PERSIST, server_accept_callback, NULL); @@ -188,20 +205,6 @@ server_start(char *path) server_signal_set(); server_loop(); exit(0); - -error: - /* Write the error and shutdown the server. */ - c = ARRAY_FIRST(&clients); - - server_write_error(c, cause); - server_write_client(c, MSG_EXIT, NULL, 0); - xfree(cause); - - server_shutdown = 1; - - server_signal_set(); - server_loop(); - exit(1); } /* Main server loop. */ diff --git a/tmux.c b/tmux.c index 758ad842..b59dd176 100644 --- a/tmux.c +++ b/tmux.c @@ -432,15 +432,10 @@ main(int argc, char **argv) home = pw->pw_dir; } xasprintf(&cfg_file, "%s/%s", home, DEFAULT_CFG); - if (access(cfg_file, R_OK) != 0) { + if (access(cfg_file, R_OK) != 0 && errno == ENOENT) { xfree(cfg_file); cfg_file = NULL; } - } else { - if (access(cfg_file, R_OK) != 0) { - log_warn("%s", cfg_file); - exit(1); - } } /* diff --git a/tmux.h b/tmux.h index c6bb8457..42a5301d 100644 --- a/tmux.h +++ b/tmux.h @@ -1257,7 +1257,11 @@ int checkshell(const char *); int areshell(const char *); /* cfg.c */ -int load_cfg(const char *, struct cmd_ctx *, char **); +extern int cfg_finished; +extern char **cfg_causes; +extern u_int cfg_ncauses; +void printflike3 cfg_add_cause(u_int *, char ***, const char *, ...); +int load_cfg(const char *, struct cmd_ctx *, u_int *, char ***); /* mode-key.c */ extern const struct mode_key_table mode_key_tables[]; @@ -1867,6 +1871,7 @@ void window_copy_pageup(struct window_pane *); /* window-more.c */ extern const struct window_mode window_more_mode; +void window_more_add(struct window_pane *, const char *, ...); void window_more_vadd(struct window_pane *, const char *, va_list); /* window-choose.c */ diff --git a/window-more.c b/window-more.c index 28423e1a..84f37d53 100644 --- a/window-more.c +++ b/window-more.c @@ -52,6 +52,16 @@ struct window_more_mode_data { u_int top; }; +void +window_more_add(struct window_pane *wp, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + window_more_vadd(wp, fmt, ap); + va_end(ap); +} + void window_more_vadd(struct window_pane *wp, const char *fmt, va_list ap) { diff --git a/window.c b/window.c index 5494142e..a990fa57 100644 --- a/window.c +++ b/window.c @@ -657,9 +657,6 @@ window_pane_parse(struct window_pane *wp) char *data; size_t new_size; - if (wp->mode != NULL) - return; - new_size = EVBUFFER_LENGTH(wp->event->input) - wp->pipe_off; if (wp->pipe_fd != -1 && new_size > 0) { data = EVBUFFER_DATA(wp->event->input); From 3ef3802629ffea0bad310e662e52db46763dd582 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 6 Feb 2010 17:35:01 +0000 Subject: [PATCH 0636/1180] Rectangle copy support, from Robin Lee Powell. --- mode-key.c | 7 +++- screen.c | 113 ++++++++++++++++++++++++++++++++++---------------- tmux.1 | 1 + tmux.h | 6 ++- window-copy.c | 112 +++++++++++++++++++++++++++++++++++++++++-------- 5 files changed, 181 insertions(+), 58 deletions(-) diff --git a/mode-key.c b/mode-key.c index 175a2a04..1a654fb2 100644 --- a/mode-key.c +++ b/mode-key.c @@ -89,6 +89,7 @@ struct mode_key_cmdstr mode_key_cmdstr_copy[] = { { MODEKEYCOPY_HISTORYBOTTOM, "history-bottom" }, { MODEKEYCOPY_HISTORYTOP, "history-top" }, { MODEKEYCOPY_LEFT, "cursor-left" }, + { MODEKEYCOPY_RECTANGLETOGGLE, "rectangle-toggle" }, { MODEKEYCOPY_MIDDLELINE, "middle-line" }, { MODEKEYCOPY_NEXTPAGE, "page-down" }, { MODEKEYCOPY_NEXTSPACE, "next-space" }, @@ -207,6 +208,7 @@ const struct mode_key_entry mode_key_vi_copy[] = { { 'l', 0, MODEKEYCOPY_RIGHT }, { 'n', 0, MODEKEYCOPY_SEARCHAGAIN }, { 'q', 0, MODEKEYCOPY_CANCEL }, + { 'v', 0, MODEKEYCOPY_RECTANGLETOGGLE }, { 'w', 0, MODEKEYCOPY_NEXTWORD }, { KEYC_BSPACE, 0, MODEKEYCOPY_LEFT }, { KEYC_DOWN | KEYC_CTRL,0, MODEKEYCOPY_SCROLLDOWN }, @@ -276,9 +278,10 @@ struct mode_key_tree mode_key_tree_emacs_choice; /* emacs copy mode keys. */ const struct mode_key_entry mode_key_emacs_copy[] = { { ' ', 0, MODEKEYCOPY_NEXTPAGE }, - { '<' | KEYC_ESCAPE,0, MODEKEYCOPY_HISTORYTOP }, - { '>' | KEYC_ESCAPE, 0, MODEKEYCOPY_HISTORYBOTTOM }, + { '<' | KEYC_ESCAPE, 0, MODEKEYCOPY_HISTORYTOP }, + { '>' | KEYC_ESCAPE, 0, MODEKEYCOPY_HISTORYBOTTOM }, { 'R' | KEYC_ESCAPE, 0, MODEKEYCOPY_TOPLINE }, + { 'R', 0, MODEKEYCOPY_RECTANGLETOGGLE }, { '\000' /* C-Space */, 0, MODEKEYCOPY_STARTSELECTION }, { '\001' /* C-a */, 0, MODEKEYCOPY_STARTOFLINE }, { '\002' /* C-b */, 0, MODEKEYCOPY_LEFT }, diff --git a/screen.c b/screen.c index 0d4f6e73..56dbbf37 100644 --- a/screen.c +++ b/screen.c @@ -228,41 +228,17 @@ screen_resize_y(struct screen *s, u_int sy) /* Set selection. */ void -screen_set_selection(struct screen *s, - u_int sx, u_int sy, u_int ex, u_int ey, struct grid_cell *gc) +screen_set_selection(struct screen *s, u_int sx, u_int sy, + u_int ex, u_int ey, u_int rectflag, struct grid_cell *gc) { struct screen_sel *sel = &s->sel; memcpy(&sel->cell, gc, sizeof sel->cell); sel->flag = 1; + sel->rectflag = rectflag; - /* starting line < ending line -- downward selection. */ - if (sy < ey) { - sel->sx = sx; sel->sy = sy; - sel->ex = ex; sel->ey = ey; - return; - } - - /* starting line > ending line -- upward selection. */ - if (sy > ey) { - if (sx > 0) { - sel->sx = ex; sel->sy = ey; - sel->ex = sx - 1; sel->ey = sy; - } else { - sel->sx = ex; sel->sy = ey; - sel->ex = -1; sel->ey = sy - 1; - } - return; - } - - /* starting line == ending line. */ - if (ex < sx) { - sel->sx = ex; sel->sy = ey; - sel->ex = sx - 1; sel->ey = sy; - } else { - sel->sx = sx; sel->sy = sy; - sel->ex = ex; sel->ey = ey; - } + sel->sx = sx; sel->sy = sy; + sel->ex = ex; sel->ey = ey; } /* Clear selection. */ @@ -280,16 +256,81 @@ screen_check_selection(struct screen *s, u_int px, u_int py) { struct screen_sel *sel = &s->sel; - if (!sel->flag || py < sel->sy || py > sel->ey) + if (!sel->flag) return (0); - if (py == sel->sy && py == sel->ey) { - if (px < sel->sx || px > sel->ex) - return (0); - return (1); + if (sel->rectflag) { + if (sel->sy < sel->ey) { + /* start line < end line -- downward selection. */ + if (py < sel->sy || py > sel->ey) + return (0); + } else if (sel->sy > sel->ey) { + /* start line > end line -- upward selection. */ + if (py > sel->sy || py < sel->ey) + return (0); + } else { + /* starting line == ending line. */ + if (py != sel->sy) + return (0); + } + + /* + * Need to include the selection start row, but not the cursor + * row, which means the selection changes depending on which + * one is on the left. + */ + if (sel->ex < sel->sx) { + /* Cursor (ex) is on the left. */ + if (px <= sel->ex) + return (0); + + if (px > sel->sx) + return (0); + } else { + /* Selection start (sx) is on the left. */ + if (px < sel->sx) + return (0); + + if (px >= sel->ex) + return (0); + } + } else { + /* + * Like emacs, keep the top-left-most character, and drop the + * bottom-right-most, regardless of copy direction. + */ + if (sel->sy < sel->ey) { + /* starting line < ending line -- downward selection. */ + if (py < sel->sy || py > sel->ey) + return (0); + + if ((py == sel->sy && px < sel->sx) + || (py == sel->ey && px > sel->ex)) + return (0); + } else if (sel->sy > sel->ey) { + /* starting line > ending line -- upward selection. */ + if (py > sel->sy || py < sel->ey) + return (0); + + if ((py == sel->sy && px >= sel->sx) + || (py == sel->ey && px < sel->ex)) + return (0); + } else { + /* starting line == ending line. */ + if (py != sel->sy) + return (0); + + if (sel->ex < sel->sx) { + /* cursor (ex) is on the left */ + if (px > sel->sx || px < sel->ex) + return (0); + } else { + /* selection start (sx) is on the left */ + if (px < sel->sx || px > sel->ex) + return (0); + } + } } - if ((py == sel->sy && px < sel->sx) || (py == sel->ey && px > sel->ex)) - return (0); return (1); } diff --git a/tmux.1 b/tmux.1 index a759c82b..67ce3bc4 100644 --- a/tmux.1 +++ b/tmux.1 @@ -564,6 +564,7 @@ The following keys are supported as appropriate for the mode: .It Li "Previous word" Ta "b" Ta "M-b" .It Li "Previous space" Ta "B" Ta "" .It Li "Quit mode" Ta "q" Ta "Escape" +.It Li "Rectangle toggle" Ta "v" Ta "R" .It Li "Scroll down" Ta "C-Down or C-e" Ta "C-Down" .It Li "Scroll up" Ta "C-Up or C-y" Ta "C-Up" .It Li "Search again" Ta "n" Ta "n" diff --git a/tmux.h b/tmux.h index 42a5301d..43cd8197 100644 --- a/tmux.h +++ b/tmux.h @@ -469,6 +469,7 @@ enum mode_key_cmd { MODEKEYCOPY_PREVIOUSPAGE, MODEKEYCOPY_PREVIOUSSPACE, MODEKEYCOPY_PREVIOUSWORD, + MODEKEYCOPY_RECTANGLETOGGLE, MODEKEYCOPY_RIGHT, MODEKEYCOPY_SCROLLDOWN, MODEKEYCOPY_SCROLLUP, @@ -674,6 +675,7 @@ SLIST_HEAD(joblist, job); /* Screen selection. */ struct screen_sel { int flag; + int rectflag; u_int sx; u_int sy; @@ -1774,8 +1776,8 @@ void screen_free(struct screen *); void screen_reset_tabs(struct screen *); void screen_set_title(struct screen *, const char *); void screen_resize(struct screen *, u_int, u_int); -void screen_set_selection( - struct screen *, u_int, u_int, u_int, u_int, struct grid_cell *); +void screen_set_selection(struct screen *, + u_int, u_int, u_int, u_int, u_int, struct grid_cell *); void screen_clear_selection(struct screen *); int screen_check_selection(struct screen *, u_int, u_int); diff --git a/window-copy.c b/window-copy.c index e2f15735..32f1a71c 100644 --- a/window-copy.c +++ b/window-copy.c @@ -68,6 +68,7 @@ void window_copy_cursor_next_word_end(struct window_pane *, const char *); void window_copy_cursor_previous_word(struct window_pane *, const char *); void window_copy_scroll_up(struct window_pane *, u_int); void window_copy_scroll_down(struct window_pane *, u_int); +void window_copy_rectangle_toggle(struct window_pane *); const struct window_mode window_copy_mode = { window_copy_init, @@ -95,6 +96,8 @@ struct window_copy_mode_data { u_int selx; u_int sely; + u_int rectflag; /* are we in rectangle copy mode? */ + u_int cx; u_int cy; @@ -126,6 +129,8 @@ window_copy_init(struct window_pane *wp) data->lastcx = 0; data->lastsx = 0; + data->rectflag = 0; + data->inputtype = WINDOW_COPY_OFF; data->inputprompt = NULL; data->inputstr = xstrdup(""); @@ -379,6 +384,9 @@ window_copy_key(struct window_pane *wp, struct client *c, int key) data->inputprompt = "Goto Line"; *data->inputstr = '\0'; goto input_on; + case MODEKEYCOPY_RECTANGLETOGGLE: + window_copy_rectangle_toggle(wp); + return; default: break; } @@ -823,7 +831,7 @@ window_copy_update_selection(struct window_pane *wp) struct screen *s = &data->screen; struct options *oo = &wp->window->options; struct grid_cell gc; - u_int sx, sy, ty; + u_int sx, sy, ty, cy; if (!s->sel.flag) return (0); @@ -841,17 +849,33 @@ window_copy_update_selection(struct window_pane *wp) sx = data->selx; sy = data->sely; if (sy < ty) { /* above screen */ - sx = 0; + if (!data->rectflag) + sx = 0; sy = 0; } else if (sy > ty + screen_size_y(s) - 1) { /* below screen */ - sx = screen_size_x(s) - 1; + if (!data->rectflag) + sx = screen_size_x(s) - 1; sy = screen_size_y(s) - 1; } else sy -= ty; sy = screen_hsize(s) + sy; - screen_set_selection( - s, sx, sy, data->cx, screen_hsize(s) + data->cy, &gc); + screen_set_selection(s, + sx, sy, data->cx, screen_hsize(s) + data->cy, data->rectflag, &gc); + + if (data->rectflag) { + /* + * Can't rely on the caller to redraw the right lines for + * rectangle selection - find the highest line and the number + * of lines, and redraw just past that in both directions + */ + cy = data->cy; + if (sy < cy) + window_copy_redraw_lines(wp, sy, cy - sy + 1); + else + window_copy_redraw_lines(wp, cy, sy - cy + 1); + } + return (1); } @@ -861,8 +885,9 @@ window_copy_copy_selection(struct window_pane *wp, struct client *c) struct window_copy_mode_data *data = wp->modedata; struct screen *s = &data->screen; char *buf; - size_t off; - u_int i, xx, yy, sx, sy, ex, ey, limit; + size_t off; + u_int i, xx, yy, sx, sy, ex, ey, limit; + u_int firstsx, lastex, restex, restsx; if (!s->sel.flag) return; @@ -893,17 +918,53 @@ window_copy_copy_selection(struct window_pane *wp, struct client *c) if (ex > xx) ex = xx; + /* + * Deal with rectangle-copy if necessary; four situations: start of + * first line (firstsx), end of last line (lastex), start (restsx) and + * end (restex) of all other lines. + */ + xx = screen_size_x(s); + if (data->rectflag) { + /* + * Need to ignore the column with the cursor in it, which for + * rectangular copy means knowing which side the cursor is on. + */ + if (data->selx < data->cx) { + /* Selection start is on the left. */ + lastex = data->cx; + restex = data->cx; + firstsx = data->selx; + restsx = data->selx; + } else { + /* Cursor is on the left. */ + lastex = data->selx + 1; + restex = data->selx + 1; + firstsx = data->cx + 1; + restsx = data->cx + 1; + } + } else { + /* + * Like emacs, keep the top-left-most character, and drop the + * bottom-right-most, regardless of copy direction. + */ + lastex = ex; + restex = xx; + firstsx = sx; + restsx = 0; + } + /* Copy the lines. */ if (sy == ey) - window_copy_copy_line(wp, &buf, &off, sy, sx, ex); + window_copy_copy_line(wp, &buf, &off, sy, firstsx, lastex); else { - xx = screen_size_x(s); - window_copy_copy_line(wp, &buf, &off, sy, sx, xx); + window_copy_copy_line(wp, &buf, &off, sy, firstsx, restex); if (ey - sy > 1) { - for (i = sy + 1; i < ey; i++) - window_copy_copy_line(wp, &buf, &off, i, 0, xx); + for (i = sy + 1; i < ey; i++) { + window_copy_copy_line( + wp, &buf, &off, i, restsx, restex); + } } - window_copy_copy_line(wp, &buf, &off, ey, 0, ex); + window_copy_copy_line(wp, &buf, &off, ey, restsx, lastex); } /* Don't bother if no data. */ @@ -1288,7 +1349,6 @@ window_copy_scroll_up(struct window_pane *wp, u_int ny) if (ny == 0) return; data->oy -= ny; - window_copy_update_selection(wp); screen_write_start(&ctx, wp, NULL); screen_write_cursormove(&ctx, 0, 0); @@ -1299,9 +1359,12 @@ window_copy_scroll_up(struct window_pane *wp, u_int ny) window_copy_write_line(wp, &ctx, 1); if (screen_size_y(s) > 3) window_copy_write_line(wp, &ctx, screen_size_y(s) - 2); - if (s->sel.flag && screen_size_y(s) > ny) + if (s->sel.flag && screen_size_y(s) > ny) { + window_copy_update_selection(wp); window_copy_write_line(wp, &ctx, screen_size_y(s) - ny - 1); + } screen_write_cursormove(&ctx, data->cx, data->cy); + window_copy_update_selection(wp); screen_write_stop(&ctx); } @@ -1320,16 +1383,29 @@ window_copy_scroll_down(struct window_pane *wp, u_int ny) if (ny == 0) return; data->oy += ny; - window_copy_update_selection(wp); screen_write_start(&ctx, wp, NULL); screen_write_cursormove(&ctx, 0, 0); screen_write_insertline(&ctx, ny); window_copy_write_lines(wp, &ctx, 0, ny); - if (s->sel.flag && screen_size_y(s) > ny) + if (s->sel.flag && screen_size_y(s) > ny) { + window_copy_update_selection(wp); window_copy_write_line(wp, &ctx, ny); - else if (ny == 1) /* nuke position */ + } else if (ny == 1) /* nuke position */ window_copy_write_line(wp, &ctx, 1); screen_write_cursormove(&ctx, data->cx, data->cy); + window_copy_update_selection(wp); screen_write_stop(&ctx); } + +void +window_copy_rectangle_toggle(struct window_pane *wp) +{ + struct window_copy_mode_data *data = wp->modedata; + + data->rectflag = !data->rectflag; + + window_copy_update_selection(wp); + window_copy_redraw_screen(wp); +} + From 4a5017d1d8a7a42b47433826747e01ba6867ba46 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 6 Feb 2010 18:29:15 +0000 Subject: [PATCH 0637/1180] Clean up $TMUX parsing, from Micah Cowan, tweaked by me. --- tmux.c | 48 +++++++++++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/tmux.c b/tmux.c index b59dd176..c6e4f830 100644 --- a/tmux.c +++ b/tmux.c @@ -46,8 +46,14 @@ time_t start_time; char *socket_path; int login_shell; +struct env_data { + char *path; + pid_t pid; + u_int idx; +}; + __dead void usage(void); -void fill_session(struct msg_command_data *); +void parse_env(struct env_data *); char *makesockpath(const char *); __dead void shell_exec(const char *, const char *); @@ -129,9 +135,9 @@ areshell(const char *shell) } void -fill_session(struct msg_command_data *data) +parse_env(struct env_data *data) { - char *env, *ptr1, *ptr2, buf[256]; + char *env, *path_pid, *pid_idx, buf[256]; size_t len; const char *errstr; long long ll; @@ -140,19 +146,24 @@ fill_session(struct msg_command_data *data) if ((env = getenv("TMUX")) == NULL) return; - if ((ptr2 = strrchr(env, ',')) == NULL || ptr2 == env) + if ((path_pid = strchr(env, ',')) == NULL || path_pid == env) return; - for (ptr1 = ptr2 - 1; ptr1 > env && *ptr1 != ','; ptr1--) - ; - if (*ptr1 != ',') + if ((pid_idx = strchr(path_pid + 1, ',')) == NULL) + return; + if ((pid_idx == path_pid + 1 || pid_idx[1] == '\0')) return; - ptr1++; - ptr2++; - len = ptr2 - ptr1 - 1; + /* path */ + len = path_pid - env; + data->path = xmalloc (len + 1); + memcpy(data->path, env, len); + data->path[len] = '\0'; + + /* pid */ + len = pid_idx - path_pid - 1; if (len > (sizeof buf) - 1) return; - memcpy(buf, ptr1, len); + memcpy(buf, path_pid + 1, len); buf[len] = '\0'; ll = strtonum(buf, 0, LONG_MAX, &errstr); @@ -160,7 +171,8 @@ fill_session(struct msg_command_data *data) return; data->pid = ll; - ll = strtonum(ptr2, 0, UINT_MAX, &errstr); + /* idx */ + ll = strtonum(pid_idx+1, 0, UINT_MAX, &errstr); if (errstr != NULL) return; data->idx = ll; @@ -224,6 +236,7 @@ main(int argc, char **argv) struct passwd *pw; struct options *oo, *so, *wo; struct keylist *keylist; + struct env_data envdata; struct msg_command_data cmddata; char *s, *shellcmd, *path, *label, *home, *cause; char cwd[MAXPATHLEN], **var; @@ -238,6 +251,7 @@ main(int argc, char **argv) flags = 0; shellcmd = label = path = NULL; + envdata.path = NULL; login_shell = (**argv == '-'); while ((opt = getopt(argc, argv, "28c:df:lL:qS:uUv")) != -1) { switch (opt) { @@ -442,13 +456,12 @@ main(int argc, char **argv) * Figure out the socket path. If specified on the command-line with * -S or -L, use it, otherwise try $TMUX or assume -L default. */ + parse_env(&envdata); if (path == NULL) { /* No -L. Try $TMUX, or default. */ if (label == NULL) { - if ((path = getenv("TMUX")) != NULL) { - path = xstrdup(path); - path[strcspn(path, ",")] = '\0'; - } else + path = envdata.path; + if (path == NULL) label = xstrdup("default"); } @@ -468,7 +481,8 @@ main(int argc, char **argv) buf = NULL; len = 0; } else { - fill_session(&cmddata); + cmddata.pid = envdata.pid; + cmddata.idx = envdata.idx; cmddata.argc = argc; if (cmd_pack_argv( From 0a86d3579edb44ee559cfe6498f43d6637a08bd9 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 6 Feb 2010 18:47:41 +0000 Subject: [PATCH 0638/1180] Change nested check to compare server socket path rather than just assuming that if $TMUX is set it is nested. From Micah Cowan. --- server-client.c | 11 ----------- tmux.c | 17 ++++++++++++++++- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/server-client.c b/server-client.c index 34b99514..03560c1c 100644 --- a/server-client.c +++ b/server-client.c @@ -693,17 +693,6 @@ server_client_msg_command(struct client *c, struct msg_command_data *data) } cmd_free_argv(argc, argv); - if (data->pid != -1) { - TAILQ_FOREACH(cmd, cmdlist, qentry) { - if (cmd->entry->flags & CMD_CANTNEST) { - server_client_msg_error(&ctx, - "sessions should be nested with care. " - "unset $TMUX to force"); - goto error; - } - } - } - if (cmd_list_exec(cmdlist, &ctx) != 1) server_write_client(c, MSG_EXIT, NULL, 0); cmd_list_free(cmdlist); diff --git a/tmux.c b/tmux.c index c6e4f830..a582b951 100644 --- a/tmux.c +++ b/tmux.c @@ -484,6 +484,7 @@ main(int argc, char **argv) cmddata.pid = envdata.pid; cmddata.idx = envdata.idx; + /* Prepare command for server. */ cmddata.argc = argc; if (cmd_pack_argv( argc, argv, cmddata.argv, sizeof cmddata.argv) != 0) { @@ -499,7 +500,7 @@ main(int argc, char **argv) if (shellcmd != NULL) cmdflags |= CMD_STARTSERVER; else if (argc == 0) /* new-session is the default */ - cmdflags |= CMD_STARTSERVER|CMD_SENDENVIRON; + cmdflags |= CMD_STARTSERVER|CMD_SENDENVIRON|CMD_CANTNEST; else { /* * It sucks parsing the command string twice (in client and @@ -516,10 +517,24 @@ main(int argc, char **argv) cmdflags |= CMD_STARTSERVER; if (cmd->entry->flags & CMD_SENDENVIRON) cmdflags |= CMD_SENDENVIRON; + if (cmd->entry->flags & CMD_CANTNEST) + cmdflags |= CMD_CANTNEST; } cmd_list_free(cmdlist); } + /* + * Check if this could be a nested session, if the command can't nest: + * if the socket path matches $TMUX, this is probably the same server. + */ + if (shellcmd == NULL && envdata.path != NULL && + cmdflags & CMD_CANTNEST && + (path == envdata.path || strcmp(path, envdata.path) == 0)) { + log_warnx("sessions should be nested with care. " + "unset $TMUX to force."); + exit(1); + } + if ((main_ibuf = client_init(path, cmdflags, flags)) == NULL) exit(1); xfree(path); From bb53c20c1882cbc909d4fe2ae3c6ad665da6abf6 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 6 Feb 2010 22:55:31 +0000 Subject: [PATCH 0639/1180] Support attaching a client read-only with a new -r flag to the attach-session command. --- cmd-attach-session.c | 7 +++++-- cmd-detach-client.c | 2 +- key-bindings.c | 14 +++++++++++++- server-client.c | 25 ++++++++++++++++--------- tmux.1 | 6 +++++- tmux.h | 2 ++ 6 files changed, 42 insertions(+), 14 deletions(-) diff --git a/cmd-attach-session.c b/cmd-attach-session.c index c8f01633..dbc43141 100644 --- a/cmd-attach-session.c +++ b/cmd-attach-session.c @@ -28,8 +28,8 @@ int cmd_attach_session_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_attach_session_entry = { "attach-session", "attach", - "[-d] " CMD_TARGET_SESSION_USAGE, - CMD_CANTNEST|CMD_STARTSERVER|CMD_SENDENVIRON, "d", + "[-dr] " CMD_TARGET_SESSION_USAGE, + CMD_CANTNEST|CMD_STARTSERVER|CMD_SENDENVIRON, "dr", cmd_target_init, cmd_target_parse, cmd_attach_session_exec, @@ -89,6 +89,9 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx) return (-1); } + if (cmd_check_flag(data->chflags, 'r')) + ctx->cmdclient->flags |= CLIENT_READONLY; + if (cmd_check_flag(data->chflags, 'd')) server_write_session(s, MSG_DETACH, NULL, 0); diff --git a/cmd-detach-client.c b/cmd-detach-client.c index 4903281f..a2288036 100644 --- a/cmd-detach-client.c +++ b/cmd-detach-client.c @@ -29,7 +29,7 @@ int cmd_detach_client_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_detach_client_entry = { "detach-client", "detach", CMD_TARGET_CLIENT_USAGE, - 0, "", + CMD_READONLY, "", cmd_target_init, cmd_target_parse, cmd_detach_client_exec, diff --git a/key-bindings.c b/key-bindings.c index d536af11..c08ac942 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -239,7 +239,9 @@ key_bindings_info(struct cmd_ctx *ctx, const char *fmt, ...) void key_bindings_dispatch(struct key_binding *bd, struct client *c) { - struct cmd_ctx ctx; + struct cmd_ctx ctx; + struct cmd *cmd; + int readonly; ctx.msgdata = NULL; ctx.curclient = c; @@ -250,5 +252,15 @@ key_bindings_dispatch(struct key_binding *bd, struct client *c) ctx.cmdclient = NULL; + readonly = 1; + TAILQ_FOREACH(cmd, bd->cmdlist, qentry) { + if (!(cmd->entry->flags & CMD_READONLY)) + readonly = 0; + } + if (!readonly && c->flags & CLIENT_READONLY) { + key_bindings_info(&ctx, "Client is read-only"); + return; + } + cmd_list_exec(bd->cmdlist, &ctx); } diff --git a/server-client.c b/server-client.c index 03560c1c..03d5c84b 100644 --- a/server-client.c +++ b/server-client.c @@ -271,6 +271,8 @@ server_client_handle_key(int key, struct mouse_event *mouse, void *data) /* Special case: number keys jump to pane in identify mode. */ if (c->flags & CLIENT_IDENTIFY && key >= '0' && key <= '9') { + if (c->flags & CLIENT_READONLY) + return; wp = window_pane_at_index(w, key - '0'); if (wp != NULL && window_pane_visible(wp)) window_set_active_pane(w, wp); @@ -279,15 +281,20 @@ server_client_handle_key(int key, struct mouse_event *mouse, void *data) } /* Handle status line. */ - status_message_clear(c); - server_clear_identify(c); + if (!(c->flags & CLIENT_READONLY)) { + status_message_clear(c); + server_clear_identify(c); + } if (c->prompt_string != NULL) { - status_prompt_key(c, key); + if (!(c->flags & CLIENT_READONLY)) + status_prompt_key(c, key); return; } /* Check for mouse keys. */ if (key == KEYC_MOUSE) { + if (c->flags & CLIENT_READONLY) + return; if (options_get_number(oo, "mouse-select-pane")) { window_set_active_at(w, mouse->x, mouse->y); server_redraw_window_borders(w); @@ -313,9 +320,10 @@ server_client_handle_key(int key, struct mouse_event *mouse, void *data) c->flags |= CLIENT_PREFIX; else { /* Try as a non-prefix key binding. */ - if ((bd = key_bindings_lookup(key)) == NULL) - window_pane_key(wp, c, key); - else + if ((bd = key_bindings_lookup(key)) == NULL) { + if (!(c->flags & CLIENT_READONLY)) + window_pane_key(wp, c, key); + } else key_bindings_dispatch(bd, c); } return; @@ -329,7 +337,7 @@ server_client_handle_key(int key, struct mouse_event *mouse, void *data) c->flags &= ~CLIENT_REPEAT; if (isprefix) c->flags |= CLIENT_PREFIX; - else + else if (!(c->flags & CLIENT_READONLY)) window_pane_key(wp, c, key); } return; @@ -340,7 +348,7 @@ server_client_handle_key(int key, struct mouse_event *mouse, void *data) c->flags &= ~CLIENT_REPEAT; if (isprefix) c->flags |= CLIENT_PREFIX; - else + else if (!(c->flags & CLIENT_READONLY)) window_pane_key(wp, c, key); return; } @@ -660,7 +668,6 @@ server_client_msg_command(struct client *c, struct msg_command_data *data) { struct cmd_ctx ctx; struct cmd_list *cmdlist = NULL; - struct cmd *cmd; int argc; char **argv, *cause; diff --git a/tmux.1 b/tmux.1 index 67ce3bc4..360d53a2 100644 --- a/tmux.1 +++ b/tmux.1 @@ -364,7 +364,7 @@ new-window ; split-window -d The following commands are available: .Bl -tag -width Ds .It Xo Ic attach-session -.Op Fl d +.Op Fl dr .Op Fl t Ar target-session .Xc .D1 (alias: Ic attach ) @@ -376,6 +376,10 @@ If used from inside, switch the current client. If .Fl d is specified, any other clients attached to the session are detached. +.Fl r +signifies the client is read-only (only keys bound to the +.Ic detach-client +command have any effect) .Pp If no server is started, .Ic attach-session diff --git a/tmux.h b/tmux.h index 43cd8197..2afaf3cc 100644 --- a/tmux.h +++ b/tmux.h @@ -1094,6 +1094,7 @@ struct client { #define CLIENT_IDENTIFY 0x100 #define CLIENT_DEAD 0x200 #define CLIENT_BORDERS 0x400 +#define CLIENT_READONLY 0x800 int flags; struct event identify_timer; @@ -1172,6 +1173,7 @@ struct cmd_entry { #define CMD_ARG01 0x10 #define CMD_ARG2 0x20 #define CMD_ARG12 0x40 +#define CMD_READONLY 0x80 int flags; const char *chflags; From 46511805037cf33bd9e2c6286e33417d9fd35d1f Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 6 Feb 2010 23:22:27 +0000 Subject: [PATCH 0640/1180] Use the array.h code for the causes list. --- array.h | 2 ++ cfg.c | 27 +++++++++++---------------- cmd-new-session.c | 12 ++++++------ cmd-source-file.c | 20 ++++++++++---------- server.c | 22 +++++++++++----------- tmux.h | 10 ++++++---- 6 files changed, 46 insertions(+), 47 deletions(-) diff --git a/array.h b/array.h index d48dbacb..543c3dfe 100644 --- a/array.h +++ b/array.h @@ -19,6 +19,8 @@ #ifndef ARRAY_H #define ARRAY_H +#define ARRAY_INITIALIZER { NULL, 0, 0 } + #define ARRAY_DECL(n, c) \ struct n { \ c *list; \ diff --git a/cfg.c b/cfg.c index 074f5f8b..d540ff9b 100644 --- a/cfg.c +++ b/cfg.c @@ -33,10 +33,9 @@ void printflike2 cfg_print(struct cmd_ctx *, const char *, ...); void printflike2 cfg_error(struct cmd_ctx *, const char *, ...); -char *cfg_cause; -int cfg_finished; -char **cfg_causes; -u_int cfg_ncauses; +char *cfg_cause; +int cfg_finished; +struct causelist cfg_causes = ARRAY_INITIALIZER; /* ARGSUSED */ void printflike2 @@ -55,8 +54,8 @@ cfg_error(unused struct cmd_ctx *ctx, const char *fmt, ...) va_end(ap); } -void printflike3 -cfg_add_cause(u_int *ncauses, char ***causes, const char *fmt, ...) +void printflike2 +cfg_add_cause(struct causelist *causes, const char *fmt, ...) { char *cause; va_list ap; @@ -65,8 +64,7 @@ cfg_add_cause(u_int *ncauses, char ***causes, const char *fmt, ...) xvasprintf(&cause, fmt, ap); va_end(ap); - *causes = xrealloc(*causes, *ncauses + 1, sizeof **causes); - (*causes)[(*ncauses)++] = cause; + ARRAY_ADD(causes, cause); } /* @@ -74,8 +72,7 @@ cfg_add_cause(u_int *ncauses, char ***causes, const char *fmt, ...) * causes. Note that causes and ncauses must be initialised by the caller! */ int -load_cfg( - const char *path, struct cmd_ctx *ctxin, u_int *ncauses, char ***causes) +load_cfg(const char *path, struct cmd_ctx *ctxin, struct causelist *causes) { FILE *f; u_int n; @@ -85,7 +82,7 @@ load_cfg( struct cmd_ctx ctx; if ((f = fopen(path, "rb")) == NULL) { - cfg_add_cause(ncauses, causes, "%s: %s", path, strerror(errno)); + cfg_add_cause(causes, "%s: %s", path, strerror(errno)); return (-1); } n = 0; @@ -105,8 +102,7 @@ load_cfg( if (cmd_string_parse(buf, &cmdlist, &cause) != 0) { if (cause == NULL) continue; - cfg_add_cause( - ncauses, causes, "%s: %u: %s", path, n, cause); + cfg_add_cause(causes, "%s: %u: %s", path, n, cause); xfree(cause); continue; } @@ -132,8 +128,7 @@ load_cfg( cmd_list_exec(cmdlist, &ctx); cmd_list_free(cmdlist); if (cfg_cause != NULL) { - cfg_add_cause( - ncauses, causes, "%s: %d: %s", path, n, cfg_cause); + cfg_add_cause(causes, "%s: %d: %s", path, n, cfg_cause); xfree(cfg_cause); continue; } @@ -142,7 +137,7 @@ load_cfg( xfree(line); fclose(f); - if (*ncauses != 0) + if (ARRAY_LENGTH(causes) != 0) return (-1); return (0); } diff --git a/cmd-new-session.c b/cmd-new-session.c index 20ef8d65..462ffc6c 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -285,15 +285,15 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) * If there are still configuration file errors to display, put the new * session's current window into more mode and display them now. */ - if (cfg_finished && cfg_ncauses != 0) { + if (cfg_finished && !ARRAY_EMPTY(&cfg_causes)) { wp = s->curw->window->active; window_pane_set_mode(wp, &window_more_mode); - for (i = 0; i < cfg_ncauses; i++) { - window_more_add(wp, "%s", cfg_causes[i]); - xfree(cfg_causes[i]); + for (i = 0; i < ARRAY_LENGTH(&cfg_causes); i++) { + cause = ARRAY_ITEM(&cfg_causes, i); + window_more_add(wp, "%s", cause); + xfree(cause); } - xfree(cfg_causes); - cfg_ncauses = 0; + ARRAY_FREE(&cfg_causes); } return (!detached); /* 1 means don't tell command client to exit */ diff --git a/cmd-source-file.c b/cmd-source-file.c index 69a27e88..93a0800c 100644 --- a/cmd-source-file.c +++ b/cmd-source-file.c @@ -89,18 +89,18 @@ int cmd_source_file_exec(struct cmd *self, struct cmd_ctx *ctx) { struct cmd_source_file_data *data = self->data; - char **causes; - u_int i, ncauses; + struct causelist causes; + char *cause; + u_int i; - causes = NULL; - ncauses = 0; - - if (load_cfg(data->path, ctx, &ncauses, &causes) != 0) { - for (i = 0; i < ncauses; i++) { - ctx->print(ctx, "%s", causes[i]); - xfree(causes[i]); + ARRAY_INIT(&causes); + if (load_cfg(data->path, ctx, &causes) != 0) { + for (i = 0; i < ARRAY_LENGTH(&causes); i++) { + cause = ARRAY_ITEM(&causes, i); + ctx->print(ctx, "%s", cause); + xfree(cause); } - xfree(causes); + ARRAY_FREE(&causes); } return (0); diff --git a/server.c b/server.c index 999389cc..e2ca33b0 100644 --- a/server.c +++ b/server.c @@ -115,7 +115,7 @@ server_start(char *path) { struct window_pane *wp; int pair[2], retval; - char rpathbuf[MAXPATHLEN]; + char rpathbuf[MAXPATHLEN], *cause; struct timeval tv; u_int i; @@ -169,27 +169,27 @@ server_start(char *path) retval = 0; if (access(SYSTEM_CFG, R_OK) == 0) - load_cfg(SYSTEM_CFG, NULL, &cfg_ncauses, &cfg_causes); + load_cfg(SYSTEM_CFG, NULL, &cfg_causes); else if (errno != ENOENT) { - cfg_add_cause(&cfg_ncauses, &cfg_causes, - "%s: %s", strerror(errno), SYSTEM_CFG); + cfg_add_cause( + &cfg_causes, "%s: %s", strerror(errno), SYSTEM_CFG); } if (cfg_file != NULL) - load_cfg(cfg_file, NULL, &cfg_ncauses, &cfg_causes); + load_cfg(cfg_file, NULL, &cfg_causes); /* * If there is a session already, put the current window and pane into * more mode. */ - if (!ARRAY_EMPTY(&sessions) && cfg_ncauses != 0) { + if (!ARRAY_EMPTY(&sessions) && !ARRAY_EMPTY(&cfg_causes)) { wp = ARRAY_FIRST(&sessions)->curw->window->active; window_pane_set_mode(wp, &window_more_mode); - for (i = 0; i < cfg_ncauses; i++) { - window_more_add(wp, "%s", cfg_causes[i]); - xfree(cfg_causes[i]); + for (i = 0; i < ARRAY_LENGTH(&cfg_causes); i++) { + cause = ARRAY_ITEM(&cfg_causes, i); + window_more_add(wp, "%s", cause); + xfree(cause); } - xfree(cfg_causes); - cfg_ncauses = 0; + ARRAY_FREE(&cfg_causes); } cfg_finished = 1; diff --git a/tmux.h b/tmux.h index 2afaf3cc..df35f092 100644 --- a/tmux.h +++ b/tmux.h @@ -1244,6 +1244,9 @@ struct set_option_entry { const char **choices; }; +/* List of configuration causes. */ +ARRAY_DECL(causelist, char *); + /* tmux.c */ extern struct options global_options; extern struct options global_s_options; @@ -1262,10 +1265,9 @@ int areshell(const char *); /* cfg.c */ extern int cfg_finished; -extern char **cfg_causes; -extern u_int cfg_ncauses; -void printflike3 cfg_add_cause(u_int *, char ***, const char *, ...); -int load_cfg(const char *, struct cmd_ctx *, u_int *, char ***); +struct causelist cfg_causes; +void printflike2 cfg_add_cause(struct causelist *, const char *, ...); +int load_cfg(const char *, struct cmd_ctx *, struct causelist *); /* mode-key.c */ extern const struct mode_key_table mode_key_tables[]; From 2dc74f2e4d754b868286d1adc0e686d707be38fc Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 7 Feb 2010 20:33:27 +0000 Subject: [PATCH 0641/1180] next-layout is bound to Space not C-Space. --- tmux.1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tmux.1 b/tmux.1 index 360d53a2..377215eb 100644 --- a/tmux.1 +++ b/tmux.1 @@ -667,7 +667,7 @@ These may be selected with the command or cycled with .Ic next-layout (bound to -.Ql C-space +.Ql Space by default); once a layout is chosen, panes within it may be moved and resized as normal. .Pp From 11dedde511e2d4adb57027edcb9d823b8269c368 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 8 Feb 2010 00:14:38 +0000 Subject: [PATCH 0642/1180] Add an option to disable the smcup/rmcup alternate screen behaviour inside tmux. From clemens fischer. --- cmd-set-option.c | 1 + input.c | 6 ++++++ tmux.1 | 13 +++++++++++++ tmux.c | 1 + 4 files changed, 21 insertions(+) diff --git a/cmd-set-option.c b/cmd-set-option.c index 63e646e0..6658b90b 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -138,6 +138,7 @@ const struct set_option_entry set_session_option_table[] = { const struct set_option_entry set_window_option_table[] = { { "aggressive-resize", SET_OPTION_FLAG, 0, 0, NULL }, + { "alternate-screen", SET_OPTION_FLAG, 0, 0, NULL }, { "automatic-rename", SET_OPTION_FLAG, 0, 0, NULL }, { "clock-mode-colour", SET_OPTION_COLOUR, 0, 0, NULL }, { "clock-mode-style", diff --git a/input.c b/input.c index cfa42406..bf31413c 100644 --- a/input.c +++ b/input.c @@ -1148,6 +1148,7 @@ void input_handle_sequence_sm(struct input_ctx *ictx) { struct window_pane *wp = ictx->wp; + struct options *oo = &wp->window->options; struct screen *s = &wp->base; u_int sx, sy; uint16_t n; @@ -1178,6 +1179,8 @@ input_handle_sequence_sm(struct input_ctx *ictx) case 1049: if (wp->saved_grid != NULL) break; + if (!options_get_number(oo, "alternate-screen")) + break; sx = screen_size_x(s); sy = screen_size_y(s); @@ -1224,6 +1227,7 @@ void input_handle_sequence_rm(struct input_ctx *ictx) { struct window_pane *wp = ictx->wp; + struct options *oo = &wp->window->options; struct screen *s = &wp->base; u_int sx, sy; uint16_t n; @@ -1254,6 +1258,8 @@ input_handle_sequence_rm(struct input_ctx *ictx) case 1049: if (wp->saved_grid == NULL) break; + if (!options_get_number(oo, "alternate-screen")) + break; sx = screen_size_x(s); sy = screen_size_y(s); diff --git a/tmux.1 b/tmux.1 index 377215eb..e01445e0 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1898,6 +1898,19 @@ command. Duplicate input to any pane to all other panes in the same window, except for panes that are not in output mode. .Pp +.It Xo Ic alternate-screen +.Op Ic on | off +.Xc +This option configures whether programs running inside +.Nm +may use the terminal alternate screen feature, which allows the +.Em smcup +and +.Em rmcup +.Xr terminfo 5 +capabilities to be issued to preserve the existing window content on start and +restore it on exit. +.Pp .It Xo Ic utf8 .Op Ic on | off .Xc diff --git a/tmux.c b/tmux.c index a582b951..8671e323 100644 --- a/tmux.c +++ b/tmux.c @@ -395,6 +395,7 @@ main(int argc, char **argv) options_init(&global_w_options, NULL); wo = &global_w_options; options_set_number(wo, "aggressive-resize", 0); + options_set_number(wo, "alternate-screen", 1); options_set_number(wo, "automatic-rename", 1); options_set_number(wo, "clock-mode-colour", 4); options_set_number(wo, "clock-mode-style", 1); From f42905707292bf0afec56ddcb30ed04969664be6 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 10 Feb 2010 19:17:27 +0000 Subject: [PATCH 0643/1180] Clarify default status-right, from Seth Wright. --- tmux.1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tmux.1 b/tmux.1 index e01445e0..bf744479 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1663,7 +1663,8 @@ The default is 10. Display .Ar string to the right of the status bar. -By default, the date and time will be shown. +By default, the current window title in double quotes, the date and the time +are shown. As with .Ic status-left , .Ar string From 44ded35d5da3d958cbb3bb92e9c9b4be9d078d4f Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 11 Feb 2010 20:39:40 +0000 Subject: [PATCH 0644/1180] Add "N" key to search the opposite way from the last search (reverse of "n"), from Micah Cowan. --- mode-key.c | 3 +++ tmux.1 | 1 + tmux.h | 1 + window-copy.c | 15 ++++++++++++--- 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/mode-key.c b/mode-key.c index 1a654fb2..0d58f3d6 100644 --- a/mode-key.c +++ b/mode-key.c @@ -104,6 +104,7 @@ struct mode_key_cmdstr mode_key_cmdstr_copy[] = { { MODEKEYCOPY_SCROLLUP, "scroll-up" }, { MODEKEYCOPY_SEARCHAGAIN, "search-again" }, { MODEKEYCOPY_SEARCHDOWN, "search-forward" }, + { MODEKEYCOPY_SEARCHREVERSE, "search-reverse" }, { MODEKEYCOPY_SEARCHUP, "search-backward" }, { MODEKEYCOPY_STARTOFLINE, "start-of-line" }, { MODEKEYCOPY_STARTSELECTION, "begin-selection" }, @@ -187,6 +188,7 @@ const struct mode_key_entry mode_key_vi_copy[] = { { 'K', 0, MODEKEYCOPY_SCROLLUP }, { 'L', 0, MODEKEYCOPY_BOTTOMLINE }, { 'M', 0, MODEKEYCOPY_MIDDLELINE }, + { 'N', 0, MODEKEYCOPY_SEARCHREVERSE }, { 'W', 0, MODEKEYCOPY_NEXTSPACE }, { '\002' /* C-b */, 0, MODEKEYCOPY_PREVIOUSPAGE }, { '\003' /* C-c */, 0, MODEKEYCOPY_CANCEL }, @@ -296,6 +298,7 @@ const struct mode_key_entry mode_key_emacs_copy[] = { { '\026' /* C-v */, 0, MODEKEYCOPY_NEXTPAGE }, { '\027' /* C-w */, 0, MODEKEYCOPY_COPYSELECTION }, { '\033' /* Escape */, 0, MODEKEYCOPY_CANCEL }, + { 'N', 0, MODEKEYCOPY_SEARCHREVERSE }, { 'b' | KEYC_ESCAPE, 0, MODEKEYCOPY_PREVIOUSWORD }, { 'f' | KEYC_ESCAPE, 0, MODEKEYCOPY_NEXTWORDEND }, { 'g', 0, MODEKEYCOPY_GOTOLINE }, diff --git a/tmux.1 b/tmux.1 index bf744479..981768c0 100644 --- a/tmux.1 +++ b/tmux.1 @@ -572,6 +572,7 @@ The following keys are supported as appropriate for the mode: .It Li "Scroll down" Ta "C-Down or C-e" Ta "C-Down" .It Li "Scroll up" Ta "C-Up or C-y" Ta "C-Up" .It Li "Search again" Ta "n" Ta "n" +.It Li "Search again in reverse" Ta "N" Ta "N" .It Li "Search backward" Ta "?" Ta "C-r" .It Li "Search forward" Ta "/" Ta "C-s" .It Li "Start of line" Ta "0" Ta "C-a" diff --git a/tmux.h b/tmux.h index df35f092..02712651 100644 --- a/tmux.h +++ b/tmux.h @@ -475,6 +475,7 @@ enum mode_key_cmd { MODEKEYCOPY_SCROLLUP, MODEKEYCOPY_SEARCHAGAIN, MODEKEYCOPY_SEARCHDOWN, + MODEKEYCOPY_SEARCHREVERSE, MODEKEYCOPY_SEARCHUP, MODEKEYCOPY_STARTOFLINE, MODEKEYCOPY_STARTSELECTION, diff --git a/window-copy.c b/window-copy.c index 32f1a71c..3bc697cf 100644 --- a/window-copy.c +++ b/window-copy.c @@ -224,6 +224,7 @@ window_copy_key(struct window_pane *wp, struct client *c, int key) struct screen *s = &data->screen; u_int n; int keys; + enum mode_key_cmd cmd; if (data->inputtype != WINDOW_COPY_OFF) { if (window_copy_key_input(wp, key) != 0) @@ -231,7 +232,8 @@ window_copy_key(struct window_pane *wp, struct client *c, int key) return; } - switch (mode_key_lookup(&data->mdata, key)) { + cmd = mode_key_lookup(&data->mdata, key); + switch (cmd) { case MODEKEYCOPY_CANCEL: window_pane_reset_mode(wp); break; @@ -367,15 +369,22 @@ window_copy_key(struct window_pane *wp, struct client *c, int key) data->inputprompt = "Search Down"; goto input_on; case MODEKEYCOPY_SEARCHAGAIN: + case MODEKEYCOPY_SEARCHREVERSE: switch (data->searchtype) { case WINDOW_COPY_OFF: case WINDOW_COPY_GOTOLINE: break; case WINDOW_COPY_SEARCHUP: - window_copy_search_up(wp, data->searchstr); + if (cmd == MODEKEYCOPY_SEARCHAGAIN) + window_copy_search_up(wp, data->searchstr); + else + window_copy_search_down(wp, data->searchstr); break; case WINDOW_COPY_SEARCHDOWN: - window_copy_search_down(wp, data->searchstr); + if (cmd == MODEKEYCOPY_SEARCHAGAIN) + window_copy_search_down(wp, data->searchstr); + else + window_copy_search_up(wp, data->searchstr); break; } break; From d285f7fd4d3d6a2000b5ef2ba0e8f098bb7e77d8 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 17 Feb 2010 20:58:24 +0000 Subject: [PATCH 0645/1180] Don't strip add newline if only copying part of wrapped line. Problem spotted by and fix from Micah Cowan. --- window-copy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/window-copy.c b/window-copy.c index 3bc697cf..40897602 100644 --- a/window-copy.c +++ b/window-copy.c @@ -1038,7 +1038,7 @@ window_copy_copy_line(struct window_pane *wp, } /* Only add a newline if the line wasn't wrapped. */ - if (!wrapped) { + if (!wrapped || ex != xx) { *buf = xrealloc(*buf, 1, (*off) + 1); (*buf)[(*off)++] = '\n'; } From c164f5886f3fd86a75fe76a65dc6139c419c79c2 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 17 Feb 2010 21:12:06 +0000 Subject: [PATCH 0646/1180] Man page additions/improvements, thanks to Robin Lee Powell. --- tmux.1 | 138 ++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 108 insertions(+), 30 deletions(-) diff --git a/tmux.1 b/tmux.1 index 981768c0..bbb66dc7 100644 --- a/tmux.1 +++ b/tmux.1 @@ -111,6 +111,11 @@ If necessary, the server will be started to retrieve the .Ic default-shell option. +This option is for compatibility with +.Xr sh 1 +when +.Nm +is used as a login shell. .It Fl f Ar file Specify an alternative configuration file. By default, @@ -342,6 +347,32 @@ One of the strings .Em bottom-right may be used instead of a pane index. .Pp +.Ar shell-command +arguments are +.Xr sh 1 +commands. +These must be passed as a single item, which typically means quoting them, for +example: +.Bd -literal -offset indent +new-window 'vi /etc/passwd' +.Ed +.Pp +.Ar command +.Op Ar arguments +refers to a +.Nm +command, passed with the command and arguments separately, for example: +.Bd -literal -offset indent +bind-key F1 set-window-option force-width 81 +.Ed +.Pp +Or if using +.Xr sh 1 : +.Pp +.Bd -literal -offset indent +$ tmux bind-key F1 set-window-option force-width 81 +.Ed +.Pp Multiple commands may be specified together as part of a .Em command sequence . Each command should be separated by spaces and a semicolon; @@ -350,7 +381,9 @@ A literal semicolon may be included by escaping it with a backslash (for example, when specifying a command sequence to .Ic bind-key ) . .Pp -Examples include: +Example +.Nm +commands include: .Bd -literal -offset indent refresh-client -t/dev/ttyp2 @@ -360,8 +393,40 @@ set-window-option -t:0 monitor-activity on new-window ; split-window -d .Ed +.Pp +Or from +.Xr sh 1 : +.Pp +.Bd -literal -offset indent +$ tmux kill-window -t :1 + +$ tmux new-window \\; split-window -d + +$ tmux new-session -d 'vi /etc/passwd' \\; split-window -d \\; attach +.Ed .Sh CLIENTS AND SESSIONS -The following commands are available: +The +.Nm +server manages clients, sessions, windows and panes. +Clients are attached to sessions to interact with them, either +when they are created with the +.Ic new-session +command, or later with the +.Ic attach-session +command. +Each session has one of more windows +.Em linked +into it. +Windows may be linked to multiple sessions and are made up of one or +more panes, +each of which contains a pseudo terminal. +Commands for creating, linking and otherwise manipulating windows +are covered +in the +.Sx WINDOWS AND PANES +section. +.Pp +The following commands are available to manage clients and sessions: .Bl -tag -width Ds .It Xo Ic attach-session .Op Fl dr @@ -428,18 +493,19 @@ Lock all clients attached to .Op Fl n Ar window-name .Op Fl s Ar session-name .Op Fl t Ar target-session -.Op Ar command +.Op Ar shell-command .Xc .D1 (alias: Ic new ) Create a new session with name .Ar session-name . +.Pp The new session is attached to the current terminal unless .Fl d is given. .Ar window-name and -.Ar command -are the name of and command to execute in the initial window. +.Ar shell-command +are the name of and shell command to execute in the initial window. .Pp If run from a terminal, any .Xr termios 4 @@ -460,7 +526,7 @@ either session may be killed without affecting the other. Giving .Fl n or -.Ar command +.Ar shell-command are invalid if .Fl t is used. @@ -886,7 +952,7 @@ is moved to .Op Fl dk .Op Fl n Ar window-name .Op Fl t Ar target-window -.Op Ar command +.Op Ar shell-command .Xc .D1 (alias: Ic neww ) Create a new window. @@ -898,11 +964,18 @@ represents the window to be created; if the target already exists an error is shown, unless the .Fl k flag is used, in which case it is destroyed. -.Ar command +.Ar shell-command is the command to execute. If -.Ar command -is not specified, the default command is used. +.Ar shell-command +is not specified, the value of the +.Ic default-command +option is used. +.Pp +When the shell command completes, the window closes. +See the +.Ic remain-on-exit +option to change this behaviour. .Pp The .Ev TERM @@ -930,7 +1003,7 @@ is used, move to the next window with a bell, activity or content alert. .It Xo Ic pipe-pane .Op Fl o .Op Fl t Ar target-pane -.Op Ar command +.Op Ar shell-command .Xc .D1 (alias: Ic pipep ) Pipe any output sent by the program in @@ -938,10 +1011,10 @@ Pipe any output sent by the program in to a shell command. A pane may only be piped to one command at a time, any existing pipe is closed before -.Ar command +.Ar shell-command is executed. If no -.Ar command +.Ar shell-command is given, the current pipe (if any) is closed. .Pp The @@ -989,14 +1062,14 @@ is given in lines or cells (the default is 1). .It Xo Ic respawn-window .Op Fl k .Op Fl t Ar target-window -.Op Ar command +.Op Ar shell-command .Xc .D1 (alias: Ic respawnw ) -Reactive a window in which the command has exited (see the +Reactivate a window in which the command has exited (see the .Ic remain-on-exit window option). If -.Ar command +.Ar shell-command is not given, the command used when the window was created is executed. The window must be already inactive, unless .Fl k @@ -1035,7 +1108,7 @@ Select the window at .Ar size | .Fl p Ar percentage Oc .Op Fl t Ar target-pane -.Op Ar command +.Op Ar shell-command .Xc .D1 (alias: splitw ) Create a new pane by splitting @@ -1376,10 +1449,10 @@ means only bell in windows other than the current window are ignored. Set the number of buffers kept for each session; as new buffers are added to the top of the stack, old ones are removed from the bottom if necessary to maintain this maximum length. -.It Ic default-command Ar command +.It Ic default-command Ar shell-command Set the command used for new windows (if not specified when the window is created) to -.Ar command , +.Ar shell-command , which may be any .Xr sh 1 command. @@ -1450,7 +1523,7 @@ seconds of inactivity, or the entire server (all sessions) if the .Ic lock-server option is set. The default is not to lock (set to 0). -.It Ic lock-command Ar command +.It Ic lock-command Ar shell-command Command to run when locking each client. The default is to run .Xr lock 1 @@ -1545,6 +1618,13 @@ command. Set the .Ic remain-on-exit window option for any windows first created in this session. +When this option is true, windows in which the running program has +exited do not close, instead remaining open but inactivate. +Use the +.Ic respawn-window +command to reactivate such a window, or the +.Ic kill-window +command to destroy it. .It Xo Ic set-titles .Op Ic on | off .Xc @@ -1601,7 +1681,7 @@ By default, the session name is shown. may contain any of the following special character sequences: .Bl -column "Character pair" "Replaced with" -offset indent .It Sy "Character pair" Ta Sy "Replaced with" -.It Li "#(command)" Ta "First line of command's output" +.It Li "#(shell-command)" Ta "First line of the command's output" .It Li "#[attributes]" Ta "Colour or attribute change" .It Li "#H" Ta "Hostname of local host" .It Li "#F" Ta "Current window flag" @@ -1613,9 +1693,9 @@ may contain any of the following special character sequences: .It Li "##" Ta "A literal" Ql # .El .Pp -The #(command) form executes -.Ql command -as a shell command and inserts the first line of its output. +The #(shell-command) form executes +.Ql shell-command +and inserts the first line of its output. Note that shell commands are only executed once at the interval specified by the .Ic status-interval @@ -2295,15 +2375,13 @@ returns success. Lock each client individually by running the command specified by the .Ic lock-command option. -.It Ic run-shell Ar command +.It Ic run-shell Ar shell-command .D1 (alias: Ic run ) Execute -.Ar command +.Ar shell-command in the background without creating a window. -After the command finishes, any output to stdout is displayed in output mode. -If -.Ar command -doesn't return success, the exit status is also displayed. +After it finishes, any output to stdout is displayed in output mode. +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. From a61b8a2033cd53281a7226affb97ddcb8b6689da Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 17 Feb 2010 21:27:18 +0000 Subject: [PATCH 0647/1180] Make next-word stop at beginning of word even if it is at the start of the line, from Micah Cowan. --- window-copy.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/window-copy.c b/window-copy.c index 40897602..1b2d1ada 100644 --- a/window-copy.c +++ b/window-copy.c @@ -1263,8 +1263,8 @@ window_copy_cursor_next_word(struct window_pane *wp, const char *separators) py = screen_hsize(base_s) + data->cy - data->oy; xx = window_copy_find_length(wp, py); - } - px++; + } else + px++; } window_copy_update_cursor(wp, px, data->cy); @@ -1295,8 +1295,8 @@ window_copy_cursor_next_word_end(struct window_pane *wp, const char *separators) py = screen_hsize(base_s) + data->cy - data->oy; xx = window_copy_find_length(wp, py); - } - px++; + } else + px++; } /* Find the end of this word. */ @@ -1417,4 +1417,3 @@ window_copy_rectangle_toggle(struct window_pane *wp) window_copy_update_selection(wp); window_copy_redraw_screen(wp); } - From 3a89d1ef7f4e9da3b3606df9385b79a77322963e Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 19 Feb 2010 00:03:21 +0000 Subject: [PATCH 0648/1180] copy mode uses the real screen as backing and if it is updated while copying, strange things can happen. So, freeze reading from the pty while in copy mode. --- server-window.c | 4 +++- tmux.h | 1 + window-copy.c | 6 ++++++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/server-window.c b/server-window.c index 048077e0..acac83c0 100644 --- a/server-window.c +++ b/server-window.c @@ -69,7 +69,9 @@ server_window_loop(void) continue; TAILQ_FOREACH(wp, &w->panes, entry) { - if (wp->fd != -1) { + if (wp->fd == -1) + continue; + if (!(wp->flags & PANE_FREEZE)) { if (server_window_backoff(wp)) bufferevent_disable(wp->event, EV_READ); else diff --git a/tmux.h b/tmux.h index 02712651..ac398f04 100644 --- a/tmux.h +++ b/tmux.h @@ -787,6 +787,7 @@ struct window_pane { int flags; #define PANE_REDRAW 0x1 +#define PANE_FREEZE 0x2 char *cmd; char *shell; diff --git a/window-copy.c b/window-copy.c index 1b2d1ada..b465f21b 100644 --- a/window-copy.c +++ b/window-copy.c @@ -138,6 +138,9 @@ window_copy_init(struct window_pane *wp) data->searchtype = WINDOW_COPY_OFF; data->searchstr = NULL; + wp->flags |= PANE_FREEZE; + bufferevent_disable(wp->event, EV_READ|EV_WRITE); + s = &data->screen; screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0); if (options_get_number(&wp->window->options, "mode-mouse")) @@ -166,6 +169,9 @@ window_copy_free(struct window_pane *wp) { struct window_copy_mode_data *data = wp->modedata; + wp->flags &= ~PANE_FREEZE; + bufferevent_enable(wp->event, EV_READ|EV_WRITE); + if (data->searchstr != NULL) xfree(data->searchstr); xfree(data->inputstr); From 24634b62816939c3fa7706e60dc2d215e62945c5 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 19 Feb 2010 17:14:23 +0000 Subject: [PATCH 0649/1180] have_arg matches buf so it is no longer necessary, spotted by Tim van der Molen. --- cmd-string.c | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/cmd-string.c b/cmd-string.c index a5dabb56..2a5e2b24 100644 --- a/cmd-string.c +++ b/cmd-string.c @@ -61,7 +61,7 @@ int cmd_string_parse(const char *s, struct cmd_list **cmdlist, char **cause) { size_t p; - int ch, i, argc, rval, have_arg; + int ch, i, argc, rval; char **argv, *buf, *t; const char *whitespace, *equals; size_t len; @@ -72,8 +72,6 @@ cmd_string_parse(const char *s, struct cmd_list **cmdlist, char **cause) buf = NULL; len = 0; - have_arg = 0; - *cause = NULL; *cmdlist = NULL; @@ -90,8 +88,6 @@ cmd_string_parse(const char *s, struct cmd_list **cmdlist, char **cause) strlcpy(buf + len, t, strlen(t) + 1); len += strlen(t); xfree(t); - - have_arg = 1; break; case '"': if ((t = cmd_string_string(s, &p, '"', 1)) == NULL) @@ -100,8 +96,6 @@ cmd_string_parse(const char *s, struct cmd_list **cmdlist, char **cause) strlcpy(buf + len, t, strlen(t) + 1); len += strlen(t); xfree(t); - - have_arg = 1; break; case '$': if ((t = cmd_string_variable(s, &p)) == NULL) @@ -110,8 +104,6 @@ cmd_string_parse(const char *s, struct cmd_list **cmdlist, char **cause) strlcpy(buf + len, t, strlen(t) + 1); len += strlen(t); xfree(t); - - have_arg = 1; break; case '#': /* Comment: discard rest of line. */ @@ -121,7 +113,7 @@ cmd_string_parse(const char *s, struct cmd_list **cmdlist, char **cause) case EOF: case ' ': case '\t': - if (have_arg) { + if (buf != NULL) { buf = xrealloc(buf, 1, len + 1); buf[len] = '\0'; @@ -130,8 +122,6 @@ cmd_string_parse(const char *s, struct cmd_list **cmdlist, char **cause) buf = NULL; len = 0; - - have_arg = 0; } if (ch != EOF) @@ -156,7 +146,7 @@ cmd_string_parse(const char *s, struct cmd_list **cmdlist, char **cause) rval = 0; goto out; case '~': - if (have_arg == 0) { + if (buf == NULL) { if ((t = cmd_string_expand_tilde(s, &p)) == NULL) goto error; buf = xrealloc(buf, 1, len + strlen(t) + 1); @@ -172,8 +162,6 @@ cmd_string_parse(const char *s, struct cmd_list **cmdlist, char **cause) buf = xrealloc(buf, 1, len + 1); buf[len++] = ch; - - have_arg = 1; break; } } From 25211020bf9d128e789b282e1c7ce205cbe46eaf Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 22 Feb 2010 20:19:16 +0000 Subject: [PATCH 0650/1180] Display -t argument to new-session, from Tiago Cunha. --- cmd-new-session.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cmd-new-session.c b/cmd-new-session.c index 462ffc6c..3dc7c7b3 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -324,10 +324,12 @@ cmd_new_session_print(struct cmd *self, char *buf, size_t len) return (off); if (off < len && data->flag_detached) off += xsnprintf(buf + off, len - off, " -d"); - if (off < len && data->newname != NULL) - off += cmd_prarg(buf + off, len - off, " -s ", data->newname); if (off < len && data->winname != NULL) off += cmd_prarg(buf + off, len - off, " -n ", data->winname); + if (off < len && data->newname != NULL) + off += cmd_prarg(buf + off, len - off, " -s ", data->newname); + if (off < len && data->target != NULL) + off += cmd_prarg(buf + off, len - off, " -t ", data->target); if (off < len && data->cmd != NULL) off += cmd_prarg(buf + off, len - off, " ", data->cmd); return (off); From 73b8c3ebf30592b4c3509f79361adee78a0c40e3 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 22 Feb 2010 20:28:21 +0000 Subject: [PATCH 0651/1180] Another copy mode fix from Micah Cowan: in rectangle copy mode, the cursor should not wrap at the end of the text on the line but should be allowed to move freely. --- window-copy.c | 53 +++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 41 insertions(+), 12 deletions(-) diff --git a/window-copy.c b/window-copy.c index b465f21b..0f956bd0 100644 --- a/window-copy.c +++ b/window-copy.c @@ -52,6 +52,7 @@ void window_copy_update_cursor(struct window_pane *, u_int, u_int); void window_copy_start_selection(struct window_pane *); int window_copy_update_selection(struct window_pane *); void window_copy_copy_selection(struct window_pane *, struct client *); +void window_copy_clear_selection(struct window_pane *); void window_copy_copy_line( struct window_pane *, char **, size_t *, u_int, u_int, u_int); int window_copy_in_set(struct window_pane *, u_int, u_int, const char *); @@ -213,7 +214,7 @@ window_copy_resize(struct window_pane *wp, u_int sx, u_int sy) if (data->cx > sx) data->cx = sx; - screen_clear_selection(&data->screen); + window_copy_clear_selection(wp); screen_write_start(&ctx, NULL, s); window_copy_write_lines(wp, &ctx, 0, screen_size_y(s) - 1); @@ -330,7 +331,7 @@ window_copy_key(struct window_pane *wp, struct client *c, int key) window_copy_redraw_screen(wp); break; case MODEKEYCOPY_CLEARSELECTION: - screen_clear_selection(&data->screen); + window_copy_clear_selection(wp); window_copy_redraw_screen(wp); break; case MODEKEYCOPY_COPYSELECTION: @@ -1050,6 +1051,20 @@ window_copy_copy_line(struct window_pane *wp, } } +void +window_copy_clear_selection(struct window_pane *wp) +{ + struct window_copy_mode_data *data = wp->modedata; + u_int px, py; + + screen_clear_selection(&data->screen); + + py = screen_hsize(&wp->base) + data->cy - data->oy; + px = window_copy_find_length(wp, py); + if (data->cx > px) + window_copy_update_cursor(wp, px, data->cy); +} + int window_copy_in_set(struct window_pane *wp, u_int px, u_int py, const char *set) { @@ -1159,8 +1174,12 @@ window_copy_cursor_right(struct window_pane *wp) struct window_copy_mode_data *data = wp->modedata; u_int px, py; - py = screen_hsize(&wp->base) + data->cy - data->oy; - px = window_copy_find_length(wp, py); + if (data->screen.sel.flag && data->rectflag) + px = screen_size_x(&data->screen); + else { + py = screen_hsize(&wp->base) + data->cy - data->oy; + px = window_copy_find_length(wp, py); + } if (data->cx >= px) { window_copy_cursor_start_of_line(wp); @@ -1205,10 +1224,12 @@ window_copy_cursor_up(struct window_pane *wp, int scroll_only) } } - py = screen_hsize(&wp->base) + data->cy - data->oy; - px = window_copy_find_length(wp, py); - if (data->cx >= data->lastsx || data->cx > px) - window_copy_cursor_end_of_line(wp); + if (!data->screen.sel.flag || !data->rectflag) { + py = screen_hsize(&wp->base) + data->cy - data->oy; + px = window_copy_find_length(wp, py); + if (data->cx >= data->lastsx || data->cx > px) + window_copy_cursor_end_of_line(wp); + } } void @@ -1236,10 +1257,12 @@ window_copy_cursor_down(struct window_pane *wp, int scroll_only) window_copy_redraw_lines(wp, data->cy - 1, 2); } - py = screen_hsize(&wp->base) + data->cy - data->oy; - px = window_copy_find_length(wp, py); - if (data->cx >= data->lastsx || data->cx > px) - window_copy_cursor_end_of_line(wp); + if (!data->screen.sel.flag || !data->rectflag) { + py = screen_hsize(&wp->base) + data->cy - data->oy; + px = window_copy_find_length(wp, py); + if (data->cx >= data->lastsx || data->cx > px) + window_copy_cursor_end_of_line(wp); + } } void @@ -1417,9 +1440,15 @@ void window_copy_rectangle_toggle(struct window_pane *wp) { struct window_copy_mode_data *data = wp->modedata; + u_int px, py; data->rectflag = !data->rectflag; + py = screen_hsize(&wp->base) + data->cy - data->oy; + px = window_copy_find_length(wp, py); + if (data->cx > px) + window_copy_update_cursor(wp, px, data->cy); + window_copy_update_selection(wp); window_copy_redraw_screen(wp); } From efbcf8747da18d62ed83d34d5eda1ba56d658f82 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 22 Feb 2010 20:33:12 +0000 Subject: [PATCH 0652/1180] In load-buffer, read until EOF rather than using stat() and reading a fixed size. Allows use of FIFOs and whatnot. From Tiago Cunha, idea from Fulvio Ciriaco. --- cmd-load-buffer.c | 45 ++++++++++++++++++--------------------------- 1 file changed, 18 insertions(+), 27 deletions(-) diff --git a/cmd-load-buffer.c b/cmd-load-buffer.c index b6386b83..1fe95818 100644 --- a/cmd-load-buffer.c +++ b/cmd-load-buffer.c @@ -16,13 +16,10 @@ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include -#include - #include +#include #include #include -#include #include "tmux.h" @@ -48,11 +45,11 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) { struct cmd_buffer_data *data = self->data; struct session *s; - struct stat sb; FILE *f; - char *pdata = NULL; + char *pdata, *new_pdata; size_t psize; u_int limit; + int ch; if ((s = cmd_find_session(ctx, data->target)) == NULL) return (-1); @@ -62,29 +59,23 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) return (-1); } - if (fstat(fileno(f), &sb) < 0) { - ctx->error(ctx, "%s: %s", data->arg, strerror(errno)); - goto error; - } - if (sb.st_size <= 0 || (uintmax_t) sb.st_size > SIZE_MAX) { - ctx->error(ctx, "%s: file empty or too large", data->arg); - goto error; - } - psize = (size_t) sb.st_size; - - /* - * We don't want to die due to memory exhaustion, hence xmalloc can't - * be used here. - */ - if ((pdata = malloc(psize)) == NULL) { - ctx->error(ctx, "malloc error: %s", strerror(errno)); - goto error; - } - - if (fread(pdata, 1, psize, f) != psize) { - ctx->error(ctx, "%s: fread error", data->arg); + pdata = NULL; + psize = 0; + while ((ch = getc(f)) != EOF) { + /* Do not let the server die due to memory exhaustion. */ + if ((new_pdata = realloc(pdata, psize + 2)) == NULL) { + ctx->error(ctx, "realloc error: %s", strerror(errno)); + goto error; + } + pdata = new_pdata; + pdata[psize++] = ch; + } + if (ferror(f)) { + ctx->error(ctx, "%s: read error", data->arg); goto error; } + if (pdata != NULL) + pdata[psize] = '\0'; fclose(f); From 6767072c9d4774e8e44d7222c01ecee08a35dad8 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 22 Feb 2010 20:41:16 +0000 Subject: [PATCH 0653/1180] Option to set the characters considered word separators in copy mode, from Micah Cowan. --- cmd-set-option.c | 1 + tmux.1 | 15 +++++++-- tmux.c | 1 + window-copy.c | 88 +++++++++++++++++++++++++++++------------------- 4 files changed, 67 insertions(+), 38 deletions(-) diff --git a/cmd-set-option.c b/cmd-set-option.c index 6658b90b..90b6d611 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -165,6 +165,7 @@ const struct set_option_entry set_window_option_table[] = { { "window-status-current-format", SET_OPTION_STRING, 0, 0, NULL }, { "window-status-fg", SET_OPTION_COLOUR, 0, 0, NULL }, { "window-status-format", SET_OPTION_STRING, 0, 0, NULL }, + { "word-separators", SET_OPTION_STRING, 0, 0, NULL }, { "xterm-keys", SET_OPTION_FLAG, 0, 0, NULL }, { NULL, 0, 0, 0, NULL } }; diff --git a/tmux.1 b/tmux.1 index bbb66dc7..348c2b3a 100644 --- a/tmux.1 +++ b/tmux.1 @@ -649,11 +649,13 @@ The following keys are supported as appropriate for the mode: .Pp The next and previous word keys use space and the .Ql - , -.Ql _ , -.Ql \&" +.Ql _ and .Ql @ -characters as word delimiters. +characters as word delimiters by default, but this can be adjusted by +setting the +.Em word-separators +window option. Next word moves to the start of the next word, next word end to the end of the next word and previous word to the start of the previous word. The three next and previous space keys work similarly but use a space alone as @@ -2031,6 +2033,13 @@ Like .Ar window-status-format , but is the format used when the window is the current window. .Pp +.It Ic word-separators Ar string +Sets the window's conception of what characters are considered word +separators, for the purposes of the next and previous word commands in +copy mode. +The default is +.Ql \ -_@ . +.Pp .It Xo Ic xterm-keys .Op Ic on | off .Xc diff --git a/tmux.c b/tmux.c index 8671e323..4f0a9090 100644 --- a/tmux.c +++ b/tmux.c @@ -418,6 +418,7 @@ main(int argc, char **argv) options_set_number(wo, "window-status-fg", 8); options_set_string(wo, "window-status-format", "#I:#W#F"); options_set_string(wo, "window-status-current-format", "#I:#W#F"); + options_set_string(wo, "word-separators", " -_@"); options_set_number(wo, "xterm-keys", 0); options_set_number(wo, "remain-on-exit", 0); options_set_number(wo, "synchronize-panes", 0); diff --git a/window-copy.c b/window-copy.c index 0f956bd0..82ae9a2b 100644 --- a/window-copy.c +++ b/window-copy.c @@ -226,7 +226,7 @@ window_copy_resize(struct window_pane *wp, u_int sx, u_int sy) void window_copy_key(struct window_pane *wp, struct client *c, int key) { - const char *word_separators = " -_@"; + const char *word_separators; struct window_copy_mode_data *data = wp->modedata; struct screen *s = &data->screen; u_int n; @@ -356,15 +356,21 @@ window_copy_key(struct window_pane *wp, struct client *c, int key) window_copy_cursor_next_word_end(wp, " "); break; case MODEKEYCOPY_NEXTWORD: + word_separators = + options_get_string(&wp->window->options, "word-separators"); window_copy_cursor_next_word(wp, word_separators); break; case MODEKEYCOPY_NEXTWORDEND: + word_separators = + options_get_string(&wp->window->options, "word-separators"); window_copy_cursor_next_word_end(wp, word_separators); break; case MODEKEYCOPY_PREVIOUSSPACE: window_copy_cursor_previous_word(wp, " "); break; case MODEKEYCOPY_PREVIOUSWORD: + word_separators = + options_get_string(&wp->window->options, "word-separators"); window_copy_cursor_previous_word(wp, word_separators); break; case MODEKEYCOPY_SEARCHUP: @@ -1271,30 +1277,36 @@ window_copy_cursor_next_word(struct window_pane *wp, const char *separators) struct window_copy_mode_data *data = wp->modedata; struct screen *base_s = &wp->base; u_int px, py, xx, yy; + int expected = 0; px = data->cx; py = screen_hsize(base_s) + data->cy - data->oy; xx = window_copy_find_length(wp, py); yy = screen_hsize(base_s) + screen_size_y(base_s) - 1; - /* Are we in a word? Skip it! */ - while (!window_copy_in_set(wp, px, py, separators)) - px++; + /* + * First skip past any nonword characters and then any word characters. + * + * expected is initially set to 0 for the former and then 1 for the + * latter. + */ + do { + while (px > xx || + window_copy_in_set(wp, px, py, separators) == expected) { + /* Move down if we're past the end of the line. */ + if (px > xx) { + if (py == yy) + return; + window_copy_cursor_down(wp, 0); + px = 0; - /* Find the start of a word. */ - while (px > xx || window_copy_in_set(wp, px, py, separators)) { - /* Past the end of the line? Nothing but spaces. */ - if (px > xx) { - if (py == yy) - return; - window_copy_cursor_down(wp, 0); - px = 0; - - py = screen_hsize(base_s) + data->cy - data->oy; - xx = window_copy_find_length(wp, py); - } else - px++; - } + py = screen_hsize(base_s) + data->cy - data->oy; + xx = window_copy_find_length(wp, py); + } else + px++; + } + expected = !expected; + } while (expected == 1); window_copy_update_cursor(wp, px, data->cy); if (window_copy_update_selection(wp)) @@ -1307,30 +1319,36 @@ window_copy_cursor_next_word_end(struct window_pane *wp, const char *separators) struct window_copy_mode_data *data = wp->modedata; struct screen *base_s = &wp->base; u_int px, py, xx, yy; + int expected = 1; px = data->cx; py = screen_hsize(base_s) + data->cy - data->oy; xx = window_copy_find_length(wp, py); yy = screen_hsize(base_s) + screen_size_y(base_s) - 1; - /* Are we on spaces? Skip 'em! */ - while (px > xx || window_copy_in_set(wp, px, py, separators)) { - /* Nothing but spaces past the end of the line, so move down. */ - if (px > xx) { - if (py == yy) - return; - window_copy_cursor_down(wp, 0); - px = 0; + /* + * First skip past any word characters, then any nonword characters. + * + * expected is initially set to 1 for the former and then 0 for the + * latter. + */ + do { + while (px > xx || + window_copy_in_set(wp, px, py, separators) == expected) { + /* Move down if we're past the end of the line. */ + if (px > xx) { + if (py == yy) + return; + window_copy_cursor_down(wp, 0); + px = 0; - py = screen_hsize(base_s) + data->cy - data->oy; - xx = window_copy_find_length(wp, py); - } else - px++; - } - - /* Find the end of this word. */ - while (!window_copy_in_set(wp, px, py, separators)) - px++; + py = screen_hsize(base_s) + data->cy - data->oy; + xx = window_copy_find_length(wp, py); + } else + px++; + } + expected = !expected; + } while (expected == 0); window_copy_update_cursor(wp, px, data->cy); if (window_copy_update_selection(wp)) From f1dd95650b6a193498b2a61694c57fb232ea41bd Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 24 Feb 2010 19:08:39 +0000 Subject: [PATCH 0654/1180] Don't set the terminal to nonblocking on detach until we have finished with it entirely. --- tty.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tty.c b/tty.c index 02ceb54e..52d3803a 100644 --- a/tty.c +++ b/tty.c @@ -213,10 +213,6 @@ tty_stop_tty(struct tty *tty) * because the fd is invalid. Things like ssh -t can easily leave us * with a dead tty. */ - if ((mode = fcntl(tty->fd, F_GETFL)) == -1) - return; - if (fcntl(tty->fd, F_SETFL, mode & ~O_NONBLOCK) == -1) - return; if (ioctl(tty->fd, TIOCGWINSZ, &ws) == -1) return; if (tcsetattr(tty->fd, TCSANOW, &tty->tio) == -1) @@ -233,6 +229,9 @@ tty_stop_tty(struct tty *tty) tty_raw(tty, "\033[?1000l"); tty_raw(tty, tty_term_string(tty->term, TTYC_RMCUP)); + + if ((mode = fcntl(tty->fd, F_GETFL)) != -1) + fcntl(tty->fd, F_SETFL, mode & ~O_NONBLOCK); } void From 6ac3343617b3c8e3739e4efd7bc013b5719e28f8 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 24 Feb 2010 19:13:38 +0000 Subject: [PATCH 0655/1180] Typo fix from Tim van der Molen. --- job.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/job.c b/job.c index 28ba3e72..36ea2f4e 100644 --- a/job.c +++ b/job.c @@ -32,7 +32,7 @@ */ /* All jobs list. */ -struct joblist all_jobs = SLIST_HEAD_INITIALIZER(&all_jobs); +struct joblist all_jobs = SLIST_HEAD_INITIALIZER(all_jobs); RB_GENERATE(jobs, job, entry, job_cmp); From c7046b9a0c338323fc478e9146371f80b843e336 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 1 Mar 2010 22:44:31 +0000 Subject: [PATCH 0656/1180] Check for colour and attribute modifications early so the translated values can be stored in the cached terminal attributes rather than the requested (untranslated) values. Prevents tmux clearing and setting the attributes for every character when using aixterm colours. --- tty.c | 143 +++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 91 insertions(+), 52 deletions(-) diff --git a/tty.c b/tty.c index 52d3803a..72be2c84 100644 --- a/tty.c +++ b/tty.c @@ -36,8 +36,10 @@ void tty_fill_acs(struct tty *); int tty_try_256(struct tty *, u_char, const char *); int tty_try_88(struct tty *, u_char, const char *); -void tty_colours(struct tty *, const struct grid_cell *, u_char *); -void tty_colours_fg(struct tty *, const struct grid_cell *, u_char *); +void tty_colours(struct tty *, const struct grid_cell *); +void tty_check_fg(struct tty *, struct grid_cell *); +void tty_check_bg(struct tty *, struct grid_cell *); +void tty_colours_fg(struct tty *, const struct grid_cell *); void tty_colours_bg(struct tty *, const struct grid_cell *); void tty_redraw_region(struct tty *, const struct tty_ctx *); @@ -1146,17 +1148,9 @@ void tty_attributes(struct tty *tty, const struct grid_cell *gc) { struct grid_cell *tc = &tty->cell, gc2; - u_char changed, new_attr; + u_char changed; - /* If the character is space, don't care about foreground. */ - if (gc->data == ' ' && !(gc->flags & GRID_FLAG_UTF8)) { - memcpy(&gc2, gc, sizeof gc2); - if (gc->attr & GRID_ATTR_REVERSE) - gc2.bg = tc->bg; - else - gc2.fg = tc->fg; - gc = &gc2; - } + memcpy(&gc2, gc, sizeof gc2); /* * If no setab, try to use the reverse attribute as a best-effort for a @@ -1164,34 +1158,32 @@ tty_attributes(struct tty *tty, const struct grid_cell *gc) * any serious harm and makes a couple of applications happier. */ if (!tty_term_has(tty->term, TTYC_SETAB)) { - if (gc != &gc2) { - memcpy(&gc2, gc, sizeof gc2); - gc = &gc2; - } - - if (gc->attr & GRID_ATTR_REVERSE) { - if (gc->fg != 7 && gc->fg != 8) + if (gc2.attr & GRID_ATTR_REVERSE) { + if (gc2.fg != 7 && gc2.fg != 8) gc2.attr &= ~GRID_ATTR_REVERSE; } else { - if (gc->bg != 0 && gc->bg != 8) + if (gc2.bg != 0 && gc2.bg != 8) gc2.attr |= GRID_ATTR_REVERSE; } } + /* Fix up the colours if necessary. */ + tty_check_fg(tty, &gc2); + tty_check_bg(tty, &gc2); + /* If any bits are being cleared, reset everything. */ - if (tc->attr & ~gc->attr) + if (tc->attr & ~gc2.attr) tty_reset(tty); /* * Set the colours. This may call tty_reset() (so it comes next) and * may add to (NOT remove) the desired attributes by changing new_attr. */ - new_attr = gc->attr; - tty_colours(tty, gc, &new_attr); + tty_colours(tty, &gc2); /* Filter out attribute bits already set. */ - changed = new_attr & ~tc->attr; - tc->attr = new_attr; + changed = gc2.attr & ~tc->attr; + tc->attr = gc2.attr; /* Set the attributes. */ if (changed & GRID_ATTR_BRIGHT) @@ -1217,7 +1209,7 @@ tty_attributes(struct tty *tty, const struct grid_cell *gc) } void -tty_colours(struct tty *tty, const struct grid_cell *gc, u_char *attr) +tty_colours(struct tty *tty, const struct grid_cell *gc) { struct grid_cell *tc = &tty->cell; u_char fg = gc->fg, bg = gc->bg, flags = gc->flags; @@ -1274,7 +1266,7 @@ tty_colours(struct tty *tty, const struct grid_cell *gc, u_char *attr) /* Set the foreground colour. */ if (!fg_default && (fg != tc->fg || ((flags & GRID_FLAG_FG256) != (tc->flags & GRID_FLAG_FG256)))) - tty_colours_fg(tty, gc, attr); + tty_colours_fg(tty, gc); /* * Set the background colour. This must come after the foreground as @@ -1286,7 +1278,71 @@ tty_colours(struct tty *tty, const struct grid_cell *gc, u_char *attr) } void -tty_colours_fg(struct tty *tty, const struct grid_cell *gc, u_char *attr) +tty_check_fg(struct tty *tty, struct grid_cell *gc) +{ + u_int colours; + + /* Is this a 256-colour colour? */ + if (gc->flags & GRID_FLAG_FG256) { + /* And not a 256 colour mode? */ + if (!(tty->term->flags & TERM_88COLOURS) && + !(tty->term_flags & TERM_88COLOURS) && + !(tty->term->flags & TERM_256COLOURS) && + !(tty->term_flags & TERM_256COLOURS)) { + gc->fg = colour_256to16(gc->fg); + if (gc->fg & 8) { + gc->fg &= 7; + gc->attr |= GRID_ATTR_BRIGHT; + } else + gc->attr &= ~GRID_ATTR_BRIGHT; + gc->flags &= ~GRID_FLAG_FG256; + } + return; + } + + /* Is this an aixterm colour? */ + colours = tty_term_number(tty->term, TTYC_COLORS); + if (gc->fg >= 90 && gc->fg <= 97 && colours < 16) { + gc->fg -= 90; + gc->attr |= GRID_ATTR_BRIGHT; + } +} + +void +tty_check_bg(struct tty *tty, struct grid_cell *gc) +{ + u_int colours; + + /* Is this a 256-colour colour? */ + if (gc->flags & GRID_FLAG_BG256) { + /* + * And not a 256 colour mode? Translate to 16-colour + * palette. Bold background doesn't exist portably, so just + * discard the bold bit if set. + */ + if (!(tty->term->flags & TERM_88COLOURS) && + !(tty->term_flags & TERM_88COLOURS) && + !(tty->term->flags & TERM_256COLOURS) && + !(tty->term_flags & TERM_256COLOURS)) { + gc->bg = colour_256to16(gc->bg); + if (gc->bg & 8) + gc->bg &= 7; + gc->attr &= ~GRID_ATTR_BRIGHT; + gc->flags &= ~GRID_FLAG_BG256; + } + return; + } + + /* Is this an aixterm colour? */ + colours = tty_term_number(tty->term, TTYC_COLORS); + if (gc->bg >= 100 && gc->bg <= 107 && colours < 16) { + gc->bg -= 90; + gc->attr |= GRID_ATTR_BRIGHT; + } +} + +void +tty_colours_fg(struct tty *tty, const struct grid_cell *gc) { struct grid_cell *tc = &tty->cell; u_char fg = gc->fg; @@ -1299,26 +1355,15 @@ tty_colours_fg(struct tty *tty, const struct grid_cell *gc, u_char *attr) goto save_fg; if (tty_try_88(tty, fg, "38") == 0) goto save_fg; - - /* Translate to 16-colour palette, updating bold if needed. */ - fg = colour_256to16(fg); - if (fg & 8) { - fg &= 7; - (*attr) |= GRID_ATTR_BRIGHT; - } else - tty_reset(tty); /* turn off bold */ + /* Else already handled by tty_check_fg. */ + return; } /* Is this an aixterm bright colour? */ if (fg >= 90 && fg <= 97) { - /* 16 colour terminals or above only. */ - if (tty_term_number(tty->term, TTYC_COLORS) >= 16) { - xsnprintf(s, sizeof s, "\033[%dm", fg); - tty_puts(tty, s); - goto save_fg; - } - fg -= 90; - (*attr) |= GRID_ATTR_BRIGHT; + xsnprintf(s, sizeof s, "\033[%dm", fg); + tty_puts(tty, s); + goto save_fg; } /* Otherwise set the foreground colour. */ @@ -1345,14 +1390,8 @@ tty_colours_bg(struct tty *tty, const struct grid_cell *gc) goto save_bg; if (tty_try_88(tty, bg, "48") == 0) goto save_bg; - - /* - * Translate to 16-colour palette. Bold background doesn't - * exist portably, so just discard the bold bit if set. - */ - bg = colour_256to16(bg); - if (bg & 8) - bg &= 7; + /* Else already handled by tty_check_bg. */ + return; } /* Is this an aixterm bright colour? */ From 56a33b157b4ca607850eedb6397c48707698537a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 1 Mar 2010 23:53:27 +0000 Subject: [PATCH 0657/1180] Extend the end-of-line key so that in normal mode a second press moves the cursor to the end of a wrapped line (if present) and in rectangle mode it toggles between the end of the text and the last cell on the line. From Micah Cowan. --- window-copy.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/window-copy.c b/window-copy.c index 82ae9a2b..6497b174 100644 --- a/window-copy.c +++ b/window-copy.c @@ -1149,12 +1149,27 @@ void window_copy_cursor_end_of_line(struct window_pane *wp) { struct window_copy_mode_data *data = wp->modedata; + struct screen *base_s = &wp->base; + struct grid *gd = base_s->grid; u_int px, py; - py = screen_hsize(&wp->base) + data->cy - data->oy; + py = screen_hsize(base_s) + data->cy - data->oy; px = window_copy_find_length(wp, py); + if (data->cx == px) { + if (data->screen.sel.flag && data->rectflag) + px = screen_size_x(&wp->base); + if (gd->linedata[py].flags & GRID_LINE_WRAPPED) { + while (py < gd->sy + gd->hsize && + gd->linedata[py].flags & GRID_LINE_WRAPPED) { + window_copy_cursor_down(wp, 0); + py = screen_hsize(base_s) + data->cy - data->oy; + } + px = window_copy_find_length(wp, py); + } + } window_copy_update_cursor(wp, px, data->cy); + if (window_copy_update_selection(wp)) window_copy_redraw_lines(wp, data->cy, 1); } @@ -1233,7 +1248,8 @@ window_copy_cursor_up(struct window_pane *wp, int scroll_only) if (!data->screen.sel.flag || !data->rectflag) { py = screen_hsize(&wp->base) + data->cy - data->oy; px = window_copy_find_length(wp, py); - if (data->cx >= data->lastsx || data->cx > px) + if ((data->cx >= data->lastsx && data->cx != px) || + data->cx > px) window_copy_cursor_end_of_line(wp); } } @@ -1266,7 +1282,8 @@ window_copy_cursor_down(struct window_pane *wp, int scroll_only) if (!data->screen.sel.flag || !data->rectflag) { py = screen_hsize(&wp->base) + data->cy - data->oy; px = window_copy_find_length(wp, py); - if (data->cx >= data->lastsx || data->cx > px) + if ((data->cx >= data->lastsx && data->cx != px) || + data->cx > px) window_copy_cursor_end_of_line(wp); } } From 7bc3f5dd8ac2d867df39225a4e2dda51b725c390 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 2 Mar 2010 00:32:41 +0000 Subject: [PATCH 0658/1180] Permit keys in copy mode to be prefixed by a repeat count, entered with [1-9] in vi mode, or M-[1-9] in emacs mode. From Micah Cowan, tweaked a little by me. --- mode-key.c | 19 ++++++ tmux.1 | 11 ++- tmux.h | 1 + window-copy.c | 182 +++++++++++++++++++++++++++++++++++++------------- 4 files changed, 167 insertions(+), 46 deletions(-) diff --git a/mode-key.c b/mode-key.c index 0d58f3d6..fb208e0d 100644 --- a/mode-key.c +++ b/mode-key.c @@ -106,6 +106,7 @@ struct mode_key_cmdstr mode_key_cmdstr_copy[] = { { MODEKEYCOPY_SEARCHDOWN, "search-forward" }, { MODEKEYCOPY_SEARCHREVERSE, "search-reverse" }, { MODEKEYCOPY_SEARCHUP, "search-backward" }, + { MODEKEYCOPY_STARTNUMBERPREFIX, "start-number-prefix" }, { MODEKEYCOPY_STARTOFLINE, "start-of-line" }, { MODEKEYCOPY_STARTSELECTION, "begin-selection" }, { MODEKEYCOPY_TOPLINE, "top-line" }, @@ -178,6 +179,15 @@ const struct mode_key_entry mode_key_vi_copy[] = { { '$', 0, MODEKEYCOPY_ENDOFLINE }, { '/', 0, MODEKEYCOPY_SEARCHDOWN }, { '0', 0, MODEKEYCOPY_STARTOFLINE }, + { '1', 0, MODEKEYCOPY_STARTNUMBERPREFIX }, + { '2', 0, MODEKEYCOPY_STARTNUMBERPREFIX }, + { '3', 0, MODEKEYCOPY_STARTNUMBERPREFIX }, + { '4', 0, MODEKEYCOPY_STARTNUMBERPREFIX }, + { '5', 0, MODEKEYCOPY_STARTNUMBERPREFIX }, + { '6', 0, MODEKEYCOPY_STARTNUMBERPREFIX }, + { '7', 0, MODEKEYCOPY_STARTNUMBERPREFIX }, + { '8', 0, MODEKEYCOPY_STARTNUMBERPREFIX }, + { '9', 0, MODEKEYCOPY_STARTNUMBERPREFIX }, { ':', 0, MODEKEYCOPY_GOTOLINE }, { '?', 0, MODEKEYCOPY_SEARCHUP }, { 'B', 0, MODEKEYCOPY_PREVIOUSSPACE }, @@ -280,6 +290,15 @@ struct mode_key_tree mode_key_tree_emacs_choice; /* emacs copy mode keys. */ const struct mode_key_entry mode_key_emacs_copy[] = { { ' ', 0, MODEKEYCOPY_NEXTPAGE }, + { '1' | KEYC_ESCAPE, 0, MODEKEYCOPY_STARTNUMBERPREFIX }, + { '2' | KEYC_ESCAPE, 0, MODEKEYCOPY_STARTNUMBERPREFIX }, + { '3' | KEYC_ESCAPE, 0, MODEKEYCOPY_STARTNUMBERPREFIX }, + { '4' | KEYC_ESCAPE, 0, MODEKEYCOPY_STARTNUMBERPREFIX }, + { '5' | KEYC_ESCAPE, 0, MODEKEYCOPY_STARTNUMBERPREFIX }, + { '6' | KEYC_ESCAPE, 0, MODEKEYCOPY_STARTNUMBERPREFIX }, + { '7' | KEYC_ESCAPE, 0, MODEKEYCOPY_STARTNUMBERPREFIX }, + { '8' | KEYC_ESCAPE, 0, MODEKEYCOPY_STARTNUMBERPREFIX }, + { '9' | KEYC_ESCAPE, 0, MODEKEYCOPY_STARTNUMBERPREFIX }, { '<' | KEYC_ESCAPE, 0, MODEKEYCOPY_HISTORYTOP }, { '>' | KEYC_ESCAPE, 0, MODEKEYCOPY_HISTORYBOTTOM }, { 'R' | KEYC_ESCAPE, 0, MODEKEYCOPY_TOPLINE }, diff --git a/tmux.1 b/tmux.1 index 348c2b3a..6d24fd53 100644 --- a/tmux.1 +++ b/tmux.1 @@ -661,7 +661,16 @@ next word and previous word to the start of the previous word. The three next and previous space keys work similarly but use a space alone as the word separator. .Pp -These key bindings are defined in a set of named tables: +Commands in copy mode may be prefaced by an optional repeat count. +With vi key bindings, a prefix is entered using the number keys; with +emacs, the Alt (meta) key and a number begins prefix entry. +For example, to move the cursor forward by ten words, use +.Ql M-1 0 M-f +in emacs mode, and +.Ql 10w +in vi. +.Pp +Mode key bindings are defined in a set of named tables: .Em vi-edit and .Em emacs-edit diff --git a/tmux.h b/tmux.h index ac398f04..0ecabf12 100644 --- a/tmux.h +++ b/tmux.h @@ -477,6 +477,7 @@ enum mode_key_cmd { MODEKEYCOPY_SEARCHDOWN, MODEKEYCOPY_SEARCHREVERSE, MODEKEYCOPY_SEARCHUP, + MODEKEYCOPY_STARTNUMBERPREFIX, MODEKEYCOPY_STARTOFLINE, MODEKEYCOPY_STARTSELECTION, MODEKEYCOPY_TOPLINE, diff --git a/window-copy.c b/window-copy.c index 6497b174..17fc792b 100644 --- a/window-copy.c +++ b/window-copy.c @@ -28,6 +28,7 @@ void window_copy_free(struct window_pane *); void window_copy_resize(struct window_pane *, u_int, u_int); void window_copy_key(struct window_pane *, struct client *, int); int window_copy_key_input(struct window_pane *, int); +int window_copy_key_numeric_prefix(struct window_pane *, int); void window_copy_mouse( struct window_pane *, struct client *, struct mouse_event *); @@ -82,6 +83,7 @@ const struct window_mode window_copy_mode = { enum window_copy_input_type { WINDOW_COPY_OFF, + WINDOW_COPY_NUMERICPREFIX, WINDOW_COPY_SEARCHUP, WINDOW_COPY_SEARCHDOWN, WINDOW_COPY_GOTOLINE, @@ -109,6 +111,8 @@ struct window_copy_mode_data { const char *inputprompt; char *inputstr; + u_int numprefix; + enum window_copy_input_type searchtype; char *searchstr; }; @@ -135,6 +139,7 @@ window_copy_init(struct window_pane *wp) data->inputtype = WINDOW_COPY_OFF; data->inputprompt = NULL; data->inputstr = xstrdup(""); + data->numprefix = 0; data->searchtype = WINDOW_COPY_OFF; data->searchstr = NULL; @@ -229,11 +234,20 @@ window_copy_key(struct window_pane *wp, struct client *c, int key) const char *word_separators; struct window_copy_mode_data *data = wp->modedata; struct screen *s = &data->screen; - u_int n; + u_int n, np; int keys; enum mode_key_cmd cmd; - if (data->inputtype != WINDOW_COPY_OFF) { + np = data->numprefix; + if (np == 0) + np = 1; + + if (data->inputtype == WINDOW_COPY_NUMERICPREFIX) { + if (window_copy_key_numeric_prefix(wp, key) == 0) + return; + data->inputtype = WINDOW_COPY_OFF; + window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1); + } else if (data->inputtype != WINDOW_COPY_OFF) { if (window_copy_key_input(wp, key) != 0) goto input_off; return; @@ -242,55 +256,69 @@ window_copy_key(struct window_pane *wp, struct client *c, int key) cmd = mode_key_lookup(&data->mdata, key); switch (cmd) { case MODEKEYCOPY_CANCEL: - window_pane_reset_mode(wp); + for (; np != 0; np--) + window_pane_reset_mode(wp); break; case MODEKEYCOPY_LEFT: - window_copy_cursor_left(wp); - return; + for (; np != 0; np--) + window_copy_cursor_left(wp); + break; case MODEKEYCOPY_RIGHT: - window_copy_cursor_right(wp); - return; + for (; np != 0; np--) + window_copy_cursor_right(wp); + break; case MODEKEYCOPY_UP: - window_copy_cursor_up(wp, 0); - return; + for (; np != 0; np--) + window_copy_cursor_up(wp, 0); + break; case MODEKEYCOPY_DOWN: - window_copy_cursor_down(wp, 0); - return; + for (; np != 0; np--) + window_copy_cursor_down(wp, 0); + break; case MODEKEYCOPY_SCROLLUP: - window_copy_cursor_up(wp, 1); + for (; np != 0; np--) + window_copy_cursor_up(wp, 1); break; case MODEKEYCOPY_SCROLLDOWN: - window_copy_cursor_down(wp, 1); + for (; np != 0; np--) + window_copy_cursor_down(wp, 1); break; case MODEKEYCOPY_PREVIOUSPAGE: - window_copy_pageup(wp); + for (; np != 0; np--) + window_copy_pageup(wp); break; case MODEKEYCOPY_NEXTPAGE: n = 1; if (screen_size_y(s) > 2) n = screen_size_y(s) - 2; - if (data->oy < n) - data->oy = 0; - else - data->oy -= n; + for (; np != 0; np--) { + if (data->oy < n) + data->oy = 0; + else + data->oy -= n; + } window_copy_update_selection(wp); window_copy_redraw_screen(wp); break; case MODEKEYCOPY_HALFPAGEUP: n = screen_size_y(s) / 2; - if (data->oy + n > screen_hsize(&wp->base)) - data->oy = screen_hsize(&wp->base); - else - data->oy += n; + for (; np != 0; np--) { + if (data->oy + n > screen_hsize(&wp->base)) + data->oy = screen_hsize(&wp->base); + else + data->oy += n; + } window_copy_update_selection(wp); window_copy_redraw_screen(wp); break; case MODEKEYCOPY_HALFPAGEDOWN: n = screen_size_y(s) / 2; - if (data->oy < n) - data->oy = 0; - else - data->oy -= n; + for (; np != 0; np--) { + if (data->oy < n) + data->oy = 0; + else + data->oy -= n; + } window_copy_update_selection(wp); window_copy_redraw_screen(wp); break; @@ -350,28 +378,34 @@ window_copy_key(struct window_pane *wp, struct client *c, int key) window_copy_cursor_end_of_line(wp); break; case MODEKEYCOPY_NEXTSPACE: - window_copy_cursor_next_word(wp, " "); + for (; np != 0; np--) + window_copy_cursor_next_word(wp, " "); break; case MODEKEYCOPY_NEXTSPACEEND: - window_copy_cursor_next_word_end(wp, " "); + for (; np != 0; np--) + window_copy_cursor_next_word_end(wp, " "); break; case MODEKEYCOPY_NEXTWORD: word_separators = options_get_string(&wp->window->options, "word-separators"); - window_copy_cursor_next_word(wp, word_separators); + for (; np != 0; np--) + window_copy_cursor_next_word(wp, word_separators); break; case MODEKEYCOPY_NEXTWORDEND: word_separators = options_get_string(&wp->window->options, "word-separators"); - window_copy_cursor_next_word_end(wp, word_separators); + for (; np != 0; np--) + window_copy_cursor_next_word_end(wp, word_separators); break; case MODEKEYCOPY_PREVIOUSSPACE: - window_copy_cursor_previous_word(wp, " "); + for (; np != 0; np--) + window_copy_cursor_previous_word(wp, " "); break; case MODEKEYCOPY_PREVIOUSWORD: word_separators = options_get_string(&wp->window->options, "word-separators"); - window_copy_cursor_previous_word(wp, word_separators); + for (; np != 0; np--) + window_copy_cursor_previous_word(wp, word_separators); break; case MODEKEYCOPY_SEARCHUP: data->inputtype = WINDOW_COPY_SEARCHUP; @@ -386,18 +420,33 @@ window_copy_key(struct window_pane *wp, struct client *c, int key) switch (data->searchtype) { case WINDOW_COPY_OFF: case WINDOW_COPY_GOTOLINE: + case WINDOW_COPY_NUMERICPREFIX: break; case WINDOW_COPY_SEARCHUP: - if (cmd == MODEKEYCOPY_SEARCHAGAIN) - window_copy_search_up(wp, data->searchstr); - else - window_copy_search_down(wp, data->searchstr); + if (cmd == MODEKEYCOPY_SEARCHAGAIN) { + for (; np != 0; np--) { + window_copy_search_up( + wp, data->searchstr); + } + } else { + for (; np != 0; np--) { + window_copy_search_down( + wp, data->searchstr); + } + } break; case WINDOW_COPY_SEARCHDOWN: - if (cmd == MODEKEYCOPY_SEARCHAGAIN) - window_copy_search_down(wp, data->searchstr); - else - window_copy_search_up(wp, data->searchstr); + if (cmd == MODEKEYCOPY_SEARCHAGAIN) { + for (; np != 0; np--) { + window_copy_search_down( + wp, data->searchstr); + } + } else { + for (; np != 0; np--) { + window_copy_search_up( + wp, data->searchstr); + } + } break; } break; @@ -406,13 +455,23 @@ window_copy_key(struct window_pane *wp, struct client *c, int key) data->inputprompt = "Goto Line"; *data->inputstr = '\0'; goto input_on; + case MODEKEYCOPY_STARTNUMBERPREFIX: + key &= 0xff; + if (key >= '0' && key <= '9') { + data->inputtype = WINDOW_COPY_NUMERICPREFIX; + data->numprefix = 0; + window_copy_key_numeric_prefix(wp, key); + return; + } + break; case MODEKEYCOPY_RECTANGLETOGGLE: window_copy_rectangle_toggle(wp); - return; + break; default: break; } + data->numprefix = 0; return; input_on: @@ -444,9 +503,11 @@ 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; + u_int np; switch (mode_key_lookup(&data->mdata, key)) { case MODEKEYEDIT_CANCEL: + data->numprefix = 0; return (-1); case MODEKEYEDIT_BACKSPACE: inputlen = strlen(data->inputstr); @@ -457,16 +518,23 @@ window_copy_key_input(struct window_pane *wp, int key) *data->inputstr = '\0'; break; case MODEKEYEDIT_ENTER: + np = data->numprefix; + if (np == 0) + np = 1; + switch (data->inputtype) { case WINDOW_COPY_OFF: + case WINDOW_COPY_NUMERICPREFIX: break; case WINDOW_COPY_SEARCHUP: - window_copy_search_up(wp, data->inputstr); + for (; np != 0; np--) + window_copy_search_up(wp, data->inputstr); data->searchtype = data->inputtype; data->searchstr = xstrdup(data->inputstr); break; case WINDOW_COPY_SEARCHDOWN: - window_copy_search_down(wp, data->inputstr); + for (; np != 0; np--) + window_copy_search_down(wp, data->inputstr); data->searchtype = data->inputtype; data->searchstr = xstrdup(data->inputstr); break; @@ -475,6 +543,7 @@ window_copy_key_input(struct window_pane *wp, int key) *data->inputstr = '\0'; break; } + data->numprefix = 0; return (1); case MODEKEY_OTHER: if (key < 32 || key > 126) @@ -493,6 +562,24 @@ window_copy_key_input(struct window_pane *wp, int key) return (0); } +int +window_copy_key_numeric_prefix(struct window_pane *wp, int key) +{ + struct window_copy_mode_data *data = wp->modedata; + struct screen *s = &data->screen; + + key &= 0xff; + if (key < '0' || key > '9') + return 1; + + if (data->numprefix >= 100) /* no more than three digits */ + return 0; + data->numprefix = data->numprefix * 10 + key - '0'; + + window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1); + return 0; +} + /* ARGSUSED */ void window_copy_mouse( @@ -762,8 +849,13 @@ 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) { - xoff = size = xsnprintf(hdr, sizeof hdr, - "%s: %s", data->inputprompt, data->inputstr); + if (data->inputtype == WINDOW_COPY_NUMERICPREFIX) { + xoff = size = xsnprintf(hdr, sizeof hdr, + "Repeat: %u", data->numprefix); + } else { + xoff = size = xsnprintf(hdr, sizeof hdr, + "%s: %s", data->inputprompt, data->inputstr); + } screen_write_cursormove(ctx, 0, last); screen_write_puts(ctx, &gc, "%s", hdr); } else From 48dd72005e879336ea2439fb3422296be664cc76 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 14 Mar 2010 23:31:23 +0000 Subject: [PATCH 0659/1180] Fix a use-after-free when cancelling copy mode, or trying to repeat cancel. ok kettenis --- window-copy.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/window-copy.c b/window-copy.c index 17fc792b..c27b1821 100644 --- a/window-copy.c +++ b/window-copy.c @@ -256,9 +256,8 @@ window_copy_key(struct window_pane *wp, struct client *c, int key) cmd = mode_key_lookup(&data->mdata, key); switch (cmd) { case MODEKEYCOPY_CANCEL: - for (; np != 0; np--) - window_pane_reset_mode(wp); - break; + window_pane_reset_mode(wp); + return; case MODEKEYCOPY_LEFT: for (; np != 0; np--) window_copy_cursor_left(wp); @@ -366,6 +365,7 @@ window_copy_key(struct window_pane *wp, struct client *c, int key) if (c != NULL && c->session != NULL) { window_copy_copy_selection(wp, c); window_pane_reset_mode(wp); + return; } break; case MODEKEYCOPY_STARTOFLINE: From 4baafd81262a2b1961e9b710b6f9c9cff9b2b828 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 22 Mar 2010 19:02:54 +0000 Subject: [PATCH 0660/1180] New input parser based on http://vt100.net/emu/dec_ansi_parser. --- input.c | 2395 +++++++++++++++++++++++++++--------------------------- tmux.h | 51 +- window.c | 75 ++ 3 files changed, 1292 insertions(+), 1229 deletions(-) diff --git a/input.c b/input.c index bf31413c..e709b366 100644 --- a/input.c +++ b/input.c @@ -18,614 +18,873 @@ #include -#include #include #include #include "tmux.h" -#define INPUT_C0CONTROL(ch) (ch <= 0x1f) -#define INPUT_INTERMEDIATE(ch) (ch == 0xa0 || (ch >= 0x20 && ch <= 0x2f)) -#define INPUT_PARAMETER(ch) (ch >= 0x30 && ch <= 0x3f) -#define INPUT_UPPERCASE(ch) (ch >= 0x40 && ch <= 0x5f) -#define INPUT_LOWERCASE(ch) (ch >= 0x60 && ch <= 0x7e) -#define INPUT_DELETE(ch) (ch == 0x7f) -#define INPUT_C1CONTROL(ch) (ch >= 0x80 && ch <= 0x9f) -#define INPUT_G1DISPLAYABLE(ch) (ch >= 0xa1 && ch <= 0xfe) -#define INPUT_SPECIAL(ch) (ch == 0xff) +/* + * Based on the description by Paul Williams at: + * + * http://vt100.net/emu/dec_ansi_parser + * + * With the following changes: + * + * - 7-bit only. + * + * - Support for UTF-8. + * + * - OSC (but not APC) may be terminated by \007 as well as ST. + * + * - A state for APC similar to OSC. Some terminals appear to use this to set + * the title. + * + * - A state for the screen \033k...\033\\ sequence to rename a window. This is + * pretty stupid but not supporting it is more trouble than it is worth. + */ -int input_get_argument(struct input_ctx *, u_int, uint16_t *, uint16_t); -void input_new_argument(struct input_ctx *); -int input_add_argument(struct input_ctx *, u_char); +/* Helper functions. */ +int input_split(struct input_ctx *); +int input_get(struct input_ctx *, u_int, int, int); +void input_reply(struct input_ctx *, const char *, ...); -void input_start_string(struct input_ctx *, int); -void input_abort_string(struct input_ctx *); -int input_add_string(struct input_ctx *, u_char); -char *input_get_string(struct input_ctx *); +/* Transition entry/exit handlers. */ +void input_clear(struct input_ctx *); +void input_enter_dcs(struct input_ctx *); +void input_exit_dcs(struct input_ctx *); +void input_enter_osc(struct input_ctx *); +void input_exit_osc(struct input_ctx *); +void input_enter_apc(struct input_ctx *); +void input_exit_apc(struct input_ctx *); +void input_enter_rename(struct input_ctx *); +void input_exit_rename(struct input_ctx *); -void input_state(struct input_ctx *, void *); +/* Input state handlers. */ +int input_print(struct input_ctx *); +int input_intermediate(struct input_ctx *); +int input_parameter(struct input_ctx *); +int input_input(struct input_ctx *); +int input_c0_dispatch(struct input_ctx *); +int input_esc_dispatch(struct input_ctx *); +int input_csi_dispatch(struct input_ctx *); +void input_csi_dispatch_sgr(struct input_ctx *); +int input_utf8_open(struct input_ctx *); +int input_utf8_add(struct input_ctx *); +int input_utf8_close(struct input_ctx *); -void input_state_first(u_char, struct input_ctx *); -void input_state_escape(u_char, struct input_ctx *); -void input_state_intermediate(u_char, struct input_ctx *); -void input_state_sequence_first(u_char, struct input_ctx *); -void input_state_sequence_next(u_char, struct input_ctx *); -void input_state_sequence_intermediate(u_char, struct input_ctx *); -void input_state_string_next(u_char, struct input_ctx *); -void input_state_string_escape(u_char, struct input_ctx *); -void input_state_utf8(u_char, struct input_ctx *); +/* Command table comparison function. */ +int input_table_compare(const void *, const void *); -void input_handle_character(u_char, struct input_ctx *); -void input_handle_c0_control(u_char, struct input_ctx *); -void input_handle_c1_control(u_char, struct input_ctx *); -void input_handle_private_two(u_char, struct input_ctx *); -void input_handle_standard_two(u_char, struct input_ctx *); -void input_handle_sequence(u_char, struct input_ctx *); - -void input_handle_sequence_cuu(struct input_ctx *); -void input_handle_sequence_cud(struct input_ctx *); -void input_handle_sequence_cuf(struct input_ctx *); -void input_handle_sequence_cub(struct input_ctx *); -void input_handle_sequence_dch(struct input_ctx *); -void input_handle_sequence_cbt(struct input_ctx *); -void input_handle_sequence_da(struct input_ctx *); -void input_handle_sequence_dl(struct input_ctx *); -void input_handle_sequence_ich(struct input_ctx *); -void input_handle_sequence_il(struct input_ctx *); -void input_handle_sequence_vpa(struct input_ctx *); -void input_handle_sequence_hpa(struct input_ctx *); -void input_handle_sequence_cup(struct input_ctx *); -void input_handle_sequence_cup(struct input_ctx *); -void input_handle_sequence_tbc(struct input_ctx *); -void input_handle_sequence_ed(struct input_ctx *); -void input_handle_sequence_el(struct input_ctx *); -void input_handle_sequence_sm(struct input_ctx *); -void input_handle_sequence_rm(struct input_ctx *); -void input_handle_sequence_decstbm(struct input_ctx *); -void input_handle_sequence_sgr(struct input_ctx *); -void input_handle_sequence_dsr(struct input_ctx *); - -int input_sequence_cmp(const void *, const void *); - -struct input_sequence_entry { - u_char ch; - void (*fn)(struct input_ctx *); -}; -const struct input_sequence_entry input_sequence_table[] = { - { '@', input_handle_sequence_ich }, - { 'A', input_handle_sequence_cuu }, - { 'B', input_handle_sequence_cud }, - { 'C', input_handle_sequence_cuf }, - { 'D', input_handle_sequence_cub }, - { 'G', input_handle_sequence_hpa }, - { 'H', input_handle_sequence_cup }, - { 'J', input_handle_sequence_ed }, - { 'K', input_handle_sequence_el }, - { 'L', input_handle_sequence_il }, - { 'M', input_handle_sequence_dl }, - { 'P', input_handle_sequence_dch }, - { 'Z', input_handle_sequence_cbt }, - { 'c', input_handle_sequence_da }, - { 'd', input_handle_sequence_vpa }, - { 'f', input_handle_sequence_cup }, - { 'g', input_handle_sequence_tbc }, - { 'h', input_handle_sequence_sm }, - { 'l', input_handle_sequence_rm }, - { 'm', input_handle_sequence_sgr }, - { 'n', input_handle_sequence_dsr }, - { 'r', input_handle_sequence_decstbm }, +/* Command table entry. */ +struct input_table_entry { + int ch; + const char *interm; + int type; }; +/* Escape commands. */ +enum input_esc_type { + INPUT_ESC_DECALN, + INPUT_ESC_DECKPAM, + INPUT_ESC_DECKPNM, + INPUT_ESC_DECRC, + INPUT_ESC_DECSC, + INPUT_ESC_HTS, + INPUT_ESC_IND, + INPUT_ESC_NEL, + INPUT_ESC_RI, + INPUT_ESC_RIS, + INPUT_ESC_SCSOFF_G0, + INPUT_ESC_SCSON_G0, +}; + +/* Escape command table. */ +const struct input_table_entry input_esc_table[] = { + { '0', "(", INPUT_ESC_SCSOFF_G0 }, + { '7', "", INPUT_ESC_DECSC }, + { '8', "", INPUT_ESC_DECRC }, + { '8', "#", INPUT_ESC_DECALN }, + { '=', "", INPUT_ESC_DECKPAM }, + { '>', "", INPUT_ESC_DECKPNM }, + { 'B', "(", INPUT_ESC_SCSON_G0 }, + { 'D', "", INPUT_ESC_IND }, + { 'E', "", INPUT_ESC_NEL }, + { 'H', "", INPUT_ESC_HTS }, + { 'M', "", INPUT_ESC_RI }, + { 'c', "", INPUT_ESC_RIS }, +}; + +/* Control (CSI) commands. */ +enum input_csi_type { + INPUT_CSI_CBT, + INPUT_CSI_CUB, + INPUT_CSI_CUD, + INPUT_CSI_CUF, + INPUT_CSI_CUP, + INPUT_CSI_CUU, + INPUT_CSI_DA, + INPUT_CSI_DCH, + INPUT_CSI_DECSTBM, + INPUT_CSI_DL, + INPUT_CSI_DSR, + INPUT_CSI_ED, + INPUT_CSI_EL, + INPUT_CSI_HPA, + INPUT_CSI_ICH, + INPUT_CSI_IL, + INPUT_CSI_RM, + INPUT_CSI_RM_PRIVATE, + INPUT_CSI_SGR, + INPUT_CSI_SM, + INPUT_CSI_SM_PRIVATE, + INPUT_CSI_TBC, + INPUT_CSI_VPA, +}; + +/* Control (CSI) command table. */ +const struct input_table_entry input_csi_table[] = { + { '@', "", INPUT_CSI_ICH }, + { 'A', "", INPUT_CSI_CUU }, + { 'B', "", INPUT_CSI_CUD }, + { 'C', "", INPUT_CSI_CUF }, + { 'D', "", INPUT_CSI_CUB }, + { 'G', "", INPUT_CSI_HPA }, + { 'H', "", INPUT_CSI_CUP }, + { 'J', "", INPUT_CSI_ED }, + { 'K', "", INPUT_CSI_EL }, + { 'L', "", INPUT_CSI_IL }, + { 'M', "", INPUT_CSI_DL }, + { 'P', "", INPUT_CSI_DCH }, + { 'Z', "", INPUT_CSI_CBT }, + { 'c', "", INPUT_CSI_DA }, + { 'd', "", INPUT_CSI_VPA }, + { 'f', "", INPUT_CSI_CUP }, + { 'g', "", INPUT_CSI_TBC }, + { 'h', "", INPUT_CSI_SM }, + { 'h', "?", INPUT_CSI_SM_PRIVATE }, + { 'l', "", INPUT_CSI_RM }, + { 'l', "?", INPUT_CSI_RM_PRIVATE }, + { 'm', "", INPUT_CSI_SGR }, + { 'n', "", INPUT_CSI_DSR }, + { 'r', "", INPUT_CSI_DECSTBM }, +}; + +/* Input transition. */ +struct input_transition { + int first; + int last; + + int (*handler)(struct input_ctx *); + const struct input_state *state; +}; + +/* Input state. */ +struct input_state { + const char *name; + void (*enter)(struct input_ctx *); + void (*exit)(struct input_ctx *); + const struct input_transition *transitions; +}; + +/* State transitions available from all states. */ +#define INPUT_STATE_ANYWHERE \ + { 0x18, 0x18, input_c0_dispatch, &input_state_ground }, \ + { 0x1a, 0x1a, input_c0_dispatch, &input_state_ground }, \ + { 0x1b, 0x1b, NULL, &input_state_esc_enter } + +/* Forward declarations of state tables. */ +const struct input_transition input_state_ground_table[]; +const struct input_transition input_state_esc_enter_table[]; +const struct input_transition input_state_esc_intermediate_table[]; +const struct input_transition input_state_csi_enter_table[]; +const struct input_transition input_state_csi_parameter_table[]; +const struct input_transition input_state_csi_intermediate_table[]; +const struct input_transition input_state_csi_ignore_table[]; +const struct input_transition input_state_dcs_enter_table[]; +const struct input_transition input_state_dcs_parameter_table[]; +const struct input_transition input_state_dcs_intermediate_table[]; +const struct input_transition input_state_dcs_handler_table[]; +const struct input_transition input_state_dcs_ignore_table[]; +const struct input_transition input_state_osc_string_table[]; +const struct input_transition input_state_apc_string_table[]; +const struct input_transition input_state_rename_string_table[]; +const struct input_transition input_state_consume_st_table[]; +const struct input_transition input_state_utf8_three_table[]; +const struct input_transition input_state_utf8_two_table[]; +const struct input_transition input_state_utf8_one_table[]; + +/* ground state definition. */ +const struct input_state input_state_ground = { + "ground", + NULL, NULL, + input_state_ground_table +}; + +/* esc_enter state definition. */ +const struct input_state input_state_esc_enter = { + "esc_enter", + input_clear, NULL, + input_state_esc_enter_table +}; + +/* esc_intermediate state definition. */ +const struct input_state input_state_esc_intermediate = { + "esc_intermediate", + NULL, NULL, + input_state_esc_intermediate_table +}; + +/* csi_enter state definition. */ +const struct input_state input_state_csi_enter = { + "csi_enter", + input_clear, NULL, + input_state_csi_enter_table +}; + +/* csi_parameter state definition. */ +const struct input_state input_state_csi_parameter = { + "csi_parameter", + NULL, NULL, + input_state_csi_parameter_table +}; + +/* csi_intermediate state definition. */ +const struct input_state input_state_csi_intermediate = { + "csi_intermediate", + NULL, NULL, + input_state_csi_intermediate_table +}; + +/* csi_ignore state definition. */ +const struct input_state input_state_csi_ignore = { + "csi_ignore", + NULL, NULL, + input_state_csi_ignore_table +}; + +/* dcs_enter state definition. */ +const struct input_state input_state_dcs_enter = { + "dcs_enter", + input_clear, NULL, + input_state_dcs_enter_table +}; + +/* dcs_parameter state definition. */ +const struct input_state input_state_dcs_parameter = { + "dcs_parameter", + NULL, NULL, + input_state_dcs_parameter_table +}; + +/* dcs_intermediate state definition. */ +const struct input_state input_state_dcs_intermediate = { + "dcs_intermediate", + NULL, NULL, + input_state_dcs_intermediate_table +}; + +/* dcs_handler state definition. */ +const struct input_state input_state_dcs_handler = { + "dcs_handler", + input_enter_dcs, input_exit_dcs, + input_state_dcs_handler_table +}; + +/* dcs_ignore state definition. */ +const struct input_state input_state_dcs_ignore = { + "dcs_ignore", + NULL, NULL, + input_state_dcs_ignore_table +}; + +/* osc_string state definition. */ +const struct input_state input_state_osc_string = { + "osc_string", + input_enter_osc, input_exit_osc, + input_state_osc_string_table +}; + +/* apc_string state definition. */ +const struct input_state input_state_apc_string = { + "apc_string", + input_enter_apc, input_exit_apc, + input_state_apc_string_table +}; + +/* rename_string state definition. */ +const struct input_state input_state_rename_string = { + "rename_string", + input_enter_rename, input_exit_rename, + input_state_rename_string_table +}; + +/* consume_st state definition. */ +const struct input_state input_state_consume_st = { + "consume_st", + NULL, NULL, + input_state_consume_st_table +}; + +/* utf8_three state definition. */ +const struct input_state input_state_utf8_three = { + "utf8_three", + NULL, NULL, + input_state_utf8_three_table +}; + +/* utf8_two state definition. */ +const struct input_state input_state_utf8_two = { + "utf8_two", + NULL, NULL, + input_state_utf8_two_table +}; + +/* utf8_one state definition. */ +const struct input_state input_state_utf8_one = { + "utf8_one", + NULL, NULL, + input_state_utf8_one_table +}; + +/* ground state table. */ +const struct input_transition input_state_ground_table[] = { + INPUT_STATE_ANYWHERE, + + { 0x00, 0x17, input_c0_dispatch, NULL }, + { 0x19, 0x19, input_c0_dispatch, NULL }, + { 0x1c, 0x1f, input_c0_dispatch, NULL }, + { 0x20, 0x7e, input_print, NULL }, + { 0x7f, 0x7f, NULL, NULL }, + { 0x80, 0xc1, input_print, NULL }, + { 0xc2, 0xdf, input_utf8_open, &input_state_utf8_one }, + { 0xe0, 0xef, input_utf8_open, &input_state_utf8_two }, + { 0xf0, 0xf4, input_utf8_open, &input_state_utf8_three }, + { 0xf5, 0xff, input_print, NULL }, + + { -1, -1, NULL, NULL } +}; + +/* esc_enter state table. */ +const struct input_transition input_state_esc_enter_table[] = { + INPUT_STATE_ANYWHERE, + + { 0x00, 0x17, input_c0_dispatch, NULL }, + { 0x19, 0x19, input_c0_dispatch, NULL }, + { 0x1c, 0x1f, input_c0_dispatch, NULL }, + { 0x20, 0x2f, input_intermediate, &input_state_esc_intermediate }, + { 0x30, 0x4f, input_esc_dispatch, &input_state_ground }, + { 0x50, 0x50, NULL, &input_state_dcs_enter }, + { 0x51, 0x57, input_esc_dispatch, &input_state_ground }, + { 0x58, 0x58, NULL, &input_state_consume_st }, + { 0x59, 0x59, input_esc_dispatch, &input_state_ground }, + { 0x5a, 0x5a, input_esc_dispatch, &input_state_ground }, + { 0x5b, 0x5b, NULL, &input_state_csi_enter }, + { 0x5c, 0x5c, input_esc_dispatch, &input_state_ground }, + { 0x5d, 0x5d, NULL, &input_state_osc_string }, + { 0x5e, 0x5e, NULL, &input_state_consume_st }, + { 0x5f, 0x5f, NULL, &input_state_apc_string }, + { 0x60, 0x6a, input_esc_dispatch, &input_state_ground }, + { 0x6b, 0x6b, NULL, &input_state_rename_string }, + { 0x6c, 0x7c, input_esc_dispatch, &input_state_ground }, + { 0x7f, 0xff, NULL, NULL }, + + { -1, -1, NULL, NULL } +}; + +/* esc_interm state table. */ +const struct input_transition input_state_esc_intermediate_table[] = { + INPUT_STATE_ANYWHERE, + + { 0x00, 0x17, input_c0_dispatch, NULL }, + { 0x19, 0x19, input_c0_dispatch, NULL }, + { 0x1c, 0x1f, input_c0_dispatch, NULL }, + { 0x20, 0x2f, input_intermediate, NULL }, + { 0x30, 0x7e, input_esc_dispatch, &input_state_ground }, + { 0x7f, 0xff, NULL, NULL }, + + { -1, -1, NULL, NULL } +}; + +/* csi_enter state table. */ +const struct input_transition input_state_csi_enter_table[] = { + INPUT_STATE_ANYWHERE, + + { 0x00, 0x17, input_c0_dispatch, NULL }, + { 0x19, 0x19, input_c0_dispatch, NULL }, + { 0x1c, 0x1f, input_c0_dispatch, NULL }, + { 0x20, 0x2f, input_intermediate, &input_state_csi_intermediate }, + { 0x30, 0x39, input_parameter, &input_state_csi_parameter }, + { 0x3a, 0x3a, NULL, &input_state_csi_ignore }, + { 0x3b, 0x3b, input_parameter, &input_state_csi_parameter }, + { 0x3c, 0x3f, input_intermediate, &input_state_csi_parameter }, + { 0x40, 0x7e, input_csi_dispatch, &input_state_ground }, + { 0x7f, 0xff, NULL, NULL }, + + { -1, -1, NULL, NULL } +}; + +/* csi_parameter state table. */ +const struct input_transition input_state_csi_parameter_table[] = { + INPUT_STATE_ANYWHERE, + + { 0x00, 0x17, input_c0_dispatch, NULL }, + { 0x19, 0x19, input_c0_dispatch, NULL }, + { 0x1c, 0x1f, input_c0_dispatch, NULL }, + { 0x20, 0x2f, input_intermediate, &input_state_csi_intermediate }, + { 0x30, 0x39, input_parameter, NULL }, + { 0x3a, 0x3a, NULL, &input_state_csi_ignore }, + { 0x3b, 0x3b, input_parameter, NULL }, + { 0x3c, 0x3f, NULL, &input_state_csi_ignore }, + { 0x40, 0x7e, input_csi_dispatch, &input_state_ground }, + { 0x7f, 0xff, NULL, NULL }, + + { -1, -1, NULL, NULL } +}; + +/* csi_intermediate state table. */ +const struct input_transition input_state_csi_intermediate_table[] = { + INPUT_STATE_ANYWHERE, + + { 0x00, 0x17, input_c0_dispatch, NULL }, + { 0x19, 0x19, input_c0_dispatch, NULL }, + { 0x1c, 0x1f, input_c0_dispatch, NULL }, + { 0x20, 0x2f, input_intermediate, NULL }, + { 0x30, 0x3f, NULL, &input_state_csi_ignore }, + { 0x40, 0x7e, input_csi_dispatch, &input_state_ground }, + { 0x7f, 0xff, NULL, NULL }, + + { -1, -1, NULL, NULL } +}; + +/* csi_ignore state table. */ +const struct input_transition input_state_csi_ignore_table[] = { + INPUT_STATE_ANYWHERE, + + { 0x00, 0x17, input_c0_dispatch, NULL }, + { 0x19, 0x19, input_c0_dispatch, NULL }, + { 0x1c, 0x1f, input_c0_dispatch, NULL }, + { 0x20, 0x3f, NULL, NULL }, + { 0x40, 0x7e, NULL, &input_state_ground }, + { 0x7f, 0xff, NULL, NULL }, + + { -1, -1, NULL, NULL } +}; + +/* dcs_enter state table. */ +const struct input_transition input_state_dcs_enter_table[] = { + INPUT_STATE_ANYWHERE, + + { 0x00, 0x17, NULL, NULL }, + { 0x19, 0x19, NULL, NULL }, + { 0x1c, 0x1f, NULL, NULL }, + { 0x20, 0x2f, input_intermediate, &input_state_dcs_intermediate }, + { 0x30, 0x39, input_parameter, &input_state_dcs_parameter }, + { 0x3a, 0x3a, NULL, &input_state_dcs_ignore }, + { 0x3b, 0x3b, input_parameter, &input_state_dcs_parameter }, + { 0x3c, 0x3f, input_intermediate, &input_state_dcs_parameter }, + { 0x40, 0x7e, NULL, &input_state_dcs_handler }, + { 0x7f, 0xff, NULL, NULL }, + + { -1, -1, NULL, NULL } +}; + +/* dcs_parameter state table. */ +const struct input_transition input_state_dcs_parameter_table[] = { + INPUT_STATE_ANYWHERE, + + { 0x00, 0x17, NULL, NULL }, + { 0x19, 0x19, NULL, NULL }, + { 0x1c, 0x1f, NULL, NULL }, + { 0x20, 0x2f, input_intermediate, &input_state_dcs_intermediate }, + { 0x30, 0x39, input_parameter, NULL }, + { 0x3a, 0x3a, NULL, &input_state_dcs_ignore }, + { 0x3b, 0x3b, input_parameter, NULL }, + { 0x3c, 0x3f, NULL, &input_state_dcs_ignore }, + { 0x40, 0x7e, NULL, &input_state_dcs_handler }, + { 0x7f, 0xff, NULL, NULL }, + + { -1, -1, NULL, NULL } +}; + +/* dcs_interm state table. */ +const struct input_transition input_state_dcs_intermediate_table[] = { + INPUT_STATE_ANYWHERE, + + { 0x00, 0x17, NULL, NULL }, + { 0x19, 0x19, NULL, NULL }, + { 0x1c, 0x1f, NULL, NULL }, + { 0x20, 0x2f, input_intermediate, NULL }, + { 0x30, 0x3f, NULL, &input_state_dcs_ignore }, + { 0x40, 0x7e, NULL, &input_state_dcs_handler }, + { 0x7f, 0xff, NULL, NULL }, + + { -1, -1, NULL, NULL } +}; + +/* dcs_handler state table. */ +const struct input_transition input_state_dcs_handler_table[] = { + INPUT_STATE_ANYWHERE, + + { 0x00, 0x17, NULL, NULL }, + { 0x19, 0x19, input_input, NULL }, + { 0x1c, 0x1f, input_input, NULL }, + { 0x20, 0x7e, input_input, NULL }, + { 0x7f, 0xff, NULL, NULL }, + + { -1, -1, NULL, NULL } +}; + +/* device_ignore state table. */ +const struct input_transition input_state_dcs_ignore_table[] = { + INPUT_STATE_ANYWHERE, + + { 0x00, 0x17, NULL, NULL }, + { 0x19, 0x19, NULL, NULL }, + { 0x1c, 0x1f, NULL, NULL }, + { 0x20, 0xff, NULL, NULL }, + + { -1, -1, NULL, NULL } +}; + +/* osc_string state table. */ +const struct input_transition input_state_osc_string_table[] = { + INPUT_STATE_ANYWHERE, + + { 0x00, 0x06, NULL, NULL }, + { 0x07, 0x07, NULL, &input_state_ground }, + { 0x08, 0x17, NULL, NULL }, + { 0x19, 0x19, NULL, NULL }, + { 0x1c, 0x1f, NULL, NULL }, + { 0x20, 0xff, input_input, NULL }, + + { -1, -1, NULL, NULL } +}; + +/* apc_string state table. */ +const struct input_transition input_state_apc_string_table[] = { + INPUT_STATE_ANYWHERE, + + { 0x00, 0x17, NULL, NULL }, + { 0x19, 0x19, NULL, NULL }, + { 0x1c, 0x1f, NULL, NULL }, + { 0x20, 0xff, input_input, NULL }, + + { -1, -1, NULL, NULL } +}; + +/* rename_string state table. */ +const struct input_transition input_state_rename_string_table[] = { + INPUT_STATE_ANYWHERE, + + { 0x00, 0x17, NULL, NULL }, + { 0x19, 0x19, NULL, NULL }, + { 0x1c, 0x1f, NULL, NULL }, + { 0x20, 0xff, input_input, NULL }, + + { -1, -1, NULL, NULL } +}; + +/* consume_st state table. */ +const struct input_transition input_state_consume_st_table[] = { + INPUT_STATE_ANYWHERE, + + { 0x00, 0x17, NULL, NULL }, + { 0x19, 0x19, NULL, NULL }, + { 0x1c, 0x1f, NULL, NULL }, + { 0x20, 0xff, NULL, NULL }, + + { -1, -1, NULL, NULL } +}; + +/* utf8_three state table. */ +const struct input_transition input_state_utf8_three_table[] = { + /* No INPUT_STATE_ANYWHERE */ + + { 0x00, 0x7f, NULL, &input_state_ground }, + { 0x80, 0xbf, input_utf8_add, &input_state_utf8_two }, + { 0xc0, 0xff, NULL, &input_state_ground }, + + { -1, -1, NULL, NULL } +}; + +/* utf8_two state table. */ +const struct input_transition input_state_utf8_two_table[] = { + /* No INPUT_STATE_ANYWHERE */ + + { 0x00, 0x7f, NULL, &input_state_ground }, + { 0x80, 0xbf, input_utf8_add, &input_state_utf8_one }, + { 0xc0, 0xff, NULL, &input_state_ground }, + + { -1, -1, NULL, NULL } +}; + +/* utf8_one state table. */ +const struct input_transition input_state_utf8_one_table[] = { + /* No INPUT_STATE_ANYWHERE */ + + { 0x00, 0x7f, NULL, &input_state_ground }, + { 0x80, 0xbf, input_utf8_close, &input_state_ground }, + { 0xc0, 0xff, NULL, &input_state_ground }, + + { -1, -1, NULL, NULL } +}; + +/* Input table compare. */ int -input_sequence_cmp(const void *a, const void *b) +input_table_compare(const void *key, const void *value) { - int ai = ((const struct input_sequence_entry *) a)->ch; - int bi = ((const struct input_sequence_entry *) b)->ch; + const struct input_ctx *ictx = key; + const struct input_table_entry *entry = value; - return (ai - bi); -} - -void -input_new_argument(struct input_ctx *ictx) -{ - struct input_arg *arg; - - ARRAY_EXPAND(&ictx->args, 1); - - arg = &ARRAY_LAST(&ictx->args); - arg->used = 0; -} - -int -input_add_argument(struct input_ctx *ictx, u_char ch) -{ - struct input_arg *arg; - - if (ARRAY_LENGTH(&ictx->args) == 0) - return (0); - - arg = &ARRAY_LAST(&ictx->args); - if (arg->used > (sizeof arg->data) - 1) - return (-1); - arg->data[arg->used++] = ch; - - return (0); -} - -int -input_get_argument(struct input_ctx *ictx, u_int i, uint16_t *n, uint16_t d) -{ - struct input_arg *arg; - const char *errstr; - - *n = d; - if (i >= ARRAY_LENGTH(&ictx->args)) - return (0); - - arg = &ARRAY_ITEM(&ictx->args, i); - if (*arg->data == '\0') - return (0); - - *n = strtonum(arg->data, 0, UINT16_MAX, &errstr); - if (errstr != NULL) - return (-1); - return (0); -} - -void -input_start_string(struct input_ctx *ictx, int type) -{ - ictx->string_type = type; - ictx->string_len = 0; -} - -void -input_abort_string(struct input_ctx *ictx) -{ - if (ictx->string_buf != NULL) - xfree(ictx->string_buf); - ictx->string_buf = NULL; -} - -int -input_add_string(struct input_ctx *ictx, u_char ch) -{ - ictx->string_buf = xrealloc(ictx->string_buf, 1, ictx->string_len + 1); - ictx->string_buf[ictx->string_len++] = ch; - - if (ictx->string_len >= MAXSTRINGLEN) { - input_abort_string(ictx); - return (1); - } - - return (0); -} - -char * -input_get_string(struct input_ctx *ictx) -{ - char *s; - - if (ictx->string_buf == NULL || input_add_string(ictx, '\0') != 0) - return (xstrdup("")); - - s = ictx->string_buf; - ictx->string_buf = NULL; - return (s); -} - -void -input_state(struct input_ctx *ictx, void *state) -{ - ictx->state = state; + if (ictx->ch != entry->ch) + return (ictx->ch - entry->ch); + return (strcmp(ictx->interm_buf, entry->interm)); } +/* Initialise input parser. */ void input_init(struct window_pane *wp) { struct input_ctx *ictx = &wp->ictx; - ARRAY_INIT(&ictx->args); - - ictx->string_len = 0; - ictx->string_buf = NULL; - memcpy(&ictx->cell, &grid_default_cell, sizeof ictx->cell); - memcpy(&ictx->saved_cell, &grid_default_cell, sizeof ictx->saved_cell); - ictx->saved_cx = 0; - ictx->saved_cy = 0; + memcpy(&ictx->old_cell, &grid_default_cell, sizeof ictx->old_cell); + ictx->old_cx = 0; + ictx->old_cy = 0; - input_state(ictx, input_state_first); + *ictx->interm_buf = '\0'; + ictx->interm_len = 0; - ictx->was = 0; + *ictx->param_buf = '\0'; + ictx->param_len = 0; + + ictx->state = &input_state_ground; + ictx->flags = 0; } +/* Destroy input parser. */ void -input_free(struct window_pane *wp) +input_free(unused struct window_pane *wp) { - if (wp->ictx.string_buf != NULL) - xfree(wp->ictx.string_buf); - - ARRAY_FREE(&wp->ictx.args); } +/* Parse input. */ void input_parse(struct window_pane *wp) { - struct input_ctx *ictx = &wp->ictx; - u_char ch; + struct input_ctx *ictx = &wp->ictx; + const struct input_transition *itr; + struct evbuffer *evb = wp->event->input; + u_char *buf; + size_t len, off; - if (EVBUFFER_LENGTH(wp->event->input) == ictx->was) + if (EVBUFFER_LENGTH(evb) == 0) return; wp->window->flags |= WINDOW_ACTIVITY; - ictx->buf = EVBUFFER_DATA(wp->event->input); - ictx->len = EVBUFFER_LENGTH(wp->event->input); - ictx->off = 0; - - ictx->wp = wp; - - /* If there is a mode set, don't want to update the screen. */ + /* + * Open the screen. Use NULL wp if there is a mode set as don't want to + * update the tty. + */ if (wp->mode == NULL) screen_write_start(&ictx->ctx, wp, &wp->base); else screen_write_start(&ictx->ctx, NULL, &wp->base); + ictx->wp = wp; - while (ictx->off < ictx->len) { - ch = ictx->buf[ictx->off++]; - ictx->state(ch, ictx); - } + buf = EVBUFFER_DATA(evb); + len = EVBUFFER_LENGTH(evb); + off = 0; - screen_write_stop(&ictx->ctx); + /* Parse the input. */ + while (off < len) { + ictx->ch = buf[off++]; + log_debug("%s: '%c' %s", __func__, ictx->ch, ictx->state->name); - evbuffer_drain(wp->event->input, ictx->len); - ictx->was = EVBUFFER_LENGTH(wp->event->input); -} - -void -input_state_first(u_char ch, struct input_ctx *ictx) -{ - ictx->intermediate = '\0'; - - if (INPUT_C0CONTROL(ch)) { - if (ch == 0x1b) - input_state(ictx, input_state_escape); - else - input_handle_c0_control(ch, ictx); - return; - } - -#if 0 - if (INPUT_C1CONTROL(ch)) { - ch -= 0x40; - if (ch == '[') - input_state(ictx, input_state_sequence_first); - else if (ch == ']') { - input_start_string(ictx, STRING_SYSTEM); - input_state(ictx, input_state_string_next); - } else if (ch == '_') { - input_start_string(ictx, STRING_APPLICATION); - input_state(ictx, input_state_string_next); - } else - input_handle_c1_control(ch, ictx); - return; - } -#endif - - if (INPUT_DELETE(ch)) - return; - - input_handle_character(ch, ictx); -} - -void -input_state_escape(u_char ch, struct input_ctx *ictx) -{ - /* Treat C1 control and G1 displayable as 7-bit equivalent. */ - if (INPUT_C1CONTROL(ch) || INPUT_G1DISPLAYABLE(ch)) - ch &= 0x7f; - - if (INPUT_C0CONTROL(ch)) { - input_handle_c0_control(ch, ictx); - return; - } - - if (INPUT_INTERMEDIATE(ch)) { - log_debug2(":: in1 %zu: %hhu (%c)", ictx->off, ch, ch); - ictx->intermediate = ch; - input_state(ictx, input_state_intermediate); - return; - } - - if (INPUT_PARAMETER(ch)) { - input_state(ictx, input_state_first); - input_handle_private_two(ch, ictx); - return; - } - - if (INPUT_UPPERCASE(ch)) { - if (ch == '[') - input_state(ictx, input_state_sequence_first); - else if (ch == ']') { - input_start_string(ictx, STRING_SYSTEM); - input_state(ictx, input_state_string_next); - } else if (ch == '_') { - input_start_string(ictx, STRING_APPLICATION); - input_state(ictx, input_state_string_next); - } else { - input_state(ictx, input_state_first); - input_handle_c1_control(ch, ictx); + /* Find the transition. */ + itr = ictx->state->transitions; + while (itr->first != -1 && itr->last != -1) { + if (ictx->ch >= itr->first && ictx->ch <= itr->last) + break; + itr++; } - return; - } - - if (INPUT_LOWERCASE(ch)) { - input_state(ictx, input_state_first); - input_handle_standard_two(ch, ictx); - return; - } - - input_state(ictx, input_state_first); -} - -void -input_state_intermediate(u_char ch, struct input_ctx *ictx) -{ - if (INPUT_INTERMEDIATE(ch)) { - /* Multiple intermediates currently ignored. */ - log_debug2(":: in2 %zu: %hhu (%c)", ictx->off, ch, ch); - return; - } - - if (INPUT_PARAMETER(ch)) { - input_state(ictx, input_state_first); - input_handle_private_two(ch, ictx); - return; - } - - if (INPUT_UPPERCASE(ch) || INPUT_LOWERCASE(ch)) { - input_state(ictx, input_state_first); - input_handle_standard_two(ch, ictx); - return; - } - - input_state(ictx, input_state_first); -} - -void -input_state_sequence_first(u_char ch, struct input_ctx *ictx) -{ - ictx->private = '\0'; - ARRAY_CLEAR(&ictx->args); - - /* Most C0 control are accepted within CSI. */ - if (INPUT_C0CONTROL(ch)) { - if (ch == 0x1b) { /* ESC */ - /* Abort sequence and begin with new. */ - input_state(ictx, input_state_escape); - return; - } else if (ch == 0x18 || ch == 0x1a) { /* CAN and SUB */ - /* Abort sequence. */ - input_state(ictx, input_state_first); - return; + if (itr->first == -1 || itr->last == -1) { + /* No transition? Eh? */ + fatalx("No transition from state!"); } - /* Handle C0 immediately. */ - input_handle_c0_control(ch, ictx); - /* - * Just come back to this state, in case the next character - * is the start of a private sequence. + * Execute the handler, if any. Don't switch state if it + * returns non-zero. */ - return; + if (itr->handler && itr->handler(ictx) != 0) + continue; + + /* And switch state, if necessary. */ + if (itr->state) { + if (ictx->state->exit != NULL) + ictx->state->exit(ictx); + ictx->state = itr->state; + if (ictx->state->enter != NULL) + ictx->state->enter(ictx); + } } - input_state(ictx, input_state_sequence_next); + /* Close the screen. */ + screen_write_stop(&ictx->ctx); - /* Private sequence: always the first character. */ - if (ch >= 0x3c && ch <= 0x3f) { - ictx->private = ch; - return; - } - - /* Pass character on directly. */ - input_state_sequence_next(ch, ictx); + evbuffer_drain(evb, len); } -void -input_state_sequence_next(u_char ch, struct input_ctx *ictx) +/* Split the parameter list (if any). */ +int +input_split(struct input_ctx *ictx) + { - if (INPUT_INTERMEDIATE(ch)) { - if (input_add_argument(ictx, '\0') != 0) - input_state(ictx, input_state_first); + const char *errstr; + char *ptr, *out; + int n; + + ictx->param_list_len = 0; + if (ictx->param_len == 0) + return (0); + + ptr = ictx->param_buf; + while ((out = strsep(&ptr, ";")) != NULL) { + if (*out == '\0') + n = -1; else { - log_debug2(":: si1 %zu: %hhu (%c)", ictx->off, ch, ch); - input_state(ictx, input_state_sequence_intermediate); - } - return; - } - - if (INPUT_PARAMETER(ch)) { - if (ARRAY_EMPTY(&ictx->args)) - input_new_argument(ictx); - - if (ch == ';') { - if (input_add_argument(ictx, '\0') != 0) - input_state(ictx, input_state_first); - else - input_new_argument(ictx); - } else if (input_add_argument(ictx, ch) != 0) - input_state(ictx, input_state_first); - return; - } - - if (INPUT_UPPERCASE(ch) || INPUT_LOWERCASE(ch)) { - if (input_add_argument(ictx, '\0') != 0) - input_state(ictx, input_state_first); - else { - input_state(ictx, input_state_first); - input_handle_sequence(ch, ictx); - } - return; - } - - /* Most C0 control are accepted within CSI. */ - if (INPUT_C0CONTROL(ch)) { - if (ch == 0x1b) { /* ESC */ - /* Abort sequence and begin with new. */ - input_state(ictx, input_state_escape); - return; - } else if (ch == 0x18 || ch == 0x1a) { /* CAN and SUB */ - /* Abort sequence. */ - input_state(ictx, input_state_first); - return; + n = strtonum(out, 0, INT_MAX, &errstr); + if (errstr != NULL) + return (-1); } - /* Handle C0 immediately. */ - input_handle_c0_control(ch, ictx); - - return; + ictx->param_list[ictx->param_list_len++] = n; + if (ictx->param_list_len == nitems(ictx->param_list)) + return (-1); } - input_state(ictx, input_state_first); + return (0); } -void -input_state_sequence_intermediate(u_char ch, struct input_ctx *ictx) +/* Get an argument or return default value..*/ +int +input_get(struct input_ctx *ictx, u_int validx, int minval, int defval) { - if (INPUT_INTERMEDIATE(ch)) { - log_debug2(":: si2 %zu: %hhu (%c)", ictx->off, ch, ch); - return; - } + int retval; - if (INPUT_UPPERCASE(ch) || INPUT_LOWERCASE(ch)) { - input_state(ictx, input_state_first); - input_handle_sequence(ch, ictx); - return; - } + if (validx >= ictx->param_list_len) + return (defval); - input_state(ictx, input_state_first); + retval = ictx->param_list[validx]; + if (retval == -1) + return (defval); + if (retval < minval) + return (minval); + return (retval); } +/* Reply to terminal query. */ void -input_state_string_next(u_char ch, struct input_ctx *ictx) +input_reply(struct input_ctx *ictx, const char *fmt, ...) { - if (ch == 0x1b) { - input_state(ictx, input_state_string_escape); - return; - } - if (ch == 0x07) { - input_state_string_escape(ch, ictx); - return; - } + va_list ap; + char *reply; - if (ch >= 0x20) { - if (input_add_string(ictx, ch) != 0) - input_state(ictx, input_state_first); - return; - } + va_start(ap, fmt); + vasprintf(&reply, fmt, ap); + va_end(ap); + + bufferevent_write(ictx->wp->event, reply, strlen(reply)); + xfree(reply); } +/* Clear saved state. */ void -input_state_string_escape(u_char ch, struct input_ctx *ictx) +input_clear(struct input_ctx *ictx) { - char *s; + *ictx->interm_buf = '\0'; + ictx->interm_len = 0; - if (ch == '\007' || ch == '\\') { - input_state(ictx, input_state_first); - switch (ictx->string_type) { - case STRING_SYSTEM: - if (ch != '\007') - return; - s = input_get_string(ictx); - if ((s[0] != '0' && s[0] != '2') || s[1] != ';') { - xfree(s); - return; - } - screen_set_title(ictx->ctx.s, s + 2); - server_status_window(ictx->wp->window); - xfree(s); - break; - case STRING_APPLICATION: - if (ch != '\\') - return; - s = input_get_string(ictx); - screen_set_title(ictx->ctx.s, s); - server_status_window(ictx->wp->window); - xfree(s); - break; - case STRING_NAME: - if (ch != '\\') - return; - xfree(ictx->wp->window->name); - ictx->wp->window->name = input_get_string(ictx); - server_status_window(ictx->wp->window); - break; - } - return; - } + *ictx->param_buf = '\0'; + ictx->param_len = 0; - input_state(ictx, input_state_string_next); - input_state_string_next(ch, ictx); + ictx->flags &= ~INPUT_DISCARD; } -void -input_state_utf8(u_char ch, struct input_ctx *ictx) +/* Output this character to the screen. */ +int +input_print(struct input_ctx *ictx) { - log_debug2("-- utf8 next: %zu: %hhu (%c)", ictx->off, ch, ch); - - if (utf8_append(&ictx->utf8data, ch)) - return; /* more to come */ - input_state(ictx, input_state_first); - - ictx->cell.flags |= GRID_FLAG_UTF8; - screen_write_cell(&ictx->ctx, &ictx->cell, &ictx->utf8data); - ictx->cell.flags &= ~GRID_FLAG_UTF8; -} - -void -input_handle_character(u_char ch, struct input_ctx *ictx) -{ - struct window_pane *wp = ictx->wp; - - if (ch > 0x7f && options_get_number(&wp->window->options, "utf8")) { - if (utf8_open(&ictx->utf8data, ch)) { - log_debug2("-- utf8 size %zu: %zu: %hhu (%c)", - ictx->utf8data.size, ictx->off, ch, ch); - input_state(ictx, input_state_utf8); - return; - } - } - log_debug2("-- ch %zu: %hhu (%c)", ictx->off, ch, ch); - - ictx->cell.data = ch; + ictx->cell.data = ictx->ch; screen_write_cell(&ictx->ctx, &ictx->cell, NULL); + + return (0); } -void -input_handle_c0_control(u_char ch, struct input_ctx *ictx) +/* Collect intermediate string. */ +int +input_intermediate(struct input_ctx *ictx) { - struct screen *s = ictx->ctx.s; + if (ictx->interm_len == (sizeof ictx->interm_buf) - 1) + ictx->flags |= INPUT_DISCARD; + else { + ictx->interm_buf[ictx->interm_len++] = ictx->ch; + ictx->interm_buf[ictx->interm_len] = '\0'; + } - log_debug2("-- c0 %zu: %hhu", ictx->off, ch); + return (0); +} - switch (ch) { - case '\0': /* NUL */ +/* Collect parameter string. */ +int +input_parameter(struct input_ctx *ictx) +{ + if (ictx->param_len == (sizeof ictx->param_buf) - 1) + ictx->flags |= INPUT_DISCARD; + else { + ictx->param_buf[ictx->param_len++] = ictx->ch; + ictx->param_buf[ictx->param_len] = '\0'; + } + + return (0); +} + +/* Collect input string. */ +int +input_input(struct input_ctx *ictx) +{ + if (ictx->input_len == (sizeof ictx->input_buf) - 1) + ictx->flags |= INPUT_DISCARD; + else { + ictx->input_buf[ictx->input_len++] = ictx->ch; + ictx->input_buf[ictx->input_len] = '\0'; + } + + return (0); +} + +/* Execute C0 control sequence. */ +int +input_c0_dispatch(struct input_ctx *ictx) +{ + struct screen_write_ctx *sctx = &ictx->ctx; + struct window_pane *wp = ictx->wp; + struct screen *s = sctx->s; + + log_debug("%s: '%c", __func__, ictx->ch); + + switch (ictx->ch) { + case '\000': /* NUL */ break; - case '\n': /* LF */ - screen_write_linefeed(&ictx->ctx, 0); + case '\007': /* BEL */ + wp->window->flags |= WINDOW_BELL; break; - case '\r': /* CR */ - screen_write_carriagereturn(&ictx->ctx); + case '\010': /* BS */ + screen_write_backspace(sctx); break; - case '\007': /* BELL */ - ictx->wp->window->flags |= WINDOW_BELL; - break; - case '\010': /* BS */ - screen_write_backspace(&ictx->ctx); - break; - case '\011': /* TAB */ + case '\011': /* HT */ /* Don't tab beyond the end of the line. */ if (s->cx >= screen_size_x(s) - 1) break; @@ -637,8 +896,13 @@ input_handle_c0_control(u_char ch, struct input_ctx *ictx) break; } while (s->cx < screen_size_x(s) - 1); break; + case '\012': /* LF */ case '\013': /* VT */ - screen_write_linefeed(&ictx->ctx, 0); + case '\014': /* FF */ + screen_write_linefeed(sctx, 0); + break; + case '\015': /* CR */ + screen_write_carriagereturn(sctx); break; case '\016': /* SO */ ictx->cell.attr |= GRID_ATTR_CHARSET; @@ -647,601 +911,240 @@ input_handle_c0_control(u_char ch, struct input_ctx *ictx) ictx->cell.attr &= ~GRID_ATTR_CHARSET; break; default: - log_debug("unknown c0: %hhu", ch); + log_debug("%s: unknown '%c'", __func__, ictx->ch); break; } + + return (0); } -void -input_handle_c1_control(u_char ch, struct input_ctx *ictx) +/* Execute escape sequence. */ +int +input_esc_dispatch(struct input_ctx *ictx) { - struct screen *s = ictx->ctx.s; + struct screen_write_ctx *sctx = &ictx->ctx; + struct screen *s = sctx->s; + struct input_table_entry *entry; - log_debug2("-- c1 %zu: %hhu (%c)", ictx->off, ch, ch); + if (ictx->flags & INPUT_DISCARD) + return (0); + log_debug("%s: '%c', %s", __func__, ictx->ch, ictx->interm_buf); - switch (ch) { - case 'D': /* IND */ - screen_write_linefeed(&ictx->ctx, 0); + entry = bsearch(ictx, input_esc_table, nitems(input_esc_table), + sizeof input_esc_table[0], input_table_compare); + if (entry == NULL) { + log_debug("%s: unknown '%c'", __func__, ictx->ch); + return (0); + } + + switch (entry->type) { + case INPUT_ESC_RIS: + memcpy(&ictx->cell, &grid_default_cell, sizeof ictx->cell); + memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell); + ictx->old_cx = 0; + ictx->old_cy = 0; + + screen_reset_tabs(sctx->s); + + screen_write_scrollregion(sctx, 0, screen_size_y(sctx->s) - 1); + + screen_write_insertmode(sctx, 0); + screen_write_kcursormode(sctx, 0); + screen_write_kkeypadmode(sctx, 0); + screen_write_mousemode(sctx, 0); + + screen_write_clearscreen(sctx); + screen_write_cursormove(sctx, 0, 0); break; - case 'E': /* NEL */ - screen_write_carriagereturn(&ictx->ctx); - screen_write_linefeed(&ictx->ctx, 0); + case INPUT_ESC_IND: + screen_write_linefeed(sctx, 0); break; - case 'H': /* HTS */ + case INPUT_ESC_NEL: + screen_write_carriagereturn(sctx); + screen_write_linefeed(sctx, 0); + break; + case INPUT_ESC_HTS: if (s->cx < screen_size_x(s)) bit_set(s->tabs, s->cx); break; - case 'M': /* RI */ - screen_write_reverseindex(&ictx->ctx); + case INPUT_ESC_RI: + screen_write_reverseindex(sctx); break; - default: - log_debug("unknown c1: %hhu", ch); + case INPUT_ESC_DECKPAM: + screen_write_kkeypadmode(sctx, 1); break; - } -} - -void -input_handle_private_two(u_char ch, struct input_ctx *ictx) -{ - struct screen *s = ictx->ctx.s; - - log_debug2( - "-- p2 %zu: %hhu (%c) %hhu", ictx->off, ch, ch, ictx->intermediate); - - switch (ch) { - case '0': /* SCS */ + case INPUT_ESC_DECKPNM: + screen_write_kkeypadmode(sctx, 0); + break; + case INPUT_ESC_DECSC: + memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell); + ictx->old_cx = s->cx; + ictx->old_cy = s->cy; + break; + case INPUT_ESC_DECRC: + memcpy(&ictx->cell, &ictx->old_cell, sizeof ictx->cell); + screen_write_cursormove(sctx, ictx->old_cx, ictx->old_cy); + break; + case INPUT_ESC_DECALN: + screen_write_alignmenttest(sctx); + break; + case INPUT_ESC_SCSON_G0: /* * Not really supported, but fake it up enough for those that * use it to switch character sets (by redefining G0 to * graphics set, rather than switching to G1). */ - switch (ictx->intermediate) { - case '(': /* G0 */ - ictx->cell.attr |= GRID_ATTR_CHARSET; - break; + ictx->cell.attr &= ~GRID_ATTR_CHARSET; + break; + case INPUT_ESC_SCSOFF_G0: + ictx->cell.attr |= GRID_ATTR_CHARSET; + break; + } + + return (0); +} + +/* Execute control sequence. */ +int +input_csi_dispatch(struct input_ctx *ictx) +{ + struct screen_write_ctx *sctx = &ictx->ctx; + struct window_pane *wp = ictx->wp; + struct screen *s = sctx->s; + struct input_table_entry *entry; + int n, m; + + if (ictx->flags & INPUT_DISCARD) + return (0); + if (input_split(ictx) != 0) + return (0); + log_debug("%s: '%c' \"%s\" \"%s\"", + __func__, ictx->ch, ictx->interm_buf, ictx->param_buf); + + entry = bsearch(ictx, input_csi_table, nitems(input_csi_table), + sizeof input_csi_table[0], input_table_compare); + if (entry == NULL) { + log_debug("%s: unknown '%c'", __func__, ictx->ch); + return (0); + } + + switch (entry->type) { + case INPUT_CSI_CBT: + /* Find the previous tab point, n times. */ + n = input_get(ictx, 0, 1, 1); + while (s->cx > 0 && n-- > 0) { + do + s->cx--; + while (s->cx > 0 && !bit_test(s->tabs, s->cx)); } break; - case '=': /* DECKPAM */ - if (ictx->intermediate != '\0') - break; - screen_write_kkeypadmode(&ictx->ctx, 1); - log_debug("kkeypad on (application mode)"); + case INPUT_CSI_CUB: + screen_write_cursorleft(sctx, input_get(ictx, 0, 1, 1)); break; - case '>': /* DECKPNM */ - if (ictx->intermediate != '\0') - break; - screen_write_kkeypadmode(&ictx->ctx, 0); - log_debug("kkeypad off (number mode)"); + case INPUT_CSI_CUD: + screen_write_cursordown(sctx, input_get(ictx, 0, 1, 1)); break; - case '7': /* DECSC */ - if (ictx->intermediate != '\0') - break; - memcpy(&ictx->saved_cell, &ictx->cell, sizeof ictx->saved_cell); - ictx->saved_cx = s->cx; - ictx->saved_cy = s->cy; + case INPUT_CSI_CUF: + screen_write_cursorright(sctx, input_get(ictx, 0, 1, 1)); break; - case '8': - switch (ictx->intermediate) { - case '\0': /* DECRC */ - memcpy( - &ictx->cell, &ictx->saved_cell, sizeof ictx->cell); - screen_write_cursormove( - &ictx->ctx, ictx->saved_cx, ictx->saved_cy); - break; - case '#': /* DECALN */ - screen_write_alignmenttest(&ictx->ctx); - break; - } + case INPUT_CSI_CUP: + n = input_get(ictx, 0, 1, 1); + m = input_get(ictx, 1, 1, 1); + screen_write_cursormove(sctx, m - 1, n - 1); break; - default: - log_debug("unknown p2: %hhu", ch); + case INPUT_CSI_CUU: + screen_write_cursorup(sctx, input_get(ictx, 0, 1, 1)); break; - } -} - -void -input_handle_standard_two(u_char ch, struct input_ctx *ictx) -{ - log_debug2( - "-- s2 %zu: %hhu (%c) %hhu", ictx->off, ch, ch, ictx->intermediate); - - switch (ch) { - case 'B': /* SCS */ - /* - * Not really supported, but fake it up enough for those that - * use it to switch character sets (by redefining G0 to - * graphics set, rather than switching to G1). - */ - switch (ictx->intermediate) { - case '(': /* G0 */ - ictx->cell.attr &= ~GRID_ATTR_CHARSET; - break; - } - break; - case 'c': /* RIS */ - memcpy(&ictx->cell, &grid_default_cell, sizeof ictx->cell); - - memcpy(&ictx->saved_cell, &ictx->cell, sizeof ictx->saved_cell); - ictx->saved_cx = 0; - ictx->saved_cy = 0; - - screen_reset_tabs(ictx->ctx.s); - - screen_write_scrollregion( - &ictx->ctx, 0, screen_size_y(ictx->ctx.s) - 1); - - screen_write_insertmode(&ictx->ctx, 0); - screen_write_kcursormode(&ictx->ctx, 0); - screen_write_kkeypadmode(&ictx->ctx, 0); - screen_write_mousemode(&ictx->ctx, 0); - - screen_write_clearscreen(&ictx->ctx); - screen_write_cursormove(&ictx->ctx, 0, 0); - break; - case 'k': - input_start_string(ictx, STRING_NAME); - input_state(ictx, input_state_string_next); - break; - default: - log_debug("unknown s2: %hhu", ch); - break; - } -} - -void -input_handle_sequence(u_char ch, struct input_ctx *ictx) -{ - struct input_sequence_entry *entry, find; - struct screen *s = ictx->ctx.s; - u_int i; - struct input_arg *iarg; - - log_debug2("-- sq %zu: %hhu (%c): %u [sx=%u, sy=%u, cx=%u, cy=%u, " - "ru=%u, rl=%u]", ictx->off, ch, ch, ARRAY_LENGTH(&ictx->args), - screen_size_x(s), screen_size_y(s), s->cx, s->cy, s->rupper, - s->rlower); - for (i = 0; i < ARRAY_LENGTH(&ictx->args); i++) { - iarg = &ARRAY_ITEM(&ictx->args, i); - if (*iarg->data != '\0') - log_debug2(" ++ %u: %s", i, iarg->data); - } - - find.ch = ch; - entry = bsearch(&find, - input_sequence_table, nitems(input_sequence_table), - sizeof input_sequence_table[0], input_sequence_cmp); - if (entry != NULL) - entry->fn(ictx); - else - log_debug("unknown sq: %c (%hhu %hhu)", ch, ch, ictx->private); -} - -void -input_handle_sequence_cuu(struct input_ctx *ictx) -{ - uint16_t n; - - if (ictx->private != '\0') - return; - - if (ARRAY_LENGTH(&ictx->args) > 1) - return; - if (input_get_argument(ictx, 0, &n, 1) != 0) - return; - if (n == 0) - n = 1; - - screen_write_cursorup(&ictx->ctx, n); -} - -void -input_handle_sequence_cud(struct input_ctx *ictx) -{ - uint16_t n; - - if (ictx->private != '\0') - return; - - if (ARRAY_LENGTH(&ictx->args) > 1) - return; - if (input_get_argument(ictx, 0, &n, 1) != 0) - return; - if (n == 0) - n = 1; - - screen_write_cursordown(&ictx->ctx, n); -} - -void -input_handle_sequence_cuf(struct input_ctx *ictx) -{ - uint16_t n; - - if (ictx->private != '\0') - return; - - if (ARRAY_LENGTH(&ictx->args) > 1) - return; - if (input_get_argument(ictx, 0, &n, 1) != 0) - return; - if (n == 0) - n = 1; - - screen_write_cursorright(&ictx->ctx, n); -} - -void -input_handle_sequence_cub(struct input_ctx *ictx) -{ - uint16_t n; - - if (ictx->private != '\0') - return; - - if (ARRAY_LENGTH(&ictx->args) > 1) - return; - if (input_get_argument(ictx, 0, &n, 1) != 0) - return; - if (n == 0) - n = 1; - - screen_write_cursorleft(&ictx->ctx, n); -} - -void -input_handle_sequence_dch(struct input_ctx *ictx) -{ - uint16_t n; - - if (ictx->private != '\0') - return; - - if (ARRAY_LENGTH(&ictx->args) > 1) - return; - if (input_get_argument(ictx, 0, &n, 1) != 0) - return; - if (n == 0) - n = 1; - - screen_write_deletecharacter(&ictx->ctx, n); -} - -void -input_handle_sequence_cbt(struct input_ctx *ictx) -{ - struct screen *s = ictx->ctx.s; - uint16_t n; - - if (ictx->private != '\0') - return; - - if (ARRAY_LENGTH(&ictx->args) > 1) - return; - if (input_get_argument(ictx, 0, &n, 1) != 0) - return; - if (n == 0) - n = 1; - - /* Find the previous tab point, n times. */ - while (s->cx > 0 && n-- > 0) { - do - s->cx--; - while (s->cx > 0 && !bit_test(s->tabs, s->cx)); - } -} - -void -input_handle_sequence_da(struct input_ctx *ictx) -{ - struct window_pane *wp = ictx->wp; - uint16_t n; - - if (ictx->private != '\0') - return; - - if (ARRAY_LENGTH(&ictx->args) > 1) - return; - if (input_get_argument(ictx, 0, &n, 0) != 0) - return; - if (n != 0) - return; - - bufferevent_write(wp->event, "\033[?1;2c", (sizeof "\033[?1;2c") - 1); -} - -void -input_handle_sequence_dl(struct input_ctx *ictx) -{ - uint16_t n; - - if (ictx->private != '\0') - return; - - if (ARRAY_LENGTH(&ictx->args) > 1) - return; - if (input_get_argument(ictx, 0, &n, 1) != 0) - return; - if (n == 0) - n = 1; - - screen_write_deleteline(&ictx->ctx, n); -} - -void -input_handle_sequence_ich(struct input_ctx *ictx) -{ - uint16_t n; - - if (ictx->private != '\0') - return; - - if (ARRAY_LENGTH(&ictx->args) > 1) - return; - if (input_get_argument(ictx, 0, &n, 1) != 0) - return; - if (n == 0) - n = 1; - - screen_write_insertcharacter(&ictx->ctx, n); -} - -void -input_handle_sequence_il(struct input_ctx *ictx) -{ - uint16_t n; - - if (ictx->private != '\0') - return; - - if (ARRAY_LENGTH(&ictx->args) > 1) - return; - if (input_get_argument(ictx, 0, &n, 1) != 0) - return; - if (n == 0) - n = 1; - - screen_write_insertline(&ictx->ctx, n); -} - -void -input_handle_sequence_vpa(struct input_ctx *ictx) -{ - struct screen *s = ictx->ctx.s; - uint16_t n; - - if (ictx->private != '\0') - return; - - if (ARRAY_LENGTH(&ictx->args) > 1) - return; - if (input_get_argument(ictx, 0, &n, 1) != 0) - return; - if (n == 0) - n = 1; - - screen_write_cursormove(&ictx->ctx, s->cx, n - 1); -} - -void -input_handle_sequence_hpa(struct input_ctx *ictx) -{ - struct screen *s = ictx->ctx.s; - uint16_t n; - - if (ictx->private != '\0') - return; - - if (ARRAY_LENGTH(&ictx->args) > 1) - return; - if (input_get_argument(ictx, 0, &n, 1) != 0) - return; - if (n == 0) - n = 1; - - screen_write_cursormove(&ictx->ctx, n - 1, s->cy); -} - -void -input_handle_sequence_cup(struct input_ctx *ictx) -{ - uint16_t n, m; - - if (ictx->private != '\0') - return; - - if (ARRAY_LENGTH(&ictx->args) > 2) - return; - if (input_get_argument(ictx, 0, &n, 1) != 0) - return; - if (input_get_argument(ictx, 1, &m, 1) != 0) - return; - if (n == 0) - n = 1; - if (m == 0) - m = 1; - - screen_write_cursormove(&ictx->ctx, m - 1, n - 1); -} - -void -input_handle_sequence_tbc(struct input_ctx *ictx) -{ - struct screen *s = ictx->ctx.s; - uint16_t n; - - if (ictx->private != '\0') - return; - - if (ARRAY_LENGTH(&ictx->args) > 1) - return; - if (input_get_argument(ictx, 0, &n, 1) != 0) - return; - - switch (n) { - case 0: - if (s->cx < screen_size_x(s)) - bit_clear(s->tabs, s->cx); - break; - case 3: - bit_nclear(s->tabs, 0, screen_size_x(s) - 1); - break; - } -} - -void -input_handle_sequence_ed(struct input_ctx *ictx) -{ - uint16_t n; - - if (ictx->private != '\0') - return; - - if (ARRAY_LENGTH(&ictx->args) > 1) - return; - if (input_get_argument(ictx, 0, &n, 0) != 0) - return; - if (n > 2) - return; - - switch (n) { - case 0: - screen_write_clearendofscreen(&ictx->ctx); - break; - case 1: - screen_write_clearstartofscreen(&ictx->ctx); - break; - case 2: - screen_write_clearscreen(&ictx->ctx); - break; - } -} - -void -input_handle_sequence_el(struct input_ctx *ictx) -{ - uint16_t n; - - if (ictx->private != '\0') - return; - - if (ARRAY_LENGTH(&ictx->args) > 1) - return; - if (input_get_argument(ictx, 0, &n, 0) != 0) - return; - if (n > 2) - return; - - switch (n) { - case 0: - screen_write_clearendofline(&ictx->ctx); - break; - case 1: - screen_write_clearstartofline(&ictx->ctx); - break; - case 2: - screen_write_clearline(&ictx->ctx); - break; - } -} - -void -input_handle_sequence_sm(struct input_ctx *ictx) -{ - struct window_pane *wp = ictx->wp; - struct options *oo = &wp->window->options; - struct screen *s = &wp->base; - u_int sx, sy; - uint16_t n; - - if (ARRAY_LENGTH(&ictx->args) > 1) - return; - if (input_get_argument(ictx, 0, &n, 0) != 0) - return; - - if (ictx->private == '?') { - switch (n) { - case 1: /* GATM */ - screen_write_kcursormode(&ictx->ctx, 1); - log_debug("kcursor on"); - break; - case 3: /* DECCOLM */ - screen_write_cursormove(&ictx->ctx, 0, 0); - screen_write_clearscreen(&ictx->ctx); - break; - case 25: /* TCEM */ - screen_write_cursormode(&ictx->ctx, 1); - log_debug("cursor on"); - break; - case 1000: - screen_write_mousemode(&ictx->ctx, 1); - log_debug("mouse on"); - break; - case 1049: - if (wp->saved_grid != NULL) - break; - if (!options_get_number(oo, "alternate-screen")) - break; - sx = screen_size_x(s); - sy = screen_size_y(s); - - /* - * Enter alternative screen mode. A copy of the visible - * screen is saved and the history is not updated - */ - - wp->saved_grid = grid_create(sx, sy, 0); - grid_duplicate_lines( - wp->saved_grid, 0, s->grid, screen_hsize(s), sy); - wp->saved_cx = s->cx; - wp->saved_cy = s->cy; - memcpy(&wp->saved_cell, - &ictx->cell, sizeof wp->saved_cell); - - grid_view_clear(s->grid, 0, 0, sx, sy); - - wp->base.grid->flags &= ~GRID_HISTORY; - - wp->flags |= PANE_REDRAW; + case INPUT_CSI_DA: + switch (input_get(ictx, 0, 0, 0)) { + case 0: + input_reply(ictx, "\033[?1;2c"); break; default: - log_debug("unknown SM [%hhu]: %u", ictx->private, n); + log_debug("%s: unknown '%c'", __func__, ictx->ch); break; } - } else { - switch (n) { + break; + case INPUT_CSI_DCH: + screen_write_deletecharacter(sctx, input_get(ictx, 0, 1, 1)); + break; + case INPUT_CSI_DECSTBM: + n = input_get(ictx, 0, 1, 1); + m = input_get(ictx, 1, 1, screen_size_y(s)); + screen_write_scrollregion(sctx, n - 1, m - 1); + break; + case INPUT_CSI_DL: + screen_write_deleteline(sctx, input_get(ictx, 0, 1, 1)); + break; + case INPUT_CSI_DSR: + switch (input_get(ictx, 0, 0, 0)) { + case 5: + input_reply(ictx, "\033[0n"); + break; + case 6: + input_reply(ictx, "\033[%u;%uR", s->cy + 1, s->cx + 1); + break; + default: + log_debug("%s: unknown '%c'", __func__, ictx->ch); + break; + } + break; + case INPUT_CSI_ED: + switch (input_get(ictx, 0, 0, 0)) { + case 0: + screen_write_clearendofscreen(sctx); + break; + case 1: + screen_write_clearstartofscreen(sctx); + break; + case 2: + screen_write_clearscreen(sctx); + break; + default: + log_debug("%s: unknown '%c'", __func__, ictx->ch); + break; + } + break; + case INPUT_CSI_EL: + switch (input_get(ictx, 0, 0, 0)) { + case 0: + screen_write_clearendofline(sctx); + break; + case 1: + screen_write_clearstartofline(sctx); + break; + case 2: + screen_write_clearline(sctx); + break; + default: + log_debug("%s: unknown '%c'", __func__, ictx->ch); + break; + } + break; + case INPUT_CSI_HPA: + n = input_get(ictx, 0, 1, 1); + screen_write_cursormove(sctx, n - 1, s->cy); + break; + case INPUT_CSI_ICH: + screen_write_insertcharacter(sctx, input_get(ictx, 0, 1, 1)); + break; + case INPUT_CSI_IL: + screen_write_insertline(sctx, input_get(ictx, 0, 1, 1)); + break; + case INPUT_CSI_RM: + switch (input_get(ictx, 0, 0, -1)) { case 4: /* IRM */ - screen_write_insertmode(&ictx->ctx, 1); - log_debug("insert on"); - break; - case 34: - /* Cursor high visibility not supported. */ + screen_write_insertmode(&ictx->ctx, 0); break; default: - log_debug("unknown SM [%hhu]: %u", ictx->private, n); + log_debug("%s: unknown '%c'", __func__, ictx->ch); break; } - } -} - -void -input_handle_sequence_rm(struct input_ctx *ictx) -{ - struct window_pane *wp = ictx->wp; - struct options *oo = &wp->window->options; - struct screen *s = &wp->base; - u_int sx, sy; - uint16_t n; - - if (ARRAY_LENGTH(&ictx->args) > 1) - return; - if (input_get_argument(ictx, 0, &n, 0) != 0) - return; - - if (ictx->private == '?') { - switch (n) { + break; + case INPUT_CSI_RM_PRIVATE: + switch (input_get(ictx, 0, 0, -1)) { case 1: /* GATM */ screen_write_kcursormode(&ictx->ctx, 0); - log_debug("kcursor off"); break; case 3: /* DECCOLM */ screen_write_cursormove(&ictx->ctx, 0, 0); @@ -1249,164 +1152,125 @@ input_handle_sequence_rm(struct input_ctx *ictx) break; case 25: /* TCEM */ screen_write_cursormode(&ictx->ctx, 0); - log_debug("cursor off"); break; case 1000: screen_write_mousemode(&ictx->ctx, 0); - log_debug("mouse off"); break; case 1049: - if (wp->saved_grid == NULL) - break; - if (!options_get_number(oo, "alternate-screen")) - break; - sx = screen_size_x(s); - sy = screen_size_y(s); - - /* - * Exit alternative screen mode and restore the copied - * grid. - */ - - /* - * If the current size is bigger, temporarily resize - * to the old size before copying back. - */ - if (sy > wp->saved_grid->sy) - screen_resize(s, sx, wp->saved_grid->sy); - - /* Restore the grid, cursor position and cell. */ - grid_duplicate_lines( - s->grid, screen_hsize(s), wp->saved_grid, 0, sy); - s->cx = wp->saved_cx; - if (s->cx > screen_size_x(s) - 1) - s->cx = screen_size_x(s) - 1; - s->cy = wp->saved_cy; - if (s->cy > screen_size_y(s) - 1) - s->cy = screen_size_y(s) - 1; - memcpy(&ictx->cell, &wp->saved_cell, sizeof ictx->cell); - - /* - * Turn history back on (so resize can use it) and then - * resize back to the current size. - */ - wp->base.grid->flags |= GRID_HISTORY; - if (sy > wp->saved_grid->sy) - screen_resize(s, sx, sy); - - grid_destroy(wp->saved_grid); - wp->saved_grid = NULL; - - wp->flags |= PANE_REDRAW; + window_pane_alternate_off(wp, &ictx->cell); break; default: - log_debug("unknown RM [%hhu]: %u", ictx->private, n); + log_debug("%s: unknown '%c'", __func__, ictx->ch); break; } - } else if (ictx->private == '\0') { - switch (n) { + break; + case INPUT_CSI_SGR: + input_csi_dispatch_sgr(ictx); + break; + case INPUT_CSI_SM: + switch (input_get(ictx, 0, 0, -1)) { case 4: /* IRM */ - screen_write_insertmode(&ictx->ctx, 0); - log_debug("insert off"); - break; - case 34: - /* Cursor high visibility not supported. */ + screen_write_insertmode(&ictx->ctx, 1); break; default: - log_debug("unknown RM [%hhu]: %u", ictx->private, n); + log_debug("%s: unknown '%c'", __func__, ictx->ch); break; } - } -} - -void -input_handle_sequence_dsr(struct input_ctx *ictx) -{ - struct window_pane *wp = ictx->wp; - struct screen *s = ictx->ctx.s; - uint16_t n; - char reply[32]; - - if (ARRAY_LENGTH(&ictx->args) > 1) - return; - if (input_get_argument(ictx, 0, &n, 0) != 0) - return; - - if (ictx->private == '\0') { - switch (n) { - case 6: /* cursor position */ - xsnprintf(reply, sizeof reply, - "\033[%u;%uR", s->cy + 1, s->cx + 1); - log_debug("cursor request, reply: %s", reply); - bufferevent_write(wp->event, reply, strlen(reply)); + break; + case INPUT_CSI_SM_PRIVATE: + switch (input_get(ictx, 0, 0, -1)) { + case 1: /* GATM */ + screen_write_kcursormode(&ictx->ctx, 1); + break; + case 3: /* DECCOLM */ + screen_write_cursormove(&ictx->ctx, 0, 0); + screen_write_clearscreen(&ictx->ctx); + break; + case 25: /* TCEM */ + screen_write_cursormode(&ictx->ctx, 1); + break; + case 1000: + screen_write_mousemode(&ictx->ctx, 1); + break; + case 1049: + window_pane_alternate_on(wp, &ictx->cell); + break; + default: + log_debug("%s: unknown '%c'", __func__, ictx->ch); break; } + break; + case INPUT_CSI_TBC: + switch (input_get(ictx, 0, 0, 0)) { + case 0: + if (s->cx < screen_size_x(s)) + bit_clear(s->tabs, s->cx); + break; + case 3: + bit_nclear(s->tabs, 0, screen_size_x(s) - 1); + break; + default: + log_debug("%s: unknown '%c'", __func__, ictx->ch); + break; + } + break; + case INPUT_CSI_VPA: + n = input_get(ictx, 0, 1, 1); + screen_write_cursormove(sctx, s->cx, n - 1); + break; } + + return (0); } +/* Handle CSI SGR. */ void -input_handle_sequence_decstbm(struct input_ctx *ictx) +input_csi_dispatch_sgr(struct input_ctx *ictx) { - struct screen *s = ictx->ctx.s; - uint16_t n, m; + struct grid_cell *gc = &ictx->cell; + u_int i; + int n, m; + u_char attr; - if (ictx->private != '\0') - return; - - if (ARRAY_LENGTH(&ictx->args) > 2) - return; - if (input_get_argument(ictx, 0, &n, 0) != 0) - return; - if (input_get_argument(ictx, 1, &m, 0) != 0) - return; - if (n == 0) - n = 1; - if (m == 0) - m = screen_size_y(s); - - screen_write_scrollregion(&ictx->ctx, n - 1, m - 1); -} - -void -input_handle_sequence_sgr(struct input_ctx *ictx) -{ - struct grid_cell *gc = &ictx->cell; - u_int i; - uint16_t m, o; - u_char attr; - - if (ARRAY_LENGTH(&ictx->args) == 0) { + if (ictx->param_list_len == 0) { attr = gc->attr; memcpy(gc, &grid_default_cell, sizeof *gc); gc->attr |= (attr & GRID_ATTR_CHARSET); return; } - for (i = 0; i < ARRAY_LENGTH(&ictx->args); i++) { - if (input_get_argument(ictx, i, &m, 0) != 0) - return; + for (i = 0; i < ictx->param_list_len; i++) { + n = input_get(ictx, i, 0, 0); - if (m == 38 || m == 48) { + if (n == 38 || n == 48) { i++; - if (input_get_argument(ictx, i, &o, 0) != 0) - return; - if (o != 5) + if (input_get(ictx, i, 0, -1) != 5) continue; i++; - if (input_get_argument(ictx, i, &o, 0) != 0) - return; - if (m == 38) { - gc->flags |= GRID_FLAG_FG256; - gc->fg = o; - } else if (m == 48) { - gc->flags |= GRID_FLAG_BG256; - gc->bg = o; + m = input_get(ictx, i, 0, -1); + if (m == -1) { + if (n == 38) { + gc->flags &= ~GRID_FLAG_FG256; + gc->fg = 8; + } else if (n == 48) { + gc->flags &= ~GRID_FLAG_BG256; + gc->fg = 8; + } + + } else { + if (n == 38) { + gc->flags |= GRID_FLAG_FG256; + gc->fg = m; + } else if (n == 48) { + gc->flags |= GRID_FLAG_BG256; + gc->bg = m; + } } continue; } - switch (m) { + switch (n) { case 0: case 10: attr = gc->attr; @@ -1458,7 +1322,7 @@ input_handle_sequence_sgr(struct input_ctx *ictx) case 36: case 37: gc->flags &= ~GRID_FLAG_FG256; - gc->fg = m - 30; + gc->fg = n - 30; break; case 39: gc->flags &= ~GRID_FLAG_FG256; @@ -1473,7 +1337,7 @@ input_handle_sequence_sgr(struct input_ctx *ictx) case 46: case 47: gc->flags &= ~GRID_FLAG_BG256; - gc->bg = m - 40; + gc->bg = n - 40; break; case 49: gc->flags &= ~GRID_FLAG_BG256; @@ -1488,7 +1352,7 @@ input_handle_sequence_sgr(struct input_ctx *ictx) case 96: case 97: gc->flags &= ~GRID_FLAG_FG256; - gc->fg = m; + gc->fg = n; break; case 100: case 101: @@ -1499,8 +1363,135 @@ input_handle_sequence_sgr(struct input_ctx *ictx) case 106: case 107: gc->flags &= ~GRID_FLAG_BG256; - gc->bg = m; + gc->bg = n; break; } } } + +/* DCS string started. */ +void +input_enter_dcs(struct input_ctx *ictx) +{ + log_debug("%s", __func__); + + ictx->input_len = 0; +} + +/* DCS terminator (ST) received. */ +void +input_exit_dcs(unused struct input_ctx *ictx) +{ + log_debug("%s", __func__); +} + +/* OSC string started. */ +void +input_enter_osc(struct input_ctx *ictx) +{ + log_debug("%s", __func__); + + ictx->input_len = 0; +} + +/* OSC terminator (ST) received. */ +void +input_exit_osc(struct input_ctx *ictx) +{ + if (ictx->flags & INPUT_DISCARD) + return; + log_debug("%s: \"%s\"", __func__, ictx->input_buf); + + if (ictx->input_len < 2 || ictx->input_buf[1] != ';') + return; + if (ictx->input_buf[0] != '0' && ictx->input_buf[0] != '2') + return; + + screen_set_title(ictx->ctx.s, ictx->input_buf + 2); + server_status_window(ictx->wp->window); +} + +/* APC string started. */ +void +input_enter_apc(struct input_ctx *ictx) +{ + log_debug("%s", __func__); + + ictx->input_len = 0; +} + +/* APC terminator (ST) received. */ +void +input_exit_apc(struct input_ctx *ictx) +{ + if (ictx->flags & INPUT_DISCARD) + return; + log_debug("%s: \"%s\"", __func__, ictx->input_buf); + + screen_set_title(ictx->ctx.s, ictx->input_buf); + server_status_window(ictx->wp->window); +} + +/* Rename string started. */ +void +input_enter_rename(struct input_ctx *ictx) +{ + log_debug("%s", __func__); + + ictx->input_len = 0; +} + +/* Rename terminator (ST) received. */ +void +input_exit_rename(struct input_ctx *ictx) +{ + if (ictx->flags & INPUT_DISCARD) + return; + log_debug("%s: \"%s\"", __func__, ictx->input_buf); + + xfree(ictx->wp->window->name); + ictx->wp->window->name = xstrdup(ictx->input_buf); + options_set_number(&ictx->wp->window->options, "automatic-rename", 0); + + server_status_window(ictx->wp->window); +} + +/* Open UTF-8 character. */ +int +input_utf8_open(struct input_ctx *ictx) +{ + if (!options_get_number(&ictx->wp->window->options, "utf8")) { + /* Print, and do not switch state. */ + input_print(ictx); + return (-1); + } + log_debug("%s", __func__); + + utf8_open(&ictx->utf8data, ictx->ch); + return (0); +} + +/* Append to UTF-8 character. */ +int +input_utf8_add(struct input_ctx *ictx) +{ + log_debug("%s", __func__); + + utf8_append(&ictx->utf8data, ictx->ch); + return (0); +} + +/* Close UTF-8 string. */ +int +input_utf8_close(struct input_ctx *ictx) +{ + log_debug("%s", __func__); + + utf8_append(&ictx->utf8data, ictx->ch); + + ictx->cell.flags |= GRID_FLAG_UTF8; + screen_write_cell(&ictx->ctx, &ictx->cell, &ictx->utf8data); + ictx->cell.flags &= ~GRID_FLAG_UTF8; + + return (0); +} diff --git a/tmux.h b/tmux.h index 0ecabf12..45fc18d9 100644 --- a/tmux.h +++ b/tmux.h @@ -719,43 +719,36 @@ struct screen_write_ctx { #define screen_hsize(s) ((s)->grid->hsize) #define screen_hlimit(s) ((s)->grid->hlimit) -/* Input parser sequence argument. */ -struct input_arg { - u_char data[64]; - size_t used; -}; - /* Input parser context. */ struct input_ctx { - struct window_pane *wp; + struct window_pane *wp; struct screen_write_ctx ctx; - u_char *buf; - size_t len; - size_t off; - size_t was; + struct grid_cell cell; - struct grid_cell cell; + struct grid_cell old_cell; + u_int old_cx; + u_int old_cy; - struct grid_cell saved_cell; - u_int saved_cx; - u_int saved_cy; + u_char interm_buf[4]; + size_t interm_len; -#define MAXSTRINGLEN 1024 - u_char *string_buf; - size_t string_len; - int string_type; -#define STRING_SYSTEM 0 -#define STRING_APPLICATION 1 -#define STRING_NAME 2 + u_char param_buf[64]; + size_t param_len; - struct utf8_data utf8data; + u_char input_buf[256]; + size_t input_len; - u_char intermediate; - void *(*state)(u_char, struct input_ctx *); + int param_list[24]; /* -1 not present */ + u_int param_list_len; - u_char private; - ARRAY_DECL(, struct input_arg) args; + struct utf8_data utf8data; + + int ch; + int flags; +#define INPUT_DISCARD 0x1 + + const struct input_state *state; }; /* @@ -1825,6 +1818,10 @@ int window_pane_spawn(struct window_pane *, const char *, const char *, const char *, struct environ *, struct termios *, char **); void window_pane_resize(struct window_pane *, u_int, u_int); +void window_pane_alternate_on( + struct window_pane *, struct grid_cell *); +void window_pane_alternate_off( + struct window_pane *, struct grid_cell *); int window_pane_set_mode( struct window_pane *, const struct window_mode *); void window_pane_reset_mode(struct window_pane *); diff --git a/window.c b/window.c index a990fa57..1a41c11a 100644 --- a/window.c +++ b/window.c @@ -623,6 +623,81 @@ window_pane_resize(struct window_pane *wp, u_int sx, u_int sy) fatal("ioctl failed"); } +/* + * Enter alternative screen mode. A copy of the visible screen is saved and the + * history is not updated + */ +void +window_pane_alternate_on(struct window_pane *wp, struct grid_cell *gc) +{ + struct screen *s = &wp->base; + u_int sx, sy; + + if (wp->saved_grid != NULL) + return; + if (!options_get_number(&wp->window->options, "alternate-screen")) + return; + sx = screen_size_x(s); + sy = screen_size_y(s); + + wp->saved_grid = grid_create(sx, sy, 0); + grid_duplicate_lines(wp->saved_grid, 0, s->grid, screen_hsize(s), sy); + wp->saved_cx = s->cx; + wp->saved_cy = s->cy; + memcpy(&wp->saved_cell, gc, sizeof wp->saved_cell); + + grid_view_clear(s->grid, 0, 0, sx, sy); + + wp->base.grid->flags &= ~GRID_HISTORY; + + wp->flags |= PANE_REDRAW; +} + +/* Exit alternate screen mode and restore the copied grid. */ +void +window_pane_alternate_off(struct window_pane *wp, struct grid_cell *gc) +{ + struct screen *s = &wp->base; + u_int sx, sy; + + if (wp->saved_grid == NULL) + return; + if (!options_get_number(&wp->window->options, "alternate-screen")) + return; + sx = screen_size_x(s); + sy = screen_size_y(s); + + /* + * If the current size is bigger, temporarily resize to the old size + * before copying back. + */ + if (sy > wp->saved_grid->sy) + screen_resize(s, sx, wp->saved_grid->sy); + + /* Restore the grid, cursor position and cell. */ + grid_duplicate_lines(s->grid, screen_hsize(s), wp->saved_grid, 0, sy); + s->cx = wp->saved_cx; + if (s->cx > screen_size_x(s) - 1) + s->cx = screen_size_x(s) - 1; + s->cy = wp->saved_cy; + if (s->cy > screen_size_y(s) - 1) + s->cy = screen_size_y(s) - 1; + memcpy(gc, &wp->saved_cell, sizeof *gc); + + /* + * Turn history back on (so resize can use it) and then resize back to + * the current size. + */ + wp->base.grid->flags |= GRID_HISTORY; + if (sy > wp->saved_grid->sy) + screen_resize(s, sx, sy); + + grid_destroy(wp->saved_grid); + wp->saved_grid = NULL; + + wp->flags |= PANE_REDRAW; +} + int window_pane_set_mode(struct window_pane *wp, const struct window_mode *mode) { From 021037c419b2044f5ba6f9596cc86923ab130309 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 22 Mar 2010 19:03:52 +0000 Subject: [PATCH 0661/1180] Accept a full key match (not a partial) even if there is data left in the buffer. --- tty-keys.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tty-keys.c b/tty-keys.c index 9404ef0a..27107bb8 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -408,7 +408,7 @@ tty_keys_find1(struct tty_key *tk, const char *buf, size_t len, size_t *size) (*size)++; /* At the end of the string, return the current node. */ - if (len == 0) + if (len == 0 || (tk->next == NULL && tk->key != KEYC_NONE)) return (tk); /* Move into the next tree for the following character. */ From 6f04866044e7482c20bd28abd876d173093fa6ac Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 22 Mar 2010 19:07:52 +0000 Subject: [PATCH 0662/1180] Support up, down, left, right movement through panes with -UDLR flags to select-pane. Also REMOVE the up- and down-pane commands: equivalent behaviour is now available using -t :.+ and -t :.-. --- Makefile | 4 +- cmd-down-pane.c | 60 ------------------------- cmd-select-pane.c | 41 +++++++++++++++-- cmd-up-pane.c | 60 ------------------------- cmd.c | 20 +++++++-- key-bindings.c | 8 ++-- tmux.1 | 30 ++++++++----- tmux.h | 4 ++ window.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 194 insertions(+), 143 deletions(-) delete mode 100644 cmd-down-pane.c delete mode 100644 cmd-up-pane.c diff --git a/Makefile b/Makefile index 574f4b48..be0051ef 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ SRCS= attributes.c cfg.c client.c clock.c \ cmd-break-pane.c cmd-choose-session.c cmd-choose-window.c \ cmd-clear-history.c cmd-clock-mode.c cmd-command-prompt.c \ cmd-confirm-before.c cmd-copy-buffer.c cmd-copy-mode.c \ - cmd-delete-buffer.c cmd-detach-client.c cmd-down-pane.c \ + cmd-delete-buffer.c cmd-detach-client.c \ cmd-find-window.c cmd-generic.c cmd-has-session.c cmd-kill-pane.c \ cmd-kill-server.c cmd-kill-session.c cmd-kill-window.c \ cmd-last-window.c cmd-link-window.c cmd-list-buffers.c \ @@ -28,7 +28,7 @@ SRCS= attributes.c cfg.c client.c clock.c \ cmd-run-shell.c cmd-suspend-client.c cmd-swap-pane.c cmd-swap-window.c \ cmd-switch-client.c cmd-unbind-key.c cmd-unlink-window.c \ cmd-set-environment.c cmd-show-environment.c cmd-choose-client.c \ - cmd-up-pane.c cmd-display-message.c cmd-display-panes.c \ + cmd-display-message.c cmd-display-panes.c \ cmd-pipe-pane.c cmd-capture-pane.c cmd.c \ colour.c environ.c grid-view.c grid-utf8.c grid.c input-keys.c \ imsg.c imsg-buffer.c input.c key-bindings.c key-string.c \ diff --git a/cmd-down-pane.c b/cmd-down-pane.c deleted file mode 100644 index a065a6e9..00000000 --- a/cmd-down-pane.c +++ /dev/null @@ -1,60 +0,0 @@ -/* $OpenBSD$ */ - -/* - * Copyright (c) 2009 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" - -/* - * Move down a pane. - */ - -int cmd_down_pane_exec(struct cmd *, struct cmd_ctx *); - -const struct cmd_entry cmd_down_pane_entry = { - "down-pane", "downp", - CMD_TARGET_WINDOW_USAGE, - 0, "", - cmd_target_init, - cmd_target_parse, - cmd_down_pane_exec, - cmd_target_free, - cmd_target_print -}; - -int -cmd_down_pane_exec(struct cmd *self, struct cmd_ctx *ctx) -{ - struct cmd_target_data *data = self->data; - struct winlink *wl; - struct window *w; - - if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) - return (-1); - w = wl->window; - - do { - w->active = TAILQ_NEXT(w->active, entry); - if (w->active == NULL) - w->active = TAILQ_FIRST(&w->panes); - } while (!window_pane_visible(w->active)); - server_status_window(wl->window); - server_redraw_window_borders(wl->window); - - return (0); -} diff --git a/cmd-select-pane.c b/cmd-select-pane.c index 956ed912..b5defa2e 100644 --- a/cmd-select-pane.c +++ b/cmd-select-pane.c @@ -24,19 +24,40 @@ * Select pane. */ +void cmd_select_pane_init(struct cmd *, int); int cmd_select_pane_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_select_pane_entry = { "select-pane", "selectp", - CMD_TARGET_PANE_USAGE, - 0, "", - cmd_target_init, + "[-DLRU] " CMD_TARGET_PANE_USAGE, + 0, "DLRU", + cmd_select_pane_init, cmd_target_parse, cmd_select_pane_exec, cmd_target_free, cmd_target_print }; +void +cmd_select_pane_init(struct cmd *self, int key) +{ + struct cmd_target_data *data; + + cmd_target_init(self, key); + data = self->data; + + if (key == KEYC_UP) + cmd_set_flag(&data->chflags, 'U'); + if (key == KEYC_DOWN) + cmd_set_flag(&data->chflags, 'D'); + if (key == KEYC_LEFT) + cmd_set_flag(&data->chflags, 'L'); + if (key == KEYC_RIGHT) + cmd_set_flag(&data->chflags, 'R'); + if (key == 'o') + data->target = xstrdup(":.+"); +} + int cmd_select_pane_exec(struct cmd *self, struct cmd_ctx *ctx) { @@ -51,6 +72,20 @@ cmd_select_pane_exec(struct cmd *self, struct cmd_ctx *ctx) ctx->error(ctx, "pane not visible: %s", data->target); return (-1); } + + if (cmd_check_flag(data->chflags, 'L')) + wp = window_pane_find_left(wp); + else if (cmd_check_flag(data->chflags, 'R')) + wp = window_pane_find_right(wp); + else if (cmd_check_flag(data->chflags, 'U')) + wp = window_pane_find_up(wp); + else if (cmd_check_flag(data->chflags, 'D')) + wp = window_pane_find_down(wp); + if (wp == NULL) { + ctx->error(ctx, "pane not found"); + return (-1); + } + window_set_active_pane(wl->window, wp); server_status_window(wl->window); server_redraw_window_borders(wl->window); diff --git a/cmd-up-pane.c b/cmd-up-pane.c deleted file mode 100644 index 62fe76be..00000000 --- a/cmd-up-pane.c +++ /dev/null @@ -1,60 +0,0 @@ -/* $OpenBSD$ */ - -/* - * Copyright (c) 2009 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" - -/* - * Move up a pane. - */ - -int cmd_up_pane_exec(struct cmd *, struct cmd_ctx *); - -const struct cmd_entry cmd_up_pane_entry = { - "up-pane", "upp", - CMD_TARGET_WINDOW_USAGE, - 0, "", - cmd_target_init, - cmd_target_parse, - cmd_up_pane_exec, - cmd_target_free, - cmd_target_print -}; - -int -cmd_up_pane_exec(struct cmd *self, struct cmd_ctx *ctx) -{ - struct cmd_target_data *data = self->data; - struct winlink *wl; - struct window *w; - - if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) - return (-1); - w = wl->window; - - do { - w->active = TAILQ_PREV(w->active, window_panes, entry); - if (w->active == NULL) - w->active = TAILQ_LAST(&w->panes, window_panes); - } while (!window_pane_visible(w->active)); - server_status_window(wl->window); - server_redraw_window_borders(wl->window); - - return (0); -} diff --git a/cmd.c b/cmd.c index 6163d78a..09b58adf 100644 --- a/cmd.c +++ b/cmd.c @@ -45,7 +45,6 @@ const struct cmd_entry *cmd_table[] = { &cmd_detach_client_entry, &cmd_display_message_entry, &cmd_display_panes_entry, - &cmd_down_pane_entry, &cmd_find_window_entry, &cmd_has_session_entry, &cmd_if_shell_entry, @@ -109,7 +108,6 @@ const struct cmd_entry *cmd_table[] = { &cmd_switch_client_entry, &cmd_unbind_key_entry, &cmd_unlink_window_entry, - &cmd_up_pane_entry, NULL }; @@ -955,15 +953,29 @@ cmd_find_pane(struct cmd_ctx *ctx, return (wl); lookup_string: + /* Try as next or previous pane. */ + if (paneptr[0] == '+' && paneptr[1] == '\0') { + *wpp = TAILQ_NEXT(wl->window->active, entry); + if (*wpp == NULL) + *wpp = TAILQ_FIRST(&wl->window->panes); + return (wl); + } + if (paneptr[0] == '-' && paneptr[1] == '\0') { + *wpp = TAILQ_PREV(wl->window->active, window_panes, entry); + if (*wpp == NULL) + *wpp = TAILQ_LAST(&wl->window->panes, window_panes); + return (wl); + } + /* Try pane string description. */ - if ((lc = layout_find_string(s->curw->window, paneptr)) == NULL) { + if ((lc = layout_find_string(wl->window, paneptr)) == NULL) { ctx->error(ctx, "can't find pane: %s", paneptr); goto error; } *wpp = lc->wp; xfree(winptr); - return (s->curw); + return (wl); no_period: /* Try as a pane number alone. */ diff --git a/key-bindings.c b/key-bindings.c index c08ac942..2eb5327c 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -136,7 +136,7 @@ key_bindings_init(void) { 'i', 0, &cmd_display_message_entry }, { 'l', 0, &cmd_last_window_entry }, { 'n', 0, &cmd_next_window_entry }, - { 'o', 0, &cmd_down_pane_entry }, + { 'o', 0, &cmd_select_pane_entry }, { 'p', 0, &cmd_previous_window_entry }, { 'q', 0, &cmd_display_panes_entry }, { 'r', 0, &cmd_refresh_client_entry }, @@ -155,8 +155,10 @@ key_bindings_init(void) { 'n' | KEYC_ESCAPE, 0, &cmd_next_window_entry }, { 'o' | KEYC_ESCAPE, 0, &cmd_rotate_window_entry }, { 'p' | KEYC_ESCAPE, 0, &cmd_previous_window_entry }, - { KEYC_UP, 0, &cmd_up_pane_entry }, - { KEYC_DOWN, 0, &cmd_down_pane_entry }, + { KEYC_UP, 1, &cmd_select_pane_entry }, + { KEYC_DOWN, 1, &cmd_select_pane_entry }, + { KEYC_LEFT, 1, &cmd_select_pane_entry }, + { KEYC_RIGHT, 1, &cmd_select_pane_entry }, { KEYC_UP | KEYC_ESCAPE, 1, &cmd_resize_pane_entry }, { KEYC_DOWN | KEYC_ESCAPE, 1, &cmd_resize_pane_entry }, { KEYC_LEFT | KEYC_ESCAPE, 1, &cmd_resize_pane_entry }, diff --git a/tmux.1 b/tmux.1 index 6d24fd53..92738dc5 100644 --- a/tmux.1 +++ b/tmux.1 @@ -336,6 +336,11 @@ If neither a colon nor period appears, first attempts to use the argument as a pane index; if that fails, it is looked up as for .Ar target-window . +A +.Ql + +or +.Ql - +indicate the next or previous pane index, respectively. One of the strings .Em top , .Em bottom , @@ -727,10 +732,8 @@ command (bound to and .Ql C-right by default), the current pane may be changed with the -.Ic up-pane -and -.Ic down-pane -commands and the +.Ic select-pane +command and the .Ic rotate-window and .Ic swap-pane @@ -859,9 +862,6 @@ While the indicator is on screen, a pane may be selected with the to .Ql 9 keys. -.It Ic down-pane Op Fl t Ar target-pane -.D1 (alias: Ic downp ) -Change the active pane to the next pane (higher index). .It Xo Ic find-window .Op Fl t Ar target-window .Ar match-string @@ -1103,12 +1103,23 @@ Choose a specific layout for a window. If .Ar layout-name is not given, the last layout used (if any) is reapplied. -.It Ic select-pane Op Fl t Ar target-pane +.It Xo Ic select-pane +.Op Fl DLRU +.Op Fl t Ar target-pane +.Xc .D1 (alias: Ic selectp ) Make pane .Ar target-pane the active pane in window .Ar target-window . +If one of +.Fl D , +.Fl L , +.Fl R , +or +.Fl U +is used, respectively the pane below, to the left, to the right, or above the +target pane is used. .It Ic select-window Op Fl t Ar target-window .D1 (alias: Ic selectw ) Select the window at @@ -1184,9 +1195,6 @@ if .Fl k is specified and the window is linked to only one session, it is unlinked and destroyed. -.It Ic up-pane Op Fl t Ar target-pane -.D1 (alias: Ic upp ) -Change the active pane to the previous pane (lower index). .El .Sh KEY BINDINGS .Nm diff --git a/tmux.h b/tmux.h index 45fc18d9..23288425 100644 --- a/tmux.h +++ b/tmux.h @@ -1832,6 +1832,10 @@ void window_pane_mouse(struct window_pane *, int window_pane_visible(struct window_pane *); char *window_pane_search( struct window_pane *, const char *, u_int *); +struct window_pane *window_pane_find_up(struct window_pane *); +struct window_pane *window_pane_find_down(struct window_pane *); +struct window_pane *window_pane_find_left(struct window_pane *); +struct window_pane *window_pane_find_right(struct window_pane *); /* layout.c */ struct layout_cell *layout_create_cell(struct layout_cell *); diff --git a/window.c b/window.c index 1a41c11a..7f2eac8d 100644 --- a/window.c +++ b/window.c @@ -827,3 +827,113 @@ window_pane_search(struct window_pane *wp, const char *searchstr, u_int *lineno) xfree(newsearchstr); return (msg); } + +/* Find the pane directly above another. */ +struct window_pane * +window_pane_find_up(struct window_pane *wp) +{ + struct window_pane *wp2; + u_int left, top; + + if (wp == NULL || !window_pane_visible(wp)) + return (NULL); + + top = wp->yoff; + if (top == 0) + top = wp->window->sy + 1; + left = wp->xoff; + + TAILQ_FOREACH(wp2, &wp->window->panes, entry) { + if (!window_pane_visible(wp2)) + continue; + if (wp2->yoff + wp2->sy + 1 != top) + continue; + if (left >= wp2->xoff && left <= wp2->xoff + wp2->sx) + return (wp2); + } + return (NULL); +} + +/* Find the pane directly below another. */ +struct window_pane * +window_pane_find_down(struct window_pane *wp) +{ + struct window_pane *wp2; + u_int left, bottom; + + if (wp == NULL || !window_pane_visible(wp)) + return (NULL); + + bottom = wp->yoff + wp->sy + 1; + if (bottom >= wp->window->sy) + bottom = 0; + left = wp->xoff; + + TAILQ_FOREACH(wp2, &wp->window->panes, entry) { + if (!window_pane_visible(wp2)) + continue; + if (wp2->yoff != bottom) + continue; + if (left >= wp2->xoff && left <= wp2->xoff + wp2->sx) + return (wp2); + } + return (NULL); +} + +/* + * Find the pane directly to the left of another, adjacent to the left side and + * containing the top edge. + */ +struct window_pane * +window_pane_find_left(struct window_pane *wp) +{ + struct window_pane *wp2; + u_int left, top; + + if (wp == NULL || !window_pane_visible(wp)) + return (NULL); + + left = wp->xoff; + if (left == 0) + left = wp->window->sx + 1; + top = wp->yoff; + + TAILQ_FOREACH(wp2, &wp->window->panes, entry) { + if (!window_pane_visible(wp2)) + continue; + if (wp2->xoff + wp2->sx + 1 != left) + continue; + if (top >= wp2->yoff && top <= wp2->yoff + wp2->sy) + return (wp2); + } + return (NULL); +} + +/* + * Find the pane directly to the right of another, that is adjacent to the + * right edge and including the top edge. + */ +struct window_pane * +window_pane_find_right(struct window_pane *wp) +{ + struct window_pane *wp2; + u_int right, top; + + if (wp == NULL || !window_pane_visible(wp)) + return (NULL); + + right = wp->xoff + wp->sx + 1; + if (right >= wp->window->sx) + right = 0; + top = wp->yoff; + + TAILQ_FOREACH(wp2, &wp->window->panes, entry) { + if (!window_pane_visible(wp2)) + continue; + if (wp2->xoff != right) + continue; + if (top >= wp2->yoff && top <= wp2->yoff + wp2->sy) + return (wp2); + } + return (NULL); +} From 0ac6efa6d5e7255f4039ceec37c9a42c0c9016cf Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 22 Mar 2010 19:10:42 +0000 Subject: [PATCH 0663/1180] Add vi-style "jump" commands for copy mode, from Micah Cowan. --- mode-key.c | 13 ++++++ tmux.1 | 20 ++++++++- tmux.h | 4 ++ window-copy.c | 121 +++++++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 154 insertions(+), 4 deletions(-) diff --git a/mode-key.c b/mode-key.c index fb208e0d..375cb925 100644 --- a/mode-key.c +++ b/mode-key.c @@ -88,6 +88,10 @@ struct mode_key_cmdstr mode_key_cmdstr_copy[] = { { MODEKEYCOPY_GOTOLINE, "goto-line" }, { MODEKEYCOPY_HISTORYBOTTOM, "history-bottom" }, { MODEKEYCOPY_HISTORYTOP, "history-top" }, + { MODEKEYCOPY_JUMP, "jump-forward" }, + { MODEKEYCOPY_JUMPAGAIN, "jump-again" }, + { MODEKEYCOPY_JUMPREVERSE, "jump-reverse" }, + { MODEKEYCOPY_JUMPBACK, "jump-backward" }, { MODEKEYCOPY_LEFT, "cursor-left" }, { MODEKEYCOPY_RECTANGLETOGGLE, "rectangle-toggle" }, { MODEKEYCOPY_MIDDLELINE, "middle-line" }, @@ -177,6 +181,8 @@ struct mode_key_tree mode_key_tree_vi_choice; const struct mode_key_entry mode_key_vi_copy[] = { { ' ', 0, MODEKEYCOPY_STARTSELECTION }, { '$', 0, MODEKEYCOPY_ENDOFLINE }, + { ',', 0, MODEKEYCOPY_JUMPREVERSE }, + { ';', 0, MODEKEYCOPY_JUMPAGAIN }, { '/', 0, MODEKEYCOPY_SEARCHDOWN }, { '0', 0, MODEKEYCOPY_STARTOFLINE }, { '1', 0, MODEKEYCOPY_STARTNUMBERPREFIX }, @@ -192,6 +198,7 @@ const struct mode_key_entry mode_key_vi_copy[] = { { '?', 0, MODEKEYCOPY_SEARCHUP }, { 'B', 0, MODEKEYCOPY_PREVIOUSSPACE }, { 'E', 0, MODEKEYCOPY_NEXTSPACEEND }, + { 'F', 0, MODEKEYCOPY_JUMPBACK }, { 'G', 0, MODEKEYCOPY_HISTORYBOTTOM }, { 'H', 0, MODEKEYCOPY_TOPLINE }, { 'J', 0, MODEKEYCOPY_SCROLLDOWN }, @@ -213,6 +220,7 @@ const struct mode_key_entry mode_key_vi_copy[] = { { '^', 0, MODEKEYCOPY_BACKTOINDENTATION }, { 'b', 0, MODEKEYCOPY_PREVIOUSWORD }, { 'e', 0, MODEKEYCOPY_NEXTWORDEND }, + { 'f', 0, MODEKEYCOPY_JUMP }, { 'g', 0, MODEKEYCOPY_HISTORYTOP }, { 'h', 0, MODEKEYCOPY_LEFT }, { 'j', 0, MODEKEYCOPY_DOWN }, @@ -290,6 +298,8 @@ struct mode_key_tree mode_key_tree_emacs_choice; /* emacs copy mode keys. */ const struct mode_key_entry mode_key_emacs_copy[] = { { ' ', 0, MODEKEYCOPY_NEXTPAGE }, + { ',', 0, MODEKEYCOPY_JUMPREVERSE }, + { ';', 0, MODEKEYCOPY_JUMPAGAIN }, { '1' | KEYC_ESCAPE, 0, MODEKEYCOPY_STARTNUMBERPREFIX }, { '2' | KEYC_ESCAPE, 0, MODEKEYCOPY_STARTNUMBERPREFIX }, { '3' | KEYC_ESCAPE, 0, MODEKEYCOPY_STARTNUMBERPREFIX }, @@ -301,6 +311,8 @@ const struct mode_key_entry mode_key_emacs_copy[] = { { '9' | KEYC_ESCAPE, 0, MODEKEYCOPY_STARTNUMBERPREFIX }, { '<' | KEYC_ESCAPE, 0, MODEKEYCOPY_HISTORYTOP }, { '>' | KEYC_ESCAPE, 0, MODEKEYCOPY_HISTORYBOTTOM }, + { 'F', 0, MODEKEYCOPY_JUMPBACK }, + { 'N', 0, MODEKEYCOPY_SEARCHREVERSE }, { 'R' | KEYC_ESCAPE, 0, MODEKEYCOPY_TOPLINE }, { 'R', 0, MODEKEYCOPY_RECTANGLETOGGLE }, { '\000' /* C-Space */, 0, MODEKEYCOPY_STARTSELECTION }, @@ -319,6 +331,7 @@ const struct mode_key_entry mode_key_emacs_copy[] = { { '\033' /* Escape */, 0, MODEKEYCOPY_CANCEL }, { 'N', 0, MODEKEYCOPY_SEARCHREVERSE }, { 'b' | KEYC_ESCAPE, 0, MODEKEYCOPY_PREVIOUSWORD }, + { 'f', 0, MODEKEYCOPY_JUMP }, { 'f' | KEYC_ESCAPE, 0, MODEKEYCOPY_NEXTWORDEND }, { 'g', 0, MODEKEYCOPY_GOTOLINE }, { 'm' | KEYC_ESCAPE, 0, MODEKEYCOPY_BACKTOINDENTATION }, diff --git a/tmux.1 b/tmux.1 index 92738dc5..6e13a9be 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD$ +.\" $Id$ .\" .\" Copyright (c) 2007 Nicholas Marriott .\" @@ -610,7 +610,7 @@ The keys available depend on whether emacs or vi mode is selected .Ic mode-keys option). The following keys are supported as appropriate for the mode: -.Bl -column "FunctionXXXXXXXXXXXXXX" "viXXXXXXXXXX" "emacs" -offset indent +.Bl -column "FunctionXXXXXXXXXXXXXXXXX" "viXXXXXXXXXX" "emacs" -offset indent .It Sy "Function" Ta Sy "vi" Ta Sy "emacs" .It Li "Back to indentation" Ta "^" Ta "M-m" .It Li "Bottom of history" Ta "G" Ta "M-<" @@ -629,6 +629,10 @@ The following keys are supported as appropriate for the mode: .It Li "Go to line" Ta ":" Ta "g" .It Li "Half page down" Ta "C-d" Ta "M-Down" .It Li "Half page up" Ta "C-u" Ta "M-Up" +.It Li "Jump forward" Ta "f" Ta "f" +.It Li "Jump backward" Ta "F" Ta "F" +.It Li "Jump again" Ta ";" Ta ";" +.It Li "Jump again in reverse" Ta "," Ta "," .It Li "Next page" Ta "C-f" Ta "Page down" .It Li "Next space" Ta "W" Ta "" .It Li "Next space, end of word" Ta "E" Ta "" @@ -666,6 +670,18 @@ next word and previous word to the start of the previous word. The three next and previous space keys work similarly but use a space alone as the word separator. .Pp +The jump commands enable quick movement within a line. +For instance, typing +.Ql f +followed by +.Ql / +will move the cursor to the next +.Ql / +character on the current line. +A +.Ql \&; +will then jump to the next occurrence. +.Pp Commands in copy mode may be prefaced by an optional repeat count. With vi key bindings, a prefix is entered using the number keys; with emacs, the Alt (meta) key and a number begins prefix entry. diff --git a/tmux.h b/tmux.h index 23288425..05a4dd94 100644 --- a/tmux.h +++ b/tmux.h @@ -459,6 +459,10 @@ enum mode_key_cmd { MODEKEYCOPY_HALFPAGEUP, MODEKEYCOPY_HISTORYBOTTOM, MODEKEYCOPY_HISTORYTOP, + MODEKEYCOPY_JUMP, + MODEKEYCOPY_JUMPAGAIN, + MODEKEYCOPY_JUMPREVERSE, + MODEKEYCOPY_JUMPBACK, MODEKEYCOPY_LEFT, MODEKEYCOPY_MIDDLELINE, MODEKEYCOPY_NEXTPAGE, diff --git a/window-copy.c b/window-copy.c index c27b1821..03666399 100644 --- a/window-copy.c +++ b/window-copy.c @@ -1,4 +1,4 @@ -/* $OpenBSD$ */ +/* $Id$ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -65,6 +65,8 @@ void window_copy_cursor_left(struct window_pane *); void window_copy_cursor_right(struct window_pane *); void window_copy_cursor_up(struct window_pane *, int); void window_copy_cursor_down(struct window_pane *, int); +void window_copy_cursor_jump(struct window_pane *); +void window_copy_cursor_jump_back(struct window_pane *); void window_copy_cursor_next_word(struct window_pane *, const char *); void window_copy_cursor_next_word_end(struct window_pane *, const char *); void window_copy_cursor_previous_word(struct window_pane *, const char *); @@ -86,6 +88,8 @@ enum window_copy_input_type { WINDOW_COPY_NUMERICPREFIX, WINDOW_COPY_SEARCHUP, WINDOW_COPY_SEARCHDOWN, + WINDOW_COPY_JUMPFORWARD, + WINDOW_COPY_JUMPBACK, WINDOW_COPY_GOTOLINE, }; @@ -115,6 +119,9 @@ struct window_copy_mode_data { enum window_copy_input_type searchtype; char *searchstr; + + enum window_copy_input_type jumptype; + char jumpchar; }; struct screen * @@ -147,6 +154,9 @@ window_copy_init(struct window_pane *wp) wp->flags |= PANE_FREEZE; bufferevent_disable(wp->event, EV_READ|EV_WRITE); + data->jumptype = WINDOW_COPY_OFF; + data->jumpchar = '\0'; + s = &data->screen; screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0); if (options_get_number(&wp->window->options, "mode-mouse")) @@ -242,7 +252,24 @@ window_copy_key(struct window_pane *wp, struct client *c, int key) if (np == 0) np = 1; - if (data->inputtype == WINDOW_COPY_NUMERICPREFIX) { + if (data->inputtype == WINDOW_COPY_JUMPFORWARD + || data->inputtype == WINDOW_COPY_JUMPBACK) { + /* Ignore keys with modifiers. */ + if ((key & 0xff00) == 0) { + data->jumpchar = key; + if (data->inputtype == WINDOW_COPY_JUMPFORWARD) { + for (; np != 0; np--) + window_copy_cursor_jump(wp); + } else { + for (; np != 0; np--) + window_copy_cursor_jump_back(wp); + } + } + data->jumptype = data->inputtype; + data->inputtype = WINDOW_COPY_OFF; + window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1); + return; + } if (data->inputtype == WINDOW_COPY_NUMERICPREFIX) { if (window_copy_key_numeric_prefix(wp, key) == 0) return; data->inputtype = WINDOW_COPY_OFF; @@ -407,6 +434,36 @@ window_copy_key(struct window_pane *wp, struct client *c, int key) for (; np != 0; np--) window_copy_cursor_previous_word(wp, word_separators); break; + case MODEKEYCOPY_JUMP: + data->inputtype = WINDOW_COPY_JUMPFORWARD; + data->inputprompt = "Jump Forward"; + *data->inputstr = '\0'; + window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1); + return; /* skip numprefix reset */ + case MODEKEYCOPY_JUMPAGAIN: + if (data->jumptype == WINDOW_COPY_JUMPFORWARD) { + for (; np != 0; np--) + window_copy_cursor_jump(wp); + } else if (data->jumptype == WINDOW_COPY_JUMPBACK) { + for (; np != 0; np--) + window_copy_cursor_jump_back(wp); + } + break; + case MODEKEYCOPY_JUMPREVERSE: + if (data->jumptype == WINDOW_COPY_JUMPFORWARD) { + for (; np != 0; np--) + window_copy_cursor_jump_back(wp); + } else if (data->jumptype == WINDOW_COPY_JUMPBACK) { + for (; np != 0; np--) + window_copy_cursor_jump(wp); + } + break; + case MODEKEYCOPY_JUMPBACK: + data->inputtype = WINDOW_COPY_JUMPBACK; + data->inputprompt = "Jump Back"; + *data->inputstr = '\0'; + window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1); + return; /* skip numprefix reset */ case MODEKEYCOPY_SEARCHUP: data->inputtype = WINDOW_COPY_SEARCHUP; data->inputprompt = "Search Up"; @@ -420,6 +477,8 @@ window_copy_key(struct window_pane *wp, struct client *c, int key) switch (data->searchtype) { case WINDOW_COPY_OFF: case WINDOW_COPY_GOTOLINE: + case WINDOW_COPY_JUMPFORWARD: + case WINDOW_COPY_JUMPBACK: case WINDOW_COPY_NUMERICPREFIX: break; case WINDOW_COPY_SEARCHUP: @@ -524,6 +583,8 @@ window_copy_key_input(struct window_pane *wp, int key) switch (data->inputtype) { case WINDOW_COPY_OFF: + case WINDOW_COPY_JUMPFORWARD: + case WINDOW_COPY_JUMPBACK: case WINDOW_COPY_NUMERICPREFIX: break; case WINDOW_COPY_SEARCHUP: @@ -1380,6 +1441,62 @@ window_copy_cursor_down(struct window_pane *wp, int scroll_only) } } +void +window_copy_cursor_jump(struct window_pane *wp) +{ + struct window_copy_mode_data *data = wp->modedata; + struct screen *base_s = &wp->base; + const struct grid_cell *gc; + uint px, py, xx; + + px = data->cx + 1; + py = screen_hsize(base_s) + data->cy - data->oy; + xx = window_copy_find_length(wp, py); + + while (px < xx) { + gc = grid_peek_cell(base_s->grid, px, py); + if ((gc->flags & (GRID_FLAG_PADDING|GRID_FLAG_UTF8)) == 0 + && gc->data == data->jumpchar) { + + window_copy_update_cursor(wp, px, data->cy); + if (window_copy_update_selection(wp)) + window_copy_redraw_lines(wp, data->cy, 1); + return; + } + px++; + } +} + +void +window_copy_cursor_jump_back(struct window_pane *wp) +{ + struct window_copy_mode_data *data = wp->modedata; + struct screen *base_s = &wp->base; + const struct grid_cell *gc; + uint px, py; + + px = data->cx; + py = screen_hsize(base_s) + data->cy - data->oy; + + if (px > 0) + px--; + + for (;;) { + gc = grid_peek_cell(base_s->grid, px, py); + if ((gc->flags & (GRID_FLAG_PADDING|GRID_FLAG_UTF8)) == 0 + && gc->data == data->jumpchar) { + + window_copy_update_cursor(wp, px, data->cy); + if (window_copy_update_selection(wp)) + window_copy_redraw_lines(wp, data->cy, 1); + return; + } + if (px == 0) + break; + px--; + } +} + void window_copy_cursor_next_word(struct window_pane *wp, const char *separators) { From 509ce7f76697841eecfa11a8137d5ba03ce349da Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 22 Mar 2010 19:11:54 +0000 Subject: [PATCH 0664/1180] Nuke unused variable. --- server.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/server.c b/server.c index e2ca33b0..2859b52a 100644 --- a/server.c +++ b/server.c @@ -114,7 +114,7 @@ int server_start(char *path) { struct window_pane *wp; - int pair[2], retval; + int pair[2]; char rpathbuf[MAXPATHLEN], *cause; struct timeval tv; u_int i; @@ -167,7 +167,6 @@ server_start(char *path) server_fd = server_create_socket(); server_client_create(pair[1]); - retval = 0; if (access(SYSTEM_CFG, R_OK) == 0) load_cfg(SYSTEM_CFG, NULL, &cfg_causes); else if (errno != ENOENT) { From 9abbe349af66a749202cd1df42b32a0997b0ba6f Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 22 Mar 2010 19:13:28 +0000 Subject: [PATCH 0665/1180] paste-buffer should be per pane, from C. Coutinho. --- cmd-paste-buffer.c | 5 ++--- tmux.1 | 7 ++++--- window-copy.c | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/cmd-paste-buffer.c b/cmd-paste-buffer.c index 1abf09a7..46934629 100644 --- a/cmd-paste-buffer.c +++ b/cmd-paste-buffer.c @@ -31,7 +31,7 @@ void cmd_paste_buffer_lf2cr(struct window_pane *, const char *, size_t); const struct cmd_entry cmd_paste_buffer_entry = { "paste-buffer", "pasteb", - "[-dr] " CMD_BUFFER_WINDOW_USAGE, + "[-dr] " CMD_BUFFER_PANE_USAGE, 0, "dr", cmd_buffer_init, cmd_buffer_parse, @@ -49,9 +49,8 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) struct session *s; struct paste_buffer *pb; - if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL) + if ((wl = cmd_find_pane(ctx, data->target, &s, &wp)) == NULL) return (-1); - wp = wl->window->active; if (data->buffer == -1) pb = paste_get_top(&s->buffers); diff --git a/tmux.1 b/tmux.1 index 6e13a9be..ad50eea8 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1,4 +1,4 @@ -.\" $Id$ +.\" $OpenBSD$ .\" .\" Copyright (c) 2007 Nicholas Marriott .\" @@ -2360,10 +2360,11 @@ Load the contents of the specified paste buffer from .It Xo Ic paste-buffer .Op Fl dr .Op Fl b Ar buffer-index -.Op Fl t Ar target-window +.Op Fl t Ar target-pane .Xc .D1 (alias: Ic pasteb ) -Insert the contents of a paste buffer into the current window. +Insert the contents of a paste buffer into the specified pane. +If not specified, paste into the current one. With .Fl d , also delete the paste buffer from the stack. diff --git a/window-copy.c b/window-copy.c index 03666399..5d915dee 100644 --- a/window-copy.c +++ b/window-copy.c @@ -1,4 +1,4 @@ -/* $Id$ */ +/* $OpenBSD$ */ /* * Copyright (c) 2007 Nicholas Marriott From e16b7b8399c7478db34788e29020f4b973fb5fe0 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 22 Mar 2010 19:14:55 +0000 Subject: [PATCH 0666/1180] Reset output functions too when changing client after attaching, to avoid crash if a command in a sequence after new/attach causes output. --- cmd-list.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cmd-list.c b/cmd-list.c index 9adf7f76..55550c21 100644 --- a/cmd-list.c +++ b/cmd-list.c @@ -99,6 +99,10 @@ cmd_list_exec(struct cmd_list *cmdlist, struct cmd_ctx *ctx) if (ctx->curclient == NULL) { ctx->curclient = ctx->cmdclient; ctx->cmdclient = NULL; + + ctx->error = key_bindings_error; + ctx->print = key_bindings_print; + ctx->info = key_bindings_info; } } } From c550e66e8542919ab4f02d1cdd87b6d59c7896fb Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 22 Mar 2010 19:18:46 +0000 Subject: [PATCH 0667/1180] Dead functions, lint. --- server-fn.c | 9 --------- status.c | 25 ------------------------- tmux.h | 1 - 3 files changed, 35 deletions(-) diff --git a/server-fn.c b/server-fn.c index 3c7277bd..86d7ffdd 100644 --- a/server-fn.c +++ b/server-fn.c @@ -42,15 +42,6 @@ server_fill_environ(struct session *s, struct environ *env) environ_set(env, "TERM", term); } -void -server_write_error(struct client *c, const char *msg) -{ - struct msg_print_data printdata; - - strlcpy(printdata.msg, msg, sizeof printdata.msg); - server_write_client(c, MSG_ERROR, &printdata, sizeof printdata); -} - void server_write_client( struct client *c, enum msgtype type, const void *buf, size_t len) diff --git a/status.c b/status.c index 5576cff9..eff8b615 100644 --- a/status.c +++ b/status.c @@ -35,7 +35,6 @@ char *status_redraw_get_right( struct client *, time_t, int, struct grid_cell *, size_t *); char *status_job(struct client *, char **); void status_job_callback(struct job *); -size_t status_width(struct client *, struct winlink *, time_t); char *status_print( struct client *, struct winlink *, time_t, struct grid_cell *); void status_replace1(struct client *, @@ -559,30 +558,6 @@ status_job_callback(struct job *job) job->data = xstrdup(line); } -/* Calculate winlink status line entry width. */ -size_t -status_width(struct client *c, struct winlink *wl, time_t t) -{ - struct options *oo = &wl->window->options; - struct session *s = c->session; - const char *fmt; - char *text; - size_t size; - int utf8flag; - - utf8flag = options_get_number(&s->options, "status-utf8"); - - fmt = options_get_string(&wl->window->options, "window-status-format"); - if (wl == s->curw) - fmt = options_get_string(oo, "window-status-current-format"); - - text = status_replace(c, wl, fmt, t, 1); - size = screen_write_cstrlen(utf8flag, "%s", text); - xfree(text); - - return (size); -} - /* Return winlink status line entry and adjust gc as necessary. */ char * status_print( diff --git a/tmux.h b/tmux.h index 05a4dd94..3145b742 100644 --- a/tmux.h +++ b/tmux.h @@ -1597,7 +1597,6 @@ void server_window_loop(void); /* server-fn.c */ void server_fill_environ(struct session *, struct environ *); -void server_write_error(struct client *, const char *); void server_write_client( struct client *, enum msgtype, const void *, size_t); void server_write_session( From d267845cfcdfaad214e1d34d55637fb9f9c2c11b Mon Sep 17 00:00:00 2001 From: Jason McIntyre Date: Fri, 26 Mar 2010 19:30:40 +0000 Subject: [PATCH 0668/1180] dispense with some wacky escape sequences; --- tmux.1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tmux.1 b/tmux.1 index ad50eea8..6509069f 100644 --- a/tmux.1 +++ b/tmux.1 @@ -405,9 +405,9 @@ Or from .Bd -literal -offset indent $ tmux kill-window -t :1 -$ tmux new-window \\; split-window -d +$ tmux new-window \e; split-window -d -$ tmux new-session -d 'vi /etc/passwd' \\; split-window -d \\; attach +$ tmux new-session -d 'vi /etc/passwd' \e; split-window -d \e; attach .Ed .Sh CLIENTS AND SESSIONS The From d3d85c3df9970820eb114c6fb6378f4db72e1d3c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 27 Mar 2010 11:46:58 +0000 Subject: [PATCH 0669/1180] -a flag to insert a window after an existing one, moving other windows up necessary. --- cmd-new-window.c | 38 +++++++++++++++++++++++++++++++++----- tmux.1 | 11 ++++++++++- 2 files changed, 43 insertions(+), 6 deletions(-) diff --git a/cmd-new-window.c b/cmd-new-window.c index ea3cff4a..cf32f29e 100644 --- a/cmd-new-window.c +++ b/cmd-new-window.c @@ -36,13 +36,14 @@ struct cmd_new_window_data { char *target; char *name; char *cmd; + int flag_insert_after; int flag_detached; int flag_kill; }; const struct cmd_entry cmd_new_window_entry = { "new-window", "neww", - "[-dk] [-n window-name] [-t target-window] [command]", + "[-adk] [-n window-name] [-t target-window] [command]", 0, "", cmd_new_window_init, cmd_new_window_parse, @@ -61,6 +62,7 @@ cmd_new_window_init(struct cmd *self, unused int arg) data->target = NULL; data->name = NULL; data->cmd = NULL; + data->flag_insert_after = 0; data->flag_detached = 0; data->flag_kill = 0; } @@ -74,8 +76,11 @@ cmd_new_window_parse(struct cmd *self, int argc, char **argv, char **cause) self->entry->init(self, KEYC_NONE); data = self->data; - while ((opt = getopt(argc, argv, "dkt:n:")) != -1) { + while ((opt = getopt(argc, argv, "adkt:n:")) != -1) { switch (opt) { + case 'a': + data->flag_insert_after = 1; + break; case 'd': data->flag_detached = 1; break; @@ -118,13 +123,36 @@ cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx) struct session *s; struct winlink *wl; char *cmd, *cwd, *cause; - int idx; + int idx, last; if (data == NULL) return (0); - if ((idx = cmd_find_index(ctx, data->target, &s)) == -2) - return (-1); + if (data->flag_insert_after) { + if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL) + return (-1); + idx = wl->idx + 1; + + /* Find the next free index. */ + for (last = idx; last < INT_MAX; last++) { + if (winlink_find_by_index(&s->windows, last) == NULL) + break; + } + if (last == INT_MAX) { + ctx->error(ctx, "no free window indexes"); + return (-1); + } + + /* Move everything from last - 1 to idx up a bit. */ + for (; last > idx; last--) { + wl = winlink_find_by_index(&s->windows, last - 1); + server_link_window(s, wl, s, last, 0, 0, NULL); + server_unlink_window(s, wl); + } + } else { + if ((idx = cmd_find_index(ctx, data->target, &s)) == -2) + return (-1); + } wl = NULL; if (idx != -1) diff --git a/tmux.1 b/tmux.1 index 6509069f..351aec44 100644 --- a/tmux.1 +++ b/tmux.1 @@ -976,13 +976,22 @@ except the window at is moved to .Ar dst-window . .It Xo Ic new-window -.Op Fl dk +.Op Fl adk .Op Fl n Ar window-name .Op Fl t Ar target-window .Op Ar shell-command .Xc .D1 (alias: Ic neww ) Create a new window. +With +.Fl a , +the new window is inserted at the next index up from the specified +.Ar target-window , +moving windows up if necessary, +otherwise +.Ar target-window +is the new window location. +.Pp If .Fl d is given, the session does not make the new window the current window. From 41f90bd08fb760f236857e7b22b89ebb2ffc106d Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 27 Mar 2010 15:06:40 +0000 Subject: [PATCH 0670/1180] Don't leak job command in #(). --- status.c | 1 + 1 file changed, 1 insertion(+) diff --git a/status.c b/status.c index eff8b615..1d7c8ea1 100644 --- a/status.c +++ b/status.c @@ -526,6 +526,7 @@ status_job(struct client *c, char **iptr) JOB_PERSIST, c, cmd, status_job_callback, xfree, NULL); job_run(job); } + xfree(cmd); if (job->data == NULL) return (xstrdup("")); return (xstrdup(job->data)); From 56481a46bfda683fd61b9726b4d703b53563b7fa Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 31 Mar 2010 18:05:14 +0000 Subject: [PATCH 0671/1180] Don't accept keys with modifiers as input. Fixes crash reported by Brian R Landy. --- status.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/status.c b/status.c index 1d7c8ea1..b3ae78ce 100644 --- a/status.c +++ b/status.c @@ -1046,7 +1046,7 @@ status_prompt_key(struct client *c, int key) status_prompt_clear(c); break; case MODEKEY_OTHER: - if (key < 32 || key == 127) + if ((key & 0xff00) != 0 || key < 32 || key == 127) break; c->prompt_buffer = xrealloc(c->prompt_buffer, 1, size + 2); From 7425122c1cd2aff909d72b33ef07b6a71d0c6922 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 4 Apr 2010 18:48:37 +0000 Subject: [PATCH 0672/1180] Squash a function that is only called in a callback into the callback function. --- tmux.h | 1 - window.c | 31 ++++++++++++------------------- 2 files changed, 12 insertions(+), 20 deletions(-) diff --git a/tmux.h b/tmux.h index 3145b742..576c4977 100644 --- a/tmux.h +++ b/tmux.h @@ -1828,7 +1828,6 @@ void window_pane_alternate_off( int window_pane_set_mode( struct window_pane *, const struct window_mode *); void window_pane_reset_mode(struct window_pane *); -void window_pane_parse(struct window_pane *); void window_pane_key(struct window_pane *, struct client *, int); void window_pane_mouse(struct window_pane *, struct client *, struct mouse_event *); diff --git a/window.c b/window.c index 7f2eac8d..4a801a76 100644 --- a/window.c +++ b/window.c @@ -586,9 +586,19 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell, void window_pane_read_callback(unused struct bufferevent *bufev, void *data) { - struct window_pane *wp = data; + struct window_pane *wp = data; + char *new_data; + size_t new_size; - window_pane_parse(wp); + new_size = EVBUFFER_LENGTH(wp->event->input) - wp->pipe_off; + if (wp->pipe_fd != -1 && new_size > 0) { + new_data = EVBUFFER_DATA(wp->event->input); + bufferevent_write(wp->pipe_event, new_data, new_size); + } + + input_parse(wp); + + wp->pipe_off = EVBUFFER_LENGTH(wp->event->input); } /* ARGSUSED */ @@ -726,23 +736,6 @@ window_pane_reset_mode(struct window_pane *wp) wp->flags |= PANE_REDRAW; } -void -window_pane_parse(struct window_pane *wp) -{ - char *data; - size_t new_size; - - new_size = EVBUFFER_LENGTH(wp->event->input) - wp->pipe_off; - if (wp->pipe_fd != -1 && new_size > 0) { - data = EVBUFFER_DATA(wp->event->input); - bufferevent_write(wp->pipe_event, data, new_size); - } - - input_parse(wp); - - wp->pipe_off = EVBUFFER_LENGTH(wp->event->input); -} - void window_pane_key(struct window_pane *wp, struct client *c, int key) { From b02cd353543cb47ddaf079bd42f94696703f2667 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 4 Apr 2010 19:02:09 +0000 Subject: [PATCH 0673/1180] Run job commands explicitly in the global enviroment (which can be modified with setenv -g) rather than with the environment tmux started with. --- environ.c | 38 +++++++++++++++++++++++++++++++++++++- job.c | 3 ++- tmux.1 | 4 ++++ tmux.h | 1 + window.c | 28 ++++++---------------------- 5 files changed, 50 insertions(+), 24 deletions(-) diff --git a/environ.c b/environ.c index 353b84fa..4c4af98f 100644 --- a/environ.c +++ b/environ.c @@ -35,12 +35,14 @@ environ_cmp(struct environ_entry *envent1, struct environ_entry *envent2) return (strcmp(envent1->name, envent2->name)); } +/* Initialise the environment. */ void environ_init(struct environ *env) { RB_INIT(env); } +/* Free an environment. */ void environ_free(struct environ *env) { @@ -56,6 +58,7 @@ environ_free(struct environ *env) } } +/* Copy one environment into another. */ void environ_copy(struct environ *srcenv, struct environ *dstenv) { @@ -65,6 +68,7 @@ environ_copy(struct environ *srcenv, struct environ *dstenv) environ_set(dstenv, envent->name, envent->value); } +/* Find an environment variable. */ struct environ_entry * environ_find(struct environ *env, const char *name) { @@ -74,6 +78,7 @@ environ_find(struct environ *env, const char *name) return (RB_FIND(environ, env, &envent)); } +/* Set an environment variable. */ void environ_set(struct environ *env, const char *name, const char *value) { @@ -97,10 +102,11 @@ environ_set(struct environ *env, const char *name, const char *value) } } +/* Set an environment variable from a NAME=VALUE string. */ void environ_put(struct environ *env, const char *var) { - char *name, *value; + char *name, *value; value = strchr(var, '='); if (value == NULL) @@ -114,6 +120,7 @@ environ_put(struct environ *env, const char *var) xfree(name); } +/* Unset an environment variable. */ void environ_unset(struct environ *env, const char *name) { @@ -128,6 +135,10 @@ environ_unset(struct environ *env, const char *name) xfree(envent); } +/* + * Copy a space-separated list of variables from a destination into a source + * environment. + */ void environ_update(const char *vars, struct environ *srcenv, struct environ *dstenv) { @@ -143,3 +154,28 @@ environ_update(const char *vars, struct environ *srcenv, struct environ *dstenv) } xfree(copyvars); } + +/* Push environment into the real environment - use after fork(). */ +void +environ_push(struct environ *env) +{ + ARRAY_DECL(, char *) varlist; + struct environ_entry *envent; + char **varp, *var; + u_int i; + + ARRAY_INIT(&varlist); + for (varp = environ; *varp != NULL; varp++) { + var = xstrdup(*varp); + var[strcspn(var, "=")] = '\0'; + ARRAY_ADD(&varlist, var); + } + for (i = 0; i < ARRAY_LENGTH(&varlist); i++) + unsetenv(ARRAY_ITEM(&varlist, i)); + ARRAY_FREE(&varlist); + + RB_FOREACH(envent, environ, env) { + if (envent->value != NULL) + setenv(envent->name, envent->value, 1); + } +} diff --git a/job.c b/job.c index 36ea2f4e..ddeae13f 100644 --- a/job.c +++ b/job.c @@ -150,7 +150,8 @@ job_run(struct job *job) return (-1); case 0: /* child */ server_signal_clear(); - /* XXX environ? */ + + environ_push(&global_environ); if (dup2(out[1], STDOUT_FILENO) == -1) fatal("dup2 failed"); diff --git a/tmux.1 b/tmux.1 index 351aec44..dc590c7e 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1745,6 +1745,10 @@ the .Ic status-interval option: if the status line is redrawn in the meantime, the previous result is used. +Shell commands are executed with the +.Nm +global environment set (see the +.Sx ENVIRONMENT section). .Pp #[attributes] allows a comma-separated list of attributes to be specified, these may be diff --git a/tmux.h b/tmux.h index 576c4977..642d5530 100644 --- a/tmux.h +++ b/tmux.h @@ -1330,6 +1330,7 @@ void environ_set(struct environ *, const char *, const char *); void environ_put(struct environ *, const char *); void environ_unset(struct environ *, const char *); void environ_update(const char *, struct environ *, struct environ *); +void environ_push(struct environ *); /* tty.c */ void tty_raw(struct tty *, const char *); diff --git a/window.c b/window.c index 4a801a76..00c03f6e 100644 --- a/window.c +++ b/window.c @@ -480,14 +480,11 @@ int window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell, const char *cwd, struct environ *env, struct termios *tio, char **cause) { - struct winsize ws; - int mode; - char *argv0, **varp, *var; - ARRAY_DECL(, char *) varlist; - struct environ_entry *envent; - const char *ptr; - struct termios tio2; - u_int i; + struct winsize ws; + int mode; + char *argv0; + const char *ptr; + struct termios tio2; if (wp->fd != -1) { close(wp->fd); @@ -530,20 +527,7 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell, if (tcsetattr(STDIN_FILENO, TCSANOW, &tio2) != 0) fatal("tcgetattr failed"); - ARRAY_INIT(&varlist); - for (varp = environ; *varp != NULL; varp++) { - var = xstrdup(*varp); - var[strcspn(var, "=")] = '\0'; - ARRAY_ADD(&varlist, var); - } - for (i = 0; i < ARRAY_LENGTH(&varlist); i++) { - var = ARRAY_ITEM(&varlist, i); - unsetenv(var); - } - RB_FOREACH(envent, environ, env) { - if (envent->value != NULL) - setenv(envent->name, envent->value, 1); - } + environ_push(env); server_signal_clear(); log_close(); From 46d5c14b1755519a57beca9e8452e7fc08f5f038 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 4 Apr 2010 19:04:09 +0000 Subject: [PATCH 0674/1180] Dead assignment, found with clang. --- cmd-paste-buffer.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cmd-paste-buffer.c b/cmd-paste-buffer.c index 46934629..e4d97f44 100644 --- a/cmd-paste-buffer.c +++ b/cmd-paste-buffer.c @@ -44,12 +44,11 @@ int cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) { struct cmd_buffer_data *data = self->data; - struct winlink *wl; struct window_pane *wp; struct session *s; struct paste_buffer *pb; - if ((wl = cmd_find_pane(ctx, data->target, &s, &wp)) == NULL) + if (cmd_find_pane(ctx, data->target, &s, &wp) == NULL) return (-1); if (data->buffer == -1) From 089c33f5be4a93c7cad49f5b7d7fb6331e0fb0eb Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 4 Apr 2010 19:12:20 +0000 Subject: [PATCH 0675/1180] Should be -s for src pane. --- cmd-join-pane.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd-join-pane.c b/cmd-join-pane.c index 425fe92a..722a2031 100644 --- a/cmd-join-pane.c +++ b/cmd-join-pane.c @@ -45,7 +45,7 @@ struct cmd_join_pane_data { const struct cmd_entry cmd_join_pane_entry = { "join-pane", "joinp", - "[-dhv] [-p percentage|-l size] [-t src-pane] [-t dst-pane] [command]", + "[-dhv] [-p percentage|-l size] [-s src-pane] [-t dst-pane] [command]", 0, "", cmd_join_pane_init, cmd_join_pane_parse, From 680f920b551c0cac9239d6b15ac390dc1bc576b4 Mon Sep 17 00:00:00 2001 From: Jason McIntyre Date: Sun, 4 Apr 2010 21:23:20 +0000 Subject: [PATCH 0676/1180] tweak; --- tmux.1 | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tmux.1 b/tmux.1 index dc590c7e..0fd7c8c8 100644 --- a/tmux.1 +++ b/tmux.1 @@ -373,7 +373,6 @@ bind-key F1 set-window-option force-width 81 .Pp Or if using .Xr sh 1 : -.Pp .Bd -literal -offset indent $ tmux bind-key F1 set-window-option force-width 81 .Ed @@ -401,7 +400,6 @@ new-window ; split-window -d .Pp Or from .Xr sh 1 : -.Pp .Bd -literal -offset indent $ tmux kill-window -t :1 @@ -1748,7 +1746,8 @@ used. Shell commands are executed with the .Nm global environment set (see the -.Sx ENVIRONMENT section). +.Sx ENVIRONMENT +section). .Pp #[attributes] allows a comma-separated list of attributes to be specified, these may be From 6704c863015a8c797796db379b89618e02d277b1 Mon Sep 17 00:00:00 2001 From: Bob Beck Date: Sun, 4 Apr 2010 23:05:15 +0000 Subject: [PATCH 0677/1180] rather than using an empty "" as the default window title, put the hostname of the machine we are running on in there. makes my many green lines easier to deal with without using fiddly options to set it. ok nicm@ --- screen.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/screen.c b/screen.c index 56dbbf37..a22b0f34 100644 --- a/screen.c +++ b/screen.c @@ -31,9 +31,14 @@ void screen_resize_y(struct screen *, u_int); void screen_init(struct screen *s, u_int sx, u_int sy, u_int hlimit) { + char hn[MAXHOSTNAMELEN]; + s->grid = grid_create(sx, sy, hlimit); - s->title = xstrdup(""); + if (gethostname(hn, MAXHOSTNAMELEN) == 0) + s->title = xstrdup(hn); + else + s->title = xstrdup(""); s->tabs = NULL; From f81190a793d1b62ba12de54433c6a115db9950ca Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 5 Apr 2010 17:46:05 +0000 Subject: [PATCH 0678/1180] Mention title setting, and the new default. --- tmux.1 | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tmux.1 b/tmux.1 index 0fd7c8c8..af50c729 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1749,6 +1749,14 @@ global environment set (see the .Sx ENVIRONMENT section). .Pp +The window title (#T) is the title set by the program running within the window +using the OSC title setting sequence, for example: +.Bd -literal -offset indent +$ printf '\e033]2;My Title\e033\e\e' +.Ed +.Pp +When a window is first created, its title is the hostname. +.Pp #[attributes] allows a comma-separated list of attributes to be specified, these may be .Ql fg=colour From ac9daf92d72210570dc9cb63fd0058e4ff50b7a5 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 6 Apr 2010 21:35:44 +0000 Subject: [PATCH 0679/1180] Merge copy mode and output mode, dropping the latter. Idea and code from Micah Cowan. --- Makefile | 2 +- cmd-copy-mode.c | 1 + cmd-new-session.c | 5 +- grid.c | 41 -------- key-bindings.c | 8 +- screen-write.c | 5 +- screen.c | 3 +- server.c | 5 +- tmux.1 | 26 +++-- tmux.h | 10 +- window-copy.c | 257 ++++++++++++++++++++++++++++++++------------- window-more.c | 260 ---------------------------------------------- 12 files changed, 222 insertions(+), 401 deletions(-) delete mode 100644 window-more.c diff --git a/Makefile b/Makefile index be0051ef..a730cbbc 100644 --- a/Makefile +++ b/Makefile @@ -37,7 +37,7 @@ SRCS= attributes.c cfg.c client.c clock.c \ resize.c screen-redraw.c screen-write.c screen.c session.c status.c \ server-fn.c server.c server-client.c server-window.c \ tmux.c tty-keys.c tty-term.c tty.c utf8.c \ - window-choose.c window-clock.c window-copy.c window-more.c window.c \ + window-choose.c window-clock.c window-copy.c window.c \ xterm-keys.c xmalloc.c CDIAGFLAGS+= -Wno-long-long -Wall -W -Wnested-externs -Wformat=2 diff --git a/cmd-copy-mode.c b/cmd-copy-mode.c index ed95105a..714ec35f 100644 --- a/cmd-copy-mode.c +++ b/cmd-copy-mode.c @@ -63,6 +63,7 @@ cmd_copy_mode_exec(struct cmd *self, struct cmd_ctx *ctx) return (-1); window_pane_set_mode(wp, &window_copy_mode); + window_copy_init_from_pane(wp); if (wp->mode == &window_copy_mode && cmd_check_flag(data->chflags, 'u')) window_copy_pageup(wp); diff --git a/cmd-new-session.c b/cmd-new-session.c index 3dc7c7b3..5e175bea 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -287,10 +287,11 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) */ if (cfg_finished && !ARRAY_EMPTY(&cfg_causes)) { wp = s->curw->window->active; - window_pane_set_mode(wp, &window_more_mode); + window_pane_set_mode(wp, &window_copy_mode); + window_copy_init_for_output(wp); for (i = 0; i < ARRAY_LENGTH(&cfg_causes); i++) { cause = ARRAY_ITEM(&cfg_causes, i); - window_more_add(wp, "%s", cause); + window_copy_add(wp, "%s", cause); xfree(cause); } ARRAY_FREE(&cfg_causes); diff --git a/grid.c b/grid.c index b7fa2783..b11e5a97 100644 --- a/grid.c +++ b/grid.c @@ -46,18 +46,9 @@ const struct grid_cell grid_default_cell = { 0, 0, 8, 8, ' ' }; gc, sizeof gd->linedata[py].utf8data[px]); \ } while (0) -int grid_check_x(struct grid *, u_int); int grid_check_y(struct grid *, u_int); #ifdef DEBUG -int -grid_check_x(struct grid *gd, u_int px) -{ - if ((px) >= (gd)->sx) - log_fatalx("x out of range: %u", px); - return (0); -} - int grid_check_y(struct grid *gd, u_int py) { @@ -66,16 +57,6 @@ grid_check_y(struct grid *gd, u_int py) return (0); } #else -int -grid_check_x(struct grid *gd, u_int px) -{ - if ((px) >= (gd)->sx) { - log_debug("x out of range: %u", px); - return (-1); - } - return (0); -} - int grid_check_y(struct grid *gd, u_int py) { @@ -270,8 +251,6 @@ grid_expand_line_utf8(struct grid *gd, u_int py, u_int sx) const struct grid_cell * grid_peek_cell(struct grid *gd, u_int px, u_int py) { - if (grid_check_x(gd, px) != 0) - return (&grid_default_cell); if (grid_check_y(gd, py) != 0) return (&grid_default_cell); @@ -284,8 +263,6 @@ grid_peek_cell(struct grid *gd, u_int px, u_int py) struct grid_cell * grid_get_cell(struct grid *gd, u_int px, u_int py) { - if (grid_check_x(gd, px) != 0) - return (NULL); if (grid_check_y(gd, py) != 0) return (NULL); @@ -298,8 +275,6 @@ void grid_set_cell( struct grid *gd, u_int px, u_int py, const struct grid_cell *gc) { - if (grid_check_x(gd, px) != 0) - return; if (grid_check_y(gd, py) != 0) return; @@ -311,8 +286,6 @@ grid_set_cell( const struct grid_utf8 * grid_peek_utf8(struct grid *gd, u_int px, u_int py) { - if (grid_check_x(gd, px) != 0) - return (NULL); if (grid_check_y(gd, py) != 0) return (NULL); @@ -325,8 +298,6 @@ grid_peek_utf8(struct grid *gd, u_int px, u_int py) struct grid_utf8 * grid_get_utf8(struct grid *gd, u_int px, u_int py) { - if (grid_check_x(gd, px) != 0) - return (NULL); if (grid_check_y(gd, py) != 0) return (NULL); @@ -339,8 +310,6 @@ void grid_set_utf8( struct grid *gd, u_int px, u_int py, const struct grid_utf8 *gc) { - if (grid_check_x(gd, px) != 0) - return; if (grid_check_y(gd, py) != 0) return; @@ -364,10 +333,6 @@ grid_clear(struct grid *gd, u_int px, u_int py, u_int nx, u_int ny) return; } - if (grid_check_x(gd, px) != 0) - return; - if (grid_check_x(gd, px + nx - 1) != 0) - return; if (grid_check_y(gd, py) != 0) return; if (grid_check_y(gd, py + ny - 1) != 0) @@ -465,12 +430,6 @@ grid_move_cells(struct grid *gd, u_int dx, u_int px, u_int py, u_int nx) if (nx == 0 || px == dx) return; - if (grid_check_x(gd, px) != 0) - return; - if (grid_check_x(gd, px + nx - 1) != 0) - return; - if (grid_check_x(gd, dx + nx - 1) != 0) - return; if (grid_check_y(gd, py) != 0) return; gl = &gd->linedata[py]; diff --git a/key-bindings.c b/key-bindings.c index 2eb5327c..7b96a12d 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -211,12 +211,14 @@ key_bindings_print(struct cmd_ctx *ctx, const char *fmt, ...) struct winlink *wl = ctx->curclient->session->curw; va_list ap; - if (wl->window->active->mode != &window_more_mode) + if (wl->window->active->mode != &window_copy_mode) { window_pane_reset_mode(wl->window->active); - window_pane_set_mode(wl->window->active, &window_more_mode); + window_pane_set_mode(wl->window->active, &window_copy_mode); + window_copy_init_for_output(wl->window->active); + } va_start(ap, fmt); - window_more_vadd(wl->window->active, fmt, ap); + window_copy_vadd(wl->window->active, fmt, ap); va_end(ap); } diff --git a/screen-write.c b/screen-write.c index e26959fd..083544c4 100644 --- a/screen-write.c +++ b/screen-write.c @@ -1009,13 +1009,14 @@ screen_write_cell(struct screen_write_ctx *ctx, } /* Check this will fit on the current line and wrap if not. */ - if (s->cx > screen_size_x(s) - width) { + if ((s->mode & MODE_WRAP) && s->cx > screen_size_x(s) - width) { screen_write_linefeed(ctx, 1); s->cx = 0; /* carriage return */ } /* Sanity checks. */ - if (s->cx > screen_size_x(s) - 1 || s->cy > screen_size_y(s) - 1) + if (((s->mode & MODE_WRAP) && s->cx > screen_size_x(s) - 1) + || s->cy > screen_size_y(s) - 1) return; /* Handle overwriting of UTF-8 characters. */ diff --git a/screen.c b/screen.c index a22b0f34..333ff969 100644 --- a/screen.c +++ b/screen.c @@ -20,6 +20,7 @@ #include #include +#include #include #include "tmux.h" @@ -55,7 +56,7 @@ screen_reinit(struct screen *s) s->rupper = 0; s->rlower = screen_size_y(s) - 1; - s->mode = MODE_CURSOR; + s->mode = MODE_CURSOR | MODE_WRAP; screen_reset_tabs(s); diff --git a/server.c b/server.c index 2859b52a..017cc729 100644 --- a/server.c +++ b/server.c @@ -182,10 +182,11 @@ server_start(char *path) */ if (!ARRAY_EMPTY(&sessions) && !ARRAY_EMPTY(&cfg_causes)) { wp = ARRAY_FIRST(&sessions)->curw->window->active; - window_pane_set_mode(wp, &window_more_mode); + window_pane_set_mode(wp, &window_copy_mode); + window_copy_init_for_output(wp); for (i = 0; i < ARRAY_LENGTH(&cfg_causes); i++) { cause = ARRAY_ITEM(&cfg_causes, i); - window_more_add(wp, "%s", cause); + window_copy_add(wp, "%s", cause); xfree(cause); } ARRAY_FREE(&cfg_causes); diff --git a/tmux.1 b/tmux.1 index af50c729..f4af706b 100644 --- a/tmux.1 +++ b/tmux.1 @@ -586,14 +586,8 @@ A .Nm window may be in one of several modes. The default permits direct access to the terminal attached to the window. -The others are: -.Bl -tag -width Ds -.It Em output mode -This is entered when a command which produces output, such as -.Ic list-keys , -is executed from a key binding. -.It Em copy mode -This permits a section of a window or its history to be copied to a +The other is copy mode, which permits a section of a window or its +history to be copied to a .Em paste buffer for later insertion into another window. This mode is entered with the @@ -601,7 +595,9 @@ This mode is entered with the command, bound to .Ql \&[ by default. -.El +It is also entered when a command that produces output, such as +.Ic list-keys , +is executed from a key binding. .Pp The keys available depend on whether emacs or vi mode is selected (see the @@ -699,7 +695,7 @@ and .Em emacs-choice for keys used when choosing from lists (such as produced by the .Ic choose-window -command) or in output mode; and +command); and .Em vi-copy and .Em emacs-copy @@ -714,7 +710,9 @@ and The paste buffer key pastes the first line from the top paste buffer on the stack. .Pp -The mode commands are as follows: +The synopsis for the +.Ic copy-mode +command is: .Bl -tag -width Ds .It Xo Ic copy-mode .Op Fl u @@ -2032,8 +2030,8 @@ command. .It Xo Ic synchronize-panes .Op Ic on | off .Xc -Duplicate input to any pane to all other panes in the same window, except -for panes that are not in output mode. +Duplicate input to any pane to all other panes in the same window (only +for panes that are not in any special mode). .Pp .It Xo Ic alternate-screen .Op Ic on | off @@ -2443,7 +2441,7 @@ option. Execute .Ar shell-command in the background without creating a window. -After it finishes, any output to stdout is displayed in output mode. +After it finishes, any output to stdout is displayed in copy mode. If the command doesn't return success, the exit status is also displayed. .It Ic server-info .D1 (alias: Ic info ) diff --git a/tmux.h b/tmux.h index 642d5530..80a6a9a7 100644 --- a/tmux.h +++ b/tmux.h @@ -541,6 +541,7 @@ struct mode_key_table { #define MODE_KCURSOR 0x4 #define MODE_KKEYPAD 0x8 /* set = application, clear = number */ #define MODE_MOUSE 0x10 +#define MODE_WRAP 0x20 /* whether lines wrap */ /* * A single UTF-8 character. @@ -1880,13 +1881,12 @@ extern const struct window_mode window_clock_mode; /* window-copy.c */ extern const struct window_mode window_copy_mode; +void window_copy_init_from_pane(struct window_pane *); +void window_copy_init_for_output(struct window_pane *); +void window_copy_add(struct window_pane *, const char *, ...); +void window_copy_vadd(struct window_pane *, const char *, va_list); void window_copy_pageup(struct window_pane *); -/* window-more.c */ -extern const struct window_mode window_more_mode; -void window_more_add(struct window_pane *, const char *, ...); -void window_more_vadd(struct window_pane *, const char *, va_list); - /* window-choose.c */ extern const struct window_mode window_choose_mode; void window_choose_vadd( diff --git a/window-copy.c b/window-copy.c index 5d915dee..bb0e81c5 100644 --- a/window-copy.c +++ b/window-copy.c @@ -93,9 +93,28 @@ enum window_copy_input_type { WINDOW_COPY_GOTOLINE, }; +/* + * Copy-mode's visible screen (the "screen" field) is filled from one of + * two sources: the original contents of the pane (used when we + * actually enter via the "copy-mode" command, to copy the contents of + * the current pane), or else a series of lines containing the output + * from an output-writing tmux command (such as any of the "show-*" or + * "list-*" commands). + * + * In either case, the full content of the copy-mode grid is pointed at + * by the "backing" field, and is copied into "screen" as needed (that + * is, when scrolling occurs). When copy-mode is backed by a pane, + * backing points directly at that pane's screen structure (&wp->base); + * when backed by a list of output-lines from a command, it points at + * a newly-allocated screen structure (which is deallocated when the + * mode ends). + */ struct window_copy_mode_data { struct screen screen; + struct screen *backing; + int backing_written; /* backing display has started */ + struct mode_key_data mdata; u_int oy; @@ -129,18 +148,18 @@ window_copy_init(struct window_pane *wp) { struct window_copy_mode_data *data; struct screen *s; - struct screen_write_ctx ctx; - u_int i; int keys; wp->modedata = data = xmalloc(sizeof *data); data->oy = 0; - data->cx = wp->base.cx; - data->cy = wp->base.cy; + data->cx = 0; + data->cy = 0; data->lastcx = 0; data->lastsx = 0; + data->backing_written = 0; + data->rectflag = 0; data->inputtype = WINDOW_COPY_OFF; @@ -168,6 +187,26 @@ window_copy_init(struct window_pane *wp) else mode_key_init(&data->mdata, &mode_key_tree_vi_copy); + data->backing = NULL; + + return (s); +} + +void +window_copy_init_from_pane(struct window_pane *wp) +{ + struct window_copy_mode_data *data = wp->modedata; + struct screen *s = &data->screen; + struct screen_write_ctx ctx; + u_int i; + + if (wp->mode != &window_copy_mode) + fatalx("not in copy mode"); + + data->backing = &wp->base; + data->cx = data->backing->cx; + data->cy = data->backing->cy; + s->cx = data->cx; s->cy = data->cy; @@ -176,8 +215,17 @@ window_copy_init(struct window_pane *wp) window_copy_write_line(wp, &ctx, i); screen_write_cursormove(&ctx, data->cx, data->cy); screen_write_stop(&ctx); +} - return (s); +void +window_copy_init_for_output(struct window_pane *wp) +{ + struct window_copy_mode_data *data = wp->modedata; + + data->backing = xmalloc(sizeof *data->backing); + screen_init(data->backing, screen_size_x(&wp->base), + screen_size_y(&wp->base), UINT_MAX); + data->backing->mode &= ~MODE_WRAP; } void @@ -192,11 +240,73 @@ window_copy_free(struct window_pane *wp) xfree(data->searchstr); xfree(data->inputstr); + if (data->backing != &wp->base) { + screen_free(data->backing); + xfree(data->backing); + } screen_free(&data->screen); xfree(data); } +void +window_copy_add(struct window_pane *wp, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + window_copy_vadd(wp, fmt, ap); + va_end(ap); +} + +void +window_copy_vadd(struct window_pane *wp, const char *fmt, va_list ap) +{ + struct window_copy_mode_data *data = wp->modedata; + struct screen *backing = data->backing; + struct screen_write_ctx back_ctx, ctx; + struct grid_cell gc; + int utf8flag; + u_int old_hsize; + + if (backing == &wp->base) + return; + + utf8flag = options_get_number(&wp->window->options, "utf8"); + memcpy(&gc, &grid_default_cell, sizeof gc); + + old_hsize = screen_hsize(data->backing); + screen_write_start(&back_ctx, NULL, backing); + if (data->backing_written) { + /* + * On the second or later line, do a CRLF before writing + * (so it's on a new line). + */ + screen_write_carriagereturn(&back_ctx); + screen_write_linefeed(&back_ctx, 0); + } else + data->backing_written = 1; + screen_write_vnputs(&back_ctx, 0, &gc, utf8flag, fmt, ap); + screen_write_stop(&back_ctx); + + data->oy += screen_hsize(data->backing) - old_hsize; + + screen_write_start(&ctx, wp, &data->screen); + + /* + * If the history has changed, draw the top line. + * (If there's any history at all, it has changed.) + */ + if (screen_hsize(data->backing)) + window_copy_redraw_lines(wp, 0, 1); + + /* Write the line, if it's visible. */ + if (backing->cy + data->oy < screen_size_y(backing)) + window_copy_redraw_lines(wp, backing->cy, 1); + + screen_write_stop(&ctx); +} + void window_copy_pageup(struct window_pane *wp) { @@ -207,8 +317,8 @@ window_copy_pageup(struct window_pane *wp) n = 1; if (screen_size_y(s) > 2) n = screen_size_y(s) - 2; - if (data->oy + n > screen_hsize(&wp->base)) - data->oy = screen_hsize(&wp->base); + if (data->oy + n > screen_hsize(data->backing)) + data->oy = screen_hsize(data->backing); else data->oy += n; window_copy_update_selection(wp); @@ -223,6 +333,8 @@ window_copy_resize(struct window_pane *wp, u_int sx, u_int sy) struct screen_write_ctx ctx; screen_resize(s, sx, sy); + if (data->backing != &wp->base) + screen_resize(data->backing, sx, sy); if (data->cy > sy - 1) data->cy = sy - 1; @@ -329,8 +441,8 @@ window_copy_key(struct window_pane *wp, struct client *c, int key) case MODEKEYCOPY_HALFPAGEUP: n = screen_size_y(s) / 2; for (; np != 0; np--) { - if (data->oy + n > screen_hsize(&wp->base)) - data->oy = screen_hsize(&wp->base); + if (data->oy + n > screen_hsize(data->backing)) + data->oy = screen_hsize(data->backing); else data->oy += n; } @@ -369,7 +481,7 @@ window_copy_key(struct window_pane *wp, struct client *c, int key) case MODEKEYCOPY_HISTORYTOP: data->cx = 0; data->cy = 0; - data->oy = screen_hsize(&wp->base); + data->oy = screen_hsize(data->backing); window_copy_update_selection(wp); window_copy_redraw_screen(wp); break; @@ -665,8 +777,7 @@ void window_copy_scroll_to(struct window_pane *wp, u_int px, u_int py) { struct window_copy_mode_data *data = wp->modedata; - struct screen *s = &wp->base; - struct grid *gd = s->grid; + struct grid *gd = data->backing->grid; u_int offset, gap; data->cx = px; @@ -761,7 +872,7 @@ void window_copy_search_up(struct window_pane *wp, const char *searchstr) { struct window_copy_mode_data *data = wp->modedata; - struct screen *s = &wp->base, ss; + struct screen *s = data->backing, ss; struct screen_write_ctx ctx; struct grid *gd = s->grid, *sgd; struct grid_cell gc; @@ -818,7 +929,7 @@ void window_copy_search_down(struct window_pane *wp, const char *searchstr) { struct window_copy_mode_data *data = wp->modedata; - struct screen *s = &wp->base, ss; + struct screen *s = data->backing, ss; struct screen_write_ctx ctx; struct grid *gd = s->grid, *sgd; struct grid_cell gc; @@ -878,7 +989,7 @@ window_copy_goto_line(struct window_pane *wp, const char *linestr) const char *errstr; u_int lineno; - lineno = strtonum(linestr, 0, screen_hsize(&wp->base), &errstr); + lineno = strtonum(linestr, 0, screen_hsize(data->backing), &errstr); if (errstr != NULL) return; @@ -906,7 +1017,7 @@ window_copy_write_line( last = screen_size_y(s) - 1; if (py == 0) { size = xsnprintf(hdr, sizeof hdr, - "[%u/%u]", data->oy, screen_hsize(&wp->base)); + "[%u/%u]", data->oy, screen_hsize(data->backing)); 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) { @@ -923,8 +1034,9 @@ window_copy_write_line( size = 0; screen_write_cursormove(ctx, xoff, py); - screen_write_copy(ctx, &wp->base, xoff, (screen_hsize(&wp->base) - - data->oy) + py, screen_size_x(s) - size, 1); + screen_write_copy(ctx, data->backing, xoff, + (screen_hsize(data->backing) - data->oy) + py, + screen_size_x(s) - size, 1); if (py == data->cy && data->cx == screen_size_x(s)) { memcpy(&gc, &grid_default_cell, sizeof gc); @@ -993,7 +1105,7 @@ window_copy_start_selection(struct window_pane *wp) struct screen *s = &data->screen; data->selx = data->cx; - data->sely = screen_hsize(&wp->base) + data->cy - data->oy; + data->sely = screen_hsize(data->backing) + data->cy - data->oy; s->sel.flag = 1; window_copy_update_selection(wp); @@ -1018,7 +1130,7 @@ window_copy_update_selection(struct window_pane *wp) gc.attr |= options_get_number(oo, "mode-attr"); /* Find top of screen. */ - ty = screen_hsize(&wp->base) - data->oy; + ty = screen_hsize(data->backing) - data->oy; /* Adjust the selection. */ sx = data->selx; @@ -1079,7 +1191,7 @@ window_copy_copy_selection(struct window_pane *wp, struct client *c) /* Find start and end. */ xx = data->cx; - yy = screen_hsize(&wp->base) + data->cy - data->oy; + yy = screen_hsize(data->backing) + data->cy - data->oy; if (yy < data->sely || (yy == data->sely && xx < data->selx)) { sx = xx; sy = yy; ex = data->selx; ey = data->sely; @@ -1158,12 +1270,13 @@ void window_copy_copy_line(struct window_pane *wp, char **buf, size_t *off, u_int sy, u_int sx, u_int ex) { - struct grid *gd = wp->base.grid; - const struct grid_cell *gc; - const struct grid_utf8 *gu; - struct grid_line *gl; - u_int i, xx, wrapped = 0; - size_t size; + struct window_copy_mode_data *data = wp->modedata; + struct grid *gd = data->backing->grid; + const struct grid_cell *gc; + const struct grid_utf8 *gu; + struct grid_line *gl; + u_int i, xx, wrapped = 0; + size_t size; if (sx > ex) return; @@ -1218,7 +1331,7 @@ window_copy_clear_selection(struct window_pane *wp) screen_clear_selection(&data->screen); - py = screen_hsize(&wp->base) + data->cy - data->oy; + py = screen_hsize(data->backing) + data->cy - data->oy; px = window_copy_find_length(wp, py); if (data->cx > px) window_copy_update_cursor(wp, px, data->cy); @@ -1227,9 +1340,10 @@ window_copy_clear_selection(struct window_pane *wp) int window_copy_in_set(struct window_pane *wp, u_int px, u_int py, const char *set) { - const struct grid_cell *gc; + struct window_copy_mode_data *data = wp->modedata; + const struct grid_cell *gc; - gc = grid_peek_cell(wp->base.grid, px, py); + gc = grid_peek_cell(data->backing->grid, px, py); if (gc->flags & (GRID_FLAG_PADDING|GRID_FLAG_UTF8)) return (0); if (gc->data == 0x00 || gc->data == 0x7f) @@ -1240,8 +1354,10 @@ window_copy_in_set(struct window_pane *wp, u_int px, u_int py, const char *set) u_int window_copy_find_length(struct window_pane *wp, u_int py) { - const struct grid_cell *gc; - u_int px; + struct window_copy_mode_data *data = wp->modedata; + struct screen *s = data->backing; + const struct grid_cell *gc; + u_int px; /* * If the pane has been resized, its grid can contain old overlong @@ -1249,11 +1365,11 @@ window_copy_find_length(struct window_pane *wp, u_int py) * width of the grid, and screen_write_copy treats them as spaces, so * ignore them here too. */ - px = wp->base.grid->linedata[py].cellsize; - if (px > screen_size_x(&wp->base)) - px = screen_size_x(&wp->base); + px = s->grid->linedata[py].cellsize; + if (px > screen_size_x(s)) + px = screen_size_x(s); while (px > 0) { - gc = grid_peek_cell(wp->base.grid, px - 1, py); + gc = grid_peek_cell(s->grid, px - 1, py); if (gc->flags & GRID_FLAG_UTF8) break; if (gc->data != ' ') @@ -1281,11 +1397,11 @@ window_copy_cursor_back_to_indentation(struct window_pane *wp) const struct grid_cell *gc; px = 0; - py = screen_hsize(&wp->base) + data->cy - data->oy; + py = screen_hsize(data->backing) + data->cy - data->oy; xx = window_copy_find_length(wp, py); while (px < xx) { - gc = grid_peek_cell(wp->base.grid, px, py); + gc = grid_peek_cell(data->backing->grid, px, py); if (gc->flags & GRID_FLAG_UTF8) break; if (gc->data != ' ') @@ -1302,21 +1418,22 @@ void window_copy_cursor_end_of_line(struct window_pane *wp) { struct window_copy_mode_data *data = wp->modedata; - struct screen *base_s = &wp->base; - struct grid *gd = base_s->grid; + struct screen *back_s = data->backing; + struct grid *gd = back_s->grid; u_int px, py; - py = screen_hsize(base_s) + data->cy - data->oy; + py = screen_hsize(back_s) + data->cy - data->oy; px = window_copy_find_length(wp, py); if (data->cx == px) { if (data->screen.sel.flag && data->rectflag) - px = screen_size_x(&wp->base); + px = screen_size_x(back_s); if (gd->linedata[py].flags & GRID_LINE_WRAPPED) { while (py < gd->sy + gd->hsize && gd->linedata[py].flags & GRID_LINE_WRAPPED) { window_copy_cursor_down(wp, 0); - py = screen_hsize(base_s) + data->cy - data->oy; + py = screen_hsize(back_s) + + data->cy - data->oy; } px = window_copy_find_length(wp, py); } @@ -1351,7 +1468,7 @@ window_copy_cursor_right(struct window_pane *wp) if (data->screen.sel.flag && data->rectflag) px = screen_size_x(&data->screen); else { - py = screen_hsize(&wp->base) + data->cy - data->oy; + py = screen_hsize(data->backing) + data->cy - data->oy; px = window_copy_find_length(wp, py); } @@ -1372,7 +1489,7 @@ window_copy_cursor_up(struct window_pane *wp, int scroll_only) struct screen *s = &data->screen; u_int ox, oy, px, py; - oy = screen_hsize(&wp->base) + data->cy - data->oy; + oy = screen_hsize(data->backing) + data->cy - data->oy; ox = window_copy_find_length(wp, oy); if (ox != 0) { data->lastcx = data->cx; @@ -1399,7 +1516,7 @@ window_copy_cursor_up(struct window_pane *wp, int scroll_only) } if (!data->screen.sel.flag || !data->rectflag) { - py = screen_hsize(&wp->base) + data->cy - data->oy; + py = screen_hsize(data->backing) + data->cy - data->oy; px = window_copy_find_length(wp, py); if ((data->cx >= data->lastsx && data->cx != px) || data->cx > px) @@ -1414,7 +1531,7 @@ window_copy_cursor_down(struct window_pane *wp, int scroll_only) struct screen *s = &data->screen; u_int ox, oy, px, py; - oy = screen_hsize(&wp->base) + data->cy - data->oy; + oy = screen_hsize(data->backing) + data->cy - data->oy; ox = window_copy_find_length(wp, oy); if (ox != 0) { data->lastcx = data->cx; @@ -1433,7 +1550,7 @@ window_copy_cursor_down(struct window_pane *wp, int scroll_only) } if (!data->screen.sel.flag || !data->rectflag) { - py = screen_hsize(&wp->base) + data->cy - data->oy; + py = screen_hsize(data->backing) + data->cy - data->oy; px = window_copy_find_length(wp, py); if ((data->cx >= data->lastsx && data->cx != px) || data->cx > px) @@ -1445,16 +1562,16 @@ void window_copy_cursor_jump(struct window_pane *wp) { struct window_copy_mode_data *data = wp->modedata; - struct screen *base_s = &wp->base; + struct screen *back_s = data->backing; const struct grid_cell *gc; uint px, py, xx; px = data->cx + 1; - py = screen_hsize(base_s) + data->cy - data->oy; + py = screen_hsize(back_s) + data->cy - data->oy; xx = window_copy_find_length(wp, py); while (px < xx) { - gc = grid_peek_cell(base_s->grid, px, py); + gc = grid_peek_cell(back_s->grid, px, py); if ((gc->flags & (GRID_FLAG_PADDING|GRID_FLAG_UTF8)) == 0 && gc->data == data->jumpchar) { @@ -1471,18 +1588,18 @@ void window_copy_cursor_jump_back(struct window_pane *wp) { struct window_copy_mode_data *data = wp->modedata; - struct screen *base_s = &wp->base; + struct screen *back_s = data->backing; const struct grid_cell *gc; uint px, py; px = data->cx; - py = screen_hsize(base_s) + data->cy - data->oy; + py = screen_hsize(back_s) + data->cy - data->oy; if (px > 0) px--; for (;;) { - gc = grid_peek_cell(base_s->grid, px, py); + gc = grid_peek_cell(back_s->grid, px, py); if ((gc->flags & (GRID_FLAG_PADDING|GRID_FLAG_UTF8)) == 0 && gc->data == data->jumpchar) { @@ -1501,14 +1618,14 @@ void window_copy_cursor_next_word(struct window_pane *wp, const char *separators) { struct window_copy_mode_data *data = wp->modedata; - struct screen *base_s = &wp->base; + struct screen *back_s = data->backing; u_int px, py, xx, yy; int expected = 0; px = data->cx; - py = screen_hsize(base_s) + data->cy - data->oy; + py = screen_hsize(back_s) + data->cy - data->oy; xx = window_copy_find_length(wp, py); - yy = screen_hsize(base_s) + screen_size_y(base_s) - 1; + yy = screen_hsize(back_s) + screen_size_y(back_s) - 1; /* * First skip past any nonword characters and then any word characters. @@ -1526,7 +1643,7 @@ window_copy_cursor_next_word(struct window_pane *wp, const char *separators) window_copy_cursor_down(wp, 0); px = 0; - py = screen_hsize(base_s) + data->cy - data->oy; + py = screen_hsize(back_s) + data->cy - data->oy; xx = window_copy_find_length(wp, py); } else px++; @@ -1543,14 +1660,14 @@ void window_copy_cursor_next_word_end(struct window_pane *wp, const char *separators) { struct window_copy_mode_data *data = wp->modedata; - struct screen *base_s = &wp->base; + struct screen *back_s = data->backing; u_int px, py, xx, yy; int expected = 1; px = data->cx; - py = screen_hsize(base_s) + data->cy - data->oy; + py = screen_hsize(back_s) + data->cy - data->oy; xx = window_copy_find_length(wp, py); - yy = screen_hsize(base_s) + screen_size_y(base_s) - 1; + yy = screen_hsize(back_s) + screen_size_y(back_s) - 1; /* * First skip past any word characters, then any nonword characters. @@ -1568,7 +1685,7 @@ window_copy_cursor_next_word_end(struct window_pane *wp, const char *separators) window_copy_cursor_down(wp, 0); px = 0; - py = screen_hsize(base_s) + data->cy - data->oy; + py = screen_hsize(back_s) + data->cy - data->oy; xx = window_copy_find_length(wp, py); } else px++; @@ -1589,7 +1706,7 @@ window_copy_cursor_previous_word(struct window_pane *wp, const char *separators) u_int px, py; px = data->cx; - py = screen_hsize(&wp->base) + data->cy - data->oy; + py = screen_hsize(data->backing) + data->cy - data->oy; /* Move back to the previous word character. */ for (;;) { @@ -1599,12 +1716,12 @@ window_copy_cursor_previous_word(struct window_pane *wp, const char *separators) break; } else { if (data->cy == 0 && - (screen_hsize(&wp->base) == 0 || - data->oy >= screen_hsize(&wp->base) - 1)) + (screen_hsize(data->backing) == 0 || + data->oy >= screen_hsize(data->backing) - 1)) goto out; window_copy_cursor_up(wp, 0); - py = screen_hsize(&wp->base) + data->cy - data->oy; + py = screen_hsize(data->backing) + data->cy - data->oy; px = window_copy_find_length(wp, py); } } @@ -1657,11 +1774,11 @@ window_copy_scroll_down(struct window_pane *wp, u_int ny) struct screen *s = &data->screen; struct screen_write_ctx ctx; - if (ny > screen_hsize(&wp->base)) + if (ny > screen_hsize(data->backing)) return; - if (data->oy > screen_hsize(&wp->base) - ny) - ny = screen_hsize(&wp->base) - data->oy; + if (data->oy > screen_hsize(data->backing) - ny) + ny = screen_hsize(data->backing) - data->oy; if (ny == 0) return; data->oy += ny; @@ -1688,7 +1805,7 @@ window_copy_rectangle_toggle(struct window_pane *wp) data->rectflag = !data->rectflag; - py = screen_hsize(&wp->base) + data->cy - data->oy; + py = screen_hsize(data->backing) + data->cy - data->oy; px = window_copy_find_length(wp, py); if (data->cx > px) window_copy_update_cursor(wp, px, data->cy); diff --git a/window-more.c b/window-more.c deleted file mode 100644 index 84f37d53..00000000 --- a/window-more.c +++ /dev/null @@ -1,260 +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 - -#include "tmux.h" - -struct screen *window_more_init(struct window_pane *); -void window_more_free(struct window_pane *); -void window_more_resize(struct window_pane *, u_int, u_int); -void window_more_key(struct window_pane *, struct client *, int); - -void window_more_redraw_screen(struct window_pane *); -void window_more_write_line( - struct window_pane *, struct screen_write_ctx *, u_int); - -void window_more_scroll_up(struct window_pane *); -void window_more_scroll_down(struct window_pane *); - -const struct window_mode window_more_mode = { - window_more_init, - window_more_free, - window_more_resize, - window_more_key, - NULL, - NULL, -}; - -struct window_more_mode_data { - struct screen screen; - - struct mode_key_data mdata; - - ARRAY_DECL(, char *) list; - u_int top; -}; - -void -window_more_add(struct window_pane *wp, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - window_more_vadd(wp, fmt, ap); - va_end(ap); -} - -void -window_more_vadd(struct window_pane *wp, const char *fmt, va_list ap) -{ - struct window_more_mode_data *data = wp->modedata; - struct screen *s = &data->screen; - struct screen_write_ctx ctx; - char *msg; - u_int size; - - xvasprintf(&msg, fmt, ap); - ARRAY_ADD(&data->list, msg); - - screen_write_start(&ctx, wp, NULL); - size = ARRAY_LENGTH(&data->list) - 1; - if (size >= data->top && size <= data->top + screen_size_y(s) - 1) { - window_more_write_line(wp, &ctx, size - data->top); - if (size != data->top) - window_more_write_line(wp, &ctx, 0); - } else - window_more_write_line(wp, &ctx, 0); - screen_write_stop(&ctx); -} - -struct screen * -window_more_init(struct window_pane *wp) -{ - struct window_more_mode_data *data; - struct screen *s; - int keys; - - wp->modedata = data = xmalloc(sizeof *data); - ARRAY_INIT(&data->list); - data->top = 0; - - s = &data->screen; - screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0); - s->mode &= ~MODE_CURSOR; - - keys = options_get_number(&wp->window->options, "mode-keys"); - if (keys == MODEKEY_EMACS) - mode_key_init(&data->mdata, &mode_key_tree_emacs_choice); - else - mode_key_init(&data->mdata, &mode_key_tree_vi_choice); - - return (s); -} - -void -window_more_free(struct window_pane *wp) -{ - struct window_more_mode_data *data = wp->modedata; - u_int i; - - for (i = 0; i < ARRAY_LENGTH(&data->list); i++) - xfree(ARRAY_ITEM(&data->list, i)); - ARRAY_FREE(&data->list); - - screen_free(&data->screen); - xfree(data); -} - -void -window_more_resize(struct window_pane *wp, u_int sx, u_int sy) -{ - struct window_more_mode_data *data = wp->modedata; - struct screen *s = &data->screen; - - screen_resize(s, sx, sy); - window_more_redraw_screen(wp); -} - -/* ARGSUSED */ -void -window_more_key(struct window_pane *wp, unused struct client *c, int key) -{ - struct window_more_mode_data *data = wp->modedata; - struct screen *s = &data->screen; - - switch (mode_key_lookup(&data->mdata, key)) { - case MODEKEYCHOICE_CANCEL: - window_pane_reset_mode(wp); - break; - case MODEKEYCHOICE_UP: - case MODEKEYCHOICE_SCROLLUP: - window_more_scroll_up(wp); - break; - case MODEKEYCHOICE_DOWN: - case MODEKEYCHOICE_SCROLLDOWN: - window_more_scroll_down(wp); - break; - case MODEKEYCHOICE_PAGEUP: - if (data->top < screen_size_y(s)) - data->top = 0; - else - data->top -= screen_size_y(s); - window_more_redraw_screen(wp); - break; - case MODEKEYCHOICE_PAGEDOWN: - if (data->top + screen_size_y(s) > ARRAY_LENGTH(&data->list)) - data->top = ARRAY_LENGTH(&data->list); - else - data->top += screen_size_y(s); - window_more_redraw_screen(wp); - break; - default: - break; - } -} - -void -window_more_write_line( - struct window_pane *wp, struct screen_write_ctx *ctx, u_int py) -{ - struct window_more_mode_data *data = wp->modedata; - struct screen *s = &data->screen; - struct options *oo = &wp->window->options; - struct grid_cell gc; - char *msg, hdr[32]; - size_t size; - int utf8flag; - - utf8flag = options_get_number(&wp->window->options, "utf8"); - memcpy(&gc, &grid_default_cell, sizeof gc); - - if (py == 0) { - size = xsnprintf(hdr, sizeof hdr, - "[%u/%u]", data->top, ARRAY_LENGTH(&data->list)); - screen_write_cursormove(ctx, screen_size_x(s) - size, 0); - 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"); - screen_write_puts(ctx, &gc, "%s", hdr); - memcpy(&gc, &grid_default_cell, sizeof gc); - } else - size = 0; - - screen_write_cursormove(ctx, 0, py); - if (data->top + py < ARRAY_LENGTH(&data->list)) { - msg = ARRAY_ITEM(&data->list, data->top + py); - screen_write_nputs( - ctx, screen_size_x(s) - size, &gc, utf8flag, "%s", msg); - } - while (s->cx < screen_size_x(s) - size) - screen_write_putc(ctx, &gc, ' '); -} - -void -window_more_redraw_screen(struct window_pane *wp) -{ - struct window_more_mode_data *data = wp->modedata; - struct screen *s = &data->screen; - struct screen_write_ctx ctx; - u_int i; - - screen_write_start(&ctx, wp, NULL); - for (i = 0; i < screen_size_y(s); i++) - window_more_write_line(wp, &ctx, i); - screen_write_stop(&ctx); -} - -void -window_more_scroll_up(struct window_pane *wp) -{ - struct window_more_mode_data *data = wp->modedata; - struct screen_write_ctx ctx; - - if (data->top == 0) - return; - data->top--; - - screen_write_start(&ctx, wp, NULL); - screen_write_cursormove(&ctx, 0, 0); - screen_write_insertline(&ctx, 1); - window_more_write_line(wp, &ctx, 0); - window_more_write_line(wp, &ctx, 1); - screen_write_stop(&ctx); -} - -void -window_more_scroll_down(struct window_pane *wp) -{ - struct window_more_mode_data *data = wp->modedata; - struct screen *s = &data->screen; - struct screen_write_ctx ctx; - - if (data->top >= ARRAY_LENGTH(&data->list)) - return; - data->top++; - - screen_write_start(&ctx, wp, NULL); - screen_write_cursormove(&ctx, 0, 0); - screen_write_deleteline(&ctx, 1); - window_more_write_line(wp, &ctx, screen_size_y(s) - 1); - window_more_write_line(wp, &ctx, 0); - screen_write_stop(&ctx); -} From a2c86dcbf6464634ebbc63ef1cd2966b8ef132f9 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 7 Apr 2010 18:09:39 +0000 Subject: [PATCH 0680/1180] Remove XXX comment and just close received fd if calloc() fails. If this happens the imsg may no longer be usable as there may be queued messages, but this is a) already the case with the code now, and b) would be the case if recvmsg() fails anyway, so we can document that -1 from imsg_read() invalidates the struct imsgbuf. discussed with and ok eric --- imsg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imsg.c b/imsg.c index 263c7c8c..1be7f5ae 100644 --- a/imsg.c +++ b/imsg.c @@ -79,7 +79,7 @@ imsg_read(struct imsgbuf *ibuf) cmsg->cmsg_type == SCM_RIGHTS) { fd = (*(int *)CMSG_DATA(cmsg)); if ((ifd = calloc(1, sizeof(struct imsg_fd))) == NULL) { - /* XXX: this return can leak */ + close(fd); return (-1); } ifd->fd = fd; From 842bc2b855114984c6c182b83523d7268b8b2b0b Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 17 Apr 2010 23:14:17 +0000 Subject: [PATCH 0681/1180] Fix use-after-free of the window link when it is part of a grouped session (and hence could have been recreated), from Micah Cowan. --- cmd-join-pane.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cmd-join-pane.c b/cmd-join-pane.c index 722a2031..acf9b754 100644 --- a/cmd-join-pane.c +++ b/cmd-join-pane.c @@ -151,13 +151,14 @@ cmd_join_pane_exec(struct cmd *self, struct cmd_ctx *ctx) struct winlink *src_wl, *dst_wl; struct window *src_w, *dst_w; struct window_pane *src_wp, *dst_wp; - int size; + int size, dst_idx; enum layout_type type; struct layout_cell *lc; if ((dst_wl = cmd_find_pane(ctx, data->dst, &dst_s, &dst_wp)) == NULL) return (-1); dst_w = dst_wl->window; + dst_idx = dst_wl->idx; if ((src_wl = cmd_find_pane(ctx, data->src, NULL, &src_wp)) == NULL) return (-1); @@ -210,7 +211,7 @@ cmd_join_pane_exec(struct cmd *self, struct cmd_ctx *ctx) if (!data->flag_detached) { window_set_active_pane(dst_w, src_wp); - session_select(dst_s, dst_wl->idx); + session_select(dst_s, dst_idx); server_redraw_session(dst_s); } else server_status_session(dst_s); From a6d52405a8eea89d803a95843687c49f9115ca65 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 17 Apr 2010 23:25:16 +0000 Subject: [PATCH 0682/1180] If remain-on-exit is set, both the error callback and a SIGCHLD could destroy the same pane (because the first one doesn't remove it from the list of panes), causing the pane bufferevent to be freed twice. So don't free it if the fd has already been set to -1, from Romain Francoise. --- server-fn.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/server-fn.c b/server-fn.c index 86d7ffdd..01e78ba2 100644 --- a/server-fn.c +++ b/server-fn.c @@ -325,9 +325,11 @@ server_destroy_pane(struct window_pane *wp) { struct window *w = wp->window; - close(wp->fd); - bufferevent_free(wp->event); - wp->fd = -1; + if (wp->fd != -1) { + close(wp->fd); + bufferevent_free(wp->event); + wp->fd = -1; + } if (options_get_number(&w->options, "remain-on-exit")) return; From 622593a77f30e9a309c1b2e4979bd961b894c858 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 17 Apr 2010 23:31:09 +0000 Subject: [PATCH 0683/1180] Fix typo in escape state table leading to fatal() when \033} or \033~ was entered, from Chris Johnsen. --- input.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/input.c b/input.c index e709b366..f49591a7 100644 --- a/input.c +++ b/input.c @@ -385,7 +385,7 @@ const struct input_transition input_state_esc_enter_table[] = { { 0x5f, 0x5f, NULL, &input_state_apc_string }, { 0x60, 0x6a, input_esc_dispatch, &input_state_ground }, { 0x6b, 0x6b, NULL, &input_state_rename_string }, - { 0x6c, 0x7c, input_esc_dispatch, &input_state_ground }, + { 0x6c, 0x7e, input_esc_dispatch, &input_state_ground }, { 0x7f, 0xff, NULL, NULL }, { -1, -1, NULL, NULL } From 67dd5df8766720925b3a30543b3e151ae6f3bc7b Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 18 Apr 2010 13:41:29 +0000 Subject: [PATCH 0684/1180] Catch SIGCHLD to avoid a zombie, from patrick keshishian. --- tmux.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tmux.c b/tmux.c index 4f0a9090..9feeb300 100644 --- a/tmux.c +++ b/tmux.c @@ -238,6 +238,7 @@ main(int argc, char **argv) struct keylist *keylist; struct env_data envdata; struct msg_command_data cmddata; + struct sigaction sigact; char *s, *shellcmd, *path, *label, *home, *cause; char cwd[MAXPATHLEN], **var; void *buf; @@ -537,6 +538,14 @@ main(int argc, char **argv) exit(1); } + /* Catch SIGCHLD to avoid a zombie when starting the server. */ + memset(&sigact, 0, sizeof sigact); + sigemptyset(&sigact.sa_mask); + sigact.sa_handler = SIG_IGN; + if (sigaction(SIGCHLD, &sigact, NULL) != 0) + fatal("sigaction failed"); + + /* Initialise the client socket/start the server. */ if ((main_ibuf = client_init(path, cmdflags, flags)) == NULL) exit(1); xfree(path); From 3ae1b8269580551b7bf8f0904bcd59611b69aa41 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 21 Apr 2010 21:17:33 +0000 Subject: [PATCH 0685/1180] Rewrite key string conversions to be readable and to work properly for multiple modifiers. --- key-string.c | 198 +++++++++++++++++++++++---------------------------- 1 file changed, 88 insertions(+), 110 deletions(-) diff --git a/key-string.c b/key-string.c index 5c01d062..f20d42db 100644 --- a/key-string.c +++ b/key-string.c @@ -23,10 +23,11 @@ #include "tmux.h" int key_string_search_table(const char *); +int key_string_get_modifiers(const char **); struct { - const char *string; - int key; + const char *string; + int key; } key_string_table[] = { /* Function keys. */ { "F1", KEYC_F1 }, @@ -100,146 +101,123 @@ key_string_search_table(const char *string) return (KEYC_NONE); } -/* Lookup a string and convert to a key value, handling C-/M-/S- prefix. */ +/* Find modifiers. */ +int +key_string_get_modifiers(const char **string) +{ + int modifiers; + + modifiers = 0; + while (((*string)[0] != '\0') && (*string)[1] == '-') { + switch ((*string)[0]) { + case 'C': + case 'c': + modifiers |= KEYC_CTRL; + break; + case 'M': + case 'm': + modifiers |= KEYC_ESCAPE; + break; + case 'S': + case 's': + modifiers |= KEYC_SHIFT; + break; + } + *string += 2; + } + return (modifiers); +} + +/* Lookup a string and convert to a key value. */ int key_string_lookup_string(const char *string) { - int key; - const char *ptr; + int key, modifiers; + /* Check for modifiers. */ + modifiers = 0; + if (string[0] == '^' && string[1] != '\0') { + modifiers |= KEYC_CTRL; + string++; + } + modifiers |= key_string_get_modifiers(&string); if (string[0] == '\0') return (KEYC_NONE); - if (string[1] == '\0') - return ((u_char) string[0]); - ptr = NULL; - if ((string[0] == 'C' || string[0] == 'c') && string[1] == '-') - ptr = string + 2; - else if (string[0] == '^') - ptr = string + 1; - if (ptr != NULL) { - if (ptr[0] == '\0') + /* Is this a standard ASCII key? */ + if (string[1] == '\0') { + key = (u_char) string[0]; + if (key < 32 || key > 126) return (KEYC_NONE); - /* - * Lookup as a named key. If a function key (>= KEYC_BASE), - * return it with the ctrl modifier, otherwise fallthrough with - * the key value from the table (eg for C-Space). If not a - * named key, check for single character keys and try that. - */ - key = key_string_search_table(ptr); - if (key != KEYC_NONE) { - if (key >= KEYC_BASE) - return (key | KEYC_CTRL); - } else { - if (ptr[1] != '\0') + + /* Convert the standard control keys. */ + if (modifiers & KEYC_CTRL) { + if (key >= 97 && key <= 122) + key -= 96; + else if (key >= 65 && key <= 90) + key -= 65; + else if (key == 32) + key = 0; + else if (key == 63) + key = KEYC_BSPACE; + else return (KEYC_NONE); - key = (u_char) ptr[0]; + modifiers &= ~KEYC_CTRL; } - /* - * Figure out if the single character in key is a valid ctrl - * key. - */ - if (key == 32) - return (0); - if (key == 63) - return (KEYC_BSPACE); - if (key >= 64 && key <= 95) - return (key - 64); - if (key >= 97 && key <= 122) - return (key - 96); - return (KEYC_NONE); + return (key | modifiers); } - if ((string[0] == 'M' || string[0] == 'm') && string[1] == '-') { - ptr = string + 2; - if (ptr[0] == '\0') - return (KEYC_NONE); - key = key_string_lookup_string(ptr); - if (key != KEYC_NONE) { - if (key >= KEYC_BASE) - return (key | KEYC_ESCAPE); - } else { - if (ptr[1] == '\0') - return (KEYC_NONE); - key = (u_char) ptr[0]; - } - - if (key >= 32 && key <= 127) - return (key | KEYC_ESCAPE); + /* Otherwise look the key up in the table. */ + key = key_string_search_table(string); + if (key == KEYC_NONE) return (KEYC_NONE); - } - - if ((string[0] == 'S' || string[0] == 's') && string[1] == '-') { - ptr = string + 2; - if (ptr[0] == '\0') - return (KEYC_NONE); - key = key_string_lookup_string(ptr); - if (key != KEYC_NONE) { - if (key >= KEYC_BASE) - return (key | KEYC_SHIFT); - } else { - if (ptr[1] == '\0') - return (KEYC_NONE); - key = (u_char) ptr[0]; - } - - if (key >= 32 && key <= 127) - return (key | KEYC_SHIFT); - return (KEYC_NONE); - } - - return (key_string_search_table(string)); + return (key | modifiers); } /* Convert a key code into string format, with prefix if necessary. */ const char * key_string_lookup_key(int key) { - static char tmp[24], tmp2[24]; - const char *s; - u_int i; + static char out[24]; + char tmp[8]; + u_int i; - if (key == 127) - return (NULL); + *out = '\0'; - if (key & KEYC_ESCAPE) { - if ((s = key_string_lookup_key(key & ~KEYC_ESCAPE)) == NULL) - return (NULL); - xsnprintf(tmp2, sizeof tmp2, "M-%s", s); - return (tmp2); - } - if (key & KEYC_CTRL) { - if ((s = key_string_lookup_key(key & ~KEYC_CTRL)) == NULL) - return (NULL); - xsnprintf(tmp2, sizeof tmp2, "C-%s", s); - return (tmp2); - } - if (key & KEYC_SHIFT) { - if ((s = key_string_lookup_key(key & ~KEYC_SHIFT)) == NULL) - return (NULL); - xsnprintf(tmp2, sizeof tmp2, "S-%s", s); - return (tmp2); - } + /* Fill in the modifiers. */ + if (key & KEYC_CTRL) + strlcat(out, "C-", sizeof out); + if (key & KEYC_ESCAPE) + strlcat(out, "M-", sizeof out); + if (key & KEYC_SHIFT) + strlcat(out, "S-", sizeof out); + key &= ~(KEYC_CTRL|KEYC_ESCAPE|KEYC_SHIFT); + /* Try the key against the string table. */ for (i = 0; i < nitems(key_string_table); i++) { if (key == key_string_table[i].key) - return (key_string_table[i].string); + break; + } + if (i != nitems(key_string_table)) { + strlcat(out, key_string_table[i].string, sizeof out); + return (out); } - if (key >= 32 && key <= 255) { - tmp[0] = (char) key; - tmp[1] = '\0'; - return (tmp); - } + /* Invalid keys are errors. */ + if (key >= 127) + return (NULL); + /* Check for standard or control key. */ if (key >= 0 && key <= 32) { if (key == 0 || key > 26) xsnprintf(tmp, sizeof tmp, "C-%c", 64 + key); else xsnprintf(tmp, sizeof tmp, "C-%c", 96 + key); - return (tmp); + } else if (key >= 32 && key <= 126) { + tmp[0] = key; + tmp[1] = '\0'; } - - return (NULL); + strlcat(out, tmp, sizeof out); + return (out); } From 261b6b861563e9b969da15361609b75cd2b800bc Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 21 Apr 2010 21:41:21 +0000 Subject: [PATCH 0686/1180] Mark zombie windows as dead in choose-window list, from Romain Francoise. --- cmd-choose-window.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmd-choose-window.c b/cmd-choose-window.c index 18b08751..f8318105 100644 --- a/cmd-choose-window.c +++ b/cmd-choose-window.c @@ -101,8 +101,9 @@ cmd_choose_window_exec(struct cmd *self, struct cmd_ctx *ctx) left = right = ""; window_choose_add(wl->window->active, - wm->idx, "%3d: %s%c [%ux%u] (%u panes)%s%s%s", + wm->idx, "%3d: %s%c [%ux%u] (%u panes%s)%s%s%s", wm->idx, w->name, flag, w->sx, w->sy, window_count_panes(w), + w->active->fd == -1 ? ", dead" : "", left, title, right); } From 6769115df2f6f7a9ffc17d7d74f3064ccc2ce663 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 23 Apr 2010 14:27:04 +0000 Subject: [PATCH 0687/1180] When converting A-Z into a control character, want to subtract 64 not 65... whoops. --- key-string.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/key-string.c b/key-string.c index f20d42db..5e806b81 100644 --- a/key-string.c +++ b/key-string.c @@ -155,7 +155,7 @@ key_string_lookup_string(const char *string) if (key >= 97 && key <= 122) key -= 96; else if (key >= 65 && key <= 90) - key -= 65; + key -= 64; else if (key == 32) key = 0; else if (key == 63) From d529e7e14e4afa86a312ebac773682cfa3e58368 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 25 Apr 2010 20:28:13 +0000 Subject: [PATCH 0688/1180] Add a tiled layout, originally from Liam Bedford a while ago, fixed up by me. --- cmd-select-layout.c | 3 ++ key-bindings.c | 1 + layout-set.c | 101 ++++++++++++++++++++++++++++++++++++++++++++ tmux.1 | 3 ++ 4 files changed, 108 insertions(+) diff --git a/cmd-select-layout.c b/cmd-select-layout.c index 2988a44f..fd66578c 100644 --- a/cmd-select-layout.c +++ b/cmd-select-layout.c @@ -59,6 +59,9 @@ cmd_select_layout_init(struct cmd *self, int key) case ('4' | KEYC_ESCAPE): data->arg = xstrdup("main-vertical"); break; + case ('5' | KEYC_ESCAPE): + data->arg = xstrdup("tiled"); + break; } } diff --git a/key-bindings.c b/key-bindings.c index 7b96a12d..9a2fcc12 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -151,6 +151,7 @@ key_bindings_init(void) { '2' | KEYC_ESCAPE, 0, &cmd_select_layout_entry }, { '3' | KEYC_ESCAPE, 0, &cmd_select_layout_entry }, { '4' | KEYC_ESCAPE, 0, &cmd_select_layout_entry }, + { '5' | KEYC_ESCAPE, 0, &cmd_select_layout_entry }, { KEYC_PPAGE, 0, &cmd_copy_mode_entry }, { 'n' | KEYC_ESCAPE, 0, &cmd_next_window_entry }, { 'o' | KEYC_ESCAPE, 0, &cmd_rotate_window_entry }, diff --git a/layout-set.c b/layout-set.c index e74a1931..7ebdead9 100644 --- a/layout-set.c +++ b/layout-set.c @@ -31,6 +31,7 @@ void layout_set_even_h(struct window *); void layout_set_even_v(struct window *); void layout_set_main_h(struct window *); void layout_set_main_v(struct window *); +void layout_set_tiled(struct window *); const struct { const char *name; @@ -40,6 +41,7 @@ const struct { { "even-vertical", layout_set_even_v }, { "main-horizontal", layout_set_main_h }, { "main-vertical", layout_set_main_v }, + { "tiled", layout_set_tiled }, }; const char * @@ -447,3 +449,102 @@ layout_set_main_v(struct window *w) server_redraw_window(w); } + +void +layout_set_tiled(struct window *w) +{ + struct window_pane *wp; + struct layout_cell *lc, *lcrow, *lcchild; + u_int n, width, height, used; + u_int i, j, columns, rows; + + layout_print_cell(w->layout_root, __func__, 1); + + /* Get number of panes. */ + n = window_count_panes(w); + if (n <= 1) + return; + + /* How many rows and columns are wanted? */ + rows = columns = 1; + while (rows * columns < n) { + rows++; + if (rows * columns < n) + columns++; + } + + /* What width and height should they be? */ + width = w->sx / columns; + if (width < PANE_MINIMUM + 1) + width = PANE_MINIMUM + 1; + height = w->sy / rows; + if (width < PANE_MINIMUM + 1) + width = PANE_MINIMUM + 1; + + /* Free old tree and create a new root. */ + layout_free(w); + lc = w->layout_root = layout_create_cell(NULL); + layout_set_size(lc, width * columns, height * rows, 0, 0); + layout_make_node(lc, LAYOUT_TOPBOTTOM); + + /* Create a grid of the cells. */ + wp = TAILQ_FIRST(&w->panes); + for (j = 0; j < rows; j++) { + /* If this is the last cell, all done. */ + if (wp == NULL) + break; + + /* Create the new row. */ + lcrow = layout_create_cell(lc); + layout_set_size(lcrow, w->sx, height - 1, 0, 0); + TAILQ_INSERT_TAIL(&lc->cells, lcrow, entry); + + /* If only one column, just use the row directly. */ + if (n - (j * columns) == 1) { + layout_make_leaf(lcrow, wp); + wp = TAILQ_NEXT(wp, entry); + continue; + } + + /* Add in the columns. */ + layout_make_node(lcrow, LAYOUT_LEFTRIGHT); + for (i = 0; i < columns; i++) { + /* Create and add a pane cell. */ + lcchild = layout_create_cell(lcrow); + layout_set_size(lcchild, width - 1, height - 1, 0, 0); + layout_make_leaf(lcchild, wp); + TAILQ_INSERT_TAIL(&lcrow->cells, lcchild, entry); + + /* Move to the next cell. */ + if ((wp = TAILQ_NEXT(wp, entry)) == NULL) + break; + } + + /* + * Adjust the row and columns to fit the full width if + * necessary. + */ + if (i == columns) + i--; + used = ((i + 1) * width) - 1; + if (w->sx <= used) + continue; + lcchild = TAILQ_LAST(&lcrow->cells, layout_cells); + layout_resize_adjust(lcchild, LAYOUT_LEFTRIGHT, w->sx - used); + } + + /* Adjust the last row height to fit if necessary. */ + used = (rows * height) - 1; + if (w->sy > used) { + lcrow = TAILQ_LAST(&lc->cells, layout_cells); + layout_resize_adjust(lcrow, LAYOUT_TOPBOTTOM, w->sy - used); + } + + /* Fix cell offsets. */ + layout_fix_offsets(lc); + layout_fix_panes(w, w->sx, w->sy); + + layout_print_cell(w->layout_root, __func__, 1); + + server_redraw_window(w); +} diff --git a/tmux.1 b/tmux.1 index f4af706b..7deac12e 100644 --- a/tmux.1 +++ b/tmux.1 @@ -784,6 +784,9 @@ bottom along the right. See the .Em main-pane-width window option. +.It Ic tiled +Panes are spread out as evenly as possible over the window in both rows and +columns. .El .Pp Commands related to windows and panes are as follows: From 83e1a33ff59b97c4b7f926d886ecb3d8070ee269 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 27 Apr 2010 21:04:04 +0000 Subject: [PATCH 0689/1180] imsg.h does not need sys/tree.h. ok eric --- imsg.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/imsg.h b/imsg.h index b84be86f..43a29282 100644 --- a/imsg.h +++ b/imsg.h @@ -18,8 +18,6 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include - #define READ_BUF_SIZE 65535 #define IMSG_HEADER_SIZE sizeof(struct imsg_hdr) #define MAX_IMSGSIZE 16384 From 2240199dbf6dd66eaada95ffdb021c844bc23c12 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 28 Apr 2010 18:19:16 +0000 Subject: [PATCH 0690/1180] Fix crash when resizing in copy mode, when cursor can end up outside screen. Reported by Romain Francois, fixed by Micah Cowan. --- window-copy.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/window-copy.c b/window-copy.c index bb0e81c5..5e04f34e 100644 --- a/window-copy.c +++ b/window-copy.c @@ -340,6 +340,8 @@ window_copy_resize(struct window_pane *wp, u_int sx, u_int sy) data->cy = sy - 1; if (data->cx > sx) data->cx = sx; + if (data->oy > screen_hsize(data->backing)) + data->oy = screen_hsize(data->backing); window_copy_clear_selection(wp); From 99e54f46c7d3798aea00f5c8c791dd1b66a8d5d7 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 28 Apr 2010 18:22:32 +0000 Subject: [PATCH 0691/1180] Make the active pane border have a green foreground instead of background by default. --- tmux.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tmux.c b/tmux.c index 9feeb300..741ee38e 100644 --- a/tmux.c +++ b/tmux.c @@ -355,8 +355,8 @@ main(int argc, char **argv) options_set_number(so, "message-fg", 0); options_set_number(so, "message-limit", 20); options_set_number(so, "mouse-select-pane", 0); - options_set_number(so, "pane-active-border-bg", 2); - options_set_number(so, "pane-active-border-fg", 8); + options_set_number(so, "pane-active-border-bg", 8); + options_set_number(so, "pane-active-border-fg", 2); options_set_number(so, "pane-border-bg", 8); options_set_number(so, "pane-border-fg", 8); options_set_number(so, "repeat-time", 500); From fc09ec30257948222a45039cd55c6d27c1984824 Mon Sep 17 00:00:00 2001 From: Igor Sobrado Date: Sun, 2 May 2010 15:19:35 +0000 Subject: [PATCH 0692/1180] sort options. --- tmux.1 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tmux.1 b/tmux.1 index 7deac12e..49816e24 100644 --- a/tmux.1 +++ b/tmux.1 @@ -131,10 +131,6 @@ commands which are executed in sequence when the server is first started. If a command in the configuration file fails, .Nm will report an error and exit without executing further commands. -.It Fl l -Behave as a login shell. -This flag currently has no effect and is for compatibility with other shells -when using tmux as a login shell. .It Fl L Ar socket-name .Nm stores the server socket in a directory under @@ -155,6 +151,10 @@ If the socket is accidentally removed, the signal may be sent to the .Nm server process to recreate it. +.It Fl l +Behave as a login shell. +This flag currently has no effect and is for compatibility with other shells +when using tmux as a login shell. .It Fl q Set the .Ic quiet From c9191394332342a570dc6620bc8cfd7c6e554e1b Mon Sep 17 00:00:00 2001 From: Ryan McBride Date: Mon, 3 May 2010 09:38:03 +0000 Subject: [PATCH 0693/1180] Make C-] and other punctuation-based control key combinations work again. ok nicm --- key-string.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/key-string.c b/key-string.c index 5e806b81..65d669bf 100644 --- a/key-string.c +++ b/key-string.c @@ -154,7 +154,7 @@ key_string_lookup_string(const char *string) if (modifiers & KEYC_CTRL) { if (key >= 97 && key <= 122) key -= 96; - else if (key >= 65 && key <= 90) + else if (key >= 64 && key <= 95) key -= 64; else if (key == 32) key = 0; From ec1d37b1b259e8a3502646876b60eb42c2c5c740 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 3 May 2010 16:06:32 +0000 Subject: [PATCH 0694/1180] Make signal handler setup/teardown two common functions instead of six, and reset SIGCHLD after fork to fix problems with some shells. From Romain Francois. --- Makefile | 2 +- client.c | 25 +------------- cmd-pipe-pane.c | 2 +- job.c | 2 +- server.c | 68 ++++--------------------------------- signal.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++++ tmux.c | 79 +++++++++---------------------------------- tmux.h | 7 ++-- window.c | 2 +- 9 files changed, 123 insertions(+), 154 deletions(-) create mode 100644 signal.c diff --git a/Makefile b/Makefile index a730cbbc..56953276 100644 --- a/Makefile +++ b/Makefile @@ -35,7 +35,7 @@ SRCS= attributes.c cfg.c client.c clock.c \ layout-set.c layout-string.c layout.c log.c job.c \ mode-key.c names.c options.c paste.c procname.c \ resize.c screen-redraw.c screen-write.c screen.c session.c status.c \ - server-fn.c server.c server-client.c server-window.c \ + server-fn.c server.c server-client.c server-window.c signal.c \ tmux.c tty-keys.c tty-term.c tty.c utf8.c \ window-choose.c window-clock.c window-copy.c window.c \ xterm-keys.c xmalloc.c diff --git a/client.c b/client.c index 69d5bd7b..5940f62e 100644 --- a/client.c +++ b/client.c @@ -172,35 +172,12 @@ client_update_event(void) __dead void client_main(void) { - struct event ev_sigcont, ev_sigterm, ev_sigwinch; - struct sigaction sigact; - logfile("client"); /* Note: event_init() has already been called. */ /* Set up signals. */ - memset(&sigact, 0, sizeof sigact); - sigemptyset(&sigact.sa_mask); - sigact.sa_flags = SA_RESTART; - sigact.sa_handler = SIG_IGN; - if (sigaction(SIGINT, &sigact, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGPIPE, &sigact, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGUSR1, &sigact, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGUSR2, &sigact, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGTSTP, &sigact, NULL) != 0) - fatal("sigaction failed"); - - signal_set(&ev_sigcont, SIGCONT, client_signal, NULL); - signal_add(&ev_sigcont, NULL); - signal_set(&ev_sigterm, SIGTERM, client_signal, NULL); - signal_add(&ev_sigterm, NULL); - signal_set(&ev_sigwinch, SIGWINCH, client_signal, NULL); - signal_add(&ev_sigwinch, NULL); + set_signals(client_signal); /* * imsg_read in the first client poll loop (before the terminal has diff --git a/cmd-pipe-pane.c b/cmd-pipe-pane.c index efe79a38..0d7c3ff6 100644 --- a/cmd-pipe-pane.c +++ b/cmd-pipe-pane.c @@ -91,7 +91,7 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx) case 0: /* Child process. */ close(pipe_fd[0]); - server_signal_clear(); + clear_signals(); if (dup2(pipe_fd[1], STDIN_FILENO) == -1) _exit(1); diff --git a/job.c b/job.c index ddeae13f..61aa61fa 100644 --- a/job.c +++ b/job.c @@ -149,7 +149,7 @@ job_run(struct job *job) case -1: return (-1); case 0: /* child */ - server_signal_clear(); + clear_signals(); environ_push(&global_environ); diff --git a/server.c b/server.c index 017cc729..e583b44f 100644 --- a/server.c +++ b/server.c @@ -49,9 +49,6 @@ struct clients dead_clients; int server_fd; int server_shutdown; struct event server_ev_accept; -struct event server_ev_sigterm; -struct event server_ev_sigusr1; -struct event server_ev_sigchld; struct event server_ev_second; int server_create_socket(void); @@ -134,6 +131,12 @@ server_start(char *path) } close(pair[0]); + /* event_init() was called by the parent, need to reinit. */ + if (event_reinit(ev_base) != 0) + fatal("event_reinit failed"); + + clear_signals(); + /* * Must daemonise before loading configuration as the PID changes so * $TMUX would be wrong for sessions created in the config file. @@ -162,8 +165,6 @@ server_start(char *path) log_debug("socket path %s", socket_path); setproctitle("server (%s)", rpathbuf); - event_init(); - server_fd = server_create_socket(); server_client_create(pair[1]); @@ -202,7 +203,7 @@ server_start(char *path) evtimer_set(&server_ev_second, server_second_callback, NULL); evtimer_add(&server_ev_second, &tv); - server_signal_set(); + set_signals(server_signal_callback); server_loop(); exit(0); } @@ -341,61 +342,6 @@ server_accept_callback(int fd, short events, unused void *data) server_client_create(newfd); } -/* Set up server signal handling. */ -void -server_signal_set(void) -{ - struct sigaction sigact; - - memset(&sigact, 0, sizeof sigact); - sigemptyset(&sigact.sa_mask); - sigact.sa_flags = SA_RESTART; - sigact.sa_handler = SIG_IGN; - if (sigaction(SIGINT, &sigact, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGPIPE, &sigact, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGUSR2, &sigact, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGTSTP, &sigact, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGHUP, &sigact, NULL) != 0) - fatal("sigaction failed"); - - signal_set(&server_ev_sigchld, SIGCHLD, server_signal_callback, NULL); - signal_add(&server_ev_sigchld, NULL); - signal_set(&server_ev_sigterm, SIGTERM, server_signal_callback, NULL); - signal_add(&server_ev_sigterm, NULL); - signal_set(&server_ev_sigusr1, SIGUSR1, server_signal_callback, NULL); - signal_add(&server_ev_sigusr1, NULL); -} - -/* Destroy server signal events. */ -void -server_signal_clear(void) -{ - struct sigaction sigact; - - memset(&sigact, 0, sizeof sigact); - sigemptyset(&sigact.sa_mask); - sigact.sa_flags = SA_RESTART; - sigact.sa_handler = SIG_DFL; - if (sigaction(SIGINT, &sigact, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGPIPE, &sigact, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGUSR2, &sigact, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGTSTP, &sigact, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGHUP, &sigact, NULL) != 0) - fatal("sigaction failed"); - - signal_del(&server_ev_sigchld); - signal_del(&server_ev_sigterm); - signal_del(&server_ev_sigusr1); -} - /* Signal handler. */ /* ARGSUSED */ void diff --git a/signal.c b/signal.c new file mode 100644 index 00000000..4bfcdc87 --- /dev/null +++ b/signal.c @@ -0,0 +1,90 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2007 Nicholas Marriott + * Copyright (c) 2010 Romain Francoise + * + * 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 "tmux.h" + +struct event ev_sigchld; +struct event ev_sigcont; +struct event ev_sigterm; +struct event ev_sigusr1; +struct event ev_sigwinch; + +void +set_signals(void(*handler)(int, short, void *)) +{ + struct sigaction sigact; + + memset(&sigact, 0, sizeof sigact); + sigemptyset(&sigact.sa_mask); + sigact.sa_flags = SA_RESTART; + sigact.sa_handler = SIG_IGN; + if (sigaction(SIGINT, &sigact, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGPIPE, &sigact, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGUSR2, &sigact, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGTSTP, &sigact, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGHUP, &sigact, NULL) != 0) + fatal("sigaction failed"); + + signal_set(&ev_sigchld, SIGCHLD, handler, NULL); + signal_add(&ev_sigchld, NULL); + signal_set(&ev_sigcont, SIGCONT, handler, NULL); + signal_add(&ev_sigcont, NULL); + signal_set(&ev_sigterm, SIGTERM, handler, NULL); + signal_add(&ev_sigterm, NULL); + signal_set(&ev_sigusr1, SIGUSR1, handler, NULL); + signal_add(&ev_sigusr1, NULL); + signal_set(&ev_sigwinch, SIGWINCH, handler, NULL); + signal_add(&ev_sigwinch, NULL); +} + +void +clear_signals(void) +{ + struct sigaction sigact; + + memset(&sigact, 0, sizeof sigact); + sigemptyset(&sigact.sa_mask); + sigact.sa_flags = SA_RESTART; + sigact.sa_handler = SIG_DFL; + if (sigaction(SIGINT, &sigact, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGPIPE, &sigact, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGUSR2, &sigact, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGTSTP, &sigact, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGHUP, &sigact, NULL) != 0) + fatal("sigaction failed"); + + event_del(&ev_sigchld); + event_del(&ev_sigcont); + event_del(&ev_sigterm); + event_del(&ev_sigusr1); + event_del(&ev_sigwinch); +} diff --git a/tmux.c b/tmux.c index 741ee38e..6b21b7b7 100644 --- a/tmux.c +++ b/tmux.c @@ -18,6 +18,7 @@ #include #include +#include #include #include @@ -41,6 +42,8 @@ struct options global_s_options; /* session options */ struct options global_w_options; /* window options */ struct environ global_environ; +struct event_base *ev_base; + int debug_level; time_t start_time; char *socket_path; @@ -58,11 +61,8 @@ char *makesockpath(const char *); __dead void shell_exec(const char *, const char *); struct imsgbuf *main_ibuf; -struct event main_ev_sigterm; int main_exitval; -void main_set_signals(void); -void main_clear_signals(void); void main_signal(int, short, unused void *); void main_callback(int, short, void *); void main_dispatch(const char *); @@ -238,7 +238,6 @@ main(int argc, char **argv) struct keylist *keylist; struct env_data envdata; struct msg_command_data cmddata; - struct sigaction sigact; char *s, *shellcmd, *path, *label, *home, *cause; char cwd[MAXPATHLEN], **var; void *buf; @@ -538,24 +537,22 @@ main(int argc, char **argv) exit(1); } - /* Catch SIGCHLD to avoid a zombie when starting the server. */ - memset(&sigact, 0, sizeof sigact); - sigemptyset(&sigact.sa_mask); - sigact.sa_handler = SIG_IGN; - if (sigaction(SIGCHLD, &sigact, NULL) != 0) - fatal("sigaction failed"); + /* Initialise the client socket/start the server. */ + if ((main_ibuf = client_init(path, cmdflags, flags)) == NULL) + exit(1); + xfree(path); + + ev_base = event_init(); + + set_signals(main_signal); /* Initialise the client socket/start the server. */ if ((main_ibuf = client_init(path, cmdflags, flags)) == NULL) exit(1); xfree(path); - event_init(); - imsg_compose(main_ibuf, msg, PROTOCOL_VERSION, -1, -1, buf, len); - main_set_signals(); - events = EV_READ; if (main_ibuf->w.queued > 0) events |= EV_WRITE; @@ -564,58 +561,11 @@ main(int argc, char **argv) main_exitval = 0; event_dispatch(); - main_clear_signals(); + clear_signals(); client_main(); /* doesn't return */ } -void -main_set_signals(void) -{ - struct sigaction sigact; - - memset(&sigact, 0, sizeof sigact); - sigemptyset(&sigact.sa_mask); - sigact.sa_flags = SA_RESTART; - sigact.sa_handler = SIG_IGN; - if (sigaction(SIGINT, &sigact, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGPIPE, &sigact, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGUSR1, &sigact, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGUSR2, &sigact, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGTSTP, &sigact, NULL) != 0) - fatal("sigaction failed"); - - signal_set(&main_ev_sigterm, SIGTERM, main_signal, NULL); - signal_add(&main_ev_sigterm, NULL); -} - -void -main_clear_signals(void) -{ - struct sigaction sigact; - - memset(&sigact, 0, sizeof sigact); - sigemptyset(&sigact.sa_mask); - sigact.sa_flags = SA_RESTART; - sigact.sa_handler = SIG_DFL; - if (sigaction(SIGINT, &sigact, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGPIPE, &sigact, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGUSR1, &sigact, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGUSR2, &sigact, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGTSTP, &sigact, NULL) != 0) - fatal("sigaction failed"); - - event_del(&main_ev_sigterm); -} - /* ARGSUSED */ void main_signal(int sig, unused short events, unused void *data) @@ -623,6 +573,9 @@ main_signal(int sig, unused short events, unused void *data) switch (sig) { case SIGTERM: exit(1); + case SIGCHLD: + waitpid(WAIT_ANY, NULL, WNOHANG); + break; } } @@ -701,7 +654,7 @@ main_dispatch(const char *shellcmd) memcpy(&shelldata, imsg.data, sizeof shelldata); shelldata.shell[(sizeof shelldata.shell) - 1] = '\0'; - main_clear_signals(); + clear_signals(); shell_exec(shelldata.shell, shellcmd); default: diff --git a/tmux.h b/tmux.h index 80a6a9a7..a91a1d93 100644 --- a/tmux.h +++ b/tmux.h @@ -1253,6 +1253,7 @@ extern struct options global_options; extern struct options global_s_options; extern struct options global_w_options; extern struct environ global_environ; +extern struct event_base *ev_base; extern char *cfg_file; extern int debug_level; extern int be_quiet; @@ -1583,8 +1584,6 @@ const char *key_string_lookup_key(int); extern struct clients clients; extern struct clients dead_clients; int server_start(char *); -void server_signal_set(void); -void server_signal_clear(void); void server_update_socket(void); /* server-client.c */ @@ -1900,6 +1899,10 @@ void window_choose_ready(struct window_pane *, void queue_window_name(struct window *); char *default_window_name(struct window *); +/* signal.c */ +void set_signals(void(*)(int, short, void *)); +void clear_signals(void); + /* session.c */ extern struct sessions sessions; extern struct sessions dead_sessions; diff --git a/window.c b/window.c index 00c03f6e..0811a4cb 100644 --- a/window.c +++ b/window.c @@ -529,7 +529,7 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell, environ_push(env); - server_signal_clear(); + clear_signals(); log_close(); if (*wp->cmd != '\0') { From af5e0bd15affd358017e43110ac5a6c3b22233bc Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 4 May 2010 08:48:06 +0000 Subject: [PATCH 0695/1180] Revert last change, it appears to be broken somehow. --- Makefile | 2 +- client.c | 25 +++++++++++++- cmd-pipe-pane.c | 2 +- job.c | 2 +- server.c | 68 +++++++++++++++++++++++++++++++++---- signal.c | 90 ------------------------------------------------- tmux.c | 79 ++++++++++++++++++++++++++++++++++--------- tmux.h | 7 ++-- window.c | 2 +- 9 files changed, 154 insertions(+), 123 deletions(-) delete mode 100644 signal.c diff --git a/Makefile b/Makefile index 56953276..a730cbbc 100644 --- a/Makefile +++ b/Makefile @@ -35,7 +35,7 @@ SRCS= attributes.c cfg.c client.c clock.c \ layout-set.c layout-string.c layout.c log.c job.c \ mode-key.c names.c options.c paste.c procname.c \ resize.c screen-redraw.c screen-write.c screen.c session.c status.c \ - server-fn.c server.c server-client.c server-window.c signal.c \ + server-fn.c server.c server-client.c server-window.c \ tmux.c tty-keys.c tty-term.c tty.c utf8.c \ window-choose.c window-clock.c window-copy.c window.c \ xterm-keys.c xmalloc.c diff --git a/client.c b/client.c index 5940f62e..69d5bd7b 100644 --- a/client.c +++ b/client.c @@ -172,12 +172,35 @@ client_update_event(void) __dead void client_main(void) { + struct event ev_sigcont, ev_sigterm, ev_sigwinch; + struct sigaction sigact; + logfile("client"); /* Note: event_init() has already been called. */ /* Set up signals. */ - set_signals(client_signal); + memset(&sigact, 0, sizeof sigact); + sigemptyset(&sigact.sa_mask); + sigact.sa_flags = SA_RESTART; + sigact.sa_handler = SIG_IGN; + if (sigaction(SIGINT, &sigact, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGPIPE, &sigact, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGUSR1, &sigact, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGUSR2, &sigact, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGTSTP, &sigact, NULL) != 0) + fatal("sigaction failed"); + + signal_set(&ev_sigcont, SIGCONT, client_signal, NULL); + signal_add(&ev_sigcont, NULL); + signal_set(&ev_sigterm, SIGTERM, client_signal, NULL); + signal_add(&ev_sigterm, NULL); + signal_set(&ev_sigwinch, SIGWINCH, client_signal, NULL); + signal_add(&ev_sigwinch, NULL); /* * imsg_read in the first client poll loop (before the terminal has diff --git a/cmd-pipe-pane.c b/cmd-pipe-pane.c index 0d7c3ff6..efe79a38 100644 --- a/cmd-pipe-pane.c +++ b/cmd-pipe-pane.c @@ -91,7 +91,7 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx) case 0: /* Child process. */ close(pipe_fd[0]); - clear_signals(); + server_signal_clear(); if (dup2(pipe_fd[1], STDIN_FILENO) == -1) _exit(1); diff --git a/job.c b/job.c index 61aa61fa..ddeae13f 100644 --- a/job.c +++ b/job.c @@ -149,7 +149,7 @@ job_run(struct job *job) case -1: return (-1); case 0: /* child */ - clear_signals(); + server_signal_clear(); environ_push(&global_environ); diff --git a/server.c b/server.c index e583b44f..017cc729 100644 --- a/server.c +++ b/server.c @@ -49,6 +49,9 @@ struct clients dead_clients; int server_fd; int server_shutdown; struct event server_ev_accept; +struct event server_ev_sigterm; +struct event server_ev_sigusr1; +struct event server_ev_sigchld; struct event server_ev_second; int server_create_socket(void); @@ -131,12 +134,6 @@ server_start(char *path) } close(pair[0]); - /* event_init() was called by the parent, need to reinit. */ - if (event_reinit(ev_base) != 0) - fatal("event_reinit failed"); - - clear_signals(); - /* * Must daemonise before loading configuration as the PID changes so * $TMUX would be wrong for sessions created in the config file. @@ -165,6 +162,8 @@ server_start(char *path) log_debug("socket path %s", socket_path); setproctitle("server (%s)", rpathbuf); + event_init(); + server_fd = server_create_socket(); server_client_create(pair[1]); @@ -203,7 +202,7 @@ server_start(char *path) evtimer_set(&server_ev_second, server_second_callback, NULL); evtimer_add(&server_ev_second, &tv); - set_signals(server_signal_callback); + server_signal_set(); server_loop(); exit(0); } @@ -342,6 +341,61 @@ server_accept_callback(int fd, short events, unused void *data) server_client_create(newfd); } +/* Set up server signal handling. */ +void +server_signal_set(void) +{ + struct sigaction sigact; + + memset(&sigact, 0, sizeof sigact); + sigemptyset(&sigact.sa_mask); + sigact.sa_flags = SA_RESTART; + sigact.sa_handler = SIG_IGN; + if (sigaction(SIGINT, &sigact, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGPIPE, &sigact, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGUSR2, &sigact, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGTSTP, &sigact, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGHUP, &sigact, NULL) != 0) + fatal("sigaction failed"); + + signal_set(&server_ev_sigchld, SIGCHLD, server_signal_callback, NULL); + signal_add(&server_ev_sigchld, NULL); + signal_set(&server_ev_sigterm, SIGTERM, server_signal_callback, NULL); + signal_add(&server_ev_sigterm, NULL); + signal_set(&server_ev_sigusr1, SIGUSR1, server_signal_callback, NULL); + signal_add(&server_ev_sigusr1, NULL); +} + +/* Destroy server signal events. */ +void +server_signal_clear(void) +{ + struct sigaction sigact; + + memset(&sigact, 0, sizeof sigact); + sigemptyset(&sigact.sa_mask); + sigact.sa_flags = SA_RESTART; + sigact.sa_handler = SIG_DFL; + if (sigaction(SIGINT, &sigact, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGPIPE, &sigact, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGUSR2, &sigact, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGTSTP, &sigact, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGHUP, &sigact, NULL) != 0) + fatal("sigaction failed"); + + signal_del(&server_ev_sigchld); + signal_del(&server_ev_sigterm); + signal_del(&server_ev_sigusr1); +} + /* Signal handler. */ /* ARGSUSED */ void diff --git a/signal.c b/signal.c deleted file mode 100644 index 4bfcdc87..00000000 --- a/signal.c +++ /dev/null @@ -1,90 +0,0 @@ -/* $OpenBSD$ */ - -/* - * Copyright (c) 2007 Nicholas Marriott - * Copyright (c) 2010 Romain Francoise - * - * 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 "tmux.h" - -struct event ev_sigchld; -struct event ev_sigcont; -struct event ev_sigterm; -struct event ev_sigusr1; -struct event ev_sigwinch; - -void -set_signals(void(*handler)(int, short, void *)) -{ - struct sigaction sigact; - - memset(&sigact, 0, sizeof sigact); - sigemptyset(&sigact.sa_mask); - sigact.sa_flags = SA_RESTART; - sigact.sa_handler = SIG_IGN; - if (sigaction(SIGINT, &sigact, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGPIPE, &sigact, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGUSR2, &sigact, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGTSTP, &sigact, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGHUP, &sigact, NULL) != 0) - fatal("sigaction failed"); - - signal_set(&ev_sigchld, SIGCHLD, handler, NULL); - signal_add(&ev_sigchld, NULL); - signal_set(&ev_sigcont, SIGCONT, handler, NULL); - signal_add(&ev_sigcont, NULL); - signal_set(&ev_sigterm, SIGTERM, handler, NULL); - signal_add(&ev_sigterm, NULL); - signal_set(&ev_sigusr1, SIGUSR1, handler, NULL); - signal_add(&ev_sigusr1, NULL); - signal_set(&ev_sigwinch, SIGWINCH, handler, NULL); - signal_add(&ev_sigwinch, NULL); -} - -void -clear_signals(void) -{ - struct sigaction sigact; - - memset(&sigact, 0, sizeof sigact); - sigemptyset(&sigact.sa_mask); - sigact.sa_flags = SA_RESTART; - sigact.sa_handler = SIG_DFL; - if (sigaction(SIGINT, &sigact, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGPIPE, &sigact, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGUSR2, &sigact, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGTSTP, &sigact, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGHUP, &sigact, NULL) != 0) - fatal("sigaction failed"); - - event_del(&ev_sigchld); - event_del(&ev_sigcont); - event_del(&ev_sigterm); - event_del(&ev_sigusr1); - event_del(&ev_sigwinch); -} diff --git a/tmux.c b/tmux.c index 6b21b7b7..741ee38e 100644 --- a/tmux.c +++ b/tmux.c @@ -18,7 +18,6 @@ #include #include -#include #include #include @@ -42,8 +41,6 @@ struct options global_s_options; /* session options */ struct options global_w_options; /* window options */ struct environ global_environ; -struct event_base *ev_base; - int debug_level; time_t start_time; char *socket_path; @@ -61,8 +58,11 @@ char *makesockpath(const char *); __dead void shell_exec(const char *, const char *); struct imsgbuf *main_ibuf; +struct event main_ev_sigterm; int main_exitval; +void main_set_signals(void); +void main_clear_signals(void); void main_signal(int, short, unused void *); void main_callback(int, short, void *); void main_dispatch(const char *); @@ -238,6 +238,7 @@ main(int argc, char **argv) struct keylist *keylist; struct env_data envdata; struct msg_command_data cmddata; + struct sigaction sigact; char *s, *shellcmd, *path, *label, *home, *cause; char cwd[MAXPATHLEN], **var; void *buf; @@ -537,22 +538,24 @@ main(int argc, char **argv) exit(1); } - /* Initialise the client socket/start the server. */ - if ((main_ibuf = client_init(path, cmdflags, flags)) == NULL) - exit(1); - xfree(path); - - ev_base = event_init(); - - set_signals(main_signal); + /* Catch SIGCHLD to avoid a zombie when starting the server. */ + memset(&sigact, 0, sizeof sigact); + sigemptyset(&sigact.sa_mask); + sigact.sa_handler = SIG_IGN; + if (sigaction(SIGCHLD, &sigact, NULL) != 0) + fatal("sigaction failed"); /* Initialise the client socket/start the server. */ if ((main_ibuf = client_init(path, cmdflags, flags)) == NULL) exit(1); xfree(path); + event_init(); + imsg_compose(main_ibuf, msg, PROTOCOL_VERSION, -1, -1, buf, len); + main_set_signals(); + events = EV_READ; if (main_ibuf->w.queued > 0) events |= EV_WRITE; @@ -561,11 +564,58 @@ main(int argc, char **argv) main_exitval = 0; event_dispatch(); - clear_signals(); + main_clear_signals(); client_main(); /* doesn't return */ } +void +main_set_signals(void) +{ + struct sigaction sigact; + + memset(&sigact, 0, sizeof sigact); + sigemptyset(&sigact.sa_mask); + sigact.sa_flags = SA_RESTART; + sigact.sa_handler = SIG_IGN; + if (sigaction(SIGINT, &sigact, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGPIPE, &sigact, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGUSR1, &sigact, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGUSR2, &sigact, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGTSTP, &sigact, NULL) != 0) + fatal("sigaction failed"); + + signal_set(&main_ev_sigterm, SIGTERM, main_signal, NULL); + signal_add(&main_ev_sigterm, NULL); +} + +void +main_clear_signals(void) +{ + struct sigaction sigact; + + memset(&sigact, 0, sizeof sigact); + sigemptyset(&sigact.sa_mask); + sigact.sa_flags = SA_RESTART; + sigact.sa_handler = SIG_DFL; + if (sigaction(SIGINT, &sigact, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGPIPE, &sigact, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGUSR1, &sigact, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGUSR2, &sigact, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGTSTP, &sigact, NULL) != 0) + fatal("sigaction failed"); + + event_del(&main_ev_sigterm); +} + /* ARGSUSED */ void main_signal(int sig, unused short events, unused void *data) @@ -573,9 +623,6 @@ main_signal(int sig, unused short events, unused void *data) switch (sig) { case SIGTERM: exit(1); - case SIGCHLD: - waitpid(WAIT_ANY, NULL, WNOHANG); - break; } } @@ -654,7 +701,7 @@ main_dispatch(const char *shellcmd) memcpy(&shelldata, imsg.data, sizeof shelldata); shelldata.shell[(sizeof shelldata.shell) - 1] = '\0'; - clear_signals(); + main_clear_signals(); shell_exec(shelldata.shell, shellcmd); default: diff --git a/tmux.h b/tmux.h index a91a1d93..80a6a9a7 100644 --- a/tmux.h +++ b/tmux.h @@ -1253,7 +1253,6 @@ extern struct options global_options; extern struct options global_s_options; extern struct options global_w_options; extern struct environ global_environ; -extern struct event_base *ev_base; extern char *cfg_file; extern int debug_level; extern int be_quiet; @@ -1584,6 +1583,8 @@ const char *key_string_lookup_key(int); extern struct clients clients; extern struct clients dead_clients; int server_start(char *); +void server_signal_set(void); +void server_signal_clear(void); void server_update_socket(void); /* server-client.c */ @@ -1899,10 +1900,6 @@ void window_choose_ready(struct window_pane *, void queue_window_name(struct window *); char *default_window_name(struct window *); -/* signal.c */ -void set_signals(void(*)(int, short, void *)); -void clear_signals(void); - /* session.c */ extern struct sessions sessions; extern struct sessions dead_sessions; diff --git a/window.c b/window.c index 0811a4cb..00c03f6e 100644 --- a/window.c +++ b/window.c @@ -529,7 +529,7 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell, environ_push(env); - clear_signals(); + server_signal_clear(); log_close(); if (*wp->cmd != '\0') { From c4a2fdf15b5f6cd35319e36636b7daee8061c2ab Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 4 May 2010 17:28:16 +0000 Subject: [PATCH 0696/1180] Put this back in with the initialisation in the right order. --- Makefile | 2 +- client.c | 25 +------------- cmd-pipe-pane.c | 2 +- job.c | 2 +- server.c | 67 ++++--------------------------------- signal.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++++ tmux.c | 75 +++++++---------------------------------- tmux.h | 7 ++-- window.c | 2 +- 9 files changed, 116 insertions(+), 154 deletions(-) create mode 100644 signal.c diff --git a/Makefile b/Makefile index a730cbbc..189ea52f 100644 --- a/Makefile +++ b/Makefile @@ -35,7 +35,7 @@ SRCS= attributes.c cfg.c client.c clock.c \ layout-set.c layout-string.c layout.c log.c job.c \ mode-key.c names.c options.c paste.c procname.c \ resize.c screen-redraw.c screen-write.c screen.c session.c status.c \ - server-fn.c server.c server-client.c server-window.c \ + signal.c server-fn.c server.c server-client.c server-window.c \ tmux.c tty-keys.c tty-term.c tty.c utf8.c \ window-choose.c window-clock.c window-copy.c window.c \ xterm-keys.c xmalloc.c diff --git a/client.c b/client.c index 69d5bd7b..5940f62e 100644 --- a/client.c +++ b/client.c @@ -172,35 +172,12 @@ client_update_event(void) __dead void client_main(void) { - struct event ev_sigcont, ev_sigterm, ev_sigwinch; - struct sigaction sigact; - logfile("client"); /* Note: event_init() has already been called. */ /* Set up signals. */ - memset(&sigact, 0, sizeof sigact); - sigemptyset(&sigact.sa_mask); - sigact.sa_flags = SA_RESTART; - sigact.sa_handler = SIG_IGN; - if (sigaction(SIGINT, &sigact, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGPIPE, &sigact, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGUSR1, &sigact, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGUSR2, &sigact, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGTSTP, &sigact, NULL) != 0) - fatal("sigaction failed"); - - signal_set(&ev_sigcont, SIGCONT, client_signal, NULL); - signal_add(&ev_sigcont, NULL); - signal_set(&ev_sigterm, SIGTERM, client_signal, NULL); - signal_add(&ev_sigterm, NULL); - signal_set(&ev_sigwinch, SIGWINCH, client_signal, NULL); - signal_add(&ev_sigwinch, NULL); + set_signals(client_signal); /* * imsg_read in the first client poll loop (before the terminal has diff --git a/cmd-pipe-pane.c b/cmd-pipe-pane.c index efe79a38..0d7c3ff6 100644 --- a/cmd-pipe-pane.c +++ b/cmd-pipe-pane.c @@ -91,7 +91,7 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx) case 0: /* Child process. */ close(pipe_fd[0]); - server_signal_clear(); + clear_signals(); if (dup2(pipe_fd[1], STDIN_FILENO) == -1) _exit(1); diff --git a/job.c b/job.c index ddeae13f..61aa61fa 100644 --- a/job.c +++ b/job.c @@ -149,7 +149,7 @@ job_run(struct job *job) case -1: return (-1); case 0: /* child */ - server_signal_clear(); + clear_signals(); environ_push(&global_environ); diff --git a/server.c b/server.c index 017cc729..fa5b8919 100644 --- a/server.c +++ b/server.c @@ -49,9 +49,6 @@ struct clients dead_clients; int server_fd; int server_shutdown; struct event server_ev_accept; -struct event server_ev_sigterm; -struct event server_ev_sigusr1; -struct event server_ev_sigchld; struct event server_ev_second; int server_create_socket(void); @@ -141,6 +138,11 @@ server_start(char *path) if (daemon(1, 0) != 0) fatal("daemon failed"); + /* event_init() was called in our parent, need to reinit. */ + if (event_reinit(ev_base) != 0) + fatal("event_reinit failed"); + clear_signals(); + logfile("server"); log_debug("server started, pid %ld", (long) getpid()); @@ -162,8 +164,6 @@ server_start(char *path) log_debug("socket path %s", socket_path); setproctitle("server (%s)", rpathbuf); - event_init(); - server_fd = server_create_socket(); server_client_create(pair[1]); @@ -202,7 +202,7 @@ server_start(char *path) evtimer_set(&server_ev_second, server_second_callback, NULL); evtimer_add(&server_ev_second, &tv); - server_signal_set(); + set_signals(server_signal_callback); server_loop(); exit(0); } @@ -341,61 +341,6 @@ server_accept_callback(int fd, short events, unused void *data) server_client_create(newfd); } -/* Set up server signal handling. */ -void -server_signal_set(void) -{ - struct sigaction sigact; - - memset(&sigact, 0, sizeof sigact); - sigemptyset(&sigact.sa_mask); - sigact.sa_flags = SA_RESTART; - sigact.sa_handler = SIG_IGN; - if (sigaction(SIGINT, &sigact, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGPIPE, &sigact, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGUSR2, &sigact, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGTSTP, &sigact, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGHUP, &sigact, NULL) != 0) - fatal("sigaction failed"); - - signal_set(&server_ev_sigchld, SIGCHLD, server_signal_callback, NULL); - signal_add(&server_ev_sigchld, NULL); - signal_set(&server_ev_sigterm, SIGTERM, server_signal_callback, NULL); - signal_add(&server_ev_sigterm, NULL); - signal_set(&server_ev_sigusr1, SIGUSR1, server_signal_callback, NULL); - signal_add(&server_ev_sigusr1, NULL); -} - -/* Destroy server signal events. */ -void -server_signal_clear(void) -{ - struct sigaction sigact; - - memset(&sigact, 0, sizeof sigact); - sigemptyset(&sigact.sa_mask); - sigact.sa_flags = SA_RESTART; - sigact.sa_handler = SIG_DFL; - if (sigaction(SIGINT, &sigact, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGPIPE, &sigact, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGUSR2, &sigact, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGTSTP, &sigact, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGHUP, &sigact, NULL) != 0) - fatal("sigaction failed"); - - signal_del(&server_ev_sigchld); - signal_del(&server_ev_sigterm); - signal_del(&server_ev_sigusr1); -} - /* Signal handler. */ /* ARGSUSED */ void diff --git a/signal.c b/signal.c new file mode 100644 index 00000000..b84d90be --- /dev/null +++ b/signal.c @@ -0,0 +1,88 @@ +/* $Id$ */ + +/* + * Copyright (c) 2007 Nicholas Marriott + * Copyright (c) 2010 Romain Francoise + * + * 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 "tmux.h" + +struct event ev_sigchld; +struct event ev_sigcont; +struct event ev_sigterm; +struct event ev_sigusr1; +struct event ev_sigwinch; + +void +set_signals(void(*handler)(int, short, unused void *)) +{ + struct sigaction sigact; + + memset(&sigact, 0, sizeof sigact); + sigemptyset(&sigact.sa_mask); + sigact.sa_flags = SA_RESTART; + sigact.sa_handler = SIG_IGN; + if (sigaction(SIGINT, &sigact, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGPIPE, &sigact, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGUSR2, &sigact, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGTSTP, &sigact, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGHUP, &sigact, NULL) != 0) + fatal("sigaction failed"); + + signal_set(&ev_sigchld, SIGCHLD, handler, NULL); + signal_add(&ev_sigchld, NULL); + signal_set(&ev_sigcont, SIGCONT, handler, NULL); + signal_add(&ev_sigcont, NULL); + signal_set(&ev_sigterm, SIGTERM, handler, NULL); + signal_add(&ev_sigterm, NULL); + signal_set(&ev_sigusr1, SIGUSR1, handler, NULL); + signal_add(&ev_sigusr1, NULL); + signal_set(&ev_sigwinch, SIGWINCH, handler, NULL); + signal_add(&ev_sigwinch, NULL); +} + +void +clear_signals(void) +{ + struct sigaction sigact; + + memset(&sigact, 0, sizeof sigact); + sigemptyset(&sigact.sa_mask); + sigact.sa_flags = SA_RESTART; + sigact.sa_handler = SIG_DFL; + if (sigaction(SIGINT, &sigact, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGPIPE, &sigact, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGUSR2, &sigact, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGTSTP, &sigact, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGHUP, &sigact, NULL) != 0) + fatal("sigaction failed"); + + event_del(&ev_sigchld); + event_del(&ev_sigcont); + event_del(&ev_sigterm); + event_del(&ev_sigusr1); + event_del(&ev_sigwinch); +} diff --git a/tmux.c b/tmux.c index 741ee38e..2b0dd63c 100644 --- a/tmux.c +++ b/tmux.c @@ -18,6 +18,7 @@ #include #include +#include #include #include @@ -41,6 +42,8 @@ struct options global_s_options; /* session options */ struct options global_w_options; /* window options */ struct environ global_environ; +struct event_base *ev_base; + int debug_level; time_t start_time; char *socket_path; @@ -58,11 +61,8 @@ char *makesockpath(const char *); __dead void shell_exec(const char *, const char *); struct imsgbuf *main_ibuf; -struct event main_ev_sigterm; int main_exitval; -void main_set_signals(void); -void main_clear_signals(void); void main_signal(int, short, unused void *); void main_callback(int, short, void *); void main_dispatch(const char *); @@ -238,7 +238,6 @@ main(int argc, char **argv) struct keylist *keylist; struct env_data envdata; struct msg_command_data cmddata; - struct sigaction sigact; char *s, *shellcmd, *path, *label, *home, *cause; char cwd[MAXPATHLEN], **var; void *buf; @@ -538,24 +537,16 @@ main(int argc, char **argv) exit(1); } - /* Catch SIGCHLD to avoid a zombie when starting the server. */ - memset(&sigact, 0, sizeof sigact); - sigemptyset(&sigact.sa_mask); - sigact.sa_handler = SIG_IGN; - if (sigaction(SIGCHLD, &sigact, NULL) != 0) - fatal("sigaction failed"); + ev_base = event_init(); + set_signals(main_signal); /* Initialise the client socket/start the server. */ if ((main_ibuf = client_init(path, cmdflags, flags)) == NULL) exit(1); xfree(path); - event_init(); - imsg_compose(main_ibuf, msg, PROTOCOL_VERSION, -1, -1, buf, len); - main_set_signals(); - events = EV_READ; if (main_ibuf->w.queued > 0) events |= EV_WRITE; @@ -564,65 +555,23 @@ main(int argc, char **argv) main_exitval = 0; event_dispatch(); - main_clear_signals(); + clear_signals(); client_main(); /* doesn't return */ } -void -main_set_signals(void) -{ - struct sigaction sigact; - - memset(&sigact, 0, sizeof sigact); - sigemptyset(&sigact.sa_mask); - sigact.sa_flags = SA_RESTART; - sigact.sa_handler = SIG_IGN; - if (sigaction(SIGINT, &sigact, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGPIPE, &sigact, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGUSR1, &sigact, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGUSR2, &sigact, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGTSTP, &sigact, NULL) != 0) - fatal("sigaction failed"); - - signal_set(&main_ev_sigterm, SIGTERM, main_signal, NULL); - signal_add(&main_ev_sigterm, NULL); -} - -void -main_clear_signals(void) -{ - struct sigaction sigact; - - memset(&sigact, 0, sizeof sigact); - sigemptyset(&sigact.sa_mask); - sigact.sa_flags = SA_RESTART; - sigact.sa_handler = SIG_DFL; - if (sigaction(SIGINT, &sigact, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGPIPE, &sigact, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGUSR1, &sigact, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGUSR2, &sigact, NULL) != 0) - fatal("sigaction failed"); - if (sigaction(SIGTSTP, &sigact, NULL) != 0) - fatal("sigaction failed"); - - event_del(&main_ev_sigterm); -} - /* ARGSUSED */ void main_signal(int sig, unused short events, unused void *data) { + int status; + switch (sig) { case SIGTERM: exit(1); + case SIGCHLD: + waitpid(WAIT_ANY, &status, WNOHANG); + break; } } @@ -701,7 +650,7 @@ main_dispatch(const char *shellcmd) memcpy(&shelldata, imsg.data, sizeof shelldata); shelldata.shell[(sizeof shelldata.shell) - 1] = '\0'; - main_clear_signals(); + clear_signals(); shell_exec(shelldata.shell, shellcmd); default: diff --git a/tmux.h b/tmux.h index 80a6a9a7..ec6ab3d4 100644 --- a/tmux.h +++ b/tmux.h @@ -1253,6 +1253,7 @@ extern struct options global_options; extern struct options global_s_options; extern struct options global_w_options; extern struct environ global_environ; +extern struct event_base *ev_base; extern char *cfg_file; extern int debug_level; extern int be_quiet; @@ -1583,8 +1584,6 @@ const char *key_string_lookup_key(int); extern struct clients clients; extern struct clients dead_clients; int server_start(char *); -void server_signal_set(void); -void server_signal_clear(void); void server_update_socket(void); /* server-client.c */ @@ -1900,6 +1899,10 @@ void window_choose_ready(struct window_pane *, void queue_window_name(struct window *); char *default_window_name(struct window *); +/* signal.c */ +void set_signals(void(*handler)(int, short, unused void *)); +void clear_signals(void); + /* session.c */ extern struct sessions sessions; extern struct sessions dead_sessions; diff --git a/window.c b/window.c index 00c03f6e..0811a4cb 100644 --- a/window.c +++ b/window.c @@ -529,7 +529,7 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell, environ_push(env); - server_signal_clear(); + clear_signals(); log_close(); if (*wp->cmd != '\0') { From e0f4697e7cfd1a09d6332eae607fd3a9a1181234 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 5 May 2010 23:24:23 +0000 Subject: [PATCH 0697/1180] Identical behaviour to select-prompt can now be obtained with command-prompt, so remove select-prompt and change ' to be bound to command-prompt -p index "select-window -t :%%". --- Makefile | 13 +++---- cmd-command-prompt.c | 4 ++ cmd-select-prompt.c | 91 -------------------------------------------- cmd.c | 1 - key-bindings.c | 2 +- tmux.1 | 6 +-- tmux.h | 1 - 7 files changed, 12 insertions(+), 106 deletions(-) delete mode 100644 cmd-select-prompt.c diff --git a/Makefile b/Makefile index 189ea52f..6907a68b 100644 --- a/Makefile +++ b/Makefile @@ -19,16 +19,15 @@ SRCS= attributes.c cfg.c client.c clock.c \ cmd-previous-layout.c cmd-previous-window.c cmd-refresh-client.c \ cmd-rename-session.c cmd-rename-window.c cmd-resize-pane.c \ cmd-respawn-window.c cmd-rotate-window.c cmd-save-buffer.c \ - cmd-select-layout.c cmd-select-pane.c \ - cmd-select-prompt.c cmd-select-window.c cmd-send-keys.c \ - cmd-send-prefix.c cmd-server-info.c cmd-set-buffer.c cmd-set-option.c \ - cmd-set-window-option.c cmd-show-buffer.c cmd-show-messages.c \ - cmd-show-options.c cmd-show-window-options.c cmd-source-file.c \ - cmd-split-window.c cmd-start-server.c cmd-string.c cmd-if-shell.c \ + cmd-select-layout.c cmd-select-pane.c cmd-select-window.c \ + cmd-send-keys.c cmd-send-prefix.c cmd-server-info.c cmd-set-buffer.c \ + cmd-set-option.c cmd-set-window-option.c cmd-show-buffer.c \ + cmd-show-messages.c cmd-show-options.c cmd-show-window-options.c \ + cmd-source-file.c cmd-split-window.c cmd-start-server.c cmd-string.c \ cmd-run-shell.c cmd-suspend-client.c cmd-swap-pane.c cmd-swap-window.c \ cmd-switch-client.c cmd-unbind-key.c cmd-unlink-window.c \ cmd-set-environment.c cmd-show-environment.c cmd-choose-client.c \ - cmd-display-message.c cmd-display-panes.c \ + cmd-display-message.c cmd-display-panes.c cmd-if-shell.c \ cmd-pipe-pane.c cmd-capture-pane.c cmd.c \ colour.c environ.c grid-view.c grid-utf8.c grid.c input-keys.c \ imsg.c imsg-buffer.c input.c key-bindings.c key-string.c \ diff --git a/cmd-command-prompt.c b/cmd-command-prompt.c index e3774256..b76ea8d1 100644 --- a/cmd-command-prompt.c +++ b/cmd-command-prompt.c @@ -81,6 +81,10 @@ cmd_command_prompt_init(struct cmd *self, int key) case 'f': data->template = xstrdup("find-window '%%'"); break; + case '\'': + data->template = xstrdup("select-window -t ':%%'"); + data->prompts = xstrdup("index"); + break; } } diff --git a/cmd-select-prompt.c b/cmd-select-prompt.c deleted file mode 100644 index 12fe711d..00000000 --- a/cmd-select-prompt.c +++ /dev/null @@ -1,91 +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 "tmux.h" - -/* - * Prompt for window index and select it. - */ - -int cmd_select_prompt_exec(struct cmd *, struct cmd_ctx *); - -int cmd_select_prompt_callback(void *, const char *); - -const struct cmd_entry cmd_select_prompt_entry = { - "select-prompt", NULL, - CMD_TARGET_CLIENT_USAGE, - 0, "", - cmd_target_init, - cmd_target_parse, - cmd_select_prompt_exec, - cmd_target_free, - cmd_target_print -}; - -int -cmd_select_prompt_exec(struct cmd *self, struct cmd_ctx *ctx) -{ - struct cmd_target_data *data = self->data; - struct client *c; - - if ((c = cmd_find_client(ctx, data->target)) == NULL) - return (-1); - - if (c->prompt_string != NULL) - return (0); - - status_prompt_set(c, "index ", cmd_select_prompt_callback, NULL, c, 0); - - return (0); -} - -int -cmd_select_prompt_callback(void *data, const char *s) -{ - struct client *c = data; - const char *errstr; - char msg[128]; - u_int idx; - - if (s == NULL || *s == '\0') - return (0); - - idx = strtonum(s, 0, UINT_MAX, &errstr); - if (errstr != NULL) { - xsnprintf(msg, sizeof msg, "Index %s: %s", errstr, s); - status_message_set(c, "%s", msg); - return (0); - } - - if (winlink_find_by_index(&c->session->windows, idx) == NULL) { - xsnprintf(msg, sizeof msg, - "Window not found: %s:%d", c->session->name, idx); - status_message_set(c, "%s", msg); - return (0); - } - - if (session_select(c->session, idx) == 0) - server_redraw_session(c->session); - recalculate_sizes(); - - return (0); -} diff --git a/cmd.c b/cmd.c index 09b58adf..d82a765e 100644 --- a/cmd.c +++ b/cmd.c @@ -85,7 +85,6 @@ const struct cmd_entry *cmd_table[] = { &cmd_save_buffer_entry, &cmd_select_layout_entry, &cmd_select_pane_entry, - &cmd_select_prompt_entry, &cmd_select_window_entry, &cmd_send_keys_entry, &cmd_send_prefix_entry, diff --git a/key-bindings.c b/key-bindings.c index 9a2fcc12..44132202 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -125,7 +125,7 @@ key_bindings_init(void) { '?', 0, &cmd_list_keys_entry }, { 'D', 0, &cmd_choose_client_entry }, { '[', 0, &cmd_copy_mode_entry }, - { '\'', 0, &cmd_select_prompt_entry }, + { '\'', 0, &cmd_command_prompt_entry }, { '\002', /* C-b */ 0, &cmd_send_prefix_entry }, { '\017', /* C-o */ 0, &cmd_rotate_window_entry }, { '\032', /* C-z */ 0, &cmd_suspend_client_entry }, diff --git a/tmux.1 b/tmux.1 index 49816e24..26966cb6 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1265,7 +1265,7 @@ or keys, quotation marks are necessary, for example: .Bd -literal -offset indent bind-key '"' split-window -bind-key "'" select-prompt +bind-key "'" new-window .Ed .Pp Commands related to key bindings are as follows: @@ -2316,10 +2316,6 @@ The format of is as for .Ic status-left , with the exception that #() are not handled. -.It Ic select-prompt Op Fl t Ar target-client -Open a prompt inside -.Ar target-client -allowing a window index to be entered interactively. .El .Sh BUFFERS .Nm diff --git a/tmux.h b/tmux.h index ec6ab3d4..d07a6517 100644 --- a/tmux.h +++ b/tmux.h @@ -1495,7 +1495,6 @@ extern const struct cmd_entry cmd_run_shell_entry; extern const struct cmd_entry cmd_save_buffer_entry; extern const struct cmd_entry cmd_select_layout_entry; extern const struct cmd_entry cmd_select_pane_entry; -extern const struct cmd_entry cmd_select_prompt_entry; extern const struct cmd_entry cmd_select_window_entry; extern const struct cmd_entry cmd_send_keys_entry; extern const struct cmd_entry cmd_send_prefix_entry; From 72d1afa169505710f3c8a05d4c6f6fc12257bfc7 Mon Sep 17 00:00:00 2001 From: Joel Sing Date: Wed, 12 May 2010 15:05:39 +0000 Subject: [PATCH 0698/1180] Catch SIGHUP and terminate if running as a client. This prevents clients from being left hanging around when, for example, a SSH session is disconnected. ok nicm@ --- client.c | 5 +++++ signal.c | 8 ++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/client.c b/client.c index 5940f62e..092ae555 100644 --- a/client.c +++ b/client.c @@ -206,6 +206,11 @@ client_signal(int sig, unused short events, unused void *data) struct sigaction sigact; switch (sig) { + case SIGHUP: + client_exitmsg = "lost tty"; + client_exitval = 1; + client_write_server(MSG_EXITING, NULL, 0); + break; case SIGTERM: client_exitmsg = "terminated"; client_exitval = 1; diff --git a/signal.c b/signal.c index b84d90be..ff1a4245 100644 --- a/signal.c +++ b/signal.c @@ -22,6 +22,7 @@ #include "tmux.h" +struct event ev_sighup; struct event ev_sigchld; struct event ev_sigcont; struct event ev_sigterm; @@ -45,9 +46,9 @@ set_signals(void(*handler)(int, short, unused void *)) fatal("sigaction failed"); if (sigaction(SIGTSTP, &sigact, NULL) != 0) fatal("sigaction failed"); - if (sigaction(SIGHUP, &sigact, NULL) != 0) - fatal("sigaction failed"); + signal_set(&ev_sighup, SIGHUP, handler, NULL); + signal_add(&ev_sighup, NULL); signal_set(&ev_sigchld, SIGCHLD, handler, NULL); signal_add(&ev_sigchld, NULL); signal_set(&ev_sigcont, SIGCONT, handler, NULL); @@ -77,9 +78,8 @@ clear_signals(void) fatal("sigaction failed"); if (sigaction(SIGTSTP, &sigact, NULL) != 0) fatal("sigaction failed"); - if (sigaction(SIGHUP, &sigact, NULL) != 0) - fatal("sigaction failed"); + event_del(&ev_sighup); event_del(&ev_sigchld); event_del(&ev_sigcont); event_del(&ev_sigterm); From e5f01febd71fcb4390788a6d9c989b27a81cd94e Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 14 May 2010 14:41:06 +0000 Subject: [PATCH 0699/1180] Use $OpenBSD$. --- signal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/signal.c b/signal.c index ff1a4245..75f80b51 100644 --- a/signal.c +++ b/signal.c @@ -1,4 +1,4 @@ -/* $Id$ */ +/* $OpenBSD$ */ /* * Copyright (c) 2007 Nicholas Marriott From 4af4d124759b4648bded82482f4d043ad2b3bb79 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 14 May 2010 18:56:21 +0000 Subject: [PATCH 0700/1180] Accept (and document) "none" instead of "default" for attributes as it is clearer and avoids confusion with default colours. --- attributes.c | 4 ++-- tmux.1 | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/attributes.c b/attributes.c index 0e42c787..81f29452 100644 --- a/attributes.c +++ b/attributes.c @@ -28,7 +28,7 @@ attributes_tostring(u_char attr) static char buf[128]; if (attr == 0) - return ("default"); + return ("none"); buf[0] = '\0'; if (attr & GRID_ATTR_BRIGHT) @@ -63,7 +63,7 @@ attributes_fromstring(const char *str) if (strchr(delimiters, str[strlen(str) - 1]) != NULL) return (-1); - if (strcasecmp(str, "default") == 0) + if (strcasecmp(str, "default") == 0 || strcasecmp(str, "none") == 0) return (0); attr = 0; diff --git a/tmux.1 b/tmux.1 index 26966cb6..85aabdb7 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1589,7 +1589,7 @@ This has no effect as a session option; it must be set as a global option. Set status line message attributes, where .Ar attributes is either -.Ic default +.Ic none or a comma-delimited list of one or more of: .Ic bright (or From d91127958d2936fdae28d695d85c15d2bca0d9cf Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 14 May 2010 19:03:09 +0000 Subject: [PATCH 0701/1180] Colour+attribute options for status line alerts, from Alex Alexander. --- cmd-set-option.c | 3 +++ status.c | 13 +++++++++++-- tmux.1 | 10 ++++++++++ tmux.c | 3 +++ 4 files changed, 27 insertions(+), 2 deletions(-) diff --git a/cmd-set-option.c b/cmd-set-option.c index 90b6d611..85776fbb 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -157,6 +157,9 @@ const struct set_option_entry set_window_option_table[] = { { "remain-on-exit", SET_OPTION_FLAG, 0, 0, NULL }, { "synchronize-panes", SET_OPTION_FLAG, 0, 0, NULL }, { "utf8", SET_OPTION_FLAG, 0, 0, NULL }, + { "window-status-alert-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL }, + { "window-status-alert-bg", SET_OPTION_COLOUR, 0, 0, NULL }, + { "window-status-alert-fg", SET_OPTION_COLOUR, 0, 0, NULL }, { "window-status-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL }, { "window-status-bg", SET_OPTION_COLOUR, 0, 0, NULL }, { "window-status-current-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL }, diff --git a/status.c b/status.c index b3ae78ce..4399ae43 100644 --- a/status.c +++ b/status.c @@ -595,8 +595,17 @@ status_print( if (session_alert_has(s, wl, WINDOW_ACTIVITY) || session_alert_has(s, wl, WINDOW_BELL) || - session_alert_has(s, wl, WINDOW_CONTENT)) - gc->attr ^= GRID_ATTR_REVERSE; + session_alert_has(s, wl, WINDOW_CONTENT)) { + fg = options_get_number(oo, "window-status-alert-fg"); + if (fg != 8) + colour_set_fg(gc, fg); + bg = options_get_number(oo, "window-status-alert-bg"); + if (bg != 8) + colour_set_bg(gc, bg); + attr = options_get_number(oo, "window-status-alert-attr"); + if (attr != 0) + gc->attr = attr; + } text = status_replace(c, wl, fmt, t, 1); return (text); diff --git a/tmux.1 b/tmux.1 index 85aabdb7..132a58ea 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2073,6 +2073,16 @@ option for details of special character sequences available. The default is .Ql #I:#W#F . .Pp +.It Ic window-status-alert-attr Ar attributes +Set status line attributes for windows which have an alert (bell, activity +or content). +.Pp +.It Ic window-status-alert-bg Ar colour +Set status line background colour for windows with an alert. +.Pp +.It Ic window-status-alert-fg Ar colour +Set status line foreground colour for windows with an alert. +.Pp .It Ic window-status-current-attr Ar attributes Set status line attributes for the currently active window. .Pp diff --git a/tmux.c b/tmux.c index 2b0dd63c..28f822ce 100644 --- a/tmux.c +++ b/tmux.c @@ -416,6 +416,9 @@ main(int argc, char **argv) options_set_number(wo, "window-status-current-bg", 8); options_set_number(wo, "window-status-current-fg", 8); options_set_number(wo, "window-status-fg", 8); + options_set_number(wo, "window-status-alert-attr", GRID_ATTR_REVERSE); + options_set_number(wo, "window-status-alert-bg", 8); + options_set_number(wo, "window-status-alert-fg", 8); options_set_string(wo, "window-status-format", "#I:#W#F"); options_set_string(wo, "window-status-current-format", "#I:#W#F"); options_set_string(wo, "word-separators", " -_@"); From 0ed727a0128dd84ae727a337208a31df8f3cff02 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 19 May 2010 22:28:14 +0000 Subject: [PATCH 0702/1180] Enhance paste-buffer to allow lines to be separated by any string, from Andrea Barisani. --- cmd-paste-buffer.c | 169 +++++++++++++++++++++++++++++++++++++++------ tmux.1 | 10 ++- 2 files changed, 154 insertions(+), 25 deletions(-) diff --git a/cmd-paste-buffer.c b/cmd-paste-buffer.c index e4d97f44..0b9b3926 100644 --- a/cmd-paste-buffer.c +++ b/cmd-paste-buffer.c @@ -18,7 +18,9 @@ #include +#include #include +#include #include "tmux.h" @@ -26,27 +28,109 @@ * Paste paste buffer if present. */ +struct cmd_paste_buffer_data { + char *target; + int buffer; + + int flag_delete; + char *sepstr; +}; + +void cmd_paste_buffer_init(struct cmd *, int); +int cmd_paste_buffer_parse(struct cmd *, int, char **, char **); int cmd_paste_buffer_exec(struct cmd *, struct cmd_ctx *); -void cmd_paste_buffer_lf2cr(struct window_pane *, const char *, size_t); +void cmd_paste_buffer_filter( + struct window_pane *, const char *, size_t, char *); +void cmd_paste_buffer_free(struct cmd *); +size_t cmd_paste_buffer_print(struct cmd *, char *, size_t); const struct cmd_entry cmd_paste_buffer_entry = { "paste-buffer", "pasteb", - "[-dr] " CMD_BUFFER_PANE_USAGE, - 0, "dr", - cmd_buffer_init, - cmd_buffer_parse, + "[-dr] [-s separator] [-b buffer-index] [-t target-window]", + 0, "", + cmd_paste_buffer_init, + cmd_paste_buffer_parse, cmd_paste_buffer_exec, - cmd_buffer_free, - cmd_buffer_print + cmd_paste_buffer_free, + cmd_paste_buffer_print }; +/* ARGSUSED */ +void +cmd_paste_buffer_init(struct cmd *self, unused int arg) +{ + struct cmd_paste_buffer_data *data; + + self->data = data = xmalloc(sizeof *data); + data->target = NULL; + data->buffer = -1; + data->flag_delete = 0; + data->sepstr = xstrdup("\r"); +} + +int +cmd_paste_buffer_parse(struct cmd *self, int argc, char **argv, char **cause) +{ + struct cmd_paste_buffer_data *data; + int opt, n; + const char *errstr; + + cmd_paste_buffer_init(self, 0); + data = self->data; + + while ((opt = getopt(argc, argv, "b:ds:t:r")) != -1) { + switch (opt) { + case 'b': + if (data->buffer == -1) { + n = strtonum(optarg, 0, INT_MAX, &errstr); + if (errstr != NULL) { + xasprintf(cause, "buffer %s", errstr); + goto error; + } + data->buffer = n; + } + break; + case 'd': + data->flag_delete = 1; + break; + case 's': + if (data->sepstr != NULL) + xfree(data->sepstr); + data->sepstr = xstrdup(optarg); + break; + case 't': + if (data->target == NULL) + data->target = xstrdup(optarg); + break; + case 'r': + if (data->sepstr != NULL) + xfree(data->sepstr); + data->sepstr = xstrdup("\n"); + break; + default: + goto usage; + } + } + argc -= optind; + argv += optind; + + return (0); + +usage: + xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); + +error: + self->entry->free(self); + return (-1); +} + int cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_buffer_data *data = self->data; - struct window_pane *wp; - struct session *s; - struct paste_buffer *pb; + struct cmd_paste_buffer_data *data = self->data; + struct window_pane *wp; + struct session *s; + struct paste_buffer *pb; if (cmd_find_pane(ctx, data->target, &s, &wp) == NULL) return (-1); @@ -60,16 +144,11 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) } } - if (pb != NULL) { - /* -r means raw data without LF->CR conversion. */ - if (cmd_check_flag(data->chflags, 'r')) - bufferevent_write(wp->event, pb->data, pb->size); - else - cmd_paste_buffer_lf2cr(wp, pb->data, pb->size); - } + if (pb != NULL) + cmd_paste_buffer_filter(wp, pb->data, pb->size, data->sepstr); /* Delete the buffer if -d. */ - if (cmd_check_flag(data->chflags, 'd')) { + if (data->flag_delete) { if (data->buffer == -1) paste_free_top(&s->buffers); else @@ -79,20 +158,66 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) return (0); } -/* Add bytes to a buffer but change every '\n' to '\r'. */ +/* Add bytes to a buffer and filter '\n' according to separator. */ void -cmd_paste_buffer_lf2cr(struct window_pane *wp, const char *data, size_t size) +cmd_paste_buffer_filter( + struct window_pane *wp, const char *data, size_t size, char *sep) { const char *end = data + size; const char *lf; + size_t seplen; + seplen = strlen(sep); while ((lf = memchr(data, '\n', end - data)) != NULL) { if (lf != data) bufferevent_write(wp->event, data, lf - data); - bufferevent_write(wp->event, "\r", 1); + bufferevent_write(wp->event, sep, seplen); data = lf + 1; } if (end != data) bufferevent_write(wp->event, data, end - data); } + +void +cmd_paste_buffer_free(struct cmd *self) +{ + struct cmd_paste_buffer_data *data = self->data; + + if (data->target != NULL) + xfree(data->target); + if (data->sepstr != NULL) + xfree(data->sepstr); + xfree(data); +} + +size_t +cmd_paste_buffer_print(struct cmd *self, char *buf, size_t len) +{ + struct cmd_paste_buffer_data *data = self->data; + size_t off = 0; + char tmp[BUFSIZ]; + int r_flag; + + r_flag = 0; + if (data->sepstr != NULL) + r_flag = (data->sepstr[0] == '\n' && data->sepstr[1] == '\0'); + + off += xsnprintf(buf, len, "%s", self->entry->name); + if (data == NULL) + return (off); + if (off < len && data->flag_delete) + off += xsnprintf(buf + off, len - off, " -d"); + if (off < len && r_flag) + off += xsnprintf(buf + off, len - off, " -r"); + if (off < len && data->buffer != -1) + off += xsnprintf(buf + off, len - off, " -b %d", data->buffer); + if (off < len && data->sepstr != NULL && !r_flag) { + strnvis( + tmp, data->sepstr, sizeof tmp, VIS_OCTAL|VIS_TAB|VIS_NL); + off += cmd_prarg(buf + off, len - off, " -s ", tmp); + } + if (off < len && data->target != NULL) + off += cmd_prarg(buf + off, len - off, " -t ", data->target); + return (off); +} diff --git a/tmux.1 b/tmux.1 index 132a58ea..8d123b25 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2387,6 +2387,7 @@ Load the contents of the specified paste buffer from .It Xo Ic paste-buffer .Op Fl dr .Op Fl b Ar buffer-index +.Op Fl s Ar separator .Op Fl t Ar target-pane .Xc .D1 (alias: Ic pasteb ) @@ -2396,10 +2397,13 @@ With .Fl d , also delete the paste buffer from the stack. When output, any linefeed (LF) characters in the paste buffer are replaced with -carriage returns (CR). -This translation may be disabled with the -.Fl r +a separator, by default carriage return (CR). +A custom separator may be specified using the +.Fl s flag. +The +.Fl r +flag means to do no replacement (equivalent to a separator of LF). .It Xo Ic save-buffer .Op Fl a .Op Fl b Ar buffer-index From 4f5c5b37b866967be189901bc140ca6b8c25c5e3 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 23 May 2010 19:42:19 +0000 Subject: [PATCH 0703/1180] Pass in the session, rather than the client, to window modes' key() function. We were only ever using the client to find the session anyway. This allows send-key to work properly for manipulating copy mode from outside tmux. From Micah Cowan. --- cmd-send-keys.c | 5 +++-- cmd-send-prefix.c | 2 +- server-client.c | 8 ++++---- tmux.h | 10 +++++----- window-choose.c | 8 ++++---- window-clock.c | 4 ++-- window-copy.c | 22 ++++++++++------------ window.c | 8 ++++---- 8 files changed, 33 insertions(+), 34 deletions(-) diff --git a/cmd-send-keys.c b/cmd-send-keys.c index 204d497d..3c680524 100644 --- a/cmd-send-keys.c +++ b/cmd-send-keys.c @@ -105,16 +105,17 @@ cmd_send_keys_exec(struct cmd *self, struct cmd_ctx *ctx) { struct cmd_send_keys_data *data = self->data; struct window_pane *wp; + struct session *s; u_int i; if (data == NULL) return (-1); - if (cmd_find_pane(ctx, data->target, NULL, &wp) == NULL) + if (cmd_find_pane(ctx, data->target, &s, &wp) == NULL) return (-1); for (i = 0; i < data->nkeys; i++) - window_pane_key(wp, ctx->curclient, data->keys[i]); + window_pane_key(wp, s, data->keys[i]); return (0); } diff --git a/cmd-send-prefix.c b/cmd-send-prefix.c index ccc98151..c7f7e9fa 100644 --- a/cmd-send-prefix.c +++ b/cmd-send-prefix.c @@ -49,7 +49,7 @@ cmd_send_prefix_exec(struct cmd *self, struct cmd_ctx *ctx) return (-1); keylist = options_get_data(&s->options, "prefix"); - window_pane_key(wp, ctx->curclient, ARRAY_FIRST(keylist)); + window_pane_key(wp, s, ARRAY_FIRST(keylist)); return (0); } diff --git a/server-client.c b/server-client.c index 03d5c84b..9d550386 100644 --- a/server-client.c +++ b/server-client.c @@ -300,7 +300,7 @@ server_client_handle_key(int key, struct mouse_event *mouse, void *data) server_redraw_window_borders(w); wp = w->active; } - window_pane_mouse(wp, c, mouse); + window_pane_mouse(wp, c->session, mouse); return; } @@ -322,7 +322,7 @@ server_client_handle_key(int key, struct mouse_event *mouse, void *data) /* Try as a non-prefix key binding. */ if ((bd = key_bindings_lookup(key)) == NULL) { if (!(c->flags & CLIENT_READONLY)) - window_pane_key(wp, c, key); + window_pane_key(wp, c->session, key); } else key_bindings_dispatch(bd, c); } @@ -338,7 +338,7 @@ server_client_handle_key(int key, struct mouse_event *mouse, void *data) if (isprefix) c->flags |= CLIENT_PREFIX; else if (!(c->flags & CLIENT_READONLY)) - window_pane_key(wp, c, key); + window_pane_key(wp, c->session, key); } return; } @@ -349,7 +349,7 @@ server_client_handle_key(int key, struct mouse_event *mouse, void *data) if (isprefix) c->flags |= CLIENT_PREFIX; else if (!(c->flags & CLIENT_READONLY)) - window_pane_key(wp, c, key); + window_pane_key(wp, c->session, key); return; } diff --git a/tmux.h b/tmux.h index d07a6517..ce9c2677 100644 --- a/tmux.h +++ b/tmux.h @@ -760,16 +760,16 @@ struct input_ctx { * Window mode. Windows can be in several modes and this is used to call the * right function to handle input and output. */ -struct client; +struct session; struct window; struct mouse_event; struct window_mode { struct screen *(*init)(struct window_pane *); void (*free)(struct window_pane *); void (*resize)(struct window_pane *, u_int, u_int); - void (*key)(struct window_pane *, struct client *, int); + void (*key)(struct window_pane *, struct session *, int); void (*mouse)(struct window_pane *, - struct client *, struct mouse_event *); + struct session *, struct mouse_event *); void (*timer)(struct window_pane *); }; @@ -1828,9 +1828,9 @@ void window_pane_alternate_off( int window_pane_set_mode( struct window_pane *, const struct window_mode *); void window_pane_reset_mode(struct window_pane *); -void window_pane_key(struct window_pane *, struct client *, int); +void window_pane_key(struct window_pane *, struct session *, int); void window_pane_mouse(struct window_pane *, - struct client *, struct mouse_event *); + struct session *, struct mouse_event *); int window_pane_visible(struct window_pane *); char *window_pane_search( struct window_pane *, const char *, u_int *); diff --git a/window-choose.c b/window-choose.c index 87f08f33..a50d7e30 100644 --- a/window-choose.c +++ b/window-choose.c @@ -25,9 +25,9 @@ struct screen *window_choose_init(struct window_pane *); void window_choose_free(struct window_pane *); void window_choose_resize(struct window_pane *, u_int, u_int); -void window_choose_key(struct window_pane *, struct client *, int); +void window_choose_key(struct window_pane *, struct session *, int); void window_choose_mouse( - struct window_pane *, struct client *, struct mouse_event *); + struct window_pane *, struct session *, struct mouse_event *); void window_choose_redraw_screen(struct window_pane *); void window_choose_write_line( @@ -171,7 +171,7 @@ window_choose_resize(struct window_pane *wp, u_int sx, u_int sy) /* ARGSUSED */ void -window_choose_key(struct window_pane *wp, unused struct client *c, int key) +window_choose_key(struct window_pane *wp, unused struct session *sess, int key) { struct window_choose_mode_data *data = wp->modedata; struct screen *s = &data->screen; @@ -304,7 +304,7 @@ window_choose_key(struct window_pane *wp, unused struct client *c, int key) /* ARGSUSED */ void window_choose_mouse( - struct window_pane *wp, unused struct client *c, struct mouse_event *m) + struct window_pane *wp, unused struct session *sess, struct mouse_event *m) { struct window_choose_mode_data *data = wp->modedata; struct screen *s = &data->screen; diff --git a/window-clock.c b/window-clock.c index bc9cf81d..64980df0 100644 --- a/window-clock.c +++ b/window-clock.c @@ -26,7 +26,7 @@ struct screen *window_clock_init(struct window_pane *); void window_clock_free(struct window_pane *); void window_clock_resize(struct window_pane *, u_int, u_int); -void window_clock_key(struct window_pane *, struct client *, int); +void window_clock_key(struct window_pane *, struct session *, int); void window_clock_timer(struct window_pane *); void window_clock_draw_screen(struct window_pane *); @@ -85,7 +85,7 @@ window_clock_resize(struct window_pane *wp, u_int sx, u_int sy) /* ARGSUSED */ void window_clock_key( - struct window_pane *wp, unused struct client *c, unused int key) + struct window_pane *wp, unused struct session *sess, unused int key) { window_pane_reset_mode(wp); } diff --git a/window-copy.c b/window-copy.c index 5e04f34e..3b42c456 100644 --- a/window-copy.c +++ b/window-copy.c @@ -26,11 +26,11 @@ struct screen *window_copy_init(struct window_pane *); void window_copy_free(struct window_pane *); void window_copy_resize(struct window_pane *, u_int, u_int); -void window_copy_key(struct window_pane *, struct client *, int); +void window_copy_key(struct window_pane *, struct session *, int); int window_copy_key_input(struct window_pane *, int); int window_copy_key_numeric_prefix(struct window_pane *, int); void window_copy_mouse( - struct window_pane *, struct client *, struct mouse_event *); + struct window_pane *, struct session *, struct mouse_event *); void window_copy_redraw_lines(struct window_pane *, u_int, u_int); void window_copy_redraw_screen(struct window_pane *); @@ -52,7 +52,7 @@ void window_copy_goto_line(struct window_pane *, const char *); void window_copy_update_cursor(struct window_pane *, u_int, u_int); void window_copy_start_selection(struct window_pane *); int window_copy_update_selection(struct window_pane *); -void window_copy_copy_selection(struct window_pane *, struct client *); +void window_copy_copy_selection(struct window_pane *, struct session *); void window_copy_clear_selection(struct window_pane *); void window_copy_copy_line( struct window_pane *, char **, size_t *, u_int, u_int, u_int); @@ -340,8 +340,6 @@ window_copy_resize(struct window_pane *wp, u_int sx, u_int sy) data->cy = sy - 1; if (data->cx > sx) data->cx = sx; - if (data->oy > screen_hsize(data->backing)) - data->oy = screen_hsize(data->backing); window_copy_clear_selection(wp); @@ -353,7 +351,7 @@ window_copy_resize(struct window_pane *wp, u_int sx, u_int sy) } void -window_copy_key(struct window_pane *wp, struct client *c, int key) +window_copy_key(struct window_pane *wp, struct session *sess, int key) { const char *word_separators; struct window_copy_mode_data *data = wp->modedata; @@ -503,8 +501,8 @@ window_copy_key(struct window_pane *wp, struct client *c, int key) window_copy_redraw_screen(wp); break; case MODEKEYCOPY_COPYSELECTION: - if (c != NULL && c->session != NULL) { - window_copy_copy_selection(wp, c); + if (sess != NULL) { + window_copy_copy_selection(wp, sess); window_pane_reset_mode(wp); return; } @@ -758,7 +756,7 @@ window_copy_key_numeric_prefix(struct window_pane *wp, int key) /* ARGSUSED */ void window_copy_mouse( - struct window_pane *wp, unused struct client *c, struct mouse_event *m) + struct window_pane *wp, unused struct session *sess, struct mouse_event *m) { struct window_copy_mode_data *data = wp->modedata; struct screen *s = &data->screen; @@ -1169,7 +1167,7 @@ window_copy_update_selection(struct window_pane *wp) } void -window_copy_copy_selection(struct window_pane *wp, struct client *c) +window_copy_copy_selection(struct window_pane *wp, struct session *sess) { struct window_copy_mode_data *data = wp->modedata; struct screen *s = &data->screen; @@ -1264,8 +1262,8 @@ window_copy_copy_selection(struct window_pane *wp, struct client *c) off--; /* remove final \n */ /* Add the buffer to the stack. */ - limit = options_get_number(&c->session->options, "buffer-limit"); - paste_add(&c->session->buffers, buf, off, limit); + limit = options_get_number(&sess->options, "buffer-limit"); + paste_add(&sess->buffers, buf, off, limit); } void diff --git a/window.c b/window.c index 0811a4cb..36ad4adb 100644 --- a/window.c +++ b/window.c @@ -721,7 +721,7 @@ window_pane_reset_mode(struct window_pane *wp) } void -window_pane_key(struct window_pane *wp, struct client *c, int key) +window_pane_key(struct window_pane *wp, struct session *sess, int key) { struct window_pane *wp2; @@ -730,7 +730,7 @@ window_pane_key(struct window_pane *wp, struct client *c, int key) if (wp->mode != NULL) { if (wp->mode->key != NULL) - wp->mode->key(wp, c, key); + wp->mode->key(wp, sess, key); return; } @@ -749,7 +749,7 @@ window_pane_key(struct window_pane *wp, struct client *c, int key) void window_pane_mouse( - struct window_pane *wp, struct client *c, struct mouse_event *m) + struct window_pane *wp, struct session *sess, struct mouse_event *m) { if (!window_pane_visible(wp)) return; @@ -763,7 +763,7 @@ window_pane_mouse( if (wp->mode != NULL) { if (wp->mode->mouse != NULL) - wp->mode->mouse(wp, c, m); + wp->mode->mouse(wp, sess, m); } else if (wp->fd != -1) input_mouse(wp, m); } From 608eef731a1e6973cff6e109aea31fabfdd8baaf Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 25 May 2010 19:47:30 +0000 Subject: [PATCH 0704/1180] Fix an out-of-date comment. --- cfg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cfg.c b/cfg.c index d540ff9b..406cf219 100644 --- a/cfg.c +++ b/cfg.c @@ -69,7 +69,7 @@ cfg_add_cause(struct causelist *causes, const char *fmt, ...) /* * Load configuration file. Returns -1 for an error with a list of messages in - * causes. Note that causes and ncauses must be initialised by the caller! + * causes. Note that causes must be initialised by the caller! */ int load_cfg(const char *path, struct cmd_ctx *ctxin, struct causelist *causes) From 1e8faaa217e205d68fb0096f42303c2f3c7bcc0c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 25 May 2010 20:05:25 +0000 Subject: [PATCH 0705/1180] Don't die if the client has been detached when the job finishes, just don't display the output. --- cmd-run-shell.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cmd-run-shell.c b/cmd-run-shell.c index f5e834f1..3b6844eb 100644 --- a/cmd-run-shell.c +++ b/cmd-run-shell.c @@ -82,6 +82,11 @@ cmd_run_shell_callback(struct job *job) int retcode; u_int lines; + if (ctx->cmdclient != NULL && ctx->cmdclient->flags & CLIENT_DEAD) + return; + if (ctx->curclient != NULL && ctx->curclient->flags & CLIENT_DEAD) + return; + lines = 0; do { if ((line = evbuffer_readline(job->event->input)) != NULL) { From c47d66f49ba50412260a33ec05c5c7c2b0249ed9 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 26 May 2010 13:56:07 +0000 Subject: [PATCH 0706/1180] Rename some imsg bits to make namespace collisions less likely buf to ibuf, buf_read to ibuf_read, READ_BUF_SIZE to IBUF_READ_SIZE. ok henning gilles claudio jacekm deraadt --- imsg-buffer.c | 64 +++++++++++++++++++++++++-------------------------- imsg.c | 20 ++++++++-------- imsg.h | 40 ++++++++++++++++---------------- 3 files changed, 62 insertions(+), 62 deletions(-) diff --git a/imsg-buffer.c b/imsg-buffer.c index 613220d4..3e45723c 100644 --- a/imsg-buffer.c +++ b/imsg-buffer.c @@ -28,16 +28,16 @@ #include "imsg.h" -int buf_realloc(struct buf *, size_t); -void buf_enqueue(struct msgbuf *, struct buf *); -void buf_dequeue(struct msgbuf *, struct buf *); +int ibuf_realloc(struct ibuf *, size_t); +void ibuf_enqueue(struct msgbuf *, struct ibuf *); +void ibuf_dequeue(struct msgbuf *, struct ibuf *); -struct buf * -buf_open(size_t len) +struct ibuf * +ibuf_open(size_t len) { - struct buf *buf; + struct ibuf *buf; - if ((buf = calloc(1, sizeof(struct buf))) == NULL) + if ((buf = calloc(1, sizeof(struct ibuf))) == NULL) return (NULL); if ((buf->buf = malloc(len)) == NULL) { free(buf); @@ -49,15 +49,15 @@ buf_open(size_t len) return (buf); } -struct buf * -buf_dynamic(size_t len, size_t max) +struct ibuf * +ibuf_dynamic(size_t len, size_t max) { - struct buf *buf; + struct ibuf *buf; if (max < len) return (NULL); - if ((buf = buf_open(len)) == NULL) + if ((buf = ibuf_open(len)) == NULL) return (NULL); if (max > 0) @@ -67,7 +67,7 @@ buf_dynamic(size_t len, size_t max) } int -buf_realloc(struct buf *buf, size_t len) +ibuf_realloc(struct ibuf *buf, size_t len) { u_char *b; @@ -87,10 +87,10 @@ buf_realloc(struct buf *buf, size_t len) } int -buf_add(struct buf *buf, const void *data, size_t len) +ibuf_add(struct ibuf *buf, const void *data, size_t len) { if (buf->wpos + len > buf->size) - if (buf_realloc(buf, len) == -1) + if (ibuf_realloc(buf, len) == -1) return (-1); memcpy(buf->buf + buf->wpos, data, len); @@ -99,12 +99,12 @@ buf_add(struct buf *buf, const void *data, size_t len) } void * -buf_reserve(struct buf *buf, size_t len) +ibuf_reserve(struct ibuf *buf, size_t len) { void *b; if (buf->wpos + len > buf->size) - if (buf_realloc(buf, len) == -1) + if (ibuf_realloc(buf, len) == -1) return (NULL); b = buf->buf + buf->wpos; @@ -113,7 +113,7 @@ buf_reserve(struct buf *buf, size_t len) } void * -buf_seek(struct buf *buf, size_t pos, size_t len) +ibuf_seek(struct ibuf *buf, size_t pos, size_t len) { /* only allowed to seek in already written parts */ if (pos + len > buf->wpos) @@ -123,28 +123,28 @@ buf_seek(struct buf *buf, size_t pos, size_t len) } size_t -buf_size(struct buf *buf) +ibuf_size(struct ibuf *buf) { return (buf->wpos); } size_t -buf_left(struct buf *buf) +ibuf_left(struct ibuf *buf) { return (buf->max - buf->wpos); } void -buf_close(struct msgbuf *msgbuf, struct buf *buf) +ibuf_close(struct msgbuf *msgbuf, struct ibuf *buf) { - buf_enqueue(msgbuf, buf); + ibuf_enqueue(msgbuf, buf); } int -buf_write(struct msgbuf *msgbuf) +ibuf_write(struct msgbuf *msgbuf) { struct iovec iov[IOV_MAX]; - struct buf *buf; + struct ibuf *buf; unsigned int i = 0; ssize_t n; @@ -176,7 +176,7 @@ buf_write(struct msgbuf *msgbuf) } void -buf_free(struct buf *buf) +ibuf_free(struct ibuf *buf) { free(buf->buf); free(buf); @@ -193,14 +193,14 @@ msgbuf_init(struct msgbuf *msgbuf) void msgbuf_drain(struct msgbuf *msgbuf, size_t n) { - struct buf *buf, *next; + struct ibuf *buf, *next; for (buf = TAILQ_FIRST(&msgbuf->bufs); buf != NULL && n > 0; buf = next) { next = TAILQ_NEXT(buf, entry); if (buf->rpos + n >= buf->wpos) { n -= buf->wpos - buf->rpos; - buf_dequeue(msgbuf, buf); + ibuf_dequeue(msgbuf, buf); } else { buf->rpos += n; n = 0; @@ -211,17 +211,17 @@ msgbuf_drain(struct msgbuf *msgbuf, size_t n) void msgbuf_clear(struct msgbuf *msgbuf) { - struct buf *buf; + struct ibuf *buf; while ((buf = TAILQ_FIRST(&msgbuf->bufs)) != NULL) - buf_dequeue(msgbuf, buf); + ibuf_dequeue(msgbuf, buf); } int msgbuf_write(struct msgbuf *msgbuf) { struct iovec iov[IOV_MAX]; - struct buf *buf; + struct ibuf *buf; unsigned int i = 0; ssize_t n; struct msghdr msg; @@ -284,14 +284,14 @@ msgbuf_write(struct msgbuf *msgbuf) } void -buf_enqueue(struct msgbuf *msgbuf, struct buf *buf) +ibuf_enqueue(struct msgbuf *msgbuf, struct ibuf *buf) { TAILQ_INSERT_TAIL(&msgbuf->bufs, buf, entry); msgbuf->queued++; } void -buf_dequeue(struct msgbuf *msgbuf, struct buf *buf) +ibuf_dequeue(struct msgbuf *msgbuf, struct ibuf *buf) { TAILQ_REMOVE(&msgbuf->bufs, buf, entry); @@ -299,5 +299,5 @@ buf_dequeue(struct msgbuf *msgbuf, struct buf *buf) close(buf->fd); msgbuf->queued--; - buf_free(buf); + ibuf_free(buf); } diff --git a/imsg.c b/imsg.c index 1be7f5ae..5d08c467 100644 --- a/imsg.c +++ b/imsg.c @@ -135,7 +135,7 @@ int imsg_compose(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid, pid_t pid, int fd, void *data, u_int16_t datalen) { - struct buf *wbuf; + struct ibuf *wbuf; if ((wbuf = imsg_create(ibuf, type, peerid, pid, datalen)) == NULL) return (-1); @@ -154,7 +154,7 @@ int imsg_composev(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid, pid_t pid, int fd, const struct iovec *iov, int iovcnt) { - struct buf *wbuf; + struct ibuf *wbuf; int i, datalen = 0; for (i = 0; i < iovcnt; i++) @@ -175,11 +175,11 @@ imsg_composev(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid, } /* ARGSUSED */ -struct buf * +struct ibuf * imsg_create(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid, pid_t pid, u_int16_t datalen) { - struct buf *wbuf; + struct ibuf *wbuf; struct imsg_hdr hdr; datalen += IMSG_HEADER_SIZE; @@ -193,7 +193,7 @@ imsg_create(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid, hdr.peerid = peerid; if ((hdr.pid = pid) == 0) hdr.pid = ibuf->pid; - if ((wbuf = buf_dynamic(datalen, MAX_IMSGSIZE)) == NULL) { + if ((wbuf = ibuf_dynamic(datalen, MAX_IMSGSIZE)) == NULL) { return (NULL); } if (imsg_add(wbuf, &hdr, sizeof(hdr)) == -1) @@ -203,18 +203,18 @@ imsg_create(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid, } int -imsg_add(struct buf *msg, void *data, u_int16_t datalen) +imsg_add(struct ibuf *msg, void *data, u_int16_t datalen) { if (datalen) - if (buf_add(msg, data, datalen) == -1) { - buf_free(msg); + if (ibuf_add(msg, data, datalen) == -1) { + ibuf_free(msg); return (-1); } return (datalen); } void -imsg_close(struct imsgbuf *ibuf, struct buf *msg) +imsg_close(struct imsgbuf *ibuf, struct ibuf *msg) { struct imsg_hdr *hdr; @@ -226,7 +226,7 @@ imsg_close(struct imsgbuf *ibuf, struct buf *msg) hdr->len = (u_int16_t)msg->wpos; - buf_close(&ibuf->w, msg); + ibuf_close(&ibuf->w, msg); } void diff --git a/imsg.h b/imsg.h index 43a29282..673d56be 100644 --- a/imsg.h +++ b/imsg.h @@ -18,12 +18,12 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#define READ_BUF_SIZE 65535 +#define IBUF_READ_SIZE 65535 #define IMSG_HEADER_SIZE sizeof(struct imsg_hdr) #define MAX_IMSGSIZE 16384 -struct buf { - TAILQ_ENTRY(buf) entry; +struct ibuf { + TAILQ_ENTRY(ibuf) entry; u_char *buf; size_t size; size_t max; @@ -33,13 +33,13 @@ struct buf { }; struct msgbuf { - TAILQ_HEAD(, buf) bufs; + TAILQ_HEAD(, ibuf) bufs; u_int32_t queued; int fd; }; -struct buf_read { - u_char buf[READ_BUF_SIZE]; +struct ibuf_read { + u_char buf[IBUF_READ_SIZE]; u_char *rptr; size_t wpos; }; @@ -51,7 +51,7 @@ struct imsg_fd { struct imsgbuf { TAILQ_HEAD(, imsg_fd) fds; - struct buf_read r; + struct ibuf_read r; struct msgbuf w; int fd; pid_t pid; @@ -75,16 +75,16 @@ struct imsg { /* buffer.c */ -struct buf *buf_open(size_t); -struct buf *buf_dynamic(size_t, size_t); -int buf_add(struct buf *, const void *, size_t); -void *buf_reserve(struct buf *, size_t); -void *buf_seek(struct buf *, size_t, size_t); -size_t buf_size(struct buf *); -size_t buf_left(struct buf *); -void buf_close(struct msgbuf *, struct buf *); -int buf_write(struct msgbuf *); -void buf_free(struct buf *); +struct ibuf *ibuf_open(size_t); +struct ibuf *ibuf_dynamic(size_t, size_t); +int ibuf_add(struct ibuf *, const void *, size_t); +void *ibuf_reserve(struct ibuf *, size_t); +void *ibuf_seek(struct ibuf *, size_t, size_t); +size_t ibuf_size(struct ibuf *); +size_t ibuf_left(struct ibuf *); +void ibuf_close(struct msgbuf *, struct ibuf *); +int ibuf_write(struct msgbuf *); +void ibuf_free(struct ibuf *); void msgbuf_init(struct msgbuf *); void msgbuf_clear(struct msgbuf *); int msgbuf_write(struct msgbuf *); @@ -98,10 +98,10 @@ int imsg_compose(struct imsgbuf *, u_int32_t, u_int32_t, pid_t, int, void *, u_int16_t); int imsg_composev(struct imsgbuf *, u_int32_t, u_int32_t, pid_t, int, const struct iovec *, int); -struct buf *imsg_create(struct imsgbuf *, u_int32_t, u_int32_t, pid_t, +struct ibuf *imsg_create(struct imsgbuf *, u_int32_t, u_int32_t, pid_t, u_int16_t); -int imsg_add(struct buf *, void *, u_int16_t); -void imsg_close(struct imsgbuf *, struct buf *); +int imsg_add(struct ibuf *, void *, u_int16_t); +void imsg_close(struct imsgbuf *, struct ibuf *); void imsg_free(struct imsg *); int imsg_flush(struct imsgbuf *); void imsg_clear(struct imsgbuf *); From 1618f3eae65743850e8b81df041e7372b8843dc6 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 26 May 2010 16:44:32 +0000 Subject: [PATCH 0707/1180] Move imsg into libutil and add a man page. Minor bump for libutil. Previous versions of this diff and man page looked at by various people. "you should just commit" deraadt --- Makefile | 2 +- imsg-buffer.c | 303 -------------------------------------------------- imsg.c | 271 -------------------------------------------- imsg.h | 107 ------------------ tmux.h | 2 +- 5 files changed, 2 insertions(+), 683 deletions(-) delete mode 100644 imsg-buffer.c delete mode 100644 imsg.c delete mode 100644 imsg.h diff --git a/Makefile b/Makefile index 6907a68b..73ca0c4d 100644 --- a/Makefile +++ b/Makefile @@ -30,7 +30,7 @@ SRCS= attributes.c cfg.c client.c clock.c \ cmd-display-message.c cmd-display-panes.c cmd-if-shell.c \ cmd-pipe-pane.c cmd-capture-pane.c cmd.c \ colour.c environ.c grid-view.c grid-utf8.c grid.c input-keys.c \ - imsg.c imsg-buffer.c input.c key-bindings.c key-string.c \ + input.c key-bindings.c key-string.c \ layout-set.c layout-string.c layout.c log.c job.c \ mode-key.c names.c options.c paste.c procname.c \ resize.c screen-redraw.c screen-write.c screen.c session.c status.c \ diff --git a/imsg-buffer.c b/imsg-buffer.c deleted file mode 100644 index 3e45723c..00000000 --- a/imsg-buffer.c +++ /dev/null @@ -1,303 +0,0 @@ -/* $OpenBSD$ */ - -/* - * Copyright (c) 2003, 2004 Henning Brauer - * - * 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 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 - -#include "imsg.h" - -int ibuf_realloc(struct ibuf *, size_t); -void ibuf_enqueue(struct msgbuf *, struct ibuf *); -void ibuf_dequeue(struct msgbuf *, struct ibuf *); - -struct ibuf * -ibuf_open(size_t len) -{ - struct ibuf *buf; - - if ((buf = calloc(1, sizeof(struct ibuf))) == NULL) - return (NULL); - if ((buf->buf = malloc(len)) == NULL) { - free(buf); - return (NULL); - } - buf->size = buf->max = len; - buf->fd = -1; - - return (buf); -} - -struct ibuf * -ibuf_dynamic(size_t len, size_t max) -{ - struct ibuf *buf; - - if (max < len) - return (NULL); - - if ((buf = ibuf_open(len)) == NULL) - return (NULL); - - if (max > 0) - buf->max = max; - - return (buf); -} - -int -ibuf_realloc(struct ibuf *buf, size_t len) -{ - u_char *b; - - /* on static buffers max is eq size and so the following fails */ - if (buf->wpos + len > buf->max) { - errno = ENOMEM; - return (-1); - } - - b = realloc(buf->buf, buf->wpos + len); - if (b == NULL) - return (-1); - buf->buf = b; - buf->size = buf->wpos + len; - - return (0); -} - -int -ibuf_add(struct ibuf *buf, const void *data, size_t len) -{ - if (buf->wpos + len > buf->size) - if (ibuf_realloc(buf, len) == -1) - return (-1); - - memcpy(buf->buf + buf->wpos, data, len); - buf->wpos += len; - return (0); -} - -void * -ibuf_reserve(struct ibuf *buf, size_t len) -{ - void *b; - - if (buf->wpos + len > buf->size) - if (ibuf_realloc(buf, len) == -1) - return (NULL); - - b = buf->buf + buf->wpos; - buf->wpos += len; - return (b); -} - -void * -ibuf_seek(struct ibuf *buf, size_t pos, size_t len) -{ - /* only allowed to seek in already written parts */ - if (pos + len > buf->wpos) - return (NULL); - - return (buf->buf + pos); -} - -size_t -ibuf_size(struct ibuf *buf) -{ - return (buf->wpos); -} - -size_t -ibuf_left(struct ibuf *buf) -{ - return (buf->max - buf->wpos); -} - -void -ibuf_close(struct msgbuf *msgbuf, struct ibuf *buf) -{ - ibuf_enqueue(msgbuf, buf); -} - -int -ibuf_write(struct msgbuf *msgbuf) -{ - struct iovec iov[IOV_MAX]; - struct ibuf *buf; - unsigned int i = 0; - ssize_t n; - - bzero(&iov, sizeof(iov)); - TAILQ_FOREACH(buf, &msgbuf->bufs, entry) { - if (i >= IOV_MAX) - break; - iov[i].iov_base = buf->buf + buf->rpos; - iov[i].iov_len = buf->wpos - buf->rpos; - i++; - } - - if ((n = writev(msgbuf->fd, iov, i)) == -1) { - if (errno == EAGAIN || errno == ENOBUFS || - errno == EINTR) /* try later */ - return (0); - else - return (-1); - } - - if (n == 0) { /* connection closed */ - errno = 0; - return (-2); - } - - msgbuf_drain(msgbuf, n); - - return (0); -} - -void -ibuf_free(struct ibuf *buf) -{ - free(buf->buf); - free(buf); -} - -void -msgbuf_init(struct msgbuf *msgbuf) -{ - msgbuf->queued = 0; - msgbuf->fd = -1; - TAILQ_INIT(&msgbuf->bufs); -} - -void -msgbuf_drain(struct msgbuf *msgbuf, size_t n) -{ - struct ibuf *buf, *next; - - for (buf = TAILQ_FIRST(&msgbuf->bufs); buf != NULL && n > 0; - buf = next) { - next = TAILQ_NEXT(buf, entry); - if (buf->rpos + n >= buf->wpos) { - n -= buf->wpos - buf->rpos; - ibuf_dequeue(msgbuf, buf); - } else { - buf->rpos += n; - n = 0; - } - } -} - -void -msgbuf_clear(struct msgbuf *msgbuf) -{ - struct ibuf *buf; - - while ((buf = TAILQ_FIRST(&msgbuf->bufs)) != NULL) - ibuf_dequeue(msgbuf, buf); -} - -int -msgbuf_write(struct msgbuf *msgbuf) -{ - struct iovec iov[IOV_MAX]; - struct ibuf *buf; - unsigned int i = 0; - ssize_t n; - struct msghdr msg; - struct cmsghdr *cmsg; - union { - struct cmsghdr hdr; - char buf[CMSG_SPACE(sizeof(int))]; - } cmsgbuf; - - bzero(&iov, sizeof(iov)); - bzero(&msg, sizeof(msg)); - TAILQ_FOREACH(buf, &msgbuf->bufs, entry) { - if (i >= IOV_MAX) - break; - iov[i].iov_base = buf->buf + buf->rpos; - iov[i].iov_len = buf->wpos - buf->rpos; - i++; - if (buf->fd != -1) - break; - } - - msg.msg_iov = iov; - msg.msg_iovlen = i; - - if (buf != NULL && buf->fd != -1) { - msg.msg_control = (caddr_t)&cmsgbuf.buf; - msg.msg_controllen = sizeof(cmsgbuf.buf); - cmsg = CMSG_FIRSTHDR(&msg); - cmsg->cmsg_len = CMSG_LEN(sizeof(int)); - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_RIGHTS; - *(int *)CMSG_DATA(cmsg) = buf->fd; - } - - if ((n = sendmsg(msgbuf->fd, &msg, 0)) == -1) { - if (errno == EAGAIN || errno == ENOBUFS || - errno == EINTR) /* try later */ - return (0); - else - return (-1); - } - - if (n == 0) { /* connection closed */ - errno = 0; - return (-2); - } - - /* - * assumption: fd got sent if sendmsg sent anything - * this works because fds are passed one at a time - */ - if (buf != NULL && buf->fd != -1) { - close(buf->fd); - buf->fd = -1; - } - - msgbuf_drain(msgbuf, n); - - return (0); -} - -void -ibuf_enqueue(struct msgbuf *msgbuf, struct ibuf *buf) -{ - TAILQ_INSERT_TAIL(&msgbuf->bufs, buf, entry); - msgbuf->queued++; -} - -void -ibuf_dequeue(struct msgbuf *msgbuf, struct ibuf *buf) -{ - TAILQ_REMOVE(&msgbuf->bufs, buf, entry); - - if (buf->fd != -1) - close(buf->fd); - - msgbuf->queued--; - ibuf_free(buf); -} diff --git a/imsg.c b/imsg.c deleted file mode 100644 index 5d08c467..00000000 --- a/imsg.c +++ /dev/null @@ -1,271 +0,0 @@ -/* $OpenBSD$ */ - -/* - * Copyright (c) 2003, 2004 Henning Brauer - * - * 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 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 - -#include "imsg.h" - -int imsg_get_fd(struct imsgbuf *); - -void -imsg_init(struct imsgbuf *ibuf, int fd) -{ - msgbuf_init(&ibuf->w); - bzero(&ibuf->r, sizeof(ibuf->r)); - ibuf->fd = fd; - ibuf->w.fd = fd; - ibuf->pid = getpid(); - TAILQ_INIT(&ibuf->fds); -} - -ssize_t -imsg_read(struct imsgbuf *ibuf) -{ - struct msghdr msg; - struct cmsghdr *cmsg; - union { - struct cmsghdr hdr; - char buf[CMSG_SPACE(sizeof(int) * 16)]; - } cmsgbuf; - struct iovec iov; - ssize_t n; - int fd; - struct imsg_fd *ifd; - - bzero(&msg, sizeof(msg)); - - iov.iov_base = ibuf->r.buf + ibuf->r.wpos; - iov.iov_len = sizeof(ibuf->r.buf) - ibuf->r.wpos; - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - msg.msg_control = &cmsgbuf.buf; - msg.msg_controllen = sizeof(cmsgbuf.buf); - - if ((n = recvmsg(ibuf->fd, &msg, 0)) == -1) { - if (errno != EINTR && errno != EAGAIN) { - return (-1); - } - return (-2); - } - - ibuf->r.wpos += n; - - for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; - cmsg = CMSG_NXTHDR(&msg, cmsg)) { - if (cmsg->cmsg_level == SOL_SOCKET && - cmsg->cmsg_type == SCM_RIGHTS) { - fd = (*(int *)CMSG_DATA(cmsg)); - if ((ifd = calloc(1, sizeof(struct imsg_fd))) == NULL) { - close(fd); - return (-1); - } - ifd->fd = fd; - TAILQ_INSERT_TAIL(&ibuf->fds, ifd, entry); - } - /* we do not handle other ctl data level */ - } - - return (n); -} - -ssize_t -imsg_get(struct imsgbuf *ibuf, struct imsg *imsg) -{ - size_t av, left, datalen; - - av = ibuf->r.wpos; - - if (IMSG_HEADER_SIZE > av) - return (0); - - memcpy(&imsg->hdr, ibuf->r.buf, sizeof(imsg->hdr)); - if (imsg->hdr.len < IMSG_HEADER_SIZE || - imsg->hdr.len > MAX_IMSGSIZE) { - errno = ERANGE; - return (-1); - } - if (imsg->hdr.len > av) - return (0); - datalen = imsg->hdr.len - IMSG_HEADER_SIZE; - ibuf->r.rptr = ibuf->r.buf + IMSG_HEADER_SIZE; - if ((imsg->data = malloc(datalen)) == NULL) - return (-1); - - if (imsg->hdr.flags & IMSGF_HASFD) - imsg->fd = imsg_get_fd(ibuf); - else - imsg->fd = -1; - - memcpy(imsg->data, ibuf->r.rptr, datalen); - - if (imsg->hdr.len < av) { - left = av - imsg->hdr.len; - memmove(&ibuf->r.buf, ibuf->r.buf + imsg->hdr.len, left); - ibuf->r.wpos = left; - } else - ibuf->r.wpos = 0; - - return (datalen + IMSG_HEADER_SIZE); -} - -int -imsg_compose(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid, - pid_t pid, int fd, void *data, u_int16_t datalen) -{ - struct ibuf *wbuf; - - if ((wbuf = imsg_create(ibuf, type, peerid, pid, datalen)) == NULL) - return (-1); - - if (imsg_add(wbuf, data, datalen) == -1) - return (-1); - - wbuf->fd = fd; - - imsg_close(ibuf, wbuf); - - return (1); -} - -int -imsg_composev(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid, - pid_t pid, int fd, const struct iovec *iov, int iovcnt) -{ - struct ibuf *wbuf; - int i, datalen = 0; - - for (i = 0; i < iovcnt; i++) - datalen += iov[i].iov_len; - - if ((wbuf = imsg_create(ibuf, type, peerid, pid, datalen)) == NULL) - return (-1); - - for (i = 0; i < iovcnt; i++) - if (imsg_add(wbuf, iov[i].iov_base, iov[i].iov_len) == -1) - return (-1); - - wbuf->fd = fd; - - imsg_close(ibuf, wbuf); - - return (1); -} - -/* ARGSUSED */ -struct ibuf * -imsg_create(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid, - pid_t pid, u_int16_t datalen) -{ - struct ibuf *wbuf; - struct imsg_hdr hdr; - - datalen += IMSG_HEADER_SIZE; - if (datalen > MAX_IMSGSIZE) { - errno = ERANGE; - return (NULL); - } - - hdr.type = type; - hdr.flags = 0; - hdr.peerid = peerid; - if ((hdr.pid = pid) == 0) - hdr.pid = ibuf->pid; - if ((wbuf = ibuf_dynamic(datalen, MAX_IMSGSIZE)) == NULL) { - return (NULL); - } - if (imsg_add(wbuf, &hdr, sizeof(hdr)) == -1) - return (NULL); - - return (wbuf); -} - -int -imsg_add(struct ibuf *msg, void *data, u_int16_t datalen) -{ - if (datalen) - if (ibuf_add(msg, data, datalen) == -1) { - ibuf_free(msg); - return (-1); - } - return (datalen); -} - -void -imsg_close(struct imsgbuf *ibuf, struct ibuf *msg) -{ - struct imsg_hdr *hdr; - - hdr = (struct imsg_hdr *)msg->buf; - - hdr->flags &= ~IMSGF_HASFD; - if (msg->fd != -1) - hdr->flags |= IMSGF_HASFD; - - hdr->len = (u_int16_t)msg->wpos; - - ibuf_close(&ibuf->w, msg); -} - -void -imsg_free(struct imsg *imsg) -{ - free(imsg->data); -} - -int -imsg_get_fd(struct imsgbuf *ibuf) -{ - int fd; - struct imsg_fd *ifd; - - if ((ifd = TAILQ_FIRST(&ibuf->fds)) == NULL) - return (-1); - - fd = ifd->fd; - TAILQ_REMOVE(&ibuf->fds, ifd, entry); - free(ifd); - - return (fd); -} - -int -imsg_flush(struct imsgbuf *ibuf) -{ - while (ibuf->w.queued) - if (msgbuf_write(&ibuf->w) < 0) - return (-1); - return (0); -} - -void -imsg_clear(struct imsgbuf *ibuf) -{ - int fd; - - msgbuf_clear(&ibuf->w); - while ((fd = imsg_get_fd(ibuf)) != -1) - close(fd); -} diff --git a/imsg.h b/imsg.h deleted file mode 100644 index 673d56be..00000000 --- a/imsg.h +++ /dev/null @@ -1,107 +0,0 @@ -/* $OpenBSD$ */ - -/* - * Copyright (c) 2006, 2007 Pierre-Yves Ritschard - * Copyright (c) 2006, 2007, 2008 Reyk Floeter - * Copyright (c) 2003, 2004 Henning Brauer - * - * 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 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. - */ - -#define IBUF_READ_SIZE 65535 -#define IMSG_HEADER_SIZE sizeof(struct imsg_hdr) -#define MAX_IMSGSIZE 16384 - -struct ibuf { - TAILQ_ENTRY(ibuf) entry; - u_char *buf; - size_t size; - size_t max; - size_t wpos; - size_t rpos; - int fd; -}; - -struct msgbuf { - TAILQ_HEAD(, ibuf) bufs; - u_int32_t queued; - int fd; -}; - -struct ibuf_read { - u_char buf[IBUF_READ_SIZE]; - u_char *rptr; - size_t wpos; -}; - -struct imsg_fd { - TAILQ_ENTRY(imsg_fd) entry; - int fd; -}; - -struct imsgbuf { - TAILQ_HEAD(, imsg_fd) fds; - struct ibuf_read r; - struct msgbuf w; - int fd; - pid_t pid; -}; - -#define IMSGF_HASFD 1 - -struct imsg_hdr { - u_int32_t type; - u_int16_t len; - u_int16_t flags; - u_int32_t peerid; - u_int32_t pid; -}; - -struct imsg { - struct imsg_hdr hdr; - int fd; - void *data; -}; - - -/* buffer.c */ -struct ibuf *ibuf_open(size_t); -struct ibuf *ibuf_dynamic(size_t, size_t); -int ibuf_add(struct ibuf *, const void *, size_t); -void *ibuf_reserve(struct ibuf *, size_t); -void *ibuf_seek(struct ibuf *, size_t, size_t); -size_t ibuf_size(struct ibuf *); -size_t ibuf_left(struct ibuf *); -void ibuf_close(struct msgbuf *, struct ibuf *); -int ibuf_write(struct msgbuf *); -void ibuf_free(struct ibuf *); -void msgbuf_init(struct msgbuf *); -void msgbuf_clear(struct msgbuf *); -int msgbuf_write(struct msgbuf *); -void msgbuf_drain(struct msgbuf *, size_t); - -/* imsg.c */ -void imsg_init(struct imsgbuf *, int); -ssize_t imsg_read(struct imsgbuf *); -ssize_t imsg_get(struct imsgbuf *, struct imsg *); -int imsg_compose(struct imsgbuf *, u_int32_t, u_int32_t, pid_t, - int, void *, u_int16_t); -int imsg_composev(struct imsgbuf *, u_int32_t, u_int32_t, pid_t, - int, const struct iovec *, int); -struct ibuf *imsg_create(struct imsgbuf *, u_int32_t, u_int32_t, pid_t, - u_int16_t); -int imsg_add(struct ibuf *, void *, u_int16_t); -void imsg_close(struct imsgbuf *, struct ibuf *); -void imsg_free(struct imsg *); -int imsg_flush(struct imsgbuf *); -void imsg_clear(struct imsgbuf *); diff --git a/tmux.h b/tmux.h index ce9c2677..961019d8 100644 --- a/tmux.h +++ b/tmux.h @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -38,7 +39,6 @@ #include #include "array.h" -#include "imsg.h" extern char *__progname; extern char **environ; From 7b7397241f5c093611a925ffc062d944df3a3c82 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 30 May 2010 19:09:50 +0000 Subject: [PATCH 0708/1180] There is no real reason not to list all the key bindings here rather than just a selection. --- tmux.1 | 102 +++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 89 insertions(+), 13 deletions(-) diff --git a/tmux.1 b/tmux.1 index 8d123b25..49de2029 100644 --- a/tmux.1 +++ b/tmux.1 @@ -213,32 +213,108 @@ prefix key, .Ql C-b (Ctrl-b) by default, followed by a command key. .Pp -Some of the default key bindings are: +The default key bindings are: .Pp -.Bl -tag -width Ds -offset indent -compact +.Bl -tag -width "XXXXXXXXXX" -offset indent -compact +.It C-b +Send the prefix key (C-b) through to the application. +.It C-o +Rotate the panes in the current window forwards. +.It C-z +Suspend the +.Nm +client. +.It ! +Break the current pane out of the window. +.It \&" +Split the current pane into two, top and bottom. +.It # +List all paste buffers. +.It % +Split the current pane into two, left and right. +.It & +Kill the current window. +.It ' +Prompt for a window index to select. +.It , +Rename the current window. +.It - +Delete the most recently copied buffer of text. +.It . +Prompt for an index to move the current window. +.It 0 to 9 +Select windows 0 to 9. +.It : +Enter the +.Nm +command prompt. +.It \&? +List all key bindings. +.It D +Choose a client to detach. +.It [ +Enter copy mode to copy text or view the history. +.It ] +Paste the most recently copied buffer of text. .It c Create a new window. .It d Detach the current client. +.It f +Prompt to search for text in open windows. +.It i +Display some information about the current window. .It l Move to the previously selected window. .It n Change to the next window. +.It o +Select the next pane in the current window. .It p Change to the previous window. -.It & -Kill the current window. -.It , -Rename the current window. -.It \&? -List all key bindings. +.It q +Briefly display pane indexes. +.It r +Force redraw of the attached client. +.It s +Select a new session for the attached client interactively. +.It t +Show the time. +.It w +Choose the current window interactively. +.It x +Kill the current pane. +.It { +Swap the current pane with the previous pane. +.It } +Swap the current pane with the next pane. +.It ~ +Show previous messages from +.Nm , +if any. +.It Page Up +Enter copy mode and scroll one page up. +.It Up, Down +.It Left, Right +Change to the pane above, below, to the left, or to the right of the current +pane. +.It M-1 to M-5 +Arrange panes in one of the five preset layouts: even-horizontal, +even-vertical, main-horizontal, main-vertical, or tiled. +.It M-n +Move to the next window with a bell or activity marker. +.It M-o +Rotate the panes in the current window backwards. +.It M-p +Move to the previous window with a bell or activity marker. +.It C-Up, C-Down +.It C-Left, C-Right +Resize the current pane in steps of one cell. +.It M-Up, M-Down +.It M-Left, M-Right +Resize the current pane in steps of five cells. .El .Pp -A complete list may be obtained with the -.Ic list-keys -command (bound to -.Ql \&? -by default). Key bindings may be changed with the .Ic bind-key and From e1e120de1c4fc5f37940ba3a6567acc914f1692c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 30 May 2010 19:19:42 +0000 Subject: [PATCH 0709/1180] Better to say "command key bindings" since we've just called them command keys. --- tmux.1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tmux.1 b/tmux.1 index 49de2029..9b565dd1 100644 --- a/tmux.1 +++ b/tmux.1 @@ -213,7 +213,7 @@ prefix key, .Ql C-b (Ctrl-b) by default, followed by a command key. .Pp -The default key bindings are: +The default command key bindings are: .Pp .Bl -tag -width "XXXXXXXXXX" -offset indent -compact .It C-b From 43fa9a9ba60f0fba1f5c7985ed9c65cea304d2c4 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 31 May 2010 19:51:29 +0000 Subject: [PATCH 0710/1180] When the mode-mouse option is on, support dragging to make a selection in copy mode. Also support the scroll wheel, although xterm strangely does not ignore it in application mouse mode, causing redraw artifacts when scrolling up (other terminals appear to be better behaved). --- tmux.1 | 6 ++---- tmux.h | 5 +++-- tty-keys.c | 3 ++- tty.c | 17 ++++++++++++----- window-copy.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++---- 5 files changed, 67 insertions(+), 16 deletions(-) diff --git a/tmux.1 b/tmux.1 index 9b565dd1..94e60758 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2078,10 +2078,8 @@ Key bindings default to emacs. .Op Ic on | off .Xc Mouse state in modes. -If on, -.Nm -will respond to mouse clicks by moving the cursor in copy mode or selecting an -option in choice mode. +If on, the mouse may be used to copy a selection by dragging in copy mode, or +to select an option in choice mode. .Pp .It Xo Ic monitor-activity .Op Ic on | off diff --git a/tmux.h b/tmux.h index 961019d8..3069f89b 100644 --- a/tmux.h +++ b/tmux.h @@ -541,7 +541,8 @@ struct mode_key_table { #define MODE_KCURSOR 0x4 #define MODE_KKEYPAD 0x8 /* set = application, clear = number */ #define MODE_MOUSE 0x10 -#define MODE_WRAP 0x20 /* whether lines wrap */ +#define MODE_MOUSEMOTION 0x20 +#define MODE_WRAP 0x40 /* whether lines wrap */ /* * A single UTF-8 character. @@ -1086,7 +1087,7 @@ struct client { #define CLIENT_TERMINAL 0x1 #define CLIENT_PREFIX 0x2 -#define CLIENT_MOUSE 0x4 +/* 0x4 unused */ #define CLIENT_REDRAW 0x8 #define CLIENT_STATUS 0x10 #define CLIENT_REPEAT 0x20 /* allow command to repeat within repeat time */ diff --git a/tty-keys.c b/tty-keys.c index 27107bb8..59002fb2 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -612,7 +612,8 @@ tty_keys_mouse(const char *buf, size_t len, size_t *size, struct mouse_event *m) return (1); *size = 6; - log_debug("mouse input is: %.6s", buf); + log_debug( + "mouse input: %.6s (%hhu,%hhu/%hhu)", buf, buf[4], buf[5], buf[3]); m->b = buf[3]; m->x = buf[4]; diff --git a/tty.c b/tty.c index 72be2c84..92ddf41f 100644 --- a/tty.c +++ b/tty.c @@ -402,11 +402,18 @@ tty_update_mode(struct tty *tty, int mode) else tty_putcode(tty, TTYC_CIVIS); } - if (changed & MODE_MOUSE) { - if (mode & MODE_MOUSE) - tty_puts(tty, "\033[?1000h"); - else - tty_puts(tty, "\033[?1000l"); + if (changed & (MODE_MOUSE|MODE_MOUSEMOTION)) { + if (mode & MODE_MOUSE) { + if (mode & MODE_MOUSEMOTION) + tty_puts(tty, "\033[?1003h"); + else + tty_puts(tty, "\033[?1000h"); + } else { + if (mode & MODE_MOUSEMOTION) + tty_puts(tty, "\033[?1003l"); + else + tty_puts(tty, "\033[?1000l"); + } } if (changed & MODE_KKEYPAD) { if (mode & MODE_KKEYPAD) diff --git a/window-copy.c b/window-copy.c index 3b42c456..66402eca 100644 --- a/window-copy.c +++ b/window-copy.c @@ -760,17 +760,61 @@ window_copy_mouse( { struct window_copy_mode_data *data = wp->modedata; struct screen *s = &data->screen; + u_int i; + + /* + * xterm mouse mode is fairly silly. Buttons are in the bottom two + * bits: 0 button 1; 1 button 2; 2 button 3; 3 buttons released. + * + * Bit 3 is shift; bit 4 is meta; bit 5 control. + * + * Bit 6 is added for mouse buttons 4 and 5. + */ - if ((m->b & 3) == 3) - return; if (m->x >= screen_size_x(s)) return; if (m->y >= screen_size_y(s)) return; - window_copy_update_cursor(wp, m->x, m->y); - if (window_copy_update_selection(wp)) + /* If mouse wheel (buttons 4 and 5), scroll. */ + if ((m->b & 64) == 64) { + if ((m->b & 3) == 0) { + for (i = 0; i < 5; i++) + window_copy_cursor_up(wp, 0); + } else if ((m->b & 3) == 1) { + for (i = 0; i < 5; i++) + window_copy_cursor_down(wp, 0); + } + return; + } + + /* + * If already reading motion, move the cursor while buttons are still + * pressed, or stop the selection on their release. + */ + if (s->mode & MODE_MOUSEMOTION) { + if ((m->b & 3) != 3) { + window_copy_update_cursor(wp, m->x, m->y); + if (window_copy_update_selection(wp)) + window_copy_redraw_screen(wp); + } else { + s->mode &= ~MODE_MOUSEMOTION; + if (sess != NULL) { + window_copy_copy_selection(wp, sess); + window_pane_reset_mode(wp); + } + } + return; + } + + /* Otherwise i other buttons pressed, start selection and motion. */ + if ((m->b & 3) != 3) { + s->mode |= MODE_MOUSEMOTION; + + window_copy_update_cursor(wp, m->x, m->y); + window_copy_start_selection(wp); window_copy_redraw_screen(wp); + } } void From cc724f327a14c607927c8ef27c4b72311a301271 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 5 Jun 2010 15:49:48 +0000 Subject: [PATCH 0711/1180] Make start-of-line work the same as end-of-line on wrapped lines (jump to real start if at edge of screen). By Micah Cowan. --- window-copy.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/window-copy.c b/window-copy.c index 66402eca..efee25d0 100644 --- a/window-copy.c +++ b/window-copy.c @@ -1427,7 +1427,17 @@ void window_copy_cursor_start_of_line(struct window_pane *wp) { struct window_copy_mode_data *data = wp->modedata; + struct screen *back_s = data->backing; + struct grid *gd = back_s->grid; + u_int py; + if (data->cx == 0) { + py = screen_hsize(back_s) + data->cy - data->oy; + while (py > 0 && gd->linedata[py-1].flags & GRID_LINE_WRAPPED) { + window_copy_cursor_up(wp, 0); + py = screen_hsize(back_s) + data->cy - data->oy; + } + } window_copy_update_cursor(wp, 0, data->cy); if (window_copy_update_selection(wp)) window_copy_redraw_lines(wp, data->cy, 1); From b88ec14f0ee93e5134e33034ac93b2229bcc8beb Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 5 Jun 2010 15:51:53 +0000 Subject: [PATCH 0712/1180] Fix binding of C-Space/C-@, from Micah Cowan. --- key-string.c | 41 ++++++++++++++++++++--------------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/key-string.c b/key-string.c index 65d669bf..62717b2f 100644 --- a/key-string.c +++ b/key-string.c @@ -149,29 +149,28 @@ key_string_lookup_string(const char *string) key = (u_char) string[0]; if (key < 32 || key > 126) return (KEYC_NONE); - - /* Convert the standard control keys. */ - if (modifiers & KEYC_CTRL) { - if (key >= 97 && key <= 122) - key -= 96; - else if (key >= 64 && key <= 95) - key -= 64; - else if (key == 32) - key = 0; - else if (key == 63) - key = KEYC_BSPACE; - else - return (KEYC_NONE); - modifiers &= ~KEYC_CTRL; - } - - return (key | modifiers); + } else { + /* Otherwise look the key up in the table. */ + key = key_string_search_table(string); + if (key == KEYC_NONE) + return (KEYC_NONE); + } + + /* Convert the standard control keys. */ + if (key < KEYC_BASE && (modifiers & KEYC_CTRL)) { + if (key >= 97 && key <= 122) + key -= 96; + else if (key >= 64 && key <= 95) + key -= 64; + else if (key == 32) + key = 0; + else if (key == 63) + key = KEYC_BSPACE; + else + return (KEYC_NONE); + modifiers &= ~KEYC_CTRL; } - /* Otherwise look the key up in the table. */ - key = key_string_search_table(string); - if (key == KEYC_NONE) - return (KEYC_NONE); return (key | modifiers); } From 36c0871c2380165fc018ec085f8c8352deffa6f3 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 5 Jun 2010 16:29:45 +0000 Subject: [PATCH 0713/1180] This ioctl(TIOCGWINSZ) call is no longer necessary, the result is never used and the server now does it later on the tty fd directly. --- client.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/client.c b/client.c index 092ae555..326ca100 100644 --- a/client.c +++ b/client.c @@ -17,7 +17,6 @@ */ #include -#include #include #include #include @@ -115,12 +114,9 @@ void client_send_identify(int flags) { struct msg_identify_data data; - struct winsize ws; char *term; int fd; - if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1) - fatal("ioctl(TIOCGWINSZ)"); data.flags = flags; if (getcwd(data.cwd, sizeof data.cwd) == NULL) From 0440d325d9dcef2170f2b7695d06d0ba10e9875d Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 5 Jun 2010 16:32:22 +0000 Subject: [PATCH 0714/1180] Shut up gcc4 warnings. --- array.h | 2 +- tty.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/array.h b/array.h index 543c3dfe..59ac356f 100644 --- a/array.h +++ b/array.h @@ -47,7 +47,7 @@ } \ } while (0) -#define ARRAY_EMPTY(a) ((a) == NULL || (a)->num == 0) +#define ARRAY_EMPTY(a) (((void *) (a)) == NULL || (a)->num == 0) #define ARRAY_LENGTH(a) ((a)->num) #define ARRAY_DATA(a) ((a)->list) diff --git a/tty.c b/tty.c index 92ddf41f..4fe946af 100644 --- a/tty.c +++ b/tty.c @@ -1090,7 +1090,7 @@ tty_cursor(struct tty *tty, u_int cx, u_int cy) * Use HPA if change is larger than absolute, otherwise move * the cursor with CUB/CUF. */ - if (abs(change) > cx && tty_term_has(term, TTYC_HPA)) { + if ((u_int) abs(change) > cx && tty_term_has(term, TTYC_HPA)) { tty_putcode1(tty, TTYC_HPA, cx); goto out; } else if (change > 0 && tty_term_has(term, TTYC_CUB)) { @@ -1126,7 +1126,7 @@ tty_cursor(struct tty *tty, u_int cx, u_int cy) * Try to use VPA if change is larger than absolute or if this * change would cross the scroll region, otherwise use CUU/CUD. */ - if (abs(change) > cy || + if ((u_int) abs(change) > cy || (change < 0 && cy - change > tty->rlower) || (change > 0 && cy - change < tty->rupper)) { if (tty_term_has(term, TTYC_VPA)) { From ceed5cc9a936840a4e40718e0e30f44e71534c5a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 5 Jun 2010 16:34:30 +0000 Subject: [PATCH 0715/1180] Support the status_replace # replacement sequences in the pipe-pane command, thanks to Andrea Barisani. --- cmd-pipe-pane.c | 9 ++++++++- tmux.1 | 7 ++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/cmd-pipe-pane.c b/cmd-pipe-pane.c index 0d7c3ff6..72903a3d 100644 --- a/cmd-pipe-pane.c +++ b/cmd-pipe-pane.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include "tmux.h" @@ -50,9 +51,14 @@ int cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx) { struct cmd_target_data *data = self->data; + struct client *c; struct window_pane *wp; + char *command; int old_fd, pipe_fd[2], null_fd, mode; + if ((c = cmd_find_client(ctx, data->target)) == NULL) + return (-1); + if (cmd_find_pane(ctx, data->target, NULL, &wp) == NULL) return (-1); @@ -106,7 +112,8 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx) if (null_fd != STDOUT_FILENO && null_fd != STDERR_FILENO) close(null_fd); - execl(_PATH_BSHELL, "sh", "-c", data->arg, (char *) NULL); + command = status_replace(c, NULL, data->arg, time(NULL), 0); + execl(_PATH_BSHELL, "sh", "-c", command, (char *) NULL); _exit(1); default: /* Parent process. */ diff --git a/tmux.1 b/tmux.1 index 94e60758..43ea6e06 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1124,6 +1124,11 @@ A pane may only be piped to one command at a time, any existing pipe is closed before .Ar shell-command is executed. +The +.Ar shell-command +string may contain the special character sequences supported by the +.Ic status-left +command. If no .Ar shell-command is given, the current pipe (if any) is closed. @@ -1133,7 +1138,7 @@ The option only opens a new pipe if no previous pipe exists, allowing a pipe to be toggled with a single key, for example: .Bd -literal -offset indent -bind-key C-p pipe-pane -o 'cat >>~/output' +bind-key C-p pipe-pane -o 'cat >>~/output.#I-#P' .Ed .It Xo Ic previous-window .Op Fl a From 510ec3fb9e14d5d611d13650f935c945025b12c9 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 5 Jun 2010 16:47:11 +0000 Subject: [PATCH 0716/1180] Fix problems with window sizing seen by Raghavendra D Prabhu when starting tmux from .xinitrc. One of the very few things the server relies on the client for now is to pass through a message on SIGWINCH, but there is a condition where potentially a SIGWINCH may be lost during the transition from unattached (main.c) to attached (client.c). So trigger a size change immediately after the client installs its SIGWINCH handler. Also, when the terminal is resized, reset the scroll region and cursor position. Previously, we were clearing our saved idea of these, but in fact some terminals do not reset them on resize, so this caused problems during redraw. While here make a resize to the same size not cause a redraw and rename the tmux.out output log file to include the tmux PID. --- client.c | 7 +++++++ server-client.c | 7 ++++--- tmux.h | 2 +- tty.c | 37 +++++++++++++++++++++++++++++-------- 4 files changed, 41 insertions(+), 12 deletions(-) diff --git a/client.c b/client.c index 326ca100..35cf2801 100644 --- a/client.c +++ b/client.c @@ -175,6 +175,13 @@ client_main(void) /* Set up signals. */ set_signals(client_signal); + /* + * Send a resize message immediately in case the terminal size has + * changed between the identify message to the server and the MSG_READY + * telling us to move into the client code. + */ + client_write_server(MSG_RESIZE, NULL, 0); + /* * imsg_read in the first client poll loop (before the terminal has * been initialised) may have read messages into the buffer after the diff --git a/server-client.c b/server-client.c index 9d550386..301c986a 100644 --- a/server-client.c +++ b/server-client.c @@ -561,9 +561,10 @@ server_client_msg_dispatch(struct client *c) if (datalen != 0) fatalx("bad MSG_RESIZE size"); - tty_resize(&c->tty); - recalculate_sizes(); - server_redraw_client(c); + if (tty_resize(&c->tty)) { + recalculate_sizes(); + server_redraw_client(c); + } break; case MSG_EXITING: if (datalen != 0) diff --git a/tmux.h b/tmux.h index 3069f89b..a9e41351 100644 --- a/tmux.h +++ b/tmux.h @@ -1351,7 +1351,7 @@ void tty_puts(struct tty *, const char *); void tty_putc(struct tty *, u_char); void tty_pututf8(struct tty *, const struct grid_utf8 *); void tty_init(struct tty *, int, char *); -void tty_resize(struct tty *); +int tty_resize(struct tty *); void tty_start_tty(struct tty *); void tty_stop_tty(struct tty *); void tty_set_title(struct tty *, const char *); diff --git a/tty.c b/tty.c index 4fe946af..fa2cd552 100644 --- a/tty.c +++ b/tty.c @@ -73,34 +73,55 @@ tty_init(struct tty *tty, int fd, char *term) tty->term_flags = 0; } -void +int tty_resize(struct tty *tty) { struct winsize ws; + u_int sx, sy; if (ioctl(tty->fd, TIOCGWINSZ, &ws) != -1) { - tty->sx = ws.ws_col; - tty->sy = ws.ws_row; + sx = ws.ws_col; + if (sx == 0) + sx = 80; + sy = ws.ws_row; + if (sy == 0) + sy = 24; + } else { + sx = 80; + sy = 24; } - if (tty->sx == 0) - tty->sx = 80; - if (tty->sy == 0) - tty->sy = 24; + if (sx == tty->sx && sy == tty->sy) + return (0); + tty->sx = sx; + tty->sy = sy; tty->cx = UINT_MAX; tty->cy = UINT_MAX; tty->rupper = UINT_MAX; tty->rlower = UINT_MAX; + + /* + * If the terminal has been started, reset the actual scroll region and + * cursor position, as this may not have happened. + */ + if (tty->flags & TTY_STARTED) { + tty_cursor(tty, 0, 0); + tty_region(tty, 0, tty->sy - 1); + } + + return (1); } int tty_open(struct tty *tty, const char *overrides, char **cause) { + char out[64]; int fd; if (debug_level > 3) { - fd = open("tmux.out", O_WRONLY|O_CREAT|O_TRUNC, 0644); + xsnprintf(out, sizeof out, "tmux-out-%ld.log", (long) getpid()); + fd = open(out, O_WRONLY|O_CREAT|O_TRUNC, 0644); if (fd != -1 && fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) fatal("fcntl failed"); tty->log_fd = fd; From 4e3bed20351e0b2293d1445d829795578321e069 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 5 Jun 2010 16:54:24 +0000 Subject: [PATCH 0717/1180] Couple of missing command aliases/flags, from Tiago Cunha. --- tmux.1 | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/tmux.1 b/tmux.1 index 43ea6e06..e3265091 100644 --- a/tmux.1 +++ b/tmux.1 @@ -554,17 +554,15 @@ List the syntax of all commands supported by .It Ic list-sessions .D1 (alias: Ic ls ) List all sessions managed by the server. -.It Xo Ic lock-client -.Op Fl t Ar target-client -.Xc +.It Ic lock-client Op Fl t Ar target-client +.D1 (alias: Ic lockc ) Lock .Ar target-client , see the .Ic lock-server command. -.It Xo Ic lock-session -.Op Fl t Ar target-session -.Xc +.It Ic lock-session Op Fl t Ar target-session +.D1 (alias: Ic locks ) Lock all clients attached to .Ar target-session . .It Xo Ic new-session @@ -1039,7 +1037,7 @@ List the panes in the current window or in List windows in the current session or in .Ar target-session . .It Xo Ic move-window -.Op Fl d +.Op Fl dk .Op Fl s Ar src-window .Op Fl t Ar dst-window .Xc From dcc100f165d2d710174db61e54d97610843578fb Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 6 Jun 2010 19:00:13 +0000 Subject: [PATCH 0718/1180] Use a macro-based mask for obtaining a key or modifier-set from the combination. Display C-@, etc, as C-Space, in list-keys. By Micah Cowan. --- key-string.c | 11 ++++++++++- tmux.h | 4 ++++ window-copy.c | 6 +++--- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/key-string.c b/key-string.c index 62717b2f..20240407 100644 --- a/key-string.c +++ b/key-string.c @@ -184,6 +184,15 @@ key_string_lookup_key(int key) *out = '\0'; + /* + * Special case: display C-@ as C-Space. Could do this below in + * the (key >= 0 && key <= 32), but this way we let it be found + * in key_string_table, for the unlikely chance that we might + * change its name. + */ + if ((key & KEYC_MASK_KEY) == 0) + key = ' ' | KEYC_CTRL | (key & KEYC_MASK_MOD); + /* Fill in the modifiers. */ if (key & KEYC_CTRL) strlcat(out, "C-", sizeof out); @@ -191,7 +200,7 @@ key_string_lookup_key(int key) strlcat(out, "M-", sizeof out); if (key & KEYC_SHIFT) strlcat(out, "S-", sizeof out); - key &= ~(KEYC_CTRL|KEYC_ESCAPE|KEYC_SHIFT); + key &= KEYC_MASK_KEY; /* Try the key against the string table. */ for (i = 0; i < nitems(key_string_table); i++) { diff --git a/tmux.h b/tmux.h index a9e41351..c090aedd 100644 --- a/tmux.h +++ b/tmux.h @@ -111,6 +111,10 @@ extern char **environ; #define KEYC_SHIFT 0x8000 #define KEYC_PREFIX 0x10000 +/* Mask to obtain key w/o modifiers */ +#define KEYC_MASK_MOD (KEYC_ESCAPE|KEYC_CTRL|KEYC_SHIFT|KEYC_PREFIX) +#define KEYC_MASK_KEY (~KEYC_MASK_MOD) + /* Other key codes. */ enum key_code { /* Mouse key. */ diff --git a/window-copy.c b/window-copy.c index efee25d0..cd94f67f 100644 --- a/window-copy.c +++ b/window-copy.c @@ -367,7 +367,7 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key) if (data->inputtype == WINDOW_COPY_JUMPFORWARD || data->inputtype == WINDOW_COPY_JUMPBACK) { /* Ignore keys with modifiers. */ - if ((key & 0xff00) == 0) { + if ((key & KEYC_MASK_MOD) == 0) { data->jumpchar = key; if (data->inputtype == WINDOW_COPY_JUMPFORWARD) { for (; np != 0; np--) @@ -627,7 +627,7 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key) *data->inputstr = '\0'; goto input_on; case MODEKEYCOPY_STARTNUMBERPREFIX: - key &= 0xff; + key &= KEYC_MASK_KEY; if (key >= '0' && key <= '9') { data->inputtype = WINDOW_COPY_NUMERICPREFIX; data->numprefix = 0; @@ -741,7 +741,7 @@ window_copy_key_numeric_prefix(struct window_pane *wp, int key) struct window_copy_mode_data *data = wp->modedata; struct screen *s = &data->screen; - key &= 0xff; + key &= KEYC_MASK_KEY; if (key < '0' || key > '9') return 1; From 1484eb8a5192cc5c2f9da543949c3d1e2e0a58a7 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 14 Jun 2010 23:04:44 +0000 Subject: [PATCH 0719/1180] Add a missing command and some missing Ic, from Tiago Cunha. --- tmux.1 | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tmux.1 b/tmux.1 index e3265091..c7c88ddf 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1138,6 +1138,11 @@ be toggled with a single key, for example: .Bd -literal -offset indent bind-key C-p pipe-pane -o 'cat >>~/output.#I-#P' .Ed +.It Xo Ic previous-layout +.Op Fl t Ar target-window +.Xc +.D1 (alias: Ic prevl ) +Move to the previous layout in the session. .It Xo Ic previous-window .Op Fl a .Op Fl t Ar target-session @@ -1201,7 +1206,7 @@ or downward (numerically higher). .Op Fl t Ar target-window .Op Ar layout-name .Xc -.D1 (alias: selectl ) +.D1 (alias: Ic selectl ) Choose a specific layout for a window. If .Ar layout-name @@ -1235,7 +1240,7 @@ Select the window at .Op Fl t Ar target-pane .Op Ar shell-command .Xc -.D1 (alias: splitw ) +.D1 (alias: Ic splitw ) Create a new pane by splitting .Ar target-pane : .Fl h From 278d9bc721d4149662f69da9e43cf2b0497536d4 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 14 Jun 2010 23:06:13 +0000 Subject: [PATCH 0720/1180] Last change erroneously used the target argument for looking up the client which caused pipe-pane to fail when used from the command line. Instead pass NULL which should use the current client. Spotted by Tiago Cunha. --- cmd-pipe-pane.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd-pipe-pane.c b/cmd-pipe-pane.c index 72903a3d..edc624dd 100644 --- a/cmd-pipe-pane.c +++ b/cmd-pipe-pane.c @@ -56,7 +56,7 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx) char *command; int old_fd, pipe_fd[2], null_fd, mode; - if ((c = cmd_find_client(ctx, data->target)) == NULL) + if ((c = cmd_find_client(ctx, NULL)) == NULL) return (-1); if (cmd_find_pane(ctx, data->target, NULL, &wp) == NULL) From 5afb820d233e2f093633e91a2fe88e07514b628f Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 21 Jun 2010 00:11:12 +0000 Subject: [PATCH 0721/1180] Ensure we overwrite UTF-8 wide characters properly, and never overwrite characters we weren't overlapping. Fixes "disappearing wide characters" glitch. From Micah Cowan. --- screen-write.c | 42 ++++++++++++++---------------------------- 1 file changed, 14 insertions(+), 28 deletions(-) diff --git a/screen-write.c b/screen-write.c index 083544c4..882fced4 100644 --- a/screen-write.c +++ b/screen-write.c @@ -23,7 +23,7 @@ #include "tmux.h" void screen_write_initctx(struct screen_write_ctx *, struct tty_ctx *, int); -void screen_write_overwrite(struct screen_write_ctx *); +void screen_write_overwrite(struct screen_write_ctx *, u_int); int screen_write_combine( struct screen_write_ctx *, const struct utf8_data *); @@ -1020,7 +1020,7 @@ screen_write_cell(struct screen_write_ctx *ctx, return; /* Handle overwriting of UTF-8 characters. */ - screen_write_overwrite(ctx); + screen_write_overwrite(ctx, width); /* * If the new character is UTF-8 wide, fill in padding cells. Have @@ -1123,12 +1123,11 @@ screen_write_combine( * by the same character. */ void -screen_write_overwrite(struct screen_write_ctx *ctx) +screen_write_overwrite(struct screen_write_ctx *ctx, u_int width) { struct screen *s = ctx->s; struct grid *gd = s->grid; const struct grid_cell *gc; - const struct grid_utf8 *gu; u_int xx; gc = grid_view_peek_cell(gd, s->cx, s->cy); @@ -1148,30 +1147,17 @@ screen_write_overwrite(struct screen_write_ctx *ctx) /* Overwrite the character at the start of this padding. */ grid_view_set_cell(gd, xx, s->cy, &grid_default_cell); + } - /* Overwrite following padding cells. */ - xx = s->cx; - while (++xx < screen_size_x(s)) { - gc = grid_view_peek_cell(gd, xx, s->cy); - if (!(gc->flags & GRID_FLAG_PADDING)) - break; - grid_view_set_cell(gd, xx, s->cy, &grid_default_cell); - } - } else if (gc->flags & GRID_FLAG_UTF8) { - gu = grid_view_peek_utf8(gd, s->cx, s->cy); - if (gu->width > 1) { - /* - * An UTF-8 wide cell; overwrite following padding - * cells only. - */ - xx = s->cx; - while (++xx < screen_size_x(s)) { - gc = grid_view_peek_cell(gd, xx, s->cy); - if (!(gc->flags & GRID_FLAG_PADDING)) - break; - grid_view_set_cell( - gd, xx, s->cy, &grid_default_cell); - } - } + /* + * Overwrite any padding cells that belong to a UTF-8 character + * we'll be overwriting with the current character. + */ + xx = s->cx + width - 1; + while (++xx < screen_size_x(s)) { + gc = grid_view_peek_cell(gd, xx, s->cy); + if (!(gc->flags & GRID_FLAG_PADDING)) + break; + grid_view_set_cell(gd, xx, s->cy, &grid_default_cell); } } From ad466a69aac179b41d624d1c097242101a699293 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 21 Jun 2010 00:18:57 +0000 Subject: [PATCH 0722/1180] Give tmux sockets (but not the containing folder) group permissions. This allows hardlinks to the sockets to be used more easily. --- server.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/server.c b/server.c index fa5b8919..0a4e2306 100644 --- a/server.c +++ b/server.c @@ -86,7 +86,7 @@ server_create_socket(void) if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) fatal("socket failed"); - mask = umask(S_IXUSR|S_IRWXG|S_IRWXO); + mask = umask(S_IXUSR|S_IXGRP|S_IRWXO); if (bind(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1) fatal("bind failed"); umask(mask); @@ -310,9 +310,9 @@ server_update_socket(void) if (n != last) { last = n; if (n != 0) - chmod(socket_path, S_IRWXU); + chmod(socket_path, S_IRWXU|S_IRWXG); else - chmod(socket_path, S_IRUSR|S_IWUSR); + chmod(socket_path, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP); } } From 447a07e9f83297bf0ad5f973e67eb32488fc1b8d Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 21 Jun 2010 00:25:32 +0000 Subject: [PATCH 0723/1180] Rename activity->alert in a couple of functions for consistency. --- session.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/session.c b/session.c index 20656957..2957c1fc 100644 --- a/session.c +++ b/session.c @@ -32,8 +32,8 @@ struct sessions sessions; struct sessions dead_sessions; struct session_groups session_groups; -struct winlink *session_next_activity(struct session *, struct winlink *); -struct winlink *session_previous_activity(struct session *, struct winlink *); +struct winlink *session_next_alert(struct session *, struct winlink *); +struct winlink *session_previous_alert(struct session *, struct winlink *); void session_alert_cancel(struct session *s, struct winlink *wl) @@ -310,7 +310,7 @@ session_has(struct session *s, struct window *w) } struct winlink * -session_next_activity(struct session *s, struct winlink *wl) +session_next_alert(struct session *s, struct winlink *wl) { while (wl != NULL) { if (session_alert_has(s, wl, WINDOW_BELL)) @@ -326,7 +326,7 @@ session_next_activity(struct session *s, struct winlink *wl) /* Move session to next window. */ int -session_next(struct session *s, int activity) +session_next(struct session *s, int alert) { struct winlink *wl; @@ -334,11 +334,11 @@ session_next(struct session *s, int activity) return (-1); wl = winlink_next(s->curw); - if (activity) - wl = session_next_activity(s, wl); + if (alert) + wl = session_next_alert(s, wl); if (wl == NULL) { wl = RB_MIN(winlinks, &s->windows); - if (activity && ((wl = session_next_activity(s, wl)) == NULL)) + if (alert && ((wl = session_next_alert(s, wl)) == NULL)) return (-1); } if (wl == s->curw) @@ -351,7 +351,7 @@ session_next(struct session *s, int activity) } struct winlink * -session_previous_activity(struct session *s, struct winlink *wl) +session_previous_alert(struct session *s, struct winlink *wl) { while (wl != NULL) { if (session_alert_has(s, wl, WINDOW_BELL)) @@ -367,7 +367,7 @@ session_previous_activity(struct session *s, struct winlink *wl) /* Move session to previous window. */ int -session_previous(struct session *s, int activity) +session_previous(struct session *s, int alert) { struct winlink *wl; @@ -375,11 +375,11 @@ session_previous(struct session *s, int activity) return (-1); wl = winlink_previous(s->curw); - if (activity) - wl = session_previous_activity(s, wl); + if (alert) + wl = session_previous_alert(s, wl); if (wl == NULL) { wl = RB_MAX(winlinks, &s->windows); - if (activity && (wl = session_previous_activity(s, wl)) == NULL) + if (alert && (wl = session_previous_alert(s, wl)) == NULL) return (-1); } if (wl == s->curw) From e63f0546a166c442464c7d8500a74b38c036432a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 21 Jun 2010 01:27:46 +0000 Subject: [PATCH 0724/1180] Having a list of winlinks->alerts for each session is stupid, just store the alert flags directly in the winlink itself. --- cmd-choose-window.c | 6 +-- cmd-new-window.c | 2 +- resize.c | 2 +- server-fn.c | 6 +-- server-window.c | 61 +++++++++++---------- session.c | 125 ++++++++------------------------------------ status.c | 32 ++++-------- tmux.h | 24 +++------ 8 files changed, 78 insertions(+), 180 deletions(-) diff --git a/cmd-choose-window.c b/cmd-choose-window.c index f8318105..e341dd41 100644 --- a/cmd-choose-window.c +++ b/cmd-choose-window.c @@ -81,11 +81,11 @@ cmd_choose_window_exec(struct cmd *self, struct cmd_ctx *ctx) idx++; flag = ' '; - if (session_alert_has(s, wm, WINDOW_ACTIVITY)) + if (wm->flags & WINLINK_ACTIVITY) flag = '#'; - else if (session_alert_has(s, wm, WINDOW_BELL)) + else if (wm->flags & WINLINK_BELL) flag = '!'; - else if (session_alert_has(s, wm, WINDOW_CONTENT)) + else if (wm->flags & WINLINK_CONTENT) flag = '+'; else if (wm == s->curw) flag = '*'; diff --git a/cmd-new-window.c b/cmd-new-window.c index cf32f29e..32c42eb4 100644 --- a/cmd-new-window.c +++ b/cmd-new-window.c @@ -162,7 +162,7 @@ cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx) * Can't use session_detach as it will destroy session if this * makes it empty. */ - session_alert_cancel(s, wl); + wl->flags &= ~WINLINK_ALERTFLAGS; winlink_stack_remove(&s->lastw, wl); winlink_remove(&s->windows, wl); diff --git a/resize.c b/resize.c index 5635f9d4..15f99e7c 100644 --- a/resize.c +++ b/resize.c @@ -105,7 +105,7 @@ recalculate_sizes(void) if (flag) has = s->curw->window == w; else - has = session_has(s, w); + has = session_has(s, w) != NULL; if (has) { if (s->sx < ssx) ssx = s->sx; diff --git a/server-fn.c b/server-fn.c index 01e78ba2..da156e46 100644 --- a/server-fn.c +++ b/server-fn.c @@ -184,7 +184,7 @@ server_status_window(struct window *w) for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { s = ARRAY_ITEM(&sessions, i); - if (s != NULL && session_has(s, w)) + if (s != NULL && session_has(s, w) != NULL) server_status_session(s); } } @@ -249,7 +249,7 @@ server_kill_window(struct window *w) for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { s = ARRAY_ITEM(&sessions, i); - if (s == NULL || !session_has(s, w)) + if (s == NULL || session_has(s, w) == NULL) continue; while ((wl = winlink_find_by_window(&s->windows, w)) != NULL) { if (session_detach(s, wl)) { @@ -286,7 +286,7 @@ server_link_window(struct session *src, struct winlink *srcwl, * Can't use session_detach as it will destroy session * if this makes it empty. */ - session_alert_cancel(dst, dstwl); + dstwl->flags &= ~WINLINK_ALERTFLAGS; winlink_stack_remove(&dst->lastw, dstwl); winlink_remove(&dst->windows, dstwl); diff --git a/server-window.c b/server-window.c index acac83c0..42a4a699 100644 --- a/server-window.c +++ b/server-window.c @@ -24,10 +24,10 @@ #include "tmux.h" int server_window_backoff(struct window_pane *); -int server_window_check_bell(struct session *, struct window *); -int server_window_check_activity(struct session *, struct window *); +int server_window_check_bell(struct session *, struct winlink *); +int server_window_check_activity(struct session *, struct winlink *); int server_window_check_content( - struct session *, struct window *, struct window_pane *); + struct session *, struct winlink *, struct window_pane *); /* Check if this window should suspend reading. */ int @@ -59,6 +59,7 @@ void server_window_loop(void) { struct window *w; + struct winlink *wl; struct window_pane *wp; struct session *s; u_int i, j; @@ -81,33 +82,37 @@ server_window_loop(void) for (j = 0; j < ARRAY_LENGTH(&sessions); j++) { s = ARRAY_ITEM(&sessions, j); - if (s == NULL || !session_has(s, w)) + if (s == NULL) + continue; + wl = session_has(s, w); + if (wl == NULL) continue; - if (server_window_check_bell(s, w) || - server_window_check_activity(s, w)) + if (server_window_check_bell(s, wl) || + server_window_check_activity(s, wl)) server_status_session(s); TAILQ_FOREACH(wp, &w->panes, entry) - server_window_check_content(s, w, wp); + server_window_check_content(s, wl, wp); } - w->flags &= ~(WINDOW_BELL|WINDOW_ACTIVITY|WINDOW_CONTENT); + w->flags &= ~(WINDOW_BELL|WINDOW_ACTIVITY); } } /* Check for bell in window. */ int -server_window_check_bell(struct session *s, struct window *w) +server_window_check_bell(struct session *s, struct winlink *wl) { struct client *c; + struct window *w = wl->window; u_int i; int action, visual; - if (!(w->flags & WINDOW_BELL)) + if (!(w->flags & WINDOW_BELL) || wl->flags & WINLINK_BELL) + return (0); + if (s->curw == wl) return (0); - if (session_alert_has_window(s, w, WINDOW_BELL)) - return (0); - session_alert_add(s, w, WINDOW_BELL); + wl->flags |= WINLINK_BELL; action = options_get_number(&s->options, "bell-action"); switch (action) { @@ -155,25 +160,22 @@ server_window_check_bell(struct session *s, struct window *w) /* Check for activity in window. */ int -server_window_check_activity(struct session *s, struct window *w) +server_window_check_activity(struct session *s, struct winlink *wl) { struct client *c; + struct window *w = wl->window; u_int i; - if (!(w->flags & WINDOW_ACTIVITY)) + if (!(w->flags & WINDOW_ACTIVITY) || wl->flags & WINLINK_ACTIVITY) return (0); - if (s->curw->window == w) + if (s->curw == wl) return (0); if (!options_get_number(&w->options, "monitor-activity")) return (0); - if (session_alert_has_window(s, w, WINDOW_ACTIVITY)) - return (0); - session_alert_add(s, w, WINDOW_ACTIVITY); + wl->flags |= WINLINK_ACTIVITY; - if (s->flags & SESSION_UNATTACHED) - return (0); if (options_get_number(&s->options, "visual-activity")) { for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); @@ -190,31 +192,28 @@ server_window_check_activity(struct session *s, struct window *w) /* Check for content change in window. */ int server_window_check_content( - struct session *s, struct window *w, struct window_pane *wp) + struct session *s, struct winlink *wl, struct window_pane *wp) { struct client *c; + struct window *w = wl->window; u_int i; char *found, *ptr; - if (!(w->flags & WINDOW_ACTIVITY)) /* activity for new content */ + /* Activity flag must be set for new content. */ + if (!(w->flags & WINDOW_ACTIVITY) || wl->flags & WINLINK_CONTENT) return (0); - if (s->curw->window == w) + if (s->curw == wl) return (0); ptr = options_get_string(&w->options, "monitor-content"); if (ptr == NULL || *ptr == '\0') return (0); - - if (session_alert_has_window(s, w, WINDOW_CONTENT)) - return (0); - if ((found = window_pane_search(wp, ptr, NULL)) == NULL) return (0); xfree(found); - session_alert_add(s, w, WINDOW_CONTENT); - if (s->flags & SESSION_UNATTACHED) - return (0); + wl->flags |= WINLINK_CONTENT; + if (options_get_number(&s->options, "visual-content")) { for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); diff --git a/session.c b/session.c index 2957c1fc..65f8ef41 100644 --- a/session.c +++ b/session.c @@ -32,71 +32,8 @@ struct sessions sessions; struct sessions dead_sessions; struct session_groups session_groups; -struct winlink *session_next_alert(struct session *, struct winlink *); -struct winlink *session_previous_alert(struct session *, struct winlink *); - -void -session_alert_cancel(struct session *s, struct winlink *wl) -{ - struct session_alert *sa, *sb; - - sa = SLIST_FIRST(&s->alerts); - while (sa != NULL) { - sb = sa; - sa = SLIST_NEXT(sa, entry); - - if (wl == NULL || sb->wl == wl) { - SLIST_REMOVE(&s->alerts, sb, session_alert, entry); - xfree(sb); - } - } -} - -void -session_alert_add(struct session *s, struct window *w, int type) -{ - struct session_alert *sa; - struct winlink *wl; - - RB_FOREACH(wl, winlinks, &s->windows) { - if (wl == s->curw) - continue; - - if (wl->window == w && - !session_alert_has(s, wl, type)) { - sa = xmalloc(sizeof *sa); - sa->wl = wl; - sa->type = type; - SLIST_INSERT_HEAD(&s->alerts, sa, entry); - } - } -} - -int -session_alert_has(struct session *s, struct winlink *wl, int type) -{ - struct session_alert *sa; - - SLIST_FOREACH(sa, &s->alerts, entry) { - if (sa->wl == wl && sa->type == type) - return (1); - } - - return (0); -} - -int -session_alert_has_window(struct session *s, struct window *w, int type) -{ - struct session_alert *sa; - - SLIST_FOREACH(sa, &s->alerts, entry) { - if (sa->wl->window == w && sa->type == type) - return (1); - } - - return (0); -} +struct winlink *session_next_alert(struct winlink *); +struct winlink *session_previous_alert(struct winlink *); /* Find session by name. */ struct session * @@ -134,7 +71,6 @@ session_create(const char *name, const char *cmd, const char *cwd, s->curw = NULL; TAILQ_INIT(&s->lastw); RB_INIT(&s->windows); - SLIST_INIT(&s->alerts); paste_init_stack(&s->buffers); @@ -197,7 +133,6 @@ session_destroy(struct session *s) xfree(s->tio); session_group_remove(s); - session_alert_cancel(s, NULL); environ_free(&s->environ); options_free(&s->options); paste_free_stack(&s->buffers); @@ -285,7 +220,7 @@ session_detach(struct session *s, struct winlink *wl) session_last(s) != 0 && session_previous(s, 0) != 0) session_next(s, 0); - session_alert_cancel(s, wl); + wl->flags &= ~WINLINK_ALERTFLAGS; winlink_stack_remove(&s->lastw, wl); winlink_remove(&s->windows, wl); session_group_synchronize_from(s); @@ -297,27 +232,23 @@ session_detach(struct session *s, struct winlink *wl) } /* Return if session has window. */ -int +struct winlink * session_has(struct session *s, struct window *w) { struct winlink *wl; RB_FOREACH(wl, winlinks, &s->windows) { if (wl->window == w) - return (1); + return (wl); } - return (0); + return (NULL); } struct winlink * -session_next_alert(struct session *s, struct winlink *wl) +session_next_alert(struct winlink *wl) { while (wl != NULL) { - if (session_alert_has(s, wl, WINDOW_BELL)) - break; - if (session_alert_has(s, wl, WINDOW_ACTIVITY)) - break; - if (session_alert_has(s, wl, WINDOW_CONTENT)) + if (wl->flags & WINLINK_ALERTFLAGS) break; wl = winlink_next(wl); } @@ -335,10 +266,10 @@ session_next(struct session *s, int alert) wl = winlink_next(s->curw); if (alert) - wl = session_next_alert(s, wl); + wl = session_next_alert(wl); if (wl == NULL) { wl = RB_MIN(winlinks, &s->windows); - if (alert && ((wl = session_next_alert(s, wl)) == NULL)) + if (alert && ((wl = session_next_alert(wl)) == NULL)) return (-1); } if (wl == s->curw) @@ -346,19 +277,15 @@ session_next(struct session *s, int alert) winlink_stack_remove(&s->lastw, wl); winlink_stack_push(&s->lastw, s->curw); s->curw = wl; - session_alert_cancel(s, wl); + wl->flags &= ~WINLINK_ALERTFLAGS; return (0); } struct winlink * -session_previous_alert(struct session *s, struct winlink *wl) +session_previous_alert(struct winlink *wl) { while (wl != NULL) { - if (session_alert_has(s, wl, WINDOW_BELL)) - break; - if (session_alert_has(s, wl, WINDOW_ACTIVITY)) - break; - if (session_alert_has(s, wl, WINDOW_CONTENT)) + if (wl->flags & WINLINK_ALERTFLAGS) break; wl = winlink_previous(wl); } @@ -376,10 +303,10 @@ session_previous(struct session *s, int alert) wl = winlink_previous(s->curw); if (alert) - wl = session_previous_alert(s, wl); + wl = session_previous_alert(wl); if (wl == NULL) { wl = RB_MAX(winlinks, &s->windows); - if (alert && (wl = session_previous_alert(s, wl)) == NULL) + if (alert && (wl = session_previous_alert(wl)) == NULL) return (-1); } if (wl == s->curw) @@ -387,7 +314,7 @@ session_previous(struct session *s, int alert) winlink_stack_remove(&s->lastw, wl); winlink_stack_push(&s->lastw, s->curw); s->curw = wl; - session_alert_cancel(s, wl); + wl->flags &= ~WINLINK_ALERTFLAGS; return (0); } @@ -405,7 +332,7 @@ session_select(struct session *s, int idx) winlink_stack_remove(&s->lastw, wl); winlink_stack_push(&s->lastw, s->curw); s->curw = wl; - session_alert_cancel(s, wl); + wl->flags &= ~WINLINK_ALERTFLAGS; return (0); } @@ -424,7 +351,7 @@ session_last(struct session *s) winlink_stack_remove(&s->lastw, wl); winlink_stack_push(&s->lastw, s->curw); s->curw = wl; - session_alert_cancel(s, wl); + wl->flags &= ~WINLINK_ALERTFLAGS; return (0); } @@ -541,7 +468,6 @@ session_group_synchronize1(struct session *target, struct session *s) struct winlinks old_windows, *ww; struct winlink_stack old_lastw; struct winlink *wl, *wl2; - struct session_alert *sa; /* Don't do anything if the session is empty (it'll be destroyed). */ ww = &target->windows; @@ -559,8 +485,10 @@ session_group_synchronize1(struct session *target, struct session *s) RB_INIT(&s->windows); /* Link all the windows from the target. */ - RB_FOREACH(wl, winlinks, ww) - winlink_add(&s->windows, wl->window, wl->idx); + RB_FOREACH(wl, winlinks, ww) { + wl2 = winlink_add(&s->windows, wl->window, wl->idx); + wl2->flags |= wl->flags & WINLINK_ALERTFLAGS; + } /* Fix up the current window. */ if (s->curw != NULL) @@ -577,15 +505,6 @@ session_group_synchronize1(struct session *target, struct session *s) TAILQ_INSERT_TAIL(&s->lastw, wl2, sentry); } - /* And update the alerts list. */ - SLIST_FOREACH(sa, &s->alerts, entry) { - wl = winlink_find_by_index(&s->windows, sa->wl->idx); - if (wl == NULL) - session_alert_cancel(s, sa->wl); - else - sa->wl = wl; - } - /* Then free the old winlinks list. */ while (!RB_EMPTY(&old_windows)) { wl = RB_ROOT(&old_windows); diff --git a/status.c b/status.c index 4399ae43..b1d93c97 100644 --- a/status.c +++ b/status.c @@ -248,25 +248,15 @@ status_redraw(struct client *c) */ offset = 0; RB_FOREACH(wl, winlinks, &s->windows) { - if (larrow == 1 && offset < wlstart) { - if (session_alert_has(s, wl, WINDOW_ACTIVITY)) - larrow = -1; - else if (session_alert_has(s, wl, WINDOW_BELL)) - larrow = -1; - else if (session_alert_has(s, wl, WINDOW_CONTENT)) - larrow = -1; - } + if (wl->flags & WINLINK_ALERTFLAGS && + larrow == 1 && offset < wlstart) + larrow = -1; offset += wl->status_width; - if (rarrow == 1 && offset > wlstart + wlwidth) { - if (session_alert_has(s, wl, WINDOW_ACTIVITY)) - rarrow = -1; - else if (session_alert_has(s, wl, WINDOW_BELL)) - rarrow = -1; - else if (session_alert_has(s, wl, WINDOW_CONTENT)) - rarrow = -1; - } + if (wl->flags & WINLINK_ALERTFLAGS && + rarrow == 1 && offset > wlstart + wlwidth) + rarrow = -1; } draw: @@ -399,11 +389,11 @@ status_replace1(struct client *c,struct winlink *wl, goto do_replace; case 'F': tmp[0] = ' '; - if (session_alert_has(s, wl, WINDOW_CONTENT)) + if (wl->flags & WINLINK_CONTENT) tmp[0] = '+'; - else if (session_alert_has(s, wl, WINDOW_BELL)) + else if (wl->flags & WINLINK_BELL) tmp[0] = '!'; - else if (session_alert_has(s, wl, WINDOW_ACTIVITY)) + else if (wl->flags & WINLINK_ACTIVITY) tmp[0] = '#'; else if (wl == s->curw) tmp[0] = '*'; @@ -593,9 +583,7 @@ status_print( fmt = options_get_string(oo, "window-status-current-format"); } - if (session_alert_has(s, wl, WINDOW_ACTIVITY) || - session_alert_has(s, wl, WINDOW_BELL) || - session_alert_has(s, wl, WINDOW_CONTENT)) { + if (wl->flags & WINLINK_ALERTFLAGS) { fg = options_get_number(oo, "window-status-alert-fg"); if (fg != 8) colour_set_fg(gc, fg); diff --git a/tmux.h b/tmux.h index c090aedd..10f3e593 100644 --- a/tmux.h +++ b/tmux.h @@ -843,8 +843,7 @@ struct window { #define WINDOW_BELL 0x1 #define WINDOW_HIDDEN 0x2 #define WINDOW_ACTIVITY 0x4 -#define WINDOW_CONTENT 0x8 -#define WINDOW_REDRAW 0x10 +#define WINDOW_REDRAW 0x8 struct options options; @@ -861,6 +860,12 @@ struct winlink { struct grid_cell status_cell; char *status_text; + int flags; +#define WINLINK_BELL 0x1 +#define WINLINK_ACTIVITY 0x2 +#define WINLINK_CONTENT 0x4 +#define WINLINK_ALERTFLAGS (WINLINK_BELL|WINLINK_ACTIVITY|WINLINK_CONTENT) + RB_ENTRY(winlink) entry; TAILQ_ENTRY(winlink) sentry; }; @@ -912,13 +917,6 @@ struct environ_entry { RB_HEAD(environ, environ_entry); /* Client session. */ -struct session_alert { - struct winlink *wl; - int type; - - SLIST_ENTRY(session_alert) entry; -}; - struct session_group { TAILQ_HEAD(, session) sessions; @@ -943,8 +941,6 @@ struct session { struct paste_stack buffers; - SLIST_HEAD(, session_alert) alerts; - #define SESSION_UNATTACHED 0x1 /* not attached to any clients */ #define SESSION_DEAD 0x2 int flags; @@ -1911,10 +1907,6 @@ void clear_signals(void); extern struct sessions sessions; extern struct sessions dead_sessions; extern struct session_groups session_groups; -void session_alert_add(struct session *, struct window *, int); -void session_alert_cancel(struct session *, struct winlink *); -int session_alert_has(struct session *, struct winlink *, int); -int session_alert_has_window(struct session *, struct window *, int); struct session *session_find(const char *); struct session *session_create(const char *, const char *, const char *, struct environ *, struct termios *, int, u_int, u_int, @@ -1926,7 +1918,7 @@ struct winlink *session_new(struct session *, struct winlink *session_attach( struct session *, struct window *, int, char **); int session_detach(struct session *, struct winlink *); -int session_has(struct session *, struct window *); +struct winlink* session_has(struct session *, struct window *); int session_next(struct session *, int); int session_previous(struct session *, int); int session_select(struct session *, int); From 386849edc1d7d322d6a48d334f83298ff7cb5501 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 21 Jun 2010 01:46:36 +0000 Subject: [PATCH 0725/1180] Extend the -t:+ and -t:- window targets for next and previous window to accept an offset such as -t:+2. From Tiago Cunha. --- cmd.c | 187 ++++++++++++++++++++++++++++++++++++------------------- tmux.1 | 12 ++++ tmux.h | 2 + window.c | 22 +++++++ 4 files changed, 159 insertions(+), 64 deletions(-) diff --git a/cmd.c b/cmd.c index d82a765e..4eeded0a 100644 --- a/cmd.c +++ b/cmd.c @@ -538,7 +538,7 @@ cmd_lookup_session(const char *name, int *ambiguous) /* * Lookup a window or return -1 if not found or ambigious. First try as an * index and if invalid, use fnmatch or leading prefix. Return NULL but fill in - * idx if the window index is a valid number but there is now window with that + * idx if the window index is a valid number but there is no window with that * index. */ struct winlink * @@ -660,6 +660,7 @@ cmd_find_window(struct cmd_ctx *ctx, const char *arg, struct session **sp) const char *winptr; char *sessptr = NULL; int ambiguous = 0; + int n = 1; /* * Find the current session. There must always be a current session, if @@ -705,11 +706,21 @@ cmd_find_window(struct cmd_ctx *ctx, const char *arg, struct session **sp) wl = s->curw; else if (winptr[0] == '!' && winptr[1] == '\0') wl = TAILQ_FIRST(&s->lastw); - else if (winptr[0] == '+' && winptr[1] == '\0') - wl = winlink_next(s->curw); - else if (winptr[0] == '-' && winptr[1] == '\0') - wl = winlink_previous(s->curw); - else + else if (winptr[0] == '+' || winptr[0] == '-') { + if (winptr[1] != '\0') + n = strtonum(winptr + 1, 1, INT_MAX, NULL); + if (n == 0) + wl = cmd_lookup_window(s, winptr, &ambiguous); + else { + if (winptr[0] == '+') + wl = winlink_next_by_number(s->curw, n); + else + wl = winlink_previous_by_number(s->curw, n); + /* Search by name before giving up. */ + if (wl == NULL) + wl = cmd_lookup_window(s, winptr, &ambiguous); + } + } else wl = cmd_lookup_window(s, winptr, &ambiguous); if (wl == NULL) goto not_found; @@ -726,25 +737,41 @@ no_colon: if (arg[0] == '!' && arg[1] == '\0') { if ((wl = TAILQ_FIRST(&s->lastw)) == NULL) goto not_found; - } else if (arg[0] == '+' && arg[1] == '\0') { - if ((wl = winlink_next(s->curw)) == NULL) - goto not_found; - } else if (arg[0] == '-' && arg[1] == '\0') { - if ((wl = winlink_previous(s->curw)) == NULL) - goto not_found; - } else if ((wl = cmd_lookup_window(s, arg, &ambiguous)) == NULL) { - if (ambiguous) - goto not_found; - if ((s = cmd_lookup_session(arg, &ambiguous)) == NULL) - goto no_session; - wl = s->curw; - } + } else if (arg[0] == '+' || arg[0] == '-') { + if (arg[1] != '\0') + n = strtonum(arg + 1, 1, INT_MAX, NULL); + if (n == 0) + wl = cmd_lookup_window(s, arg, &ambiguous); + else { + if (arg[0] == '+') + wl = winlink_next_by_number(s->curw, n); + else + wl = winlink_previous_by_number(s->curw, n); + /* Search by name before giving up. */ + if (wl == NULL) + wl = cmd_lookup_window(s, arg, &ambiguous); + } + if (wl == NULL) + goto lookup_session; + } else if ((wl = cmd_lookup_window(s, arg, &ambiguous)) == NULL) + goto lookup_session; if (sp != NULL) *sp = s; return (wl); +lookup_session: + if (ambiguous) + goto not_found; + if ((s = cmd_lookup_session(arg, &ambiguous)) == NULL) + goto no_session; + + if (sp != NULL) + *sp = s; + + return (s->curw); + no_session: if (ambiguous) ctx->error(ctx, "multiple sessions: %s", arg); @@ -778,6 +805,7 @@ cmd_find_index(struct cmd_ctx *ctx, const char *arg, struct session **sp) const char *winptr; char *sessptr = NULL; int idx, ambiguous = 0; + int n = 1; /* * Find the current session. There must always be a current session, if @@ -825,20 +853,23 @@ cmd_find_index(struct cmd_ctx *ctx, const char *arg, struct session **sp) if ((wl = TAILQ_FIRST(&s->lastw)) == NULL) goto not_found; idx = wl->idx; - } else if (winptr[0] == '+' && winptr[1] == '\0') { - if (s->curw->idx == INT_MAX) - goto not_found; - idx = s->curw->idx + 1; - } else if (winptr[0] == '-' && winptr[1] == '\0') { - if (s->curw->idx == 0) - goto not_found; - idx = s->curw->idx - 1; - } else if ((idx = cmd_lookup_index(s, winptr, &ambiguous)) == -1) { - if (ambiguous) - goto not_found; - ctx->error(ctx, "invalid index: %s", arg); - idx = -2; - } + } else if (winptr[0] == '+' || winptr[0] == '-') { + if (winptr[1] != '\0') + n = strtonum(winptr + 1, 1, INT_MAX, NULL); + if (winptr[0] == '+' && s->curw->idx == INT_MAX) + idx = cmd_lookup_index(s, winptr, &ambiguous); + else if (winptr[0] == '-' && s->curw->idx == 0) + idx = cmd_lookup_index(s, winptr, &ambiguous); + else if (n == 0) + idx = cmd_lookup_index(s, winptr, &ambiguous); + else if (winptr[0] == '+') + idx = s->curw->idx + n; + else + idx = s->curw->idx - n; + if (idx < 0) + goto invalid_index; + } else if ((idx = cmd_lookup_index(s, winptr, &ambiguous)) == -1) + goto invalid_index; if (sessptr != NULL) xfree(sessptr); @@ -853,27 +884,40 @@ no_colon: if ((wl = TAILQ_FIRST(&s->lastw)) == NULL) goto not_found; idx = wl->idx; - } else if (arg[0] == '+' && arg[1] == '\0') { - if (s->curw->idx == INT_MAX) - goto not_found; - idx = s->curw->idx + 1; - } else if (arg[0] == '-' && arg[1] == '\0') { - if (s->curw->idx == 0) - goto not_found; - idx = s->curw->idx - 1; - } else if ((idx = cmd_lookup_index(s, arg, &ambiguous)) == -1) { - if (ambiguous) - goto not_found; - if ((s = cmd_lookup_session(arg, &ambiguous)) == NULL) - goto no_session; - idx = -1; - } + } else if (arg[0] == '+' || arg[0] == '-') { + if (arg[1] != '\0') + n = strtonum(arg + 1, 1, INT_MAX, NULL); + if (arg[0] == '+' && s->curw->idx == INT_MAX) + idx = cmd_lookup_index(s, arg, &ambiguous); + else if (arg[0] == '-' && s->curw->idx == 0) + idx = cmd_lookup_index(s, arg, &ambiguous); + else if (n == 0) + idx = cmd_lookup_index(s, arg, &ambiguous); + else if (arg[0] == '+') + idx = s->curw->idx + n; + else + idx = s->curw->idx - n; + if (idx < 0) + goto lookup_session; + } else if ((idx = cmd_lookup_index(s, arg, &ambiguous)) == -1) + goto lookup_session; if (sp != NULL) *sp = s; return (idx); +lookup_session: + if (ambiguous) + goto not_found; + if ((s = cmd_lookup_session(arg, &ambiguous)) == NULL) + goto no_session; + + if (sp != NULL) + *sp = s; + + return (-1); + no_session: if (ambiguous) ctx->error(ctx, "multiple sessions: %s", arg); @@ -883,6 +927,15 @@ no_session: xfree(sessptr); return (-2); +invalid_index: + if (ambiguous) + goto not_found; + ctx->error(ctx, "invalid index: %s", arg); + + if (sessptr != NULL) + xfree(sessptr); + return (-2); + not_found: if (ambiguous) ctx->error(ctx, "multiple windows: %s", arg); @@ -907,7 +960,7 @@ cmd_find_pane(struct cmd_ctx *ctx, struct layout_cell *lc; const char *period, *errstr; char *winptr, *paneptr; - u_int idx; + u_int idx, n = 1; /* Get the current session. */ if ((s = cmd_current_session(ctx)) == NULL) { @@ -939,7 +992,27 @@ cmd_find_pane(struct cmd_ctx *ctx, paneptr = winptr + (period - arg) + 1; if (*paneptr == '\0') *wpp = wl->window->active; - else { + else if (paneptr[0] == '+' || paneptr[0] == '-') { + if (paneptr[1] != '\0') + n = strtonum(paneptr + 1, 1, INT_MAX, NULL); + idx = window_pane_index(wl->window, wl->window->active); + if (paneptr[0] == '+' && idx == INT_MAX) + *wpp = TAILQ_FIRST(&wl->window->panes); + else if (paneptr[0] == '-' && idx == 0) + *wpp = TAILQ_LAST(&wl->window->panes, window_panes); + else if (n == 0) + *wpp = wl->window->active; + else if (paneptr[0] == '+') + *wpp = window_pane_at_index(wl->window, idx + n); + else + *wpp = window_pane_at_index(wl->window, idx - n); + if (paneptr[0] == '+' && *wpp == NULL) + *wpp = TAILQ_FIRST(&wl->window->panes); + else if (paneptr[0] == '-' && *wpp == NULL) + *wpp = TAILQ_LAST(&wl->window->panes, window_panes); + else if (*wpp == NULL) + goto error; + } else { idx = strtonum(paneptr, 0, INT_MAX, &errstr); if (errstr != NULL) goto lookup_string; @@ -952,20 +1025,6 @@ cmd_find_pane(struct cmd_ctx *ctx, return (wl); lookup_string: - /* Try as next or previous pane. */ - if (paneptr[0] == '+' && paneptr[1] == '\0') { - *wpp = TAILQ_NEXT(wl->window->active, entry); - if (*wpp == NULL) - *wpp = TAILQ_FIRST(&wl->window->panes); - return (wl); - } - if (paneptr[0] == '-' && paneptr[1] == '\0') { - *wpp = TAILQ_PREV(wl->window->active, window_panes, entry); - if (*wpp == NULL) - *wpp = TAILQ_LAST(&wl->window->panes, window_panes); - return (wl); - } - /* Try pane string description. */ if ((lc = layout_find_string(wl->window, paneptr)) == NULL) { ctx->error(ctx, "can't find pane: %s", paneptr); diff --git a/tmux.1 b/tmux.1 index c7c88ddf..30725f6e 100644 --- a/tmux.1 +++ b/tmux.1 @@ -428,6 +428,18 @@ One of the strings .Em bottom-right may be used instead of a pane index. .Pp +The special characters +.Ql + +and +.Ql - +may be followed by an offset, for example: +.Bd -literal -offset indent +select-window -t:+2 +.Ed +.Pp +When dealing with a session that doesn't contain sequential window indexes, +they will be correctly skipped. +.Pp .Ar shell-command arguments are .Xr sh 1 diff --git a/tmux.h b/tmux.h index 10f3e593..c0d41383 100644 --- a/tmux.h +++ b/tmux.h @@ -1799,6 +1799,8 @@ struct winlink *winlink_add(struct winlinks *, struct window *, int); void winlink_remove(struct winlinks *, struct winlink *); struct winlink *winlink_next(struct winlink *); struct winlink *winlink_previous(struct winlink *); +struct winlink *winlink_next_by_number(struct winlink *, int); +struct winlink *winlink_previous_by_number(struct winlink *, int); void winlink_stack_push(struct winlink_stack *, struct winlink *); void winlink_stack_remove(struct winlink_stack *, struct winlink *); int window_index(struct window *, u_int *); diff --git a/window.c b/window.c index 36ad4adb..320da2a2 100644 --- a/window.c +++ b/window.c @@ -172,6 +172,28 @@ winlink_previous(struct winlink *wl) return (RB_PREV(winlinks, wwl, wl)); } +struct winlink * +winlink_next_by_number(struct winlink *wl, int n) +{ + for (; n > 0; n--) { + if ((wl = RB_NEXT(winlinks, wwl, wl)) == NULL) + break; + } + + return (wl); +} + +struct winlink * +winlink_previous_by_number(struct winlink *wl, int n) +{ + for (; n > 0; n--) { + if ((wl = RB_PREV(winlinks, wwl, wl)) == NULL) + break; + } + + return (wl); +} + void winlink_stack_push(struct winlink_stack *stack, struct winlink *wl) { From ef7293379f00b85cb96dd0dff128bb503e87612b Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 21 Jun 2010 21:44:09 +0000 Subject: [PATCH 0726/1180] Add a choose-buffer command for easier use of the paste buffer stack. --- Makefile | 2 +- cmd-choose-buffer.c | 146 ++++++++++++++++++++++++++++++++++++++++++++ cmd-list-buffers.c | 26 ++------ cmd.c | 1 + key-bindings.c | 1 + paste.c | 25 ++++++++ tmux.1 | 19 ++++++ tmux.h | 2 + 8 files changed, 200 insertions(+), 22 deletions(-) create mode 100644 cmd-choose-buffer.c diff --git a/Makefile b/Makefile index 73ca0c4d..fa4e6af6 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ SRCS= attributes.c cfg.c client.c clock.c \ cmd-break-pane.c cmd-choose-session.c cmd-choose-window.c \ cmd-clear-history.c cmd-clock-mode.c cmd-command-prompt.c \ cmd-confirm-before.c cmd-copy-buffer.c cmd-copy-mode.c \ - cmd-delete-buffer.c cmd-detach-client.c \ + cmd-choose-buffer.c cmd-delete-buffer.c cmd-detach-client.c \ cmd-find-window.c cmd-generic.c cmd-has-session.c cmd-kill-pane.c \ cmd-kill-server.c cmd-kill-session.c cmd-kill-window.c \ cmd-last-window.c cmd-link-window.c cmd-list-buffers.c \ diff --git a/cmd-choose-buffer.c b/cmd-choose-buffer.c new file mode 100644 index 00000000..4008c54a --- /dev/null +++ b/cmd-choose-buffer.c @@ -0,0 +1,146 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2010 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 "tmux.h" + +/* + * Enter choice mode to choose a buffer. + */ + +int cmd_choose_buffer_exec(struct cmd *, struct cmd_ctx *); + +void cmd_choose_buffer_callback(void *, int); +void cmd_choose_buffer_free(void *); + +const struct cmd_entry cmd_choose_buffer_entry = { + "choose-buffer", NULL, + CMD_TARGET_WINDOW_USAGE " [template]", + CMD_ARG01, "", + cmd_target_init, + cmd_target_parse, + cmd_choose_buffer_exec, + cmd_target_free, + cmd_target_print +}; + +struct cmd_choose_buffer_data { + struct client *client; + char *template; +}; + +int +cmd_choose_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_target_data *data = self->data; + struct cmd_choose_buffer_data *cdata; + struct session *s; + struct winlink *wl; + struct paste_buffer *pb; + u_int idx; + char *tmp; + + if (ctx->curclient == NULL) { + ctx->error(ctx, "must be run interactively"); + return (-1); + } + s = ctx->curclient->session; + + if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) + return (-1); + + if (paste_get_top(&s->buffers) == NULL) + return (0); + + if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0) + return (0); + + idx = 0; + while ((pb = paste_walk_stack(&s->buffers, &idx)) != NULL) { + tmp = paste_print(pb, 50); + window_choose_add(wl->window->active, idx - 1, + "%u: %zu bytes: \"%s\"", idx - 1, pb->size, tmp); + xfree(tmp); + } + + cdata = xmalloc(sizeof *cdata); + if (data->arg != NULL) + cdata->template = xstrdup(data->arg); + else + cdata->template = xstrdup("paste-buffer -b '%%'"); + cdata->client = ctx->curclient; + cdata->client->references++; + + window_choose_ready(wl->window->active, + 0, cmd_choose_buffer_callback, cmd_choose_buffer_free, cdata); + + return (0); +} + +void +cmd_choose_buffer_callback(void *data, int idx) +{ + struct cmd_choose_buffer_data *cdata = data; + struct cmd_list *cmdlist; + struct cmd_ctx ctx; + char *template, *cause, tmp[16]; + + if (idx == -1) + return; + if (cdata->client->flags & CLIENT_DEAD) + return; + + xsnprintf(tmp, sizeof tmp, "%u", idx); + template = cmd_template_replace(cdata->template, tmp, 1); + + if (cmd_string_parse(template, &cmdlist, &cause) != 0) { + if (cause != NULL) { + *cause = toupper((u_char) *cause); + status_message_set(cdata->client, "%s", cause); + xfree(cause); + } + xfree(template); + return; + } + xfree(template); + + ctx.msgdata = NULL; + ctx.curclient = cdata->client; + + ctx.error = key_bindings_error; + ctx.print = key_bindings_print; + ctx.info = key_bindings_info; + + ctx.cmdclient = NULL; + + cmd_list_exec(cmdlist, &ctx); + cmd_list_free(cmdlist); +} + +void +cmd_choose_buffer_free(void *data) +{ + struct cmd_choose_buffer_data *cdata = data; + + cdata->client->references--; + xfree(cdata->template); + xfree(cdata); +} diff --git a/cmd-list-buffers.c b/cmd-list-buffers.c index 0416dfe7..c2b0edc9 100644 --- a/cmd-list-buffers.c +++ b/cmd-list-buffers.c @@ -19,7 +19,6 @@ #include #include -#include #include "tmux.h" @@ -47,32 +46,17 @@ cmd_list_buffers_exec(struct cmd *self, struct cmd_ctx *ctx) struct session *s; struct paste_buffer *pb; u_int idx; - char tmp[51 * 4 + 1]; - size_t size, len; + char *tmp; if ((s = cmd_find_session(ctx, data->target)) == NULL) return (-1); idx = 0; while ((pb = paste_walk_stack(&s->buffers, &idx)) != NULL) { - size = pb->size; - - /* Translate the first 50 characters. */ - len = size; - if (len > 50) - len = 50; - strvisx(tmp, pb->data, len, VIS_OCTAL|VIS_TAB|VIS_NL); - - /* - * If the first 50 characters were encoded as a longer string, - * or there is definitely more data, add "...". - */ - if (size > 50 || strlen(tmp) > 50) { - tmp[50 - 3] = '\0'; - strlcat(tmp, "...", sizeof tmp); - } - - ctx->print(ctx, "%u: %zu bytes: \"%s\"", idx - 1, size, tmp); + tmp = paste_print(pb, 50); + ctx->print(ctx, + "%u: %zu bytes: \"%s\"", idx - 1, pb->size, tmp); + xfree(tmp); } return (0); diff --git a/cmd.c b/cmd.c index 4eeded0a..0c9aa8d2 100644 --- a/cmd.c +++ b/cmd.c @@ -32,6 +32,7 @@ const struct cmd_entry *cmd_table[] = { &cmd_bind_key_entry, &cmd_break_pane_entry, &cmd_capture_pane_entry, + &cmd_choose_buffer_entry, &cmd_choose_client_entry, &cmd_choose_session_entry, &cmd_choose_window_entry, diff --git a/key-bindings.c b/key-bindings.c index 44132202..ac4039f9 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -122,6 +122,7 @@ key_bindings_init(void) { '8', 0, &cmd_select_window_entry }, { '9', 0, &cmd_select_window_entry }, { ':', 0, &cmd_command_prompt_entry }, + { '=', 0, &cmd_choose_buffer_entry }, { '?', 0, &cmd_list_keys_entry }, { 'D', 0, &cmd_choose_client_entry }, { '[', 0, &cmd_copy_mode_entry }, diff --git a/paste.c b/paste.c index 4596ce95..da93129a 100644 --- a/paste.c +++ b/paste.c @@ -20,6 +20,7 @@ #include #include +#include #include "tmux.h" @@ -156,3 +157,27 @@ paste_replace(struct paste_stack *ps, u_int idx, char *data, size_t size) return (0); } + +/* Convert a buffer into a visible string. */ +char * +paste_print(struct paste_buffer *pb, size_t width) +{ + char *buf; + size_t len, used; + + if (width < 3) + width = 3; + buf = xmalloc(width * 4 + 1); + + len = pb->size; + if (len > width) + len = width; + + used = strvisx(buf, pb->data, len, VIS_OCTAL|VIS_TAB|VIS_NL); + if (pb->size > width || used > width) { + buf[width - 3] = '\0'; + strlcat(buf, "...", width); + } + + return (buf); +} diff --git a/tmux.1 b/tmux.1 index 30725f6e..f53e65f3 100644 --- a/tmux.1 +++ b/tmux.1 @@ -248,6 +248,8 @@ Select windows 0 to 9. Enter the .Nm command prompt. +.It = +Choose which buffer to paste interactively from a list. .It \&? List all key bindings. .It D @@ -2447,6 +2449,23 @@ command above). .Pp The buffer commands are as follows: .Bl -tag -width Ds +.It Xo +.Ic choose-buffer +.Op Fl t Ar target-window +.Op Ar template +.Xc +Put a window into buffer choice mode, where a buffer may be chosen +interactively from a list. +After a buffer is selected, +.Ql %% +is replaced by the buffer index in +.Ar template +and the result executed as a command. +If +.Ar template +is not given, "paste-buffer -b '%%'" is used. +This command works only from inside +.Nm . .It Ic clear-history Op Fl t Ar target-pane .D1 (alias: Ic clearhist ) Remove and free the history for the specified pane. diff --git a/tmux.h b/tmux.h index c0d41383..7d6c2e70 100644 --- a/tmux.h +++ b/tmux.h @@ -1406,6 +1406,7 @@ int paste_free_top(struct paste_stack *); int paste_free_index(struct paste_stack *, u_int); void paste_add(struct paste_stack *, char *, size_t, u_int); int paste_replace(struct paste_stack *, u_int, char *, size_t); +char *paste_print(struct paste_buffer *, size_t); /* clock.c */ extern const char clock_table[14][5][5]; @@ -1442,6 +1443,7 @@ extern const struct cmd_entry cmd_attach_session_entry; extern const struct cmd_entry cmd_bind_key_entry; extern const struct cmd_entry cmd_break_pane_entry; extern const struct cmd_entry cmd_capture_pane_entry; +extern const struct cmd_entry cmd_choose_buffer_entry; extern const struct cmd_entry cmd_choose_client_entry; extern const struct cmd_entry cmd_choose_session_entry; extern const struct cmd_entry cmd_choose_window_entry; From 42e24139788d76f00896005df0f745d9e022709a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 26 Jun 2010 18:20:53 +0000 Subject: [PATCH 0727/1180] Setting the cmdlist pointer in the bind-key to NULL to prevent it being freed after the command is executing is bogus because it may still be needed if the same command is going to be executed again (for example if you "bind-key a bind-key b ..."). Making a copy is hard, so instead add a reference count to the cmd_list. While here, also print bind-key -n and the rest of the flags properly. Fixes problem reported by mcbride@. --- cmd-bind-key.c | 13 +++++++++++-- cmd-list.c | 20 ++++++++++++-------- key-bindings.c | 7 ++++--- tmux.c | 2 +- tmux.h | 5 ++++- 5 files changed, 32 insertions(+), 15 deletions(-) diff --git a/cmd-bind-key.c b/cmd-bind-key.c index c535612f..60887904 100644 --- a/cmd-bind-key.c +++ b/cmd-bind-key.c @@ -130,7 +130,7 @@ cmd_bind_key_exec(struct cmd *self, unused struct cmd_ctx *ctx) return (cmd_bind_key_table(self, ctx)); key_bindings_add(data->key, data->can_repeat, data->cmdlist); - data->cmdlist = NULL; /* avoid free */ + data->cmdlist->references++; return (0); } @@ -192,8 +192,17 @@ cmd_bind_key_print(struct cmd *self, char *buf, size_t len) off += xsnprintf(buf, len, "%s", self->entry->name); if (data == NULL) return (off); + + if (off < len && data->command_key) + off += xsnprintf(buf + off, len - off, " -c"); + if (off < len && !(data->key & KEYC_PREFIX)) + off += xsnprintf(buf + off, len - off, " -n"); + if (off < len && data->can_repeat) + off += xsnprintf(buf + off, len - off, " -r"); + if (off < len && data->tablename != NULL) + off += cmd_prarg(buf + off, len - off, " -t ", data->tablename); if (off < len) { - skey = key_string_lookup_key(data->key); + skey = key_string_lookup_key(data->key & ~KEYC_PREFIX); off += xsnprintf(buf + off, len - off, " %s ", skey); } if (off < len) diff --git a/cmd-list.c b/cmd-list.c index 55550c21..181127ae 100644 --- a/cmd-list.c +++ b/cmd-list.c @@ -32,7 +32,8 @@ cmd_list_parse(int argc, char **argv, char **cause) char **new_argv; cmdlist = xmalloc(sizeof *cmdlist); - TAILQ_INIT(cmdlist); + cmdlist->references = 1; + TAILQ_INIT(&cmdlist->list); lastsplit = 0; for (i = 0; i < argc; i++) { @@ -54,7 +55,7 @@ cmd_list_parse(int argc, char **argv, char **cause) cmd = cmd_parse(new_argc, new_argv, cause); if (cmd == NULL) goto bad; - TAILQ_INSERT_TAIL(cmdlist, cmd, qentry); + TAILQ_INSERT_TAIL(&cmdlist->list, cmd, qentry); lastsplit = i + 1; } @@ -63,7 +64,7 @@ cmd_list_parse(int argc, char **argv, char **cause) cmd = cmd_parse(argc - lastsplit, argv + lastsplit, cause); if (cmd == NULL) goto bad; - TAILQ_INSERT_TAIL(cmdlist, cmd, qentry); + TAILQ_INSERT_TAIL(&cmdlist->list, cmd, qentry); } return (cmdlist); @@ -80,7 +81,7 @@ cmd_list_exec(struct cmd_list *cmdlist, struct cmd_ctx *ctx) int n, retval; retval = 0; - TAILQ_FOREACH(cmd, cmdlist, qentry) { + TAILQ_FOREACH(cmd, &cmdlist->list, qentry) { if ((n = cmd_exec(cmd, ctx)) == -1) return (-1); @@ -114,9 +115,12 @@ cmd_list_free(struct cmd_list *cmdlist) { struct cmd *cmd; - while (!TAILQ_EMPTY(cmdlist)) { - cmd = TAILQ_FIRST(cmdlist); - TAILQ_REMOVE(cmdlist, cmd, qentry); + if (--cmdlist->references != 0) + return; + + while (!TAILQ_EMPTY(&cmdlist->list)) { + cmd = TAILQ_FIRST(&cmdlist->list); + TAILQ_REMOVE(&cmdlist->list, cmd, qentry); cmd_free(cmd); } xfree(cmdlist); @@ -129,7 +133,7 @@ cmd_list_print(struct cmd_list *cmdlist, char *buf, size_t len) size_t off; off = 0; - TAILQ_FOREACH(cmd, cmdlist, qentry) { + TAILQ_FOREACH(cmd, &cmdlist->list, qentry) { if (off >= len) break; off += cmd_print(cmd, buf + off, len - off); diff --git a/key-bindings.c b/key-bindings.c index ac4039f9..2a039af0 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -178,14 +178,15 @@ key_bindings_init(void) for (i = 0; i < nitems(table); i++) { cmdlist = xmalloc(sizeof *cmdlist); - TAILQ_INIT(cmdlist); + TAILQ_INIT(&cmdlist->list); + cmdlist->references = 1; cmd = xmalloc(sizeof *cmd); cmd->entry = table[i].entry; cmd->data = NULL; if (cmd->entry->init != NULL) cmd->entry->init(cmd, table[i].key); - TAILQ_INSERT_HEAD(cmdlist, cmd, qentry); + TAILQ_INSERT_HEAD(&cmdlist->list, cmd, qentry); key_bindings_add( table[i].key | KEYC_PREFIX, table[i].can_repeat, cmdlist); @@ -259,7 +260,7 @@ key_bindings_dispatch(struct key_binding *bd, struct client *c) ctx.cmdclient = NULL; readonly = 1; - TAILQ_FOREACH(cmd, bd->cmdlist, qentry) { + TAILQ_FOREACH(cmd, &bd->cmdlist->list, qentry) { if (!(cmd->entry->flags & CMD_READONLY)) readonly = 0; } diff --git a/tmux.c b/tmux.c index 28f822ce..f85a3556 100644 --- a/tmux.c +++ b/tmux.c @@ -517,7 +517,7 @@ main(int argc, char **argv) exit(1); } cmdflags &= ~CMD_STARTSERVER; - TAILQ_FOREACH(cmd, cmdlist, qentry) { + TAILQ_FOREACH(cmd, &cmdlist->list, qentry) { if (cmd->entry->flags & CMD_STARTSERVER) cmdflags |= CMD_STARTSERVER; if (cmd->entry->flags & CMD_SENDENVIRON) diff --git a/tmux.h b/tmux.h index 7d6c2e70..6b158cd7 100644 --- a/tmux.h +++ b/tmux.h @@ -1161,7 +1161,10 @@ struct cmd { TAILQ_ENTRY(cmd) qentry; }; -TAILQ_HEAD(cmd_list, cmd); +struct cmd_list { + int references; + TAILQ_HEAD(, cmd) list; +}; struct cmd_entry { const char *name; From 34464da8d3f762ccca3ebfdc418e93f4c02997f1 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 26 Jun 2010 23:55:50 +0000 Subject: [PATCH 0728/1180] Use server_destroy_session() for kill-session. --- cmd-kill-session.c | 12 +----------- server-fn.c | 1 + 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/cmd-kill-session.c b/cmd-kill-session.c index 26331b79..efd91801 100644 --- a/cmd-kill-session.c +++ b/cmd-kill-session.c @@ -45,21 +45,11 @@ cmd_kill_session_exec(struct cmd *self, struct cmd_ctx *ctx) { struct cmd_target_data *data = self->data; struct session *s; - struct client *c; - u_int i; if ((s = cmd_find_session(ctx, data->target)) == NULL) return (-1); - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - c = ARRAY_ITEM(&clients, i); - if (c != NULL && c->session == s) { - c->session = NULL; - server_write_client(c, MSG_EXIT, NULL, 0); - } - } - recalculate_sizes(); - + server_destroy_session(s); session_destroy(s); return (0); diff --git a/server-fn.c b/server-fn.c index da156e46..3a713686 100644 --- a/server-fn.c +++ b/server-fn.c @@ -371,6 +371,7 @@ server_destroy_session(struct session *s) c->session = NULL; server_write_client(c, MSG_EXIT, NULL, 0); } + recalculate_sizes(); } void From 26524c99f68959b5a0d1698529f332934061d424 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 27 Jun 2010 00:22:22 +0000 Subject: [PATCH 0729/1180] New option, detach-on-destroy, to set what happens to a client when the session it is attached to is destroyed. If on (the default), it is detached; if off, it is switched to the most recently active session. --- cmd-set-option.c | 1 + server-fn.c | 36 +++++++++++++++++++++++++++++++++--- tmux.1 | 5 +++++ tmux.c | 3 ++- 4 files changed, 41 insertions(+), 4 deletions(-) diff --git a/cmd-set-option.c b/cmd-set-option.c index 85776fbb..8caf42e2 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -87,6 +87,7 @@ const struct set_option_entry set_session_option_table[] = { { "default-path", SET_OPTION_STRING, 0, 0, NULL }, { "default-shell", SET_OPTION_STRING, 0, 0, NULL }, { "default-terminal", SET_OPTION_STRING, 0, 0, NULL }, + { "detach-on-destroy", SET_OPTION_FLAG, 0, 0, NULL }, { "display-panes-colour", SET_OPTION_COLOUR, 0, 0, NULL }, { "display-panes-active-colour", SET_OPTION_COLOUR, 0, 0, NULL }, { "display-panes-time", SET_OPTION_NUMBER, 1, INT_MAX, NULL }, diff --git a/server-fn.c b/server-fn.c index 3a713686..74452fe8 100644 --- a/server-fn.c +++ b/server-fn.c @@ -24,7 +24,8 @@ #include "tmux.h" -void server_callback_identify(int, short, void *); +struct session *server_next_session(struct session *); +void server_callback_identify(int, short, void *); void server_fill_environ(struct session *s, struct environ *env) @@ -358,18 +359,47 @@ server_destroy_session_group(struct session *s) } } +struct session * +server_next_session(struct session *s) +{ + struct session *s_loop, *s_out; + u_int i; + + s_out = NULL; + for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { + s_loop = ARRAY_ITEM(&sessions, i); + if (s_loop == s) + continue; + if (s_out == NULL || + timercmp(&s_loop->activity_time, &s_out->activity_time, <)) + s_out = s_loop; + } + return (s_out); +} + void server_destroy_session(struct session *s) { struct client *c; + struct session *s_new; u_int i; + if (!options_get_number(&s->options, "detach-on-destroy")) + s_new = server_next_session(s); + else + s_new = NULL; + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); if (c == NULL || c->session != s) continue; - c->session = NULL; - server_write_client(c, MSG_EXIT, NULL, 0); + if (s_new == NULL) { + c->session = NULL; + server_write_client(c, MSG_EXIT, NULL, 0); + } else { + c->session = s_new; + server_redraw_client(c); + } } recalculate_sizes(); } diff --git a/tmux.1 b/tmux.1 index f53e65f3..cdd7ecdf 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1557,6 +1557,11 @@ Available window options are listed under .Pp Available server options are: .Bl -tag -width Ds +.It Ic detach-on-destroy +If on (the default), the client is detached when the session it is attached to +is destroyed. +If off, the client is switched to the most recently active of the remaining +sessions. .It Ic escape-time Set the time in milliseconds for which .Nm diff --git a/tmux.c b/tmux.c index f85a3556..b7e24a8b 100644 --- a/tmux.c +++ b/tmux.c @@ -341,8 +341,9 @@ main(int argc, char **argv) options_set_string(so, "default-command", "%s", ""); options_set_string(so, "default-shell", "%s", getshell()); options_set_string(so, "default-terminal", "screen"); - options_set_number(so, "display-panes-colour", 4); + options_set_number(so, "detach-on-destroy", 1); options_set_number(so, "display-panes-active-colour", 1); + options_set_number(so, "display-panes-colour", 4); options_set_number(so, "display-panes-time", 1000); options_set_number(so, "display-time", 750); options_set_number(so, "history-limit", 2000); From 07a71fd432df5873515da82d2d620ec0d986b558 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 27 Jun 2010 02:56:59 +0000 Subject: [PATCH 0730/1180] Store the current working directory in the session, change the default-path option to default to empty and make that mean that the stored session CWD is used. --- cmd-new-session.c | 16 ++++++++++++---- cmd-new-window.c | 11 +++++++---- cmd-split-window.c | 11 +++++++---- session.c | 3 +++ tmux.1 | 3 ++- tmux.c | 12 ++---------- tmux.h | 1 + 7 files changed, 34 insertions(+), 23 deletions(-) diff --git a/cmd-new-session.c b/cmd-new-session.c index 5e175bea..290d5a3b 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -18,8 +18,10 @@ #include +#include #include #include +#include #include "tmux.h" @@ -125,8 +127,9 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) struct window_pane *wp; struct environ env; struct termios tio, *tiop; - const char *update; - char *overrides, *cmd, *cwd, *cause; + struct passwd *pw; + const char *update, *cwd; + char *overrides, *cmd, *cause; int detached, idx; u_int sx, sy, i; @@ -198,8 +201,13 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) /* Get the new session working directory. */ if (ctx->cmdclient != NULL && ctx->cmdclient->cwd != NULL) cwd = ctx->cmdclient->cwd; - else - cwd = options_get_string(&global_s_options, "default-path"); + else { + pw = getpwuid(getuid()); + if (pw->pw_dir != NULL && *pw->pw_dir != '\0') + cwd = pw->pw_dir; + else + cwd = "/"; + } /* Find new session size. */ if (detached) { diff --git a/cmd-new-window.c b/cmd-new-window.c index 32c42eb4..b44be0b2 100644 --- a/cmd-new-window.c +++ b/cmd-new-window.c @@ -176,10 +176,13 @@ cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx) cmd = data->cmd; if (cmd == NULL) cmd = options_get_string(&s->options, "default-command"); - if (ctx->cmdclient == NULL || ctx->cmdclient->cwd == NULL) - cwd = options_get_string(&s->options, "default-path"); - else - cwd = ctx->cmdclient->cwd; + cwd = options_get_string(&s->options, "default-path"); + if (*cwd == '\0') { + if (ctx->cmdclient != NULL && ctx->cmdclient->cwd != NULL) + cwd = ctx->cmdclient->cwd; + else + cwd = s->cwd; + } if (idx == -1) idx = -1 - options_get_number(&s->options, "base-index"); diff --git a/cmd-split-window.c b/cmd-split-window.c index f4bfe4e2..e4f46c34 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -170,10 +170,13 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) cmd = data->cmd; if (cmd == NULL) cmd = options_get_string(&s->options, "default-command"); - if (ctx->cmdclient == NULL || ctx->cmdclient->cwd == NULL) - cwd = options_get_string(&s->options, "default-path"); - else - cwd = ctx->cmdclient->cwd; + cwd = options_get_string(&s->options, "default-path"); + if (*cwd == '\0') { + if (ctx->cmdclient != NULL && ctx->cmdclient->cwd != NULL) + cwd = ctx->cmdclient->cwd; + else + cwd = s->cwd; + } type = LAYOUT_TOPBOTTOM; if (data->flag_horizontal) diff --git a/session.c b/session.c index 65f8ef41..b164eef8 100644 --- a/session.c +++ b/session.c @@ -68,6 +68,8 @@ session_create(const char *name, const char *cmd, const char *cwd, fatal("gettimeofday failed"); memcpy(&s->activity_time, &s->creation_time, sizeof s->activity_time); + s->cwd = xstrdup(cwd); + s->curw = NULL; TAILQ_INIT(&s->lastw); RB_INIT(&s->windows); @@ -142,6 +144,7 @@ session_destroy(struct session *s) while (!RB_EMPTY(&s->windows)) winlink_remove(&s->windows, RB_ROOT(&s->windows)); + xfree(s->cwd); xfree(s->name); for (i = 0; i < ARRAY_LENGTH(&dead_sessions); i++) { diff --git a/tmux.1 b/tmux.1 index cdd7ecdf..cd44b7f5 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1626,7 +1626,8 @@ is used as a login shell. .It Ic default-path Ar path Set the default working directory for processes created from keys, or interactively from the prompt. -The default is the current working directory when the server is started. +The default is empty, which means to use the working directory of the shell +from which the server was started if it is available or the user's home if not. .It Ic default-terminal Ar terminal Set the default terminal for new windows created in this session - the default value of the diff --git a/tmux.c b/tmux.c index b7e24a8b..dc5631be 100644 --- a/tmux.c +++ b/tmux.c @@ -239,7 +239,7 @@ main(int argc, char **argv) struct env_data envdata; struct msg_command_data cmddata; char *s, *shellcmd, *path, *label, *home, *cause; - char cwd[MAXPATHLEN], **var; + char **var; void *buf; size_t len; int opt, flags, quiet = 0, cmdflags = 0; @@ -339,6 +339,7 @@ main(int argc, char **argv) options_set_number(so, "bell-action", BELL_ANY); options_set_number(so, "buffer-limit", 9); options_set_string(so, "default-command", "%s", ""); + options_set_string(so, "default-path", "%s", ""); options_set_string(so, "default-shell", "%s", getshell()); options_set_string(so, "default-terminal", "screen"); options_set_number(so, "detach-on-destroy", 1); @@ -435,15 +436,6 @@ main(int argc, char **argv) options_set_number(wo, "utf8", 0); } - if (getcwd(cwd, sizeof cwd) == NULL) { - pw = getpwuid(getuid()); - if (pw->pw_dir != NULL && *pw->pw_dir != '\0') - strlcpy(cwd, pw->pw_dir, sizeof cwd); - else - strlcpy(cwd, "/", sizeof cwd); - } - options_set_string(so, "default-path", "%s", cwd); - if (cfg_file == NULL) { home = getenv("HOME"); if (home == NULL || *home == '\0') { diff --git a/tmux.h b/tmux.h index 6b158cd7..88a8e814 100644 --- a/tmux.h +++ b/tmux.h @@ -926,6 +926,7 @@ TAILQ_HEAD(session_groups, session_group); struct session { char *name; + char *cwd; struct timeval creation_time; struct timeval activity_time; From 76bbdeb586ad93cfb16bd12db865b4c672a9168e Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 28 Jun 2010 22:10:42 +0000 Subject: [PATCH 0731/1180] Send all three of stdin, stdout, stderr from the client to the server, so that commands can directly make use of them. This means that load-buffer and save-buffer can have "-" as the file to read from stdin or write to stdout. This is a protocol version bump so the tmux server will need to be restarted after upgrade (or an older client used). --- client.c | 11 ++++++-- cmd-load-buffer.c | 31 +++++++++++++++++----- cmd-save-buffer.c | 33 ++++++++++++++++-------- server-client.c | 66 +++++++++++++++++++++++++++++++++++++---------- tmux.c | 12 --------- tmux.h | 15 ++++++----- 6 files changed, 117 insertions(+), 51 deletions(-) diff --git a/client.c b/client.c index 35cf2801..e86a64ad 100644 --- a/client.c +++ b/client.c @@ -96,8 +96,7 @@ server_started: if (cmdflags & CMD_SENDENVIRON) client_send_environ(); - if (isatty(STDIN_FILENO)) - client_send_identify(flags); + client_send_identify(flags); return (&client_ibuf); @@ -131,6 +130,14 @@ client_send_identify(int flags) fatal("dup failed"); imsg_compose(&client_ibuf, MSG_IDENTIFY, PROTOCOL_VERSION, -1, fd, &data, sizeof data); + + if ((fd = dup(STDOUT_FILENO)) == -1) + fatal("dup failed"); + imsg_compose(&client_ibuf, MSG_STDOUT, PROTOCOL_VERSION, -1, fd, NULL, 0); + + if ((fd = dup(STDERR_FILENO)) == -1) + fatal("dup failed"); + imsg_compose(&client_ibuf, MSG_STDERR, PROTOCOL_VERSION, -1, fd, NULL, 0); } void diff --git a/cmd-load-buffer.c b/cmd-load-buffer.c index 1fe95818..0f118490 100644 --- a/cmd-load-buffer.c +++ b/cmd-load-buffer.c @@ -16,10 +16,13 @@ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include + #include #include #include #include +#include #include "tmux.h" @@ -45,7 +48,7 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) { struct cmd_buffer_data *data = self->data; struct session *s; - FILE *f; + FILE *f, *close_f; char *pdata, *new_pdata; size_t psize; u_int limit; @@ -54,9 +57,23 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) if ((s = cmd_find_session(ctx, data->target)) == NULL) return (-1); - if ((f = fopen(data->arg, "rb")) == NULL) { - ctx->error(ctx, "%s: %s", data->arg, strerror(errno)); - return (-1); + if (strcmp(data->arg, "-") == 0 ) { + if (ctx->cmdclient == NULL) { + ctx->error(ctx, "%s: can't read from stdin", data->arg); + return (-1); + } + f = ctx->cmdclient->stdin_file; + if (isatty(fileno(ctx->cmdclient->stdin_file))) { + ctx->error(ctx, "%s: stdin is a tty", data->arg); + return (-1); + } + close_f = NULL; + } else { + if ((f = fopen(data->arg, "rb")) == NULL) { + ctx->error(ctx, "%s: %s", data->arg, strerror(errno)); + return (-1); + } + close_f = f; } pdata = NULL; @@ -77,7 +94,8 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) if (pdata != NULL) pdata[psize] = '\0'; - fclose(f); + if (close_f != NULL) + fclose(close_f); limit = options_get_number(&s->options, "buffer-limit"); if (data->buffer == -1) { @@ -94,6 +112,7 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) error: if (pdata != NULL) xfree(pdata); - fclose(f); + if (close_f != NULL) + fclose(close_f); return (-1); } diff --git a/cmd-save-buffer.c b/cmd-save-buffer.c index 22bc44f8..57c3f5f0 100644 --- a/cmd-save-buffer.c +++ b/cmd-save-buffer.c @@ -48,7 +48,7 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) struct session *s; struct paste_buffer *pb; mode_t mask; - FILE *f; + FILE *f, *close_f; if ((s = cmd_find_session(ctx, data->target)) == NULL) return (-1); @@ -65,15 +65,25 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) } } - mask = umask(S_IRWXG | S_IRWXO); - if (cmd_check_flag(data->chflags, 'a')) - f = fopen(data->arg, "ab"); - else - f = fopen(data->arg, "wb"); - umask(mask); - if (f == NULL) { - ctx->error(ctx, "%s: %s", data->arg, strerror(errno)); - return (-1); + if (strcmp(data->arg, "-") == 0) { + if (ctx->cmdclient == NULL) { + ctx->error(ctx, "%s: can't write to stdout", data->arg); + return (-1); + } + f = ctx->cmdclient->stdout_file; + close_f = NULL; + } else { + mask = umask(S_IRWXG | S_IRWXO); + if (cmd_check_flag(data->chflags, 'a')) + f = fopen(data->arg, "ab"); + else + f = fopen(data->arg, "wb"); + umask(mask); + if (f == NULL) { + ctx->error(ctx, "%s: %s", data->arg, strerror(errno)); + return (-1); + } + close_f = f; } if (fwrite(pb->data, 1, pb->size, f) != pb->size) { @@ -82,7 +92,8 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) return (-1); } - fclose(f); + if (close_f != NULL) + fclose(close_f); return (0); } diff --git a/server-client.c b/server-client.c index 301c986a..c7929fc1 100644 --- a/server-client.c +++ b/server-client.c @@ -69,6 +69,10 @@ server_client_create(int fd) ARRAY_INIT(&c->prompt_hdata); + c->stdin_file = NULL; + c->stdout_file = NULL; + c->stderr_file = NULL; + c->tty.fd = -1; c->title = NULL; @@ -118,6 +122,13 @@ server_client_lost(struct client *c) if (c->flags & CLIENT_TERMINAL) tty_free(&c->tty); + if (c->stdin_file != NULL) + fclose(c->stdin_file); + if (c->stdout_file != NULL) + fclose(c->stdout_file); + if (c->stderr_file != NULL) + fclose(c->stderr_file); + screen_free(&c->status); job_tree_free(&c->status_jobs); @@ -555,8 +566,31 @@ server_client_msg_dispatch(struct client *c) fatalx("MSG_IDENTIFY missing fd"); memcpy(&identifydata, imsg.data, sizeof identifydata); + c->stdin_file = fdopen(imsg.fd, "r"); + if (c->stdin_file == NULL) + fatal("fdopen(stdin) failed"); server_client_msg_identify(c, &identifydata, imsg.fd); break; + case MSG_STDOUT: + if (datalen != 0) + fatalx("bad MSG_STDOUT size"); + if (imsg.fd == -1) + fatalx("MSG_STDOUT missing fd"); + + c->stdout_file = fdopen(imsg.fd, "w"); + if (c->stdout_file == NULL) + fatal("fdopen(stdout) failed"); + break; + case MSG_STDERR: + if (datalen != 0) + fatalx("bad MSG_STDERR size"); + if (imsg.fd == -1) + fatalx("MSG_STDERR missing fd"); + + c->stderr_file = fdopen(imsg.fd, "w"); + if (c->stderr_file == NULL) + fatal("fdopen(stderr) failed"); + break; case MSG_RESIZE: if (datalen != 0) fatalx("bad MSG_RESIZE size"); @@ -622,45 +656,45 @@ server_client_msg_dispatch(struct client *c) void printflike2 server_client_msg_error(struct cmd_ctx *ctx, const char *fmt, ...) { - struct msg_print_data data; - va_list ap; + va_list ap; va_start(ap, fmt); - xvsnprintf(data.msg, sizeof data.msg, fmt, ap); + vfprintf(ctx->cmdclient->stderr_file, fmt, ap); va_end(ap); - server_write_client(ctx->cmdclient, MSG_ERROR, &data, sizeof data); + fputc('\n', ctx->cmdclient->stderr_file); + fflush(ctx->cmdclient->stderr_file); } /* Callback to send print message to client. */ void printflike2 server_client_msg_print(struct cmd_ctx *ctx, const char *fmt, ...) { - struct msg_print_data data; - va_list ap; + va_list ap; va_start(ap, fmt); - xvsnprintf(data.msg, sizeof data.msg, fmt, ap); + vfprintf(ctx->cmdclient->stdout_file, fmt, ap); va_end(ap); - server_write_client(ctx->cmdclient, MSG_PRINT, &data, sizeof data); + fputc('\n', ctx->cmdclient->stdout_file); + fflush(ctx->cmdclient->stdout_file); } /* Callback to send print message to client, if not quiet. */ void printflike2 server_client_msg_info(struct cmd_ctx *ctx, const char *fmt, ...) { - struct msg_print_data data; - va_list ap; + va_list ap; if (options_get_number(&global_options, "quiet")) return; va_start(ap, fmt); - xvsnprintf(data.msg, sizeof data.msg, fmt, ap); + vfprintf(ctx->cmdclient->stdout_file, fmt, ap); va_end(ap); - server_write_client(ctx->cmdclient, MSG_PRINT, &data, sizeof data); + fputc('\n', ctx->cmdclient->stderr_file); + fflush(ctx->cmdclient->stdout_file); } /* Handle command message. */ @@ -717,13 +751,19 @@ void server_client_msg_identify( struct client *c, struct msg_identify_data *data, int fd) { + int tty_fd; + c->cwd = NULL; data->cwd[(sizeof data->cwd) - 1] = '\0'; if (*data->cwd != '\0') c->cwd = xstrdup(data->cwd); + if (!isatty(fd)) + return; + if ((tty_fd = dup(fd)) == -1) + fatal("dup failed"); data->term[(sizeof data->term) - 1] = '\0'; - tty_init(&c->tty, fd, data->term); + tty_init(&c->tty, tty_fd, data->term); if (data->flags & IDENTIFY_UTF8) c->tty.flags |= TTY_UTF8; if (data->flags & IDENTIFY_256COLOURS) diff --git a/tmux.c b/tmux.c index dc5631be..1c9d1cb5 100644 --- a/tmux.c +++ b/tmux.c @@ -596,7 +596,6 @@ main_dispatch(const char *shellcmd) { struct imsg imsg; ssize_t n, datalen; - struct msg_print_data printdata; struct msg_shell_data shelldata; if ((n = imsg_read(main_ibuf)) == -1 || n == 0) @@ -616,17 +615,6 @@ main_dispatch(const char *shellcmd) fatalx("bad MSG_EXIT size"); exit(main_exitval); - case MSG_ERROR: - case MSG_PRINT: - if (datalen != sizeof printdata) - fatalx("bad MSG_PRINT size"); - memcpy(&printdata, imsg.data, sizeof printdata); - printdata.msg[(sizeof printdata.msg) - 1] = '\0'; - - log_info("%s", printdata.msg); - if (imsg.hdr.type == MSG_ERROR) - main_exitval = 1; - break; case MSG_READY: if (datalen != 0) fatalx("bad MSG_READY size"); diff --git a/tmux.h b/tmux.h index 88a8e814..9b46a4f4 100644 --- a/tmux.h +++ b/tmux.h @@ -19,7 +19,7 @@ #ifndef TMUX_H #define TMUX_H -#define PROTOCOL_VERSION 5 +#define PROTOCOL_VERSION 6 #include #include @@ -68,7 +68,6 @@ extern char **environ; */ #define COMMAND_LENGTH 2048 /* packed argv size */ #define TERMINAL_LENGTH 128 /* length of TERM environment variable */ -#define PRINT_LENGTH 512 /* printed error/message size */ #define ENVIRON_LENGTH 1024 /* environment variable length */ /* @@ -373,7 +372,9 @@ enum msgtype { MSG_ENVIRON, MSG_UNLOCK, MSG_LOCK, - MSG_SHELL + MSG_SHELL, + MSG_STDERR, + MSG_STDOUT, }; /* @@ -381,10 +382,6 @@ enum msgtype { * * Don't forget to bump PROTOCOL_VERSION if any of these change! */ -struct msg_print_data { - char msg[PRINT_LENGTH]; -}; - struct msg_command_data { pid_t pid; /* pid from $TMUX or -1 */ u_int idx; /* index from $TMUX */ @@ -1080,6 +1077,10 @@ struct client { char *cwd; struct tty tty; + FILE *stdin_file; + FILE *stdout_file; + FILE *stderr_file; + struct event repeat_timer; struct timeval status_timer; From 552c9cd83f7207759b41947f63ada828683b7892 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 29 Jun 2010 03:30:13 +0000 Subject: [PATCH 0732/1180] Custom layouts. list-windows command displays the layout as a string (such as "bb62,159x48,0,0{79x48,0,0,79x48,80,0}") and it can be applied to another window (with the same number of panes or fewer) using select-layout. --- Makefile | 2 +- cmd-list-windows.c | 4 + cmd-select-layout.c | 15 ++- layout-custom.c | 264 ++++++++++++++++++++++++++++++++++++++++++++ layout-string.c | 1 - layout.c | 128 ++++++++++++--------- tmux.1 | 20 +++- tmux.h | 7 ++ 8 files changed, 382 insertions(+), 59 deletions(-) create mode 100644 layout-custom.c diff --git a/Makefile b/Makefile index fa4e6af6..b70804f1 100644 --- a/Makefile +++ b/Makefile @@ -31,7 +31,7 @@ SRCS= attributes.c cfg.c client.c clock.c \ cmd-pipe-pane.c cmd-capture-pane.c cmd.c \ colour.c environ.c grid-view.c grid-utf8.c grid.c input-keys.c \ input.c key-bindings.c key-string.c \ - layout-set.c layout-string.c layout.c log.c job.c \ + layout-custom.c layout-set.c layout-string.c layout.c log.c job.c \ mode-key.c names.c options.c paste.c procname.c \ resize.c screen-redraw.c screen-write.c screen.c session.c status.c \ signal.c server-fn.c server.c server-client.c server-window.c \ diff --git a/cmd-list-windows.c b/cmd-list-windows.c index 7e78c94e..cc12b0f4 100644 --- a/cmd-list-windows.c +++ b/cmd-list-windows.c @@ -45,6 +45,7 @@ cmd_list_windows_exec(struct cmd *self, struct cmd_ctx *ctx) struct cmd_target_data *data = self->data; struct session *s; struct winlink *wl; + char *layout; if ((s = cmd_find_session(ctx, data->target)) == NULL) return (-1); @@ -52,6 +53,9 @@ cmd_list_windows_exec(struct cmd *self, struct cmd_ctx *ctx) RB_FOREACH(wl, winlinks, &s->windows) { ctx->print(ctx, "%d: %s [%ux%u]", wl->idx, wl->window->name, wl->window->sx, wl->window->sy); + layout = layout_dump(wl->window); + ctx->print(ctx, " layout: %s", layout); + xfree(layout); } return (0); diff --git a/cmd-select-layout.c b/cmd-select-layout.c index fd66578c..70f7125f 100644 --- a/cmd-select-layout.c +++ b/cmd-select-layout.c @@ -79,13 +79,16 @@ cmd_select_layout_exec(struct cmd *self, struct cmd_ctx *ctx) layout = wl->window->lastlayout; if (layout == -1) return (0); - } else if ((layout = layout_set_lookup(data->arg)) == -1) { - ctx->error(ctx, "unknown layout or ambiguous: %s", data->arg); - return (-1); + } else if ((layout = layout_set_lookup(data->arg)) != -1) { + layout = layout_set_select(wl->window, layout); + ctx->info(ctx, "arranging in: %s", layout_set_name(layout)); + } else { + if (layout_parse(wl->window, data->arg) == -1) { + ctx->error(ctx, "can't set layout: %s", data->arg); + return (-1); + } + ctx->info(ctx, "arranging in: %s", data->arg); } - layout = layout_set_select(wl->window, layout); - ctx->info(ctx, "arranging in: %s", layout_set_name(layout)); - return (0); } diff --git a/layout-custom.c b/layout-custom.c new file mode 100644 index 00000000..617e3170 --- /dev/null +++ b/layout-custom.c @@ -0,0 +1,264 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2010 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 "tmux.h" + +u_short layout_checksum(const char *); +int layout_append(struct layout_cell *, char *, size_t); +struct layout_cell *layout_construct(struct layout_cell *, const char **); +void layout_assign(struct window_pane **, struct layout_cell *); + +/* Calculate layout checksum. */ +u_short +layout_checksum(const char *layout) +{ + u_short csum; + + csum = 0; + for (; *layout != '\0'; layout++) { + csum = (csum >> 1) + ((csum & 1) << 15); + csum += *layout; + } + return (csum); +} + +/* Dump layout as a string. */ +char * +layout_dump(struct window *w) +{ + char layout[BUFSIZ], *out; + + *layout = '\0'; + if (layout_append(w->layout_root, layout, sizeof layout) != 0) + return (NULL); + + xasprintf(&out, "%4x,%s", layout_checksum(layout), layout); + return (out); +} + +/* Append information for a single cell. */ +int +layout_append(struct layout_cell *lc, char *buf, size_t len) +{ + struct layout_cell *lcchild; + char tmp[64]; + size_t tmplen; + const char *brackets = "]["; + + if (len == 0) + return (-1); + + tmplen = xsnprintf(tmp, sizeof tmp, + "%ux%u,%u,%u", lc->sx, lc->sy, lc->xoff, lc->yoff); + if (tmplen > (sizeof tmp) - 1) + return (-1); + if (strlcat(buf, tmp, len) >= len) + return (-1); + + switch (lc->type) { + case LAYOUT_LEFTRIGHT: + brackets = "}{"; + /* FALLTHROUGH */ + case LAYOUT_TOPBOTTOM: + if (strlcat(buf, &brackets[1], len) >= len) + return (-1); + TAILQ_FOREACH(lcchild, &lc->cells, entry) { + if (layout_append(lcchild, buf, len) != 0) + return (-1); + if (strlcat(buf, ",", len) >= len) + return (-1); + } + buf[strlen(buf) - 1] = brackets[0]; + break; + case LAYOUT_WINDOWPANE: + break; + } + + return (0); +} + +/* Parse a layout string and arrange window as layout. */ +int +layout_parse(struct window *w, const char *layout) +{ + struct layout_cell *lc, *lcchild; + struct window_pane *wp; + u_int npanes, ncells, sx, sy; + u_short csum; + + /* Check validity. */ + if (sscanf(layout, "%hx,", &csum) != 1) + return (-1); + layout += 5; + if (csum != layout_checksum(layout)) + return (-1); + + /* Build the layout. */ + lc = layout_construct(NULL, &layout); + if (lc == NULL) + return (-1); + if (*layout != '\0') + goto fail; + + /* Check this window will fit into the layout. */ + for (;;) { + npanes = window_count_panes(w); + ncells = layout_count_cells(lc); + if (npanes > ncells) + goto fail; + if (npanes == ncells) + break; + + /* Fewer panes than cells - close the bottom right. */ + lcchild = layout_find_bottomright(lc); + layout_destroy_cell(lcchild, &lc); + } + + /* Save the old window size and resize to the layout size. */ + sx = w->sx; sy = w->sy; + window_resize(w, lc->sx, lc->sy); + + /* Destroy the old layout and swap to the new. */ + layout_free_cell(w->layout_root); + w->layout_root = lc; + + /* Assign the panes into the cells. */ + wp = TAILQ_FIRST(&w->panes); + layout_assign(&wp, lc); + + /* Update pane offsets and sizes. */ + layout_fix_offsets(lc); + layout_fix_panes(w, lc->sx, lc->sy); + + /* Then resize the layout back to the original window size. */ + layout_resize(w, sx, sy); + window_resize(w, sx, sy); + + layout_print_cell(lc, __func__, 0); + + return (0); + +fail: + layout_free_cell(lc); + return (-1); +} + +/* Assign panes into cells. */ +void +layout_assign(struct window_pane **wp, struct layout_cell *lc) +{ + struct layout_cell *lcchild; + + switch (lc->type) { + case LAYOUT_WINDOWPANE: + layout_make_leaf(lc, *wp); + *wp = TAILQ_NEXT(*wp, entry); + return; + case LAYOUT_LEFTRIGHT: + case LAYOUT_TOPBOTTOM: + TAILQ_FOREACH(lcchild, &lc->cells, entry) + layout_assign(wp, lcchild); + return; + } +} + +/* Construct a cell from all or part of a layout tree. */ +struct layout_cell * +layout_construct(struct layout_cell *lcparent, const char **layout) +{ + struct layout_cell *lc, *lcchild; + u_int sx, sy, xoff, yoff; + + if (!isdigit((u_char) **layout)) + return (NULL); + if (sscanf(*layout, "%ux%u,%u,%u", &sx, &sy, &xoff, &yoff) != 4) + return (NULL); + + while (isdigit((u_char) **layout)) + (*layout)++; + if (**layout != 'x') + return (NULL); + (*layout)++; + while (isdigit((u_char) **layout)) + (*layout)++; + if (**layout != ',') + return (NULL); + (*layout)++; + while (isdigit((u_char) **layout)) + (*layout)++; + if (**layout != ',') + return (NULL); + (*layout)++; + while (isdigit((u_char) **layout)) + (*layout)++; + + lc = layout_create_cell(lcparent); + lc->sx = sx; + lc->sy = sy; + lc->xoff = xoff; + lc->yoff = yoff; + + switch (**layout) { + case ',': + case '}': + case ']': + case '\0': + return (lc); + case '{': + lc->type = LAYOUT_LEFTRIGHT; + break; + case '[': + lc->type = LAYOUT_TOPBOTTOM; + break; + default: + goto fail; + } + + do { + (*layout)++; + lcchild = layout_construct(lc, layout); + if (lcchild == NULL) + goto fail; + TAILQ_INSERT_TAIL(&lc->cells, lcchild, entry); + } while (**layout == ','); + + switch (lc->type) { + case LAYOUT_LEFTRIGHT: + if (**layout != '}') + goto fail; + break; + case LAYOUT_TOPBOTTOM: + if (**layout != ']') + goto fail; + break; + default: + goto fail; + } + (*layout)++; + + return (lc); + +fail: + layout_free_cell(lc); + return (NULL); +} diff --git a/layout-string.c b/layout-string.c index f3abe8f9..4b63f19a 100644 --- a/layout-string.c +++ b/layout-string.c @@ -36,7 +36,6 @@ struct layout_cell *layout_find_right(struct layout_cell *); struct layout_cell *layout_find_topleft(struct layout_cell *); struct layout_cell *layout_find_topright(struct layout_cell *); struct layout_cell *layout_find_bottomleft(struct layout_cell *); -struct layout_cell *layout_find_bottomright(struct layout_cell *); /* Find the cell; returns NULL if string not understood. */ struct layout_cell * diff --git a/layout.c b/layout.c index 2d7fd596..eee29905 100644 --- a/layout.c +++ b/layout.c @@ -218,6 +218,27 @@ layout_fix_panes(struct window *w, u_int wsx, u_int wsy) } } +/* Count the number of available cells in a layout. */ +u_int +layout_count_cells(struct layout_cell *lc) +{ + struct layout_cell *lcchild; + u_int n; + + switch (lc->type) { + case LAYOUT_WINDOWPANE: + return (1); + case LAYOUT_LEFTRIGHT: + case LAYOUT_TOPBOTTOM: + n = 0; + TAILQ_FOREACH(lcchild, &lc->cells, entry) + n += layout_count_cells(lcchild); + return (n); + default: + fatalx("bad layout type"); + } +} + /* Calculate how much size is available to be removed from a cell. */ u_int layout_resize_check(struct layout_cell *lc, enum layout_type type) @@ -302,6 +323,56 @@ layout_resize_adjust(struct layout_cell *lc, enum layout_type type, int change) } } +/* Destroy a cell and redistribute the space. */ +void +layout_destroy_cell(struct layout_cell *lc, struct layout_cell **lcroot) +{ + struct layout_cell *lcother, *lcparent; + + /* + * If no parent, this is the last pane so window close is imminent and + * there is no need to resize anything. + */ + lcparent = lc->parent; + if (lcparent == NULL) { + layout_free_cell(lc); + *lcroot = NULL; + return; + } + + /* Merge the space into the previous or next cell. */ + if (lc == TAILQ_FIRST(&lcparent->cells)) + lcother = TAILQ_NEXT(lc, entry); + else + lcother = TAILQ_PREV(lc, layout_cells, entry); + if (lcparent->type == LAYOUT_LEFTRIGHT) + layout_resize_adjust(lcother, lcparent->type, lc->sx + 1); + else + layout_resize_adjust(lcother, lcparent->type, lc->sy + 1); + + /* Remove this from the parent's list. */ + TAILQ_REMOVE(&lcparent->cells, lc, entry); + layout_free_cell(lc); + + /* + * If the parent now has one cell, remove the parent from the tree and + * replace it by that cell. + */ + lc = TAILQ_FIRST(&lcparent->cells); + if (TAILQ_NEXT(lc, entry) == NULL) { + TAILQ_REMOVE(&lcparent->cells, lc, entry); + + lc->parent = lcparent->parent; + if (lc->parent == NULL) { + lc->xoff = 0; lc->yoff = 0; + *lcroot = lc; + } else + TAILQ_REPLACE(&lc->parent->cells, lcparent, lc, entry); + + layout_free_cell(lcparent); + } +} + void layout_init(struct window *w) { @@ -597,59 +668,16 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size) return (lcnew); } -/* Destroy the layout associated with a pane and redistribute the space. */ +/* Destroy the cell associated with a pane. */ void layout_close_pane(struct window_pane *wp) { - struct layout_cell *lc, *lcother, *lcparent; - - lc = wp->layout_cell; - lcparent = lc->parent; - - /* - * If no parent, this is the last pane so window close is imminent and - * there is no need to resize anything. - */ - if (lcparent == NULL) { - layout_free_cell(lc); - wp->window->layout_root = NULL; - return; - } - - /* Merge the space into the previous or next cell. */ - if (lc == TAILQ_FIRST(&lcparent->cells)) - lcother = TAILQ_NEXT(lc, entry); - else - lcother = TAILQ_PREV(lc, layout_cells, entry); - if (lcparent->type == LAYOUT_LEFTRIGHT) - layout_resize_adjust(lcother, lcparent->type, lc->sx + 1); - else - layout_resize_adjust(lcother, lcparent->type, lc->sy + 1); - - /* Remove this from the parent's list. */ - TAILQ_REMOVE(&lcparent->cells, lc, entry); - layout_free_cell(lc); - - /* - * If the parent now has one cell, remove the parent from the tree and - * replace it by that cell. - */ - lc = TAILQ_FIRST(&lcparent->cells); - if (TAILQ_NEXT(lc, entry) == NULL) { - TAILQ_REMOVE(&lcparent->cells, lc, entry); - - lc->parent = lcparent->parent; - if (lc->parent == NULL) { - lc->xoff = 0; lc->yoff = 0; - wp->window->layout_root = lc; - } else - TAILQ_REPLACE(&lc->parent->cells, lcparent, lc, entry); - - layout_free_cell(lcparent); - } + /* Remove the cell. */ + layout_destroy_cell(wp->layout_cell, &wp->window->layout_root); /* Fix pane offsets and sizes. */ - layout_fix_offsets(wp->window->layout_root); - layout_fix_panes(wp->window, wp->window->sx, wp->window->sy); + if (wp->window->layout_root != NULL) { + layout_fix_offsets(wp->window->layout_root); + layout_fix_panes(wp->window, wp->window->sx, wp->window->sy); + } } - diff --git a/tmux.1 b/tmux.1 index cd44b7f5..9252e25a 100644 --- a/tmux.1 +++ b/tmux.1 @@ -877,6 +877,24 @@ Panes are spread out as evenly as possible over the window in both rows and columns. .El .Pp +In addition, +.Ic select-layout +may be used to apply a previously used layout - the +.Ic list-windows +command displays the layout of each window in a form suitable for use with +.Ic select-layout . +For example: +.Bd -literal -offset indent +$ tmux list-windows +0: ksh [159x48] + layout: bb62,159x48,0,0{79x48,0,0,79x48,80,0} +$ tmux select-layout bb62,159x48,0,0{79x48,0,0,79x48,80,0} +.Ed +.Nm +automatically adjusts the size of the layout for the current window size. +Note that a layout cannot be applied to a window with more panes than that +from which the layout was originally defined. +.Pp Commands related to windows and panes are as follows: .Bl -tag -width Ds .It Xo Ic break-pane @@ -1224,7 +1242,7 @@ or downward (numerically higher). Choose a specific layout for a window. If .Ar layout-name -is not given, the last layout used (if any) is reapplied. +is not given, the last preset layout used (if any) is reapplied. .It Xo Ic select-pane .Op Fl DLRU .Op Fl t Ar target-pane diff --git a/tmux.h b/tmux.h index 9b46a4f4..57656773 100644 --- a/tmux.h +++ b/tmux.h @@ -1850,9 +1850,11 @@ struct window_pane *window_pane_find_left(struct window_pane *); struct window_pane *window_pane_find_right(struct window_pane *); /* layout.c */ +u_int layout_count_cells(struct layout_cell *); struct layout_cell *layout_create_cell(struct layout_cell *); void layout_free_cell(struct layout_cell *); void layout_print_cell(struct layout_cell *, const char *, u_int); +void layout_destroy_cell(struct layout_cell *, struct layout_cell **); void layout_set_size( struct layout_cell *, u_int, u_int, u_int, u_int); void layout_make_leaf( @@ -1873,6 +1875,10 @@ struct layout_cell *layout_split_pane( struct window_pane *, enum layout_type, int); void layout_close_pane(struct window_pane *); +/* layout-custom.c */ +char *layout_dump(struct window *); +int layout_parse(struct window *, const char *); + /* layout-set.c */ const char *layout_set_name(u_int); int layout_set_lookup(const char *); @@ -1883,6 +1889,7 @@ void layout_set_active_changed(struct window *); /* layout-string.c */ struct layout_cell *layout_find_string(struct window *, const char *); +struct layout_cell *layout_find_bottomright(struct layout_cell *); /* window-clock.c */ extern const struct window_mode window_clock_mode; From b4b9b831ee9f6b1848657939fb19a7b7076d26f4 Mon Sep 17 00:00:00 2001 From: Ted Unangst Date: Tue, 29 Jun 2010 05:24:49 +0000 Subject: [PATCH 0733/1180] replace some magic mouse constants with defines for clarity. ok nicm --- tmux.h | 14 ++++++++++++++ window-copy.c | 19 +++++-------------- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/tmux.h b/tmux.h index 57656773..a6d10a0b 100644 --- a/tmux.h +++ b/tmux.h @@ -1050,9 +1050,23 @@ struct tty_ctx { u_int last_width; }; +/* + * xterm mouse mode is fairly silly. Buttons are in the bottom two + * bits: 0 button 1; 1 button 2; 2 button 3; 3 buttons released. + * + * Bit 3 is shift; bit 4 is meta; bit 5 control. + * + * Bit 6 is added for mouse buttons 4 and 5. + */ /* Mouse input. */ struct mouse_event { u_char b; +#define MOUSE_1 0 +#define MOUSE_2 1 +#define MOUSE_3 2 +#define MOUSE_UP 3 +#define MOUSE_BUTTON 3 +#define MOUSE_45 64 u_char x; u_char y; }; diff --git a/window-copy.c b/window-copy.c index cd94f67f..3324fed3 100644 --- a/window-copy.c +++ b/window-copy.c @@ -762,26 +762,17 @@ window_copy_mouse( struct screen *s = &data->screen; u_int i; - /* - * xterm mouse mode is fairly silly. Buttons are in the bottom two - * bits: 0 button 1; 1 button 2; 2 button 3; 3 buttons released. - * - * Bit 3 is shift; bit 4 is meta; bit 5 control. - * - * Bit 6 is added for mouse buttons 4 and 5. - */ - if (m->x >= screen_size_x(s)) return; if (m->y >= screen_size_y(s)) return; /* If mouse wheel (buttons 4 and 5), scroll. */ - if ((m->b & 64) == 64) { - if ((m->b & 3) == 0) { + if ((m->b & MOUSE_45)) { + if ((m->b & MOUSE_BUTTON) == MOUSE_1) { for (i = 0; i < 5; i++) window_copy_cursor_up(wp, 0); - } else if ((m->b & 3) == 1) { + } else if ((m->b & MOUSE_BUTTON) == MOUSE_2) { for (i = 0; i < 5; i++) window_copy_cursor_down(wp, 0); } @@ -793,7 +784,7 @@ window_copy_mouse( * pressed, or stop the selection on their release. */ if (s->mode & MODE_MOUSEMOTION) { - if ((m->b & 3) != 3) { + if ((m->b & MOUSE_BUTTON) != MOUSE_UP) { window_copy_update_cursor(wp, m->x, m->y); if (window_copy_update_selection(wp)) window_copy_redraw_screen(wp); @@ -808,7 +799,7 @@ window_copy_mouse( } /* Otherwise i other buttons pressed, start selection and motion. */ - if ((m->b & 3) != 3) { + if ((m->b & MOUSE_BUTTON) != MOUSE_UP) { s->mode |= MODE_MOUSEMOTION; window_copy_update_cursor(wp, m->x, m->y); From b9c873cdaa3256f95a007d501fcab8375930bd94 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 11 Jul 2010 17:06:45 +0000 Subject: [PATCH 0734/1180] Return the command client return code with MSG_EXIT now that MSG_ERROR and MSG_PRINT are unused. New clients should be compatible with old tmux servers but vice versa may print an error. --- cmd-if-shell.c | 5 ++++- cmd-run-shell.c | 5 ++++- server-client.c | 20 +++++++++++++------- tmux.c | 14 ++++++++------ tmux.h | 5 +++++ 5 files changed, 34 insertions(+), 15 deletions(-) diff --git a/cmd-if-shell.c b/cmd-if-shell.c index 1779486a..367bb691 100644 --- a/cmd-if-shell.c +++ b/cmd-if-shell.c @@ -104,10 +104,13 @@ cmd_if_shell_free(void *data) { struct cmd_if_shell_data *cdata = data; struct cmd_ctx *ctx = &cdata->ctx; + struct msg_exit_data exitdata; if (ctx->cmdclient != NULL) { ctx->cmdclient->references--; - server_write_client(ctx->cmdclient, MSG_EXIT, NULL, 0); + exitdata.retcode = ctx->cmdclient->retcode; + server_write_client( + ctx->cmdclient, MSG_EXIT, &exitdata, sizeof exitdata); } if (ctx->curclient != NULL) ctx->curclient->references--; diff --git a/cmd-run-shell.c b/cmd-run-shell.c index 3b6844eb..f9d1e237 100644 --- a/cmd-run-shell.c +++ b/cmd-run-shell.c @@ -131,10 +131,13 @@ cmd_run_shell_free(void *data) { struct cmd_run_shell_data *cdata = data; struct cmd_ctx *ctx = &cdata->ctx; + struct msg_exit_data exitdata; if (ctx->cmdclient != NULL) { ctx->cmdclient->references--; - server_write_client(ctx->cmdclient, MSG_EXIT, NULL, 0); + exitdata.retcode = ctx->cmdclient->retcode; + server_write_client( + ctx->cmdclient, MSG_EXIT, &exitdata, sizeof exitdata); } if (ctx->curclient != NULL) ctx->curclient->references--; diff --git a/server-client.c b/server-client.c index c7929fc1..6dc0fd3a 100644 --- a/server-client.c +++ b/server-client.c @@ -664,6 +664,8 @@ server_client_msg_error(struct cmd_ctx *ctx, const char *fmt, ...) fputc('\n', ctx->cmdclient->stderr_file); fflush(ctx->cmdclient->stderr_file); + + ctx->cmdclient->retcode = 1; } /* Callback to send print message to client. */ @@ -701,10 +703,11 @@ server_client_msg_info(struct cmd_ctx *ctx, const char *fmt, ...) void server_client_msg_command(struct client *c, struct msg_command_data *data) { - struct cmd_ctx ctx; - struct cmd_list *cmdlist = NULL; - int argc; - char **argv, *cause; + struct cmd_ctx ctx; + struct cmd_list *cmdlist = NULL; + struct msg_exit_data exitdata; + int argc; + char **argv, *cause; ctx.error = server_client_msg_error; ctx.print = server_client_msg_print; @@ -735,15 +738,18 @@ server_client_msg_command(struct client *c, struct msg_command_data *data) } cmd_free_argv(argc, argv); - if (cmd_list_exec(cmdlist, &ctx) != 1) - server_write_client(c, MSG_EXIT, NULL, 0); + if (cmd_list_exec(cmdlist, &ctx) != 1) { + exitdata.retcode = c->retcode; + server_write_client(c, MSG_EXIT, &exitdata, sizeof exitdata); + } cmd_list_free(cmdlist); return; error: if (cmdlist != NULL) cmd_list_free(cmdlist); - server_write_client(c, MSG_EXIT, NULL, 0); + exitdata.retcode = c->retcode; + server_write_client(c, MSG_EXIT, &exitdata, sizeof exitdata); } /* Handle identify message. */ diff --git a/tmux.c b/tmux.c index 1c9d1cb5..e42e48d3 100644 --- a/tmux.c +++ b/tmux.c @@ -61,7 +61,6 @@ char *makesockpath(const char *); __dead void shell_exec(const char *, const char *); struct imsgbuf *main_ibuf; -int main_exitval; void main_signal(int, short, unused void *); void main_callback(int, short, void *); @@ -548,7 +547,6 @@ main(int argc, char **argv) events |= EV_WRITE; event_once(main_ibuf->fd, events, main_callback, shellcmd, NULL); - main_exitval = 0; event_dispatch(); clear_signals(); @@ -597,6 +595,7 @@ main_dispatch(const char *shellcmd) struct imsg imsg; ssize_t n, datalen; struct msg_shell_data shelldata; + struct msg_exit_data exitdata; if ((n = imsg_read(main_ibuf)) == -1 || n == 0) fatalx("imsg_read failed"); @@ -611,10 +610,13 @@ main_dispatch(const char *shellcmd) switch (imsg.hdr.type) { case MSG_EXIT: case MSG_SHUTDOWN: - if (datalen != 0) - fatalx("bad MSG_EXIT size"); - - exit(main_exitval); + if (datalen != sizeof exitdata) { + if (datalen != 0) + fatalx("bad MSG_EXIT size"); + exit(0); + } + memcpy(&exitdata, imsg.data, sizeof exitdata); + exit(exitdata.retcode); case MSG_READY: if (datalen != 0) fatalx("bad MSG_READY size"); diff --git a/tmux.h b/tmux.h index a6d10a0b..c8e2c13d 100644 --- a/tmux.h +++ b/tmux.h @@ -413,6 +413,10 @@ struct msg_shell_data { char shell[MAXPATHLEN]; }; +struct msg_exit_data { + int retcode; +}; + /* Mode key commands. */ enum mode_key_cmd { MODEKEY_NONE, @@ -1081,6 +1085,7 @@ struct message_entry { struct client { struct imsgbuf ibuf; struct event event; + int retcode; struct timeval creation_time; struct timeval activity_time; From 43355fa75c067e4dda8e4f1aa5370bb3bddc3bf4 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 14 Jul 2010 18:37:49 +0000 Subject: [PATCH 0735/1180] Make pane/window wrapping more logical (so with 10 windows, +10 from window 5 stays in the same place), and tidy the code. From Tiago Cunha. --- cmd.c | 157 +++++++++++++++++++++++++++---------------------------- tmux.h | 10 +++- window.c | 31 +++++++++-- 3 files changed, 113 insertions(+), 85 deletions(-) diff --git a/cmd.c b/cmd.c index 0c9aa8d2..2643bb12 100644 --- a/cmd.c +++ b/cmd.c @@ -117,6 +117,9 @@ struct client *cmd_lookup_client(const char *); struct session *cmd_lookup_session(const char *, int *); struct winlink *cmd_lookup_window(struct session *, const char *, int *); int cmd_lookup_index(struct session *, const char *, int *); +struct winlink *cmd_find_window_offset(const char *, struct session *, int *); +int cmd_find_index_offset(const char *, struct session *, int *); +struct window_pane *cmd_find_pane_offset(const char *, struct winlink *); int cmd_pack_argv(int argc, char **argv, char *buf, size_t len) @@ -661,7 +664,6 @@ cmd_find_window(struct cmd_ctx *ctx, const char *arg, struct session **sp) const char *winptr; char *sessptr = NULL; int ambiguous = 0; - int n = 1; /* * Find the current session. There must always be a current session, if @@ -707,21 +709,9 @@ cmd_find_window(struct cmd_ctx *ctx, const char *arg, struct session **sp) wl = s->curw; else if (winptr[0] == '!' && winptr[1] == '\0') wl = TAILQ_FIRST(&s->lastw); - else if (winptr[0] == '+' || winptr[0] == '-') { - if (winptr[1] != '\0') - n = strtonum(winptr + 1, 1, INT_MAX, NULL); - if (n == 0) - wl = cmd_lookup_window(s, winptr, &ambiguous); - else { - if (winptr[0] == '+') - wl = winlink_next_by_number(s->curw, n); - else - wl = winlink_previous_by_number(s->curw, n); - /* Search by name before giving up. */ - if (wl == NULL) - wl = cmd_lookup_window(s, winptr, &ambiguous); - } - } else + else if (winptr[0] == '+' || winptr[0] == '-') + wl = cmd_find_window_offset(winptr, s, &ambiguous); + else wl = cmd_lookup_window(s, winptr, &ambiguous); if (wl == NULL) goto not_found; @@ -739,20 +729,7 @@ no_colon: if ((wl = TAILQ_FIRST(&s->lastw)) == NULL) goto not_found; } else if (arg[0] == '+' || arg[0] == '-') { - if (arg[1] != '\0') - n = strtonum(arg + 1, 1, INT_MAX, NULL); - if (n == 0) - wl = cmd_lookup_window(s, arg, &ambiguous); - else { - if (arg[0] == '+') - wl = winlink_next_by_number(s->curw, n); - else - wl = winlink_previous_by_number(s->curw, n); - /* Search by name before giving up. */ - if (wl == NULL) - wl = cmd_lookup_window(s, arg, &ambiguous); - } - if (wl == NULL) + if ((wl = cmd_find_window_offset(arg, s, &ambiguous)) == NULL) goto lookup_session; } else if ((wl = cmd_lookup_window(s, arg, &ambiguous)) == NULL) goto lookup_session; @@ -792,6 +769,26 @@ not_found: return (NULL); } +struct winlink * +cmd_find_window_offset(const char *winptr, struct session *s, int *ambiguous) +{ + struct winlink *wl; + int offset = 1; + + if (winptr[1] != '\0') + offset = strtonum(winptr + 1, 1, INT_MAX, NULL); + if (offset == 0) + wl = cmd_lookup_window(s, winptr, ambiguous); + else { + if (winptr[0] == '+') + wl = winlink_next_by_number(s->curw, s, offset); + else + wl = winlink_previous_by_number(s->curw, s, offset); + } + + return (wl); +} + /* * Find the target session and window index, whether or not it exists in the * session. Return -2 on error or -1 if no window index is specified. This is @@ -806,7 +803,6 @@ cmd_find_index(struct cmd_ctx *ctx, const char *arg, struct session **sp) const char *winptr; char *sessptr = NULL; int idx, ambiguous = 0; - int n = 1; /* * Find the current session. There must always be a current session, if @@ -855,19 +851,7 @@ cmd_find_index(struct cmd_ctx *ctx, const char *arg, struct session **sp) goto not_found; idx = wl->idx; } else if (winptr[0] == '+' || winptr[0] == '-') { - if (winptr[1] != '\0') - n = strtonum(winptr + 1, 1, INT_MAX, NULL); - if (winptr[0] == '+' && s->curw->idx == INT_MAX) - idx = cmd_lookup_index(s, winptr, &ambiguous); - else if (winptr[0] == '-' && s->curw->idx == 0) - idx = cmd_lookup_index(s, winptr, &ambiguous); - else if (n == 0) - idx = cmd_lookup_index(s, winptr, &ambiguous); - else if (winptr[0] == '+') - idx = s->curw->idx + n; - else - idx = s->curw->idx - n; - if (idx < 0) + if ((idx = cmd_find_index_offset(winptr, s, &ambiguous)) < 0) goto invalid_index; } else if ((idx = cmd_lookup_index(s, winptr, &ambiguous)) == -1) goto invalid_index; @@ -886,19 +870,7 @@ no_colon: goto not_found; idx = wl->idx; } else if (arg[0] == '+' || arg[0] == '-') { - if (arg[1] != '\0') - n = strtonum(arg + 1, 1, INT_MAX, NULL); - if (arg[0] == '+' && s->curw->idx == INT_MAX) - idx = cmd_lookup_index(s, arg, &ambiguous); - else if (arg[0] == '-' && s->curw->idx == 0) - idx = cmd_lookup_index(s, arg, &ambiguous); - else if (n == 0) - idx = cmd_lookup_index(s, arg, &ambiguous); - else if (arg[0] == '+') - idx = s->curw->idx + n; - else - idx = s->curw->idx - n; - if (idx < 0) + if ((idx = cmd_find_index_offset(arg, s, &ambiguous)) < 0) goto lookup_session; } else if ((idx = cmd_lookup_index(s, arg, &ambiguous)) == -1) goto lookup_session; @@ -947,6 +919,32 @@ not_found: return (-2); } +int +cmd_find_index_offset(const char *winptr, struct session *s, int *ambiguous) +{ + int idx, offset = 1; + + if (winptr[1] != '\0') + offset = strtonum(winptr + 1, 1, INT_MAX, NULL); + if (offset == 0) + idx = cmd_lookup_index(s, winptr, ambiguous); + else { + if (winptr[0] == '+') { + if (s->curw->idx == INT_MAX) + idx = cmd_lookup_index(s, winptr, ambiguous); + else + idx = s->curw->idx + offset; + } else { + if (s->curw->idx == 0) + idx = cmd_lookup_index(s, winptr, ambiguous); + else + idx = s->curw->idx - offset; + } + } + + return (idx); +} + /* * Find the target session, window and pane number or report an error and * return NULL. The pane number is separated from the session:window by a ., @@ -961,7 +959,7 @@ cmd_find_pane(struct cmd_ctx *ctx, struct layout_cell *lc; const char *period, *errstr; char *winptr, *paneptr; - u_int idx, n = 1; + u_int idx; /* Get the current session. */ if ((s = cmd_current_session(ctx)) == NULL) { @@ -993,27 +991,9 @@ cmd_find_pane(struct cmd_ctx *ctx, paneptr = winptr + (period - arg) + 1; if (*paneptr == '\0') *wpp = wl->window->active; - else if (paneptr[0] == '+' || paneptr[0] == '-') { - if (paneptr[1] != '\0') - n = strtonum(paneptr + 1, 1, INT_MAX, NULL); - idx = window_pane_index(wl->window, wl->window->active); - if (paneptr[0] == '+' && idx == INT_MAX) - *wpp = TAILQ_FIRST(&wl->window->panes); - else if (paneptr[0] == '-' && idx == 0) - *wpp = TAILQ_LAST(&wl->window->panes, window_panes); - else if (n == 0) - *wpp = wl->window->active; - else if (paneptr[0] == '+') - *wpp = window_pane_at_index(wl->window, idx + n); - else - *wpp = window_pane_at_index(wl->window, idx - n); - if (paneptr[0] == '+' && *wpp == NULL) - *wpp = TAILQ_FIRST(&wl->window->panes); - else if (paneptr[0] == '-' && *wpp == NULL) - *wpp = TAILQ_LAST(&wl->window->panes, window_panes); - else if (*wpp == NULL) - goto error; - } else { + else if (paneptr[0] == '+' || paneptr[0] == '-') + *wpp = cmd_find_pane_offset(paneptr, wl); + else { idx = strtonum(paneptr, 0, INT_MAX, &errstr); if (errstr != NULL) goto lookup_string; @@ -1065,6 +1045,25 @@ error: return (NULL); } +struct window_pane * +cmd_find_pane_offset(const char *paneptr, struct winlink *wl) +{ + struct window *w = wl->window; + struct window_pane *wp = w->active; + u_int offset = 1; + + if (paneptr[1] != '\0') + offset = strtonum(paneptr + 1, 1, INT_MAX, NULL); + if (offset > 0) { + if (paneptr[0] == '+') + wp = window_pane_next_by_number(w, wp, offset); + else + wp = window_pane_previous_by_number(w, wp, offset); + } + + return (wp); +} + /* Replace the first %% or %idx in template by s. */ char * cmd_template_replace(char *template, const char *s, int idx) diff --git a/tmux.h b/tmux.h index c8e2c13d..8a4ec29d 100644 --- a/tmux.h +++ b/tmux.h @@ -1825,8 +1825,10 @@ struct winlink *winlink_add(struct winlinks *, struct window *, int); void winlink_remove(struct winlinks *, struct winlink *); struct winlink *winlink_next(struct winlink *); struct winlink *winlink_previous(struct winlink *); -struct winlink *winlink_next_by_number(struct winlink *, int); -struct winlink *winlink_previous_by_number(struct winlink *, int); +struct winlink *winlink_next_by_number(struct winlink *, struct session *, + int); +struct winlink *winlink_previous_by_number(struct winlink *, struct session *, + int); void winlink_stack_push(struct winlink_stack *, struct winlink *); void winlink_stack_remove(struct winlink_stack *, struct winlink *); int window_index(struct window *, u_int *); @@ -1841,6 +1843,10 @@ struct window_pane *window_add_pane(struct window *, u_int); void window_resize(struct window *, u_int, u_int); void window_remove_pane(struct window *, struct window_pane *); struct window_pane *window_pane_at_index(struct window *, u_int); +struct window_pane *window_pane_next_by_number(struct window *, + struct window_pane *, u_int); +struct window_pane *window_pane_previous_by_number(struct window *, + struct window_pane *, u_int); u_int window_pane_index(struct window *, struct window_pane *); u_int window_count_panes(struct window *); void window_destroy_panes(struct window *); diff --git a/window.c b/window.c index 320da2a2..70596284 100644 --- a/window.c +++ b/window.c @@ -173,22 +173,22 @@ winlink_previous(struct winlink *wl) } struct winlink * -winlink_next_by_number(struct winlink *wl, int n) +winlink_next_by_number(struct winlink *wl, struct session *s, int n) { for (; n > 0; n--) { if ((wl = RB_NEXT(winlinks, wwl, wl)) == NULL) - break; + wl = RB_MIN(winlinks, &s->windows); } return (wl); } struct winlink * -winlink_previous_by_number(struct winlink *wl, int n) +winlink_previous_by_number(struct winlink *wl, struct session *s, int n) { for (; n > 0; n--) { if ((wl = RB_PREV(winlinks, wwl, wl)) == NULL) - break; + wl = RB_MAX(winlinks, &s->windows); } return (wl); @@ -391,6 +391,29 @@ window_pane_at_index(struct window *w, u_int idx) return (NULL); } +struct window_pane * +window_pane_next_by_number(struct window *w, struct window_pane *wp, u_int n) +{ + for (; n > 0; n--) { + if ((wp = TAILQ_NEXT(wp, entry)) == NULL) + wp = TAILQ_FIRST(&w->panes); + } + + return (wp); +} + +struct window_pane * +window_pane_previous_by_number(struct window *w, struct window_pane *wp, + u_int n) +{ + for (; n > 0; n--) { + if ((wp = TAILQ_PREV(wp, window_panes, entry)) == NULL) + wp = TAILQ_LAST(&w->panes, window_panes); + } + + return (wp); +} + u_int window_pane_index(struct window *w, struct window_pane *wp) { From a471b5de9c4b23b9d0f825066d8d8a93ac6f0cd9 Mon Sep 17 00:00:00 2001 From: Jason McIntyre Date: Thu, 15 Jul 2010 21:54:20 +0000 Subject: [PATCH 0736/1180] some escapes i missed; --- tmux.1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tmux.1 b/tmux.1 index 9252e25a..38f0687f 100644 --- a/tmux.1 +++ b/tmux.1 @@ -254,9 +254,9 @@ Choose which buffer to paste interactively from a list. List all key bindings. .It D Choose a client to detach. -.It [ +.It \&[ Enter copy mode to copy text or view the history. -.It ] +.It \&] Paste the most recently copied buffer of text. .It c Create a new window. From 2a0f3f0d7981fc4fe4739f22f699a5a59a0b2bf8 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 19 Jul 2010 18:27:38 +0000 Subject: [PATCH 0737/1180] Send the \n to stdout with the message, not stderr... doh. --- server-client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server-client.c b/server-client.c index 6dc0fd3a..f594f1e3 100644 --- a/server-client.c +++ b/server-client.c @@ -695,7 +695,7 @@ server_client_msg_info(struct cmd_ctx *ctx, const char *fmt, ...) vfprintf(ctx->cmdclient->stdout_file, fmt, ap); va_end(ap); - fputc('\n', ctx->cmdclient->stderr_file); + fputc('\n', ctx->cmdclient->stdout_file); fflush(ctx->cmdclient->stdout_file); } From 2b80ede9631b8236aa213c730cd6d91805e761f9 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 19 Jul 2010 21:13:03 +0000 Subject: [PATCH 0738/1180] Don't return if in the current window since we may want to report a bell (if bell-action any/current), just clear the flag so the status line doesn't show the bell. --- server-window.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/server-window.c b/server-window.c index 42a4a699..f8bf27d8 100644 --- a/server-window.c +++ b/server-window.c @@ -109,10 +109,8 @@ server_window_check_bell(struct session *s, struct winlink *wl) if (!(w->flags & WINDOW_BELL) || wl->flags & WINLINK_BELL) return (0); - if (s->curw == wl) - return (0); - - wl->flags |= WINLINK_BELL; + if (s->curw != wl) + wl->flags |= WINLINK_BELL; action = options_get_number(&s->options, "bell-action"); switch (action) { From a97b7ad11cc6415a120c08bb6598ec9e0ccc5194 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 22 Jul 2010 21:10:51 +0000 Subject: [PATCH 0739/1180] Fix a crash: if remain-on-exit is set and the pane has exited, the buffers may not be valid, so do not try to disable/enable them when switching to copy mode. --- window-copy.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/window-copy.c b/window-copy.c index 3324fed3..186f018d 100644 --- a/window-copy.c +++ b/window-copy.c @@ -171,7 +171,8 @@ window_copy_init(struct window_pane *wp) data->searchstr = NULL; wp->flags |= PANE_FREEZE; - bufferevent_disable(wp->event, EV_READ|EV_WRITE); + if (wp->fd != -1) + bufferevent_disable(wp->event, EV_READ|EV_WRITE); data->jumptype = WINDOW_COPY_OFF; data->jumpchar = '\0'; @@ -234,7 +235,8 @@ window_copy_free(struct window_pane *wp) struct window_copy_mode_data *data = wp->modedata; wp->flags &= ~PANE_FREEZE; - bufferevent_enable(wp->event, EV_READ|EV_WRITE); + if (wp->fd != -1) + bufferevent_enable(wp->event, EV_READ|EV_WRITE); if (data->searchstr != NULL) xfree(data->searchstr); From bf09b00fe946a06c2f1192bd213f26e5a47889a8 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 24 Jul 2010 19:25:31 +0000 Subject: [PATCH 0740/1180] kqueue(2) is currently broken when used with /dev/null and a few other devices. An upcoming fix for some problems with the client stdout/stderr handling relies on it working, so make tmux force libevent to use poll(2) via EVENT_NOKQUEUE, until we have fixed kqueue. --- server.c | 3 +++ tmux.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/server.c b/server.c index 0a4e2306..e53fc9c7 100644 --- a/server.c +++ b/server.c @@ -139,8 +139,11 @@ server_start(char *path) fatal("daemon failed"); /* event_init() was called in our parent, need to reinit. */ + if (setenv("EVENT_NOKQUEUE", "1", 1) != 0) + fatal("setenv"); if (event_reinit(ev_base) != 0) fatal("event_reinit failed"); + unsetenv("EVENT_NOKQUEUE"); clear_signals(); logfile("server"); diff --git a/tmux.c b/tmux.c index e42e48d3..6edaf8f5 100644 --- a/tmux.c +++ b/tmux.c @@ -532,7 +532,10 @@ main(int argc, char **argv) exit(1); } + if (setenv("EVENT_NOKQUEUE", "1", 1) != 0) + fatal("setenv"); ev_base = event_init(); + unsetenv("EVENT_NOKQUEUE"); set_signals(main_signal); /* Initialise the client socket/start the server. */ From c87187f913f853a650a00ca0328817987298f7d0 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 24 Jul 2010 20:11:59 +0000 Subject: [PATCH 0741/1180] When changing so that the client passes its stdout and stderr as well as stdin up to the server, I forgot one essential point - the tmux server could now be both the producer and consumer. This happens when tmux is run inside tmux, as well as when piping tmux commands together. So, using stdio(3) was a bad idea - if sufficient data was written, this could block in write(2). When that happened and the server was both producer and consumer, it deadlocks. Change to use libevent bufferevents for the client stdin, stdout and stderr instead. This is trivial enough for output but requires a callback mechanism to trigger when stdin is finished. This relies on the underlying polling mechanism for libevent to work with whatever devices to which the user could redirect stdin, stdout or stderr, hence the change to use poll(2) over kqueue(2) for tmux. --- cmd-if-shell.c | 3 +- cmd-load-buffer.c | 108 ++++++++++++++++++++++------ cmd-run-shell.c | 5 +- cmd-save-buffer.c | 24 +++---- server-client.c | 180 +++++++++++++++++++++++++++++++++++----------- server-fn.c | 2 +- tmux.h | 16 +++-- 7 files changed, 250 insertions(+), 88 deletions(-) diff --git a/cmd-if-shell.c b/cmd-if-shell.c index 367bb691..bf60fb23 100644 --- a/cmd-if-shell.c +++ b/cmd-if-shell.c @@ -109,8 +109,7 @@ cmd_if_shell_free(void *data) if (ctx->cmdclient != NULL) { ctx->cmdclient->references--; exitdata.retcode = ctx->cmdclient->retcode; - server_write_client( - ctx->cmdclient, MSG_EXIT, &exitdata, sizeof exitdata); + ctx->cmdclient->flags |= CLIENT_EXIT; } if (ctx->curclient != NULL) ctx->curclient->references--; diff --git a/cmd-load-buffer.c b/cmd-load-buffer.c index 0f118490..e28b9c74 100644 --- a/cmd-load-buffer.c +++ b/cmd-load-buffer.c @@ -31,6 +31,7 @@ */ int cmd_load_buffer_exec(struct cmd *, struct cmd_ctx *); +void cmd_load_buffer_callback(struct client *, void *); const struct cmd_entry cmd_load_buffer_entry = { "load-buffer", "loadb", @@ -43,37 +44,55 @@ const struct cmd_entry cmd_load_buffer_entry = { cmd_buffer_print }; +struct cmd_load_buffer_cdata { + struct session *session; + int buffer; +}; + int cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_buffer_data *data = self->data; - struct session *s; - FILE *f, *close_f; - char *pdata, *new_pdata; - size_t psize; - u_int limit; - int ch; + struct cmd_buffer_data *data = self->data; + struct cmd_load_buffer_cdata *cdata; + struct session *s; + struct client *c = ctx->cmdclient; + FILE *f; + char *pdata, *new_pdata; + size_t psize; + u_int limit; + int ch; if ((s = cmd_find_session(ctx, data->target)) == NULL) return (-1); - if (strcmp(data->arg, "-") == 0 ) { - if (ctx->cmdclient == NULL) { + if (strcmp(data->arg, "-") == 0) { + if (c == NULL) { ctx->error(ctx, "%s: can't read from stdin", data->arg); return (-1); } - f = ctx->cmdclient->stdin_file; - if (isatty(fileno(ctx->cmdclient->stdin_file))) { + if (c->flags & CLIENT_TERMINAL) { ctx->error(ctx, "%s: stdin is a tty", data->arg); return (-1); } - close_f = NULL; - } else { - if ((f = fopen(data->arg, "rb")) == NULL) { - ctx->error(ctx, "%s: %s", data->arg, strerror(errno)); + if (c->stdin_fd == -1) { + ctx->error(ctx, "%s: can't read from stdin", data->arg); return (-1); } - close_f = f; + + cdata = xmalloc(sizeof *cdata); + cdata->session = s; + cdata->buffer = data->buffer; + c->stdin_data = cdata; + c->stdin_callback = cmd_load_buffer_callback; + + c->references++; + bufferevent_enable(c->stdin_event, EV_READ); + return (1); + } + + if ((f = fopen(data->arg, "rb")) == NULL) { + ctx->error(ctx, "%s: %s", data->arg, strerror(errno)); + return (-1); } pdata = NULL; @@ -94,8 +113,8 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) if (pdata != NULL) pdata[psize] = '\0'; - if (close_f != NULL) - fclose(close_f); + fclose(f); + f = NULL; limit = options_get_number(&s->options, "buffer-limit"); if (data->buffer == -1) { @@ -104,7 +123,7 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) } if (paste_replace(&s->buffers, data->buffer, pdata, psize) != 0) { ctx->error(ctx, "no buffer %d", data->buffer); - goto error; + return (-1); } return (0); @@ -112,7 +131,54 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) error: if (pdata != NULL) xfree(pdata); - if (close_f != NULL) - fclose(close_f); + if (f != NULL) + fclose(f); return (-1); } + +void +cmd_load_buffer_callback(struct client *c, void *data) +{ + struct cmd_load_buffer_cdata *cdata = data; + struct session *s = cdata->session; + char *pdata; + size_t psize; + u_int limit; + int idx; + + /* + * Event callback has already checked client is not dead and reduced + * its reference count. But tell it to exit. + */ + c->flags |= CLIENT_EXIT; + + /* Does the target session still exist? */ + if (session_index(s, &idx) != 0) + goto out; + + psize = EVBUFFER_LENGTH(c->stdin_event->input); + if (psize == 0) + goto out; + + pdata = malloc(psize + 1); + if (pdata == NULL) + goto out; + bufferevent_read(c->stdin_event, pdata, psize); + pdata[psize] = '\0'; + + limit = options_get_number(&s->options, "buffer-limit"); + if (cdata->buffer == -1) { + paste_add(&s->buffers, pdata, psize, limit); + goto out; + } + if (paste_replace(&s->buffers, cdata->buffer, pdata, psize) != 0) { + /* No context so can't use server_client_msg_error. */ + evbuffer_add_printf( + c->stderr_event->output, "no buffer %d\n", cdata->buffer); + bufferevent_enable(c->stderr_event, EV_WRITE); + goto out; + } + +out: + xfree(cdata); +} diff --git a/cmd-run-shell.c b/cmd-run-shell.c index f9d1e237..7bfb8916 100644 --- a/cmd-run-shell.c +++ b/cmd-run-shell.c @@ -131,13 +131,10 @@ cmd_run_shell_free(void *data) { struct cmd_run_shell_data *cdata = data; struct cmd_ctx *ctx = &cdata->ctx; - struct msg_exit_data exitdata; if (ctx->cmdclient != NULL) { ctx->cmdclient->references--; - exitdata.retcode = ctx->cmdclient->retcode; - server_write_client( - ctx->cmdclient, MSG_EXIT, &exitdata, sizeof exitdata); + ctx->cmdclient->flags |= CLIENT_EXIT; } if (ctx->curclient != NULL) ctx->curclient->references--; diff --git a/cmd-save-buffer.c b/cmd-save-buffer.c index 57c3f5f0..1d287cd2 100644 --- a/cmd-save-buffer.c +++ b/cmd-save-buffer.c @@ -47,8 +47,8 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) struct cmd_buffer_data *data = self->data; struct session *s; struct paste_buffer *pb; - mode_t mask; - FILE *f, *close_f; + mode_t mask; + FILE *f; if ((s = cmd_find_session(ctx, data->target)) == NULL) return (-1); @@ -70,8 +70,8 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) ctx->error(ctx, "%s: can't write to stdout", data->arg); return (-1); } - f = ctx->cmdclient->stdout_file; - close_f = NULL; + bufferevent_write( + ctx->cmdclient->stdout_event, pb->data, pb->size); } else { mask = umask(S_IRWXG | S_IRWXO); if (cmd_check_flag(data->chflags, 'a')) @@ -83,17 +83,13 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) ctx->error(ctx, "%s: %s", data->arg, strerror(errno)); return (-1); } - close_f = f; + if (fwrite(pb->data, 1, pb->size, f) != pb->size) { + ctx->error(ctx, "%s: fwrite error", data->arg); + fclose(f); + return (-1); + } + fclose(f); } - if (fwrite(pb->data, 1, pb->size, f) != pb->size) { - ctx->error(ctx, "%s: fwrite error", data->arg); - fclose(f); - return (-1); - } - - if (close_f != NULL) - fclose(close_f); - return (0); } diff --git a/server-client.c b/server-client.c index f594f1e3..a27089b4 100644 --- a/server-client.c +++ b/server-client.c @@ -29,9 +29,13 @@ void server_client_handle_key(int, struct mouse_event *, void *); void server_client_repeat_timer(int, short, void *); +void server_client_check_exit(struct client *); void server_client_check_redraw(struct client *); void server_client_set_title(struct client *); void server_client_reset_state(struct client *); +void server_client_in_callback(struct bufferevent *, short, void *); +void server_client_out_callback(struct bufferevent *, short, void *); +void server_client_err_callback(struct bufferevent *, short, void *); int server_client_msg_dispatch(struct client *); void server_client_msg_command(struct client *, struct msg_command_data *); @@ -69,9 +73,9 @@ server_client_create(int fd) ARRAY_INIT(&c->prompt_hdata); - c->stdin_file = NULL; - c->stdout_file = NULL; - c->stderr_file = NULL; + c->stdin_event = NULL; + c->stdout_event = NULL; + c->stderr_event = NULL; c->tty.fd = -1; c->title = NULL; @@ -122,12 +126,18 @@ server_client_lost(struct client *c) if (c->flags & CLIENT_TERMINAL) tty_free(&c->tty); - if (c->stdin_file != NULL) - fclose(c->stdin_file); - if (c->stdout_file != NULL) - fclose(c->stdout_file); - if (c->stderr_file != NULL) - fclose(c->stderr_file); + if (c->stdin_fd != -1) + close(c->stdin_fd); + if (c->stdin_event != NULL) + bufferevent_free(c->stdin_event); + if (c->stdout_fd != -1) + close(c->stdout_fd); + if (c->stdout_event != NULL) + bufferevent_free(c->stdout_event); + if (c->stderr_fd != -1) + close(c->stderr_fd); + if (c->stderr_event != NULL) + bufferevent_free(c->stderr_event); screen_free(&c->status); job_tree_free(&c->status_jobs); @@ -390,11 +400,14 @@ server_client_loop(void) for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); - if (c == NULL || c->session == NULL) + if (c == NULL) continue; - server_client_check_redraw(c); - server_client_reset_state(c); + server_client_check_exit(c); + if (c->session != NULL) { + server_client_check_redraw(c); + server_client_reset_state(c); + } } /* @@ -457,6 +470,28 @@ server_client_repeat_timer(unused int fd, unused short events, void *data) c->flags &= ~(CLIENT_PREFIX|CLIENT_REPEAT); } +/* Check if client should be exited. */ +void +server_client_check_exit(struct client *c) +{ + struct msg_exit_data exitdata; + + if (!(c->flags & CLIENT_EXIT)) + return; + + if (c->stdout_fd != -1 && c->stdout_event != NULL && + EVBUFFER_LENGTH(c->stdout_event->output) != 0) + return; + if (c->stderr_fd != -1 && c->stderr_event != NULL && + EVBUFFER_LENGTH(c->stderr_event->output) != 0) + return; + + exitdata.retcode = c->retcode; + server_write_client(c, MSG_EXIT, &exitdata, sizeof exitdata); + + c->flags &= ~CLIENT_EXIT; +} + /* Check for client redraws. */ void server_client_check_redraw(struct client *c) @@ -523,6 +558,52 @@ server_client_set_title(struct client *c) xfree(title); } +/* + * Error callback for client stdin. Caller must increase reference count when + * enabling event! + */ +void +server_client_in_callback( + unused struct bufferevent *bufev, unused short what, void *data) +{ + struct client *c = data; + + c->references--; + if (c->flags & CLIENT_DEAD) + return; + + bufferevent_disable(c->stdin_event, EV_READ|EV_WRITE); + close(c->stdin_fd); + c->stdin_fd = -1; + + if (c->stdin_callback != NULL) + c->stdin_callback(c, c->stdin_data); +} + +/* Error callback for client stdout. */ +void +server_client_out_callback( + unused struct bufferevent *bufev, unused short what, unused void *data) +{ + struct client *c = data; + + bufferevent_disable(c->stdout_event, EV_READ|EV_WRITE); + close(c->stdout_fd); + c->stdout_fd = -1; +} + +/* Error callback for client stderr. */ +void +server_client_err_callback( + unused struct bufferevent *bufev, unused short what, unused void *data) +{ + struct client *c = data; + + bufferevent_disable(c->stderr_event, EV_READ|EV_WRITE); + close(c->stderr_fd); + c->stderr_fd = -1; +} + /* Dispatch message from client. */ int server_client_msg_dispatch(struct client *c) @@ -532,6 +613,7 @@ server_client_msg_dispatch(struct client *c) struct msg_identify_data identifydata; struct msg_environ_data environdata; ssize_t n, datalen; + int mode; if ((n = imsg_read(&c->ibuf)) == -1 || n == 0) return (-1); @@ -566,9 +648,17 @@ server_client_msg_dispatch(struct client *c) fatalx("MSG_IDENTIFY missing fd"); memcpy(&identifydata, imsg.data, sizeof identifydata); - c->stdin_file = fdopen(imsg.fd, "r"); - if (c->stdin_file == NULL) - fatal("fdopen(stdin) failed"); + c->stdin_fd = imsg.fd; + c->stdin_event = bufferevent_new(imsg.fd, NULL, NULL, + server_client_in_callback, c); + if (c->stdin_event == NULL) + fatalx("failed to create stdin event"); + + if ((mode = fcntl(imsg.fd, F_GETFL)) != -1) + fcntl(imsg.fd, F_SETFL, mode|O_NONBLOCK); + if (fcntl(imsg.fd, F_SETFD, FD_CLOEXEC) == -1) + fatal("fcntl failed"); + server_client_msg_identify(c, &identifydata, imsg.fd); break; case MSG_STDOUT: @@ -577,9 +667,16 @@ server_client_msg_dispatch(struct client *c) if (imsg.fd == -1) fatalx("MSG_STDOUT missing fd"); - c->stdout_file = fdopen(imsg.fd, "w"); - if (c->stdout_file == NULL) - fatal("fdopen(stdout) failed"); + c->stdout_fd = imsg.fd; + c->stdout_event = bufferevent_new(imsg.fd, NULL, NULL, + server_client_out_callback, c); + if (c->stdout_event == NULL) + fatalx("failed to create stdout event"); + + if ((mode = fcntl(imsg.fd, F_GETFL)) != -1) + fcntl(imsg.fd, F_SETFL, mode|O_NONBLOCK); + if (fcntl(imsg.fd, F_SETFD, FD_CLOEXEC) == -1) + fatal("fcntl failed"); break; case MSG_STDERR: if (datalen != 0) @@ -587,9 +684,16 @@ server_client_msg_dispatch(struct client *c) if (imsg.fd == -1) fatalx("MSG_STDERR missing fd"); - c->stderr_file = fdopen(imsg.fd, "w"); - if (c->stderr_file == NULL) - fatal("fdopen(stderr) failed"); + c->stderr_fd = imsg.fd; + c->stderr_event = bufferevent_new(imsg.fd, NULL, NULL, + server_client_err_callback, c); + if (c->stderr_event == NULL) + fatalx("failed to create stderr event"); + + if ((mode = fcntl(imsg.fd, F_GETFL)) != -1) + fcntl(imsg.fd, F_SETFL, mode|O_NONBLOCK); + if (fcntl(imsg.fd, F_SETFD, FD_CLOEXEC) == -1) + fatal("fcntl failed"); break; case MSG_RESIZE: if (datalen != 0) @@ -659,12 +763,10 @@ server_client_msg_error(struct cmd_ctx *ctx, const char *fmt, ...) va_list ap; va_start(ap, fmt); - vfprintf(ctx->cmdclient->stderr_file, fmt, ap); + evbuffer_add_vprintf(ctx->cmdclient->stderr_event->output, fmt, ap); va_end(ap); - fputc('\n', ctx->cmdclient->stderr_file); - fflush(ctx->cmdclient->stderr_file); - + bufferevent_write(ctx->cmdclient->stderr_event, "\n", 1); ctx->cmdclient->retcode = 1; } @@ -675,11 +777,10 @@ server_client_msg_print(struct cmd_ctx *ctx, const char *fmt, ...) va_list ap; va_start(ap, fmt); - vfprintf(ctx->cmdclient->stdout_file, fmt, ap); + evbuffer_add_vprintf(ctx->cmdclient->stdout_event->output, fmt, ap); va_end(ap); - fputc('\n', ctx->cmdclient->stdout_file); - fflush(ctx->cmdclient->stdout_file); + bufferevent_write(ctx->cmdclient->stdout_event, "\n", 1); } /* Callback to send print message to client, if not quiet. */ @@ -692,22 +793,20 @@ server_client_msg_info(struct cmd_ctx *ctx, const char *fmt, ...) return; va_start(ap, fmt); - vfprintf(ctx->cmdclient->stdout_file, fmt, ap); + evbuffer_add_vprintf(ctx->cmdclient->stdout_event->output, fmt, ap); va_end(ap); - fputc('\n', ctx->cmdclient->stdout_file); - fflush(ctx->cmdclient->stdout_file); + bufferevent_write(ctx->cmdclient->stdout_event, "\n", 1); } /* Handle command message. */ void server_client_msg_command(struct client *c, struct msg_command_data *data) { - struct cmd_ctx ctx; - struct cmd_list *cmdlist = NULL; - struct msg_exit_data exitdata; - int argc; - char **argv, *cause; + struct cmd_ctx ctx; + struct cmd_list *cmdlist = NULL; + int argc; + char **argv, *cause; ctx.error = server_client_msg_error; ctx.print = server_client_msg_print; @@ -738,18 +837,15 @@ server_client_msg_command(struct client *c, struct msg_command_data *data) } cmd_free_argv(argc, argv); - if (cmd_list_exec(cmdlist, &ctx) != 1) { - exitdata.retcode = c->retcode; - server_write_client(c, MSG_EXIT, &exitdata, sizeof exitdata); - } + if (cmd_list_exec(cmdlist, &ctx) != 1) + c->flags |= CLIENT_EXIT; cmd_list_free(cmdlist); return; error: if (cmdlist != NULL) cmd_list_free(cmdlist); - exitdata.retcode = c->retcode; - server_write_client(c, MSG_EXIT, &exitdata, sizeof exitdata); + c->flags |= CLIENT_EXIT; } /* Handle identify message. */ diff --git a/server-fn.c b/server-fn.c index 74452fe8..4ecbce9e 100644 --- a/server-fn.c +++ b/server-fn.c @@ -395,7 +395,7 @@ server_destroy_session(struct session *s) continue; if (s_new == NULL) { c->session = NULL; - server_write_client(c, MSG_EXIT, NULL, 0); + c->flags |= CLIENT_EXIT; } else { c->session = s_new; server_redraw_client(c); diff --git a/tmux.h b/tmux.h index 8a4ec29d..e1cd0b7e 100644 --- a/tmux.h +++ b/tmux.h @@ -1096,9 +1096,17 @@ struct client { char *cwd; struct tty tty; - FILE *stdin_file; - FILE *stdout_file; - FILE *stderr_file; + + int stdin_fd; + void *stdin_data; + void (*stdin_callback)(struct client *, void *); + struct bufferevent *stdin_event; + + int stdout_fd; + struct bufferevent *stdout_event; + + int stderr_fd; + struct bufferevent *stderr_event; struct event repeat_timer; @@ -1108,7 +1116,7 @@ struct client { #define CLIENT_TERMINAL 0x1 #define CLIENT_PREFIX 0x2 -/* 0x4 unused */ +#define CLIENT_EXIT 0x4 #define CLIENT_REDRAW 0x8 #define CLIENT_STATUS 0x10 #define CLIENT_REPEAT 0x20 /* allow command to repeat within repeat time */ From 77f9c49829fa6c9f33f14ed7cf43ecb4827b54bc Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 28 Jul 2010 22:15:15 +0000 Subject: [PATCH 0742/1180] dup() the stdin fd so it isn't closed twice (once for stdin, once for tty). --- server-client.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/server-client.c b/server-client.c index a27089b4..b8ccbeff 100644 --- a/server-client.c +++ b/server-client.c @@ -648,9 +648,11 @@ server_client_msg_dispatch(struct client *c) fatalx("MSG_IDENTIFY missing fd"); memcpy(&identifydata, imsg.data, sizeof identifydata); - c->stdin_fd = imsg.fd; - c->stdin_event = bufferevent_new(imsg.fd, NULL, NULL, - server_client_in_callback, c); + c->stdin_fd = dup(imsg.fd); + if (c->stdin_fd == -1) + fatal("dup failed"); + c->stdin_event = bufferevent_new(c->stdin_fd, + NULL, NULL, server_client_in_callback, c); if (c->stdin_event == NULL) fatalx("failed to create stdin event"); @@ -668,14 +670,14 @@ server_client_msg_dispatch(struct client *c) fatalx("MSG_STDOUT missing fd"); c->stdout_fd = imsg.fd; - c->stdout_event = bufferevent_new(imsg.fd, NULL, NULL, - server_client_out_callback, c); + c->stdout_event = bufferevent_new(c->stdout_fd, + NULL, NULL, server_client_out_callback, c); if (c->stdout_event == NULL) fatalx("failed to create stdout event"); - if ((mode = fcntl(imsg.fd, F_GETFL)) != -1) - fcntl(imsg.fd, F_SETFL, mode|O_NONBLOCK); - if (fcntl(imsg.fd, F_SETFD, FD_CLOEXEC) == -1) + if ((mode = fcntl(c->stdout_fd, F_GETFL)) != -1) + fcntl(c->stdout_fd, F_SETFL, mode|O_NONBLOCK); + if (fcntl(c->stdout_fd, F_SETFD, FD_CLOEXEC) == -1) fatal("fcntl failed"); break; case MSG_STDERR: @@ -685,14 +687,14 @@ server_client_msg_dispatch(struct client *c) fatalx("MSG_STDERR missing fd"); c->stderr_fd = imsg.fd; - c->stderr_event = bufferevent_new(imsg.fd, NULL, NULL, - server_client_err_callback, c); + c->stderr_event = bufferevent_new(c->stderr_fd, + NULL, NULL, server_client_err_callback, c); if (c->stderr_event == NULL) fatalx("failed to create stderr event"); - if ((mode = fcntl(imsg.fd, F_GETFL)) != -1) - fcntl(imsg.fd, F_SETFL, mode|O_NONBLOCK); - if (fcntl(imsg.fd, F_SETFD, FD_CLOEXEC) == -1) + if ((mode = fcntl(c->stderr_fd, F_GETFL)) != -1) + fcntl(c->stderr_fd, F_SETFL, mode|O_NONBLOCK); + if (fcntl(c->stderr_fd, F_SETFD, FD_CLOEXEC) == -1) fatal("fcntl failed"); break; case MSG_RESIZE: From 4274a7ec89fbf2a0f8417f97d37f8cc8c5e3e156 Mon Sep 17 00:00:00 2001 From: Theo Deraadt Date: Wed, 4 Aug 2010 19:46:13 +0000 Subject: [PATCH 0743/1180] switch back to kqueue for now, since (a) kqueue has been fixed to deal with strange devices and (b) since there appears to be a bull in the poll code in libevent as well... requested by nicm who is away --- server.c | 3 --- tmux.c | 3 --- 2 files changed, 6 deletions(-) diff --git a/server.c b/server.c index e53fc9c7..0a4e2306 100644 --- a/server.c +++ b/server.c @@ -139,11 +139,8 @@ server_start(char *path) fatal("daemon failed"); /* event_init() was called in our parent, need to reinit. */ - if (setenv("EVENT_NOKQUEUE", "1", 1) != 0) - fatal("setenv"); if (event_reinit(ev_base) != 0) fatal("event_reinit failed"); - unsetenv("EVENT_NOKQUEUE"); clear_signals(); logfile("server"); diff --git a/tmux.c b/tmux.c index 6edaf8f5..e42e48d3 100644 --- a/tmux.c +++ b/tmux.c @@ -532,10 +532,7 @@ main(int argc, char **argv) exit(1); } - if (setenv("EVENT_NOKQUEUE", "1", 1) != 0) - fatal("setenv"); ev_base = event_init(); - unsetenv("EVENT_NOKQUEUE"); set_signals(main_signal); /* Initialise the client socket/start the server. */ From 933dc48de356e387c0c027e654e1ae5f2f24c711 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 11 Aug 2010 07:27:50 +0000 Subject: [PATCH 0744/1180] Show which pane is active in the list-panes output, suggested by Dominik Honnef. --- cmd-list-panes.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cmd-list-panes.c b/cmd-list-panes.c index ffb89787..ba70faa1 100644 --- a/cmd-list-panes.c +++ b/cmd-list-panes.c @@ -65,8 +65,9 @@ cmd_list_panes_exec(struct cmd *self, struct cmd_ctx *ctx) } size += gd->hsize * sizeof *gd->linedata; - ctx->print(ctx, "%u: [%ux%u] [history %u/%u, %llu bytes]", - n, wp->sx, wp->sy, gd->hsize, gd->hlimit, size); + ctx->print(ctx, "%u: [%ux%u] [history %u/%u, %llu bytes]%s", + n, wp->sx, wp->sy, gd->hsize, gd->hlimit, size, + wp == wp->window->active ? " (active)" : ""); n++; } From 8363e31953a346b3cd4141bf30a8d79d37ca2674 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 11 Aug 2010 07:34:43 +0000 Subject: [PATCH 0745/1180] Change the way backoff works. Instead of stopping reading from the pty when the client tty backs up too much, just stop updating the tty and only update the internal screen. Then when the tty recovers, force a redraw. This prevents a dodgy client from causing other clients to go into backoff while still allowing tmux to be responsive (locally) when seeing lots of output. --- server-client.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ server-window.c | 36 ------------------------------------ tmux.h | 7 +++++-- tty.c | 4 +++- 4 files changed, 56 insertions(+), 39 deletions(-) diff --git a/server-client.c b/server-client.c index b8ccbeff..059a5c89 100644 --- a/server-client.c +++ b/server-client.c @@ -492,6 +492,50 @@ server_client_check_exit(struct client *c) c->flags &= ~CLIENT_EXIT; } +/* + * Check if the client should backoff. During backoff, data from external + * programs is not written to the terminal. When the existing data drains, the + * client is redrawn. + * + * There are two backoff phases - both the tty and client have backoff flags - + * the first to allow existing data to drain and the latter to ensure backoff + * is disabled until the redraw has finished and prevent the redraw triggering + * another backoff. + */ +void +server_client_check_backoff(struct client *c) +{ + struct tty *tty = &c->tty; + size_t used; + + used = EVBUFFER_LENGTH(tty->event->output); + + /* + * If in the second backoff phase (redrawing), don't check backoff + * until the redraw has completed (or enough of it to drop below the + * backoff threshold). + */ + if (c->flags & CLIENT_BACKOFF) { + if (used > BACKOFF_THRESHOLD) + return; + c->flags &= ~CLIENT_BACKOFF; + return; + } + + /* Once drained, allow data through again and schedule redraw. */ + if (tty->flags & TTY_BACKOFF) { + if (used != 0) + return; + tty->flags &= ~TTY_BACKOFF; + c->flags |= (CLIENT_BACKOFF|CLIENT_REDRAWWINDOW|CLIENT_STATUS); + return; + } + + /* If too much data, start backoff. */ + if (used > BACKOFF_THRESHOLD) + tty->flags |= TTY_BACKOFF; +} + /* Check for client redraws. */ void server_client_check_redraw(struct client *c) @@ -520,6 +564,10 @@ server_client_check_redraw(struct client *c) if (c->flags & CLIENT_REDRAW) { screen_redraw_screen(c, 0, 0); c->flags &= ~(CLIENT_STATUS|CLIENT_BORDERS); + } else if (c->flags & CLIENT_REDRAWWINDOW) { + TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry) + screen_redraw_pane(c, wp); + c->flags &= ~CLIENT_REDRAWWINDOW; } else { TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry) { if (wp->flags & PANE_REDRAW) diff --git a/server-window.c b/server-window.c index f8bf27d8..634a1b8a 100644 --- a/server-window.c +++ b/server-window.c @@ -29,31 +29,6 @@ int server_window_check_activity(struct session *, struct winlink *); int server_window_check_content( struct session *, struct winlink *, struct window_pane *); -/* Check if this window should suspend reading. */ -int -server_window_backoff(struct window_pane *wp) -{ - struct client *c; - u_int i; - - if (!window_pane_visible(wp)) - return (0); - - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - c = ARRAY_ITEM(&clients, i); - if (c == NULL || c->session == NULL) - continue; - if ((c->flags & (CLIENT_SUSPENDED|CLIENT_DEAD)) != 0) - continue; - if (c->session->curw->window != wp->window) - continue; - - if (EVBUFFER_LENGTH(c->tty.event->output) > BACKOFF_THRESHOLD) - return (1); - } - return (0); -} - /* Window functions that need to happen every loop. */ void server_window_loop(void) @@ -69,17 +44,6 @@ server_window_loop(void) if (w == NULL) continue; - TAILQ_FOREACH(wp, &w->panes, entry) { - if (wp->fd == -1) - continue; - if (!(wp->flags & PANE_FREEZE)) { - if (server_window_backoff(wp)) - bufferevent_disable(wp->event, EV_READ); - else - bufferevent_enable(wp->event, EV_READ); - } - } - for (j = 0; j < ARRAY_LENGTH(&sessions); j++) { s = ARRAY_ITEM(&sessions, j); if (s == NULL) diff --git a/tmux.h b/tmux.h index e1cd0b7e..af731ff7 100644 --- a/tmux.h +++ b/tmux.h @@ -59,8 +59,8 @@ extern char **environ; /* Automatic name refresh interval, in milliseconds. */ #define NAME_INTERVAL 500 -/* Maximum data to buffer for output before suspending reading from panes. */ -#define BACKOFF_THRESHOLD 1024 +/* Maximum data to buffer for output before suspending writing to a tty. */ +#define BACKOFF_THRESHOLD 16384 /* * Maximum sizes of strings in message data. Don't forget to bump @@ -1017,6 +1017,7 @@ struct tty { #define TTY_UTF8 0x8 #define TTY_STARTED 0x10 #define TTY_OPENED 0x20 +#define TTY_BACKOFF 0x40 int flags; int term_flags; @@ -1126,6 +1127,8 @@ struct client { #define CLIENT_DEAD 0x200 #define CLIENT_BORDERS 0x400 #define CLIENT_READONLY 0x800 +#define CLIENT_BACKOFF 0x1000 +#define CLIENT_REDRAWWINDOW 0x2000 int flags; struct event identify_timer; diff --git a/tty.c b/tty.c index fa2cd552..bf0a48b0 100644 --- a/tty.c +++ b/tty.c @@ -578,7 +578,9 @@ tty_write(void (*cmdfn)( continue; if (c->session->curw->window == wp->window) { - if (c->tty.flags & TTY_FREEZE || c->tty.term == NULL) + if (c->tty.term == NULL) + continue; + if (c->tty.flags & (TTY_FREEZE|TTY_BACKOFF)) continue; cmdfn(&c->tty, ctx); } From cc474b4ede4644a417f838efe2cc53c6a73028e4 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 11 Aug 2010 07:36:23 +0000 Subject: [PATCH 0746/1180] Treat trying to link or move to the same window as an error to avoid removing it accidentally. --- server-fn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server-fn.c b/server-fn.c index 4ecbce9e..03c89cf5 100644 --- a/server-fn.c +++ b/server-fn.c @@ -281,7 +281,7 @@ server_link_window(struct session *src, struct winlink *srcwl, dstwl = winlink_find_by_index(&dst->windows, dstidx); if (dstwl != NULL) { if (dstwl->window == srcwl->window) - return (0); + return (-1); if (killflag) { /* * Can't use session_detach as it will destroy session From 399988690149acc84d0d971cf632e1be12341a8c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 11 Aug 2010 07:38:00 +0000 Subject: [PATCH 0747/1180] Usage string fixes from Ben Boeckel. --- cmd-join-pane.c | 2 +- cmd-paste-buffer.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd-join-pane.c b/cmd-join-pane.c index acf9b754..d13c23e3 100644 --- a/cmd-join-pane.c +++ b/cmd-join-pane.c @@ -45,7 +45,7 @@ struct cmd_join_pane_data { const struct cmd_entry cmd_join_pane_entry = { "join-pane", "joinp", - "[-dhv] [-p percentage|-l size] [-s src-pane] [-t dst-pane] [command]", + "[-dhv] [-p percentage|-l size] [-s src-pane] [-t dst-pane]", 0, "", cmd_join_pane_init, cmd_join_pane_parse, diff --git a/cmd-paste-buffer.c b/cmd-paste-buffer.c index 0b9b3926..75d9373f 100644 --- a/cmd-paste-buffer.c +++ b/cmd-paste-buffer.c @@ -46,7 +46,7 @@ size_t cmd_paste_buffer_print(struct cmd *, char *, size_t); const struct cmd_entry cmd_paste_buffer_entry = { "paste-buffer", "pasteb", - "[-dr] [-s separator] [-b buffer-index] [-t target-window]", + "[-dr] [-s separator] [-b buffer-index] [-t target-pane]", 0, "", cmd_paste_buffer_init, cmd_paste_buffer_parse, From ae70071494a297a8a37518baadaabaf0bd44775b Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 11 Aug 2010 07:41:05 +0000 Subject: [PATCH 0748/1180] Handle failure to change mode, to avoid dying when switching into copy mode when already in a different mode. Reported by "Florian". --- cmd-copy-mode.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmd-copy-mode.c b/cmd-copy-mode.c index 714ec35f..3e858a33 100644 --- a/cmd-copy-mode.c +++ b/cmd-copy-mode.c @@ -62,7 +62,8 @@ cmd_copy_mode_exec(struct cmd *self, struct cmd_ctx *ctx) if (cmd_find_pane(ctx, data->target, NULL, &wp) == NULL) return (-1); - window_pane_set_mode(wp, &window_copy_mode); + if (window_pane_set_mode(wp, &window_copy_mode) != 0) + return (0); window_copy_init_from_pane(wp); if (wp->mode == &window_copy_mode && cmd_check_flag(data->chflags, 'u')) window_copy_pageup(wp); From 828f12b74876e9cc51fc60ab59f397d697f7041c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 11 Aug 2010 07:45:06 +0000 Subject: [PATCH 0749/1180] Do not allow duplicate session names to be created, reported by Dominik Honnef, patch from Thomas Adam. --- cmd-rename-session.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cmd-rename-session.c b/cmd-rename-session.c index 679c6109..0b674ce0 100644 --- a/cmd-rename-session.c +++ b/cmd-rename-session.c @@ -45,6 +45,11 @@ cmd_rename_session_exec(struct cmd *self, struct cmd_ctx *ctx) struct cmd_target_data *data = self->data; struct session *s; + if (data->arg != NULL && session_find(data->arg) != NULL) { + ctx->error(ctx, "duplicate session: %s", data->arg); + return (-1); + } + if ((s = cmd_find_session(ctx, data->target)) == NULL) return (-1); From c2822ca119d9270f9193eaa574d9b157772b77ed Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 19 Aug 2010 17:20:26 +0000 Subject: [PATCH 0750/1180] Do not need to dup() the tty fd sent from the client because it is already dup()d again later. Fixes a leak seen by espie@. --- server-client.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/server-client.c b/server-client.c index 059a5c89..695c4e48 100644 --- a/server-client.c +++ b/server-client.c @@ -696,17 +696,15 @@ server_client_msg_dispatch(struct client *c) fatalx("MSG_IDENTIFY missing fd"); memcpy(&identifydata, imsg.data, sizeof identifydata); - c->stdin_fd = dup(imsg.fd); - if (c->stdin_fd == -1) - fatal("dup failed"); + c->stdin_fd = imsg.fd; c->stdin_event = bufferevent_new(c->stdin_fd, NULL, NULL, server_client_in_callback, c); if (c->stdin_event == NULL) fatalx("failed to create stdin event"); - if ((mode = fcntl(imsg.fd, F_GETFL)) != -1) - fcntl(imsg.fd, F_SETFL, mode|O_NONBLOCK); - if (fcntl(imsg.fd, F_SETFD, FD_CLOEXEC) == -1) + if ((mode = fcntl(c->stdin_fd, F_GETFL)) != -1) + fcntl(c->stdin_fd, F_SETFL, mode|O_NONBLOCK); + if (fcntl(c->stdin_fd, F_SETFD, FD_CLOEXEC) == -1) fatal("fcntl failed"); server_client_msg_identify(c, &identifydata, imsg.fd); From e3be9b1951856f84d30c2903eccdf792618f71ba Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 19 Aug 2010 18:29:01 +0000 Subject: [PATCH 0751/1180] Do not call event_del() for signals after fork(), just use sigaction() directly instead - calling libevent functions after fork() w/o event_reinit() is a bad idea, even if in this case it was harmless. --- cmd-pipe-pane.c | 2 +- job.c | 2 +- server.c | 2 +- signal.c | 29 ++++++++++++++++++++++------- tmux.c | 4 ++-- tmux.h | 4 ++-- window.c | 2 +- 7 files changed, 30 insertions(+), 15 deletions(-) diff --git a/cmd-pipe-pane.c b/cmd-pipe-pane.c index edc624dd..be6f8e25 100644 --- a/cmd-pipe-pane.c +++ b/cmd-pipe-pane.c @@ -97,7 +97,7 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx) case 0: /* Child process. */ close(pipe_fd[0]); - clear_signals(); + clear_signals(1); if (dup2(pipe_fd[1], STDIN_FILENO) == -1) _exit(1); diff --git a/job.c b/job.c index 61aa61fa..e0dc99ef 100644 --- a/job.c +++ b/job.c @@ -149,7 +149,7 @@ job_run(struct job *job) case -1: return (-1); case 0: /* child */ - clear_signals(); + clear_signals(1); environ_push(&global_environ); diff --git a/server.c b/server.c index 0a4e2306..96bafb54 100644 --- a/server.c +++ b/server.c @@ -141,7 +141,7 @@ server_start(char *path) /* event_init() was called in our parent, need to reinit. */ if (event_reinit(ev_base) != 0) fatal("event_reinit failed"); - clear_signals(); + clear_signals(0); logfile("server"); log_debug("server started, pid %ld", (long) getpid()); diff --git a/signal.c b/signal.c index 75f80b51..f9546dc5 100644 --- a/signal.c +++ b/signal.c @@ -62,7 +62,7 @@ set_signals(void(*handler)(int, short, unused void *)) } void -clear_signals(void) +clear_signals(int after_fork) { struct sigaction sigact; @@ -79,10 +79,25 @@ clear_signals(void) if (sigaction(SIGTSTP, &sigact, NULL) != 0) fatal("sigaction failed"); - event_del(&ev_sighup); - event_del(&ev_sigchld); - event_del(&ev_sigcont); - event_del(&ev_sigterm); - event_del(&ev_sigusr1); - event_del(&ev_sigwinch); + if (after_fork) { + if (sigaction(SIGHUP, &sigact, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGCHLD, &sigact, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGCONT, &sigact, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGTERM, &sigact, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGUSR1, &sigact, NULL) != 0) + fatal("sigaction failed"); + if (sigaction(SIGWINCH, &sigact, NULL) != 0) + fatal("sigaction failed"); + } else { + event_del(&ev_sighup); + event_del(&ev_sigchld); + event_del(&ev_sigcont); + event_del(&ev_sigterm); + event_del(&ev_sigusr1); + event_del(&ev_sigwinch); + } } diff --git a/tmux.c b/tmux.c index e42e48d3..9274236e 100644 --- a/tmux.c +++ b/tmux.c @@ -549,7 +549,7 @@ main(int argc, char **argv) event_dispatch(); - clear_signals(); + clear_signals(0); client_main(); /* doesn't return */ } @@ -636,7 +636,7 @@ main_dispatch(const char *shellcmd) memcpy(&shelldata, imsg.data, sizeof shelldata); shelldata.shell[(sizeof shelldata.shell) - 1] = '\0'; - clear_signals(); + clear_signals(0); shell_exec(shelldata.shell, shellcmd); default: diff --git a/tmux.h b/tmux.h index af731ff7..a68bd0ea 100644 --- a/tmux.h +++ b/tmux.h @@ -1952,8 +1952,8 @@ void queue_window_name(struct window *); char *default_window_name(struct window *); /* signal.c */ -void set_signals(void(*handler)(int, short, unused void *)); -void clear_signals(void); +void set_signals(void(*)(int, short, void *)); +void clear_signals(int); /* session.c */ extern struct sessions sessions; diff --git a/window.c b/window.c index 70596284..c2afc6d2 100644 --- a/window.c +++ b/window.c @@ -574,7 +574,7 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell, environ_push(env); - clear_signals(); + clear_signals(1); log_close(); if (*wp->cmd != '\0') { From 5f5104e782782a26e436d5cfd59e3d38ad9063fa Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 22 Aug 2010 16:09:49 +0000 Subject: [PATCH 0752/1180] MSG_EXIT can now have a return code in the message, so check for that size as well. Stops the client fatal()ing on exit. --- client.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client.c b/client.c index e86a64ad..3ee3e4ef 100644 --- a/client.c +++ b/client.c @@ -297,7 +297,8 @@ client_dispatch(void) client_exitmsg = "detached"; break; case MSG_EXIT: - if (datalen != 0) + if (datalen != 0 && + datalen != sizeof (struct msg_exit_data)) fatalx("bad MSG_EXIT size"); client_write_server(MSG_EXITING, NULL, 0); From fc9f08235bcec4551afa531eeff09e572f56fcf4 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 23 Aug 2010 17:36:32 +0000 Subject: [PATCH 0753/1180] Can't call event_del() without event_set() first - so call event_set() when setting up the client. --- client.c | 1 + 1 file changed, 1 insertion(+) diff --git a/client.c b/client.c index 3ee3e4ef..e6b17c59 100644 --- a/client.c +++ b/client.c @@ -93,6 +93,7 @@ server_started: if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) fatal("fcntl failed"); imsg_init(&client_ibuf, fd); + event_set(&client_event, fd, EV_READ, client_callback, NULL); if (cmdflags & CMD_SENDENVIRON) client_send_environ(); From f69ce39a6c174f5d05d33fb756d1af3a5d5c9b0c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 25 Aug 2010 19:19:43 +0000 Subject: [PATCH 0754/1180] When destroying a pane, reset any mode (which reenables pane bufferevent) before freeing the bufferevent. --- window.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/window.c b/window.c index c2afc6d2..731eff02 100644 --- a/window.c +++ b/window.c @@ -495,6 +495,8 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit) void window_pane_destroy(struct window_pane *wp) { + window_pane_reset_mode(wp); + if (wp->fd != -1) { close(wp->fd); bufferevent_free(wp->event); @@ -502,7 +504,6 @@ window_pane_destroy(struct window_pane *wp) input_free(wp); - window_pane_reset_mode(wp); screen_free(&wp->base); if (wp->saved_grid != NULL) grid_destroy(wp->saved_grid); From 8e8e0f1d5353be14b4b0439f12895a86426fdbab Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 31 Aug 2010 22:46:59 +0000 Subject: [PATCH 0755/1180] Add missing prototype. --- server-client.c | 1 + 1 file changed, 1 insertion(+) diff --git a/server-client.c b/server-client.c index 695c4e48..27a5d207 100644 --- a/server-client.c +++ b/server-client.c @@ -30,6 +30,7 @@ void server_client_handle_key(int, struct mouse_event *, void *); void server_client_repeat_timer(int, short, void *); void server_client_check_exit(struct client *); +void server_client_check_backoff(struct client *); void server_client_check_redraw(struct client *); void server_client_set_title(struct client *); void server_client_reset_state(struct client *); From 5309252053309339f5987726a0d9fe8827f70ecd Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 1 Sep 2010 21:06:51 +0000 Subject: [PATCH 0756/1180] Reset running jobs when the status line is enabled or disabled as well, some people have it bound to a key. --- cmd-set-option.c | 1 + 1 file changed, 1 insertion(+) diff --git a/cmd-set-option.c b/cmd-set-option.c index 8caf42e2..a3ca635c 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -293,6 +293,7 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) */ if (strcmp(entry->name, "status-left") == 0 || strcmp(entry->name, "status-right") == 0 || + strcmp(entry->name, "status") == 0 || strcmp(entry->name, "set-titles-string") == 0 || strcmp(entry->name, "window-status-format") == 0) { for (i = 0; i < ARRAY_LENGTH(&clients); i++) { From de68c2a7da02cfecd0d4238bca1d1c88eaaba0e1 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 1 Sep 2010 21:11:14 +0000 Subject: [PATCH 0757/1180] Simplify xterm modifier detection by treating as a bitmask + 1. Spotted by and diff from Emanuele Giaquinta. --- xterm-keys.c | 55 ++++++++++++++++++---------------------------------- 1 file changed, 19 insertions(+), 36 deletions(-) diff --git a/xterm-keys.c b/xterm-keys.c index e4cb25d1..3c9fd3ba 100644 --- a/xterm-keys.c +++ b/xterm-keys.c @@ -114,27 +114,21 @@ int xterm_keys_modifiers(const char *template, const char *buf, size_t len) { size_t idx; + int param, modifiers; idx = strcspn(template, "_"); if (idx >= len) return (0); - switch (buf[idx]) { - case '2': - return (KEYC_SHIFT); - case '3': - return (KEYC_ESCAPE); - case '4': - return (KEYC_SHIFT|KEYC_ESCAPE); - case '5': - return (KEYC_CTRL); - case '6': - return (KEYC_SHIFT|KEYC_CTRL); - case '7': - return (KEYC_ESCAPE|KEYC_CTRL); - case '8': - return (KEYC_SHIFT|KEYC_ESCAPE|KEYC_CTRL); - } - return (0); + param = buf[idx] - '1'; + + modifiers = 0; + if (param & 1) + modifiers |= KEYC_SHIFT; + if (param & 2) + modifiers |= KEYC_ESCAPE; + if (param & 4) + modifiers |= KEYC_CTRL; + return (modifiers); } /* @@ -171,30 +165,19 @@ xterm_keys_lookup(int key) int modifiers; char *out; -#define KEY_MODIFIERS(key, modifiers) \ - (((key) & (KEYC_SHIFT|KEYC_ESCAPE|KEYC_CTRL)) == (modifiers)) - modifiers = 0; - if (KEY_MODIFIERS(key, KEYC_SHIFT)) - modifiers = 2; - else if (KEY_MODIFIERS(key, KEYC_ESCAPE)) - modifiers = 3; - else if (KEY_MODIFIERS(key, KEYC_SHIFT|KEYC_ESCAPE)) - modifiers = 4; - else if (KEY_MODIFIERS(key, KEYC_CTRL)) - modifiers = 5; - else if (KEY_MODIFIERS(key, KEYC_SHIFT|KEYC_CTRL)) - modifiers = 6; - else if (KEY_MODIFIERS(key, KEYC_ESCAPE|KEYC_CTRL)) - modifiers = 7; - else if (KEY_MODIFIERS(key, KEYC_SHIFT|KEYC_ESCAPE|KEYC_CTRL)) - modifiers = 8; -#undef KEY_MODIFIERS + modifiers = 1; + if (key & KEYC_SHIFT) + modifiers += 1; + if (key & KEYC_ESCAPE) + modifiers += 2; + if (key & KEYC_CTRL) + modifiers += 4; /* * If the key has no modifiers, return NULL and let it fall through to * the normal lookup. */ - if (modifiers == 0) + if (modifiers == 1) return (NULL); /* Otherwise, find the key in the table. */ From bbf743769bf0e71dbd6c0cc96aa6817662b939e1 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 8 Sep 2010 20:36:42 +0000 Subject: [PATCH 0758/1180] Do not crash if the screen size is too small for the indicator in copy mode. --- window-copy.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/window-copy.c b/window-copy.c index 186f018d..5ab163cc 100644 --- a/window-copy.c +++ b/window-copy.c @@ -1055,6 +1055,8 @@ window_copy_write_line( if (py == 0) { size = xsnprintf(hdr, sizeof hdr, "[%u/%u]", data->oy, screen_hsize(data->backing)); + if (size > screen_size_x(s)) + size = screen_size_x(s); 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) { From a22a6deda500945b13687997f09279d62e91e0e8 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 8 Sep 2010 22:02:28 +0000 Subject: [PATCH 0759/1180] Add -n and -p flags to switch-client to move to the next and previous session (yes, it doesn't match window/pane, but so what, nor does switch-client). Based on a diff long ago from "edsouza". --- cmd-switch-client.c | 66 ++++++++++++++++++++++++++++++++++++++++----- key-bindings.c | 2 ++ session.c | 42 +++++++++++++++++++++++++++++ tmux.1 | 6 +++++ tmux.h | 2 ++ 5 files changed, 111 insertions(+), 7 deletions(-) diff --git a/cmd-switch-client.c b/cmd-switch-client.c index 03cb7c8d..913bb501 100644 --- a/cmd-switch-client.c +++ b/cmd-switch-client.c @@ -27,6 +27,7 @@ * Switch client to a different session. */ +void cmd_switch_client_init(struct cmd *, int); int cmd_switch_client_parse(struct cmd *, int, char **, char **); int cmd_switch_client_exec(struct cmd *, struct cmd_ctx *); void cmd_switch_client_free(struct cmd *); @@ -35,28 +36,50 @@ size_t cmd_switch_client_print(struct cmd *, char *, size_t); struct cmd_switch_client_data { char *name; char *target; + int flag_next; + int flag_previous; }; const struct cmd_entry cmd_switch_client_entry = { "switch-client", "switchc", - "[-c target-client] [-t target-session]", + "[-np] [-c target-client] [-t target-session]", 0, "", - NULL, + cmd_switch_client_init, cmd_switch_client_parse, cmd_switch_client_exec, cmd_switch_client_free, cmd_switch_client_print }; +void +cmd_switch_client_init(struct cmd *self, int key) +{ + struct cmd_switch_client_data *data; + + self->data = data = xmalloc(sizeof *data); + data->name = NULL; + data->target = NULL; + data->flag_next = 0; + data->flag_previous = 0; + + switch (key) { + case '(': + data->flag_previous = 1; + break; + case ')': + data->flag_next = 1; + break; + } +} + int cmd_switch_client_parse(struct cmd *self, int argc, char **argv, char **cause) { struct cmd_switch_client_data *data; int opt; - self->data = data = xmalloc(sizeof *data); - data->name = NULL; - data->target = NULL; + self->entry->init(self, KEYC_NONE); + data = self->data; while ((opt = getopt(argc, argv, "c:t:")) != -1) { switch (opt) { @@ -65,9 +88,21 @@ cmd_switch_client_parse(struct cmd *self, int argc, char **argv, char **cause) data->name = xstrdup(optarg); break; case 't': + if (data->flag_next || data->flag_previous) + goto usage; if (data->target == NULL) data->target = xstrdup(optarg); break; + case 'n': + if (data->flag_previous || data->target != NULL) + goto usage; + data->flag_next = 1; + break; + case 'p': + if (data->flag_next || data->target != NULL) + goto usage; + data->flag_next = 1; + break; default: goto usage; } @@ -98,9 +133,22 @@ cmd_switch_client_exec(struct cmd *self, struct cmd_ctx *ctx) if ((c = cmd_find_client(ctx, data->name)) == NULL) return (-1); - if ((s = cmd_find_session(ctx, data->target)) == NULL) - return (-1); + if (data->flag_next) { + if ((s = session_next_session(c->session)) == NULL) { + ctx->error(ctx, "can't find next session"); + return (-1); + } + } else if (data->flag_previous) { + if ((s = session_previous_session(c->session)) == NULL) { + ctx->error(ctx, "can't find previous session"); + return (-1); + } + } else + s = cmd_find_session(ctx, data->target); + + if (s == NULL) + return (-1); c->session = s; recalculate_sizes(); @@ -130,6 +178,10 @@ cmd_switch_client_print(struct cmd *self, char *buf, size_t len) off += xsnprintf(buf, len, "%s", self->entry->name); if (data == NULL) return (off); + if (off < len && data->flag_next) + off += xsnprintf(buf + off, len - off, "%s", " -n"); + if (off < len && data->flag_previous) + off += xsnprintf(buf + off, len - off, "%s", " -p"); if (off < len && data->name != NULL) off += cmd_prarg(buf + off, len - off, " -c ", data->name); if (off < len && data->target != NULL) diff --git a/key-bindings.c b/key-bindings.c index 2a039af0..61d392d3 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -108,6 +108,8 @@ key_bindings_init(void) { '#', 0, &cmd_list_buffers_entry }, { '%', 0, &cmd_split_window_entry }, { '&', 0, &cmd_confirm_before_entry }, + { '(', 0, &cmd_switch_client_entry }, + { ')', 0, &cmd_switch_client_entry }, { ',', 0, &cmd_command_prompt_entry }, { '-', 0, &cmd_delete_buffer_entry }, { '.', 0, &cmd_command_prompt_entry }, diff --git a/session.c b/session.c index b164eef8..7d3fb32d 100644 --- a/session.c +++ b/session.c @@ -169,6 +169,48 @@ session_index(struct session *s, u_int *i) return (-1); } +/* Find the next usable session. */ +struct session * +session_next_session(struct session *s) +{ + struct session *s2; + u_int i; + + if (ARRAY_LENGTH(&sessions) == 0 || session_index(s, &i) != 0) + return (NULL); + + do { + if (i == ARRAY_LENGTH(&sessions) - 1) + i = 0; + else + i++; + s2 = ARRAY_ITEM(&sessions, i); + } while (s2 == NULL || s2->flags & SESSION_DEAD); + + return (s2); +} + +/* Find the previous usable session. */ +struct session * +session_previous_session(struct session *s) +{ + struct session *s2; + u_int i; + + if (ARRAY_LENGTH(&sessions) == 0 || session_index(s, &i) != 0) + return (NULL); + + do { + if (i == 0) + i = ARRAY_LENGTH(&sessions) - 1; + else + i--; + s2 = ARRAY_ITEM(&sessions, i); + } while (s2 == NULL || s2->flags & SESSION_DEAD); + + return (s2); +} + /* Create a new window on a session. */ struct winlink * session_new(struct session *s, diff --git a/tmux.1 b/tmux.1 index 38f0687f..f1894113 100644 --- a/tmux.1 +++ b/tmux.1 @@ -660,6 +660,7 @@ Suspend a client by sending .Dv SIGTSTP (tty stop). .It Xo Ic switch-client +.Op Fl np .Op Fl c Ar target-client .Op Fl t Ar target-session .Xc @@ -668,6 +669,11 @@ Switch the current session for client .Ar target-client to .Ar target-session . +If +.Fl n +or +.Fl p +is used, the client is moved to the next or previous session respectively. .El .Sh WINDOWS AND PANES A diff --git a/tmux.h b/tmux.h index a68bd0ea..34274b50 100644 --- a/tmux.h +++ b/tmux.h @@ -1965,6 +1965,8 @@ struct session *session_create(const char *, const char *, const char *, char **); void session_destroy(struct session *); int session_index(struct session *, u_int *); +struct session *session_next_session(struct session *); +struct session *session_previous_session(struct session *); struct winlink *session_new(struct session *, const char *, const char *, const char *, int, char **); struct winlink *session_attach( From c1c5f43a012aa6c00e6445e062f9d915bcaa756e Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 11 Sep 2010 15:39:55 +0000 Subject: [PATCH 0760/1180] When resizing the copy mode screen, don't allow it to end up with the viewable position beyond the size of the history. --- window-copy.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/window-copy.c b/window-copy.c index 5ab163cc..b66eb74f 100644 --- a/window-copy.c +++ b/window-copy.c @@ -342,6 +342,8 @@ window_copy_resize(struct window_pane *wp, u_int sx, u_int sy) data->cy = sy - 1; if (data->cx > sx) data->cx = sx; + if (data->oy > screen_hsize(data->backing)) + data->oy = screen_hsize(data->backing); window_copy_clear_selection(wp); From 3696cce4ae83e27ac757bceaad6a0c9fa27525d4 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 11 Sep 2010 15:43:11 +0000 Subject: [PATCH 0761/1180] Ignore terminal overrides settings without a value. --- tty-term.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tty-term.c b/tty-term.c index 2338b42c..18858501 100644 --- a/tty-term.c +++ b/tty-term.c @@ -249,7 +249,8 @@ tty_term_override(struct tty_term *term, const char *overrides) } else if (entstr[strlen(entstr) - 1] == '@') { entstr[strlen(entstr) - 1] = '\0'; removeflag = 1; - } + } else + continue; for (i = 0; i < NTTYCODE; i++) { ent = &tty_term_codes[i]; From cb564bb427b9db5b1e48a74e6b818454f7ab0c77 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 11 Sep 2010 16:19:22 +0000 Subject: [PATCH 0762/1180] Use UTF-8 line drawing characters on UTF-8 terminals. Fixes some stupid terminals (I'm looking at you, putty) which disable the vt100 ACS mode switching sequences in UTF-8 mode. Also on terminals without ACS at all, use ASCII equivalents where obvious. --- Makefile | 2 +- screen-redraw.c | 17 ++------- tmux.h | 8 ++-- tty-acs.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++++ tty-term.c | 12 +++++- tty.c | 55 ++++++++++------------------ 6 files changed, 137 insertions(+), 54 deletions(-) create mode 100644 tty-acs.c diff --git a/Makefile b/Makefile index b70804f1..70f073da 100644 --- a/Makefile +++ b/Makefile @@ -35,7 +35,7 @@ SRCS= attributes.c cfg.c client.c clock.c \ mode-key.c names.c options.c paste.c procname.c \ resize.c screen-redraw.c screen-write.c screen.c session.c status.c \ signal.c server-fn.c server.c server-client.c server-window.c \ - tmux.c tty-keys.c tty-term.c tty.c utf8.c \ + tmux.c tty-acs.c tty-keys.c tty-term.c tty.c utf8.c \ window-choose.c window-clock.c window-copy.c window.c \ xterm-keys.c xmalloc.c diff --git a/screen-redraw.c b/screen-redraw.c index bd3010cb..2024e675 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -41,6 +41,8 @@ void screen_redraw_draw_number(struct client *, struct window_pane *); #define CELL_JOIN 11 #define CELL_OUTSIDE 12 +#define CELL_BORDERS " xqlkmjwvtun~" + /* Check if cell is on the border of a particular pane. */ int screen_redraw_cell_border1(struct window_pane *wp, u_int px, u_int py) @@ -173,8 +175,6 @@ screen_redraw_screen(struct client *c, int status_only, int borders_only) struct grid_cell active_gc, other_gc; u_int i, j, type; int status, fg, bg; - const u_char *base, *ptr; - u_char ch, border[20]; /* Get status line, er, status. */ if (c->message_string != NULL || c->prompt_string != NULL) @@ -193,6 +193,7 @@ screen_redraw_screen(struct client *c, int status_only, int borders_only) memcpy(&other_gc, &grid_default_cell, sizeof other_gc); memcpy(&active_gc, &grid_default_cell, sizeof active_gc); active_gc.data = other_gc.data = 'x'; /* not space */ + active_gc.attr = other_gc.attr = GRID_ATTR_CHARSET; fg = options_get_number(&c->session->options, "pane-border-fg"); colour_set_fg(&other_gc, fg); bg = options_get_number(&c->session->options, "pane-border-bg"); @@ -203,16 +204,6 @@ screen_redraw_screen(struct client *c, int status_only, int borders_only) colour_set_bg(&active_gc, bg); /* Draw background and borders. */ - strlcpy(border, " |-....--||+.", sizeof border); - if (tty_term_has(tty->term, TTYC_ACSC)) { - base = " xqlkmjwvtun~"; - for (ptr = base; *ptr != '\0'; ptr++) { - if ((ch = tty_get_acs(tty, *ptr)) != '\0') - border[ptr - base] = ch; - } - other_gc.attr |= GRID_ATTR_CHARSET; - active_gc.attr |= GRID_ATTR_CHARSET; - } for (j = 0; j < tty->sy - status; j++) { if (status_only && j != tty->sy - 1) continue; @@ -225,7 +216,7 @@ screen_redraw_screen(struct client *c, int status_only, int borders_only) else tty_attributes(tty, &other_gc); tty_cursor(tty, i, j); - tty_putc(tty, border[type]); + tty_putc(tty, CELL_BORDERS[type]); } } diff --git a/tmux.h b/tmux.h index 34274b50..257c0816 100644 --- a/tmux.h +++ b/tmux.h @@ -972,6 +972,8 @@ struct tty_term { char *name; u_int references; + char acs[UCHAR_MAX + 1][2]; + struct tty_code codes[NTTYCODE]; #define TERM_256COLOURS 0x1 @@ -1009,8 +1011,6 @@ struct tty { struct grid_cell cell; - u_char acs[UCHAR_MAX + 1]; - #define TTY_NOCURSOR 0x1 #define TTY_FREEZE 0x2 #define TTY_ESCAPE 0x4 @@ -1372,7 +1372,6 @@ void environ_push(struct environ *); /* tty.c */ void tty_raw(struct tty *, const char *); -u_char tty_get_acs(struct tty *, u_char); void tty_attributes(struct tty *, const struct grid_cell *); void tty_reset(struct tty *); void tty_region_pane(struct tty *, const struct tty_ctx *, u_int, u_int); @@ -1426,6 +1425,9 @@ const char *tty_term_string2( int tty_term_number(struct tty_term *, enum tty_code_code); int tty_term_flag(struct tty_term *, enum tty_code_code); +/* tty-acs.c */ +const char *tty_acs_get(struct tty *, u_char); + /* tty-keys.c */ void tty_keys_init(struct tty *); void tty_keys_free(struct tty *); diff --git a/tty-acs.c b/tty-acs.c new file mode 100644 index 00000000..297c51ac --- /dev/null +++ b/tty-acs.c @@ -0,0 +1,97 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2010 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 "tmux.h" + +int tty_acs_cmp(const void *, const void *); + +/* Table mapping ACS entries to UTF-8. */ +struct tty_acs_entry { + u_char key; + 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" } +}; + +int +tty_acs_cmp(const void *key, const void *value) +{ + const struct tty_acs_entry *entry = value; + u_char ch; + + ch = *(u_char *) key; + return (ch - entry->key); +} + +/* Retrieve ACS to output as a string. */ +const char * +tty_acs_get(struct tty *tty, u_char ch) +{ + struct tty_acs_entry *entry; + + /* If not a UTF-8 terminal, use the ACS set. */ + if (!(tty->flags & TTY_UTF8)) { + if (tty->term->acs[ch][0] == '\0') + return (NULL); + return (&tty->term->acs[ch][0]); + } + + /* Otherwise look up the UTF-8 translation. */ + entry = bsearch(&ch, + tty_acs_table, nitems(tty_acs_table), sizeof tty_acs_table[0], + tty_acs_cmp); + if (entry == NULL) + return (NULL); + return (entry->string); +} diff --git a/tty-term.c b/tty-term.c index 18858501..1566253d 100644 --- a/tty-term.c +++ b/tty-term.c @@ -302,6 +302,7 @@ tty_term_find(char *name, int fd, const char *overrides, char **cause) u_int i; int n, error; char *s; + const char *acs; SLIST_FOREACH(term, &tty_terms, entry) { if (strcmp(term->name, name) == 0) { @@ -315,7 +316,7 @@ tty_term_find(char *name, int fd, const char *overrides, char **cause) term->name = xstrdup(name); term->references = 1; term->flags = 0; - memset(&term->codes, 0, sizeof term->codes); + memset(term->codes, 0, sizeof term->codes); SLIST_INSERT_HEAD(&tty_terms, term, entry); /* Set up curses terminal. */ @@ -411,6 +412,15 @@ tty_term_find(char *name, int fd, const char *overrides, char **cause) if (!tty_term_flag(term, TTYC_XENL)) term->flags |= TERM_EARLYWRAP; + /* Generate ACS table. If none is present, use nearest ASCII. */ + memset(term->acs, 0, sizeof term->acs); + if (tty_term_has(term, TTYC_ACSC)) + acs = tty_term_string(term, TTYC_ACSC); + else + acs = "a#j+k+l+m+n+o-p-q-r-s-t+u+v+w+x|y~."; + for (; acs[0] != '\0' && acs[1] != '\0'; acs += 2) + term->acs[(u_char) acs[0]][0] = acs[1]; + return (term); error: diff --git a/tty.c b/tty.c index bf0a48b0..642b9766 100644 --- a/tty.c +++ b/tty.c @@ -31,8 +31,6 @@ void tty_read_callback(struct bufferevent *, void *); void tty_error_callback(struct bufferevent *, short, void *); -void tty_fill_acs(struct tty *); - int tty_try_256(struct tty *, u_char, const char *); int tty_try_88(struct tty *, u_char, const char *); @@ -48,6 +46,9 @@ void tty_emulate_repeat( void tty_cell(struct tty *, const struct grid_cell *, const struct grid_utf8 *); +#define tty_use_acs(tty) \ + (tty_term_has(tty, TTYC_ACSC) && !((tty)->flags & TTY_UTF8)) + void tty_init(struct tty *tty, int fd, char *term) { @@ -143,8 +144,6 @@ tty_open(struct tty *tty, const char *overrides, char **cause) tty_keys_init(tty); - tty_fill_acs(tty); - return (0); } @@ -201,7 +200,8 @@ tty_start_tty(struct tty *tty) memcpy(&tty->cell, &grid_default_cell, sizeof tty->cell); tty_putcode(tty, TTYC_RMKX); - tty_putcode(tty, TTYC_ENACS); + if (tty_use_acs(tty)) + tty_putcode(tty, TTYC_ENACS); tty_putcode(tty, TTYC_CLEAR); tty_putcode(tty, TTYC_CNORM); @@ -242,7 +242,8 @@ tty_stop_tty(struct tty *tty) return; tty_raw(tty, tty_term_string2(tty->term, TTYC_CSR, 0, ws.ws_row - 1)); - tty_raw(tty, tty_term_string(tty->term, TTYC_RMACS)); + if (tty_use_acs(tty)) + tty_raw(tty, tty_term_string(tty->term, TTYC_RMACS)); tty_raw(tty, tty_term_string(tty->term, TTYC_SGR0)); tty_raw(tty, tty_term_string(tty->term, TTYC_RMKX)); tty_raw(tty, tty_term_string(tty->term, TTYC_CLEAR)); @@ -257,30 +258,6 @@ tty_stop_tty(struct tty *tty) fcntl(tty->fd, F_SETFL, mode & ~O_NONBLOCK); } -void -tty_fill_acs(struct tty *tty) -{ - const char *ptr; - - memset(tty->acs, 0, sizeof tty->acs); - if (!tty_term_has(tty->term, TTYC_ACSC)) - return; - - ptr = tty_term_string(tty->term, TTYC_ACSC); - if (strlen(ptr) % 2 != 0) - return; - for (; *ptr != '\0'; ptr += 2) - tty->acs[(u_char) ptr[0]] = ptr[1]; -} - -u_char -tty_get_acs(struct tty *tty, u_char ch) -{ - if (tty->acs[ch] != '\0') - return (tty->acs[ch]); - return (ch); -} - void tty_close(struct tty *tty) { @@ -360,11 +337,17 @@ tty_puts(struct tty *tty, const char *s) void tty_putc(struct tty *tty, u_char ch) { - u_int sx; + const char *acs; + u_int sx; - if (tty->cell.attr & GRID_ATTR_CHARSET) - ch = tty_get_acs(tty, ch); - bufferevent_write(tty->event, &ch, 1); + if (tty->cell.attr & GRID_ATTR_CHARSET) { + acs = tty_acs_get(tty, ch); + if (acs != NULL) + bufferevent_write(tty->event, acs, strlen(acs)); + else + bufferevent_write(tty->event, &ch, 1); + } else + bufferevent_write(tty->event, &ch, 1); if (ch >= 0x20 && ch != 0x7f) { sx = tty->sx; @@ -997,7 +980,7 @@ tty_reset(struct tty *tty) if (memcmp(gc, &grid_default_cell, sizeof *gc) == 0) return; - if (tty_term_has(tty->term, TTYC_RMACS) && gc->attr & GRID_ATTR_CHARSET) + if ((gc->attr & GRID_ATTR_CHARSET) && tty_use_acs(tty)) tty_putcode(tty, TTYC_RMACS); tty_putcode(tty, TTYC_SGR0); memcpy(gc, &grid_default_cell, sizeof *gc); @@ -1234,7 +1217,7 @@ tty_attributes(struct tty *tty, const struct grid_cell *gc) } if (changed & GRID_ATTR_HIDDEN) tty_putcode(tty, TTYC_INVIS); - if (changed & GRID_ATTR_CHARSET) + if ((changed & GRID_ATTR_CHARSET) && tty_use_acs(tty)) tty_putcode(tty, TTYC_SMACS); } From ea4487c6dad37429dbef6e6377f6f8f02f877380 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 11 Sep 2010 16:20:58 +0000 Subject: [PATCH 0763/1180] Ugh. Pass the right type into tty_term_has. Teaches me to make last minute changes :-/. --- tty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tty.c b/tty.c index 642b9766..268ea2e8 100644 --- a/tty.c +++ b/tty.c @@ -47,7 +47,7 @@ void tty_cell(struct tty *, const struct grid_cell *, const struct grid_utf8 *); #define tty_use_acs(tty) \ - (tty_term_has(tty, TTYC_ACSC) && !((tty)->flags & TTY_UTF8)) + (tty_term_has(tty->term, TTYC_ACSC) && !((tty)->flags & TTY_UTF8)) void tty_init(struct tty *tty, int fd, char *term) From 2772557d154b7773fb5f6a2bc48fe43a26e7c7e4 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 25 Sep 2010 20:35:52 +0000 Subject: [PATCH 0764/1180] detach-on-destroy is a session option, not server. --- tmux.1 | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tmux.1 b/tmux.1 index f1894113..d9b76ae1 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1581,11 +1581,6 @@ Available window options are listed under .Pp Available server options are: .Bl -tag -width Ds -.It Ic detach-on-destroy -If on (the default), the client is detached when the session it is attached to -is destroyed. -If off, the client is switched to the most recently active of the remaining -sessions. .It Ic escape-time Set the time in milliseconds for which .Nm @@ -1664,6 +1659,11 @@ to work correctly, this be set to .Ql screen or a derivative of it. +.It Ic detach-on-destroy +If on (the default), the client is detached when the session it is attached to +is destroyed. +If off, the client is switched to the most recently active of the remaining +sessions. .It Ic display-panes-active-colour Ar colour Set the colour used by the .Ic display-panes From 66152010a7e03a10780815b074cd0b4d47fc1cdc Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 26 Sep 2010 18:51:48 +0000 Subject: [PATCH 0765/1180] Modify the permissions on the socket when adding or removing +x to show attached sessions, rather than replacing them. --- server.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/server.c b/server.c index 96bafb54..d5514f62 100644 --- a/server.c +++ b/server.c @@ -296,7 +296,8 @@ server_update_socket(void) struct session *s; u_int i; static int last = -1; - int n; + int n, mode; + struct stat sb; n = 0; for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { @@ -309,10 +310,20 @@ server_update_socket(void) if (n != last) { last = n; - if (n != 0) - chmod(socket_path, S_IRWXU|S_IRWXG); - else - chmod(socket_path, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP); + + if (stat(socket_path, &sb) != 0) + return; + mode = sb.st_mode; + if (n != 0) { + if (mode & S_IRUSR) + mode |= S_IXUSR; + if (mode & S_IRGRP) + mode |= S_IXGRP; + if (mode & S_IROTH) + mode |= S_IXOTH; + } else + mode &= ~(S_IXUSR|S_IXGRP|S_IXOTH); + chmod(socket_path, mode); } } From 9a7cde0c9be168900d3914857c85d71bc472608f Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 26 Sep 2010 20:43:30 +0000 Subject: [PATCH 0766/1180] Two new options: - server option "exit-unattached" makes the server exit when no clients are attached, even if sessions are present; - session option "destroy-unattached" destroys a session once no clients are attached to it. These are useful for preventing tmux remaining in the background where it is undesirable and when using tmux as a login shell to keep a limit on new sessions. --- cmd-set-option.c | 2 ++ cmd-switch-client.c | 1 + server-client.c | 1 + server-fn.c | 19 +++++++++++++++++++ server.c | 10 ++++++---- tmux.1 | 6 ++++++ tmux.c | 2 ++ tmux.h | 1 + 8 files changed, 38 insertions(+), 4 deletions(-) diff --git a/cmd-set-option.c b/cmd-set-option.c index a3ca635c..684f1b04 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -75,6 +75,7 @@ const char *set_option_bell_action_list[] = { const struct set_option_entry set_option_table[] = { { "escape-time", SET_OPTION_NUMBER, 0, INT_MAX, NULL }, + { "exit-unattached", SET_OPTION_FLAG, 0, 0, NULL }, { "quiet", SET_OPTION_FLAG, 0, 0, NULL }, { NULL, 0, 0, 0, NULL } }; @@ -87,6 +88,7 @@ const struct set_option_entry set_session_option_table[] = { { "default-path", SET_OPTION_STRING, 0, 0, NULL }, { "default-shell", SET_OPTION_STRING, 0, 0, NULL }, { "default-terminal", SET_OPTION_STRING, 0, 0, NULL }, + { "destroy-unattached", SET_OPTION_FLAG, 0, 0, NULL }, { "detach-on-destroy", SET_OPTION_FLAG, 0, 0, NULL }, { "display-panes-colour", SET_OPTION_COLOUR, 0, 0, NULL }, { "display-panes-active-colour", SET_OPTION_COLOUR, 0, 0, NULL }, diff --git a/cmd-switch-client.c b/cmd-switch-client.c index 913bb501..bce42c2a 100644 --- a/cmd-switch-client.c +++ b/cmd-switch-client.c @@ -152,6 +152,7 @@ cmd_switch_client_exec(struct cmd *self, struct cmd_ctx *ctx) c->session = s; recalculate_sizes(); + server_check_unattached(); server_redraw_client(c); return (0); diff --git a/server-client.c b/server-client.c index 27a5d207..427f8dfb 100644 --- a/server-client.c +++ b/server-client.c @@ -185,6 +185,7 @@ server_client_lost(struct client *c) c->flags |= CLIENT_DEAD; recalculate_sizes(); + server_check_unattached(); server_update_socket(); } diff --git a/server-fn.c b/server-fn.c index 03c89cf5..af443e8f 100644 --- a/server-fn.c +++ b/server-fn.c @@ -404,6 +404,25 @@ server_destroy_session(struct session *s) recalculate_sizes(); } +void +server_check_unattached (void) +{ + struct session *s; + u_int i; + + /* + * If any sessions are no longer attached and have destroy-unattached + * set, collect them. + */ + for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { + s = ARRAY_ITEM(&sessions, i); + if (s == NULL || !(s->flags & SESSION_UNATTACHED)) + continue; + if (options_get_number (&s->options, "destroy-unattached")) + session_destroy(s); + } +} + void server_set_identify(struct client *c) { diff --git a/server.c b/server.c index d5514f62..7dfd5be6 100644 --- a/server.c +++ b/server.c @@ -222,15 +222,17 @@ server_loop(void) } } -/* Check if the server should be shutting down (no more clients or windows). */ +/* Check if the server should be shutting down (no more clients or sessions). */ int server_should_shutdown(void) { u_int i; - for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { - if (ARRAY_ITEM(&sessions, i) != NULL) - return (0); + if (!options_get_number(&global_options, "exit-unattached")) { + for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { + if (ARRAY_ITEM(&sessions, i) != NULL) + return (0); + } } for (i = 0; i < ARRAY_LENGTH(&clients); i++) { if (ARRAY_ITEM(&clients, i) != NULL) diff --git a/tmux.1 b/tmux.1 index d9b76ae1..bfd05c55 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1587,6 +1587,9 @@ Set the time in milliseconds for which waits after an escape is input to determine if it is part of a function or meta key sequences. The default is 500 milliseconds. +.It Ic exit-unattached +If enabled, the server will exit when there are no attached clients, rather +than when there are no attached sessions. .It Ic quiet Enable or disable the display of various informational messages (see also the .Fl q @@ -1659,6 +1662,9 @@ to work correctly, this be set to .Ql screen or a derivative of it. +.It Ic destroy-unattached +If enabled and the session is no longer attached to any clients, it is +destroyed. .It Ic detach-on-destroy If on (the default), the client is detached when the session it is attached to is destroyed. diff --git a/tmux.c b/tmux.c index 9274236e..2b01f2b7 100644 --- a/tmux.c +++ b/tmux.c @@ -331,6 +331,7 @@ main(int argc, char **argv) oo = &global_options; options_set_number(oo, "quiet", quiet); options_set_number(oo, "escape-time", 500); + options_set_number(oo, "exit-unattached", 0); options_init(&global_s_options, NULL); so = &global_s_options; @@ -341,6 +342,7 @@ main(int argc, char **argv) options_set_string(so, "default-path", "%s", ""); options_set_string(so, "default-shell", "%s", getshell()); options_set_string(so, "default-terminal", "screen"); + options_set_number(so, "destroy-unattached", 0); options_set_number(so, "detach-on-destroy", 1); options_set_number(so, "display-panes-active-colour", 1); options_set_number(so, "display-panes-colour", 4); diff --git a/tmux.h b/tmux.h index 257c0816..762f0d26 100644 --- a/tmux.h +++ b/tmux.h @@ -1661,6 +1661,7 @@ void server_unlink_window(struct session *, struct winlink *); void server_destroy_pane(struct window_pane *); void server_destroy_session_group(struct session *); void server_destroy_session(struct session *); +void server_check_unattached (void); void server_set_identify(struct client *); void server_clear_identify(struct client *); void server_update_event(struct client *); From 4789a4ee1f27034484fbf9622db8b5740d1cd51f Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 28 Sep 2010 07:15:45 +0000 Subject: [PATCH 0767/1180] Nuke a leftover RB tree declaration spotted by blambert. --- tmux.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/tmux.h b/tmux.h index 762f0d26..2e1c8e1d 100644 --- a/tmux.h +++ b/tmux.h @@ -1827,9 +1827,7 @@ int screen_check_selection(struct screen *, u_int, u_int); /* window.c */ extern struct windows windows; -int window_cmp(struct window *, struct window *); int winlink_cmp(struct winlink *, struct winlink *); -RB_PROTOTYPE(windows, window, entry, window_cmp); RB_PROTOTYPE(winlinks, winlink, entry, winlink_cmp); struct winlink *winlink_find_by_index(struct winlinks *, int); struct winlink *winlink_find_by_window(struct winlinks *, struct window *); From 08bcd6978cd6f699ec688dbea8c8a7ea43002e0c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 5 Oct 2010 17:15:21 +0000 Subject: [PATCH 0768/1180] Skip NULL entries in the sessions list when choosing the next session, from Simon Olofsson. --- server-fn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server-fn.c b/server-fn.c index af443e8f..a166541d 100644 --- a/server-fn.c +++ b/server-fn.c @@ -368,7 +368,7 @@ server_next_session(struct session *s) s_out = NULL; for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { s_loop = ARRAY_ITEM(&sessions, i); - if (s_loop == s) + if (s_loop == NULL || s_loop == s) continue; if (s_out == NULL || timercmp(&s_loop->activity_time, &s_out->activity_time, <)) From 7aef2994e453df8e3cdd13e22e0041c9d7c23564 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 9 Oct 2010 12:58:00 +0000 Subject: [PATCH 0769/1180] Set cause when failing due to linking a window to itself, from Martin Pieuchot. --- server-fn.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/server-fn.c b/server-fn.c index a166541d..59f61373 100644 --- a/server-fn.c +++ b/server-fn.c @@ -280,8 +280,10 @@ server_link_window(struct session *src, struct winlink *srcwl, if (dstidx != -1) dstwl = winlink_find_by_index(&dst->windows, dstidx); if (dstwl != NULL) { - if (dstwl->window == srcwl->window) + if (dstwl->window == srcwl->window) { + xasprintf(cause, "same index: %d", dstidx); return (-1); + } if (killflag) { /* * Can't use session_detach as it will destroy session From 1580afdfdf72e3dd33a5063bce69fd96f0906d42 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 14 Oct 2010 00:30:03 +0000 Subject: [PATCH 0770/1180] Put "or" on new line from command with .Ic. --- tmux.1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tmux.1 b/tmux.1 index bfd05c55..cd65fed9 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2082,7 +2082,8 @@ will attempt - on supported platforms - to rename the window to reflect the command currently running in it. This flag is automatically disabled for an individual window when a name is specified at creation with -.Ic new-window or +.Ic new-window +or .Ic new-session , or later with .Ic rename-window . From f6cd0342f69ff47da2c298febeec59919c002eca Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 14 Oct 2010 00:37:51 +0000 Subject: [PATCH 0771/1180] Treat the meta bit in the xterm extended modifier key set as the same as escape (tmux's meta). From Emanuele Giaquinta. --- xterm-keys.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/xterm-keys.c b/xterm-keys.c index 3c9fd3ba..5f8db986 100644 --- a/xterm-keys.c +++ b/xterm-keys.c @@ -128,6 +128,8 @@ xterm_keys_modifiers(const char *template, const char *buf, size_t len) modifiers |= KEYC_ESCAPE; if (param & 4) modifiers |= KEYC_CTRL; + if (param & 8) + modifiers |= KEYC_ESCAPE; return (modifiers); } @@ -172,6 +174,8 @@ xterm_keys_lookup(int key) modifiers += 2; if (key & KEYC_CTRL) modifiers += 4; + if (key & KEYC_ESCAPE) + modifiers += 8; /* * If the key has no modifiers, return NULL and let it fall through to From 65ff5b00bd786ca02ebfde9f76d0730acb9f68b4 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 14 Oct 2010 17:38:39 +0000 Subject: [PATCH 0772/1180] Use an explicit event rather than event_once for the main event so it can be removed when the client becomes ready. --- tmux.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/tmux.c b/tmux.c index 2b01f2b7..842fd1b9 100644 --- a/tmux.c +++ b/tmux.c @@ -61,6 +61,7 @@ char *makesockpath(const char *); __dead void shell_exec(const char *, const char *); struct imsgbuf *main_ibuf; +struct event main_event; void main_signal(int, short, unused void *); void main_callback(int, short, void *); @@ -547,12 +548,14 @@ main(int argc, char **argv) events = EV_READ; if (main_ibuf->w.queued > 0) events |= EV_WRITE; - event_once(main_ibuf->fd, events, main_callback, shellcmd, NULL); + event_set(&main_event, main_ibuf->fd, events, main_callback, shellcmd); + event_add(&main_event, NULL); event_dispatch(); - clear_signals(0); + event_del(&main_event); + clear_signals(0); client_main(); /* doesn't return */ } @@ -585,10 +588,12 @@ main_callback(unused int fd, short events, void *data) fatalx("msgbuf_write failed"); } + event_del(&main_event); events = EV_READ; if (main_ibuf->w.queued > 0) events |= EV_WRITE; - event_once(main_ibuf->fd, events, main_callback, shellcmd, NULL); + event_set(&main_event, main_ibuf->fd, events, main_callback, shellcmd); + event_add(&main_event, NULL); } void From 6c42f1a89e16d69d5fe24bb8b3f6b37148cfa308 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 16 Oct 2010 07:57:42 +0000 Subject: [PATCH 0773/1180] Fall back on normal session choice method if $TMUX exists but is invalid rather than rejecting. --- cmd.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/cmd.c b/cmd.c index 2643bb12..b324621c 100644 --- a/cmd.c +++ b/cmd.c @@ -340,15 +340,11 @@ cmd_current_session(struct cmd_ctx *ctx) } /* Use the session from the TMUX environment variable. */ - if (data != NULL && data->pid != -1) { - if (data->pid != getpid()) - return (NULL); - if (data->idx > ARRAY_LENGTH(&sessions)) - return (NULL); - if ((s = ARRAY_ITEM(&sessions, data->idx)) == NULL) - return (NULL); + if (data != NULL && + data->pid == getpid() && + data->idx <= ARRAY_LENGTH(&sessions) && + (s = ARRAY_ITEM(&sessions, data->idx)) != NULL) return (s); - } return (cmd_choose_session(&sessions)); } From f56b4ec2ffa6d5667a3bd86040a1c771c1de33a5 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 16 Oct 2010 08:31:55 +0000 Subject: [PATCH 0774/1180] Trying to set FD_CLOEXEC on every fd is a lost cause, just use closefrom() before exec. --- client.c | 2 -- cmd-pipe-pane.c | 4 ++-- job.c | 4 ++-- server-client.c | 8 -------- server.c | 2 -- tmux.c | 2 ++ tty.c | 3 --- window.c | 4 ++-- 8 files changed, 8 insertions(+), 21 deletions(-) diff --git a/client.c b/client.c index e6b17c59..d9682b49 100644 --- a/client.c +++ b/client.c @@ -90,8 +90,6 @@ server_started: fatal("fcntl failed"); if (fcntl(fd, F_SETFL, mode|O_NONBLOCK) == -1) fatal("fcntl failed"); - if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) - fatal("fcntl failed"); imsg_init(&client_ibuf, fd); event_set(&client_event, fd, EV_READ, client_callback, NULL); diff --git a/cmd-pipe-pane.c b/cmd-pipe-pane.c index be6f8e25..d287d3b6 100644 --- a/cmd-pipe-pane.c +++ b/cmd-pipe-pane.c @@ -112,6 +112,8 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx) if (null_fd != STDOUT_FILENO && null_fd != STDERR_FILENO) close(null_fd); + closefrom(STDERR_FILENO + 1); + command = status_replace(c, NULL, data->arg, time(NULL), 0); execl(_PATH_BSHELL, "sh", "-c", command, (char *) NULL); _exit(1); @@ -130,8 +132,6 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx) fatal("fcntl failed"); if (fcntl(wp->pipe_fd, F_SETFL, mode|O_NONBLOCK) == -1) fatal("fcntl failed"); - if (fcntl(wp->pipe_fd, F_SETFD, FD_CLOEXEC) == -1) - fatal("fcntl failed"); return (0); } } diff --git a/job.c b/job.c index e0dc99ef..ef4066e5 100644 --- a/job.c +++ b/job.c @@ -169,6 +169,8 @@ job_run(struct job *job) if (nullfd != STDIN_FILENO && nullfd != STDERR_FILENO) close(nullfd); + closefrom(STDERR_FILENO + 1); + execl(_PATH_BSHELL, "sh", "-c", job->cmd, (char *) NULL); fatal("execl failed"); default: /* parent */ @@ -179,8 +181,6 @@ job_run(struct job *job) fatal("fcntl failed"); if (fcntl(job->fd, F_SETFL, mode|O_NONBLOCK) == -1) fatal("fcntl failed"); - if (fcntl(job->fd, F_SETFD, FD_CLOEXEC) == -1) - fatal("fcntl failed"); if (job->event != NULL) bufferevent_free(job->event); diff --git a/server-client.c b/server-client.c index 427f8dfb..cd3eb079 100644 --- a/server-client.c +++ b/server-client.c @@ -60,8 +60,6 @@ server_client_create(int fd) fatal("fcntl failed"); if (fcntl(fd, F_SETFL, mode|O_NONBLOCK) == -1) fatal("fcntl failed"); - if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) - fatal("fcntl failed"); c = xcalloc(1, sizeof *c); c->references = 0; @@ -706,8 +704,6 @@ server_client_msg_dispatch(struct client *c) if ((mode = fcntl(c->stdin_fd, F_GETFL)) != -1) fcntl(c->stdin_fd, F_SETFL, mode|O_NONBLOCK); - if (fcntl(c->stdin_fd, F_SETFD, FD_CLOEXEC) == -1) - fatal("fcntl failed"); server_client_msg_identify(c, &identifydata, imsg.fd); break; @@ -725,8 +721,6 @@ server_client_msg_dispatch(struct client *c) if ((mode = fcntl(c->stdout_fd, F_GETFL)) != -1) fcntl(c->stdout_fd, F_SETFL, mode|O_NONBLOCK); - if (fcntl(c->stdout_fd, F_SETFD, FD_CLOEXEC) == -1) - fatal("fcntl failed"); break; case MSG_STDERR: if (datalen != 0) @@ -742,8 +736,6 @@ server_client_msg_dispatch(struct client *c) if ((mode = fcntl(c->stderr_fd, F_GETFL)) != -1) fcntl(c->stderr_fd, F_SETFL, mode|O_NONBLOCK); - if (fcntl(c->stderr_fd, F_SETFD, FD_CLOEXEC) == -1) - fatal("fcntl failed"); break; case MSG_RESIZE: if (datalen != 0) diff --git a/server.c b/server.c index 7dfd5be6..721bb570 100644 --- a/server.c +++ b/server.c @@ -98,8 +98,6 @@ server_create_socket(void) fatal("fcntl failed"); if (fcntl(fd, F_SETFL, mode|O_NONBLOCK) == -1) fatal("fcntl failed"); - if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) - fatal("fcntl failed"); server_update_socket(); diff --git a/tmux.c b/tmux.c index 842fd1b9..fe1fd394 100644 --- a/tmux.c +++ b/tmux.c @@ -223,6 +223,8 @@ shell_exec(const char *shell, const char *shellcmd) xasprintf(&argv0, "%s", shellname); setenv("SHELL", shell, 1); + closefrom(STDERR_FILENO + 1); + execl(shell, argv0, "-c", shellcmd, (char *) NULL); fatal("execl failed"); } diff --git a/tty.c b/tty.c index 268ea2e8..379fa42d 100644 --- a/tty.c +++ b/tty.c @@ -61,9 +61,6 @@ tty_init(struct tty *tty, int fd, char *term) tty->termname = xstrdup("unknown"); else tty->termname = xstrdup(term); - - if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) - fatal("fcntl failed"); tty->fd = fd; if ((path = ttyname(fd)) == NULL) diff --git a/window.c b/window.c index 731eff02..181ffd7c 100644 --- a/window.c +++ b/window.c @@ -573,6 +573,8 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell, if (tcsetattr(STDIN_FILENO, TCSANOW, &tio2) != 0) fatal("tcgetattr failed"); + closefrom(STDERR_FILENO + 1); + environ_push(env); clear_signals(1); @@ -603,8 +605,6 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell, fatal("fcntl failed"); if (fcntl(wp->fd, F_SETFL, mode|O_NONBLOCK) == -1) fatal("fcntl failed"); - if (fcntl(wp->fd, F_SETFD, FD_CLOEXEC) == -1) - fatal("fcntl failed"); wp->event = bufferevent_new(wp->fd, window_pane_read_callback, NULL, window_pane_error_callback, wp); bufferevent_enable(wp->event, EV_READ|EV_WRITE); From 31954339d1487d2a179f6180867e67cbd22aabd1 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 16 Oct 2010 08:42:35 +0000 Subject: [PATCH 0775/1180] Make stdio blocking again before calling shell command with -c. --- tmux.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tmux.c b/tmux.c index fe1fd394..f6601cdf 100644 --- a/tmux.c +++ b/tmux.c @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -211,6 +212,7 @@ shell_exec(const char *shell, const char *shellcmd) { const char *shellname, *ptr; char *argv0; + int mode; ptr = strrchr(shell, '/'); if (ptr != NULL && *(ptr + 1) != '\0') @@ -223,6 +225,12 @@ shell_exec(const char *shell, const char *shellcmd) xasprintf(&argv0, "%s", shellname); setenv("SHELL", shell, 1); + if ((mode = fcntl(STDIN_FILENO, F_GETFL)) != -1) + fcntl(STDIN_FILENO, F_SETFL, mode & ~O_NONBLOCK); + if ((mode = fcntl(STDOUT_FILENO, F_GETFL)) != -1) + fcntl(STDOUT_FILENO, F_SETFL, mode & ~O_NONBLOCK); + if ((mode = fcntl(STDERR_FILENO, F_GETFL)) != -1) + fcntl(STDERR_FILENO, F_SETFL, mode & ~O_NONBLOCK); closefrom(STDERR_FILENO + 1); execl(shell, argv0, "-c", shellcmd, (char *) NULL); From 248fb14f089216bf384c8914163cc77b4f219154 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 18 Oct 2010 20:00:02 +0000 Subject: [PATCH 0776/1180] Merge the before and after attach client code into one in client.c (instead of two in tmux.c and client.c). --- client.c | 337 +++++++++++++++++++++++++++++++++++++++---------------- server.c | 10 +- tmux.c | 274 +++++++------------------------------------- tmux.h | 13 ++- 4 files changed, 297 insertions(+), 337 deletions(-) diff --git a/client.c b/client.c index d9682b49..35a2e4e8 100644 --- a/client.c +++ b/client.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include "tmux.h" @@ -37,77 +36,171 @@ struct imsgbuf client_ibuf; struct event client_event; const char *client_exitmsg; int client_exitval; +int client_attached; +int client_connect(char *, int); void client_send_identify(int); void client_send_environ(void); void client_write_server(enum msgtype, void *, size_t); void client_update_event(void); void client_signal(int, short, void *); void client_callback(int, short, void *); -int client_dispatch(void); +int client_dispatch_attached(void); +int client_dispatch_wait(void *); -struct imsgbuf * -client_init(char *path, int cmdflags, int flags) +/* Connect client to server. */ +int +client_connect(char *path, int start_server) { struct sockaddr_un sa; size_t size; int fd, mode; - char rpathbuf[MAXPATHLEN]; - - if (realpath(path, rpathbuf) == NULL) - strlcpy(rpathbuf, path, sizeof rpathbuf); - setproctitle("client (%s)", rpathbuf); memset(&sa, 0, sizeof sa); sa.sun_family = AF_UNIX; size = strlcpy(sa.sun_path, path, sizeof sa.sun_path); if (size >= sizeof sa.sun_path) { errno = ENAMETOOLONG; - goto not_found; + return (-1); } if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) fatal("socket failed"); if (connect(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1) { - if (!(cmdflags & CMD_STARTSERVER)) - goto not_found; + if (!start_server) + goto failed; switch (errno) { case ECONNREFUSED: if (unlink(path) != 0) - goto not_found; + goto failed; /* FALLTHROUGH */ case ENOENT: - if ((fd = server_start(path)) == -1) - goto start_failed; - goto server_started; + if ((fd = server_start()) == -1) + goto failed; + break; + default: + goto failed; } - goto not_found; } -server_started: if ((mode = fcntl(fd, F_GETFL)) == -1) fatal("fcntl failed"); if (fcntl(fd, F_SETFL, mode|O_NONBLOCK) == -1) fatal("fcntl failed"); - imsg_init(&client_ibuf, fd); - event_set(&client_event, fd, EV_READ, client_callback, NULL); + return (fd); +failed: + close(fd); + return (-1); +} + +/* Client main loop. */ +int +client_main(int argc, char **argv, int flags) +{ + struct cmd *cmd; + struct cmd_list *cmdlist; + struct msg_command_data cmddata; + int cmdflags, fd; + enum msgtype msg; + char *cause; + + /* Set up the initial command. */ + cmdflags = 0; + if (shell_cmd != NULL) { + msg = MSG_SHELL; + cmdflags = CMD_STARTSERVER; + } else if (argc == 0) { + msg = MSG_COMMAND; + cmdflags = CMD_STARTSERVER|CMD_SENDENVIRON|CMD_CANTNEST; + } else { + msg = MSG_COMMAND; + + /* + * It sucks parsing the command string twice (in client and + * later in server) but it is necessary to get the start server + * flag. + */ + if ((cmdlist = cmd_list_parse(argc, argv, &cause)) == NULL) { + log_warnx("%s", cause); + return (1); + } + cmdflags &= ~CMD_STARTSERVER; + TAILQ_FOREACH(cmd, &cmdlist->list, qentry) { + if (cmd->entry->flags & CMD_STARTSERVER) + cmdflags |= CMD_STARTSERVER; + if (cmd->entry->flags & CMD_SENDENVIRON) + cmdflags |= CMD_SENDENVIRON; + if (cmd->entry->flags & CMD_CANTNEST) + cmdflags |= CMD_CANTNEST; + } + cmd_list_free(cmdlist); + } + + /* + * Check if this could be a nested session, if the command can't nest: + * if the socket path matches $TMUX, this is probably the same server. + */ + if (shell_cmd == NULL && environ_path != NULL && + cmdflags & CMD_CANTNEST && strcmp(socket_path, environ_path) == 0) { + log_warnx("sessions should be nested with care. " + "unset $TMUX to force."); + return (1); + } + + /* Initialise the client socket and start the server. */ + fd = client_connect(socket_path, cmdflags & CMD_STARTSERVER); + if (fd == -1) { + log_warn("failed to connect to server"); + return (1); + } + + /* Set process title, log and signals now this is the client. */ + setproctitle("client (%s)", socket_path); + logfile("client"); + + /* Create imsg. */ + imsg_init(&client_ibuf, fd); + event_set(&client_event, fd, EV_READ, client_callback, shell_cmd); + + /* Establish signal handlers. */ + set_signals(client_signal); + + /* Send initial environment. */ if (cmdflags & CMD_SENDENVIRON) client_send_environ(); client_send_identify(flags); - return (&client_ibuf); + /* Send first command. */ + if (msg == MSG_COMMAND) { + /* Fill in command line arguments. */ + cmddata.pid = environ_pid; + cmddata.idx = environ_idx; -start_failed: - log_warnx("server failed to start"); - return (NULL); + /* Prepare command for server. */ + cmddata.argc = argc; + if (cmd_pack_argv( + argc, argv, cmddata.argv, sizeof cmddata.argv) != 0) { + log_warnx("command too long"); + return (1); + } -not_found: - log_warn("server not found"); - return (NULL); + client_write_server(msg, &cmddata, sizeof cmddata); + } else if (msg == MSG_SHELL) + client_write_server(msg, NULL, 0); + + /* Set the event and dispatch. */ + client_update_event(); + event_dispatch(); + + /* Print the exit message, if any, and exit. */ + if (client_attached && client_exitmsg != NULL && !login_shell) + printf("[%s]\n", client_exitmsg); + return (client_exitval); } +/* Send identify message to server with the file descriptors. */ void client_send_identify(int flags) { @@ -132,13 +225,16 @@ client_send_identify(int flags) if ((fd = dup(STDOUT_FILENO)) == -1) fatal("dup failed"); - imsg_compose(&client_ibuf, MSG_STDOUT, PROTOCOL_VERSION, -1, fd, NULL, 0); + imsg_compose(&client_ibuf, + MSG_STDOUT, PROTOCOL_VERSION, -1, fd, NULL, 0); if ((fd = dup(STDERR_FILENO)) == -1) fatal("dup failed"); - imsg_compose(&client_ibuf, MSG_STDERR, PROTOCOL_VERSION, -1, fd, NULL, 0); + imsg_compose(&client_ibuf, + MSG_STDERR, PROTOCOL_VERSION, -1, fd, NULL, 0); } +/* Forward entire environment to server. */ void client_send_environ(void) { @@ -152,12 +248,14 @@ client_send_environ(void) } } +/* Write a message to the server without a file descriptor. */ void client_write_server(enum msgtype type, void *buf, size_t len) { imsg_compose(&client_ibuf, type, PROTOCOL_VERSION, -1, -1, buf, len); } +/* Update client event based on whether it needs to read or read and write. */ void client_update_event(void) { @@ -167,91 +265,74 @@ client_update_event(void) events = EV_READ; if (client_ibuf.w.queued > 0) events |= EV_WRITE; - event_set(&client_event, client_ibuf.fd, events, client_callback, NULL); + event_set( + &client_event, client_ibuf.fd, events, client_callback, shell_cmd); event_add(&client_event, NULL); } -__dead void -client_main(void) -{ - logfile("client"); - - /* Note: event_init() has already been called. */ - - /* Set up signals. */ - set_signals(client_signal); - - /* - * Send a resize message immediately in case the terminal size has - * changed between the identify message to the server and the MSG_READY - * telling us to move into the client code. - */ - client_write_server(MSG_RESIZE, NULL, 0); - - /* - * imsg_read in the first client poll loop (before the terminal has - * been initialised) may have read messages into the buffer after the - * MSG_READY switched to here. Process anything outstanding now to - * avoid hanging waiting for messages that have already arrived. - */ - if (client_dispatch() != 0) - goto out; - - /* Set the event and dispatch. */ - client_update_event(); - event_dispatch(); - -out: - /* Print the exit message, if any, and exit. */ - if (client_exitmsg != NULL && !login_shell) - printf("[%s]\n", client_exitmsg); - exit(client_exitval); -} - +/* Callback to handle signals in the client. */ /* ARGSUSED */ void client_signal(int sig, unused short events, unused void *data) { - struct sigaction sigact; + struct sigaction sigact; + int status; - switch (sig) { - case SIGHUP: - client_exitmsg = "lost tty"; - client_exitval = 1; - client_write_server(MSG_EXITING, NULL, 0); - break; - case SIGTERM: - client_exitmsg = "terminated"; - client_exitval = 1; - client_write_server(MSG_EXITING, NULL, 0); - break; - case SIGWINCH: - client_write_server(MSG_RESIZE, NULL, 0); - break; - case SIGCONT: - memset(&sigact, 0, sizeof sigact); - sigemptyset(&sigact.sa_mask); - sigact.sa_flags = SA_RESTART; - sigact.sa_handler = SIG_IGN; - if (sigaction(SIGTSTP, &sigact, NULL) != 0) - fatal("sigaction failed"); - client_write_server(MSG_WAKEUP, NULL, 0); - break; + if (!client_attached) { + switch (sig) { + case SIGCHLD: + waitpid(WAIT_ANY, &status, WNOHANG); + break; + case SIGTERM: + event_loopexit(NULL); + break; + } + } else { + switch (sig) { + case SIGHUP: + client_exitmsg = "lost tty"; + client_exitval = 1; + client_write_server(MSG_EXITING, NULL, 0); + break; + case SIGTERM: + client_exitmsg = "terminated"; + client_exitval = 1; + client_write_server(MSG_EXITING, NULL, 0); + break; + case SIGWINCH: + client_write_server(MSG_RESIZE, NULL, 0); + break; + case SIGCONT: + memset(&sigact, 0, sizeof sigact); + sigemptyset(&sigact.sa_mask); + sigact.sa_flags = SA_RESTART; + sigact.sa_handler = SIG_IGN; + if (sigaction(SIGTSTP, &sigact, NULL) != 0) + fatal("sigaction failed"); + client_write_server(MSG_WAKEUP, NULL, 0); + break; + } } client_update_event(); } +/* Callback for client imsg read events. */ /* ARGSUSED */ void -client_callback(unused int fd, short events, unused void *data) +client_callback(unused int fd, short events, void *data) { ssize_t n; + int retval; if (events & EV_READ) { if ((n = imsg_read(&client_ibuf)) == -1 || n == 0) goto lost_server; - if (client_dispatch() != 0) { + if (client_attached) + retval = client_dispatch_attached(); + else + retval = client_dispatch_wait(data); + if (retval != 0) { event_loopexit(NULL); return; } @@ -271,8 +352,76 @@ lost_server: event_loopexit(NULL); } +/* Dispatch imsgs when in wait state (before MSG_READY). */ int -client_dispatch(void) +client_dispatch_wait(void *data) +{ + struct imsg imsg; + ssize_t n, datalen; + struct msg_shell_data shelldata; + struct msg_exit_data exitdata; + const char *shellcmd = data; + + if ((n = imsg_read(&client_ibuf)) == -1 || n == 0) + fatalx("imsg_read failed"); + + for (;;) { + if ((n = imsg_get(&client_ibuf, &imsg)) == -1) + fatalx("imsg_get failed"); + if (n == 0) + return (0); + datalen = imsg.hdr.len - IMSG_HEADER_SIZE; + + switch (imsg.hdr.type) { + case MSG_EXIT: + case MSG_SHUTDOWN: + if (datalen != sizeof exitdata) { + if (datalen != 0) + fatalx("bad MSG_EXIT size"); + } else { + memcpy(&exitdata, imsg.data, sizeof exitdata); + client_exitval = exitdata.retcode; + } + imsg_free(&imsg); + return (-1); + case MSG_READY: + if (datalen != 0) + fatalx("bad MSG_READY size"); + + client_attached = 1; + break; + case MSG_VERSION: + if (datalen != 0) + fatalx("bad MSG_VERSION size"); + + log_warnx("protocol version mismatch (client %u, " + "server %u)", PROTOCOL_VERSION, imsg.hdr.peerid); + client_exitval = 1; + + imsg_free(&imsg); + return (-1); + case MSG_SHELL: + if (datalen != sizeof shelldata) + fatalx("bad MSG_SHELL size"); + memcpy(&shelldata, imsg.data, sizeof shelldata); + shelldata.shell[(sizeof shelldata.shell) - 1] = '\0'; + + clear_signals(0); + + shell_exec(shelldata.shell, shellcmd); + /* NOTREACHED */ + default: + fatalx("unexpected message"); + } + + imsg_free(&imsg); + } +} + +/* Dispatch imsgs in attached state (after MSG_READY). */ +/* ARGSUSED */ +int +client_dispatch_attached(void) { struct imsg imsg; struct msg_lock_data lockdata; diff --git a/server.c b/server.c index 721bb570..7a4e5fcf 100644 --- a/server.c +++ b/server.c @@ -106,11 +106,11 @@ server_create_socket(void) /* Fork new server. */ int -server_start(char *path) +server_start(void) { struct window_pane *wp; int pair[2]; - char rpathbuf[MAXPATHLEN], *cause; + char *cause; struct timeval tv; u_int i; @@ -155,12 +155,8 @@ server_start(char *path) utf8_build(); start_time = time(NULL); - socket_path = path; - - if (realpath(socket_path, rpathbuf) == NULL) - strlcpy(rpathbuf, socket_path, sizeof rpathbuf); log_debug("socket path %s", socket_path); - setproctitle("server (%s)", rpathbuf); + setproctitle("server (%s)", socket_path); server_fd = server_create_socket(); server_client_create(pair[1]); diff --git a/tmux.c b/tmux.c index f6601cdf..3a3f82f9 100644 --- a/tmux.c +++ b/tmux.c @@ -18,17 +18,14 @@ #include #include -#include #include #include #include #include #include -#include #include #include -#include #include #include "tmux.h" @@ -37,7 +34,6 @@ extern char *malloc_options; #endif -char *cfg_file; struct options global_options; /* server options */ struct options global_s_options; /* session options */ struct options global_w_options; /* window options */ @@ -45,28 +41,19 @@ struct environ global_environ; struct event_base *ev_base; +char *cfg_file; +char *shell_cmd; int debug_level; time_t start_time; -char *socket_path; +char socket_path[MAXPATHLEN]; int login_shell; - -struct env_data { - char *path; - pid_t pid; - u_int idx; -}; +char *environ_path; +pid_t environ_pid; +u_int environ_idx; __dead void usage(void); -void parse_env(struct env_data *); -char *makesockpath(const char *); -__dead void shell_exec(const char *, const char *); - -struct imsgbuf *main_ibuf; -struct event main_event; - -void main_signal(int, short, unused void *); -void main_callback(int, short, void *); -void main_dispatch(const char *); +void parseenvironment(void); +char *makesocketpath(const char *); __dead void usage(void) @@ -136,14 +123,14 @@ areshell(const char *shell) } void -parse_env(struct env_data *data) +parseenvironment(void) { char *env, *path_pid, *pid_idx, buf[256]; size_t len; const char *errstr; long long ll; - data->pid = -1; + environ_pid = -1; if ((env = getenv("TMUX")) == NULL) return; @@ -156,9 +143,9 @@ parse_env(struct env_data *data) /* path */ len = path_pid - env; - data->path = xmalloc (len + 1); - memcpy(data->path, env, len); - data->path[len] = '\0'; + environ_path = xmalloc(len + 1); + memcpy(environ_path, env, len); + environ_path[len] = '\0'; /* pid */ len = pid_idx - path_pid - 1; @@ -170,17 +157,17 @@ parse_env(struct env_data *data) ll = strtonum(buf, 0, LONG_MAX, &errstr); if (errstr != NULL) return; - data->pid = ll; + environ_pid = ll; /* idx */ - ll = strtonum(pid_idx+1, 0, UINT_MAX, &errstr); + ll = strtonum(pid_idx + 1, 0, UINT_MAX, &errstr); if (errstr != NULL) return; - data->idx = ll; + environ_idx = ll; } char * -makesockpath(const char *label) +makesocketpath(const char *label) { char base[MAXPATHLEN], *path; struct stat sb; @@ -240,28 +227,18 @@ shell_exec(const char *shell, const char *shellcmd) int main(int argc, char **argv) { - struct cmd_list *cmdlist; - struct cmd *cmd; - enum msgtype msg; - struct passwd *pw; - struct options *oo, *so, *wo; - struct keylist *keylist; - struct env_data envdata; - struct msg_command_data cmddata; - char *s, *shellcmd, *path, *label, *home, *cause; - char **var; - void *buf; - size_t len; - int opt, flags, quiet = 0, cmdflags = 0; - short events; + struct passwd *pw; + struct options *oo, *so, *wo; + struct keylist *keylist; + char *s, *path, *label, *home, **var; + int opt, flags, quiet = 0; #ifdef DEBUG malloc_options = (char *) "AFGJPX"; #endif flags = 0; - shellcmd = label = path = NULL; - envdata.path = NULL; + label = path = NULL; login_shell = (**argv == '-'); while ((opt = getopt(argc, argv, "28c:df:lL:qS:uUv")) != -1) { switch (opt) { @@ -274,9 +251,9 @@ main(int argc, char **argv) flags &= ~IDENTIFY_256COLOURS; break; case 'c': - if (shellcmd != NULL) - xfree(shellcmd); - shellcmd = xstrdup(optarg); + if (shell_cmd != NULL) + xfree(shell_cmd); + shell_cmd = xstrdup(optarg); break; case 'f': if (cfg_file != NULL) @@ -312,7 +289,7 @@ main(int argc, char **argv) argc -= optind; argv += optind; - if (shellcmd != NULL && argc != 0) + if (shell_cmd != NULL && argc != 0) usage(); log_open_tty(debug_level); @@ -448,6 +425,7 @@ main(int argc, char **argv) options_set_number(wo, "utf8", 0); } + /* Locate the configuration file. */ if (cfg_file == NULL) { home = getenv("HOME"); if (home == NULL || *home == '\0') { @@ -463,21 +441,22 @@ main(int argc, char **argv) } /* - * Figure out the socket path. If specified on the command-line with - * -S or -L, use it, otherwise try $TMUX or assume -L default. + * Figure out the socket path. If specified on the command-line with -S + * or -L, use it, otherwise try $TMUX or assume -L default. */ - parse_env(&envdata); + parseenvironment(); if (path == NULL) { - /* No -L. Try $TMUX, or default. */ + /* If no -L, use the environment. */ if (label == NULL) { - path = envdata.path; - if (path == NULL) + if (environ_path != NULL) + path = xstrdup(environ_path); + else label = xstrdup("default"); } /* -L or default set. */ if (label != NULL) { - if ((path = makesockpath(label)) == NULL) { + if ((path = makesocketpath(label)) == NULL) { log_warn("can't create socket"); exit(1); } @@ -485,181 +464,14 @@ main(int argc, char **argv) } if (label != NULL) xfree(label); - - if (shellcmd != NULL) { - msg = MSG_SHELL; - buf = NULL; - len = 0; - } else { - cmddata.pid = envdata.pid; - cmddata.idx = envdata.idx; - - /* Prepare command for server. */ - cmddata.argc = argc; - if (cmd_pack_argv( - argc, argv, cmddata.argv, sizeof cmddata.argv) != 0) { - log_warnx("command too long"); - exit(1); - } - - msg = MSG_COMMAND; - buf = &cmddata; - len = sizeof cmddata; - } - - if (shellcmd != NULL) - cmdflags |= CMD_STARTSERVER; - else if (argc == 0) /* new-session is the default */ - cmdflags |= CMD_STARTSERVER|CMD_SENDENVIRON|CMD_CANTNEST; - else { - /* - * It sucks parsing the command string twice (in client and - * later in server) but it is necessary to get the start server - * flag. - */ - if ((cmdlist = cmd_list_parse(argc, argv, &cause)) == NULL) { - log_warnx("%s", cause); - exit(1); - } - cmdflags &= ~CMD_STARTSERVER; - TAILQ_FOREACH(cmd, &cmdlist->list, qentry) { - if (cmd->entry->flags & CMD_STARTSERVER) - cmdflags |= CMD_STARTSERVER; - if (cmd->entry->flags & CMD_SENDENVIRON) - cmdflags |= CMD_SENDENVIRON; - if (cmd->entry->flags & CMD_CANTNEST) - cmdflags |= CMD_CANTNEST; - } - cmd_list_free(cmdlist); - } - - /* - * Check if this could be a nested session, if the command can't nest: - * if the socket path matches $TMUX, this is probably the same server. - */ - if (shellcmd == NULL && envdata.path != NULL && - cmdflags & CMD_CANTNEST && - (path == envdata.path || strcmp(path, envdata.path) == 0)) { - log_warnx("sessions should be nested with care. " - "unset $TMUX to force."); - exit(1); - } - - ev_base = event_init(); - set_signals(main_signal); - - /* Initialise the client socket/start the server. */ - if ((main_ibuf = client_init(path, cmdflags, flags)) == NULL) - exit(1); + if (realpath(path, socket_path) == NULL) + strlcpy(socket_path, path, sizeof socket_path); xfree(path); - imsg_compose(main_ibuf, msg, PROTOCOL_VERSION, -1, -1, buf, len); + /* Set process title. */ + setproctitle("%s (%s)", __progname, socket_path); - events = EV_READ; - if (main_ibuf->w.queued > 0) - events |= EV_WRITE; - event_set(&main_event, main_ibuf->fd, events, main_callback, shellcmd); - event_add(&main_event, NULL); - - event_dispatch(); - - event_del(&main_event); - - clear_signals(0); - client_main(); /* doesn't return */ -} - -/* ARGSUSED */ -void -main_signal(int sig, unused short events, unused void *data) -{ - int status; - - switch (sig) { - case SIGTERM: - exit(1); - case SIGCHLD: - waitpid(WAIT_ANY, &status, WNOHANG); - break; - } -} - -/* ARGSUSED */ -void -main_callback(unused int fd, short events, void *data) -{ - char *shellcmd = data; - - if (events & EV_READ) - main_dispatch(shellcmd); - - if (events & EV_WRITE) { - if (msgbuf_write(&main_ibuf->w) < 0) - fatalx("msgbuf_write failed"); - } - - event_del(&main_event); - events = EV_READ; - if (main_ibuf->w.queued > 0) - events |= EV_WRITE; - event_set(&main_event, main_ibuf->fd, events, main_callback, shellcmd); - event_add(&main_event, NULL); -} - -void -main_dispatch(const char *shellcmd) -{ - struct imsg imsg; - ssize_t n, datalen; - struct msg_shell_data shelldata; - struct msg_exit_data exitdata; - - if ((n = imsg_read(main_ibuf)) == -1 || n == 0) - fatalx("imsg_read failed"); - - for (;;) { - if ((n = imsg_get(main_ibuf, &imsg)) == -1) - fatalx("imsg_get failed"); - if (n == 0) - return; - datalen = imsg.hdr.len - IMSG_HEADER_SIZE; - - switch (imsg.hdr.type) { - case MSG_EXIT: - case MSG_SHUTDOWN: - if (datalen != sizeof exitdata) { - if (datalen != 0) - fatalx("bad MSG_EXIT size"); - exit(0); - } - memcpy(&exitdata, imsg.data, sizeof exitdata); - exit(exitdata.retcode); - case MSG_READY: - if (datalen != 0) - fatalx("bad MSG_READY size"); - - event_loopexit(NULL); /* move to client_main() */ - break; - case MSG_VERSION: - if (datalen != 0) - fatalx("bad MSG_VERSION size"); - - log_warnx("protocol version mismatch (client %u, " - "server %u)", PROTOCOL_VERSION, imsg.hdr.peerid); - exit(1); - case MSG_SHELL: - if (datalen != sizeof shelldata) - fatalx("bad MSG_SHELL size"); - memcpy(&shelldata, imsg.data, sizeof shelldata); - shelldata.shell[(sizeof shelldata.shell) - 1] = '\0'; - - clear_signals(0); - - shell_exec(shelldata.shell, shellcmd); - default: - fatalx("unexpected message"); - } - - imsg_free(&imsg); - } + /* Pass control to the client. */ + ev_base = event_init(); + exit(client_main(argc, argv, flags)); } diff --git a/tmux.h b/tmux.h index 2e1c8e1d..47837851 100644 --- a/tmux.h +++ b/tmux.h @@ -1291,15 +1291,19 @@ extern struct options global_w_options; extern struct environ global_environ; extern struct event_base *ev_base; extern char *cfg_file; +extern char *shell_cmd; extern int debug_level; -extern int be_quiet; extern time_t start_time; -extern char *socket_path; +extern char socket_path[MAXPATHLEN]; extern int login_shell; +extern char *environ_path; +extern pid_t environ_pid; +extern u_int environ_idx; void logfile(const char *); const char *getshell(void); int checkshell(const char *); int areshell(const char *); +__dead void shell_exec(const char *, const char *); /* cfg.c */ extern int cfg_finished; @@ -1598,8 +1602,7 @@ void cmd_buffer_free(struct cmd *); size_t cmd_buffer_print(struct cmd *, char *, size_t); /* client.c */ -struct imsgbuf *client_init(char *, int, int); -__dead void client_main(void); +int client_main(int, char **, int); /* key-bindings.c */ extern struct key_bindings key_bindings; @@ -1622,7 +1625,7 @@ const char *key_string_lookup_key(int); /* server.c */ extern struct clients clients; extern struct clients dead_clients; -int server_start(char *); +int server_start(void); void server_update_socket(void); /* server-client.c */ From 139754b9feef91f1911b7a22c3ac2a684eee2aa9 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 20 Oct 2010 18:20:36 +0000 Subject: [PATCH 0777/1180] Mark repeating keys with "(repeat)" in the key list. --- cmd-list-keys.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cmd-list-keys.c b/cmd-list-keys.c index d41f890b..b60b4666 100644 --- a/cmd-list-keys.c +++ b/cmd-list-keys.c @@ -80,6 +80,11 @@ cmd_list_keys_exec(struct cmd *self, struct cmd_ctx *ctx) if (used >= sizeof tmp) continue; } + if (bd->can_repeat) { + used = strlcat(tmp, "(repeat) ", sizeof tmp); + if (used >= sizeof tmp) + continue; + } cmd_list_print(bd->cmdlist, tmp + used, (sizeof tmp) - used); ctx->print(ctx, "%s", tmp); } From a3efd2ab5aa80757dff1570444faae927ece15b8 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 23 Oct 2010 12:51:51 +0000 Subject: [PATCH 0778/1180] When removing a pane, don't change the active pane unless the active pane is actually the one being removed. --- window.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/window.c b/window.c index 181ffd7c..874f4723 100644 --- a/window.c +++ b/window.c @@ -368,9 +368,11 @@ window_add_pane(struct window *w, u_int hlimit) void window_remove_pane(struct window *w, struct window_pane *wp) { - w->active = TAILQ_PREV(wp, window_panes, entry); - if (w->active == NULL) - w->active = TAILQ_NEXT(wp, entry); + if (wp == w->active) { + w->active = TAILQ_PREV(wp, window_panes, entry); + if (w->active == NULL) + w->active = TAILQ_NEXT(wp, entry); + } TAILQ_REMOVE(&w->panes, wp, entry); window_pane_destroy(wp); From 5de84eca3dbaa7b9fcc378a58198ced8a2d95a3e Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 23 Oct 2010 13:04:34 +0000 Subject: [PATCH 0779/1180] Add a last-pane command (bound to ; by default). Requested ages ago by somebody whose name I have forgotten. --- Makefile | 2 +- cmd-last-pane.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++ cmd.c | 1 + key-bindings.c | 1 + tmux.1 | 5 +++++ tmux.h | 2 ++ window.c | 14 ++++++++---- 7 files changed, 78 insertions(+), 5 deletions(-) create mode 100644 cmd-last-pane.c diff --git a/Makefile b/Makefile index 70f073da..0b27bd45 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ SRCS= attributes.c cfg.c client.c clock.c \ cmd-choose-buffer.c cmd-delete-buffer.c cmd-detach-client.c \ cmd-find-window.c cmd-generic.c cmd-has-session.c cmd-kill-pane.c \ cmd-kill-server.c cmd-kill-session.c cmd-kill-window.c \ - cmd-last-window.c cmd-link-window.c cmd-list-buffers.c \ + cmd-last-pane.c cmd-last-window.c cmd-link-window.c cmd-list-buffers.c \ cmd-list-clients.c cmd-list-commands.c cmd-list-keys.c \ cmd-list-sessions.c cmd-list-windows.c cmd-list-panes.c \ cmd-list.c cmd-load-buffer.c cmd-join-pane.c \ diff --git a/cmd-last-pane.c b/cmd-last-pane.c new file mode 100644 index 00000000..b59843b7 --- /dev/null +++ b/cmd-last-pane.c @@ -0,0 +1,58 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2010 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" + +/* + * Move to last pane. + */ + +int cmd_last_pane_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_last_pane_entry = { + "last-pane", "lastp", + CMD_TARGET_WINDOW_USAGE, + 0, "", + cmd_target_init, + cmd_target_parse, + cmd_last_pane_exec, + cmd_target_free, + cmd_target_print +}; + +int +cmd_last_pane_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_target_data *data = self->data; + struct winlink *wl; + struct window *w; + + if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) + return (-1); + w = wl->window; + + if (w->last == NULL) { + ctx->error(ctx, "no last pane"); + return (-1); + } + window_set_active_pane(w, w->last); + + return (0); +} diff --git a/cmd.c b/cmd.c index b324621c..20cf9cdc 100644 --- a/cmd.c +++ b/cmd.c @@ -54,6 +54,7 @@ const struct cmd_entry *cmd_table[] = { &cmd_kill_server_entry, &cmd_kill_session_entry, &cmd_kill_window_entry, + &cmd_last_pane_entry, &cmd_last_window_entry, &cmd_link_window_entry, &cmd_list_buffers_entry, diff --git a/key-bindings.c b/key-bindings.c index 61d392d3..721620ff 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -124,6 +124,7 @@ key_bindings_init(void) { '8', 0, &cmd_select_window_entry }, { '9', 0, &cmd_select_window_entry }, { ':', 0, &cmd_command_prompt_entry }, + { ';', 0, &cmd_last_pane_entry }, { '=', 0, &cmd_choose_buffer_entry }, { '?', 0, &cmd_list_keys_entry }, { 'D', 0, &cmd_choose_client_entry }, diff --git a/tmux.1 b/tmux.1 index cd65fed9..86e35e72 100644 --- a/tmux.1 +++ b/tmux.1 @@ -248,6 +248,8 @@ Select windows 0 to 9. Enter the .Nm command prompt. +.It ; +Move to the previously active pane. .It = Choose which buffer to paste interactively from a list. .It \&? @@ -1037,6 +1039,9 @@ option kills all but the pane given with Kill the current window or the window at .Ar target-window , removing it from any sessions to which it is linked. +.It Ic last-pane Op Fl t Ar target-window +.D1 (alias: Ic lastp ) +Select the last (previously selected) pane. .It Ic last-window Op Fl t Ar target-session .D1 (alias: Ic last ) Select the last (previously selected) window. diff --git a/tmux.h b/tmux.h index 47837851..d851ee2e 100644 --- a/tmux.h +++ b/tmux.h @@ -832,6 +832,7 @@ struct window { struct event name_timer; struct window_pane *active; + struct window_pane *last; struct window_panes panes; int lastlayout; @@ -1507,6 +1508,7 @@ extern const struct cmd_entry cmd_kill_pane_entry; extern const struct cmd_entry cmd_kill_server_entry; extern const struct cmd_entry cmd_kill_session_entry; extern const struct cmd_entry cmd_kill_window_entry; +extern const struct cmd_entry cmd_last_pane_entry; extern const struct cmd_entry cmd_last_window_entry; extern const struct cmd_entry cmd_link_window_entry; extern const struct cmd_entry cmd_list_buffers_entry; diff --git a/window.c b/window.c index 874f4723..7087e324 100644 --- a/window.c +++ b/window.c @@ -325,6 +325,7 @@ window_resize(struct window *w, u_int sx, u_int sy) void window_set_active_pane(struct window *w, struct window_pane *wp) { + w->last = w->active; w->active = wp; while (!window_pane_visible(w->active)) { w->active = TAILQ_PREV(w->active, window_panes, entry); @@ -369,10 +370,15 @@ void window_remove_pane(struct window *w, struct window_pane *wp) { if (wp == w->active) { - w->active = TAILQ_PREV(wp, window_panes, entry); - if (w->active == NULL) - w->active = TAILQ_NEXT(wp, entry); - } + w->active = w->last; + w->last = NULL; + if (w->active == NULL) { + w->active = TAILQ_PREV(wp, window_panes, entry); + if (w->active == NULL) + w->active = TAILQ_NEXT(wp, entry); + } + } else if (wp == w->last) + w->last = NULL; TAILQ_REMOVE(&w->panes, wp, entry); window_pane_destroy(wp); From 34d05ea7cdc168f3f40ee8f7c1f203a216f2dfdf Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 29 Oct 2010 20:11:57 +0000 Subject: [PATCH 0780/1180] We now send argv to the server after parsing it in the client to get the command, so the client should not modify it. Instead, take a copy. Fixes parsing command lists, reported by mcbride@. --- cmd-list.c | 20 ++++++++++++-------- cmd.c | 16 ++++++++++++++++ tmux.h | 1 + 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/cmd-list.c b/cmd-list.c index 181127ae..b8a8c115 100644 --- a/cmd-list.c +++ b/cmd-list.c @@ -29,7 +29,9 @@ cmd_list_parse(int argc, char **argv, char **cause) struct cmd *cmd; int i, lastsplit; size_t arglen, new_argc; - char **new_argv; + char **copy_argv, **new_argv; + + copy_argv = cmd_copy_argv(argc, argv); cmdlist = xmalloc(sizeof *cmdlist); cmdlist->references = 1; @@ -37,18 +39,18 @@ cmd_list_parse(int argc, char **argv, char **cause) lastsplit = 0; for (i = 0; i < argc; i++) { - arglen = strlen(argv[i]); - if (arglen == 0 || argv[i][arglen - 1] != ';') + arglen = strlen(copy_argv[i]); + if (arglen == 0 || copy_argv[i][arglen - 1] != ';') continue; - argv[i][arglen - 1] = '\0'; + copy_argv[i][arglen - 1] = '\0'; - if (arglen > 1 && argv[i][arglen - 2] == '\\') { - argv[i][arglen - 2] = ';'; + if (arglen > 1 && copy_argv[i][arglen - 2] == '\\') { + copy_argv[i][arglen - 2] = ';'; continue; } new_argc = i - lastsplit; - new_argv = argv + lastsplit; + new_argv = copy_argv + lastsplit; if (arglen != 1) new_argc++; @@ -61,16 +63,18 @@ cmd_list_parse(int argc, char **argv, char **cause) } if (lastsplit != argc) { - cmd = cmd_parse(argc - lastsplit, argv + lastsplit, cause); + cmd = cmd_parse(argc - lastsplit, copy_argv + lastsplit, cause); if (cmd == NULL) goto bad; TAILQ_INSERT_TAIL(&cmdlist->list, cmd, qentry); } + cmd_free_argv(argc, copy_argv); return (cmdlist); bad: cmd_list_free(cmdlist); + cmd_free_argv(argc, copy_argv); return (NULL); } diff --git a/cmd.c b/cmd.c index 20cf9cdc..af038b7b 100644 --- a/cmd.c +++ b/cmd.c @@ -166,6 +166,22 @@ cmd_unpack_argv(char *buf, size_t len, int argc, char ***argv) return (0); } +char ** +cmd_copy_argv(int argc, char **argv) +{ + char **new_argv; + int i; + + if (argc == 0) + return (NULL); + new_argv = xcalloc(argc, sizeof *new_argv); + for (i = 0; i < argc; i++) { + if (argv[i] != NULL) + new_argv[i] = xstrdup(argv[i]); + } + return (new_argv); +} + void cmd_free_argv(int argc, char **argv) { diff --git a/tmux.h b/tmux.h index d851ee2e..d49d11e3 100644 --- a/tmux.h +++ b/tmux.h @@ -1464,6 +1464,7 @@ const char *cmd_set_option_print( /* cmd.c */ int cmd_pack_argv(int, char **, char *, size_t); int cmd_unpack_argv(char *, size_t, int, char ***); +char **cmd_copy_argv(int, char **); void cmd_free_argv(int, char **); struct cmd *cmd_parse(int, char **, char **); int cmd_exec(struct cmd *, struct cmd_ctx *); From 023137a891ce4b78f042fb694dd07ca752503139 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 1 Nov 2010 20:59:45 +0000 Subject: [PATCH 0781/1180] Typo, from Rob Paisley. --- tmux.1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tmux.1 b/tmux.1 index 86e35e72..db538144 100644 --- a/tmux.1 +++ b/tmux.1 @@ -509,7 +509,7 @@ when they are created with the command, or later with the .Ic attach-session command. -Each session has one of more windows +Each session has one or more windows .Em linked into it. Windows may be linked to multiple sessions and are made up of one or From c7fccfa2998b386aa633fc76496ad42094fcaafb Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 11 Nov 2010 20:51:30 +0000 Subject: [PATCH 0782/1180] Declaration in header should be extern. --- tmux.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tmux.h b/tmux.h index d49d11e3..0d37e554 100644 --- a/tmux.h +++ b/tmux.h @@ -1308,7 +1308,7 @@ __dead void shell_exec(const char *, const char *); /* cfg.c */ extern int cfg_finished; -struct causelist cfg_causes; +extern struct causelist cfg_causes; void printflike2 cfg_add_cause(struct causelist *, const char *, ...); int load_cfg(const char *, struct cmd_ctx *, struct causelist *); From 17b56562c421b1f5b8634b12002e6d5cc0f49582 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 11 Nov 2010 20:54:06 +0000 Subject: [PATCH 0783/1180] Flag to flush all key bindings from Rob Paisley. --- cmd-unbind-key.c | 42 +++++++++++++++++++++++++++++++----------- tmux.1 | 5 ++++- 2 files changed, 35 insertions(+), 12 deletions(-) diff --git a/cmd-unbind-key.c b/cmd-unbind-key.c index c5a97301..f95342b9 100644 --- a/cmd-unbind-key.c +++ b/cmd-unbind-key.c @@ -33,13 +33,14 @@ int cmd_unbind_key_table(struct cmd *, struct cmd_ctx *); struct cmd_unbind_key_data { int key; + int flag_all; int command_key; char *tablename; }; const struct cmd_entry cmd_unbind_key_entry = { "unbind-key", "unbind", - "[-cn] [-t key-table] key", + "[-acn] [-t key-table] key", 0, "", NULL, cmd_unbind_key_parse, @@ -55,11 +56,15 @@ cmd_unbind_key_parse(struct cmd *self, int argc, char **argv, char **cause) int opt, no_prefix = 0; self->data = data = xmalloc(sizeof *data); + data->flag_all = 0; data->command_key = 0; data->tablename = NULL; - while ((opt = getopt(argc, argv, "cnt:")) != -1) { + while ((opt = getopt(argc, argv, "acnt:")) != -1) { switch (opt) { + case 'a': + data->flag_all = 1; + break; case 'c': data->command_key = 1; break; @@ -76,15 +81,20 @@ cmd_unbind_key_parse(struct cmd *self, int argc, char **argv, char **cause) } argc -= optind; argv += optind; - if (argc != 1) + if (data->flag_all && (argc != 0 || data->tablename)) + goto usage; + if (!data->flag_all && argc != 1) goto usage; - if ((data->key = key_string_lookup_string(argv[0])) == KEYC_NONE) { - xasprintf(cause, "unknown key: %s", argv[0]); - goto error; + if (!data->flag_all) { + data->key = key_string_lookup_string(argv[0]); + if (data->key == KEYC_NONE) { + xasprintf(cause, "unknown key: %s", argv[0]); + goto error; + } + if (!no_prefix) + data->key |= KEYC_PREFIX; } - if (!no_prefix) - data->key |= KEYC_PREFIX; return (0); @@ -100,13 +110,23 @@ int cmd_unbind_key_exec(struct cmd *self, unused struct cmd_ctx *ctx) { struct cmd_unbind_key_data *data = self->data; + struct key_binding *bd; if (data == NULL) return (0); - if (data->tablename != NULL) - return (cmd_unbind_key_table(self, ctx)); + if (data->flag_all) { + while (!SPLAY_EMPTY(&key_bindings)) { + bd = SPLAY_ROOT(&key_bindings); + SPLAY_REMOVE(key_bindings, &key_bindings, bd); + cmd_list_free(bd->cmdlist); + xfree(bd); + } + } else { + if (data->tablename != NULL) + return (cmd_unbind_key_table(self, ctx)); - key_bindings_remove(data->key); + key_bindings_remove(data->key); + } return (0); } diff --git a/tmux.1 b/tmux.1 index db538144..4db1cf8b 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1479,7 +1479,7 @@ All arguments are sent sequentially from first to last. Send the prefix key to a window as if it was pressed. If multiple prefix keys are configured, only the first is sent. .It Xo Ic unbind-key -.Op Fl cn +.Op Fl acn .Op Fl t Ar key-table .Ar key .Xc @@ -1493,6 +1493,9 @@ the primary key bindings are modified; in this case, if is specified, the command bound to .Ar key without a prefix (if any) is removed. +If +.Fl a +is present, all key bindings are removed. .Pp If .Fl t From e4e728664b1a02b6c259131f9c34cbd0d30252a7 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 11 Nov 2010 21:06:09 +0000 Subject: [PATCH 0784/1180] Add XAUTHORITY to update-environment, requested by Andreas Kloeckner. --- tmux.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tmux.c b/tmux.c index 3a3f82f9..0562da3b 100644 --- a/tmux.c +++ b/tmux.c @@ -372,8 +372,11 @@ main(int argc, char **argv) options_set_number(so, "status-right-length", 40); options_set_string(so, "terminal-overrides", "*88col*:colors=88,*256col*:colors=256"); - options_set_string(so, "update-environment", "DISPLAY " - "WINDOWID SSH_ASKPASS SSH_AUTH_SOCK SSH_AGENT_PID SSH_CONNECTION"); + options_set_string(so, "update-environment", + "DISPLAY " + "SSH_ASKPASS SSH_AUTH_SOCK SSH_AGENT_PID SSH_CONNECTION " + "WINDOWID " + "XAUTHORITY"); options_set_number(so, "visual-activity", 0); options_set_number(so, "visual-bell", 0); options_set_number(so, "visual-content", 0); From 503edae26fff7a6e6bb8b76f2ea009b2ed99ced1 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 14 Nov 2010 08:58:25 +0000 Subject: [PATCH 0785/1180] Don't allow last and active window to become the same - a very bad move when the active window is closed and freed. Reported by sthen@. --- window.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/window.c b/window.c index 7087e324..a7a5c40e 100644 --- a/window.c +++ b/window.c @@ -325,6 +325,8 @@ window_resize(struct window *w, u_int sx, u_int sy) void window_set_active_pane(struct window *w, struct window_pane *wp) { + if (wp == w->active) + return; w->last = w->active; w->active = wp; while (!window_pane_visible(w->active)) { @@ -342,7 +344,7 @@ window_set_active_at(struct window *w, u_int x, u_int y) struct window_pane *wp; TAILQ_FOREACH(wp, &w->panes, entry) { - if (!window_pane_visible(wp)) + if (wp == w->active || !window_pane_visible(wp)) continue; if (x < wp->xoff || x >= wp->xoff + wp->sx) continue; From 7e542d119b8c2f80cbd675f86959171e2c0b50d4 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 14 Nov 2010 09:04:22 +0000 Subject: [PATCH 0786/1180] Update man page for update-environment. --- tmux.1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tmux.1 b/tmux.1 index 4db1cf8b..f738f166 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2022,7 +2022,8 @@ was given to the .Ic set-environment command). The default is -"DISPLAY WINDOWID SSH_ASKPASS SSH_AUTH_SOCK SSH_AGENT_PID SSH_CONNECTION". +"DISPLAY SSH_ASKPASS SSH_AUTH_SOCK SSH_AGENT_PID SSH_CONNECTION WINDOWID +XAUTHORITY". .It Xo Ic visual-activity .Op Ic on | off .Xc From 9a1b4f9ed3285d3b9b0e8d22b0bdb1a97df7e949 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 15 Nov 2010 06:52:11 +0000 Subject: [PATCH 0787/1180] Show more window and pane flags in list-* output, and put layout on the same line. --- cmd-list-panes.c | 5 +++-- cmd-list-windows.c | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/cmd-list-panes.c b/cmd-list-panes.c index ba70faa1..e96d596b 100644 --- a/cmd-list-panes.c +++ b/cmd-list-panes.c @@ -65,9 +65,10 @@ cmd_list_panes_exec(struct cmd *self, struct cmd_ctx *ctx) } size += gd->hsize * sizeof *gd->linedata; - ctx->print(ctx, "%u: [%ux%u] [history %u/%u, %llu bytes]%s", + ctx->print(ctx, "%u: [%ux%u] [history %u/%u, %llu bytes]%s%s", n, wp->sx, wp->sy, gd->hsize, gd->hlimit, size, - wp == wp->window->active ? " (active)" : ""); + wp == wp->window->active ? " (active)" : "", + wp->fd == -1 ? " (dead)" : ""); n++; } diff --git a/cmd-list-windows.c b/cmd-list-windows.c index cc12b0f4..7a4a28c2 100644 --- a/cmd-list-windows.c +++ b/cmd-list-windows.c @@ -51,10 +51,10 @@ cmd_list_windows_exec(struct cmd *self, struct cmd_ctx *ctx) return (-1); RB_FOREACH(wl, winlinks, &s->windows) { - ctx->print(ctx, "%d: %s [%ux%u]", - wl->idx, wl->window->name, wl->window->sx, wl->window->sy); layout = layout_dump(wl->window); - ctx->print(ctx, " layout: %s", layout); + ctx->print(ctx, "%d: %s [%ux%u] [layout %s]%s", + wl->idx, wl->window->name, wl->window->sx, wl->window->sy, + layout, wl == s->curw ? " (active)" : ""); xfree(layout); } From ef9b2eb566fc090b773c79e406dd43d0006a3217 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 22 Nov 2010 21:13:13 +0000 Subject: [PATCH 0788/1180] There is somewhere that WINDOW_HIDDEN is getting set when it shouldn't be and I can't find it, but the flag itself is a useless optimisation that only applies to automatic-resize windows, so just dispose of it entirely. Fixes problems reported by Nicholas Riley. --- resize.c | 5 +---- tmux.h | 5 ++--- tty.c | 2 +- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/resize.c b/resize.c index 15f99e7c..af84eaba 100644 --- a/resize.c +++ b/resize.c @@ -113,11 +113,8 @@ recalculate_sizes(void) ssy = s->sy; } } - if (ssx == UINT_MAX || ssy == UINT_MAX) { - w->flags |= WINDOW_HIDDEN; + if (ssx == UINT_MAX || ssy == UINT_MAX) continue; - } - w->flags &= ~WINDOW_HIDDEN; limit = options_get_number(&w->options, "force-width"); if (limit != 0 && ssx > limit) diff --git a/tmux.h b/tmux.h index 0d37e554..e4323a5d 100644 --- a/tmux.h +++ b/tmux.h @@ -843,9 +843,8 @@ struct window { int flags; #define WINDOW_BELL 0x1 -#define WINDOW_HIDDEN 0x2 -#define WINDOW_ACTIVITY 0x4 -#define WINDOW_REDRAW 0x8 +#define WINDOW_ACTIVITY 0x2 +#define WINDOW_REDRAW 0x4 struct options options; diff --git a/tty.c b/tty.c index 379fa42d..63f6127f 100644 --- a/tty.c +++ b/tty.c @@ -547,7 +547,7 @@ tty_write(void (*cmdfn)( if (wp->window->flags & WINDOW_REDRAW || wp->flags & PANE_REDRAW) return; - if (wp->window->flags & WINDOW_HIDDEN || !window_pane_visible(wp)) + if (!window_pane_visible(wp)) return; for (i = 0; i < ARRAY_LENGTH(&clients); i++) { From ebd0eb4fb4790cbf289a0dace00e37fe866c9bf3 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 29 Nov 2010 19:45:58 +0000 Subject: [PATCH 0789/1180] If VISUAL or EDITOR contains "vi", configure mode-keys and status-keys to vi. Based on a diff from martynas@, previously requested by a couple of other people. --- tmux.1 | 16 ++++++++++++++-- tmux.c | 16 ++++++++++++---- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/tmux.1 b/tmux.1 index f738f166..de5144a5 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1852,7 +1852,12 @@ or right justified. .Xc Use vi or emacs-style key bindings in the status line, for example at the command prompt. -Defaults to emacs. +The default is emacs, unless the +.Ev VISUAL +or +.Ev EDITOR +environment variables are set and contain the string +.Ql vi . .It Ic status-left Ar string Display .Ar string @@ -2140,7 +2145,14 @@ Set window modes foreground colour. .Op Ic vi | emacs .Xc Use vi or emacs-style key bindings in copy and choice modes. -Key bindings default to emacs. +As with the +.Ic status-keys +option, the default is emacs, unless +.Ev VISUAL +or +.Ev EDITOR +contains +.Ql vi . .Pp .It Xo Ic mode-mouse .Op Ic on | off diff --git a/tmux.c b/tmux.c index 0562da3b..c5793955 100644 --- a/tmux.c +++ b/tmux.c @@ -231,13 +231,13 @@ main(int argc, char **argv) struct options *oo, *so, *wo; struct keylist *keylist; char *s, *path, *label, *home, **var; - int opt, flags, quiet = 0; + int opt, flags, quiet, keys; #ifdef DEBUG malloc_options = (char *) "AFGJPX"; #endif - flags = 0; + quiet = flags = 0; label = path = NULL; login_shell = (**argv == '-'); while ((opt = getopt(argc, argv, "28c:df:lL:qS:uUv")) != -1) { @@ -359,7 +359,6 @@ main(int argc, char **argv) options_set_number(so, "status-fg", 0); options_set_number(so, "status-interval", 15); options_set_number(so, "status-justify", 0); - options_set_number(so, "status-keys", MODEKEY_EMACS); options_set_string(so, "status-left", "[#S]"); options_set_number(so, "status-left-attr", 0); options_set_number(so, "status-left-bg", 8); @@ -400,7 +399,6 @@ main(int argc, char **argv) options_set_number(wo, "mode-attr", 0); options_set_number(wo, "mode-bg", 3); options_set_number(wo, "mode-fg", 0); - options_set_number(wo, "mode-keys", MODEKEY_EMACS); options_set_number(wo, "mode-mouse", 0); options_set_number(wo, "monitor-activity", 0); options_set_string(wo, "monitor-content", "%s", ""); @@ -428,6 +426,16 @@ main(int argc, char **argv) options_set_number(wo, "utf8", 0); } + keys = MODEKEY_EMACS; + if ((s = getenv("VISUAL")) != NULL || (s = getenv("EDITOR")) != NULL) { + if (strrchr(s, '/') != NULL) + s = strrchr(s, '/') + 1; + if (strstr(s, "vi") != NULL) + keys = MODEKEY_VI; + } + options_set_number(so, "status-keys", keys); + options_set_number(wo, "mode-keys", keys); + /* Locate the configuration file. */ if (cfg_file == NULL) { home = getenv("HOME"); From e26a351865a0d969b3f40ca3c14be7ff8d7533ad Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 6 Dec 2010 22:51:02 +0000 Subject: [PATCH 0790/1180] Add an option to alert (monitor) for silence (lack of activity) in a window. From Thomas Adam. --- cmd-choose-window.c | 2 ++ cmd-set-option.c | 2 ++ input.c | 2 ++ server-window.c | 53 ++++++++++++++++++++++++++++++++++++++++++++- status.c | 2 ++ tmux.1 | 17 +++++++++++++++ tmux.c | 2 ++ tmux.h | 6 ++++- window.c | 8 +++++++ 9 files changed, 92 insertions(+), 2 deletions(-) diff --git a/cmd-choose-window.c b/cmd-choose-window.c index e341dd41..b3e4b2b3 100644 --- a/cmd-choose-window.c +++ b/cmd-choose-window.c @@ -87,6 +87,8 @@ cmd_choose_window_exec(struct cmd *self, struct cmd_ctx *ctx) flag = '!'; else if (wm->flags & WINLINK_CONTENT) flag = '+'; + else if (wm->flags & WINLINK_SILENCE) + flag = '~'; else if (wm == s->curw) flag = '*'; else if (wm == TAILQ_FIRST(&s->lastw)) diff --git a/cmd-set-option.c b/cmd-set-option.c index 684f1b04..7856a52e 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -136,6 +136,7 @@ const struct set_option_entry set_session_option_table[] = { { "visual-activity", SET_OPTION_FLAG, 0, 0, NULL }, { "visual-bell", SET_OPTION_FLAG, 0, 0, NULL }, { "visual-content", SET_OPTION_FLAG, 0, 0, NULL }, + { "visual-silence", SET_OPTION_FLAG, 0, 0, NULL }, { NULL, 0, 0, 0, NULL } }; @@ -157,6 +158,7 @@ const struct set_option_entry set_window_option_table[] = { { "mode-mouse", SET_OPTION_FLAG, 0, 0, NULL }, { "monitor-activity", SET_OPTION_FLAG, 0, 0, NULL }, { "monitor-content", SET_OPTION_STRING, 0, 0, NULL }, + { "monitor-silence",SET_OPTION_NUMBER, 0, INT_MAX, NULL}, { "remain-on-exit", SET_OPTION_FLAG, 0, 0, NULL }, { "synchronize-panes", SET_OPTION_FLAG, 0, 0, NULL }, { "utf8", SET_OPTION_FLAG, 0, 0, NULL }, diff --git a/input.c b/input.c index f49591a7..4a964550 100644 --- a/input.c +++ b/input.c @@ -681,7 +681,9 @@ input_parse(struct window_pane *wp) if (EVBUFFER_LENGTH(evb) == 0) return; + wp->window->flags |= WINDOW_ACTIVITY; + wp->window->flags &= ~WINDOW_SILENCE; /* * Open the screen. Use NULL wp if there is a mode set as don't want to diff --git a/server-window.c b/server-window.c index 634a1b8a..abf82499 100644 --- a/server-window.c +++ b/server-window.c @@ -26,6 +26,7 @@ int server_window_backoff(struct window_pane *); int server_window_check_bell(struct session *, struct winlink *); int server_window_check_activity(struct session *, struct winlink *); +int server_window_check_silence(struct session *, struct winlink *); int server_window_check_content( struct session *, struct winlink *, struct window_pane *); @@ -53,7 +54,8 @@ server_window_loop(void) continue; if (server_window_check_bell(s, wl) || - server_window_check_activity(s, wl)) + server_window_check_activity(s, wl) || + server_window_check_silence(s, wl)) server_status_session(s); TAILQ_FOREACH(wp, &w->panes, entry) server_window_check_content(s, wl, wp); @@ -151,6 +153,55 @@ server_window_check_activity(struct session *s, struct winlink *wl) return (1); } +/* Check for silence in window. */ +int +server_window_check_silence(struct session *s, struct winlink *wl) +{ + struct client *c; + struct window *w = wl->window; + struct timeval timer; + u_int i; + int silence_interval, timer_difference; + + if (!(w->flags & WINDOW_SILENCE) || wl->flags & WINLINK_SILENCE) + return (0); + + if (s->curw == wl) { + /* + * Reset the timer for this window if we've focused it. We + * don't want the timer tripping as soon as we've switched away + * from this window. + */ + if (gettimeofday(&w->silence_timer, NULL) != 0) + fatal("gettimeofday failed."); + + return (0); + } + + silence_interval = options_get_number(&w->options, "monitor-silence"); + if (silence_interval == 0) + return (0); + + if (gettimeofday(&timer, NULL) != 0) + fatal("gettimeofday"); + timer_difference = timer.tv_sec - w->silence_timer.tv_sec; + if (timer_difference <= silence_interval) + return (0); + wl->flags |= WINLINK_SILENCE; + + if (options_get_number(&s->options, "visual-silence")) { + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c == NULL || c->session != s) + continue; + status_message_set(c, "Silence in window %u", + winlink_find_by_window(&s->windows, w)->idx); + } + } + + return (1); +} + /* Check for content change in window. */ int server_window_check_content( diff --git a/status.c b/status.c index b1d93c97..65a0afeb 100644 --- a/status.c +++ b/status.c @@ -395,6 +395,8 @@ status_replace1(struct client *c,struct winlink *wl, tmp[0] = '!'; else if (wl->flags & WINLINK_ACTIVITY) tmp[0] = '#'; + else if (wl->flags & WINLINK_SILENCE) + tmp[0] = '~'; else if (wl == s->curw) tmp[0] = '*'; else if (wl == TAILQ_FIRST(&s->lastw)) diff --git a/tmux.1 b/tmux.1 index de5144a5..8ce1cce9 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2053,6 +2053,12 @@ display a message when content is present in a window for which the .Ic monitor-content window option is enabled. +.It Xo Ic visual-silence +.Op Ic on | off +.Xc +If +.Ic monitor-silence +is enabled, prints a message after the interval has expired on a given window. .El .It Xo Ic set-window-option .Op Fl agu @@ -2175,6 +2181,16 @@ pattern .Ar match-string appears in the window, it is highlighted in the status line. .Pp +.It Xo Ic monitor-silence +.Op Ic interval +.Xc +Monitor for silence (no activity) in the window within +.Ic interval +seconds. +Windows that have been silent for the interval are highlighted in the +status line. +An interval of zero disables the monitoring. +.Pp .It Xo Ic remain-on-exit .Op Ic on | off .Xc @@ -2386,6 +2402,7 @@ The flag is one of the following symbols appended to the window name: .It Li "#" Ta "Window is monitored and activity has been detected." .It Li "!" Ta "A bell has occurred in the window." .It Li "+" Ta "Window is monitored for content and it has appeared." +.It Li "~" Ta "The window has been silent for the monitor-silence interval." .El .Pp The # symbol relates to the diff --git a/tmux.c b/tmux.c index c5793955..0ebeea28 100644 --- a/tmux.c +++ b/tmux.c @@ -379,6 +379,7 @@ main(int argc, char **argv) options_set_number(so, "visual-activity", 0); options_set_number(so, "visual-bell", 0); options_set_number(so, "visual-content", 0); + options_set_number(so, "visual-silence", 0); keylist = xmalloc(sizeof *keylist); ARRAY_INIT(keylist); @@ -402,6 +403,7 @@ main(int argc, char **argv) options_set_number(wo, "mode-mouse", 0); options_set_number(wo, "monitor-activity", 0); options_set_string(wo, "monitor-content", "%s", ""); + options_set_number(wo, "monitor-silence", 0); options_set_number(wo, "window-status-attr", 0); options_set_number(wo, "window-status-bg", 8); options_set_number(wo, "window-status-current-attr", 0); diff --git a/tmux.h b/tmux.h index e4323a5d..529b6439 100644 --- a/tmux.h +++ b/tmux.h @@ -830,6 +830,7 @@ TAILQ_HEAD(window_panes, window_pane); struct window { char *name; struct event name_timer; + struct timeval silence_timer; struct window_pane *active; struct window_pane *last; @@ -845,6 +846,7 @@ struct window { #define WINDOW_BELL 0x1 #define WINDOW_ACTIVITY 0x2 #define WINDOW_REDRAW 0x4 +#define WINDOW_SILENCE 0x8 struct options options; @@ -865,7 +867,9 @@ struct winlink { #define WINLINK_BELL 0x1 #define WINLINK_ACTIVITY 0x2 #define WINLINK_CONTENT 0x4 -#define WINLINK_ALERTFLAGS (WINLINK_BELL|WINLINK_ACTIVITY|WINLINK_CONTENT) +#define WINLINK_SILENCE 0x8 +#define WINLINK_ALERTFLAGS \ + (WINLINK_BELL|WINLINK_ACTIVITY|WINLINK_CONTENT|WINLINK_SILENCE) RB_ENTRY(winlink) entry; TAILQ_ENTRY(winlink) sentry; diff --git a/window.c b/window.c index a7a5c40e..95877cb5 100644 --- a/window.c +++ b/window.c @@ -639,6 +639,14 @@ window_pane_read_callback(unused struct bufferevent *bufev, void *data) input_parse(wp); wp->pipe_off = EVBUFFER_LENGTH(wp->event->input); + + /* + * If we get here, we're not outputting anymore, so set the silence + * flag on the window. + */ + wp->window->flags |= WINDOW_SILENCE; + if (gettimeofday(&wp->window->silence_timer, NULL) != 0) + fatal("gettimeofday failed."); } /* ARGSUSED */ From 1f185235651107efe3d32e1d002ad38619f81bd5 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 8 Dec 2010 19:57:03 +0000 Subject: [PATCH 0791/1180] In the built-in layouts, distribute the panes more evenly. Set the default value of main-pane-width to 80, rather than 81. By Micah Cowan. --- layout-set.c | 85 ++++++++++++++++++++++++++-------------------------- tmux.c | 2 +- 2 files changed, 43 insertions(+), 44 deletions(-) diff --git a/layout-set.c b/layout-set.c index 7ebdead9..cc907ff3 100644 --- a/layout-set.c +++ b/layout-set.c @@ -135,10 +135,9 @@ layout_set_even_h(struct window *w) return; /* How many can we fit? */ - if (w->sx / n < PANE_MINIMUM + 1) - width = PANE_MINIMUM + 1; - else - width = w->sx / n; + width = (w->sx - (n - 1)) / n; + if (width < PANE_MINIMUM) + width = PANE_MINIMUM; /* Free the old root and construct a new. */ layout_free(w); @@ -151,12 +150,12 @@ layout_set_even_h(struct window *w) TAILQ_FOREACH(wp, &w->panes, entry) { /* Create child cell. */ lcnew = layout_create_cell(lc); - layout_set_size(lcnew, width - 1, w->sy, xoff, 0); + layout_set_size(lcnew, width, w->sy, xoff, 0); layout_make_leaf(lcnew, wp); TAILQ_INSERT_TAIL(&lc->cells, lcnew, entry); i++; - xoff += width; + xoff += width + 1; } /* Allocate any remaining space. */ @@ -189,10 +188,9 @@ layout_set_even_v(struct window *w) return; /* How many can we fit? */ - if (w->sy / n < PANE_MINIMUM + 1) - height = PANE_MINIMUM + 1; - else - height = w->sy / n; + height = (w->sy - (n - 1)) / n; + if (height < PANE_MINIMUM) + height = PANE_MINIMUM; /* Free the old root and construct a new. */ layout_free(w); @@ -205,12 +203,12 @@ layout_set_even_v(struct window *w) TAILQ_FOREACH(wp, &w->panes, entry) { /* Create child cell. */ lcnew = layout_create_cell(lc); - layout_set_size(lcnew, w->sx, height - 1, 0, yoff); + layout_set_size(lcnew, w->sx, height, 0, yoff); layout_make_leaf(lcnew, wp); TAILQ_INSERT_TAIL(&lc->cells, lcnew, entry); i++; - yoff += height; + yoff += height + 1; } /* Allocate any remaining space. */ @@ -244,13 +242,13 @@ layout_set_main_h(struct window *w) return; n--; /* take off main pane */ - /* How many rows and columns will be needed? */ - columns = w->sx / (PANE_MINIMUM + 1); /* maximum columns */ + /* How many rows and columns will be needed, not counting main? */ + columns = (w->sx + 1) / (PANE_MINIMUM + 1); /* maximum columns */ if (columns == 0) columns = 1; rows = 1 + (n - 1) / columns; columns = 1 + (n - 1) / rows; - width = w->sx / columns; + width = (w->sx - (n - 1)) / columns; /* Get the main pane height and add one for separator line. */ mainheight = options_get_number(&w->options, "main-pane-height") + 1; @@ -264,14 +262,14 @@ layout_set_main_h(struct window *w) mainheight = PANE_MINIMUM + 2; else mainheight = w->sy - totalrows; - height = PANE_MINIMUM + 1; + height = PANE_MINIMUM; } else - height = (w->sy - mainheight) / rows; + height = (w->sy - mainheight - (rows - 1)) / rows; /* Free old tree and create a new root. */ layout_free(w); lc = w->layout_root = layout_create_cell(NULL); - layout_set_size(lc, w->sx, mainheight + rows * height, 0, 0); + layout_set_size(lc, w->sx, mainheight + rows * (height + 1) - 1, 0, 0); layout_make_node(lc, LAYOUT_TOPBOTTOM); /* Create the main pane. */ @@ -289,7 +287,7 @@ layout_set_main_h(struct window *w) /* Create the new row. */ lcrow = layout_create_cell(lc); - layout_set_size(lcrow, w->sx, height - 1, 0, 0); + layout_set_size(lcrow, w->sx, height, 0, 0); TAILQ_INSERT_TAIL(&lc->cells, lcrow, entry); /* If only one column, just use the row directly. */ @@ -304,7 +302,7 @@ layout_set_main_h(struct window *w) for (i = 0; i < columns; i++) { /* Create and add a pane cell. */ lcchild = layout_create_cell(lcrow); - layout_set_size(lcchild, width - 1, height - 1, 0, 0); + layout_set_size(lcchild, width, height, 0, 0); layout_make_leaf(lcchild, wp); TAILQ_INSERT_TAIL(&lcrow->cells, lcchild, entry); @@ -316,7 +314,7 @@ layout_set_main_h(struct window *w) /* Adjust the row to fit the full width if necessary. */ if (i == columns) i--; - used = ((i + 1) * width) - 1; + used = ((i + 1) * (width + 1)) - 1; if (w->sx <= used) continue; lcchild = TAILQ_LAST(&lcrow->cells, layout_cells); @@ -324,7 +322,7 @@ layout_set_main_h(struct window *w) } /* Adjust the last row height to fit if necessary. */ - used = mainheight + (rows * height) - 1; + used = mainheight + (rows * height) + rows - 1; if (w->sy > used) { lcrow = TAILQ_LAST(&lc->cells, layout_cells); layout_resize_adjust(lcrow, LAYOUT_TOPBOTTOM, w->sy - used); @@ -355,13 +353,13 @@ layout_set_main_v(struct window *w) return; n--; /* take off main pane */ - /* How many rows and columns will be needed? */ - rows = w->sy / (PANE_MINIMUM + 1); /* maximum rows */ + /* How many rows and columns will be needed, not counting main? */ + rows = (w->sy + 1) / (PANE_MINIMUM + 1); /* maximum rows */ if (rows == 0) rows = 1; columns = 1 + (n - 1) / rows; rows = 1 + (n - 1) / columns; - height = w->sy / rows; + height = (w->sy - (n - 1)) / rows; /* Get the main pane width and add one for separator line. */ mainwidth = options_get_number(&w->options, "main-pane-width") + 1; @@ -375,14 +373,14 @@ layout_set_main_v(struct window *w) mainwidth = PANE_MINIMUM + 2; else mainwidth = w->sx - totalcolumns; - width = PANE_MINIMUM + 1; + width = PANE_MINIMUM; } else - width = (w->sx - mainwidth) / columns; + width = (w->sx - mainwidth - (columns - 1)) / columns; /* Free old tree and create a new root. */ layout_free(w); lc = w->layout_root = layout_create_cell(NULL); - layout_set_size(lc, mainwidth + columns * width, w->sy, 0, 0); + layout_set_size(lc, mainwidth + columns * (width + 1) - 1, w->sy, 0, 0); layout_make_node(lc, LAYOUT_LEFTRIGHT); /* Create the main pane. */ @@ -400,7 +398,7 @@ layout_set_main_v(struct window *w) /* Create the new column. */ lccolumn = layout_create_cell(lc); - layout_set_size(lccolumn, width - 1, w->sy, 0, 0); + layout_set_size(lccolumn, width, w->sy, 0, 0); TAILQ_INSERT_TAIL(&lc->cells, lccolumn, entry); /* If only one row, just use the row directly. */ @@ -415,7 +413,7 @@ layout_set_main_v(struct window *w) for (i = 0; i < rows; i++) { /* Create and add a pane cell. */ lcchild = layout_create_cell(lccolumn); - layout_set_size(lcchild, width - 1, height - 1, 0, 0); + layout_set_size(lcchild, width, height, 0, 0); layout_make_leaf(lcchild, wp); TAILQ_INSERT_TAIL(&lccolumn->cells, lcchild, entry); @@ -427,7 +425,7 @@ layout_set_main_v(struct window *w) /* Adjust the column to fit the full height if necessary. */ if (i == rows) i--; - used = ((i + 1) * height) - 1; + used = ((i + 1) * (height + 1)) - 1; if (w->sy <= used) continue; lcchild = TAILQ_LAST(&lccolumn->cells, layout_cells); @@ -435,7 +433,7 @@ layout_set_main_v(struct window *w) } /* Adjust the last column width to fit if necessary. */ - used = mainwidth + (columns * width) - 1; + used = mainwidth + (columns * width) + columns - 1; if (w->sx > used) { lccolumn = TAILQ_LAST(&lc->cells, layout_cells); layout_resize_adjust(lccolumn, LAYOUT_LEFTRIGHT, w->sx - used); @@ -474,17 +472,18 @@ layout_set_tiled(struct window *w) } /* What width and height should they be? */ - width = w->sx / columns; - if (width < PANE_MINIMUM + 1) - width = PANE_MINIMUM + 1; - height = w->sy / rows; - if (width < PANE_MINIMUM + 1) - width = PANE_MINIMUM + 1; + width = (w->sx - (columns - 1)) / columns; + if (width < PANE_MINIMUM) + width = PANE_MINIMUM; + height = (w->sy - (rows - 1)) / rows; + if (height < PANE_MINIMUM) + height = PANE_MINIMUM; /* Free old tree and create a new root. */ layout_free(w); lc = w->layout_root = layout_create_cell(NULL); - layout_set_size(lc, width * columns, height * rows, 0, 0); + layout_set_size(lc, (width + 1) * columns - 1, + (height + 1) * rows - 1, 0, 0); layout_make_node(lc, LAYOUT_TOPBOTTOM); /* Create a grid of the cells. */ @@ -496,7 +495,7 @@ layout_set_tiled(struct window *w) /* Create the new row. */ lcrow = layout_create_cell(lc); - layout_set_size(lcrow, w->sx, height - 1, 0, 0); + layout_set_size(lcrow, w->sx, height, 0, 0); TAILQ_INSERT_TAIL(&lc->cells, lcrow, entry); /* If only one column, just use the row directly. */ @@ -511,7 +510,7 @@ layout_set_tiled(struct window *w) for (i = 0; i < columns; i++) { /* Create and add a pane cell. */ lcchild = layout_create_cell(lcrow); - layout_set_size(lcchild, width - 1, height - 1, 0, 0); + layout_set_size(lcchild, width, height, 0, 0); layout_make_leaf(lcchild, wp); TAILQ_INSERT_TAIL(&lcrow->cells, lcchild, entry); @@ -526,7 +525,7 @@ layout_set_tiled(struct window *w) */ if (i == columns) i--; - used = ((i + 1) * width) - 1; + used = ((i + 1) * (width + 1)) - 1; if (w->sx <= used) continue; lcchild = TAILQ_LAST(&lcrow->cells, layout_cells); @@ -534,7 +533,7 @@ layout_set_tiled(struct window *w) } /* Adjust the last row height to fit if necessary. */ - used = (rows * height) - 1; + used = (rows * height) + rows - 1; if (w->sy > used) { lcrow = TAILQ_LAST(&lc->cells, layout_cells); layout_resize_adjust(lcrow, LAYOUT_TOPBOTTOM, w->sy - used); diff --git a/tmux.c b/tmux.c index 0ebeea28..662007a7 100644 --- a/tmux.c +++ b/tmux.c @@ -396,7 +396,7 @@ main(int argc, char **argv) options_set_number(wo, "force-height", 0); options_set_number(wo, "force-width", 0); options_set_number(wo, "main-pane-height", 24); - options_set_number(wo, "main-pane-width", 81); + options_set_number(wo, "main-pane-width", 80); options_set_number(wo, "mode-attr", 0); options_set_number(wo, "mode-bg", 3); options_set_number(wo, "mode-fg", 0); From 6be32c89c5b52f4a07fe9694bc4f899be1389d17 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 10 Dec 2010 21:01:38 +0000 Subject: [PATCH 0792/1180] Rephrase a confusing sentence. --- tmux.1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tmux.1 b/tmux.1 index 8ce1cce9..28f71d83 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2319,9 +2319,9 @@ copies the environment into the .Em global environment ; in addition, each session has a .Em session environment . -When a window is created, the session and global environments are merged with -the session environment overriding any variable present in both. -This is the initial environment passed to the new process. +When a window is created, the session and global environments are merged. +If a variable exists in both, the value from the session environment is used. +The result is the initial environment passed to the new process. .Pp The .Ic update-environment From 7ce77ffc9c4973197377ecdfa329ba1cdd6af75e Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 11 Dec 2010 16:05:57 +0000 Subject: [PATCH 0793/1180] Make the prompt history global for all clients which is much more useful than per-client history. --- server-client.c | 5 --- status.c | 82 ++++++++++++++++++++++++++++++++++--------------- tmux.h | 4 +-- 3 files changed, 58 insertions(+), 33 deletions(-) diff --git a/server-client.c b/server-client.c index cd3eb079..80ec0e91 100644 --- a/server-client.c +++ b/server-client.c @@ -70,8 +70,6 @@ server_client_create(int fd) fatal("gettimeofday failed"); memcpy(&c->activity_time, &c->creation_time, sizeof c->activity_time); - ARRAY_INIT(&c->prompt_hdata); - c->stdin_event = NULL; c->stdout_event = NULL; c->stderr_event = NULL; @@ -161,9 +159,6 @@ server_client_lost(struct client *c) xfree(c->prompt_string); if (c->prompt_buffer != NULL) xfree(c->prompt_buffer); - for (i = 0; i < ARRAY_LENGTH(&c->prompt_hdata); i++) - xfree(ARRAY_ITEM(&c->prompt_hdata, i)); - ARRAY_FREE(&c->prompt_hdata); if (c->cwd != NULL) xfree(c->cwd); diff --git a/status.c b/status.c index 65a0afeb..aac6c828 100644 --- a/status.c +++ b/status.c @@ -41,9 +41,14 @@ void status_replace1(struct client *, struct winlink *, char **, char **, char *, size_t, int); void status_message_callback(int, short, void *); -void status_prompt_add_history(struct client *); +const char *status_prompt_up_history(u_int *); +const char *status_prompt_down_history(u_int *); +void status_prompt_add_history(const char *); char *status_prompt_complete(const char *); +/* Status prompt history. */ +ARRAY_DECL(, char *) status_prompt_history = ARRAY_INITIALIZER; + /* Retrieve options for left string. */ char * status_redraw_get_left(struct client *c, @@ -972,29 +977,20 @@ status_prompt_key(struct client *c, int key) } break; case MODEKEYEDIT_HISTORYUP: - if (ARRAY_LENGTH(&c->prompt_hdata) == 0) + s = status_prompt_up_history(&c->prompt_hindex); + if (s == NULL) break; xfree(c->prompt_buffer); - - c->prompt_buffer = xstrdup(ARRAY_ITEM(&c->prompt_hdata, - ARRAY_LENGTH(&c->prompt_hdata) - 1 - c->prompt_hindex)); - if (c->prompt_hindex != ARRAY_LENGTH(&c->prompt_hdata) - 1) - c->prompt_hindex++; - + c->prompt_buffer = xstrdup(s); c->prompt_index = strlen(c->prompt_buffer); c->flags |= CLIENT_STATUS; break; case MODEKEYEDIT_HISTORYDOWN: + s = status_prompt_down_history(&c->prompt_hindex); + if (s == NULL) + break; xfree(c->prompt_buffer); - - if (c->prompt_hindex != 0) { - c->prompt_hindex--; - c->prompt_buffer = xstrdup(ARRAY_ITEM( - &c->prompt_hdata, ARRAY_LENGTH( - &c->prompt_hdata) - 1 - c->prompt_hindex)); - } else - c->prompt_buffer = xstrdup(""); - + c->prompt_buffer = xstrdup(s); c->prompt_index = strlen(c->prompt_buffer); c->flags |= CLIENT_STATUS; break; @@ -1036,7 +1032,7 @@ status_prompt_key(struct client *c, int key) break; case MODEKEYEDIT_ENTER: if (*c->prompt_buffer != '\0') - status_prompt_add_history(c); + status_prompt_add_history(c->prompt_buffer); if (c->prompt_callbackfn(c->prompt_data, c->prompt_buffer) == 0) status_prompt_clear(c); break; @@ -1072,20 +1068,56 @@ status_prompt_key(struct client *c, int key) } } +/* Get previous line from the history. */ +const char * +status_prompt_up_history(u_int *idx) +{ + u_int size; + + /* + * History runs from 0 to size - 1. + * + * Index is from 0 to size. Zero is empty. + */ + + size = ARRAY_LENGTH(&status_prompt_history); + if (size == 0 || *idx == size) + return (NULL); + (*idx)++; + return (ARRAY_ITEM(&status_prompt_history, size - *idx)); +} + +/* Get next line from the history. */ +const char * +status_prompt_down_history(u_int *idx) +{ + u_int size; + + size = ARRAY_LENGTH(&status_prompt_history); + if (size == 0 || *idx == 0) + return (""); + (*idx)--; + if (*idx == 0) + return (""); + return (ARRAY_ITEM(&status_prompt_history, size - *idx)); +} + /* Add line to the history. */ void -status_prompt_add_history(struct client *c) +status_prompt_add_history(const char *line) { - if (ARRAY_LENGTH(&c->prompt_hdata) > 0 && - strcmp(ARRAY_LAST(&c->prompt_hdata), c->prompt_buffer) == 0) + u_int size; + + size = ARRAY_LENGTH(&status_prompt_history); + if (size > 0 && strcmp(ARRAY_LAST(&status_prompt_history), line) == 0) return; - if (ARRAY_LENGTH(&c->prompt_hdata) == PROMPT_HISTORY) { - xfree(ARRAY_FIRST(&c->prompt_hdata)); - ARRAY_REMOVE(&c->prompt_hdata, 0); + if (size == PROMPT_HISTORY) { + xfree(ARRAY_FIRST(&status_prompt_history)); + ARRAY_REMOVE(&status_prompt_history, 0); } - ARRAY_ADD(&c->prompt_hdata, xstrdup(c->prompt_buffer)); + ARRAY_ADD(&status_prompt_history, xstrdup(line)); } /* Complete word. */ diff --git a/tmux.h b/tmux.h index 529b6439..3fd5ef8b 100644 --- a/tmux.h +++ b/tmux.h @@ -1147,13 +1147,11 @@ struct client { int (*prompt_callbackfn)(void *, const char *); void (*prompt_freefn)(void *); void *prompt_data; + u_int prompt_hindex; #define PROMPT_SINGLE 0x1 int prompt_flags; - u_int prompt_hindex; - ARRAY_DECL(, char *) prompt_hdata; - struct mode_key_data prompt_mdata; struct session *session; From 9802fea6152197c7887937c0d1e8637ae317443b Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 11 Dec 2010 16:13:15 +0000 Subject: [PATCH 0794/1180] Oops, these functions return a const char *, so make the local variable const as well. --- status.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/status.c b/status.c index aac6c828..74316f2d 100644 --- a/status.c +++ b/status.c @@ -865,6 +865,7 @@ status_prompt_key(struct client *c, int key) { struct paste_buffer *pb; char *s, *first, *last, word[64], swapc; + const char *histstr; u_char ch; size_t size, n, off, idx; @@ -977,20 +978,20 @@ status_prompt_key(struct client *c, int key) } break; case MODEKEYEDIT_HISTORYUP: - s = status_prompt_up_history(&c->prompt_hindex); - if (s == NULL) + histstr = status_prompt_up_history(&c->prompt_hindex); + if (histstr == NULL) break; xfree(c->prompt_buffer); - c->prompt_buffer = xstrdup(s); + c->prompt_buffer = xstrdup(histstr); c->prompt_index = strlen(c->prompt_buffer); c->flags |= CLIENT_STATUS; break; case MODEKEYEDIT_HISTORYDOWN: - s = status_prompt_down_history(&c->prompt_hindex); - if (s == NULL) + histstr = status_prompt_down_history(&c->prompt_hindex); + if (histstr == NULL) break; xfree(c->prompt_buffer); - c->prompt_buffer = xstrdup(s); + c->prompt_buffer = xstrdup(histstr); c->prompt_index = strlen(c->prompt_buffer); c->flags |= CLIENT_STATUS; break; From 20ed20ea1eb996cbfc530688dac7646f58a43fe6 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 11 Dec 2010 17:56:01 +0000 Subject: [PATCH 0795/1180] Fix rectangle copy to behave like emacs - the cursor is not part of the selection on the right edge but on the left it is. --- screen.c | 4 ++-- window-copy.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/screen.c b/screen.c index 333ff969..1860e247 100644 --- a/screen.c +++ b/screen.c @@ -287,7 +287,7 @@ screen_check_selection(struct screen *s, u_int px, u_int py) */ if (sel->ex < sel->sx) { /* Cursor (ex) is on the left. */ - if (px <= sel->ex) + if (px < sel->ex) return (0); if (px > sel->sx) @@ -297,7 +297,7 @@ screen_check_selection(struct screen *s, u_int px, u_int py) if (px < sel->sx) return (0); - if (px >= sel->ex) + if (px > sel->ex) return (0); } } else { diff --git a/window-copy.c b/window-copy.c index b66eb74f..9f92464b 100644 --- a/window-copy.c +++ b/window-copy.c @@ -1267,8 +1267,8 @@ window_copy_copy_selection(struct window_pane *wp, struct session *sess) /* Cursor is on the left. */ lastex = data->selx + 1; restex = data->selx + 1; - firstsx = data->cx + 1; - restsx = data->cx + 1; + firstsx = data->cx; + restsx = data->cx; } } else { /* From 51487ed22f0acf199f64728f3efc15a3c9ad615f Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 11 Dec 2010 18:39:25 +0000 Subject: [PATCH 0796/1180] Track the last session for a client and add a flag to switch-client and a key binding (L) to move a client back to its last session. --- cmd-new-session.c | 8 +++++++ cmd-switch-client.c | 52 +++++++++++++++++++++++++++++++++------------ key-bindings.c | 1 + server-client.c | 1 + server-fn.c | 1 + tmux.1 | 8 +++++-- tmux.h | 1 + 7 files changed, 57 insertions(+), 15 deletions(-) diff --git a/cmd-new-session.c b/cmd-new-session.c index 290d5a3b..573b0ebb 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -279,9 +279,17 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) if (!detached) { if (ctx->cmdclient != NULL) { server_write_client(ctx->cmdclient, MSG_READY, NULL, 0); + if (ctx->cmdclient->session != NULL) { + session_index(ctx->cmdclient->session, + &ctx->cmdclient->last_session); + } ctx->cmdclient->session = s; server_redraw_client(ctx->cmdclient); } else { + if (ctx->curclient->session != NULL) { + session_index(ctx->curclient->session, + &ctx->curclient->last_session); + } ctx->curclient->session = s; server_redraw_client(ctx->curclient); } diff --git a/cmd-switch-client.c b/cmd-switch-client.c index bce42c2a..dfe8aca1 100644 --- a/cmd-switch-client.c +++ b/cmd-switch-client.c @@ -36,13 +36,14 @@ size_t cmd_switch_client_print(struct cmd *, char *, size_t); struct cmd_switch_client_data { char *name; char *target; + int flag_last; int flag_next; int flag_previous; }; const struct cmd_entry cmd_switch_client_entry = { "switch-client", "switchc", - "[-np] [-c target-client] [-t target-session]", + "[-lnp] [-c target-client] [-t target-session]", 0, "", cmd_switch_client_init, cmd_switch_client_parse, @@ -59,6 +60,7 @@ cmd_switch_client_init(struct cmd *self, int key) self->data = data = xmalloc(sizeof *data); data->name = NULL; data->target = NULL; + data->flag_last = 0; data->flag_next = 0; data->flag_previous = 0; @@ -69,6 +71,9 @@ cmd_switch_client_init(struct cmd *self, int key) case ')': data->flag_next = 1; break; + case 'L': + data->flag_last = 1; + break; } } @@ -81,28 +86,36 @@ cmd_switch_client_parse(struct cmd *self, int argc, char **argv, char **cause) self->entry->init(self, KEYC_NONE); data = self->data; - while ((opt = getopt(argc, argv, "c:t:")) != -1) { + while ((opt = getopt(argc, argv, "c:lnpt:")) != -1) { switch (opt) { case 'c': if (data->name == NULL) data->name = xstrdup(optarg); break; + case 'l': + if (data->flag_next || data->flag_previous || + data->target != NULL) + goto usage; + data->flag_last = 1; + break; + case 'n': + if (data->flag_previous || data->flag_last || + data->target != NULL) + goto usage; + data->flag_next = 1; + break; + case 'p': + if (data->flag_next || data->flag_last || + data->target != NULL) + goto usage; + data->flag_next = 1; + break; case 't': if (data->flag_next || data->flag_previous) goto usage; if (data->target == NULL) data->target = xstrdup(optarg); break; - case 'n': - if (data->flag_previous || data->target != NULL) - goto usage; - data->flag_next = 1; - break; - case 'p': - if (data->flag_next || data->target != NULL) - goto usage; - data->flag_next = 1; - break; default: goto usage; } @@ -134,6 +147,7 @@ cmd_switch_client_exec(struct cmd *self, struct cmd_ctx *ctx) if ((c = cmd_find_client(ctx, data->name)) == NULL) return (-1); + s = NULL; if (data->flag_next) { if ((s = session_next_session(c->session)) == NULL) { ctx->error(ctx, "can't find next session"); @@ -144,11 +158,21 @@ cmd_switch_client_exec(struct cmd *self, struct cmd_ctx *ctx) ctx->error(ctx, "can't find previous session"); return (-1); } + } else if (data->flag_last) { + if (c->last_session != UINT_MAX && + c->last_session < ARRAY_LENGTH(&sessions)) + s = ARRAY_ITEM(&sessions, c->last_session); + if (s == NULL) { + ctx->error(ctx, "can't find last session"); + return (-1); + } } else s = cmd_find_session(ctx, data->target); - if (s == NULL) return (-1); + + if (c->session != NULL) + session_index(c->session, &c->last_session); c->session = s; recalculate_sizes(); @@ -179,6 +203,8 @@ cmd_switch_client_print(struct cmd *self, char *buf, size_t len) off += xsnprintf(buf, len, "%s", self->entry->name); if (data == NULL) return (off); + if (off < len && data->flag_last) + off += xsnprintf(buf + off, len - off, "%s", " -l"); if (off < len && data->flag_next) off += xsnprintf(buf + off, len - off, "%s", " -n"); if (off < len && data->flag_previous) diff --git a/key-bindings.c b/key-bindings.c index 721620ff..32e81e94 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -128,6 +128,7 @@ key_bindings_init(void) { '=', 0, &cmd_choose_buffer_entry }, { '?', 0, &cmd_list_keys_entry }, { 'D', 0, &cmd_choose_client_entry }, + { 'L', 0, &cmd_switch_client_entry }, { '[', 0, &cmd_copy_mode_entry }, { '\'', 0, &cmd_command_prompt_entry }, { '\002', /* C-b */ 0, &cmd_send_prefix_entry }, diff --git a/server-client.c b/server-client.c index 80ec0e91..290a175a 100644 --- a/server-client.c +++ b/server-client.c @@ -78,6 +78,7 @@ server_client_create(int fd) c->title = NULL; c->session = NULL; + c->last_session = UINT_MAX; c->tty.sx = 80; c->tty.sy = 24; diff --git a/server-fn.c b/server-fn.c index 59f61373..20a245e0 100644 --- a/server-fn.c +++ b/server-fn.c @@ -399,6 +399,7 @@ server_destroy_session(struct session *s) c->session = NULL; c->flags |= CLIENT_EXIT; } else { + c->last_session = UINT_MAX; c->session = s_new; server_redraw_client(c); } diff --git a/tmux.1 b/tmux.1 index 28f71d83..2ebe43ce 100644 --- a/tmux.1 +++ b/tmux.1 @@ -282,6 +282,8 @@ Briefly display pane indexes. Force redraw of the attached client. .It s Select a new session for the attached client interactively. +.It L +Switch the attached client back to the last session. .It t Show the time. .It w @@ -662,7 +664,7 @@ Suspend a client by sending .Dv SIGTSTP (tty stop). .It Xo Ic switch-client -.Op Fl np +.Op Fl lnp .Op Fl c Ar target-client .Op Fl t Ar target-session .Xc @@ -672,10 +674,12 @@ Switch the current session for client to .Ar target-session . If +.Fl l, .Fl n or .Fl p -is used, the client is moved to the next or previous session respectively. +is used, the client is moved to the last, next or previous session +respectively. .El .Sh WINDOWS AND PANES A diff --git a/tmux.h b/tmux.h index 3fd5ef8b..11665195 100644 --- a/tmux.h +++ b/tmux.h @@ -1155,6 +1155,7 @@ struct client { struct mode_key_data prompt_mdata; struct session *session; + u_int last_session; int references; }; From 8715247a43c05fe68d6ab2062b0d23c8777c7671 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 13 Dec 2010 22:53:14 +0000 Subject: [PATCH 0797/1180] Read ${X} environment variables in strings and $HOME from the global environment rather than getenv, this allows them to be updated during the configuration file. --- cmd-string.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/cmd-string.c b/cmd-string.c index 2a5e2b24..9384f9e2 100644 --- a/cmd-string.c +++ b/cmd-string.c @@ -247,9 +247,10 @@ error: char * cmd_string_variable(const char *s, size_t *p) { - int ch, fch; - char *buf, *t; - size_t len; + int ch, fch; + char *buf, *t; + size_t len; + struct environ_entry *envent; #define cmd_string_first(ch) ((ch) == '_' || \ ((ch) >= 'a' && (ch) <= 'z') || ((ch) >= 'A' && (ch) <= 'Z')) @@ -301,12 +302,11 @@ cmd_string_variable(const char *s, size_t *p) buf = xrealloc(buf, 1, len + 1); buf[len] = '\0'; - if ((t = getenv(buf)) == NULL) { - xfree(buf); - return (xstrdup("")); - } + envent = environ_find(&global_environ, buf); xfree(buf); - return (xstrdup(t)); + if (envent == NULL) + return (xstrdup("")); + return (xstrdup(envent->value)); error: if (buf != NULL) @@ -317,15 +317,17 @@ error: char * cmd_string_expand_tilde(const char *s, size_t *p) { - struct passwd *pw; - char *home, *path, *username; + struct passwd *pw; + struct environ_entry *envent; + char *home, *path, *username; home = NULL; if (cmd_string_getc(s, p) == '/') { - if ((home = getenv("HOME")) == NULL || *home == '\0') { - if ((pw = getpwuid(getuid())) != NULL) - home = pw->pw_dir; - } + envent = environ_find(&global_environ, "HOME"); + if (envent != NULL && *envent->value != '\0') + home = envent->value; + else if ((pw = getpwuid(getuid())) != NULL) + home = pw->pw_dir; } else { cmd_string_ungetc(p); if ((username = cmd_string_string(s, p, '/', 0)) == NULL) From c198664d151f51575ebf7f445f5f26d61e1b67a2 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 19 Dec 2010 18:35:08 +0000 Subject: [PATCH 0798/1180] Add other-pane-height and other-pane-width options, allowing the width or height of the smaller panes in the main-horizontal and main-vertical layouts to be set. Mostly from David Goodlad. --- cmd-set-option.c | 2 ++ layout-set.c | 28 ++++++++++++++++++++++++---- tmux.1 | 19 +++++++++++++++++++ tmux.c | 2 ++ 4 files changed, 47 insertions(+), 4 deletions(-) diff --git a/cmd-set-option.c b/cmd-set-option.c index 7856a52e..5c5c70ae 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -159,6 +159,8 @@ const struct set_option_entry set_window_option_table[] = { { "monitor-activity", SET_OPTION_FLAG, 0, 0, NULL }, { "monitor-content", SET_OPTION_STRING, 0, 0, NULL }, { "monitor-silence",SET_OPTION_NUMBER, 0, INT_MAX, NULL}, + { "other-pane-height", SET_OPTION_NUMBER, 0, INT_MAX, NULL }, + { "other-pane-width", SET_OPTION_NUMBER, 0, INT_MAX, NULL }, { "remain-on-exit", SET_OPTION_FLAG, 0, 0, NULL }, { "synchronize-panes", SET_OPTION_FLAG, 0, 0, NULL }, { "utf8", SET_OPTION_FLAG, 0, 0, NULL }, diff --git a/layout-set.c b/layout-set.c index cc907ff3..63a6a69e 100644 --- a/layout-set.c +++ b/layout-set.c @@ -231,8 +231,8 @@ layout_set_main_h(struct window *w) { struct window_pane *wp; struct layout_cell *lc, *lcmain, *lcrow, *lcchild; - u_int n, mainheight, width, height, used; - u_int i, j, columns, rows, totalrows; + u_int n, mainheight, otherheight, width, height; + u_int used, i, j, columns, rows, totalrows; layout_print_cell(w->layout_root, __func__, 1); @@ -252,6 +252,16 @@ layout_set_main_h(struct window *w) /* Get the main pane height and add one for separator line. */ mainheight = options_get_number(&w->options, "main-pane-height") + 1; + + /* Get the optional other pane height and add one for separator line. */ + otherheight = options_get_number(&w->options, "other-pane-height") + 1; + + /* + * If an other pane height was specified, honour it so long as it + * doesn't shrink the main height to less than the main-pane-height + */ + if (otherheight > 1 && w->sx - otherheight > mainheight) + mainheight = w->sx - otherheight; if (mainheight < PANE_MINIMUM + 1) mainheight = PANE_MINIMUM + 1; @@ -342,8 +352,8 @@ layout_set_main_v(struct window *w) { struct window_pane *wp; struct layout_cell *lc, *lcmain, *lccolumn, *lcchild; - u_int n, mainwidth, width, height, used; - u_int i, j, columns, rows, totalcolumns; + u_int n, mainwidth, otherwidth, width, height; + u_int used, i, j, columns, rows, totalcolumns; layout_print_cell(w->layout_root, __func__, 1); @@ -363,6 +373,16 @@ layout_set_main_v(struct window *w) /* Get the main pane width and add one for separator line. */ mainwidth = options_get_number(&w->options, "main-pane-width") + 1; + + /* Get the optional other pane width and add one for separator line. */ + otherwidth = options_get_number(&w->options, "other-pane-width") + 1; + + /* + * If an other pane width was specified, honour it so long as it + * doesn't shrink the main width to less than the main-pane-width + */ + if (otherwidth > 1 && w->sx - otherwidth > mainwidth) + mainwidth = w->sx - otherwidth; if (mainwidth < PANE_MINIMUM + 1) mainwidth = PANE_MINIMUM + 1; diff --git a/tmux.1 b/tmux.1 index 2ebe43ce..d958bbb1 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2195,6 +2195,25 @@ Windows that have been silent for the interval are highlighted in the status line. An interval of zero disables the monitoring. .Pp +.It Ic other-pane-height Ar height +Set the height of the other panes (not the main pane) in the +.Ic main-horizontal +layout. +If this option is set to 0 (the default), it will have no effect. +If both the +.Ic main-pane-height +and +.Ic other-pane-height +options are set, the main pane will grow taller to make the other panes the +specified height, but will never shrink to do so. +.Pp +.It Ic other-pane-width Ar width +Like +.Ic other-pane-height , +but set the width of other panes in the +.Ic main-vertical +layout. +.Pp .It Xo Ic remain-on-exit .Op Ic on | off .Xc diff --git a/tmux.c b/tmux.c index 662007a7..2618ce31 100644 --- a/tmux.c +++ b/tmux.c @@ -404,6 +404,8 @@ main(int argc, char **argv) options_set_number(wo, "monitor-activity", 0); options_set_string(wo, "monitor-content", "%s", ""); options_set_number(wo, "monitor-silence", 0); + options_set_number(wo, "other-pane-height", 0); + options_set_number(wo, "other-pane-width", 0); options_set_number(wo, "window-status-attr", 0); options_set_number(wo, "window-status-bg", 8); options_set_number(wo, "window-status-current-attr", 0); From c65d4220f019b8022ae0192d4a9014be5cc08f40 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 19 Dec 2010 22:35:54 +0000 Subject: [PATCH 0799/1180] Don't nuke the index counter when a session group comes up. --- cmd-choose-session.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd-choose-session.c b/cmd-choose-session.c index 23228105..7cd56f5d 100644 --- a/cmd-choose-session.c +++ b/cmd-choose-session.c @@ -55,7 +55,7 @@ cmd_choose_session_exec(struct cmd *self, struct cmd_ctx *ctx) struct winlink *wl; struct session *s; struct session_group *sg; - u_int i, idx, cur; + u_int i, idx, sgidx, cur; char tmp[64]; if (ctx->curclient == NULL) { @@ -82,8 +82,8 @@ cmd_choose_session_exec(struct cmd *self, struct cmd_ctx *ctx) if (sg == NULL) *tmp = '\0'; else { - idx = session_group_index(sg); - xsnprintf(tmp, sizeof tmp, " (group %u)", idx); + sgidx = session_group_index(sg); + xsnprintf(tmp, sizeof tmp, " (group %u)", sgidx); } window_choose_add(wl->window->active, i, From a51dcdc430150b688d56ec35e8c96ce6f978f68b Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 20 Dec 2010 00:03:55 +0000 Subject: [PATCH 0800/1180] Unify the way sessions are used by callbacks - store the address and use the reference count, then check it is still on the global sessions list in the callback. --- cmd-choose-window.c | 9 ++++----- cmd-find-window.c | 33 +++++++++++++++++++++++---------- cmd-load-buffer.c | 5 +++-- session.c | 12 ++++++++++++ tmux.h | 1 + 5 files changed, 43 insertions(+), 17 deletions(-) diff --git a/cmd-choose-window.c b/cmd-choose-window.c index b3e4b2b3..3f4c956b 100644 --- a/cmd-choose-window.c +++ b/cmd-choose-window.c @@ -129,20 +129,19 @@ void cmd_choose_window_callback(void *data, int idx) { struct cmd_choose_window_data *cdata = data; + struct session *s = cdata->session; struct cmd_list *cmdlist; struct cmd_ctx ctx; char *target, *template, *cause; if (idx == -1) return; + if (!session_alive(s)) + return; if (cdata->client->flags & CLIENT_DEAD) return; - if (cdata->session->flags & SESSION_DEAD) - return; - if (cdata->client->session != cdata->session) - return; - xasprintf(&target, "%s:%d", cdata->session->name, idx); + xasprintf(&target, "%s:%d", s->name, idx); template = cmd_template_replace(cdata->template, target, 1); xfree(target); diff --git a/cmd-find-window.c b/cmd-find-window.c index 49e29337..482d9243 100644 --- a/cmd-find-window.c +++ b/cmd-find-window.c @@ -30,6 +30,7 @@ int cmd_find_window_exec(struct cmd *, struct cmd_ctx *); void cmd_find_window_callback(void *, int); +void cmd_find_window_free(void *); const struct cmd_entry cmd_find_window_entry = { "find-window", "findw", @@ -43,7 +44,7 @@ const struct cmd_entry cmd_find_window_entry = { }; struct cmd_find_window_data { - u_int session; + struct session *session; }; int @@ -134,11 +135,11 @@ cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx) } cdata = xmalloc(sizeof *cdata); - if (session_index(s, &cdata->session) != 0) - fatalx("session not found"); + cdata->session = s; + cdata->session->references++; - window_choose_ready( - wl->window->active, 0, cmd_find_window_callback, xfree, cdata); + window_choose_ready(wl->window->active, + 0, cmd_find_window_callback, cmd_find_window_free, cdata); out: ARRAY_FREE(&list_idx); @@ -151,12 +152,24 @@ void cmd_find_window_callback(void *data, int idx) { struct cmd_find_window_data *cdata = data; - struct session *s; + struct session *s = cdata->session; - if (idx != -1 && cdata->session <= ARRAY_LENGTH(&sessions) - 1) { - s = ARRAY_ITEM(&sessions, cdata->session); - if (s != NULL && session_select(s, idx) == 0) - server_redraw_session(s); + if (idx == -1) + return; + if (!session_alive(s)) + return; + + if (session_select(s, idx) == 0) { + server_redraw_session(s); recalculate_sizes(); } } + +void +cmd_find_window_free(void *data) +{ + struct cmd_find_window_data *cdata = data; + + cdata->session->references--; + xfree(cdata); +} diff --git a/cmd-load-buffer.c b/cmd-load-buffer.c index e28b9c74..abaa76ca 100644 --- a/cmd-load-buffer.c +++ b/cmd-load-buffer.c @@ -81,6 +81,7 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) cdata = xmalloc(sizeof *cdata); cdata->session = s; + cdata->session->references++; cdata->buffer = data->buffer; c->stdin_data = cdata; c->stdin_callback = cmd_load_buffer_callback; @@ -144,7 +145,6 @@ cmd_load_buffer_callback(struct client *c, void *data) char *pdata; size_t psize; u_int limit; - int idx; /* * Event callback has already checked client is not dead and reduced @@ -153,7 +153,7 @@ cmd_load_buffer_callback(struct client *c, void *data) c->flags |= CLIENT_EXIT; /* Does the target session still exist? */ - if (session_index(s, &idx) != 0) + if (!session_alive(s)) goto out; psize = EVBUFFER_LENGTH(c->stdin_event->input); @@ -180,5 +180,6 @@ cmd_load_buffer_callback(struct client *c, void *data) } out: + cdata->session->references--; xfree(cdata); } diff --git a/session.c b/session.c index 7d3fb32d..c4d553cb 100644 --- a/session.c +++ b/session.c @@ -35,6 +35,18 @@ struct session_groups session_groups; struct winlink *session_next_alert(struct winlink *); struct winlink *session_previous_alert(struct winlink *); +/* + * Find if session is still alive. This is true if it is still on the global + * sessions list. + */ +int +session_alive(struct session *s) +{ + u_int idx; + + return (session_index(s, &idx) == 0); +} + /* Find session by name. */ struct session * session_find(const char *name) diff --git a/tmux.h b/tmux.h index 11665195..0f36c92e 100644 --- a/tmux.h +++ b/tmux.h @@ -1968,6 +1968,7 @@ void clear_signals(int); extern struct sessions sessions; extern struct sessions dead_sessions; extern struct session_groups session_groups; +int session_alive(struct session *); struct session *session_find(const char *); struct session *session_create(const char *, const char *, const char *, struct environ *, struct termios *, int, u_int, u_int, From 9358cfaf4a566a060af81312ff73ee1e3e8c8ced Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 20 Dec 2010 00:17:22 +0000 Subject: [PATCH 0801/1180] Use pointer rather than index for the client's last session. --- cmd-new-session.c | 17 ++++++++--------- cmd-switch-client.c | 7 +++---- server-client.c | 2 +- server-fn.c | 2 +- tmux.h | 2 +- 5 files changed, 14 insertions(+), 16 deletions(-) diff --git a/cmd-new-session.c b/cmd-new-session.c index 573b0ebb..5511da5d 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -122,7 +122,7 @@ int cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) { struct cmd_new_session_data *data = self->data; - struct session *s, *groupwith; + struct session *s, *old_s, *groupwith; struct window *w; struct window_pane *wp; struct environ env; @@ -279,17 +279,16 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) if (!detached) { if (ctx->cmdclient != NULL) { server_write_client(ctx->cmdclient, MSG_READY, NULL, 0); - if (ctx->cmdclient->session != NULL) { - session_index(ctx->cmdclient->session, - &ctx->cmdclient->last_session); - } + + old_s = ctx->cmdclient->session; + if (old_s != NULL) + ctx->cmdclient->last_session = old_s; ctx->cmdclient->session = s; server_redraw_client(ctx->cmdclient); } else { - if (ctx->curclient->session != NULL) { - session_index(ctx->curclient->session, - &ctx->curclient->last_session); - } + old_s = ctx->curclient->session; + if (old_s != NULL) + ctx->curclient->last_session = old_s; ctx->curclient->session = s; server_redraw_client(ctx->curclient); } diff --git a/cmd-switch-client.c b/cmd-switch-client.c index dfe8aca1..1be8a6c7 100644 --- a/cmd-switch-client.c +++ b/cmd-switch-client.c @@ -159,9 +159,8 @@ cmd_switch_client_exec(struct cmd *self, struct cmd_ctx *ctx) return (-1); } } else if (data->flag_last) { - if (c->last_session != UINT_MAX && - c->last_session < ARRAY_LENGTH(&sessions)) - s = ARRAY_ITEM(&sessions, c->last_session); + if (c->last_session != NULL && session_alive(c->last_session)) + s = c->last_session; if (s == NULL) { ctx->error(ctx, "can't find last session"); return (-1); @@ -172,7 +171,7 @@ cmd_switch_client_exec(struct cmd *self, struct cmd_ctx *ctx) return (-1); if (c->session != NULL) - session_index(c->session, &c->last_session); + c->last_session = c->session; c->session = s; recalculate_sizes(); diff --git a/server-client.c b/server-client.c index 290a175a..c4cc9847 100644 --- a/server-client.c +++ b/server-client.c @@ -78,7 +78,7 @@ server_client_create(int fd) c->title = NULL; c->session = NULL; - c->last_session = UINT_MAX; + c->last_session = NULL; c->tty.sx = 80; c->tty.sy = 24; diff --git a/server-fn.c b/server-fn.c index 20a245e0..134cfb6e 100644 --- a/server-fn.c +++ b/server-fn.c @@ -399,7 +399,7 @@ server_destroy_session(struct session *s) c->session = NULL; c->flags |= CLIENT_EXIT; } else { - c->last_session = UINT_MAX; + c->last_session = NULL; c->session = s_new; server_redraw_client(c); } diff --git a/tmux.h b/tmux.h index 0f36c92e..8b384af1 100644 --- a/tmux.h +++ b/tmux.h @@ -1155,7 +1155,7 @@ struct client { struct mode_key_data prompt_mdata; struct session *session; - u_int last_session; + struct session *last_session; int references; }; From 8705c6b4352bc2ffa3f06cd7eed0df65d6e3a5ba Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 20 Dec 2010 00:19:20 +0000 Subject: [PATCH 0802/1180] Dead sessions are never on the active sessions list, so the SESSION_DEAD flag is effectively unused. Remove it. --- session.c | 9 ++++----- tmux.h | 1 - 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/session.c b/session.c index c4d553cb..ba114e4b 100644 --- a/session.c +++ b/session.c @@ -167,7 +167,6 @@ session_destroy(struct session *s) } if (i == ARRAY_LENGTH(&dead_sessions)) ARRAY_ADD(&dead_sessions, s); - s->flags |= SESSION_DEAD; } /* Find session index. */ @@ -188,7 +187,7 @@ session_next_session(struct session *s) struct session *s2; u_int i; - if (ARRAY_LENGTH(&sessions) == 0 || session_index(s, &i) != 0) + if (ARRAY_LENGTH(&sessions) == 0 || !session_alive(s)) return (NULL); do { @@ -197,7 +196,7 @@ session_next_session(struct session *s) else i++; s2 = ARRAY_ITEM(&sessions, i); - } while (s2 == NULL || s2->flags & SESSION_DEAD); + } while (s2 == NULL); return (s2); } @@ -209,7 +208,7 @@ session_previous_session(struct session *s) struct session *s2; u_int i; - if (ARRAY_LENGTH(&sessions) == 0 || session_index(s, &i) != 0) + if (ARRAY_LENGTH(&sessions) == 0 || !session_alive(s)) return (NULL); do { @@ -218,7 +217,7 @@ session_previous_session(struct session *s) else i--; s2 = ARRAY_ITEM(&sessions, i); - } while (s2 == NULL || s2->flags & SESSION_DEAD); + } while (s2 == NULL); return (s2); } diff --git a/tmux.h b/tmux.h index 8b384af1..f5384773 100644 --- a/tmux.h +++ b/tmux.h @@ -948,7 +948,6 @@ struct session { struct paste_stack buffers; #define SESSION_UNATTACHED 0x1 /* not attached to any clients */ -#define SESSION_DEAD 0x2 int flags; struct termios *tio; From 6fcdc714b64bdc5fe065d90148aa13d4963b565d Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 20 Dec 2010 00:43:24 +0000 Subject: [PATCH 0803/1180] Undo a change to next/previous session that got mixed in prematurely. --- session.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/session.c b/session.c index ba114e4b..6242a156 100644 --- a/session.c +++ b/session.c @@ -187,9 +187,10 @@ session_next_session(struct session *s) struct session *s2; u_int i; - if (ARRAY_LENGTH(&sessions) == 0 || !session_alive(s)) + if (ARRAY_LENGTH(&sessions) == 0 || session_index(s, &i) != 0) return (NULL); + i = 0; do { if (i == ARRAY_LENGTH(&sessions) - 1) i = 0; @@ -208,7 +209,7 @@ session_previous_session(struct session *s) struct session *s2; u_int i; - if (ARRAY_LENGTH(&sessions) == 0 || !session_alive(s)) + if (ARRAY_LENGTH(&sessions) == 0 || session_index(s, &i) != 0) return (NULL); do { From 1b8488ee75458c4561089bf056c0e911de958428 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 20 Dec 2010 01:28:18 +0000 Subject: [PATCH 0804/1180] Fix another stray addition that was too early. Oops. --- session.c | 1 - 1 file changed, 1 deletion(-) diff --git a/session.c b/session.c index 6242a156..cdfddb6a 100644 --- a/session.c +++ b/session.c @@ -190,7 +190,6 @@ session_next_session(struct session *s) if (ARRAY_LENGTH(&sessions) == 0 || session_index(s, &i) != 0) return (NULL); - i = 0; do { if (i == ARRAY_LENGTH(&sessions) - 1) i = 0; From acf13ce9784111ca1e42ffc8206e752668476859 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 21 Dec 2010 22:37:59 +0000 Subject: [PATCH 0805/1180] Store sessions in an RB tree by name rather than a list, this is tidier and allows them to easily be shown sorted in various lists (list-sessions/choose-sessions). Keep a session index which is used in a couple of places internally but make it an ever-increasing number rather than filling in gaps with new sessions. --- cmd-attach-session.c | 2 +- cmd-choose-session.c | 13 ++--- cmd-list-sessions.c | 8 +-- cmd-rename-session.c | 2 + cmd-server-info.c | 13 ++--- cmd.c | 57 +++++++++++++--------- resize.c | 11 ++--- server-fn.c | 31 ++++-------- server-window.c | 7 +-- server.c | 59 ++++++++++------------ session.c | 113 +++++++++++++++++++------------------------ tmux.h | 10 +++- 12 files changed, 143 insertions(+), 183 deletions(-) diff --git a/cmd-attach-session.c b/cmd-attach-session.c index dbc43141..13fabc8d 100644 --- a/cmd-attach-session.c +++ b/cmd-attach-session.c @@ -47,7 +47,7 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx) char *overrides, *cause; u_int i; - if (ARRAY_LENGTH(&sessions) == 0) { + if (RB_EMPTY(&sessions)) { ctx->error(ctx, "no sessions"); return (-1); } diff --git a/cmd-choose-session.c b/cmd-choose-session.c index 7cd56f5d..cf36fe98 100644 --- a/cmd-choose-session.c +++ b/cmd-choose-session.c @@ -55,7 +55,7 @@ cmd_choose_session_exec(struct cmd *self, struct cmd_ctx *ctx) struct winlink *wl; struct session *s; struct session_group *sg; - u_int i, idx, sgidx, cur; + u_int idx, sgidx, cur; char tmp[64]; if (ctx->curclient == NULL) { @@ -70,10 +70,7 @@ cmd_choose_session_exec(struct cmd *self, struct cmd_ctx *ctx) return (0); cur = idx = 0; - for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { - s = ARRAY_ITEM(&sessions, i); - if (s == NULL) - continue; + RB_FOREACH(s, sessions, &sessions) { if (s == ctx->curclient->session) cur = idx; idx++; @@ -86,7 +83,7 @@ cmd_choose_session_exec(struct cmd *self, struct cmd_ctx *ctx) xsnprintf(tmp, sizeof tmp, " (group %u)", sgidx); } - window_choose_add(wl->window->active, i, + window_choose_add(wl->window->active, s->idx, "%s: %u windows [%ux%u]%s%s", s->name, winlink_count(&s->windows), s->sx, s->sy, tmp, s->flags & SESSION_UNATTACHED ? "" : " (attached)"); @@ -120,9 +117,7 @@ cmd_choose_session_callback(void *data, int idx) if (cdata->client->flags & CLIENT_DEAD) return; - if ((u_int) idx > ARRAY_LENGTH(&sessions) - 1) - return; - s = ARRAY_ITEM(&sessions, idx); + s = session_find_by_index(idx); if (s == NULL) return; template = cmd_template_replace(cdata->template, s->name, 1); diff --git a/cmd-list-sessions.c b/cmd-list-sessions.c index 774c599b..e7aa22d7 100644 --- a/cmd-list-sessions.c +++ b/cmd-list-sessions.c @@ -46,14 +46,10 @@ cmd_list_sessions_exec(unused struct cmd *self, struct cmd_ctx *ctx) struct session *s; struct session_group *sg; char *tim, tmp[64]; - u_int i, idx; + u_int idx; time_t t; - for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { - s = ARRAY_ITEM(&sessions, i); - if (s == NULL) - continue; - + RB_FOREACH(s, sessions, &sessions) { sg = session_group_find(s); if (sg == NULL) *tmp = '\0'; diff --git a/cmd-rename-session.c b/cmd-rename-session.c index 0b674ce0..bd9e787f 100644 --- a/cmd-rename-session.c +++ b/cmd-rename-session.c @@ -53,8 +53,10 @@ cmd_rename_session_exec(struct cmd *self, struct cmd_ctx *ctx) if ((s = cmd_find_session(ctx, data->target)) == NULL) return (-1); + RB_REMOVE(sessions, &sessions, s); xfree(s->name); s->name = xstrdup(data->arg); + RB_INSERT(sessions, &sessions, s); server_status_session(s); diff --git a/cmd-server-info.c b/cmd-server-info.c index 60acbdf8..a114bf05 100644 --- a/cmd-server-info.c +++ b/cmd-server-info.c @@ -81,8 +81,6 @@ cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx) else ctx->print(ctx, "configuration file not specified"); ctx->print(ctx, "protocol version is %d", PROTOCOL_VERSION); - ctx->print(ctx, "%u clients, %u sessions", - ARRAY_LENGTH(&clients), ARRAY_LENGTH(&sessions)); ctx->print(ctx, "%s", ""); ctx->print(ctx, "Clients:"); @@ -101,19 +99,14 @@ cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx) ctx->print(ctx, "Sessions: [%zu/%zu]", sizeof (struct grid_cell), sizeof (struct grid_utf8)); - for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { - s = ARRAY_ITEM(&sessions, i); - if (s == NULL) - continue; - + RB_FOREACH(s, sessions, &sessions) { t = s->creation_time.tv_sec; tim = ctime(&t); *strchr(tim, '\n') = '\0'; ctx->print(ctx, "%2u: %s: %u windows (created %s) [%ux%u] " - "[flags=0x%x, references=%u]", i, s->name, - winlink_count(&s->windows), tim, s->sx, s->sy, s->flags, - s->references); + "[flags=0x%x]", s->idx, s->name, + winlink_count(&s->windows), tim, s->sx, s->sy, s->flags); RB_FOREACH(wl, winlinks, &s->windows) { w = wl->window; ctx->print(ctx, "%4u: %s [%ux%u] [flags=0x%x, " diff --git a/cmd.c b/cmd.c index af038b7b..c4aa582c 100644 --- a/cmd.c +++ b/cmd.c @@ -112,7 +112,8 @@ const struct cmd_entry *cmd_table[] = { NULL }; -struct session *cmd_choose_session(struct sessions *); +struct session *cmd_choose_session_list(struct sessionslist *); +struct session *cmd_choose_session(void); struct client *cmd_choose_client(struct clients *); struct client *cmd_lookup_client(const char *); struct session *cmd_lookup_session(const char *, int *); @@ -316,10 +317,9 @@ cmd_current_session(struct cmd_ctx *ctx) struct msg_command_data *data = ctx->msgdata; struct client *c = ctx->cmdclient; struct session *s; - struct sessions ss; + struct sessionslist ss; struct winlink *wl; struct window_pane *wp; - u_int i; int found; if (ctx->curclient != NULL && ctx->curclient->session != NULL) @@ -332,9 +332,7 @@ cmd_current_session(struct cmd_ctx *ctx) */ if (c != NULL && c->tty.path != NULL) { ARRAY_INIT(&ss); - for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { - if ((s = ARRAY_ITEM(&sessions, i)) == NULL) - continue; + RB_FOREACH(s, sessions, &sessions) { found = 0; RB_FOREACH(wl, winlinks, &s->windows) { TAILQ_FOREACH(wp, &wl->window->panes, entry) { @@ -350,25 +348,43 @@ cmd_current_session(struct cmd_ctx *ctx) ARRAY_ADD(&ss, s); } - s = cmd_choose_session(&ss); + s = cmd_choose_session_list(&ss); ARRAY_FREE(&ss); if (s != NULL) return (s); } /* Use the session from the TMUX environment variable. */ - if (data != NULL && - data->pid == getpid() && - data->idx <= ARRAY_LENGTH(&sessions) && - (s = ARRAY_ITEM(&sessions, data->idx)) != NULL) - return (s); + if (data != NULL && data->pid == getpid()) { + s = session_find_by_index(data->idx); + if (s != NULL) + return (s); + } - return (cmd_choose_session(&sessions)); + return (cmd_choose_session()); +} + +/* Find the most recently used session. */ +struct session * +cmd_choose_session(void) +{ + struct session *s, *sbest; + struct timeval *tv = NULL; + + sbest = NULL; + RB_FOREACH(s, sessions, &sessions) { + if (tv == NULL || timercmp(&s->activity_time, tv, >)) { + sbest = s; + tv = &s->activity_time; + } + } + + return (sbest); } /* Find the most recently used session from a list. */ struct session * -cmd_choose_session(struct sessions *ss) +cmd_choose_session_list(struct sessionslist *ss) { struct session *s, *sbest; struct timeval *tv = NULL; @@ -516,7 +532,6 @@ struct session * cmd_lookup_session(const char *name, int *ambiguous) { struct session *s, *sfound; - u_int i; *ambiguous = 0; @@ -525,21 +540,15 @@ cmd_lookup_session(const char *name, int *ambiguous) * be unique so an exact match can't be ambigious and can just be * returned. */ - for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { - if ((s = ARRAY_ITEM(&sessions, i)) == NULL) - continue; - if (strcmp(name, s->name) == 0) - return (s); - } + if ((s = session_find(name)) != NULL) + return (s); /* * Otherwise look for partial matches, returning early if it is found to * be ambiguous. */ sfound = NULL; - for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { - if ((s = ARRAY_ITEM(&sessions, i)) == NULL) - continue; + RB_FOREACH(s, sessions, &sessions) { if (strncmp(name, s->name, strlen(name)) == 0 || fnmatch(name, s->name, 0) == 0) { if (sfound != NULL) { diff --git a/resize.c b/resize.c index af84eaba..517a7481 100644 --- a/resize.c +++ b/resize.c @@ -52,11 +52,7 @@ recalculate_sizes(void) u_int i, j, ssx, ssy, has, limit; int flag; - for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { - s = ARRAY_ITEM(&sessions, i); - if (s == NULL) - continue; - + RB_FOREACH(s, sessions, &sessions) { ssx = ssy = UINT_MAX; for (j = 0; j < ARRAY_LENGTH(&clients); j++) { c = ARRAY_ITEM(&clients, j); @@ -98,9 +94,8 @@ recalculate_sizes(void) flag = options_get_number(&w->options, "aggressive-resize"); ssx = ssy = UINT_MAX; - for (j = 0; j < ARRAY_LENGTH(&sessions); j++) { - s = ARRAY_ITEM(&sessions, j); - if (s == NULL || s->flags & SESSION_UNATTACHED) + RB_FOREACH(s, sessions, &sessions) { + if (s->flags & SESSION_UNATTACHED) continue; if (flag) has = s->curw->window == w; diff --git a/server-fn.c b/server-fn.c index 134cfb6e..ada92b9a 100644 --- a/server-fn.c +++ b/server-fn.c @@ -30,13 +30,10 @@ void server_callback_identify(int, short, void *); void server_fill_environ(struct session *s, struct environ *env) { - char tmuxvar[MAXPATHLEN], *term; - u_int idx; + char tmuxvar[MAXPATHLEN], *term; - if (session_index(s, &idx) != 0) - fatalx("session not found"); xsnprintf(tmuxvar, sizeof tmuxvar, - "%s,%ld,%u", socket_path, (long) getpid(), idx); + "%s,%ld,%u", socket_path, (long) getpid(), s->idx); environ_set(env, "TMUX", tmuxvar); term = options_get_string(&s->options, "default-terminal"); @@ -175,7 +172,6 @@ void server_status_window(struct window *w) { struct session *s; - u_int i; /* * This is slightly different. We want to redraw the status line of any @@ -183,9 +179,8 @@ server_status_window(struct window *w) * current window. */ - for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { - s = ARRAY_ITEM(&sessions, i); - if (s != NULL && session_has(s, w) != NULL) + RB_FOREACH(s, sessions, &sessions) { + if (session_has(s, w) != NULL) server_status_session(s); } } @@ -246,11 +241,9 @@ server_kill_window(struct window *w) { struct session *s; struct winlink *wl; - u_int i; - for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { - s = ARRAY_ITEM(&sessions, i); - if (s == NULL || session_has(s, w) == NULL) + RB_FOREACH(s, sessions, &sessions) { + if (session_has(s, w) == NULL) continue; while ((wl = winlink_find_by_window(&s->windows, w)) != NULL) { if (session_detach(s, wl)) { @@ -365,12 +358,10 @@ struct session * server_next_session(struct session *s) { struct session *s_loop, *s_out; - u_int i; s_out = NULL; - for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { - s_loop = ARRAY_ITEM(&sessions, i); - if (s_loop == NULL || s_loop == s) + RB_FOREACH(s_loop, sessions, &sessions) { + if (s_loop == s) continue; if (s_out == NULL || timercmp(&s_loop->activity_time, &s_out->activity_time, <)) @@ -411,15 +402,13 @@ void server_check_unattached (void) { struct session *s; - u_int i; /* * If any sessions are no longer attached and have destroy-unattached * set, collect them. */ - for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { - s = ARRAY_ITEM(&sessions, i); - if (s == NULL || !(s->flags & SESSION_UNATTACHED)) + RB_FOREACH(s, sessions, &sessions) { + if (!(s->flags & SESSION_UNATTACHED)) continue; if (options_get_number (&s->options, "destroy-unattached")) session_destroy(s); diff --git a/server-window.c b/server-window.c index abf82499..d415e0d7 100644 --- a/server-window.c +++ b/server-window.c @@ -38,17 +38,14 @@ server_window_loop(void) struct winlink *wl; struct window_pane *wp; struct session *s; - u_int i, j; + u_int i; for (i = 0; i < ARRAY_LENGTH(&windows); i++) { w = ARRAY_ITEM(&windows, i); if (w == NULL) continue; - for (j = 0; j < ARRAY_LENGTH(&sessions); j++) { - s = ARRAY_ITEM(&sessions, j); - if (s == NULL) - continue; + RB_FOREACH(s, sessions, &sessions) { wl = session_has(s, w); if (wl == NULL) continue; diff --git a/server.c b/server.c index 7a4e5fcf..40667a04 100644 --- a/server.c +++ b/server.c @@ -147,8 +147,8 @@ server_start(void) ARRAY_INIT(&windows); ARRAY_INIT(&clients); ARRAY_INIT(&dead_clients); - ARRAY_INIT(&sessions); - ARRAY_INIT(&dead_sessions); + RB_INIT(&sessions); + RB_INIT(&dead_sessions); TAILQ_INIT(&session_groups); mode_key_init_trees(); key_bindings_init(); @@ -174,8 +174,8 @@ server_start(void) * If there is a session already, put the current window and pane into * more mode. */ - if (!ARRAY_EMPTY(&sessions) && !ARRAY_EMPTY(&cfg_causes)) { - wp = ARRAY_FIRST(&sessions)->curw->window->active; + if (!RB_EMPTY(&sessions) && !ARRAY_EMPTY(&cfg_causes)) { + wp = RB_MIN(sessions, &sessions)->curw->window->active; window_pane_set_mode(wp, &window_copy_mode); window_copy_init_for_output(wp); for (i = 0; i < ARRAY_LENGTH(&cfg_causes); i++) { @@ -223,10 +223,8 @@ server_should_shutdown(void) u_int i; if (!options_get_number(&global_options, "exit-unattached")) { - for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { - if (ARRAY_ITEM(&sessions, i) != NULL) - return (0); - } + if (!RB_EMPTY(&sessions)) + return (0); } for (i = 0; i < ARRAY_LENGTH(&clients); i++) { if (ARRAY_ITEM(&clients, i) != NULL) @@ -240,7 +238,7 @@ void server_send_shutdown(void) { struct client *c; - struct session *s; + struct session *s, *next_s; u_int i; for (i = 0; i < ARRAY_LENGTH(&clients); i++) { @@ -254,9 +252,11 @@ server_send_shutdown(void) } } - for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { - if ((s = ARRAY_ITEM(&sessions, i)) != NULL) - session_destroy(s); + s = RB_MIN(sessions, &sessions); + while (s != NULL) { + next_s = RB_NEXT(sessions, &sessions, s); + session_destroy(s); + s = next_s; } } @@ -264,16 +264,19 @@ server_send_shutdown(void) void server_clean_dead(void) { - struct session *s; + struct session *s, *next_s; struct client *c; u_int i; - for (i = 0; i < ARRAY_LENGTH(&dead_sessions); i++) { - s = ARRAY_ITEM(&dead_sessions, i); - if (s == NULL || s->references != 0) - continue; - ARRAY_SET(&dead_sessions, i, NULL); - xfree(s); + s = RB_MIN(sessions, &dead_sessions); + while (s != NULL) { + next_s = RB_NEXT(sessions, &dead_sessions, s); + if (s->references == 0) { + RB_REMOVE(sessions, &dead_sessions, s); + xfree(s->name); + xfree(s); + } + s = next_s; } for (i = 0; i < ARRAY_LENGTH(&dead_clients); i++) { @@ -290,15 +293,13 @@ void server_update_socket(void) { struct session *s; - u_int i; static int last = -1; int n, mode; struct stat sb; n = 0; - for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { - s = ARRAY_ITEM(&sessions, i); - if (s != NULL && !(s->flags & SESSION_UNATTACHED)) { + RB_FOREACH(s, sessions, &sessions) { + if (!(s->flags & SESSION_UNATTACHED)) { n++; break; } @@ -485,15 +486,11 @@ void server_lock_server(void) { struct session *s; - u_int i; int timeout; time_t t; t = time(NULL); - for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { - if ((s = ARRAY_ITEM(&sessions, i)) == NULL) - continue; - + RB_FOREACH(s, sessions, &sessions) { if (s->flags & SESSION_UNATTACHED) { if (gettimeofday(&s->activity_time, NULL) != 0) fatal("gettimeofday failed"); @@ -514,15 +511,11 @@ void server_lock_sessions(void) { struct session *s; - u_int i; int timeout; time_t t; t = time(NULL); - for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { - if ((s = ARRAY_ITEM(&sessions, i)) == NULL) - continue; - + RB_FOREACH(s, sessions, &sessions) { if (s->flags & SESSION_UNATTACHED) { if (gettimeofday(&s->activity_time, NULL) != 0) fatal("gettimeofday failed"); diff --git a/session.c b/session.c index cdfddb6a..6832e088 100644 --- a/session.c +++ b/session.c @@ -30,11 +30,20 @@ /* Global session list. */ struct sessions sessions; struct sessions dead_sessions; +u_int next_session; struct session_groups session_groups; struct winlink *session_next_alert(struct winlink *); struct winlink *session_previous_alert(struct winlink *); +RB_GENERATE(sessions, session, entry, session_cmp); + +int +session_cmp(struct session *s1, struct session *s2) +{ + return (strcmp(s1->name, s2->name)); +} + /* * Find if session is still alive. This is true if it is still on the global * sessions list. @@ -42,24 +51,35 @@ struct winlink *session_previous_alert(struct winlink *); int session_alive(struct session *s) { - u_int idx; + struct session *s_loop; - return (session_index(s, &idx) == 0); + RB_FOREACH(s_loop, sessions, &sessions) { + if (s_loop == s) + return (1); + } + return (0); } /* Find session by name. */ struct session * session_find(const char *name) { - struct session *s; - u_int i; + struct session s; - for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { - s = ARRAY_ITEM(&sessions, i); - if (s != NULL && strcmp(s->name, name) == 0) + s.name = (char *) name; + return (RB_FIND(sessions, &sessions, &s)); +} + +/* Find session by index. */ +struct session * +session_find_by_index(u_int idx) +{ + struct session *s; + + RB_FOREACH(s, sessions, &sessions) { + if (s->idx == idx) return (s); } - return (NULL); } @@ -70,7 +90,6 @@ session_create(const char *name, const char *cmd, const char *cwd, char **cause) { struct session *s; - u_int i; s = xmalloc(sizeof *s); s->references = 0; @@ -102,19 +121,12 @@ session_create(const char *name, const char *cmd, const char *cwd, s->sx = sx; s->sy = sy; - for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { - if (ARRAY_ITEM(&sessions, i) == NULL) { - ARRAY_SET(&sessions, i, s); - break; - } - } - if (i == ARRAY_LENGTH(&sessions)) - ARRAY_ADD(&sessions, s); - + s->idx = next_session++; if (name != NULL) s->name = xstrdup(name); else - xasprintf(&s->name, "%u", i); + xasprintf(&s->name, "%u", s->idx); + RB_INSERT(sessions, &sessions, s); if (cmd != NULL) { if (session_new(s, NULL, cmd, cwd, idx, cause) == NULL) { @@ -133,15 +145,9 @@ session_create(const char *name, const char *cmd, const char *cwd, void session_destroy(struct session *s) { - u_int i; - log_debug("session %s destroyed", s->name); - if (session_index(s, &i) != 0) - fatalx("session not found"); - ARRAY_SET(&sessions, i, NULL); - while (!ARRAY_EMPTY(&sessions) && ARRAY_LAST(&sessions) == NULL) - ARRAY_TRUNC(&sessions, 1); + RB_REMOVE(sessions, &sessions, s); if (s->tio != NULL) xfree(s->tio); @@ -157,27 +163,8 @@ session_destroy(struct session *s) winlink_remove(&s->windows, RB_ROOT(&s->windows)); xfree(s->cwd); - xfree(s->name); - for (i = 0; i < ARRAY_LENGTH(&dead_sessions); i++) { - if (ARRAY_ITEM(&dead_sessions, i) == NULL) { - ARRAY_SET(&dead_sessions, i, s); - break; - } - } - if (i == ARRAY_LENGTH(&dead_sessions)) - ARRAY_ADD(&dead_sessions, s); -} - -/* Find session index. */ -int -session_index(struct session *s, u_int *i) -{ - for (*i = 0; *i < ARRAY_LENGTH(&sessions); (*i)++) { - if (s == ARRAY_ITEM(&sessions, *i)) - return (0); - } - return (-1); + RB_INSERT(sessions, &dead_sessions, s); } /* Find the next usable session. */ @@ -185,19 +172,18 @@ struct session * session_next_session(struct session *s) { struct session *s2; - u_int i; - if (ARRAY_LENGTH(&sessions) == 0 || session_index(s, &i) != 0) + if (RB_EMPTY(&sessions) || !session_alive(s)) return (NULL); + s2 = s; do { - if (i == ARRAY_LENGTH(&sessions) - 1) - i = 0; - else - i++; - s2 = ARRAY_ITEM(&sessions, i); - } while (s2 == NULL); - + s2 = RB_NEXT(sessions, &sessions, s2); + if (s2 == NULL) + s2 = RB_MIN(sessions, &sessions); + } while (s2 != s); + if (s2 == s) + return (NULL); return (s2); } @@ -206,19 +192,18 @@ struct session * session_previous_session(struct session *s) { struct session *s2; - u_int i; - if (ARRAY_LENGTH(&sessions) == 0 || session_index(s, &i) != 0) + if (RB_EMPTY(&sessions) || !session_alive(s)) return (NULL); + s2 = s; do { - if (i == 0) - i = ARRAY_LENGTH(&sessions) - 1; - else - i--; - s2 = ARRAY_ITEM(&sessions, i); - } while (s2 == NULL); - + s2 = RB_PREV(sessions, &sessions, s2); + if (s2 == NULL) + s2 = RB_MAX(sessions, &sessions); + } while (s2 != s); + if (s2 == s) + return (NULL); return (s2); } diff --git a/tmux.h b/tmux.h index f5384773..075e581c 100644 --- a/tmux.h +++ b/tmux.h @@ -930,6 +930,8 @@ struct session_group { TAILQ_HEAD(session_groups, session_group); struct session { + u_int idx; + char *name; char *cwd; @@ -957,8 +959,10 @@ struct session { int references; TAILQ_ENTRY(session) gentry; + RB_ENTRY(session) entry; }; -ARRAY_DECL(sessions, struct session *); +RB_HEAD(sessions, session); +ARRAY_DECL(sessionslist, struct session *); /* TTY information. */ struct tty_key { @@ -1967,13 +1971,15 @@ void clear_signals(int); extern struct sessions sessions; extern struct sessions dead_sessions; extern struct session_groups session_groups; +int session_cmp(struct session *, struct session *); +RB_PROTOTYPE(sessions, session, entry, session_cmp); int session_alive(struct session *); struct session *session_find(const char *); +struct session *session_find_by_index(u_int); struct session *session_create(const char *, const char *, const char *, struct environ *, struct termios *, int, u_int, u_int, char **); void session_destroy(struct session *); -int session_index(struct session *, u_int *); struct session *session_next_session(struct session *); struct session *session_previous_session(struct session *); struct winlink *session_new(struct session *, From 6fd2b5b87fd5cfe839223253c8f85af49599b886 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 23 Dec 2010 20:18:39 +0000 Subject: [PATCH 0806/1180] Style tweaks. --- input.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/input.c b/input.c index 4a964550..cbcdd83c 100644 --- a/input.c +++ b/input.c @@ -720,11 +720,11 @@ input_parse(struct window_pane *wp) * Execute the handler, if any. Don't switch state if it * returns non-zero. */ - if (itr->handler && itr->handler(ictx) != 0) + if (itr->handler != NULL && itr->handler(ictx) != 0) continue; /* And switch state, if necessary. */ - if (itr->state) { + if (itr->state != NULL) { if (ictx->state->exit != NULL) ictx->state->exit(ictx); ictx->state = itr->state; @@ -924,9 +924,9 @@ input_c0_dispatch(struct input_ctx *ictx) int input_esc_dispatch(struct input_ctx *ictx) { - struct screen_write_ctx *sctx = &ictx->ctx; - struct screen *s = sctx->s; - struct input_table_entry *entry; + struct screen_write_ctx *sctx = &ictx->ctx; + struct screen *s = sctx->s; + struct input_table_entry *entry; if (ictx->flags & INPUT_DISCARD) return (0); From d3d25365f17b2e7c4244a345a39e8c48f067858a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 23 Dec 2010 21:56:38 +0000 Subject: [PATCH 0807/1180] server_kill_window can modify the RB tree so don't use RB_FOREACH, fixes crash seen by Dan Harnett. --- server-fn.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/server-fn.c b/server-fn.c index ada92b9a..03fa01d2 100644 --- a/server-fn.c +++ b/server-fn.c @@ -239,10 +239,14 @@ server_lock_client(struct client *c) void server_kill_window(struct window *w) { - struct session *s; + struct session *s, *next_s; struct winlink *wl; - RB_FOREACH(s, sessions, &sessions) { + next_s = RB_MIN(sessions, &sessions); + while (next_s != NULL) { + s = next_s; + next_s = RB_NEXT(sessions, &sessions, s); + if (session_has(s, w) == NULL) continue; while ((wl = winlink_find_by_window(&s->windows, w)) != NULL) { From 3e0bc052e1c66d0f388658b425e296b08da92511 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 27 Dec 2010 18:22:25 +0000 Subject: [PATCH 0808/1180] Add a missing .Pp and sort options alphabetically, from Tiago Cunha. --- tmux.1 | 56 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/tmux.1 b/tmux.1 index d958bbb1..8ab874e1 100644 --- a/tmux.1 +++ b/tmux.1 @@ -902,6 +902,7 @@ $ tmux list-windows layout: bb62,159x48,0,0{79x48,0,0,79x48,80,0} $ tmux select-layout bb62,159x48,0,0{79x48,0,0,79x48,80,0} .Ed +.Pp .Nm automatically adjusts the size of the layout for the current window size. Note that a layout cannot be applied to a window with more panes than that @@ -1641,6 +1642,11 @@ The default is an empty string, which instructs to create a login shell using the value of the .Ic default-shell option. +.It Ic default-path Ar path +Set the default working directory for processes created from keys, or +interactively from the prompt. +The default is empty, which means to use the working directory of the shell +from which the server was started if it is available or the user's home if not. .It Ic default-shell Ar path Specify the default shell. This is used as the login shell for new windows when the @@ -1657,11 +1663,6 @@ or This option should be configured when .Nm is used as a login shell. -.It Ic default-path Ar path -Set the default working directory for processes created from keys, or -interactively from the prompt. -The default is empty, which means to use the working directory of the shell -from which the server was started if it is available or the user's home if not. .It Ic default-terminal Ar terminal Set the default terminal for new windows created in this session - the default value of the @@ -1778,12 +1779,12 @@ If on, captures the mouse and when a window is split into multiple panes the mouse may be used to select the current pane. The mouse click is also passed through to the application as normal. -.It Ic pane-border-fg Ar colour -.It Ic pane-border-bg Ar colour -Set the pane border colour for panes aside from the active pane. -.It Ic pane-active-border-fg Ar colour .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 prefix Ar keys Set the keys accepted as a prefix key. .Ar keys @@ -1938,10 +1939,10 @@ is not interpreted, to enable UTF-8, use the option. .It Ic status-left-attr Ar attributes Set the attribute 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-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 @@ -1963,16 +1964,15 @@ character pairs are replaced, and UTF-8 is dependent on the option. .It Ic status-right-attr Ar attributes Set the attribute 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-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. -.Pp .It Xo Ic status-utf8 .Op Ic on | off .Xc @@ -2096,6 +2096,19 @@ this option is good for full-screen programs which support .Dv SIGWINCH and poor for interactive programs such as shells. .Pp +.It Xo Ic alternate-screen +.Op Ic on | off +.Xc +This option configures whether programs running inside +.Nm +may use the terminal alternate screen feature, which allows the +.Em smcup +and +.Em rmcup +.Xr terminfo 5 +capabilities to be issued to preserve the existing window content on start and +restore it on exit. +.Pp .It Xo Ic automatic-rename .Op Ic on | off .Xc @@ -2134,8 +2147,8 @@ or .Ar height . A value of zero restores the default unlimited setting. .Pp -.It Ic main-pane-width Ar width .It Ic main-pane-height Ar height +.It Ic main-pane-width Ar width Set the width or height of the main (left or top) pane in the .Ic main-horizontal or @@ -2229,19 +2242,6 @@ command. Duplicate input to any pane to all other panes in the same window (only for panes that are not in any special mode). .Pp -.It Xo Ic alternate-screen -.Op Ic on | off -.Xc -This option configures whether programs running inside -.Nm -may use the terminal alternate screen feature, which allows the -.Em smcup -and -.Em rmcup -.Xr terminfo 5 -capabilities to be issued to preserve the existing window content on start and -restore it on exit. -.Pp .It Xo Ic utf8 .Op Ic on | off .Xc From efa8c93664f6cf7a7b70a5f4b915d8fb135a0744 Mon Sep 17 00:00:00 2001 From: Jason McIntyre Date: Mon, 27 Dec 2010 19:57:31 +0000 Subject: [PATCH 0809/1180] tweak previous; --- tmux.1 | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tmux.1 b/tmux.1 index 8ab874e1..11d950ae 100644 --- a/tmux.1 +++ b/tmux.1 @@ -674,7 +674,7 @@ Switch the current session for client to .Ar target-session . If -.Fl l, +.Fl l , .Fl n or .Fl p @@ -2643,7 +2643,6 @@ Set the contents of the specified buffer to Display the contents of the specified buffer. .El .Sh MISCELLANEOUS -.Pp Miscellaneous commands are as follows: .Bl -tag -width Ds .It Ic clock-mode Op Fl t Ar target-pane From 230e39ec3558142c94858efae53c36ab0efbcf59 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 29 Dec 2010 21:28:32 +0000 Subject: [PATCH 0810/1180] Allow the config file parser and source-file to return "don't exit" to the client to let attach work from configuration files. --- cfg.c | 10 +++++----- cmd-source-file.c | 22 +++++++++++++++++++--- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/cfg.c b/cfg.c index 406cf219..75e0414f 100644 --- a/cfg.c +++ b/cfg.c @@ -80,6 +80,7 @@ load_cfg(const char *path, struct cmd_ctx *ctxin, struct causelist *causes) size_t len; struct cmd_list *cmdlist; struct cmd_ctx ctx; + int retval; if ((f = fopen(path, "rb")) == NULL) { cfg_add_cause(causes, "%s: %s", path, strerror(errno)); @@ -88,6 +89,7 @@ load_cfg(const char *path, struct cmd_ctx *ctxin, struct causelist *causes) n = 0; line = NULL; + retval = 0; while ((buf = fgetln(f, &len))) { if (buf[len - 1] == '\n') buf[len - 1] = '\0'; @@ -125,19 +127,17 @@ load_cfg(const char *path, struct cmd_ctx *ctxin, struct causelist *causes) ctx.info = cfg_print; cfg_cause = NULL; - cmd_list_exec(cmdlist, &ctx); + if (cmd_list_exec(cmdlist, &ctx) == 1) + retval = 1; cmd_list_free(cmdlist); if (cfg_cause != NULL) { cfg_add_cause(causes, "%s: %d: %s", path, n, cfg_cause); xfree(cfg_cause); - continue; } } if (line != NULL) xfree(line); fclose(f); - if (ARRAY_LENGTH(causes) != 0) - return (-1); - return (0); + return (retval); } diff --git a/cmd-source-file.c b/cmd-source-file.c index 93a0800c..5ba7ed8b 100644 --- a/cmd-source-file.c +++ b/cmd-source-file.c @@ -91,19 +91,35 @@ cmd_source_file_exec(struct cmd *self, struct cmd_ctx *ctx) struct cmd_source_file_data *data = self->data; struct causelist causes; char *cause; + struct window_pane *wp; + int retval; u_int i; ARRAY_INIT(&causes); - if (load_cfg(data->path, ctx, &causes) != 0) { + + retval = load_cfg(data->path, ctx, &causes); + if (ARRAY_EMPTY(&causes)) + return (retval); + + if (retval == 1 && !RB_EMPTY(&sessions) && ctx->cmdclient != NULL) { + wp = RB_MIN(sessions, &sessions)->curw->window->active; + window_pane_set_mode(wp, &window_copy_mode); + window_copy_init_for_output(wp); + for (i = 0; i < ARRAY_LENGTH(&causes); i++) { + cause = ARRAY_ITEM(&causes, i); + window_copy_add(wp, "%s", cause); + xfree(cause); + } + } else { for (i = 0; i < ARRAY_LENGTH(&causes); i++) { cause = ARRAY_ITEM(&causes, i); ctx->print(ctx, "%s", cause); xfree(cause); } - ARRAY_FREE(&causes); } + ARRAY_FREE(&causes); - return (0); + return (retval); } void From f7c42c21bacf84af52079b239a18294851fbdb3a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 29 Dec 2010 21:49:06 +0000 Subject: [PATCH 0811/1180] Support all four of the xterm mouse modes. Based on a diff from hsim at gmx.li. --- input-keys.c | 2 +- input.c | 21 ++++++++++++++++++--- screen-write.c | 19 +++++++++++++------ server-client.c | 2 +- tmux.h | 14 ++++++++++---- tty.c | 24 ++++++++++++++++-------- window-choose.c | 2 +- window-copy.c | 12 +++++++----- 8 files changed, 67 insertions(+), 29 deletions(-) diff --git a/input-keys.c b/input-keys.c index b731f6dc..81976123 100644 --- a/input-keys.c +++ b/input-keys.c @@ -204,7 +204,7 @@ input_mouse(struct window_pane *wp, struct mouse_event *m) { char out[8]; - if (wp->screen->mode & MODE_MOUSE) { + if (wp->screen->mode & ALL_MOUSE_MODES) { xsnprintf(out, sizeof out, "\033[M%c%c%c", m->b + 32, m->x + 33, m->y + 33); bufferevent_write(wp->event, out, strlen(out)); diff --git a/input.c b/input.c index cbcdd83c..49224e0e 100644 --- a/input.c +++ b/input.c @@ -953,7 +953,7 @@ input_esc_dispatch(struct input_ctx *ictx) screen_write_insertmode(sctx, 0); screen_write_kcursormode(sctx, 0); screen_write_kkeypadmode(sctx, 0); - screen_write_mousemode(sctx, 0); + screen_write_mousemode_off(sctx); screen_write_clearscreen(sctx); screen_write_cursormove(sctx, 0, 0); @@ -1156,7 +1156,10 @@ input_csi_dispatch(struct input_ctx *ictx) screen_write_cursormode(&ictx->ctx, 0); break; case 1000: - screen_write_mousemode(&ictx->ctx, 0); + case 1001: + case 1002: + case 1003: + screen_write_mousemode_off(&ictx->ctx); break; case 1049: window_pane_alternate_off(wp, &ictx->cell); @@ -1192,7 +1195,19 @@ input_csi_dispatch(struct input_ctx *ictx) screen_write_cursormode(&ictx->ctx, 1); break; case 1000: - screen_write_mousemode(&ictx->ctx, 1); + screen_write_mousemode_on( + &ictx->ctx, MODE_MOUSE_STANDARD); + break; + case 1001: + screen_write_mousemode_on( + &ictx->ctx, MODE_MOUSE_HIGHLIGHT); + break; + case 1002: + screen_write_mousemode_on( + &ictx->ctx, MODE_MOUSE_BUTTON); + break; + case 1003: + screen_write_mousemode_on(&ictx->ctx, MODE_MOUSE_ANY); break; case 1049: window_pane_alternate_on(wp, &ictx->cell); diff --git a/screen-write.c b/screen-write.c index 882fced4..c4e873b1 100644 --- a/screen-write.c +++ b/screen-write.c @@ -829,16 +829,23 @@ screen_write_insertmode(struct screen_write_ctx *ctx, int state) s->mode &= ~MODE_INSERT; } -/* Set mouse mode. */ +/* Set mouse mode off. */ void -screen_write_mousemode(struct screen_write_ctx *ctx, int state) +screen_write_mousemode_off(struct screen_write_ctx *ctx) { struct screen *s = ctx->s; - if (state) - s->mode |= MODE_MOUSE; - else - s->mode &= ~MODE_MOUSE; + s->mode &= ~ALL_MOUSE_MODES; +} + +/* Set mouse mode on. */ +void +screen_write_mousemode_on(struct screen_write_ctx *ctx, int mode) +{ + struct screen *s = ctx->s; + + s->mode &= ~ALL_MOUSE_MODES; + s->mode |= mode; } /* Line feed. */ diff --git a/server-client.c b/server-client.c index c4cc9847..31ea99f5 100644 --- a/server-client.c +++ b/server-client.c @@ -450,7 +450,7 @@ server_client_reset_state(struct client *c) mode = s->mode; if (TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry) != NULL && options_get_number(oo, "mouse-select-pane")) - mode |= MODE_MOUSE; + mode |= MODE_MOUSE_STANDARD; tty_update_mode(&c->tty, mode); tty_reset(&c->tty); } diff --git a/tmux.h b/tmux.h index 075e581c..a59f57cf 100644 --- a/tmux.h +++ b/tmux.h @@ -545,9 +545,14 @@ struct mode_key_table { #define MODE_INSERT 0x2 #define MODE_KCURSOR 0x4 #define MODE_KKEYPAD 0x8 /* set = application, clear = number */ -#define MODE_MOUSE 0x10 -#define MODE_MOUSEMOTION 0x20 -#define MODE_WRAP 0x40 /* whether lines wrap */ +#define MODE_WRAP 0x10 /* whether lines wrap */ +#define MODE_MOUSE_STANDARD 0x20 +#define MODE_MOUSE_HIGHLIGHT 0x40 +#define MODE_MOUSE_BUTTON 0x80 +#define MODE_MOUSE_ANY 0x100 + +#define ALL_MOUSE_MODES (MODE_MOUSE_STANDARD| \ + MODE_MOUSE_HIGHLIGHT|MODE_MOUSE_BUTTON|MODE_MOUSE_ANY) /* * A single UTF-8 character. @@ -1808,7 +1813,8 @@ void screen_write_cursormode(struct screen_write_ctx *, int); void screen_write_reverseindex(struct screen_write_ctx *); void screen_write_scrollregion(struct screen_write_ctx *, u_int, u_int); void screen_write_insertmode(struct screen_write_ctx *, int); -void screen_write_mousemode(struct screen_write_ctx *, int); +void screen_write_mousemode_on(struct screen_write_ctx *, int); +void screen_write_mousemode_off(struct screen_write_ctx *); void screen_write_linefeed(struct screen_write_ctx *, int); void screen_write_linefeedscreen(struct screen_write_ctx *, int); void screen_write_carriagereturn(struct screen_write_ctx *); diff --git a/tty.c b/tty.c index 63f6127f..f7698708 100644 --- a/tty.c +++ b/tty.c @@ -403,17 +403,25 @@ tty_update_mode(struct tty *tty, int mode) else tty_putcode(tty, TTYC_CIVIS); } - if (changed & (MODE_MOUSE|MODE_MOUSEMOTION)) { - if (mode & MODE_MOUSE) { - if (mode & MODE_MOUSEMOTION) - tty_puts(tty, "\033[?1003h"); - else + if (changed & ALL_MOUSE_MODES) { + if (mode & ALL_MOUSE_MODES) { + if (mode & MODE_MOUSE_STANDARD) tty_puts(tty, "\033[?1000h"); + else if (mode & MODE_MOUSE_HIGHLIGHT) + tty_puts(tty, "\033[?1001h"); + else if (mode & MODE_MOUSE_BUTTON) + tty_puts(tty, "\033[?1002h"); + else if (mode & MODE_MOUSE_ANY) + tty_puts(tty, "\033[?1003h"); } else { - if (mode & MODE_MOUSEMOTION) - tty_puts(tty, "\033[?1003l"); - else + if (tty->mode & MODE_MOUSE_STANDARD) tty_puts(tty, "\033[?1000l"); + else if (tty->mode & MODE_MOUSE_HIGHLIGHT) + tty_puts(tty, "\033[?1001l"); + else if (tty->mode & MODE_MOUSE_BUTTON) + tty_puts(tty, "\033[?1002l"); + else if (tty->mode & MODE_MOUSE_ANY) + tty_puts(tty, "\033[?1003l"); } } if (changed & MODE_KKEYPAD) { diff --git a/window-choose.c b/window-choose.c index a50d7e30..ccd09afc 100644 --- a/window-choose.c +++ b/window-choose.c @@ -127,7 +127,7 @@ window_choose_init(struct window_pane *wp) screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0); s->mode &= ~MODE_CURSOR; if (options_get_number(&wp->window->options, "mode-mouse")) - s->mode |= MODE_MOUSE; + s->mode |= MODE_MOUSE_STANDARD; keys = options_get_number(&wp->window->options, "mode-keys"); if (keys == MODEKEY_EMACS) diff --git a/window-copy.c b/window-copy.c index 9f92464b..3cc7e4c1 100644 --- a/window-copy.c +++ b/window-copy.c @@ -180,7 +180,7 @@ window_copy_init(struct window_pane *wp) s = &data->screen; screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0); if (options_get_number(&wp->window->options, "mode-mouse")) - s->mode |= MODE_MOUSE; + s->mode |= MODE_MOUSE_STANDARD; keys = options_get_number(&wp->window->options, "mode-keys"); if (keys == MODEKEY_EMACS) @@ -787,13 +787,14 @@ window_copy_mouse( * If already reading motion, move the cursor while buttons are still * pressed, or stop the selection on their release. */ - if (s->mode & MODE_MOUSEMOTION) { + if (s->mode & MODE_MOUSE_ANY) { if ((m->b & MOUSE_BUTTON) != MOUSE_UP) { window_copy_update_cursor(wp, m->x, m->y); if (window_copy_update_selection(wp)) window_copy_redraw_screen(wp); } else { - s->mode &= ~MODE_MOUSEMOTION; + s->mode &= ~MODE_MOUSE_ANY; + s->mode |= MODE_MOUSE_STANDARD; if (sess != NULL) { window_copy_copy_selection(wp, sess); window_pane_reset_mode(wp); @@ -802,9 +803,10 @@ window_copy_mouse( return; } - /* Otherwise i other buttons pressed, start selection and motion. */ + /* Otherwise if other buttons pressed, start selection and motion. */ if ((m->b & MOUSE_BUTTON) != MOUSE_UP) { - s->mode |= MODE_MOUSEMOTION; + s->mode &= ~MODE_MOUSE_STANDARD; + s->mode |= MODE_MOUSE_ANY; window_copy_update_cursor(wp, m->x, m->y); window_copy_start_selection(wp); From 2231e72968629d67575b18979fed13b4f5ad730b Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 30 Dec 2010 21:35:17 +0000 Subject: [PATCH 0812/1180] Add a function to create window flags rather than doing the same thing in two places. From Thomas Adam. --- cmd-choose-window.c | 23 ++++++----------------- status.c | 17 ++--------------- tmux.h | 2 ++ window.c | 26 ++++++++++++++++++++++++++ 4 files changed, 36 insertions(+), 32 deletions(-) diff --git a/cmd-choose-window.c b/cmd-choose-window.c index 3f4c956b..1bbe0dfe 100644 --- a/cmd-choose-window.c +++ b/cmd-choose-window.c @@ -57,7 +57,7 @@ cmd_choose_window_exec(struct cmd *self, struct cmd_ctx *ctx) struct winlink *wl, *wm; struct window *w; u_int idx, cur; - char flag, *title; + char *flags, *title; const char *left, *right; if (ctx->curclient == NULL) { @@ -80,20 +80,7 @@ cmd_choose_window_exec(struct cmd *self, struct cmd_ctx *ctx) cur = idx; idx++; - flag = ' '; - if (wm->flags & WINLINK_ACTIVITY) - flag = '#'; - else if (wm->flags & WINLINK_BELL) - flag = '!'; - else if (wm->flags & WINLINK_CONTENT) - flag = '+'; - else if (wm->flags & WINLINK_SILENCE) - flag = '~'; - else if (wm == s->curw) - flag = '*'; - else if (wm == TAILQ_FIRST(&s->lastw)) - flag = '-'; - + flags = window_printable_flags(s, wm); title = w->active->screen->title; if (wm == wl) title = w->active->base.title; @@ -103,10 +90,12 @@ cmd_choose_window_exec(struct cmd *self, struct cmd_ctx *ctx) left = right = ""; window_choose_add(wl->window->active, - wm->idx, "%3d: %s%c [%ux%u] (%u panes%s)%s%s%s", - wm->idx, w->name, flag, w->sx, w->sy, window_count_panes(w), + wm->idx, "%3d: %s%s [%ux%u] (%u panes%s)%s%s%s", + wm->idx, w->name, flags, w->sx, w->sy, window_count_panes(w), w->active->fd == -1 ? ", dead" : "", left, title, right); + + xfree(flags); } cdata = xmalloc(sizeof *cdata); diff --git a/status.c b/status.c index 74316f2d..5523858d 100644 --- a/status.c +++ b/status.c @@ -393,21 +393,8 @@ status_replace1(struct client *c,struct winlink *wl, ptr = wl->window->name; goto do_replace; case 'F': - tmp[0] = ' '; - if (wl->flags & WINLINK_CONTENT) - tmp[0] = '+'; - else if (wl->flags & WINLINK_BELL) - tmp[0] = '!'; - else if (wl->flags & WINLINK_ACTIVITY) - tmp[0] = '#'; - else if (wl->flags & WINLINK_SILENCE) - tmp[0] = '~'; - else if (wl == s->curw) - tmp[0] = '*'; - else if (wl == TAILQ_FIRST(&s->lastw)) - tmp[0] = '-'; - tmp[1] = '\0'; - ptr = tmp; + ptr = window_printable_flags(s, wl); + freeptr = ptr; goto do_replace; case '[': /* diff --git a/tmux.h b/tmux.h index a59f57cf..b2fc9a0a 100644 --- a/tmux.h +++ b/tmux.h @@ -1898,6 +1898,8 @@ void window_pane_mouse(struct window_pane *, int window_pane_visible(struct window_pane *); char *window_pane_search( struct window_pane *, const char *, u_int *); +char *window_printable_flags(struct session *, struct winlink *); + struct window_pane *window_pane_find_up(struct window_pane *); struct window_pane *window_pane_find_down(struct window_pane *); struct window_pane *window_pane_find_left(struct window_pane *); diff --git a/window.c b/window.c index 95877cb5..ebd3976b 100644 --- a/window.c +++ b/window.c @@ -463,6 +463,32 @@ window_destroy_panes(struct window *w) } } +/* Return list of printable window flag symbols. No flags is just a space. */ +char * +window_printable_flags(struct session *s, struct winlink *wl) +{ + char flags[BUFSIZ]; + int pos; + + pos = 0; + if (wl->flags & WINLINK_ACTIVITY) + flags[pos++] = '#'; + if (wl->flags & WINLINK_BELL) + flags[pos++] = '!'; + if (wl->flags & WINLINK_CONTENT) + flags[pos++] = '+'; + if (wl->flags & WINLINK_SILENCE) + flags[pos++] = '~'; + if (wl == s->curw) + flags[pos++] = '*'; + if (wl == TAILQ_FIRST(&s->lastw)) + flags[pos++] = '-'; + if (pos == 0) + flags[pos++] = ' '; + flags[pos] = '\0'; + return (xstrdup(flags)); +} + struct window_pane * window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit) { From cc42614fa92a0fd93ae359af6562401a2d3d00d7 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 30 Dec 2010 23:16:18 +0000 Subject: [PATCH 0813/1180] Change from a per-session stack of buffers to one global stack which is much more convenient and also simplifies lot of code. This renders copy-buffer useless and makes buffer-limit now a server option. By Tiago Cunha. --- Makefile | 2 +- cmd-capture-pane.c | 119 +++++++++++++++++++++---- cmd-choose-buffer.c | 4 +- cmd-copy-buffer.c | 205 -------------------------------------------- cmd-delete-buffer.c | 10 +-- cmd-generic.c | 11 +-- cmd-list-buffers.c | 20 ++--- cmd-load-buffer.c | 73 +++++----------- cmd-paste-buffer.c | 9 +- cmd-save-buffer.c | 11 +-- cmd-set-buffer.c | 11 +-- cmd-set-option.c | 4 +- cmd-show-buffer.c | 17 ++-- cmd.c | 1 - paste.c | 13 --- server.c | 3 + session.c | 3 - status.c | 2 +- tmux.1 | 32 ++----- tmux.c | 2 +- tmux.h | 9 +- window-copy.c | 12 +-- 22 files changed, 187 insertions(+), 386 deletions(-) delete mode 100644 cmd-copy-buffer.c diff --git a/Makefile b/Makefile index 0b27bd45..532b19e1 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ SRCS= attributes.c cfg.c client.c clock.c \ cmd-attach-session.c cmd-bind-key.c \ cmd-break-pane.c cmd-choose-session.c cmd-choose-window.c \ cmd-clear-history.c cmd-clock-mode.c cmd-command-prompt.c \ - cmd-confirm-before.c cmd-copy-buffer.c cmd-copy-mode.c \ + cmd-confirm-before.c cmd-copy-mode.c \ cmd-choose-buffer.c cmd-delete-buffer.c cmd-detach-client.c \ cmd-find-window.c cmd-generic.c cmd-has-session.c cmd-kill-pane.c \ cmd-kill-server.c cmd-kill-session.c cmd-kill-window.c \ diff --git a/cmd-capture-pane.c b/cmd-capture-pane.c index 4d551706..df5875e7 100644 --- a/cmd-capture-pane.c +++ b/cmd-capture-pane.c @@ -18,6 +18,7 @@ #include +#include #include #include "tmux.h" @@ -26,31 +27,93 @@ * Write the entire contents of a pane to a buffer. */ +int cmd_capture_pane_parse(struct cmd *, int, char **, char **); int cmd_capture_pane_exec(struct cmd *, struct cmd_ctx *); +void cmd_capture_pane_free(struct cmd *); +void cmd_capture_pane_init(struct cmd *, int); +size_t cmd_capture_pane_print(struct cmd *, char *, size_t); + +struct cmd_capture_pane_data { + char *target; + int buffer; +}; const struct cmd_entry cmd_capture_pane_entry = { "capture-pane", "capturep", CMD_BUFFER_PANE_USAGE, 0, "", - cmd_buffer_init, - cmd_buffer_parse, + cmd_capture_pane_init, + cmd_capture_pane_parse, cmd_capture_pane_exec, - cmd_buffer_free, - cmd_buffer_print + cmd_capture_pane_free, + cmd_capture_pane_print }; +/* ARGSUSED */ +void +cmd_capture_pane_init(struct cmd *self, unused int arg) +{ + struct cmd_capture_pane_data *data; + + self->data = data = xmalloc(sizeof *data); + data->buffer = -1; + data->target = NULL; +} + +int +cmd_capture_pane_parse(struct cmd *self, int argc, char **argv, char **cause) +{ + struct cmd_capture_pane_data *data; + const char *errstr; + int n, opt; + + self->entry->init(self, KEYC_NONE); + data = self->data; + + while ((opt = getopt(argc, argv, "b:t:")) != -1) { + switch (opt) { + case 'b': + if (data->buffer == -1) { + n = strtonum(optarg, 0, INT_MAX, &errstr); + if (errstr != NULL) { + xasprintf(cause, "buffer %s", errstr); + goto error; + } + data->buffer = n; + } + break; + case 't': + if (data->target == NULL) + data->target = xstrdup(optarg); + break; + default: + goto usage; + } + } + argc -= optind; + argv += optind; + + return (0); + +usage: + xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); + +error: + self->entry->free(self); + return (-1); +} + int cmd_capture_pane_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_buffer_data *data = self->data; - struct window_pane *wp; - char *buf, *line; - struct screen *s; - struct session *sess; - u_int i, limit; - size_t len, linelen; + struct cmd_capture_pane_data *data = self->data; + struct window_pane *wp; + char *buf, *line; + struct screen *s; + u_int i, limit; + size_t len, linelen; - if (cmd_find_pane(ctx, data->target, &sess, &wp) == NULL) + if (cmd_find_pane(ctx, data->target, NULL, &wp) == NULL) return (-1); s = &wp->base; @@ -69,15 +132,41 @@ cmd_capture_pane_exec(struct cmd *self, struct cmd_ctx *ctx) xfree(line); } - limit = options_get_number(&sess->options, "buffer-limit"); + limit = options_get_number(&global_options, "buffer-limit"); if (data->buffer == -1) { - paste_add(&sess->buffers, buf, len, limit); + paste_add(&global_buffers, buf, len, limit); return (0); } - if (paste_replace(&sess->buffers, data->buffer, buf, len) != 0) { + if (paste_replace(&global_buffers, data->buffer, buf, len) != 0) { ctx->error(ctx, "no buffer %d", data->buffer); xfree(buf); return (-1); } return (0); } + +void +cmd_capture_pane_free(struct cmd *self) +{ + struct cmd_capture_pane_data *data = self->data; + + if (data->target != NULL) + xfree(data->target); + xfree(data); +} + +size_t +cmd_capture_pane_print(struct cmd *self, char *buf, size_t len) +{ + struct cmd_capture_pane_data *data = self->data; + size_t off = 0; + + off += xsnprintf(buf, len, "%s", self->entry->name); + if (data == NULL) + return (off); + if (off < len && data->buffer != -1) + off += xsnprintf(buf + off, len - off, " -b %d", data->buffer); + if (off < len && data->target != NULL) + off += xsnprintf(buf + off, len - off, " -t %s", data->target); + return (off); +} diff --git a/cmd-choose-buffer.c b/cmd-choose-buffer.c index 4008c54a..665f41b1 100644 --- a/cmd-choose-buffer.c +++ b/cmd-choose-buffer.c @@ -67,14 +67,14 @@ cmd_choose_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) return (-1); - if (paste_get_top(&s->buffers) == NULL) + if (paste_get_top(&global_buffers) == NULL) return (0); if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0) return (0); idx = 0; - while ((pb = paste_walk_stack(&s->buffers, &idx)) != NULL) { + while ((pb = paste_walk_stack(&global_buffers, &idx)) != NULL) { tmp = paste_print(pb, 50); window_choose_add(wl->window->active, idx - 1, "%u: %zu bytes: \"%s\"", idx - 1, pb->size, tmp); diff --git a/cmd-copy-buffer.c b/cmd-copy-buffer.c deleted file mode 100644 index 5f407e0c..00000000 --- a/cmd-copy-buffer.c +++ /dev/null @@ -1,205 +0,0 @@ -/* $OpenBSD$ */ - -/* - * Copyright (c) 2009 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 -#include - -#include "tmux.h" - -/* - * Copies a session paste buffer to another session. - */ - -int cmd_copy_buffer_parse(struct cmd *, int, char **, char **); -int cmd_copy_buffer_exec(struct cmd *, struct cmd_ctx *); -void cmd_copy_buffer_free(struct cmd *); -void cmd_copy_buffer_init(struct cmd *, int); -size_t cmd_copy_buffer_print(struct cmd *, char *, size_t); - -struct cmd_copy_buffer_data { - char *dst_session; - char *src_session; - int dst_idx; - int src_idx; -}; - -const struct cmd_entry cmd_copy_buffer_entry = { - "copy-buffer", "copyb", - "[-a src-index] [-b dst-index] [-s src-session] [-t dst-session]", - 0, "", - cmd_copy_buffer_init, - cmd_copy_buffer_parse, - cmd_copy_buffer_exec, - cmd_copy_buffer_free, - cmd_copy_buffer_print -}; - -/* ARGSUSED */ -void -cmd_copy_buffer_init(struct cmd *self, unused int arg) -{ - struct cmd_copy_buffer_data *data; - - self->data = data = xmalloc(sizeof *data); - data->dst_session = NULL; - data->src_session = NULL; - data->dst_idx = -1; - data->src_idx = -1; -} - -int -cmd_copy_buffer_parse(struct cmd *self, int argc, char **argv, char **cause) -{ - struct cmd_copy_buffer_data *data; - const char *errstr; - int n, opt; - - self->entry->init(self, KEYC_NONE); - data = self->data; - - while ((opt = getopt(argc, argv, "a:b:s:t:")) != -1) { - switch (opt) { - case 'a': - if (data->src_idx == -1) { - n = strtonum(optarg, 0, INT_MAX, &errstr); - if (errstr != NULL) { - xasprintf(cause, "buffer %s", errstr); - goto error; - } - data->src_idx = n; - } - break; - case 'b': - if (data->dst_idx == -1) { - n = strtonum(optarg, 0, INT_MAX, &errstr); - if (errstr != NULL) { - xasprintf(cause, "buffer %s", errstr); - goto error; - } - data->dst_idx = n; - } - break; - case 's': - if (data->src_session == NULL) - data->src_session = xstrdup(optarg); - break; - case 't': - if (data->dst_session == NULL) - data->dst_session = xstrdup(optarg); - break; - default: - goto usage; - } - } - argc -= optind; - argv += optind; - - return (0); - -usage: - xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); - -error: - self->entry->free(self); - return (-1); -} - -int -cmd_copy_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) -{ - struct cmd_copy_buffer_data *data = self->data; - struct paste_buffer *pb; - struct paste_stack *dst_ps, *src_ps; - u_char *pdata; - struct session *dst_session, *src_session; - u_int limit; - - if ((dst_session = cmd_find_session(ctx, data->dst_session)) == NULL || - (src_session = cmd_find_session(ctx, data->src_session)) == NULL) - return (-1); - dst_ps = &dst_session->buffers; - src_ps = &src_session->buffers; - - if (data->src_idx == -1) { - if ((pb = paste_get_top(src_ps)) == NULL) { - ctx->error(ctx, "no buffers"); - return (-1); - } - } else { - if ((pb = paste_get_index(src_ps, data->src_idx)) == NULL) { - ctx->error(ctx, "no buffer %d", data->src_idx); - return (-1); - } - } - limit = options_get_number(&dst_session->options, "buffer-limit"); - - pdata = xmalloc(pb->size); - memcpy(pdata, pb->data, pb->size); - - if (data->dst_idx == -1) - paste_add(dst_ps, pdata, pb->size, limit); - else if (paste_replace(dst_ps, data->dst_idx, pdata, pb->size) != 0) { - ctx->error(ctx, "no buffer %d", data->dst_idx); - xfree(pdata); - return (-1); - } - - return (0); -} - -void -cmd_copy_buffer_free(struct cmd *self) -{ - struct cmd_copy_buffer_data *data = self->data; - - if (data->dst_session != NULL) - xfree(data->dst_session); - if (data->src_session != NULL) - xfree(data->src_session); - xfree(data); -} - -size_t -cmd_copy_buffer_print(struct cmd *self, char *buf, size_t len) -{ - struct cmd_copy_buffer_data *data = self->data; - size_t off = 0; - - off += xsnprintf(buf, len, "%s", self->entry->name); - if (data == NULL) - return (off); - if (off < len && data->src_idx != -1) { - off += xsnprintf(buf + off, len - off, " -a %d", - data->src_idx); - } - if (off < len && data->dst_idx != -1) { - off += xsnprintf(buf + off, len - off, " -b %d", - data->dst_idx); - } - if (off < len && data->src_session != NULL) { - off += cmd_prarg(buf + off, len - off, " -s ", - data->src_session); - } - if (off < len && data->dst_session != NULL) { - off += cmd_prarg(buf + off, len - off, " -t ", - data->dst_session); - } - return (off); -} diff --git a/cmd-delete-buffer.c b/cmd-delete-buffer.c index 1a5b6d82..0bfd77ae 100644 --- a/cmd-delete-buffer.c +++ b/cmd-delete-buffer.c @@ -30,7 +30,7 @@ int cmd_delete_buffer_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_delete_buffer_entry = { "delete-buffer", "deleteb", - CMD_BUFFER_SESSION_USAGE, + CMD_BUFFER_USAGE, 0, "", cmd_buffer_init, cmd_buffer_parse, @@ -43,14 +43,10 @@ int cmd_delete_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) { struct cmd_buffer_data *data = self->data; - struct session *s; - - if ((s = cmd_find_session(ctx, data->target)) == NULL) - return (-1); if (data->buffer == -1) - paste_free_top(&s->buffers); - else if (paste_free_index(&s->buffers, data->buffer) != 0) { + paste_free_top(&global_buffers); + else if (paste_free_index(&global_buffers, data->buffer) != 0) { ctx->error(ctx, "no buffer %d", data->buffer); return (-1); } diff --git a/cmd-generic.c b/cmd-generic.c index 8b536fa0..97e731c9 100644 --- a/cmd-generic.c +++ b/cmd-generic.c @@ -332,7 +332,6 @@ cmd_buffer_init(struct cmd *self, unused int key) self->data = data = xmalloc(sizeof *data); data->chflags = 0; - data->target = NULL; data->buffer = -1; data->arg = NULL; data->arg2 = NULL; @@ -349,7 +348,7 @@ cmd_buffer_parse(struct cmd *self, int argc, char **argv, char **cause) cmd_buffer_init(self, 0); data = self->data; - while ((opt = cmd_getopt(argc, argv, "b:t:", entry->chflags)) != -1) { + while ((opt = cmd_getopt(argc, argv, "b:", entry->chflags)) != -1) { if (cmd_parse_flags(opt, entry->chflags, &data->chflags) == 0) continue; switch (opt) { @@ -363,10 +362,6 @@ cmd_buffer_parse(struct cmd *self, int argc, char **argv, char **cause) data->buffer = n; } break; - case 't': - if (data->target == NULL) - data->target = xstrdup(optarg); - break; default: goto usage; } @@ -392,8 +387,6 @@ cmd_buffer_free(struct cmd *self) { struct cmd_buffer_data *data = self->data; - if (data->target != NULL) - xfree(data->target); if (data->arg != NULL) xfree(data->arg); if (data->arg2 != NULL) @@ -413,8 +406,6 @@ cmd_buffer_print(struct cmd *self, char *buf, size_t len) off += cmd_print_flags(buf, len, off, data->chflags); if (off < len && data->buffer != -1) off += xsnprintf(buf + off, len - off, " -b %d", data->buffer); - if (off < len && data->target != NULL) - off += cmd_prarg(buf + off, len - off, " -t ", data->target); if (off < len && data->arg != NULL) off += cmd_prarg(buf + off, len - off, " ", data->arg); if (off < len && data->arg2 != NULL) diff --git a/cmd-list-buffers.c b/cmd-list-buffers.c index c2b0edc9..efc86f97 100644 --- a/cmd-list-buffers.c +++ b/cmd-list-buffers.c @@ -30,29 +30,25 @@ int cmd_list_buffers_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_list_buffers_entry = { "list-buffers", "lsb", - CMD_TARGET_SESSION_USAGE, + "", 0, "", - cmd_target_init, - cmd_target_parse, + NULL, + NULL, cmd_list_buffers_exec, - cmd_target_free, - cmd_target_print + NULL, + NULL }; +/* ARGSUSED */ int -cmd_list_buffers_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_list_buffers_exec(unused struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; - struct session *s; struct paste_buffer *pb; u_int idx; char *tmp; - if ((s = cmd_find_session(ctx, data->target)) == NULL) - return (-1); - idx = 0; - while ((pb = paste_walk_stack(&s->buffers, &idx)) != NULL) { + while ((pb = paste_walk_stack(&global_buffers, &idx)) != NULL) { tmp = paste_print(pb, 50); ctx->print(ctx, "%u: %zu bytes: \"%s\"", idx - 1, pb->size, tmp); diff --git a/cmd-load-buffer.c b/cmd-load-buffer.c index abaa76ca..13413e4b 100644 --- a/cmd-load-buffer.c +++ b/cmd-load-buffer.c @@ -35,7 +35,7 @@ void cmd_load_buffer_callback(struct client *, void *); const struct cmd_entry cmd_load_buffer_entry = { "load-buffer", "loadb", - CMD_BUFFER_SESSION_USAGE " path", + CMD_BUFFER_USAGE " path", CMD_ARG1, "", cmd_buffer_init, cmd_buffer_parse, @@ -44,26 +44,16 @@ const struct cmd_entry cmd_load_buffer_entry = { cmd_buffer_print }; -struct cmd_load_buffer_cdata { - struct session *session; - int buffer; -}; - int cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_buffer_data *data = self->data; - struct cmd_load_buffer_cdata *cdata; - struct session *s; - struct client *c = ctx->cmdclient; - FILE *f; - char *pdata, *new_pdata; - size_t psize; - u_int limit; - int ch; - - if ((s = cmd_find_session(ctx, data->target)) == NULL) - return (-1); + struct cmd_buffer_data *data = self->data; + struct client *c = ctx->cmdclient; + FILE *f; + char *pdata, *new_pdata; + size_t psize; + u_int limit; + int ch; if (strcmp(data->arg, "-") == 0) { if (c == NULL) { @@ -79,11 +69,7 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) return (-1); } - cdata = xmalloc(sizeof *cdata); - cdata->session = s; - cdata->session->references++; - cdata->buffer = data->buffer; - c->stdin_data = cdata; + c->stdin_data = &data->buffer; c->stdin_callback = cmd_load_buffer_callback; c->references++; @@ -115,14 +101,13 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) pdata[psize] = '\0'; fclose(f); - f = NULL; - limit = options_get_number(&s->options, "buffer-limit"); + limit = options_get_number(&global_options, "buffer-limit"); if (data->buffer == -1) { - paste_add(&s->buffers, pdata, psize, limit); + paste_add(&global_buffers, pdata, psize, limit); return (0); } - if (paste_replace(&s->buffers, data->buffer, pdata, psize) != 0) { + if (paste_replace(&global_buffers, data->buffer, pdata, psize) != 0) { ctx->error(ctx, "no buffer %d", data->buffer); return (-1); } @@ -140,11 +125,10 @@ error: void cmd_load_buffer_callback(struct client *c, void *data) { - struct cmd_load_buffer_cdata *cdata = data; - struct session *s = cdata->session; - char *pdata; - size_t psize; - u_int limit; + char *pdata; + size_t psize; + u_int limit; + int *buffer = data; /* * Event callback has already checked client is not dead and reduced @@ -152,34 +136,23 @@ cmd_load_buffer_callback(struct client *c, void *data) */ c->flags |= CLIENT_EXIT; - /* Does the target session still exist? */ - if (!session_alive(s)) - goto out; - psize = EVBUFFER_LENGTH(c->stdin_event->input); if (psize == 0) - goto out; + return; pdata = malloc(psize + 1); if (pdata == NULL) - goto out; + return; bufferevent_read(c->stdin_event, pdata, psize); pdata[psize] = '\0'; - limit = options_get_number(&s->options, "buffer-limit"); - if (cdata->buffer == -1) { - paste_add(&s->buffers, pdata, psize, limit); - goto out; - } - if (paste_replace(&s->buffers, cdata->buffer, pdata, psize) != 0) { + limit = options_get_number(&global_options, "buffer-limit"); + if (*buffer == -1) + paste_add(&global_buffers, pdata, psize, limit); + else if (paste_replace(&global_buffers, *buffer, pdata, psize) != 0) { /* No context so can't use server_client_msg_error. */ evbuffer_add_printf( - c->stderr_event->output, "no buffer %d\n", cdata->buffer); + c->stderr_event->output, "no buffer %d\n", *buffer); bufferevent_enable(c->stderr_event, EV_WRITE); - goto out; } - -out: - cdata->session->references--; - xfree(cdata); } diff --git a/cmd-paste-buffer.c b/cmd-paste-buffer.c index 75d9373f..439d7190 100644 --- a/cmd-paste-buffer.c +++ b/cmd-paste-buffer.c @@ -136,9 +136,10 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) return (-1); if (data->buffer == -1) - pb = paste_get_top(&s->buffers); + pb = paste_get_top(&global_buffers); else { - if ((pb = paste_get_index(&s->buffers, data->buffer)) == NULL) { + pb = paste_get_index(&global_buffers, data->buffer); + if (pb == NULL) { ctx->error(ctx, "no buffer %d", data->buffer); return (-1); } @@ -150,9 +151,9 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) /* Delete the buffer if -d. */ if (data->flag_delete) { if (data->buffer == -1) - paste_free_top(&s->buffers); + paste_free_top(&global_buffers); else - paste_free_index(&s->buffers, data->buffer); + paste_free_index(&global_buffers, data->buffer); } return (0); diff --git a/cmd-save-buffer.c b/cmd-save-buffer.c index 1d287cd2..7a30d12b 100644 --- a/cmd-save-buffer.c +++ b/cmd-save-buffer.c @@ -32,7 +32,7 @@ int cmd_save_buffer_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_save_buffer_entry = { "save-buffer", "saveb", - "[-a] " CMD_BUFFER_SESSION_USAGE " path", + "[-a] " CMD_BUFFER_USAGE " path", CMD_ARG1, "a", cmd_buffer_init, cmd_buffer_parse, @@ -45,21 +45,18 @@ int cmd_save_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) { struct cmd_buffer_data *data = self->data; - struct session *s; struct paste_buffer *pb; mode_t mask; FILE *f; - if ((s = cmd_find_session(ctx, data->target)) == NULL) - return (-1); - if (data->buffer == -1) { - if ((pb = paste_get_top(&s->buffers)) == NULL) { + if ((pb = paste_get_top(&global_buffers)) == NULL) { ctx->error(ctx, "no buffers"); return (-1); } } else { - if ((pb = paste_get_index(&s->buffers, data->buffer)) == NULL) { + pb = paste_get_index(&global_buffers, data->buffer); + if (pb == NULL) { ctx->error(ctx, "no buffer %d", data->buffer); return (-1); } diff --git a/cmd-set-buffer.c b/cmd-set-buffer.c index a93a0adf..376adb14 100644 --- a/cmd-set-buffer.c +++ b/cmd-set-buffer.c @@ -30,7 +30,7 @@ int cmd_set_buffer_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_set_buffer_entry = { "set-buffer", "setb", - CMD_BUFFER_SESSION_USAGE " data", + CMD_BUFFER_USAGE " data", CMD_ARG1, "", cmd_buffer_init, cmd_buffer_parse, @@ -43,23 +43,20 @@ int cmd_set_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) { struct cmd_buffer_data *data = self->data; - struct session *s; u_int limit; char *pdata; size_t psize; - if ((s = cmd_find_session(ctx, data->target)) == NULL) - return (-1); - limit = options_get_number(&s->options, "buffer-limit"); + limit = options_get_number(&global_options, "buffer-limit"); pdata = xstrdup(data->arg); psize = strlen(pdata); if (data->buffer == -1) { - paste_add(&s->buffers, pdata, psize, limit); + paste_add(&global_buffers, pdata, psize, limit); return (0); } - if (paste_replace(&s->buffers, data->buffer, pdata, psize) != 0) { + if (paste_replace(&global_buffers, data->buffer, pdata, psize) != 0) { ctx->error(ctx, "no buffer %d", data->buffer); xfree(pdata); return (-1); diff --git a/cmd-set-option.c b/cmd-set-option.c index 5c5c70ae..81e3cffa 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -74,6 +74,7 @@ const char *set_option_bell_action_list[] = { }; const struct set_option_entry set_option_table[] = { + { "buffer-limit", SET_OPTION_NUMBER, 1, INT_MAX, NULL }, { "escape-time", SET_OPTION_NUMBER, 0, INT_MAX, NULL }, { "exit-unattached", SET_OPTION_FLAG, 0, 0, NULL }, { "quiet", SET_OPTION_FLAG, 0, 0, NULL }, @@ -83,15 +84,14 @@ const struct set_option_entry set_option_table[] = { const struct set_option_entry set_session_option_table[] = { { "base-index", SET_OPTION_NUMBER, 0, INT_MAX, NULL }, { "bell-action", SET_OPTION_CHOICE, 0, 0, set_option_bell_action_list }, - { "buffer-limit", SET_OPTION_NUMBER, 1, INT_MAX, NULL }, { "default-command", SET_OPTION_STRING, 0, 0, NULL }, { "default-path", SET_OPTION_STRING, 0, 0, NULL }, { "default-shell", SET_OPTION_STRING, 0, 0, NULL }, { "default-terminal", SET_OPTION_STRING, 0, 0, NULL }, { "destroy-unattached", SET_OPTION_FLAG, 0, 0, NULL }, { "detach-on-destroy", SET_OPTION_FLAG, 0, 0, NULL }, - { "display-panes-colour", SET_OPTION_COLOUR, 0, 0, NULL }, { "display-panes-active-colour", SET_OPTION_COLOUR, 0, 0, NULL }, + { "display-panes-colour", SET_OPTION_COLOUR, 0, 0, NULL }, { "display-panes-time", SET_OPTION_NUMBER, 1, INT_MAX, NULL }, { "display-time", SET_OPTION_NUMBER, 1, INT_MAX, NULL }, { "history-limit", SET_OPTION_NUMBER, 0, INT_MAX, NULL }, diff --git a/cmd-show-buffer.c b/cmd-show-buffer.c index b8c3c05d..b6d0c231 100644 --- a/cmd-show-buffer.c +++ b/cmd-show-buffer.c @@ -30,7 +30,7 @@ int cmd_show_buffer_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_show_buffer_entry = { "show-buffer", "showb", - CMD_BUFFER_SESSION_USAGE, + CMD_BUFFER_USAGE, 0, "", cmd_buffer_init, cmd_buffer_parse, @@ -49,20 +49,21 @@ cmd_show_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) size_t size, len; u_int width; - if ((s = cmd_find_session(ctx, data->target)) == NULL) + if ((s = cmd_find_session(ctx, NULL)) == NULL) return (-1); if (data->buffer == -1) { - if ((pb = paste_get_top(&s->buffers)) == NULL) { + if ((pb = paste_get_top(&global_buffers)) == NULL) { ctx->error(ctx, "no buffers"); return (-1); } - } else if ((pb = paste_get_index(&s->buffers, data->buffer)) == NULL) { - ctx->error(ctx, "no buffer %d", data->buffer); - return (-1); + } else { + pb = paste_get_index(&global_buffers, data->buffer); + if (pb == NULL) { + ctx->error(ctx, "no buffer %d", data->buffer); + return (-1); + } } - if (pb == NULL) - return (0); size = pb->size; if (size > SIZE_MAX / 4 - 1) diff --git a/cmd.c b/cmd.c index c4aa582c..cff10f9a 100644 --- a/cmd.c +++ b/cmd.c @@ -40,7 +40,6 @@ const struct cmd_entry *cmd_table[] = { &cmd_clock_mode_entry, &cmd_command_prompt_entry, &cmd_confirm_before_entry, - &cmd_copy_buffer_entry, &cmd_copy_mode_entry, &cmd_delete_buffer_entry, &cmd_detach_client_entry, diff --git a/paste.c b/paste.c index da93129a..a5489552 100644 --- a/paste.c +++ b/paste.c @@ -29,19 +29,6 @@ * string! */ -void -paste_init_stack(struct paste_stack *ps) -{ - ARRAY_INIT(ps); -} - -void -paste_free_stack(struct paste_stack *ps) -{ - while (paste_free_top(ps) == 0) - ; -} - /* Return each item of the stack in turn. */ struct paste_buffer * paste_walk_stack(struct paste_stack *ps, uint *idx) diff --git a/server.c b/server.c index 40667a04..b9b4a290 100644 --- a/server.c +++ b/server.c @@ -51,6 +51,8 @@ int server_shutdown; struct event server_ev_accept; struct event server_ev_second; +struct paste_stack global_buffers; + int server_create_socket(void); void server_loop(void); int server_should_shutdown(void); @@ -150,6 +152,7 @@ server_start(void) RB_INIT(&sessions); RB_INIT(&dead_sessions); TAILQ_INIT(&session_groups); + ARRAY_INIT(&global_buffers); mode_key_init_trees(); key_bindings_init(); utf8_build(); diff --git a/session.c b/session.c index 6832e088..473f1bc6 100644 --- a/session.c +++ b/session.c @@ -105,8 +105,6 @@ session_create(const char *name, const char *cmd, const char *cwd, TAILQ_INIT(&s->lastw); RB_INIT(&s->windows); - paste_init_stack(&s->buffers); - options_init(&s->options, &global_s_options); environ_init(&s->environ); if (env != NULL) @@ -155,7 +153,6 @@ session_destroy(struct session *s) session_group_remove(s); environ_free(&s->environ); options_free(&s->options); - paste_free_stack(&s->buffers); while (!TAILQ_EMPTY(&s->lastw)) winlink_stack_remove(&s->lastw, TAILQ_FIRST(&s->lastw)); diff --git a/status.c b/status.c index 5523858d..75b0a830 100644 --- a/status.c +++ b/status.c @@ -983,7 +983,7 @@ status_prompt_key(struct client *c, int key) c->flags |= CLIENT_STATUS; break; case MODEKEYEDIT_PASTE: - if ((pb = paste_get_top(&c->session->buffers)) == NULL) + if ((pb = paste_get_top(&global_buffers)) == NULL) break; for (n = 0; n < pb->size; n++) { ch = (u_char) pb->data[n]; diff --git a/tmux.1 b/tmux.1 index 11d950ae..d949d40b 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1594,6 +1594,10 @@ Available window options are listed under .Pp Available server options are: .Bl -tag -width Ds +.It Ic buffer-limit Ar number +Set the number of buffers; as new buffers are added to the top of the stack, +old ones are removed from the bottom if necessary to maintain this maximum +length. .It Ic escape-time Set the time in milliseconds for which .Nm @@ -1626,10 +1630,6 @@ window of that session, means all bells are ignored and .Ic current means only bell in windows other than the current window are ignored. -.It Ic buffer-limit Ar number -Set the number of buffers kept for each session; as new buffers are added to -the top of the stack, old ones are removed from the bottom if necessary to -maintain this maximum length. .It Ic default-command Ar shell-command Set the command used for new windows (if not specified when the window is created) to @@ -2567,29 +2567,16 @@ This command works only from inside .It Ic clear-history Op Fl t Ar target-pane .D1 (alias: Ic clearhist ) Remove and free the history for the specified pane. -.It Xo Ic copy-buffer -.Op Fl a Ar src-index -.Op Fl b Ar dst-index -.Op Fl s Ar src-session -.Op Fl t Ar dst-session -.Xc -.D1 (alias: Ic copyb ) -Copy a session paste buffer to another session. -If no sessions are specified, the current one is used instead. -.It Xo Ic delete-buffer -.Op Fl b Ar buffer-index -.Op Fl t Ar target-session -.Xc +.It Ic delete-buffer Op Fl b Ar buffer-index .D1 (alias: Ic deleteb ) Delete the buffer at .Ar buffer-index , or the top buffer if not specified. -.It Ic list-buffers Op Fl t Ar target-session +.It Ic list-buffers .D1 (alias: Ic lsb ) -List the buffers in the given session. -.It Xo Ic load-buffer +List the global buffers. +.It Xo Ic load-buffer .Op Fl b Ar buffer-index -.Op Fl t Ar target-session .Ar path .Xc .D1 (alias: Ic loadb ) @@ -2618,7 +2605,6 @@ flag means to do no replacement (equivalent to a separator of LF). .It Xo Ic save-buffer .Op Fl a .Op Fl b Ar buffer-index -.Op Fl t Ar target-session .Ar path .Xc .D1 (alias: Ic saveb ) @@ -2629,7 +2615,6 @@ The option appends to rather than overwriting the file. .It Xo Ic set-buffer .Op Fl b Ar buffer-index -.Op Fl t Ar target-session .Ar data .Xc .D1 (alias: Ic setb ) @@ -2637,7 +2622,6 @@ Set the contents of the specified buffer to .Ar data . .It Xo Ic show-buffer .Op Fl b Ar buffer-index -.Op Fl t Ar target-session .Xc .D1 (alias: Ic showb ) Display the contents of the specified buffer. diff --git a/tmux.c b/tmux.c index 2618ce31..a8331a1f 100644 --- a/tmux.c +++ b/tmux.c @@ -320,12 +320,12 @@ main(int argc, char **argv) options_set_number(oo, "quiet", quiet); options_set_number(oo, "escape-time", 500); options_set_number(oo, "exit-unattached", 0); + options_set_number(oo, "buffer-limit", 9); options_init(&global_s_options, NULL); so = &global_s_options; options_set_number(so, "base-index", 0); options_set_number(so, "bell-action", BELL_ANY); - options_set_number(so, "buffer-limit", 9); options_set_string(so, "default-command", "%s", ""); options_set_string(so, "default-path", "%s", ""); options_set_string(so, "default-shell", "%s", getshell()); diff --git a/tmux.h b/tmux.h index b2fc9a0a..081212bc 100644 --- a/tmux.h +++ b/tmux.h @@ -952,8 +952,6 @@ struct session { struct options options; - struct paste_stack buffers; - #define SESSION_UNATTACHED 0x1 /* not attached to any clients */ int flags; @@ -1256,7 +1254,6 @@ struct cmd_srcdst_data { struct cmd_buffer_data { uint64_t chflags; - char *target; int buffer; char *arg; @@ -1449,8 +1446,6 @@ void tty_keys_free(struct tty *); int tty_keys_next(struct tty *); /* paste.c */ -void paste_init_stack(struct paste_stack *); -void paste_free_stack(struct paste_stack *); struct paste_buffer *paste_walk_stack(struct paste_stack *, uint *); struct paste_buffer *paste_get_top(struct paste_stack *); struct paste_buffer *paste_get_index(struct paste_stack *, u_int); @@ -1504,7 +1499,6 @@ extern const struct cmd_entry cmd_clear_history_entry; extern const struct cmd_entry cmd_clock_mode_entry; extern const struct cmd_entry cmd_command_prompt_entry; extern const struct cmd_entry cmd_confirm_before_entry; -extern const struct cmd_entry cmd_copy_buffer_entry; extern const struct cmd_entry cmd_copy_mode_entry; extern const struct cmd_entry cmd_delete_buffer_entry; extern const struct cmd_entry cmd_detach_client_entry; @@ -1607,8 +1601,8 @@ void cmd_srcdst_free(struct cmd *); size_t cmd_srcdst_print(struct cmd *, char *, size_t); #define CMD_BUFFER_PANE_USAGE "[-b buffer-index] [-t target-pane]" #define CMD_BUFFER_WINDOW_USAGE "[-b buffer-index] [-t target-window]" -#define CMD_BUFFER_SESSION_USAGE "[-b buffer-index] [-t target-session]" #define CMD_BUFFER_CLIENT_USAGE "[-b buffer-index] [-t target-client]" +#define CMD_BUFFER_USAGE "[-b buffer-index]" void cmd_buffer_init(struct cmd *, int); int cmd_buffer_parse(struct cmd *, int, char **, char **); void cmd_buffer_free(struct cmd *); @@ -1638,6 +1632,7 @@ const char *key_string_lookup_key(int); /* server.c */ extern struct clients clients; extern struct clients dead_clients; +extern struct paste_stack global_buffers; int server_start(void); void server_update_socket(void); diff --git a/window-copy.c b/window-copy.c index 3cc7e4c1..1cdb88d8 100644 --- a/window-copy.c +++ b/window-copy.c @@ -52,7 +52,7 @@ void window_copy_goto_line(struct window_pane *, const char *); void window_copy_update_cursor(struct window_pane *, u_int, u_int); void window_copy_start_selection(struct window_pane *); int window_copy_update_selection(struct window_pane *); -void window_copy_copy_selection(struct window_pane *, struct session *); +void window_copy_copy_selection(struct window_pane *); void window_copy_clear_selection(struct window_pane *); void window_copy_copy_line( struct window_pane *, char **, size_t *, u_int, u_int, u_int); @@ -506,7 +506,7 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key) break; case MODEKEYCOPY_COPYSELECTION: if (sess != NULL) { - window_copy_copy_selection(wp, sess); + window_copy_copy_selection(wp); window_pane_reset_mode(wp); return; } @@ -796,7 +796,7 @@ window_copy_mouse( s->mode &= ~MODE_MOUSE_ANY; s->mode |= MODE_MOUSE_STANDARD; if (sess != NULL) { - window_copy_copy_selection(wp, sess); + window_copy_copy_selection(wp); window_pane_reset_mode(wp); } } @@ -1210,7 +1210,7 @@ window_copy_update_selection(struct window_pane *wp) } void -window_copy_copy_selection(struct window_pane *wp, struct session *sess) +window_copy_copy_selection(struct window_pane *wp) { struct window_copy_mode_data *data = wp->modedata; struct screen *s = &data->screen; @@ -1305,8 +1305,8 @@ window_copy_copy_selection(struct window_pane *wp, struct session *sess) off--; /* remove final \n */ /* Add the buffer to the stack. */ - limit = options_get_number(&sess->options, "buffer-limit"); - paste_add(&sess->buffers, buf, off, limit); + limit = options_get_number(&global_options, "buffer-limit"); + paste_add(&global_buffers, buf, off, limit); } void From 2b3c2fd8523e94f13d6063abed72bdea8ac8cacb Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 30 Dec 2010 23:17:41 +0000 Subject: [PATCH 0814/1180] Fix BUFFERS section now they are global. --- tmux.1 | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tmux.1 b/tmux.1 index d949d40b..941ad948 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2524,8 +2524,7 @@ with the exception that #() are not handled. .Sh BUFFERS .Nm maintains a stack of -.Em paste buffers -for each session. +.Em paste buffers . Up to the value of the .Ic buffer-limit option are kept; when a new buffer is added, the buffer at the bottom of the From 4fb1045f5a1829d39935b7cd05a2a049aa0d406c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 30 Dec 2010 23:20:13 +0000 Subject: [PATCH 0815/1180] Remove some unused defines. --- cmd-capture-pane.c | 2 +- tmux.h | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/cmd-capture-pane.c b/cmd-capture-pane.c index df5875e7..c711db42 100644 --- a/cmd-capture-pane.c +++ b/cmd-capture-pane.c @@ -40,7 +40,7 @@ struct cmd_capture_pane_data { const struct cmd_entry cmd_capture_pane_entry = { "capture-pane", "capturep", - CMD_BUFFER_PANE_USAGE, + "[-b buffer-index] [-t target-pane]", 0, "", cmd_capture_pane_init, cmd_capture_pane_parse, diff --git a/tmux.h b/tmux.h index 081212bc..64b66e15 100644 --- a/tmux.h +++ b/tmux.h @@ -1599,9 +1599,6 @@ void cmd_srcdst_init(struct cmd *, int); int cmd_srcdst_parse(struct cmd *, int, char **, char **); void cmd_srcdst_free(struct cmd *); size_t cmd_srcdst_print(struct cmd *, char *, size_t); -#define CMD_BUFFER_PANE_USAGE "[-b buffer-index] [-t target-pane]" -#define CMD_BUFFER_WINDOW_USAGE "[-b buffer-index] [-t target-window]" -#define CMD_BUFFER_CLIENT_USAGE "[-b buffer-index] [-t target-client]" #define CMD_BUFFER_USAGE "[-b buffer-index]" void cmd_buffer_init(struct cmd *, int); int cmd_buffer_parse(struct cmd *, int, char **, char **); From 1a1efd5bc9ec0ad05a61f2a222db69ed991bb4aa Mon Sep 17 00:00:00 2001 From: Jason McIntyre Date: Fri, 31 Dec 2010 00:41:11 +0000 Subject: [PATCH 0816/1180] fix trailing whitespace; --- tmux.1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tmux.1 b/tmux.1 index 941ad948..b9d56fe3 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2574,7 +2574,7 @@ or the top buffer if not specified. .It Ic list-buffers .D1 (alias: Ic lsb ) List the global buffers. -.It Xo Ic load-buffer +.It Xo Ic load-buffer .Op Fl b Ar buffer-index .Ar path .Xc From 91218f8714dafa83f49ece4435cc3d26a738a02e Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 1 Jan 2011 00:44:24 +0000 Subject: [PATCH 0817/1180] Remove unused variable. --- cmd-choose-buffer.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/cmd-choose-buffer.c b/cmd-choose-buffer.c index 665f41b1..32bf2f2d 100644 --- a/cmd-choose-buffer.c +++ b/cmd-choose-buffer.c @@ -52,7 +52,6 @@ cmd_choose_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) { struct cmd_target_data *data = self->data; struct cmd_choose_buffer_data *cdata; - struct session *s; struct winlink *wl; struct paste_buffer *pb; u_int idx; @@ -62,7 +61,6 @@ cmd_choose_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) ctx->error(ctx, "must be run interactively"); return (-1); } - s = ctx->curclient->session; if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) return (-1); From 04b32fa734d491e7ae9b915dc309858310d96185 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 1 Jan 2011 01:12:09 +0000 Subject: [PATCH 0818/1180] Don't reset the activity timer for unattached sessions every second, this screws up the choice of most-recently-used. Instead, break the time update into a little function and do it when the session is attached. Pointed out by joshe@. --- cmd-attach-session.c | 2 ++ cmd-new-session.c | 2 ++ cmd-switch-client.c | 1 + server-client.c | 7 ++----- server-fn.c | 1 + server.c | 12 ++---------- session.c | 10 +++++++++- tmux.h | 1 + 8 files changed, 20 insertions(+), 16 deletions(-) diff --git a/cmd-attach-session.c b/cmd-attach-session.c index 13fabc8d..45a49f2b 100644 --- a/cmd-attach-session.c +++ b/cmd-attach-session.c @@ -74,6 +74,7 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx) } ctx->curclient->session = s; + session_update_activity(s); server_redraw_client(ctx->curclient); } else { if (!(ctx->cmdclient->flags & CLIENT_TERMINAL)) { @@ -96,6 +97,7 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx) server_write_session(s, MSG_DETACH, NULL, 0); ctx->cmdclient->session = s; + session_update_activity(s); server_write_client(ctx->cmdclient, MSG_READY, NULL, 0); update = options_get_string(&s->options, "update-environment"); diff --git a/cmd-new-session.c b/cmd-new-session.c index 5511da5d..53a50bbb 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -284,12 +284,14 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) if (old_s != NULL) ctx->cmdclient->last_session = old_s; ctx->cmdclient->session = s; + session_update_activity(s); server_redraw_client(ctx->cmdclient); } else { old_s = ctx->curclient->session; if (old_s != NULL) ctx->curclient->last_session = old_s; ctx->curclient->session = s; + session_update_activity(s); server_redraw_client(ctx->curclient); } } diff --git a/cmd-switch-client.c b/cmd-switch-client.c index 1be8a6c7..d695ce42 100644 --- a/cmd-switch-client.c +++ b/cmd-switch-client.c @@ -173,6 +173,7 @@ cmd_switch_client_exec(struct cmd *self, struct cmd_ctx *ctx) if (c->session != NULL) c->last_session = c->session; c->session = s; + session_update_activity(s); recalculate_sizes(); server_check_unattached(); diff --git a/server-client.c b/server-client.c index 31ea99f5..76f8d3a8 100644 --- a/server-client.c +++ b/server-client.c @@ -761,11 +761,8 @@ server_client_msg_dispatch(struct client *c) if (gettimeofday(&c->activity_time, NULL) != 0) fatal("gettimeofday"); - if (c->session != NULL) { - memcpy(&c->session->activity_time, - &c->activity_time, - sizeof c->session->activity_time); - } + if (c->session != NULL) + session_update_activity(c->session); tty_start_tty(&c->tty); server_redraw_client(c); diff --git a/server-fn.c b/server-fn.c index 03fa01d2..7064c1ed 100644 --- a/server-fn.c +++ b/server-fn.c @@ -396,6 +396,7 @@ server_destroy_session(struct session *s) } else { c->last_session = NULL; c->session = s_new; + session_update_activity(s_new); server_redraw_client(c); } } diff --git a/server.c b/server.c index b9b4a290..3b35454d 100644 --- a/server.c +++ b/server.c @@ -494,12 +494,8 @@ server_lock_server(void) t = time(NULL); RB_FOREACH(s, sessions, &sessions) { - if (s->flags & SESSION_UNATTACHED) { - if (gettimeofday(&s->activity_time, NULL) != 0) - fatal("gettimeofday failed"); + if (s->flags & SESSION_UNATTACHED) continue; - } - timeout = options_get_number(&s->options, "lock-after-time"); if (timeout <= 0 || t <= s->activity_time.tv_sec + timeout) return; /* not timed out */ @@ -519,12 +515,8 @@ server_lock_sessions(void) t = time(NULL); RB_FOREACH(s, sessions, &sessions) { - if (s->flags & SESSION_UNATTACHED) { - if (gettimeofday(&s->activity_time, NULL) != 0) - fatal("gettimeofday failed"); + if (s->flags & SESSION_UNATTACHED) continue; - } - timeout = options_get_number(&s->options, "lock-after-time"); if (timeout > 0 && t > s->activity_time.tv_sec + timeout) { server_lock_session(s); diff --git a/session.c b/session.c index 473f1bc6..fc0d9f07 100644 --- a/session.c +++ b/session.c @@ -97,7 +97,7 @@ session_create(const char *name, const char *cmd, const char *cwd, if (gettimeofday(&s->creation_time, NULL) != 0) fatal("gettimeofday failed"); - memcpy(&s->activity_time, &s->creation_time, sizeof s->activity_time); + session_update_activity(s); s->cwd = xstrdup(cwd); @@ -164,6 +164,14 @@ session_destroy(struct session *s) RB_INSERT(sessions, &dead_sessions, s); } +/* Update session active time. */ +void +session_update_activity(struct session *s) +{ + if (gettimeofday(&s->activity_time, NULL) != 0) + fatal("gettimeofday"); +} + /* Find the next usable session. */ struct session * session_next_session(struct session *s) diff --git a/tmux.h b/tmux.h index 64b66e15..1d198b69 100644 --- a/tmux.h +++ b/tmux.h @@ -1980,6 +1980,7 @@ struct session *session_create(const char *, const char *, const char *, struct environ *, struct termios *, int, u_int, u_int, char **); void session_destroy(struct session *); +void session_update_activity(struct session *); struct session *session_next_session(struct session *); struct session *session_previous_session(struct session *); struct winlink *session_new(struct session *, From b6950ed8aa4487f0c1a45cbf202a97d9fa22d485 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 1 Jan 2011 01:33:07 +0000 Subject: [PATCH 0819/1180] Add a -P option to new-window and split-window to print the new window or pane index in target form (useful to pass it into other commands). --- cmd-new-window.c | 13 +++++++++++-- cmd-split-window.c | 18 +++++++++++++++--- tmux.1 | 8 ++++++-- 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/cmd-new-window.c b/cmd-new-window.c index b44be0b2..e17cdf1d 100644 --- a/cmd-new-window.c +++ b/cmd-new-window.c @@ -39,11 +39,12 @@ struct cmd_new_window_data { int flag_insert_after; int flag_detached; int flag_kill; + int flag_print; }; const struct cmd_entry cmd_new_window_entry = { "new-window", "neww", - "[-adk] [-n window-name] [-t target-window] [command]", + "[-adkP] [-n window-name] [-t target-window] [command]", 0, "", cmd_new_window_init, cmd_new_window_parse, @@ -65,6 +66,7 @@ cmd_new_window_init(struct cmd *self, unused int arg) data->flag_insert_after = 0; data->flag_detached = 0; data->flag_kill = 0; + data->flag_print = 0; } int @@ -76,7 +78,7 @@ cmd_new_window_parse(struct cmd *self, int argc, char **argv, char **cause) self->entry->init(self, KEYC_NONE); data = self->data; - while ((opt = getopt(argc, argv, "adkt:n:")) != -1) { + while ((opt = getopt(argc, argv, "adkt:n:P")) != -1) { switch (opt) { case 'a': data->flag_insert_after = 1; @@ -95,6 +97,9 @@ cmd_new_window_parse(struct cmd *self, int argc, char **argv, char **cause) if (data->name == NULL) data->name = xstrdup(optarg); break; + case 'P': + data->flag_print = 1; + break; default: goto usage; } @@ -198,6 +203,8 @@ cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx) } else server_status_session_group(s); + if (data->flag_print) + ctx->print(ctx, "%s:%u", s->name, wl->idx); return (0); } @@ -226,6 +233,8 @@ cmd_new_window_print(struct cmd *self, char *buf, size_t len) return (off); if (off < len && data->flag_detached) off += xsnprintf(buf + off, len - off, " -d"); + if (off < len && data->flag_print) + off += xsnprintf(buf + off, len - off, " -P"); if (off < len && data->target != NULL) off += cmd_prarg(buf + off, len - off, " -t ", data->target); if (off < len && data->name != NULL) diff --git a/cmd-split-window.c b/cmd-split-window.c index e4f46c34..e9a6eb4e 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -39,13 +39,14 @@ struct cmd_split_window_data { char *cmd; int flag_detached; int flag_horizontal; + int flag_print; int percentage; int size; }; const struct cmd_entry cmd_split_window_entry = { "split-window", "splitw", - "[-dhv] [-p percentage|-l size] [-t target-pane] [command]", + "[-dhvP] [-p percentage|-l size] [-t target-pane] [command]", 0, "", cmd_split_window_init, cmd_split_window_parse, @@ -64,6 +65,7 @@ cmd_split_window_init(struct cmd *self, int key) data->cmd = NULL; data->flag_detached = 0; data->flag_horizontal = 0; + data->flag_print = 0; data->percentage = -1; data->size = -1; @@ -87,7 +89,7 @@ cmd_split_window_parse(struct cmd *self, int argc, char **argv, char **cause) self->entry->init(self, KEYC_NONE); data = self->data; - while ((opt = getopt(argc, argv, "dhl:p:t:v")) != -1) { + while ((opt = getopt(argc, argv, "dhl:p:Pt:v")) != -1) { switch (opt) { case 'd': data->flag_detached = 1; @@ -117,6 +119,9 @@ cmd_split_window_parse(struct cmd *self, int argc, char **argv, char **cause) goto error; } break; + case 'P': + data->flag_print = 1; + break; case 'v': data->flag_horizontal = 0; break; @@ -153,7 +158,7 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) struct environ env; char *cmd, *cwd, *cause; const char *shell; - u_int hlimit; + u_int hlimit, paneidx; int size; enum layout_type type; struct layout_cell *lc; @@ -217,6 +222,11 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) server_status_session(s); environ_free(&env); + + if (data->flag_print) { + paneidx = window_pane_index(wl->window, new_wp); + ctx->print(ctx, "%s:%u.%u", s->name, wl->idx, paneidx); + } return (0); error: @@ -253,6 +263,8 @@ cmd_split_window_print(struct cmd *self, char *buf, size_t len) off += xsnprintf(buf + off, len - off, " -d"); if (off < len && data->flag_horizontal) off += xsnprintf(buf + off, len - off, " -h"); + if (off < len && data->flag_print) + off += xsnprintf(buf + off, len - off, " -P"); if (off < len && data->size > 0) off += xsnprintf(buf + off, len - off, " -l %d", data->size); if (off < len && data->percentage > 0) { diff --git a/tmux.1 b/tmux.1 index b9d56fe3..3c600520 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1097,7 +1097,7 @@ except the window at is moved to .Ar dst-window . .It Xo Ic new-window -.Op Fl adk +.Op Fl adkP .Op Fl n Ar window-name .Op Fl t Ar target-window .Op Ar shell-command @@ -1145,6 +1145,10 @@ New windows will automatically have .Dq TERM=screen added to their environment, but care must be taken not to reset this in shell start-up files. +.Pp +The +.Fl P +option prints the location of the new window after it has been created. .It Ic next-layout Op Fl t Ar target-window .D1 (alias: Ic nextl ) Move a window to the next layout and rearrange the panes to fit. @@ -1281,7 +1285,7 @@ target pane is used. Select the window at .Ar target-window . .It Xo Ic split-window -.Op Fl dhv +.Op Fl dhvP .Oo Fl l .Ar size | .Fl p Ar percentage Oc From 1c86713afd3e6d42547f64daa520992c74f3cdcd Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 1 Jan 2011 02:16:25 +0000 Subject: [PATCH 0820/1180] Key table should be const. --- tty-keys.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tty-keys.c b/tty-keys.c index 59002fb2..19964538 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -54,7 +54,7 @@ struct tty_key_ent { * Default key tables. Those flagged with TTYKEY_RAW are inserted directly, * otherwise they are looked up in terminfo(5). */ -struct tty_key_ent tty_keys[] = { +const struct tty_key_ent tty_keys[] = { /* * Numeric keypad. Just use the vt100 escape sequences here and always * put the terminal into keypad_xmit mode. Translation of numbers @@ -343,9 +343,9 @@ tty_keys_add1(struct tty_key **tkp, const char *s, int key) void tty_keys_init(struct tty *tty) { - struct tty_key_ent *tke; - u_int i; - const char *s; + const struct tty_key_ent *tke; + u_int i; + const char *s; tty->key_tree = NULL; for (i = 0; i < nitems(tty_keys); i++) { From 5d0cfe079b5c1309c40fc5bfd76f7786059577d5 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 1 Jan 2011 03:32:28 +0000 Subject: [PATCH 0821/1180] Another table that should be const. --- cmd-server-info.c | 36 ++++++++++++++++++------------------ tmux.h | 2 +- tty-term.c | 31 ++++++++++++++++--------------- 3 files changed, 35 insertions(+), 34 deletions(-) diff --git a/cmd-server-info.c b/cmd-server-info.c index a114bf05..51a42219 100644 --- a/cmd-server-info.c +++ b/cmd-server-info.c @@ -48,24 +48,24 @@ const struct cmd_entry cmd_server_info_entry = { int cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx) { - struct tty_term *term; - struct client *c; - struct session *s; - struct winlink *wl; - struct window *w; - struct window_pane *wp; - struct tty_code *code; - struct tty_term_code_entry *ent; - struct utsname un; - struct job *job; - struct grid *gd; - struct grid_line *gl; - u_int i, j, k; - char out[80]; - char *tim; - time_t t; - u_int lines, ulines; - size_t size, usize; + 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; + char out[80]; + char *tim; + time_t t; + u_int lines, ulines; + size_t size, usize; tim = ctime(&start_time); *strchr(tim, '\n') = '\0'; diff --git a/tmux.h b/tmux.h index 1d198b69..fcf14362 100644 --- a/tmux.h +++ b/tmux.h @@ -1426,7 +1426,7 @@ void tty_cmd_reverseindex(struct tty *, const struct tty_ctx *); /* tty-term.c */ extern struct tty_terms tty_terms; -extern struct tty_term_code_entry tty_term_codes[NTTYCODE]; +extern const struct tty_term_code_entry tty_term_codes[NTTYCODE]; struct tty_term *tty_term_find(char *, int, const char *, char **); void tty_term_free(struct tty_term *); int tty_term_has(struct tty_term *, enum tty_code_code); diff --git a/tty-term.c b/tty-term.c index 1566253d..efc962ec 100644 --- a/tty-term.c +++ b/tty-term.c @@ -32,7 +32,7 @@ char *tty_term_strip(const char *); struct tty_terms tty_terms = SLIST_HEAD_INITIALIZER(tty_terms); -struct tty_term_code_entry tty_term_codes[NTTYCODE] = { +const struct tty_term_code_entry tty_term_codes[NTTYCODE] = { { TTYC_ACSC, TTYCODE_STRING, "acsc" }, { TTYC_AX, TTYCODE_FLAG, "AX" }, { TTYC_BEL, TTYCODE_STRING, "bel" }, @@ -214,13 +214,14 @@ tty_term_strip(const char *s) void tty_term_override(struct tty_term *term, const char *overrides) { - struct tty_term_code_entry *ent; - struct tty_code *code; - char *termnext, *termstr, *entnext, *entstr; - char *s, *ptr, *val; - const char *errstr; - u_int i; - int n, removeflag; + const struct tty_term_code_entry *ent; + struct tty_code *code; + char *termnext, *termstr; + char *entnext, *entstr; + char *s, *ptr, *val; + const char *errstr; + u_int i; + int n, removeflag; s = xstrdup(overrides); @@ -296,13 +297,13 @@ tty_term_override(struct tty_term *term, const char *overrides) struct tty_term * tty_term_find(char *name, int fd, const char *overrides, char **cause) { - struct tty_term *term; - struct tty_term_code_entry *ent; - struct tty_code *code; - u_int i; - int n, error; - char *s; - const char *acs; + struct tty_term *term; + const struct tty_term_code_entry *ent; + struct tty_code *code; + u_int i; + int n, error; + char *s; + const char *acs; SLIST_FOREACH(term, &tty_terms, entry) { if (strcmp(term->name, name) == 0) { From 67ee86085cc8e13222a6d5b4cc67c5f0934f0b3b Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 1 Jan 2011 03:39:21 +0000 Subject: [PATCH 0822/1180] Sprinkle a little more const. --- mode-key.c | 10 +++++----- tmux.h | 14 ++++++++------ 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/mode-key.c b/mode-key.c index 375cb925..1edccbef 100644 --- a/mode-key.c +++ b/mode-key.c @@ -40,7 +40,7 @@ */ /* Edit keys command strings. */ -struct mode_key_cmdstr mode_key_cmdstr_edit[] = { +const struct mode_key_cmdstr mode_key_cmdstr_edit[] = { { MODEKEYEDIT_BACKSPACE, "backspace" }, { MODEKEYEDIT_CANCEL, "cancel" }, { MODEKEYEDIT_COMPLETE, "complete" }, @@ -63,7 +63,7 @@ struct mode_key_cmdstr mode_key_cmdstr_edit[] = { }; /* Choice keys command strings. */ -struct mode_key_cmdstr mode_key_cmdstr_choice[] = { +const struct mode_key_cmdstr mode_key_cmdstr_choice[] = { { MODEKEYCHOICE_CANCEL, "cancel" }, { MODEKEYCHOICE_CHOOSE, "choose" }, { MODEKEYCHOICE_DOWN, "down" }, @@ -77,7 +77,7 @@ struct mode_key_cmdstr mode_key_cmdstr_choice[] = { }; /* Copy keys command strings. */ -struct mode_key_cmdstr mode_key_cmdstr_copy[] = { +const struct mode_key_cmdstr mode_key_cmdstr_copy[] = { { MODEKEYCOPY_BACKTOINDENTATION, "back-to-indentation" }, { MODEKEYCOPY_BOTTOMLINE, "bottom-line" }, { MODEKEYCOPY_CANCEL, "cancel" }, @@ -384,7 +384,7 @@ mode_key_cmp(struct mode_key_binding *mbind1, struct mode_key_binding *mbind2) } const char * -mode_key_tostring(struct mode_key_cmdstr *cmdstr, enum mode_key_cmd cmd) +mode_key_tostring(const struct mode_key_cmdstr *cmdstr, enum mode_key_cmd cmd) { for (; cmdstr->name != NULL; cmdstr++) { if (cmdstr->cmd == cmd) @@ -394,7 +394,7 @@ mode_key_tostring(struct mode_key_cmdstr *cmdstr, enum mode_key_cmd cmd) } enum mode_key_cmd -mode_key_fromstring(struct mode_key_cmdstr *cmdstr, const char *name) +mode_key_fromstring(const struct mode_key_cmdstr *cmdstr, const char *name) { for (; cmdstr->name != NULL; cmdstr++) { if (strcasecmp(cmdstr->name, name) == 0) diff --git a/tmux.h b/tmux.h index fcf14362..116f8d78 100644 --- a/tmux.h +++ b/tmux.h @@ -534,10 +534,10 @@ struct mode_key_cmdstr { /* Named mode key table description. */ struct mode_key_table { - const char *name; - struct mode_key_cmdstr *cmdstr; - struct mode_key_tree *tree; - const struct mode_key_entry *table; /* default entries */ + const char *name; + const struct mode_key_cmdstr *cmdstr; + struct mode_key_tree *tree; + const struct mode_key_entry *table; /* default entries */ }; /* Modes. */ @@ -1329,8 +1329,10 @@ extern struct mode_key_tree mode_key_tree_emacs_choice; extern struct mode_key_tree mode_key_tree_emacs_copy; int mode_key_cmp(struct mode_key_binding *, struct mode_key_binding *); SPLAY_PROTOTYPE(mode_key_tree, mode_key_binding, entry, mode_key_cmp); -const char *mode_key_tostring(struct mode_key_cmdstr *r, enum mode_key_cmd); -enum mode_key_cmd mode_key_fromstring(struct mode_key_cmdstr *, const char *); +const char *mode_key_tostring(const struct mode_key_cmdstr *, + enum mode_key_cmd); +enum mode_key_cmd mode_key_fromstring(const struct mode_key_cmdstr *, + const char *); const struct mode_key_table *mode_key_findtable(const char *); void mode_key_init_trees(void); void mode_key_init(struct mode_key_data *, struct mode_key_tree *); From f833b885a17463658d8d5e814a4b3e269c3678c9 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 1 Jan 2011 03:43:20 +0000 Subject: [PATCH 0823/1180] Last few tables that should be const. --- input-keys.c | 12 ++++++------ key-string.c | 2 +- xterm-keys.c | 14 +++++++------- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/input-keys.c b/input-keys.c index 81976123..ac759684 100644 --- a/input-keys.c +++ b/input-keys.c @@ -40,7 +40,7 @@ struct input_key_ent { #define INPUTKEY_CURSOR 0x2 /* cursor key */ }; -struct input_key_ent input_keys[] = { +const struct input_key_ent input_keys[] = { /* Backspace key. */ { KEYC_BSPACE, "\177", 0 }, @@ -137,11 +137,11 @@ struct input_key_ent input_keys[] = { void input_key(struct window_pane *wp, int key) { - struct input_key_ent *ike; - u_int i; - size_t dlen; - char *out; - u_char ch; + const struct input_key_ent *ike; + u_int i; + size_t dlen; + char *out; + u_char ch; log_debug2("writing key 0x%x", key); diff --git a/key-string.c b/key-string.c index 20240407..2d768aef 100644 --- a/key-string.c +++ b/key-string.c @@ -25,7 +25,7 @@ int key_string_search_table(const char *); int key_string_get_modifiers(const char **); -struct { +const struct { const char *string; int key; } key_string_table[] = { diff --git a/xterm-keys.c b/xterm-keys.c index 5f8db986..1e5583f7 100644 --- a/xterm-keys.c +++ b/xterm-keys.c @@ -48,7 +48,7 @@ struct xterm_keys_entry { const char *template; }; -struct xterm_keys_entry xterm_keys_table[] = { +const struct xterm_keys_entry xterm_keys_table[] = { { KEYC_F1, "\033[1;_P" }, { KEYC_F1, "\033O_P" }, { KEYC_F2, "\033[1;_Q" }, @@ -140,8 +140,8 @@ xterm_keys_modifiers(const char *template, const char *buf, size_t len) int xterm_keys_find(const char *buf, size_t len, size_t *size, int *key) { - struct xterm_keys_entry *entry; - u_int i; + const struct xterm_keys_entry *entry; + u_int i; for (i = 0; i < nitems(xterm_keys_table); i++) { entry = &xterm_keys_table[i]; @@ -162,10 +162,10 @@ xterm_keys_find(const char *buf, size_t len, size_t *size, int *key) char * xterm_keys_lookup(int key) { - struct xterm_keys_entry *entry; - u_int i; - int modifiers; - char *out; + const struct xterm_keys_entry *entry; + u_int i; + int modifiers; + char *out; modifiers = 1; if (key & KEYC_SHIFT) From a4515ce138a7c5f275a7134018cfa28c76612321 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 1 Jan 2011 11:24:45 +0000 Subject: [PATCH 0824/1180] suspend-client has used -t for the client target (like everything else) for ages, fix the usage string and man page and trim some leftover code. --- cmd-suspend-client.c | 7 +------ tmux.1 | 2 +- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/cmd-suspend-client.c b/cmd-suspend-client.c index 5c166c37..b90121a0 100644 --- a/cmd-suspend-client.c +++ b/cmd-suspend-client.c @@ -29,14 +29,9 @@ int cmd_suspend_client_exec(struct cmd *, struct cmd_ctx *); -struct cmd_suspend_client_data { - char *name; - char *target; -}; - const struct cmd_entry cmd_suspend_client_entry = { "suspend-client", "suspendc", - "[-c target-client]", + CMD_TARGET_CLIENT_USAGE, 0, "", cmd_target_init, cmd_target_parse, diff --git a/tmux.1 b/tmux.1 index 3c600520..079c8b8c 100644 --- a/tmux.1 +++ b/tmux.1 @@ -657,7 +657,7 @@ Start the .Nm server, if not already running, without creating any sessions. .It Xo Ic suspend-client -.Op Fl c Ar target-client +.Op Fl t Ar target-client .Xc .D1 (alias: Ic suspendc ) Suspend a client by sending From 3e8124009f6737c656e260b2f5b459b4ebe1a10c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 1 Jan 2011 16:51:21 +0000 Subject: [PATCH 0825/1180] Move the user-visible parts of all options (names, types, limit, default values) together into one set of tables in options-table.c. Also clean up and simplify cmd-set-options.c and move a common print function into option-table.c. --- Makefile | 2 +- cmd-set-option.c | 561 ++++++++++++++------------------------- cmd-show-options.c | 29 +- options-table.c | 639 +++++++++++++++++++++++++++++++++++++++++++++ status.c | 30 +-- tmux.c | 125 ++------- tmux.h | 54 ++-- 7 files changed, 913 insertions(+), 527 deletions(-) create mode 100644 options-table.c diff --git a/Makefile b/Makefile index 532b19e1..86b28b60 100644 --- a/Makefile +++ b/Makefile @@ -32,7 +32,7 @@ SRCS= attributes.c cfg.c client.c clock.c \ colour.c environ.c grid-view.c grid-utf8.c grid.c input-keys.c \ input.c key-bindings.c key-string.c \ layout-custom.c layout-set.c layout-string.c layout.c log.c job.c \ - mode-key.c names.c options.c paste.c procname.c \ + mode-key.c names.c options.c options-table.c paste.c procname.c \ resize.c screen-redraw.c screen-write.c screen.c session.c status.c \ signal.c server-fn.c server.c server-client.c server-window.c \ tmux.c tty-acs.c tty-keys.c tty-term.c tty.c utf8.c \ diff --git a/cmd-set-option.c b/cmd-set-option.c index 81e3cffa..f15ce052 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -29,22 +29,25 @@ int cmd_set_option_exec(struct cmd *, struct cmd_ctx *); -const char *cmd_set_option_print( - const struct set_option_entry *, struct options_entry *); -void cmd_set_option_string(struct cmd_ctx *, - struct options *, const struct set_option_entry *, char *, int); -void cmd_set_option_number(struct cmd_ctx *, - struct options *, const struct set_option_entry *, char *); -void cmd_set_option_keys(struct cmd_ctx *, - struct options *, const struct set_option_entry *, char *); -void cmd_set_option_colour(struct cmd_ctx *, - struct options *, const struct set_option_entry *, char *); -void cmd_set_option_attributes(struct cmd_ctx *, - struct options *, const struct set_option_entry *, char *); -void cmd_set_option_flag(struct cmd_ctx *, - struct options *, const struct set_option_entry *, char *); -void cmd_set_option_choice(struct cmd_ctx *, - struct options *, const struct set_option_entry *, char *); +int cmd_set_option_unset(struct cmd *, struct cmd_ctx *, + const struct options_table_entry *, struct options *); +int cmd_set_option_set(struct cmd *, struct cmd_ctx *, + const struct options_table_entry *, struct options *); + +struct options_entry *cmd_set_option_string(struct cmd *, struct cmd_ctx *, + const struct options_table_entry *, struct options *); +struct options_entry *cmd_set_option_number(struct cmd *, struct cmd_ctx *, + const struct options_table_entry *, struct options *); +struct options_entry *cmd_set_option_keys(struct cmd *, struct cmd_ctx *, + const struct options_table_entry *, struct options *); +struct options_entry *cmd_set_option_colour(struct cmd *, struct cmd_ctx *, + const struct options_table_entry *, struct options *); +struct options_entry *cmd_set_option_attributes(struct cmd *, struct cmd_ctx *, + const struct options_table_entry *, struct options *); +struct options_entry *cmd_set_option_flag(struct cmd *, struct cmd_ctx *, + const struct options_table_entry *, struct options *); +struct options_entry *cmd_set_option_choice(struct cmd *, struct cmd_ctx *, + const struct options_table_entry *, struct options *); const struct cmd_entry cmd_set_option_entry = { "set-option", "set", @@ -57,149 +60,26 @@ const struct cmd_entry cmd_set_option_entry = { cmd_target_print }; -const char *set_option_mode_keys_list[] = { - "emacs", "vi", NULL -}; -const char *set_option_clock_mode_style_list[] = { - "12", "24", NULL -}; -const char *set_option_status_keys_list[] = { - "emacs", "vi", NULL -}; -const char *set_option_status_justify_list[] = { - "left", "centre", "right", NULL -}; -const char *set_option_bell_action_list[] = { - "none", "any", "current", NULL -}; - -const struct set_option_entry set_option_table[] = { - { "buffer-limit", SET_OPTION_NUMBER, 1, INT_MAX, NULL }, - { "escape-time", SET_OPTION_NUMBER, 0, INT_MAX, NULL }, - { "exit-unattached", SET_OPTION_FLAG, 0, 0, NULL }, - { "quiet", SET_OPTION_FLAG, 0, 0, NULL }, - { NULL, 0, 0, 0, NULL } -}; - -const struct set_option_entry set_session_option_table[] = { - { "base-index", SET_OPTION_NUMBER, 0, INT_MAX, NULL }, - { "bell-action", SET_OPTION_CHOICE, 0, 0, set_option_bell_action_list }, - { "default-command", SET_OPTION_STRING, 0, 0, NULL }, - { "default-path", SET_OPTION_STRING, 0, 0, NULL }, - { "default-shell", SET_OPTION_STRING, 0, 0, NULL }, - { "default-terminal", SET_OPTION_STRING, 0, 0, NULL }, - { "destroy-unattached", SET_OPTION_FLAG, 0, 0, NULL }, - { "detach-on-destroy", SET_OPTION_FLAG, 0, 0, NULL }, - { "display-panes-active-colour", SET_OPTION_COLOUR, 0, 0, NULL }, - { "display-panes-colour", SET_OPTION_COLOUR, 0, 0, NULL }, - { "display-panes-time", SET_OPTION_NUMBER, 1, INT_MAX, NULL }, - { "display-time", SET_OPTION_NUMBER, 1, INT_MAX, NULL }, - { "history-limit", SET_OPTION_NUMBER, 0, INT_MAX, NULL }, - { "lock-after-time", SET_OPTION_NUMBER, 0, INT_MAX, NULL }, - { "lock-command", SET_OPTION_STRING, 0, 0, NULL }, - { "lock-server", SET_OPTION_FLAG, 0, 0, NULL }, - { "message-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL }, - { "message-bg", SET_OPTION_COLOUR, 0, 0, NULL }, - { "message-fg", SET_OPTION_COLOUR, 0, 0, NULL }, - { "message-limit", SET_OPTION_NUMBER, 0, INT_MAX, NULL }, - { "mouse-select-pane", SET_OPTION_FLAG, 0, 0, NULL }, - { "pane-active-border-bg", SET_OPTION_COLOUR, 0, 0, NULL }, - { "pane-active-border-fg", SET_OPTION_COLOUR, 0, 0, NULL }, - { "pane-border-bg", SET_OPTION_COLOUR, 0, 0, NULL }, - { "pane-border-fg", SET_OPTION_COLOUR, 0, 0, NULL }, - { "prefix", SET_OPTION_KEYS, 0, 0, NULL }, - { "repeat-time", SET_OPTION_NUMBER, 0, SHRT_MAX, NULL }, - { "set-remain-on-exit", SET_OPTION_FLAG, 0, 0, NULL }, - { "set-titles", SET_OPTION_FLAG, 0, 0, NULL }, - { "set-titles-string", SET_OPTION_STRING, 0, 0, NULL }, - { "status", SET_OPTION_FLAG, 0, 0, NULL }, - { "status-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL }, - { "status-bg", SET_OPTION_COLOUR, 0, 0, NULL }, - { "status-fg", SET_OPTION_COLOUR, 0, 0, NULL }, - { "status-interval", SET_OPTION_NUMBER, 0, INT_MAX, NULL }, - { "status-justify", - SET_OPTION_CHOICE, 0, 0, set_option_status_justify_list }, - { "status-keys", SET_OPTION_CHOICE, 0, 0, set_option_status_keys_list }, - { "status-left", SET_OPTION_STRING, 0, 0, NULL }, - { "status-left-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL }, - { "status-left-bg", SET_OPTION_COLOUR, 0, 0, NULL }, - { "status-left-fg", SET_OPTION_COLOUR, 0, 0, NULL }, - { "status-left-length", SET_OPTION_NUMBER, 0, SHRT_MAX, NULL }, - { "status-right", SET_OPTION_STRING, 0, 0, NULL }, - { "status-right-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL }, - { "status-right-bg", SET_OPTION_COLOUR, 0, 0, NULL }, - { "status-right-fg", SET_OPTION_COLOUR, 0, 0, NULL }, - { "status-right-length", SET_OPTION_NUMBER, 0, SHRT_MAX, NULL }, - { "status-utf8", SET_OPTION_FLAG, 0, 0, NULL }, - { "terminal-overrides", SET_OPTION_STRING, 0, 0, NULL }, - { "update-environment", SET_OPTION_STRING, 0, 0, NULL }, - { "visual-activity", SET_OPTION_FLAG, 0, 0, NULL }, - { "visual-bell", SET_OPTION_FLAG, 0, 0, NULL }, - { "visual-content", SET_OPTION_FLAG, 0, 0, NULL }, - { "visual-silence", SET_OPTION_FLAG, 0, 0, NULL }, - { NULL, 0, 0, 0, NULL } -}; - -const struct set_option_entry set_window_option_table[] = { - { "aggressive-resize", SET_OPTION_FLAG, 0, 0, NULL }, - { "alternate-screen", SET_OPTION_FLAG, 0, 0, NULL }, - { "automatic-rename", SET_OPTION_FLAG, 0, 0, NULL }, - { "clock-mode-colour", SET_OPTION_COLOUR, 0, 0, NULL }, - { "clock-mode-style", - SET_OPTION_CHOICE, 0, 0, set_option_clock_mode_style_list }, - { "force-height", SET_OPTION_NUMBER, 0, INT_MAX, NULL }, - { "force-width", SET_OPTION_NUMBER, 0, INT_MAX, NULL }, - { "main-pane-height", SET_OPTION_NUMBER, 1, INT_MAX, NULL }, - { "main-pane-width", SET_OPTION_NUMBER, 1, INT_MAX, NULL }, - { "mode-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL }, - { "mode-bg", SET_OPTION_COLOUR, 0, 0, NULL }, - { "mode-fg", SET_OPTION_COLOUR, 0, 0, NULL }, - { "mode-keys", SET_OPTION_CHOICE, 0, 0, set_option_mode_keys_list }, - { "mode-mouse", SET_OPTION_FLAG, 0, 0, NULL }, - { "monitor-activity", SET_OPTION_FLAG, 0, 0, NULL }, - { "monitor-content", SET_OPTION_STRING, 0, 0, NULL }, - { "monitor-silence",SET_OPTION_NUMBER, 0, INT_MAX, NULL}, - { "other-pane-height", SET_OPTION_NUMBER, 0, INT_MAX, NULL }, - { "other-pane-width", SET_OPTION_NUMBER, 0, INT_MAX, NULL }, - { "remain-on-exit", SET_OPTION_FLAG, 0, 0, NULL }, - { "synchronize-panes", SET_OPTION_FLAG, 0, 0, NULL }, - { "utf8", SET_OPTION_FLAG, 0, 0, NULL }, - { "window-status-alert-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL }, - { "window-status-alert-bg", SET_OPTION_COLOUR, 0, 0, NULL }, - { "window-status-alert-fg", SET_OPTION_COLOUR, 0, 0, NULL }, - { "window-status-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL }, - { "window-status-bg", SET_OPTION_COLOUR, 0, 0, NULL }, - { "window-status-current-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL }, - { "window-status-current-bg", SET_OPTION_COLOUR, 0, 0, NULL }, - { "window-status-current-fg", SET_OPTION_COLOUR, 0, 0, NULL }, - { "window-status-current-format", SET_OPTION_STRING, 0, 0, NULL }, - { "window-status-fg", SET_OPTION_COLOUR, 0, 0, NULL }, - { "window-status-format", SET_OPTION_STRING, 0, 0, NULL }, - { "word-separators", SET_OPTION_STRING, 0, 0, NULL }, - { "xterm-keys", SET_OPTION_FLAG, 0, 0, NULL }, - { NULL, 0, 0, 0, NULL } -}; - int cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; - const struct set_option_entry *table; - struct session *s; - struct winlink *wl; - struct client *c; - struct options *oo; - const struct set_option_entry *entry, *opt; - struct jobs *jobs; - struct job *job, *nextjob; - u_int i; - int try_again; + struct cmd_target_data *data = self->data; + const struct options_table_entry *table, *oe, *oe_loop; + struct session *s; + struct winlink *wl; + struct client *c; + struct options *oo; + struct jobs *jobs; + struct job *job, *nextjob; + u_int i; + int try_again; + /* Work out the options tree and table to use. */ if (cmd_check_flag(data->chflags, 's')) { oo = &global_options; - table = set_option_table; + table = server_options_table; } else if (cmd_check_flag(data->chflags, 'w')) { - table = set_window_option_table; + table = window_options_table; if (cmd_check_flag(data->chflags, 'g')) oo = &global_w_options; else { @@ -209,7 +89,7 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) oo = &wl->window->options; } } else { - table = set_session_option_table; + table = session_options_table; if (cmd_check_flag(data->chflags, 'g')) oo = &global_s_options; else { @@ -220,71 +100,36 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) } } - if (*data->arg == '\0') { - ctx->error(ctx, "invalid option"); - return (-1); - } - - entry = NULL; - for (opt = table; opt->name != NULL; opt++) { - if (strncmp(opt->name, data->arg, strlen(data->arg)) != 0) + /* Find the option table entry. */ + oe = NULL; + for (oe_loop = table; oe_loop->name != NULL; oe_loop++) { + if (strncmp(oe_loop->name, data->arg, strlen(data->arg)) != 0) continue; - if (entry != NULL) { + if (oe != NULL) { ctx->error(ctx, "ambiguous option: %s", data->arg); return (-1); } - entry = opt; + oe = oe_loop; /* Bail now if an exact match. */ - if (strcmp(entry->name, data->arg) == 0) + if (strcmp(oe->name, data->arg) == 0) break; } - if (entry == NULL) { + if (oe == NULL) { ctx->error(ctx, "unknown option: %s", data->arg); return (-1); } + /* Unset or set the option. */ if (cmd_check_flag(data->chflags, 'u')) { - if (cmd_check_flag(data->chflags, 'g')) { - ctx->error(ctx, - "can't unset global option: %s", entry->name); + if (cmd_set_option_unset(self, ctx, oe, oo) != 0) return (-1); - } - if (data->arg2 != NULL) { - ctx->error(ctx, - "value passed to unset option: %s", entry->name); - return (-1); - } - - options_remove(oo, entry->name); - ctx->info(ctx, "unset option: %s", entry->name); } else { - switch (entry->type) { - case SET_OPTION_STRING: - cmd_set_option_string(ctx, oo, entry, - data->arg2, cmd_check_flag(data->chflags, 'a')); - break; - case SET_OPTION_NUMBER: - cmd_set_option_number(ctx, oo, entry, data->arg2); - break; - case SET_OPTION_KEYS: - cmd_set_option_keys(ctx, oo, entry, data->arg2); - break; - case SET_OPTION_COLOUR: - cmd_set_option_colour(ctx, oo, entry, data->arg2); - break; - case SET_OPTION_ATTRIBUTES: - cmd_set_option_attributes(ctx, oo, entry, data->arg2); - break; - case SET_OPTION_FLAG: - cmd_set_option_flag(ctx, oo, entry, data->arg2); - break; - case SET_OPTION_CHOICE: - cmd_set_option_choice(ctx, oo, entry, data->arg2); - break; - } + if (cmd_set_option_set(self, ctx, oe, oo) != 0) + return (-1); } + /* Update sizes and redraw. May not need it but meh. */ recalculate_sizes(); for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); @@ -297,11 +142,11 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) * or set-titles-string have changed. Persistent jobs are only used by * the status line at the moment so this works XXX. */ - if (strcmp(entry->name, "status-left") == 0 || - strcmp(entry->name, "status-right") == 0 || - strcmp(entry->name, "status") == 0 || - strcmp(entry->name, "set-titles-string") == 0 || - strcmp(entry->name, "window-status-format") == 0) { + if (strcmp(oe->name, "status-left") == 0 || + strcmp(oe->name, "status-right") == 0 || + strcmp(oe->name, "status") == 0 || + strcmp(oe->name, "set-titles-string") == 0 || + strcmp(oe->name, "window-status-format") == 0) { for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); if (c == NULL || c->session == NULL) @@ -328,242 +173,226 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) return (0); } -const char * -cmd_set_option_print( - const struct set_option_entry *entry, struct options_entry *o) +/* Unset an option. */ +int +cmd_set_option_unset(struct cmd *self, struct cmd_ctx *ctx, + const struct options_table_entry *oe, struct options *oo) { - static char out[BUFSIZ]; - const char *s; - struct keylist *keylist; - u_int i; + struct cmd_target_data *data = self->data; - *out = '\0'; - switch (entry->type) { - case SET_OPTION_STRING: - xsnprintf(out, sizeof out, "\"%s\"", o->str); - break; - case SET_OPTION_NUMBER: - xsnprintf(out, sizeof out, "%lld", o->num); - break; - case SET_OPTION_KEYS: - keylist = o->data; - for (i = 0; i < ARRAY_LENGTH(keylist); i++) { - strlcat(out, key_string_lookup_key( - ARRAY_ITEM(keylist, i)), sizeof out); - if (i != ARRAY_LENGTH(keylist) - 1) - strlcat(out, ",", sizeof out); - } - break; - case SET_OPTION_COLOUR: - s = colour_tostring(o->num); - xsnprintf(out, sizeof out, "%s", s); - break; - case SET_OPTION_ATTRIBUTES: - s = attributes_tostring(o->num); - xsnprintf(out, sizeof out, "%s", s); - break; - case SET_OPTION_FLAG: - if (o->num) - strlcpy(out, "on", sizeof out); - else - strlcpy(out, "off", sizeof out); - break; - case SET_OPTION_CHOICE: - s = entry->choices[o->num]; - xsnprintf(out, sizeof out, "%s", s); - break; + if (cmd_check_flag(data->chflags, 'g')) { + ctx->error(ctx, "can't unset global option: %s", oe->name); + return (-1); } - return (out); + if (data->arg2 != NULL) { + ctx->error(ctx, "value passed to unset option: %s", oe->name); + return (-1); + } + + options_remove(oo, oe->name); + ctx->info(ctx, "unset option: %s", oe->name); + return (0); } -void -cmd_set_option_string(struct cmd_ctx *ctx, struct options *oo, - const struct set_option_entry *entry, char *value, int append) +/* Set an option. */ +int +cmd_set_option_set(struct cmd *self, struct cmd_ctx *ctx, + const struct options_table_entry *oe, struct options *oo) { + struct cmd_target_data *data = self->data; struct options_entry *o; - char *oldvalue, *newvalue; + const char *s; - if (value == NULL) { - ctx->error(ctx, "empty value"); - return; + if (oe->type != OPTIONS_TABLE_FLAG && data->arg2 == NULL) { + ctx->error(ctx, "empty data->arg2"); + return (-1); } - if (append) { - oldvalue = options_get_string(oo, entry->name); - xasprintf(&newvalue, "%s%s", oldvalue, value); + o = NULL; + switch (oe->type) { + case OPTIONS_TABLE_STRING: + o = cmd_set_option_string(self, ctx, oe, oo); + break; + case OPTIONS_TABLE_NUMBER: + o = cmd_set_option_number(self, ctx, oe, oo); + break; + case OPTIONS_TABLE_KEYS: + o = cmd_set_option_keys(self, ctx, oe, oo); + break; + case OPTIONS_TABLE_COLOUR: + o = cmd_set_option_colour(self, ctx, oe, oo); + break; + case OPTIONS_TABLE_ATTRIBUTES: + o = cmd_set_option_attributes(self, ctx, oe, oo); + break; + case OPTIONS_TABLE_FLAG: + o = cmd_set_option_flag(self, ctx, oe, oo); + break; + case OPTIONS_TABLE_CHOICE: + o = cmd_set_option_choice(self, ctx, oe, oo); + break; + } + if (o == NULL) + return (-1); + + s = options_table_print_entry(oe, o); + ctx->info(ctx, "set option: %s -> %s", oe->name, s); + return (0); +} + +/* Set a string option. */ +struct options_entry * +cmd_set_option_string(struct cmd *self, unused struct cmd_ctx *ctx, + const struct options_table_entry *oe, struct options *oo) +{ + struct cmd_target_data *data = self->data; + struct options_entry *o; + char *oldval, *newval; + + if (cmd_check_flag(data->chflags, 'a')) { + oldval = options_get_string(oo, oe->name); + xasprintf(&newval, "%s%s", oldval, data->arg2); } else - newvalue = value; + newval = data->arg2; - o = options_set_string(oo, entry->name, "%s", newvalue); - ctx->info(ctx, - "set option: %s -> %s", o->name, cmd_set_option_print(entry, o)); + o = options_set_string(oo, oe->name, "%s", newval); - if (newvalue != value) - xfree(newvalue); + if (newval != data->arg2) + xfree(newval); + return (o); } -void -cmd_set_option_number(struct cmd_ctx *ctx, struct options *oo, - const struct set_option_entry *entry, char *value) +/* Set a number option. */ +struct options_entry * +cmd_set_option_number(struct cmd *self, struct cmd_ctx *ctx, + const struct options_table_entry *oe, struct options *oo) { - struct options_entry *o; - long long number; + struct cmd_target_data *data = self->data; + long long ll; const char *errstr; - if (value == NULL) { - ctx->error(ctx, "empty value"); - return; - } - - number = strtonum(value, entry->minimum, entry->maximum, &errstr); + ll = strtonum(data->arg2, oe->minimum, oe->maximum, &errstr); if (errstr != NULL) { - ctx->error(ctx, "value is %s: %s", errstr, value); - return; + ctx->error(ctx, "value is %s: %s", errstr, data->arg2); + return (NULL); } - o = options_set_number(oo, entry->name, number); - ctx->info(ctx, - "set option: %s -> %s", o->name, cmd_set_option_print(entry, o)); + return (options_set_number(oo, oe->name, ll)); } -void -cmd_set_option_keys(struct cmd_ctx *ctx, struct options *oo, - const struct set_option_entry *entry, char *value) +/* Set a keys option. */ +struct options_entry * +cmd_set_option_keys(struct cmd *self, struct cmd_ctx *ctx, + const struct options_table_entry *oe, struct options *oo) { - struct options_entry *o; + struct cmd_target_data *data = self->data; struct keylist *keylist; - char *copyvalue, *ptr, *str; + char *copy, *ptr, *s; int key; - if (value == NULL) { - ctx->error(ctx, "empty value"); - return; - } - keylist = xmalloc(sizeof *keylist); ARRAY_INIT(keylist); - ptr = copyvalue = xstrdup(value); - while ((str = strsep(&ptr, ",")) != NULL) { - if ((key = key_string_lookup_string(str)) == KEYC_NONE) { + ptr = copy = xstrdup(data->arg2); + while ((s = strsep(&ptr, ",")) != NULL) { + if ((key = key_string_lookup_string(s)) == KEYC_NONE) { + ctx->error(ctx, "unknown key: %s", s); + xfree(copy); xfree(keylist); - ctx->error(ctx, "unknown key: %s", str); - xfree(copyvalue); - return; + return (NULL); } ARRAY_ADD(keylist, key); } - xfree(copyvalue); + xfree(copy); - o = options_set_data(oo, entry->name, keylist, xfree); - ctx->info(ctx, - "set option: %s -> %s", o->name, cmd_set_option_print(entry, o)); + return (options_set_data(oo, oe->name, keylist, xfree)); } -void -cmd_set_option_colour(struct cmd_ctx *ctx, struct options *oo, - const struct set_option_entry *entry, char *value) +/* Set a colour option. */ +struct options_entry * +cmd_set_option_colour(struct cmd *self, struct cmd_ctx *ctx, + const struct options_table_entry *oe, struct options *oo) { - struct options_entry *o; + struct cmd_target_data *data = self->data; int colour; - if (value == NULL) { - ctx->error(ctx, "empty value"); - return; + if ((colour = colour_fromstring(data->arg2)) == -1) { + ctx->error(ctx, "bad colour: %s", data->arg2); + return (NULL); } - if ((colour = colour_fromstring(value)) == -1) { - ctx->error(ctx, "bad colour: %s", value); - return; - } - - o = options_set_number(oo, entry->name, colour); - ctx->info(ctx, - "set option: %s -> %s", o->name, cmd_set_option_print(entry, o)); + return (options_set_number(oo, oe->name, colour)); } -void -cmd_set_option_attributes(struct cmd_ctx *ctx, struct options *oo, - const struct set_option_entry *entry, char *value) +/* Set an attributes option. */ +struct options_entry * +cmd_set_option_attributes(struct cmd *self, struct cmd_ctx *ctx, + const struct options_table_entry *oe, struct options *oo) { - struct options_entry *o; + struct cmd_target_data *data = self->data; int attr; - if (value == NULL) { - ctx->error(ctx, "empty value"); - return; + if ((attr = attributes_fromstring(data->arg2)) == -1) { + ctx->error(ctx, "bad attributes: %s", data->arg2); + return (NULL); } - if ((attr = attributes_fromstring(value)) == -1) { - ctx->error(ctx, "bad attributes: %s", value); - return; - } - - o = options_set_number(oo, entry->name, attr); - ctx->info(ctx, - "set option: %s -> %s", o->name, cmd_set_option_print(entry, o)); + return (options_set_number(oo, oe->name, attr)); } -void -cmd_set_option_flag(struct cmd_ctx *ctx, struct options *oo, - const struct set_option_entry *entry, char *value) +/* Set a flag option. */ +struct options_entry * +cmd_set_option_flag(struct cmd *self, struct cmd_ctx *ctx, + const struct options_table_entry *oe, struct options *oo) { - struct options_entry *o; + struct cmd_target_data *data = self->data; int flag; - if (value == NULL || *value == '\0') - flag = !options_get_number(oo, entry->name); + if (data->arg2 == NULL || *data->arg2 == '\0') + flag = !options_get_number(oo, oe->name); else { - if ((value[0] == '1' && value[1] == '\0') || - strcasecmp(value, "on") == 0 || - strcasecmp(value, "yes") == 0) + if ((data->arg2[0] == '1' && data->arg2[1] == '\0') || + strcasecmp(data->arg2, "on") == 0 || + strcasecmp(data->arg2, "yes") == 0) flag = 1; - else if ((value[0] == '0' && value[1] == '\0') || - strcasecmp(value, "off") == 0 || - strcasecmp(value, "no") == 0) + else if ((data->arg2[0] == '0' && data->arg2[1] == '\0') || + strcasecmp(data->arg2, "off") == 0 || + strcasecmp(data->arg2, "no") == 0) flag = 0; else { - ctx->error(ctx, "bad value: %s", value); - return; + ctx->error(ctx, "bad value: %s", data->arg2); + return (NULL); } } - o = options_set_number(oo, entry->name, flag); - ctx->info(ctx, - "set option: %s -> %s", o->name, cmd_set_option_print(entry, o)); + return (options_set_number(oo, oe->name, flag)); } -void -cmd_set_option_choice(struct cmd_ctx *ctx, struct options *oo, - const struct set_option_entry *entry, char *value) +/* Set a choice option. */ +struct options_entry * +cmd_set_option_choice(struct cmd *self, struct cmd_ctx *ctx, + const struct options_table_entry *oe, struct options *oo) { - struct options_entry *o; + struct cmd_target_data *data = self->data; const char **choicep; int n, choice = -1; - if (value == NULL) { - ctx->error(ctx, "empty value"); - return; - } - n = 0; - for (choicep = entry->choices; *choicep != NULL; choicep++) { + for (choicep = oe->choices; *choicep != NULL; choicep++) { n++; - if (strncmp(*choicep, value, strlen(value)) != 0) + if (strncmp(*choicep, data->arg2, strlen(data->arg2)) != 0) continue; if (choice != -1) { - ctx->error(ctx, "ambiguous option value: %s", value); - return; + ctx->error(ctx, "ambiguous value: %s", data->arg2); + return (NULL); } choice = n - 1; } if (choice == -1) { - ctx->error(ctx, "unknown option value: %s", value); - return; + ctx->error(ctx, "unknown value: %s", data->arg2); + return (NULL); } - o = options_set_number(oo, entry->name, choice); - ctx->info(ctx, - "set option: %s -> %s", o->name, cmd_set_option_print(entry, o)); + return (options_set_number(oo, oe->name, choice)); } diff --git a/cmd-show-options.c b/cmd-show-options.c index 23838e4c..02ca91e3 100644 --- a/cmd-show-options.c +++ b/cmd-show-options.c @@ -43,20 +43,19 @@ const struct cmd_entry cmd_show_options_entry = { int cmd_show_options_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; - const struct set_option_entry *table; - struct session *s; - struct winlink *wl; - struct options *oo; - struct options_entry *o; - const struct set_option_entry *entry; - const char *optval; + struct cmd_target_data *data = self->data; + const struct options_table_entry *table, *oe; + struct session *s; + struct winlink *wl; + struct options *oo; + struct options_entry *o; + const char *optval; if (cmd_check_flag(data->chflags, 's')) { oo = &global_options; - table = set_option_table; + table = server_options_table; } else if (cmd_check_flag(data->chflags, 'w')) { - table = set_window_option_table; + table = window_options_table; if (cmd_check_flag(data->chflags, 'g')) oo = &global_w_options; else { @@ -66,7 +65,7 @@ cmd_show_options_exec(struct cmd *self, struct cmd_ctx *ctx) oo = &wl->window->options; } } else { - table = set_session_option_table; + table = session_options_table; if (cmd_check_flag(data->chflags, 'g')) oo = &global_s_options; else { @@ -77,11 +76,11 @@ cmd_show_options_exec(struct cmd *self, struct cmd_ctx *ctx) } } - for (entry = table; entry->name != NULL; entry++) { - if ((o = options_find1(oo, entry->name)) == NULL) + for (oe = table; oe->name != NULL; oe++) { + if ((o = options_find1(oo, oe->name)) == NULL) continue; - optval = cmd_set_option_print(entry, o); - ctx->print(ctx, "%s %s", entry->name, optval); + optval = options_table_print_entry(oe, o); + ctx->print(ctx, "%s %s", oe->name, optval); } return (0); diff --git a/options-table.c b/options-table.c new file mode 100644 index 00000000..56cb24e5 --- /dev/null +++ b/options-table.c @@ -0,0 +1,639 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2011 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 "tmux.h" + +/* + * This file has a tables with all the server, session and window + * options. These tables are the master copy of the options with their real + * (user-visible) types, range limits and default values. At start these are + * copied into the runtime global options trees (which only has number and + * string types). These tables are then used to loop up the real type when + * the user sets an option or its value needs to be shown. + */ + +/* Choice option type lists. */ +const char *options_table_mode_keys_list[] = { + "emacs", "vi", NULL +}; +const char *options_table_clock_mode_style_list[] = { + "12", "24", NULL +}; +const char *options_table_status_keys_list[] = { + "emacs", "vi", NULL +}; +const char *options_table_status_justify_list[] = { + "left", "centre", "right", NULL +}; +const char *options_table_bell_action_list[] = { + "none", "any", "current", NULL +}; + +/* Server options. */ +const struct options_table_entry server_options_table[] = { + { .name = "buffer-limit", + .type = OPTIONS_TABLE_NUMBER, + .minimum = 1, + .maximum = INT_MAX, + .default_num = 9 + }, + + { .name = "escape-time", + .type = OPTIONS_TABLE_NUMBER, + .minimum = 0, + .maximum = INT_MAX, + .default_num = 500 + }, + + { .name = "exit-unattached", + .type = OPTIONS_TABLE_FLAG, + .default_num = 0 + }, + + { .name = "quiet", + .type = OPTIONS_TABLE_FLAG, + .default_num = 0 /* overridden in main() */ + }, + + { .name = NULL } +}; + +/* Session options. */ +const struct options_table_entry session_options_table[] = { + { .name = "base-index", + .type = OPTIONS_TABLE_NUMBER, + .minimum = 0, + .maximum = INT_MAX, + .default_num = 0 + }, + + { .name = "bell-action", + .type = OPTIONS_TABLE_CHOICE, + .choices = options_table_bell_action_list, + .default_num = BELL_ANY + }, + + { .name = "default-command", + .type = OPTIONS_TABLE_STRING, + .default_str = "" + }, + + { .name = "default-path", + .type = OPTIONS_TABLE_STRING, + .default_str = "" + }, + + { .name = "default-shell", + .type = OPTIONS_TABLE_STRING, + .default_str = _PATH_BSHELL + }, + + { .name = "default-terminal", + .type = OPTIONS_TABLE_STRING, + .default_str = "screen" + }, + + { .name = "destroy-unattached", + .type = OPTIONS_TABLE_FLAG, + .default_num = 0 + }, + + { .name = "detach-on-destroy", + .type = OPTIONS_TABLE_FLAG, + .default_num = 1 + }, + + { .name = "display-panes-active-colour", + .type = OPTIONS_TABLE_COLOUR, + .default_num = 1 + }, + + { .name = "display-panes-colour", + .type = OPTIONS_TABLE_COLOUR, + .default_num = 4 + }, + + { .name = "display-panes-time", + .type = OPTIONS_TABLE_NUMBER, + .minimum = 1, + .maximum = INT_MAX, + .default_num = 1000 + }, + + { .name = "display-time", + .type = OPTIONS_TABLE_NUMBER, + .minimum = 1, + .maximum = INT_MAX, + .default_num = 750 + }, + + { .name = "history-limit", + .type = OPTIONS_TABLE_NUMBER, + .minimum = 0, + .maximum = SHRT_MAX, + .default_num = 2000 + }, + + { .name = "lock-after-time", + .type = OPTIONS_TABLE_NUMBER, + .minimum = 0, + .maximum = INT_MAX, + .default_num = 0 + }, + + { .name = "lock-command", + .type = OPTIONS_TABLE_STRING, + .default_str = "lock -np" + }, + + { .name = "lock-server", + .type = OPTIONS_TABLE_FLAG, + .default_num = 1 + }, + + { .name = "message-attr", + .type = OPTIONS_TABLE_ATTRIBUTES, + .default_num = 0 + }, + + { .name = "message-bg", + .type = OPTIONS_TABLE_COLOUR, + .default_num = 3 + }, + + { .name = "message-fg", + .type = OPTIONS_TABLE_COLOUR, + .default_num = 0 + }, + + { .name = "message-limit", + .type = OPTIONS_TABLE_NUMBER, + .minimum = 0, + .maximum = INT_MAX, + .default_num = 20 + }, + + { .name = "mouse-select-pane", + .type = OPTIONS_TABLE_FLAG, + .default_num = 0 + }, + + { .name = "pane-active-border-bg", + .type = OPTIONS_TABLE_COLOUR, + .default_num = 8 + }, + + { .name = "pane-active-border-fg", + .type = OPTIONS_TABLE_COLOUR, + .default_num = 2 + }, + + { .name = "pane-border-bg", + .type = OPTIONS_TABLE_COLOUR, + .default_num = 8 + }, + + { .name = "pane-border-fg", + .type = OPTIONS_TABLE_COLOUR, + .default_num = 8 + }, + + { .name = "prefix", + .type = OPTIONS_TABLE_KEYS, + /* set in main() */ + }, + + { .name = "repeat-time", + .type = OPTIONS_TABLE_NUMBER, + .minimum = 0, + .maximum = SHRT_MAX, + .default_num = 500 + }, + + { .name = "set-remain-on-exit", + .type = OPTIONS_TABLE_FLAG, + .default_num = 0 + }, + + { .name = "set-titles", + .type = OPTIONS_TABLE_FLAG, + .default_num = 0 + }, + + { .name = "set-titles-string", + .type = OPTIONS_TABLE_STRING, + .default_str = "#S:#I:#W - \"#T\"" + }, + + { .name = "status", + .type = OPTIONS_TABLE_FLAG, + .default_num = 1 + }, + + { .name = "status-attr", + .type = OPTIONS_TABLE_ATTRIBUTES, + .default_num = 0 + }, + + { .name = "status-bg", + .type = OPTIONS_TABLE_COLOUR, + .default_num = 2 + }, + + { .name = "status-fg", + .type = OPTIONS_TABLE_COLOUR, + .default_num = 0 + }, + + { .name = "status-interval", + .type = OPTIONS_TABLE_NUMBER, + .minimum = 0, + .maximum = INT_MAX, + .default_num = 15 + }, + + { .name = "status-justify", + .type = OPTIONS_TABLE_CHOICE, + .choices = options_table_status_justify_list, + .default_num = 0 + }, + + { .name = "status-keys", + .type = OPTIONS_TABLE_CHOICE, + .choices = options_table_status_keys_list, + .default_num = MODEKEY_EMACS + }, + + { .name = "status-left", + .type = OPTIONS_TABLE_STRING, + .default_str = "[#S]" + }, + + { .name = "status-left-attr", + .type = OPTIONS_TABLE_ATTRIBUTES, + .default_num = 0 + }, + + { .name = "status-left-bg", + .type = OPTIONS_TABLE_COLOUR, + .default_num = 8 + }, + + { .name = "status-left-fg", + .type = OPTIONS_TABLE_COLOUR, + .default_num = 8 + }, + + { .name = "status-left-length", + .type = OPTIONS_TABLE_NUMBER, + .minimum = 0, + .maximum = SHRT_MAX, + .default_num = 10 + }, + + { .name = "status-right", + .type = OPTIONS_TABLE_STRING, + .default_str = "\"#22T\" %H:%M %d-%b-%y" + }, + + { .name = "status-right-attr", + .type = OPTIONS_TABLE_ATTRIBUTES, + .default_num = 0 + }, + + { .name = "status-right-bg", + .type = OPTIONS_TABLE_COLOUR, + .default_num = 8 + }, + + { .name = "status-right-fg", + .type = OPTIONS_TABLE_COLOUR, + .default_num = 8 + }, + + { .name = "status-right-length", + .type = OPTIONS_TABLE_NUMBER, + .minimum = 0, + .maximum = SHRT_MAX, + .default_num = 40 + }, + + { .name = "status-utf8", + .type = OPTIONS_TABLE_FLAG, + .default_num = 0 /* overridden in main() */ + }, + + { .name = "terminal-overrides", + .type = OPTIONS_TABLE_STRING, + .default_str = "*88col*:colors=88,*256col*:colors=256" + }, + + { .name = "update-environment", + .type = OPTIONS_TABLE_STRING, + .default_str = "DISPLAY SSH_ASKPASS SSH_AUTH_SOCK SSH_AGENT_PID " + "SSH_CONNECTION WINDOWID XAUTHORITY" + + }, + + { .name = "visual-activity", + .type = OPTIONS_TABLE_FLAG, + .default_num = 0 + }, + + { .name = "visual-bell", + .type = OPTIONS_TABLE_FLAG, + .default_num = 0 + }, + + { .name = "visual-content", + .type = OPTIONS_TABLE_FLAG, + .default_num = 0 + }, + + { .name = "visual-silence", + .type = OPTIONS_TABLE_FLAG, + .default_num = 0 + }, + + { .name = NULL } +}; + +/* Window options. */ +const struct options_table_entry window_options_table[] = { + { .name = "aggressive-resize", + .type = OPTIONS_TABLE_FLAG, + .default_num = 0 + }, + + { .name = "alternate-screen", + .type = OPTIONS_TABLE_FLAG, + .default_num = 1 + }, + + { .name = "automatic-rename", + .type = OPTIONS_TABLE_FLAG, + .default_num = 1 + }, + + { .name = "clock-mode-colour", + .type = OPTIONS_TABLE_COLOUR, + .default_num = 4 + }, + + { .name = "clock-mode-style", + .type = OPTIONS_TABLE_CHOICE, + .choices = options_table_clock_mode_style_list, + .default_num = 1 + }, + + { .name = "force-height", + .type = OPTIONS_TABLE_NUMBER, + .minimum = 0, + .maximum = INT_MAX, + .default_num = 0 + }, + + { .name = "force-width", + .type = OPTIONS_TABLE_NUMBER, + .minimum = 0, + .maximum = INT_MAX, + .default_num = 0 + }, + + { .name = "main-pane-height", + .type = OPTIONS_TABLE_NUMBER, + .minimum = 1, + .maximum = INT_MAX, + .default_num = 24 + }, + + { .name = "main-pane-width", + .type = OPTIONS_TABLE_NUMBER, + .minimum = 1, + .maximum = INT_MAX, + .default_num = 80 + }, + + { .name = "mode-attr", + .type = OPTIONS_TABLE_ATTRIBUTES, + .default_num = 0 + }, + + { .name = "mode-bg", + .type = OPTIONS_TABLE_COLOUR, + .default_num = 3 + }, + + { .name = "mode-fg", + .type = OPTIONS_TABLE_COLOUR, + .default_num = 0 + }, + + { .name = "mode-keys", + .type = OPTIONS_TABLE_CHOICE, + .choices = options_table_mode_keys_list, + .default_num = MODEKEY_EMACS + }, + + { .name = "mode-mouse", + .type = OPTIONS_TABLE_FLAG, + .default_num = 0 + }, + + { .name = "monitor-activity", + .type = OPTIONS_TABLE_FLAG, + .default_num = 0 + }, + + { .name = "monitor-content", + .type = OPTIONS_TABLE_STRING, + .default_str = "" + }, + + { .name = "monitor-silence", + .type = OPTIONS_TABLE_NUMBER, + .minimum = 0, + .maximum = INT_MAX, + .default_num = 0 + }, + + { .name = "other-pane-height", + .type = OPTIONS_TABLE_NUMBER, + .minimum = 0, + .maximum = INT_MAX, + .default_num = 0 + }, + + { .name = "other-pane-width", + .type = OPTIONS_TABLE_NUMBER, + .minimum = 0, + .maximum = INT_MAX, + .default_num = 0 + }, + + { .name = "remain-on-exit", + .type = OPTIONS_TABLE_FLAG, + .default_num = 0 + }, + + { .name = "synchronize-panes", + .type = OPTIONS_TABLE_FLAG, + .default_num = 0 + }, + + { .name = "utf8", + .type = OPTIONS_TABLE_FLAG, + .default_num = 0 /* overridden in main() */ + }, + + { .name = "window-status-alert-attr", + .type = OPTIONS_TABLE_ATTRIBUTES, + .default_num = GRID_ATTR_REVERSE + }, + + { .name = "window-status-alert-bg", + .type = OPTIONS_TABLE_COLOUR, + .default_num = 8 + }, + + { .name = "window-status-alert-fg", + .type = OPTIONS_TABLE_COLOUR, + .default_num = 8 + }, + + { .name = "window-status-attr", + .type = OPTIONS_TABLE_ATTRIBUTES, + .default_num = 0 + }, + + { .name = "window-status-bg", + .type = OPTIONS_TABLE_COLOUR, + .default_num = 8 + }, + + { .name = "window-status-current-attr", + .type = OPTIONS_TABLE_ATTRIBUTES, + .default_num = 0 + }, + + { .name = "window-status-current-bg", + .type = OPTIONS_TABLE_COLOUR, + .default_num = 8 + }, + + { .name = "window-status-current-fg", + .type = OPTIONS_TABLE_COLOUR, + .default_num = 8 + }, + + { .name = "window-status-current-format", + .type = OPTIONS_TABLE_STRING, + .default_str = "#I:#W#F" + }, + + { .name = "window-status-fg", + .type = OPTIONS_TABLE_COLOUR, + .default_num = 8 + }, + + { .name = "window-status-format", + .type = OPTIONS_TABLE_STRING, + .default_str = "#I:#W#F" + }, + + { .name = "word-separators", + .type = OPTIONS_TABLE_STRING, + .default_str = " -_@" + }, + + { .name = "xterm-keys", + .type = OPTIONS_TABLE_FLAG, + .default_num = 0 + }, + + { .name = NULL } +}; + +/* Populate an options tree from a table. */ +void +options_table_populate_tree( + const struct options_table_entry *table, struct options *oo) +{ + const struct options_table_entry *oe; + + for (oe = table; oe->name != NULL; oe++) { + if (oe->default_str != NULL) + options_set_string(oo, oe->name, "%s", oe->default_str); + else + options_set_number(oo, oe->name, oe->default_num); + } +} + +/* Print an option using its type from the table. */ +const char * +options_table_print_entry( + const struct options_table_entry *oe, struct options_entry *o) +{ + static char out[BUFSIZ]; + const char *s; + struct keylist *keylist; + u_int i; + + *out = '\0'; + switch (oe->type) { + case OPTIONS_TABLE_STRING: + xsnprintf(out, sizeof out, "\"%s\"", o->str); + break; + case OPTIONS_TABLE_NUMBER: + xsnprintf(out, sizeof out, "%lld", o->num); + break; + case OPTIONS_TABLE_KEYS: + keylist = o->data; + for (i = 0; i < ARRAY_LENGTH(keylist); i++) { + s = key_string_lookup_key(ARRAY_ITEM(keylist, i)); + strlcat(out, s, sizeof out); + if (i != ARRAY_LENGTH(keylist) - 1) + strlcat(out, ",", sizeof out); + } + break; + case OPTIONS_TABLE_COLOUR: + s = colour_tostring(o->num); + xsnprintf(out, sizeof out, "%s", s); + break; + case OPTIONS_TABLE_ATTRIBUTES: + s = attributes_tostring(o->num); + xsnprintf(out, sizeof out, "%s", s); + break; + case OPTIONS_TABLE_FLAG: + if (o->num) + strlcpy(out, "on", sizeof out); + else + strlcpy(out, "off", sizeof out); + break; + case OPTIONS_TABLE_CHOICE: + s = oe->choices[o->num]; + xsnprintf(out, sizeof out, "%s", s); + break; + } + return (out); +} diff --git a/status.c b/status.c index 75b0a830..073ccf12 100644 --- a/status.c +++ b/status.c @@ -1112,12 +1112,12 @@ status_prompt_add_history(const char *line) char * status_prompt_complete(const char *s) { - const struct cmd_entry **cmdent; - const struct set_option_entry *entry; - ARRAY_DECL(, const char *) list; - char *prefix, *s2; - u_int i; - size_t j; + const struct cmd_entry **cmdent; + const struct options_table_entry *oe; + ARRAY_DECL(, const char *) list; + char *prefix, *s2; + u_int i; + size_t j; if (*s == '\0') return (NULL); @@ -1128,17 +1128,17 @@ status_prompt_complete(const char *s) if (strncmp((*cmdent)->name, s, strlen(s)) == 0) ARRAY_ADD(&list, (*cmdent)->name); } - for (entry = set_option_table; entry->name != NULL; entry++) { - if (strncmp(entry->name, s, strlen(s)) == 0) - ARRAY_ADD(&list, entry->name); + for (oe = server_options_table; oe->name != NULL; oe++) { + if (strncmp(oe->name, s, strlen(s)) == 0) + ARRAY_ADD(&list, oe->name); } - for (entry = set_session_option_table; entry->name != NULL; entry++) { - if (strncmp(entry->name, s, strlen(s)) == 0) - ARRAY_ADD(&list, entry->name); + for (oe = session_options_table; oe->name != NULL; oe++) { + if (strncmp(oe->name, s, strlen(s)) == 0) + ARRAY_ADD(&list, oe->name); } - for (entry = set_window_option_table; entry->name != NULL; entry++) { - if (strncmp(entry->name, s, strlen(s)) == 0) - ARRAY_ADD(&list, entry->name); + for (oe = window_options_table; oe->name != NULL; oe++) { + if (strncmp(oe->name, s, strlen(s)) == 0) + ARRAY_ADD(&list, oe->name); } /* If none, bail now. */ diff --git a/tmux.c b/tmux.c index a8331a1f..54abf658 100644 --- a/tmux.c +++ b/tmux.c @@ -228,7 +228,6 @@ int main(int argc, char **argv) { struct passwd *pw; - struct options *oo, *so, *wo; struct keylist *keylist; char *s, *path, *label, *home, **var; int opt, flags, quiet, keys; @@ -316,129 +315,39 @@ main(int argc, char **argv) environ_put(&global_environ, *var); options_init(&global_options, NULL); - oo = &global_options; - options_set_number(oo, "quiet", quiet); - options_set_number(oo, "escape-time", 500); - options_set_number(oo, "exit-unattached", 0); - options_set_number(oo, "buffer-limit", 9); + options_table_populate_tree(server_options_table, &global_options); + options_set_number(&global_options, "quiet", quiet); options_init(&global_s_options, NULL); - so = &global_s_options; - options_set_number(so, "base-index", 0); - options_set_number(so, "bell-action", BELL_ANY); - options_set_string(so, "default-command", "%s", ""); - options_set_string(so, "default-path", "%s", ""); - options_set_string(so, "default-shell", "%s", getshell()); - options_set_string(so, "default-terminal", "screen"); - options_set_number(so, "destroy-unattached", 0); - options_set_number(so, "detach-on-destroy", 1); - options_set_number(so, "display-panes-active-colour", 1); - options_set_number(so, "display-panes-colour", 4); - options_set_number(so, "display-panes-time", 1000); - options_set_number(so, "display-time", 750); - options_set_number(so, "history-limit", 2000); - options_set_number(so, "lock-after-time", 0); - options_set_string(so, "lock-command", "lock -np"); - options_set_number(so, "lock-server", 1); - options_set_number(so, "message-attr", 0); - options_set_number(so, "message-bg", 3); - options_set_number(so, "message-fg", 0); - options_set_number(so, "message-limit", 20); - options_set_number(so, "mouse-select-pane", 0); - options_set_number(so, "pane-active-border-bg", 8); - options_set_number(so, "pane-active-border-fg", 2); - options_set_number(so, "pane-border-bg", 8); - options_set_number(so, "pane-border-fg", 8); - options_set_number(so, "repeat-time", 500); - options_set_number(so, "set-remain-on-exit", 0); - options_set_number(so, "set-titles", 0); - options_set_string(so, "set-titles-string", "#S:#I:#W - \"#T\""); - options_set_number(so, "status", 1); - options_set_number(so, "status-attr", 0); - options_set_number(so, "status-bg", 2); - options_set_number(so, "status-fg", 0); - options_set_number(so, "status-interval", 15); - options_set_number(so, "status-justify", 0); - options_set_string(so, "status-left", "[#S]"); - options_set_number(so, "status-left-attr", 0); - options_set_number(so, "status-left-bg", 8); - options_set_number(so, "status-left-fg", 8); - options_set_number(so, "status-left-length", 10); - options_set_string(so, "status-right", "\"#22T\" %%H:%%M %%d-%%b-%%y"); - options_set_number(so, "status-right-attr", 0); - options_set_number(so, "status-right-bg", 8); - options_set_number(so, "status-right-fg", 8); - options_set_number(so, "status-right-length", 40); - options_set_string(so, "terminal-overrides", - "*88col*:colors=88,*256col*:colors=256"); - options_set_string(so, "update-environment", - "DISPLAY " - "SSH_ASKPASS SSH_AUTH_SOCK SSH_AGENT_PID SSH_CONNECTION " - "WINDOWID " - "XAUTHORITY"); - options_set_number(so, "visual-activity", 0); - options_set_number(so, "visual-bell", 0); - options_set_number(so, "visual-content", 0); - options_set_number(so, "visual-silence", 0); + options_table_populate_tree(session_options_table, &global_s_options); + options_set_string(&global_s_options, "default-shell", "%s", getshell()); + options_init(&global_w_options, NULL); + options_table_populate_tree(window_options_table, &global_w_options); + + /* Set the prefix option (its a list, so not in the table). */ keylist = xmalloc(sizeof *keylist); ARRAY_INIT(keylist); ARRAY_ADD(keylist, '\002'); - options_set_data(so, "prefix", keylist, xfree); - - options_init(&global_w_options, NULL); - wo = &global_w_options; - options_set_number(wo, "aggressive-resize", 0); - options_set_number(wo, "alternate-screen", 1); - options_set_number(wo, "automatic-rename", 1); - options_set_number(wo, "clock-mode-colour", 4); - options_set_number(wo, "clock-mode-style", 1); - options_set_number(wo, "force-height", 0); - options_set_number(wo, "force-width", 0); - options_set_number(wo, "main-pane-height", 24); - options_set_number(wo, "main-pane-width", 80); - options_set_number(wo, "mode-attr", 0); - options_set_number(wo, "mode-bg", 3); - options_set_number(wo, "mode-fg", 0); - options_set_number(wo, "mode-mouse", 0); - options_set_number(wo, "monitor-activity", 0); - options_set_string(wo, "monitor-content", "%s", ""); - options_set_number(wo, "monitor-silence", 0); - options_set_number(wo, "other-pane-height", 0); - options_set_number(wo, "other-pane-width", 0); - options_set_number(wo, "window-status-attr", 0); - options_set_number(wo, "window-status-bg", 8); - options_set_number(wo, "window-status-current-attr", 0); - options_set_number(wo, "window-status-current-bg", 8); - options_set_number(wo, "window-status-current-fg", 8); - options_set_number(wo, "window-status-fg", 8); - options_set_number(wo, "window-status-alert-attr", GRID_ATTR_REVERSE); - options_set_number(wo, "window-status-alert-bg", 8); - options_set_number(wo, "window-status-alert-fg", 8); - options_set_string(wo, "window-status-format", "#I:#W#F"); - options_set_string(wo, "window-status-current-format", "#I:#W#F"); - options_set_string(wo, "word-separators", " -_@"); - options_set_number(wo, "xterm-keys", 0); - options_set_number(wo, "remain-on-exit", 0); - options_set_number(wo, "synchronize-panes", 0); + options_set_data(&global_s_options, "prefix", keylist, xfree); + /* Enable UTF-8 if the first client is on UTF-8 terminal. */ if (flags & IDENTIFY_UTF8) { - options_set_number(so, "status-utf8", 1); - options_set_number(wo, "utf8", 1); - } else { - options_set_number(so, "status-utf8", 0); - options_set_number(wo, "utf8", 0); + options_set_number(&global_s_options, "status-utf8", 1); + options_set_number(&global_w_options, "utf8", 1); } - keys = MODEKEY_EMACS; + /* Override keys to vi if VISUAL or EDITOR are set. */ if ((s = getenv("VISUAL")) != NULL || (s = getenv("EDITOR")) != NULL) { if (strrchr(s, '/') != NULL) s = strrchr(s, '/') + 1; if (strstr(s, "vi") != NULL) keys = MODEKEY_VI; + else + keys = MODEKEY_EMACS; + options_set_number(&global_s_options, "status-keys", keys); + options_set_number(&global_w_options, "mode-keys", keys); } - options_set_number(so, "status-keys", keys); - options_set_number(wo, "mode-keys", keys); /* Locate the configuration file. */ if (cfg_file == NULL) { diff --git a/tmux.h b/tmux.h index 116f8d78..45bb1a1b 100644 --- a/tmux.h +++ b/tmux.h @@ -1270,23 +1270,31 @@ struct key_binding { }; SPLAY_HEAD(key_bindings, key_binding); -/* Set/display option data. */ -struct set_option_entry { - const char *name; - enum { - SET_OPTION_STRING, - SET_OPTION_NUMBER, - SET_OPTION_KEYS, - SET_OPTION_COLOUR, - SET_OPTION_ATTRIBUTES, - SET_OPTION_FLAG, - SET_OPTION_CHOICE - } type; +/* + * Option table entries. The option table is the user-visible part of the + * option, as opposed to the internal options (struct option) which are just + * number or string. + */ +enum options_table_type { + OPTIONS_TABLE_STRING, + OPTIONS_TABLE_NUMBER, + OPTIONS_TABLE_KEYS, + OPTIONS_TABLE_COLOUR, + OPTIONS_TABLE_ATTRIBUTES, + OPTIONS_TABLE_FLAG, + OPTIONS_TABLE_CHOICE +}; - u_int minimum; - u_int maximum; +struct options_table_entry { + const char *name; + enum options_table_type type; - const char **choices; + u_int minimum; + u_int maximum; + const char **choices; + + const char *default_str; + long long default_num; }; /* List of configuration causes. */ @@ -1356,6 +1364,15 @@ struct options_entry *options_set_data( struct options *, const char *, void *, void (*)(void *)); void *options_get_data(struct options *, const char *); +/* options-table.c */ +extern const struct options_table_entry server_options_table[]; +extern const struct options_table_entry session_options_table[]; +extern const struct options_table_entry window_options_table[]; +void options_table_populate_tree( + const struct options_table_entry *, struct options *); +const char *options_table_print_entry( + const struct options_table_entry *, struct options_entry *); + /* job.c */ extern struct joblist all_jobs; int job_cmp(struct job *, struct job *); @@ -1461,13 +1478,6 @@ char *paste_print(struct paste_buffer *, size_t); extern const char clock_table[14][5][5]; void clock_draw(struct screen_write_ctx *, int, int); -/* cmd-set-option.c */ -extern const struct set_option_entry set_option_table[]; -extern const struct set_option_entry set_session_option_table[]; -extern const struct set_option_entry set_window_option_table[]; -const char *cmd_set_option_print( - const struct set_option_entry *, struct options_entry *); - /* cmd.c */ int cmd_pack_argv(int, char **, char *, size_t); int cmd_unpack_argv(char *, size_t, int, char ***); From 5158dd9a8dddf34a00ec6359840488d34faabd88 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 3 Jan 2011 21:30:49 +0000 Subject: [PATCH 0826/1180] Handle a # at the end of a replacement string (such as status-left) correctly. Found by Thomas Adam. --- status.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/status.c b/status.c index 073ccf12..c23f9ac3 100644 --- a/status.c +++ b/status.c @@ -456,7 +456,7 @@ status_replace(struct client *c, break; ch = *iptr++; - if (ch != '#') { + if (ch != '#' || *iptr == '\0') { *optr++ = ch; continue; } From ac3b78a84178a308536a56ea114b0f6f8ce6fb47 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 3 Jan 2011 23:35:21 +0000 Subject: [PATCH 0827/1180] Support for UTF-8 mouse input (\033[1005h). This was added in xterm 262 and supports larger terminals than the older way. If the new mouse-utf8 option is on, UTF-8 mouse input is enabled for all UTF-8 terminals. The option defaults to on if LANG etc are set in the same manner as the utf8 option. With help and based on code from hsim at gmx.li. --- input-keys.c | 20 +++++++++++++---- input.c | 6 +++++ options-table.c | 5 +++++ screen-write.c | 12 ++++++++++ server-client.c | 15 +++++++++++++ tmux.1 | 4 ++++ tmux.c | 1 + tmux.h | 10 ++++++--- tty-keys.c | 60 ++++++++++++++++++++++++++++++++++++------------- tty.c | 4 ++++ utf8.c | 13 +++++++++++ 11 files changed, 128 insertions(+), 22 deletions(-) diff --git a/input-keys.c b/input-keys.c index ac759684..f73ce397 100644 --- a/input-keys.c +++ b/input-keys.c @@ -202,11 +202,23 @@ input_key(struct window_pane *wp, int key) void input_mouse(struct window_pane *wp, struct mouse_event *m) { - char out[8]; + char buf[10]; + size_t len; if (wp->screen->mode & ALL_MOUSE_MODES) { - xsnprintf(out, sizeof out, - "\033[M%c%c%c", m->b + 32, m->x + 33, m->y + 33); - bufferevent_write(wp->event, out, strlen(out)); + if (wp->screen->mode & MODE_MOUSE_UTF8) { + len = xsnprintf(buf, sizeof buf, "\033[M"); + len += utf8_split2(m->b + 32, &buf[len]); + len += utf8_split2(m->x + 33, &buf[len]); + len += utf8_split2(m->y + 33, &buf[len]); + } else { + if (m->b > 223 || m->x >= 222 || m->y > 222) + return; + len = xsnprintf(buf, sizeof buf, "\033[M"); + buf[len++] = m->b + 32; + buf[len++] = m->x + 33; + buf[len++] = m->y + 33; + } + bufferevent_write(wp->event, buf, len); } } diff --git a/input.c b/input.c index 49224e0e..cb8c4e52 100644 --- a/input.c +++ b/input.c @@ -1161,6 +1161,9 @@ input_csi_dispatch(struct input_ctx *ictx) case 1003: screen_write_mousemode_off(&ictx->ctx); break; + case 1005: + screen_write_utf8mousemode(&ictx->ctx, 0); + break; case 1049: window_pane_alternate_off(wp, &ictx->cell); break; @@ -1209,6 +1212,9 @@ input_csi_dispatch(struct input_ctx *ictx) case 1003: screen_write_mousemode_on(&ictx->ctx, MODE_MOUSE_ANY); break; + case 1005: + screen_write_utf8mousemode(&ictx->ctx, 1); + break; case 1049: window_pane_alternate_on(wp, &ictx->cell); break; diff --git a/options-table.c b/options-table.c index 56cb24e5..4e2b8f61 100644 --- a/options-table.c +++ b/options-table.c @@ -198,6 +198,11 @@ const struct options_table_entry session_options_table[] = { .default_num = 0 }, + { .name = "mouse-utf8", + .type = OPTIONS_TABLE_FLAG, + .default_num = 0 + }, + { .name = "pane-active-border-bg", .type = OPTIONS_TABLE_COLOUR, .default_num = 8 diff --git a/screen-write.c b/screen-write.c index c4e873b1..88c183ae 100644 --- a/screen-write.c +++ b/screen-write.c @@ -829,6 +829,18 @@ screen_write_insertmode(struct screen_write_ctx *ctx, int state) s->mode &= ~MODE_INSERT; } +/* Set UTF-8 mouse mode. */ +void +screen_write_utf8mousemode(struct screen_write_ctx *ctx, int state) +{ + struct screen *s = ctx->s; + + if (state) + s->mode |= MODE_MOUSE_UTF8; + else + s->mode &= ~MODE_MOUSE_UTF8; +} + /* Set mouse mode off. */ void screen_write_mousemode_off(struct screen_write_ctx *ctx) diff --git a/server-client.c b/server-client.c index 76f8d3a8..24a85b56 100644 --- a/server-client.c +++ b/server-client.c @@ -451,6 +451,21 @@ server_client_reset_state(struct client *c) if (TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry) != NULL && options_get_number(oo, "mouse-select-pane")) mode |= MODE_MOUSE_STANDARD; + + /* + * Set UTF-8 mouse input if required. If the terminal is UTF-8, the + * user has set mouse-utf8 and any mouse mode is in effect, turn on + * UTF-8 mouse input. If the receiving terminal hasn't requested it + * (that is, it isn't in s->mode), then it'll be converted in + * input_mouse. + */ + if ((c->tty.flags & TTY_UTF8) && + (mode & ALL_MOUSE_MODES) && options_get_number(oo, "mouse-utf8")) + mode |= MODE_MOUSE_UTF8; + else + mode &= ~MODE_MOUSE_UTF8; + + /* Set the terminal mode and reset attributes. */ tty_update_mode(&c->tty, mode); tty_reset(&c->tty); } diff --git a/tmux.1 b/tmux.1 index 079c8b8c..0f86e195 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1806,6 +1806,10 @@ flag to Repeat is enabled for the default keys bound to the .Ic resize-pane command. +.It Xo Ic mouse-utf8 +.Op Ic on | off +.Xc +If enabled, request mouse input as UTF-8 on UTF-8 terminals. .It Xo Ic set-remain-on-exit .Op Ic on | off .Xc diff --git a/tmux.c b/tmux.c index 54abf658..007d81fd 100644 --- a/tmux.c +++ b/tmux.c @@ -334,6 +334,7 @@ main(int argc, char **argv) /* Enable UTF-8 if the first client is on UTF-8 terminal. */ if (flags & IDENTIFY_UTF8) { options_set_number(&global_s_options, "status-utf8", 1); + options_set_number(&global_s_options, "mouse-utf8", 1); options_set_number(&global_w_options, "utf8", 1); } diff --git a/tmux.h b/tmux.h index 45bb1a1b..09999b00 100644 --- a/tmux.h +++ b/tmux.h @@ -550,6 +550,7 @@ struct mode_key_table { #define MODE_MOUSE_HIGHLIGHT 0x40 #define MODE_MOUSE_BUTTON 0x80 #define MODE_MOUSE_ANY 0x100 +#define MODE_MOUSE_UTF8 0x200 #define ALL_MOUSE_MODES (MODE_MOUSE_STANDARD| \ MODE_MOUSE_HIGHLIGHT|MODE_MOUSE_BUTTON|MODE_MOUSE_ANY) @@ -1075,15 +1076,15 @@ struct tty_ctx { */ /* Mouse input. */ struct mouse_event { - u_char b; + u_int b; #define MOUSE_1 0 #define MOUSE_2 1 #define MOUSE_3 2 #define MOUSE_UP 3 #define MOUSE_BUTTON 3 #define MOUSE_45 64 - u_char x; - u_char y; + u_int x; + u_int y; }; /* Saved message entry. */ @@ -1817,6 +1818,7 @@ void screen_write_cursormode(struct screen_write_ctx *, int); void screen_write_reverseindex(struct screen_write_ctx *); void screen_write_scrollregion(struct screen_write_ctx *, u_int, u_int); void screen_write_insertmode(struct screen_write_ctx *, int); +void screen_write_utf8mousemode(struct screen_write_ctx *, int); void screen_write_mousemode_on(struct screen_write_ctx *, int); void screen_write_mousemode_off(struct screen_write_ctx *); void screen_write_linefeed(struct screen_write_ctx *, int); @@ -2017,6 +2019,8 @@ void session_group_synchronize1(struct session *, struct session *); void utf8_build(void); int utf8_open(struct utf8_data *, u_char); int utf8_append(struct utf8_data *, u_char); +u_int utf8_combine(const struct utf8_data *); +u_int utf8_split2(u_int, u_char *); /* procname.c */ char *get_proc_name(int, char *); diff --git a/tty-keys.c b/tty-keys.c index 19964538..3381aefe 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -38,7 +38,7 @@ struct tty_key *tty_keys_find1( struct tty_key *, const char *, size_t, size_t *); struct tty_key *tty_keys_find(struct tty *, const char *, size_t, size_t *); void tty_keys_callback(int, short, void *); -int tty_keys_mouse( +int tty_keys_mouse(struct tty *, const char *, size_t, size_t *, struct mouse_event *); struct tty_key_ent { @@ -462,7 +462,7 @@ tty_keys_next(struct tty *tty) } /* Is this a mouse key press? */ - switch (tty_keys_mouse(buf, len, &size, &mouse)) { + switch (tty_keys_mouse(tty, buf, len, &size, &mouse)) { case 0: /* yes */ evbuffer_drain(tty->event->input, size); key = KEYC_MOUSE; @@ -584,44 +584,74 @@ tty_keys_callback(unused int fd, unused short events, void *data) * (probably a mouse sequence but need more data). */ int -tty_keys_mouse(const char *buf, size_t len, size_t *size, struct mouse_event *m) +tty_keys_mouse(struct tty *tty, + const char *buf, size_t len, size_t *size, struct mouse_event *m) { + struct utf8_data utf8data; + u_int i, value; + /* - * Mouse sequences are \033[M followed by three characters indicating - * buttons, X and Y, all based at 32 with 1,1 top-left. + * Standard mouse sequences are \033[M followed by three characters + * indicating buttons, X and Y, all based at 32 with 1,1 top-left. + * + * UTF-8 mouse sequences are similar but the three are expressed as + * UTF-8 characters. */ *size = 0; + /* First three bytes are always \033[M. */ if (buf[0] != '\033') return (-1); if (len == 1) return (1); - if (buf[1] != '[') return (-1); if (len == 2) return (1); - if (buf[2] != 'M') return (-1); if (len == 3) return (1); - if (len < 6) - return (1); - *size = 6; + /* Read the three inputs. */ + *size = 3; + for (i = 0; i < 3; i++) { + if (len < *size) + return (1); - log_debug( - "mouse input: %.6s (%hhu,%hhu/%hhu)", buf, buf[4], buf[5], buf[3]); + if (tty->mode & MODE_MOUSE_UTF8) { + if (utf8_open(&utf8data, buf[*size])) { + if (utf8data.size != 2) + return (-1); + (*size)++; + if (len < *size) + return (1); + utf8_append(&utf8data, buf[*size]); + value = utf8_combine(&utf8data); + } else + value = buf[*size]; + (*size)++; + } else { + value = buf[*size]; + (*size)++; + } - m->b = buf[3]; - m->x = buf[4]; - m->y = buf[5]; + if (i == 0) + m->b = value; + else if (i == 1) + m->x = value; + else + m->y = value; + } + log_debug("mouse input: %.*s", (int) *size, buf); + + /* Check and return the mouse input. */ if (m->b < 32 || m->x < 33 || m->y < 33) return (-1); m->b -= 32; m->x -= 33; m->y -= 33; + log_debug("mouse position: x=%u y=%u b=%u", m->x, m->y, m->b); return (0); } diff --git a/tty.c b/tty.c index f7698708..80afa2d4 100644 --- a/tty.c +++ b/tty.c @@ -405,6 +405,8 @@ tty_update_mode(struct tty *tty, int mode) } if (changed & ALL_MOUSE_MODES) { if (mode & ALL_MOUSE_MODES) { + if (mode & MODE_MOUSE_UTF8) + tty_puts(tty, "\033[?1005h"); if (mode & MODE_MOUSE_STANDARD) tty_puts(tty, "\033[?1000h"); else if (mode & MODE_MOUSE_HIGHLIGHT) @@ -422,6 +424,8 @@ tty_update_mode(struct tty *tty, int mode) tty_puts(tty, "\033[?1002l"); else if (tty->mode & MODE_MOUSE_ANY) tty_puts(tty, "\033[?1003l"); + if (tty->mode & MODE_MOUSE_UTF8) + tty_puts(tty, "\033[?1005l"); } } if (changed & MODE_KKEYPAD) { diff --git a/utf8.c b/utf8.c index 00b1c736..b276d872 100644 --- a/utf8.c +++ b/utf8.c @@ -318,6 +318,19 @@ utf8_combine(const struct utf8_data *utf8data) return (value); } +/* Split a two-byte UTF-8 character. */ +u_int +utf8_split2(u_int uc, u_char *ptr) +{ + if (uc > 0x7f) { + ptr[0] = (uc >> 6) | 0xc0; + ptr[1] = (uc & 0x3f) | 0x80; + return (2); + } + ptr[0] = uc; + return (1); +} + /* Lookup width of UTF-8 data in tree. */ u_int utf8_width(const struct utf8_data *utf8data) From 7502cb3adbb26a2f94445a35626e64041d6769f9 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 4 Jan 2011 00:42:46 +0000 Subject: [PATCH 0828/1180] Clean up and simplify tmux command argument parsing. Originally, tmux commands were parsed in the client process into a struct with the command data which was then serialised and sent to the server to be executed. The parsing was later moved into the server (an argv was sent from the client), but the parse step and intermediate struct was kept. This change removes that struct and the separate parse step. Argument parsing and printing is now common to all commands (in arguments.c) with each command left with just an optional check function (to validate the arguments at parse time), the exec function and a function to set up any key bindings (renamed from the old init function). This is overall more simple and consistent. There should be no changes to any commands behaviour or syntax although as this touches every command please watch for any unexpected changes. --- Makefile | 4 +- arguments.c | 222 ++++++++++++++++++++ cmd-attach-session.c | 32 +-- cmd-bind-key.c | 189 +++++------------ cmd-break-pane.c | 19 +- cmd-capture-pane.c | 131 +++--------- cmd-choose-buffer.c | 23 +-- cmd-choose-client.c | 19 +- cmd-choose-session.c | 19 +- cmd-choose-window.c | 19 +- cmd-clear-history.c | 15 +- cmd-clock-mode.c | 15 +- cmd-command-prompt.c | 150 ++++---------- cmd-confirm-before.c | 35 ++-- cmd-copy-mode.c | 34 ++-- cmd-delete-buffer.c | 31 ++- cmd-detach-client.c | 17 +- cmd-display-message.c | 21 +- cmd-display-panes.c | 17 +- cmd-find-window.c | 25 +-- cmd-generic.c | 414 -------------------------------------- cmd-has-session.c | 15 +- cmd-if-shell.c | 17 +- cmd-join-pane.c | 196 ++++-------------- cmd-kill-pane.c | 17 +- cmd-kill-server.c | 7 +- cmd-kill-session.c | 17 +- cmd-kill-window.c | 17 +- cmd-last-pane.c | 19 +- cmd-last-window.c | 17 +- cmd-link-window.c | 29 ++- cmd-list-buffers.c | 7 +- cmd-list-clients.c | 7 +- cmd-list-commands.c | 7 +- cmd-list-keys.c | 23 ++- cmd-list-panes.c | 15 +- cmd-list-sessions.c | 10 +- cmd-list-windows.c | 21 +- cmd-load-buffer.c | 76 ++++--- cmd-lock-client.c | 17 +- cmd-lock-server.c | 7 +- cmd-lock-session.c | 17 +- cmd-move-window.c | 29 ++- cmd-new-session.c | 175 ++++------------ cmd-new-window.c | 167 +++------------ cmd-next-layout.c | 19 +- cmd-next-window.c | 33 ++- cmd-paste-buffer.c | 192 +++++------------- cmd-pipe-pane.c | 21 +- cmd-previous-layout.c | 19 +- cmd-previous-window.c | 33 ++- cmd-refresh-client.c | 17 +- cmd-rename-session.c | 25 +-- cmd-rename-window.c | 21 +- cmd-resize-pane.c | 98 ++++----- cmd-respawn-window.c | 25 ++- cmd-rotate-window.c | 29 ++- cmd-run-shell.c | 17 +- cmd-save-buffer.c | 52 +++-- cmd-select-layout.c | 73 +++---- cmd-select-pane.c | 45 ++--- cmd-select-window.c | 31 ++- cmd-send-keys.c | 126 ++---------- cmd-send-prefix.c | 15 +- cmd-server-info.c | 7 +- cmd-set-buffer.c | 37 ++-- cmd-set-environment.c | 46 +++-- cmd-set-option.c | 205 ++++++++++--------- cmd-set-window-option.c | 13 +- cmd-show-buffer.c | 29 ++- cmd-show-environment.c | 23 +-- cmd-show-messages.c | 23 +-- cmd-show-options.c | 25 ++- cmd-show-window-options.c | 15 +- cmd-source-file.c | 97 ++------- cmd-split-window.c | 216 +++++--------------- cmd-start-server.c | 7 +- cmd-suspend-client.c | 17 +- cmd-swap-pane.c | 44 ++-- cmd-swap-window.c | 22 +- cmd-switch-client.c | 152 ++------------ cmd-unbind-key.c | 128 ++++-------- cmd-unlink-window.c | 17 +- cmd.c | 58 +++--- key-bindings.c | 7 +- tmux.h | 117 +++++------ 86 files changed, 1609 insertions(+), 2967 deletions(-) create mode 100644 arguments.c delete mode 100644 cmd-generic.c diff --git a/Makefile b/Makefile index 86b28b60..0f7f403e 100644 --- a/Makefile +++ b/Makefile @@ -1,13 +1,13 @@ # $OpenBSD$ PROG= tmux -SRCS= attributes.c cfg.c client.c clock.c \ +SRCS= arguments.c attributes.c cfg.c client.c clock.c \ cmd-attach-session.c cmd-bind-key.c \ cmd-break-pane.c cmd-choose-session.c cmd-choose-window.c \ cmd-clear-history.c cmd-clock-mode.c cmd-command-prompt.c \ cmd-confirm-before.c cmd-copy-mode.c \ cmd-choose-buffer.c cmd-delete-buffer.c cmd-detach-client.c \ - cmd-find-window.c cmd-generic.c cmd-has-session.c cmd-kill-pane.c \ + cmd-find-window.c cmd-has-session.c cmd-kill-pane.c \ cmd-kill-server.c cmd-kill-session.c cmd-kill-window.c \ cmd-last-pane.c cmd-last-window.c cmd-link-window.c cmd-list-buffers.c \ cmd-list-clients.c cmd-list-commands.c cmd-list-keys.c \ diff --git a/arguments.c b/arguments.c new file mode 100644 index 00000000..ebd09580 --- /dev/null +++ b/arguments.c @@ -0,0 +1,222 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2010 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 "tmux.h" + +/* Create an arguments set with no flags. */ +struct args * +args_create(int argc, ...) +{ + struct args *args; + va_list ap; + int i; + + args = xcalloc(1, sizeof *args); + if ((args->flags = bit_alloc(SCHAR_MAX)) == NULL) + fatal("bit_alloc failed"); + + args->argc = argc; + if (argc == 0) + args->argv = NULL; + else + args->argv = xcalloc(argc, sizeof **args->argv); + + va_start(ap, argc); + for (i = 0; i < argc; i++) + args->argv[i] = xstrdup(va_arg(ap, char *)); + va_end(ap); + + return (args); +} + +/* Parse an argv and argc into a new argument set. */ +struct args * +args_parse(const char *template, int argc, char **argv) +{ + struct args *args; + char *ptr; + int opt; + + args = xcalloc(1, sizeof *args); + if ((args->flags = bit_alloc(SCHAR_MAX)) == NULL) + fatal("bit_alloc failed"); + + optreset = 1; + optind = 1; + + while ((opt = getopt(argc, argv, template)) != -1) { + if (opt < 0 || opt >= SCHAR_MAX) + continue; + if (opt == '?' || (ptr = strchr(template, opt)) == NULL) { + xfree(args->flags); + xfree(args); + return (NULL); + } + + bit_set(args->flags, opt); + if (ptr[1] == ':') { + if (args->values[opt] != NULL) + xfree(args->values[opt]); + args->values[opt] = xstrdup(optarg); + } + } + argc -= optind; + argv += optind; + + args->argc = argc; + args->argv = cmd_copy_argv(argc, argv); + + return (args); +} + +/* Free an arguments set. */ +void +args_free(struct args *args) +{ + u_int i; + + cmd_free_argv(args->argc, args->argv); + + for (i = 0; i < SCHAR_MAX; i++) { + if (args->values[i] != NULL) + xfree(args->values[i]); + } + + xfree(args->flags); + xfree(args); +} + +/* Print a set of arguments. */ +size_t +args_print(struct args *args, char *buf, size_t len) +{ + size_t off; + int i; + const char *quotes; + + /* There must be at least one byte at the start. */ + if (len == 0) + return (0); + off = 0; + + /* Process the flags first. */ + buf[off++] = '-'; + for (i = 0; i < SCHAR_MAX; i++) { + if (!bit_test(args->flags, i) || args->values[i] != NULL) + continue; + + if (off == len - 1) { + buf[off] = '\0'; + return (len); + } + buf[off++] = i; + buf[off] = '\0'; + } + if (off == 1) + buf[--off] = '\0'; + + /* Then the flags with arguments. */ + for (i = 0; i < SCHAR_MAX; i++) { + if (!bit_test(args->flags, i) || args->values[i] == NULL) + continue; + + if (off >= len) { + /* snprintf will have zero terminated. */ + return (len); + } + + if (strchr(args->values[i], ' ') != NULL) + quotes = "\""; + else + quotes = ""; + off += xsnprintf(buf + off, len - off, "%s-%c %s%s%s", + off != 0 ? " " : "", i, quotes, args->values[i], quotes); + } + + /* And finally the argument vector. */ + for (i = 0; i < args->argc; i++) { + if (off >= len) { + /* snprintf will have zero terminated. */ + return (len); + } + + if (strchr(args->argv[i], ' ') != NULL) + quotes = "\""; + else + quotes = ""; + off += xsnprintf(buf + off, len - off, "%s%s%s%s", + off != 0 ? " " : "", quotes, args->argv[i], quotes); + } + + return (off); +} + +/* Return if an argument is present. */ +int +args_has(struct args *args, u_char ch) +{ + return (bit_test(args->flags, ch)); +} + +/* Set argument value. */ +void +args_set(struct args *args, u_char ch, const char *value) +{ + if (value != NULL) { + if (args->values[ch] != NULL) + xfree(args->values[ch]); + args->values[ch] = xstrdup(value); + } + bit_set(args->flags, ch); +} + +/* Get argument value. Will be NULL if it isn't present. */ +const char * +args_get(struct args *args, u_char ch) +{ + return (args->values[ch]); +} + +/* Convert an argument value to a number. */ +long long +args_strtonum(struct args *args, + u_char ch, long long minval, long long maxval, char **cause) +{ + const char *errstr; + long long ll; + + if (!args_has(args, ch)) { + *cause = xstrdup("missing"); + return (0); + } + + ll = strtonum(args->values[ch], minval, maxval, &errstr); + if (errstr != NULL) { + *cause = xstrdup(errstr); + return (0); + } + + *cause = NULL; + return (ll); +} diff --git a/cmd-attach-session.c b/cmd-attach-session.c index 45a49f2b..f320056d 100644 --- a/cmd-attach-session.c +++ b/cmd-attach-session.c @@ -28,37 +28,37 @@ int cmd_attach_session_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_attach_session_entry = { "attach-session", "attach", + "drt:", 0, 0, "[-dr] " CMD_TARGET_SESSION_USAGE, - CMD_CANTNEST|CMD_STARTSERVER|CMD_SENDENVIRON, "dr", - cmd_target_init, - cmd_target_parse, - cmd_attach_session_exec, - cmd_target_free, - cmd_target_print + CMD_CANTNEST|CMD_STARTSERVER|CMD_SENDENVIRON, + NULL, + NULL, + cmd_attach_session_exec }; int cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; - struct session *s; - struct client *c; - const char *update; - char *overrides, *cause; - u_int i; + struct args *args = self->args; + struct session *s; + struct client *c; + const char *update; + char *overrides, *cause; + u_int i; if (RB_EMPTY(&sessions)) { ctx->error(ctx, "no sessions"); return (-1); } - if ((s = cmd_find_session(ctx, data->target)) == NULL) + + if ((s = cmd_find_session(ctx, args_get(args, 't'))) == NULL) return (-1); if (ctx->cmdclient == NULL && ctx->curclient == NULL) return (0); if (ctx->cmdclient == NULL) { - if (cmd_check_flag(data->chflags, 'd')) { + if (args_has(self->args, 'd')) { /* * Can't use server_write_session in case attaching to * the same session as currently attached to. @@ -90,10 +90,10 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx) return (-1); } - if (cmd_check_flag(data->chflags, 'r')) + if (args_has(self->args, 'r')) ctx->cmdclient->flags |= CLIENT_READONLY; - if (cmd_check_flag(data->chflags, 'd')) + if (args_has(self->args, 'd')) server_write_session(s, MSG_DETACH, NULL, 0); ctx->cmdclient->session = s; diff --git a/cmd-bind-key.c b/cmd-bind-key.c index 60887904..025f6c79 100644 --- a/cmd-bind-key.c +++ b/cmd-bind-key.c @@ -26,136 +26,87 @@ * Bind a key to a command, this recurses through cmd_*. */ -int cmd_bind_key_parse(struct cmd *, int, char **, char **); +int cmd_bind_key_check(struct args *); int cmd_bind_key_exec(struct cmd *, struct cmd_ctx *); -void cmd_bind_key_free(struct cmd *); -size_t cmd_bind_key_print(struct cmd *, char *, size_t); -int cmd_bind_key_table(struct cmd *, struct cmd_ctx *); - -struct cmd_bind_key_data { - int key; - int can_repeat; - struct cmd_list *cmdlist; - - int command_key; - char *tablename; - char *modecmd; -}; +int cmd_bind_key_table(struct cmd *, struct cmd_ctx *, int); const struct cmd_entry cmd_bind_key_entry = { "bind-key", "bind", + "cnrt:", 1, -1, "[-cnr] [-t key-table] key command [arguments]", - 0, "", + 0, NULL, - cmd_bind_key_parse, - cmd_bind_key_exec, - cmd_bind_key_free, - cmd_bind_key_print + cmd_bind_key_check, + cmd_bind_key_exec }; int -cmd_bind_key_parse(struct cmd *self, int argc, char **argv, char **cause) +cmd_bind_key_check(struct args *args) { - struct cmd_bind_key_data *data; - int opt, no_prefix = 0; - - self->data = data = xmalloc(sizeof *data); - data->can_repeat = 0; - data->cmdlist = NULL; - data->command_key = 0; - data->tablename = NULL; - data->modecmd = NULL; - - while ((opt = getopt(argc, argv, "cnrt:")) != -1) { - switch (opt) { - case 'c': - data->command_key = 1; - break; - case 'n': - no_prefix = 1; - break; - case 'r': - data->can_repeat = 1; - break; - case 't': - if (data->tablename == NULL) - data->tablename = xstrdup(optarg); - break; - default: - goto usage; - } - } - argc -= optind; - argv += optind; - if (argc < 1) - goto usage; - - if ((data->key = key_string_lookup_string(argv[0])) == KEYC_NONE) { - xasprintf(cause, "unknown key: %s", argv[0]); - goto error; - } - if (!no_prefix) - data->key |= KEYC_PREFIX; - - argc--; - argv++; - if (data->tablename != NULL) { - if (argc != 1) - goto usage; - data->modecmd = xstrdup(argv[0]); + if (args_has(args, 't')) { + if (args->argc != 1) + return (-1); } else { - if ((data->cmdlist = cmd_list_parse(argc, argv, cause)) == NULL) - goto error; + if (args->argc < 2) + return (-1); + } + return (0); +} + +int +cmd_bind_key_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct args *args = self->args; + char *cause; + struct cmd_list *cmdlist; + int key; + + key = key_string_lookup_string(args->argv[0]); + if (key == KEYC_NONE) { + ctx->error(ctx, "unknown key: %s", args->argv[0]); + return (-1); } - return (0); + if (args_has(args, 't')) + return (cmd_bind_key_table(self, ctx, key)); -usage: - xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); - -error: - self->entry->free(self); - return (-1); -} - -int -cmd_bind_key_exec(struct cmd *self, unused struct cmd_ctx *ctx) -{ - struct cmd_bind_key_data *data = self->data; - - if (data == NULL) - return (0); - if (data->tablename != NULL) - return (cmd_bind_key_table(self, ctx)); - - key_bindings_add(data->key, data->can_repeat, data->cmdlist); - data->cmdlist->references++; + cmdlist = cmd_list_parse(args->argc - 1, args->argv + 1, &cause); + if (cmdlist == NULL) { + ctx->error(ctx, "%s", cause); + xfree(cause); + return (-1); + } + if (!args_has(args, 'n')) + key |= KEYC_PREFIX; + key_bindings_add(key, args_has(args, 'r'), cmdlist); return (0); } int -cmd_bind_key_table(struct cmd *self, struct cmd_ctx *ctx) +cmd_bind_key_table(struct cmd *self, struct cmd_ctx *ctx, int key) { - struct cmd_bind_key_data *data = self->data; + struct args *args = self->args; + const char *tablename; const struct mode_key_table *mtab; struct mode_key_binding *mbind, mtmp; enum mode_key_cmd cmd; - if ((mtab = mode_key_findtable(data->tablename)) == NULL) { - ctx->error(ctx, "unknown key table: %s", data->tablename); + tablename = args_get(args, 't'); + if ((mtab = mode_key_findtable(tablename)) == NULL) { + ctx->error(ctx, "unknown key table: %s", tablename); return (-1); } - cmd = mode_key_fromstring(mtab->cmdstr, data->modecmd); + cmd = mode_key_fromstring(mtab->cmdstr, args->argv[0]); if (cmd == MODEKEY_NONE) { - ctx->error(ctx, "unknown command: %s", data->modecmd); + ctx->error(ctx, "unknown command: %s", args->argv[0]); return (-1); } - mtmp.key = data->key & ~KEYC_PREFIX; - mtmp.mode = data->command_key ? 1 : 0; + mtmp.key = key; + mtmp.mode = !!args_has(args, 'c'); if ((mbind = SPLAY_FIND(mode_key_tree, mtab->tree, &mtmp)) != NULL) { mbind->cmd = cmd; return (0); @@ -167,45 +118,3 @@ cmd_bind_key_table(struct cmd *self, struct cmd_ctx *ctx) SPLAY_INSERT(mode_key_tree, mtab->tree, mbind); return (0); } - -void -cmd_bind_key_free(struct cmd *self) -{ - struct cmd_bind_key_data *data = self->data; - - if (data->cmdlist != NULL) - cmd_list_free(data->cmdlist); - if (data->tablename != NULL) - xfree(data->tablename); - if (data->modecmd != NULL) - xfree(data->modecmd); - xfree(data); -} - -size_t -cmd_bind_key_print(struct cmd *self, char *buf, size_t len) -{ - struct cmd_bind_key_data *data = self->data; - size_t off = 0; - const char *skey; - - off += xsnprintf(buf, len, "%s", self->entry->name); - if (data == NULL) - return (off); - - if (off < len && data->command_key) - off += xsnprintf(buf + off, len - off, " -c"); - if (off < len && !(data->key & KEYC_PREFIX)) - off += xsnprintf(buf + off, len - off, " -n"); - if (off < len && data->can_repeat) - off += xsnprintf(buf + off, len - off, " -r"); - if (off < len && data->tablename != NULL) - off += cmd_prarg(buf + off, len - off, " -t ", data->tablename); - if (off < len) { - skey = key_string_lookup_key(data->key & ~KEYC_PREFIX); - off += xsnprintf(buf + off, len - off, " %s ", skey); - } - if (off < len) - off += cmd_list_print(data->cmdlist, buf + off, len - off); - return (off); -} diff --git a/cmd-break-pane.c b/cmd-break-pane.c index d5f847fb..4c57a116 100644 --- a/cmd-break-pane.c +++ b/cmd-break-pane.c @@ -30,19 +30,18 @@ int cmd_break_pane_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_break_pane_entry = { "break-pane", "breakp", - CMD_TARGET_PANE_USAGE " [-d]", - 0, "d", - cmd_target_init, - cmd_target_parse, - cmd_break_pane_exec, - cmd_target_free, - cmd_target_print + "dt:", 0, 0, + "[-d] " CMD_TARGET_PANE_USAGE, + 0, + NULL, + NULL, + cmd_break_pane_exec }; int cmd_break_pane_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; + struct args *args = self->args; struct winlink *wl; struct session *s; struct window_pane *wp; @@ -50,7 +49,7 @@ cmd_break_pane_exec(struct cmd *self, struct cmd_ctx *ctx) char *cause; int base_idx; - if ((wl = cmd_find_pane(ctx, data->target, &s, &wp)) == NULL) + if ((wl = cmd_find_pane(ctx, args_get(args, 't'), &s, &wp)) == NULL) return (-1); if (window_count_panes(wl->window) == 1) { @@ -74,7 +73,7 @@ cmd_break_pane_exec(struct cmd *self, struct cmd_ctx *ctx) base_idx = options_get_number(&s->options, "base-index"); wl = session_attach(s, w, -1 - base_idx, &cause); /* can't fail */ - if (!cmd_check_flag(data->chflags, 'd')) + if (!args_has(self->args, 'd')) session_select(s, wl->idx); server_redraw_session(s); diff --git a/cmd-capture-pane.c b/cmd-capture-pane.c index c711db42..6efbfe97 100644 --- a/cmd-capture-pane.c +++ b/cmd-capture-pane.c @@ -27,93 +27,30 @@ * Write the entire contents of a pane to a buffer. */ -int cmd_capture_pane_parse(struct cmd *, int, char **, char **); int cmd_capture_pane_exec(struct cmd *, struct cmd_ctx *); -void cmd_capture_pane_free(struct cmd *); -void cmd_capture_pane_init(struct cmd *, int); -size_t cmd_capture_pane_print(struct cmd *, char *, size_t); - -struct cmd_capture_pane_data { - char *target; - int buffer; -}; const struct cmd_entry cmd_capture_pane_entry = { "capture-pane", "capturep", + "b:t:", 0, 0, "[-b buffer-index] [-t target-pane]", - 0, "", - cmd_capture_pane_init, - cmd_capture_pane_parse, - cmd_capture_pane_exec, - cmd_capture_pane_free, - cmd_capture_pane_print + 0, + NULL, + NULL, + cmd_capture_pane_exec }; -/* ARGSUSED */ -void -cmd_capture_pane_init(struct cmd *self, unused int arg) -{ - struct cmd_capture_pane_data *data; - - self->data = data = xmalloc(sizeof *data); - data->buffer = -1; - data->target = NULL; -} - -int -cmd_capture_pane_parse(struct cmd *self, int argc, char **argv, char **cause) -{ - struct cmd_capture_pane_data *data; - const char *errstr; - int n, opt; - - self->entry->init(self, KEYC_NONE); - data = self->data; - - while ((opt = getopt(argc, argv, "b:t:")) != -1) { - switch (opt) { - case 'b': - if (data->buffer == -1) { - n = strtonum(optarg, 0, INT_MAX, &errstr); - if (errstr != NULL) { - xasprintf(cause, "buffer %s", errstr); - goto error; - } - data->buffer = n; - } - break; - case 't': - if (data->target == NULL) - data->target = xstrdup(optarg); - break; - default: - goto usage; - } - } - argc -= optind; - argv += optind; - - return (0); - -usage: - xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); - -error: - self->entry->free(self); - return (-1); -} - int cmd_capture_pane_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_capture_pane_data *data = self->data; - struct window_pane *wp; - char *buf, *line; - struct screen *s; - u_int i, limit; - size_t len, linelen; + struct args *args = self->args; + struct window_pane *wp; + char *buf, *line, *cause; + struct screen *s; + int buffer; + u_int i, limit; + size_t len, linelen; - if (cmd_find_pane(ctx, data->target, NULL, &wp) == NULL) + if (cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp) == NULL) return (-1); s = &wp->base; @@ -133,40 +70,24 @@ cmd_capture_pane_exec(struct cmd *self, struct cmd_ctx *ctx) } limit = options_get_number(&global_options, "buffer-limit"); - if (data->buffer == -1) { + + if (!args_has(args, 'b')) { paste_add(&global_buffers, buf, len, limit); return (0); } - if (paste_replace(&global_buffers, data->buffer, buf, len) != 0) { - ctx->error(ctx, "no buffer %d", data->buffer); + + buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause); + if (cause != NULL) { + ctx->error(ctx, "buffer %s", cause); + xfree(cause); + return (-1); + } + + if (paste_replace(&global_buffers, buffer, buf, len) != 0) { + ctx->error(ctx, "no buffer %d", buffer); xfree(buf); return (-1); } + return (0); } - -void -cmd_capture_pane_free(struct cmd *self) -{ - struct cmd_capture_pane_data *data = self->data; - - if (data->target != NULL) - xfree(data->target); - xfree(data); -} - -size_t -cmd_capture_pane_print(struct cmd *self, char *buf, size_t len) -{ - struct cmd_capture_pane_data *data = self->data; - size_t off = 0; - - off += xsnprintf(buf, len, "%s", self->entry->name); - if (data == NULL) - return (off); - if (off < len && data->buffer != -1) - off += xsnprintf(buf + off, len - off, " -b %d", data->buffer); - if (off < len && data->target != NULL) - off += xsnprintf(buf + off, len - off, " -t %s", data->target); - return (off); -} diff --git a/cmd-choose-buffer.c b/cmd-choose-buffer.c index 32bf2f2d..c1093f92 100644 --- a/cmd-choose-buffer.c +++ b/cmd-choose-buffer.c @@ -33,24 +33,23 @@ void cmd_choose_buffer_free(void *); const struct cmd_entry cmd_choose_buffer_entry = { "choose-buffer", NULL, + "t:", 0, 1, CMD_TARGET_WINDOW_USAGE " [template]", - CMD_ARG01, "", - cmd_target_init, - cmd_target_parse, - cmd_choose_buffer_exec, - cmd_target_free, - cmd_target_print + 0, + NULL, + NULL, + cmd_choose_buffer_exec }; struct cmd_choose_buffer_data { - struct client *client; - char *template; + struct client *client; + char *template; }; int cmd_choose_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; + struct args *args = self->args; struct cmd_choose_buffer_data *cdata; struct winlink *wl; struct paste_buffer *pb; @@ -62,7 +61,7 @@ cmd_choose_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) return (-1); } - if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) + if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL) return (-1); if (paste_get_top(&global_buffers) == NULL) @@ -80,8 +79,8 @@ cmd_choose_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) } cdata = xmalloc(sizeof *cdata); - if (data->arg != NULL) - cdata->template = xstrdup(data->arg); + if (args->argc != 0) + cdata->template = xstrdup(args->argv[0]); else cdata->template = xstrdup("paste-buffer -b '%%'"); cdata->client = ctx->curclient; diff --git a/cmd-choose-client.c b/cmd-choose-client.c index cd5ab9ea..ac766ab5 100644 --- a/cmd-choose-client.c +++ b/cmd-choose-client.c @@ -33,13 +33,12 @@ void cmd_choose_client_free(void *); const struct cmd_entry cmd_choose_client_entry = { "choose-client", NULL, + "t:", 0, 1, CMD_TARGET_WINDOW_USAGE " [template]", - CMD_ARG01, "", - cmd_target_init, - cmd_target_parse, - cmd_choose_client_exec, - cmd_target_free, - cmd_target_print + 0, + NULL, + NULL, + cmd_choose_client_exec }; struct cmd_choose_client_data { @@ -50,7 +49,7 @@ struct cmd_choose_client_data { int cmd_choose_client_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; + struct args *args = self->args; struct cmd_choose_client_data *cdata; struct winlink *wl; struct client *c; @@ -61,7 +60,7 @@ cmd_choose_client_exec(struct cmd *self, struct cmd_ctx *ctx) return (-1); } - if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) + if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL) return (-1); if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0) @@ -83,8 +82,8 @@ cmd_choose_client_exec(struct cmd *self, struct cmd_ctx *ctx) } cdata = xmalloc(sizeof *cdata); - if (data->arg != NULL) - cdata->template = xstrdup(data->arg); + if (args->argc != 0) + cdata->template = xstrdup(args->argv[0]); else cdata->template = xstrdup("detach-client -t '%%'"); cdata->client = ctx->curclient; diff --git a/cmd-choose-session.c b/cmd-choose-session.c index cf36fe98..5aa0877b 100644 --- a/cmd-choose-session.c +++ b/cmd-choose-session.c @@ -33,13 +33,12 @@ void cmd_choose_session_free(void *); const struct cmd_entry cmd_choose_session_entry = { "choose-session", NULL, + "t:", 0, 1, CMD_TARGET_WINDOW_USAGE " [template]", - CMD_ARG01, "", - cmd_target_init, - cmd_target_parse, - cmd_choose_session_exec, - cmd_target_free, - cmd_target_print + 0, + NULL, + NULL, + cmd_choose_session_exec }; struct cmd_choose_session_data { @@ -50,7 +49,7 @@ struct cmd_choose_session_data { int cmd_choose_session_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; + struct args *args = self->args; struct cmd_choose_session_data *cdata; struct winlink *wl; struct session *s; @@ -63,7 +62,7 @@ cmd_choose_session_exec(struct cmd *self, struct cmd_ctx *ctx) return (-1); } - if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) + if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL) return (-1); if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0) @@ -90,8 +89,8 @@ cmd_choose_session_exec(struct cmd *self, struct cmd_ctx *ctx) } cdata = xmalloc(sizeof *cdata); - if (data->arg != NULL) - cdata->template = xstrdup(data->arg); + if (args->argc != 0) + cdata->template = xstrdup(args->argv[0]); else cdata->template = xstrdup("switch-client -t '%%'"); cdata->client = ctx->curclient; diff --git a/cmd-choose-window.c b/cmd-choose-window.c index 1bbe0dfe..a1280927 100644 --- a/cmd-choose-window.c +++ b/cmd-choose-window.c @@ -33,13 +33,12 @@ void cmd_choose_window_free(void *); const struct cmd_entry cmd_choose_window_entry = { "choose-window", NULL, + "t:", 0, 1, CMD_TARGET_WINDOW_USAGE " [template]", - CMD_ARG01, "", - cmd_target_init, - cmd_target_parse, - cmd_choose_window_exec, - cmd_target_free, - cmd_target_print + 0, + NULL, + NULL, + cmd_choose_window_exec }; struct cmd_choose_window_data { @@ -51,7 +50,7 @@ struct cmd_choose_window_data { int cmd_choose_window_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; + struct args *args = self->args; struct cmd_choose_window_data *cdata; struct session *s; struct winlink *wl, *wm; @@ -66,7 +65,7 @@ cmd_choose_window_exec(struct cmd *self, struct cmd_ctx *ctx) } s = ctx->curclient->session; - if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) + if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL) return (-1); if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0) @@ -99,8 +98,8 @@ cmd_choose_window_exec(struct cmd *self, struct cmd_ctx *ctx) } cdata = xmalloc(sizeof *cdata); - if (data->arg != NULL) - cdata->template = xstrdup(data->arg); + if (args->argc != 0) + cdata->template = xstrdup(args->argv[0]); else cdata->template = xstrdup("select-window -t '%%'"); cdata->session = s; diff --git a/cmd-clear-history.c b/cmd-clear-history.c index 9241485a..cf3da229 100644 --- a/cmd-clear-history.c +++ b/cmd-clear-history.c @@ -28,23 +28,22 @@ int cmd_clear_history_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_clear_history_entry = { "clear-history", "clearhist", + "t:", 0, 0, CMD_TARGET_PANE_USAGE, - 0, "", - cmd_target_init, - cmd_target_parse, - cmd_clear_history_exec, - cmd_target_free, - cmd_target_print + 0, + NULL, + NULL, + cmd_clear_history_exec }; int cmd_clear_history_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; + struct args *args = self->args; struct window_pane *wp; struct grid *gd; - if (cmd_find_pane(ctx, data->target, NULL, &wp) == NULL) + if (cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp) == NULL) return (-1); gd = wp->base.grid; diff --git a/cmd-clock-mode.c b/cmd-clock-mode.c index 4df934f7..0dc151d1 100644 --- a/cmd-clock-mode.c +++ b/cmd-clock-mode.c @@ -28,22 +28,21 @@ int cmd_clock_mode_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_clock_mode_entry = { "clock-mode", NULL, + "t:", 0, 0, CMD_TARGET_PANE_USAGE, - 0, "", - cmd_target_init, - cmd_target_parse, - cmd_clock_mode_exec, - cmd_target_free, - cmd_target_print + 0, + NULL, + NULL, + cmd_clock_mode_exec }; int cmd_clock_mode_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; + struct args *args = self->args; struct window_pane *wp; - if (cmd_find_pane(ctx, data->target, NULL, &wp) == NULL) + if (cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp) == NULL) return (-1); window_pane_set_mode(wp, &window_clock_mode); diff --git a/cmd-command-prompt.c b/cmd-command-prompt.c index b76ea8d1..db50adc7 100644 --- a/cmd-command-prompt.c +++ b/cmd-command-prompt.c @@ -27,30 +27,21 @@ * Prompt for command in client. */ -void cmd_command_prompt_init(struct cmd *, int); -int cmd_command_prompt_parse(struct cmd *, int, char **, char **); -int cmd_command_prompt_exec(struct cmd *, struct cmd_ctx *); -void cmd_command_prompt_free(struct cmd *); -size_t cmd_command_prompt_print(struct cmd *, char *, size_t); +void cmd_command_prompt_key_binding(struct cmd *, int); +int cmd_command_prompt_check(struct args *); +int cmd_command_prompt_exec(struct cmd *, struct cmd_ctx *); -int cmd_command_prompt_callback(void *, const char *); -void cmd_command_prompt_cfree(void *); +int cmd_command_prompt_callback(void *, const char *); +void cmd_command_prompt_free(void *); const struct cmd_entry cmd_command_prompt_entry = { "command-prompt", NULL, + "p:t:", 0, 0, CMD_TARGET_CLIENT_USAGE " [-p prompts] [template]", - 0, "", - cmd_command_prompt_init, - cmd_command_prompt_parse, - cmd_command_prompt_exec, - cmd_command_prompt_free, - cmd_command_prompt_print -}; - -struct cmd_command_prompt_data { - char *prompts; - char *target; - char *template; + 0, + cmd_command_prompt_key_binding, + NULL, + cmd_command_prompt_exec }; struct cmd_command_prompt_cdata { @@ -62,82 +53,39 @@ struct cmd_command_prompt_cdata { }; void -cmd_command_prompt_init(struct cmd *self, int key) +cmd_command_prompt_key_binding(struct cmd *self, int key) { - struct cmd_command_prompt_data *data; - - self->data = data = xmalloc(sizeof *data); - data->prompts = NULL; - data->target = NULL; - data->template = NULL; - switch (key) { case ',': - data->template = xstrdup("rename-window '%%'"); + self->args = args_create(1, "rename-window '%%'"); break; case '.': - data->template = xstrdup("move-window -t '%%'"); + self->args = args_create(1, "move-window -t '%%'"); break; case 'f': - data->template = xstrdup("find-window '%%'"); + self->args = args_create(1, "find-window '%%'"); break; case '\'': - data->template = xstrdup("select-window -t ':%%'"); - data->prompts = xstrdup("index"); + self->args = args_create(1, "select-window -t ':%%'"); + args_set(self->args, 'p', "index"); + break; + default: + self->args = args_create(0); break; } } -int -cmd_command_prompt_parse(struct cmd *self, int argc, char **argv, char **cause) -{ - struct cmd_command_prompt_data *data; - int opt; - - self->entry->init(self, KEYC_NONE); - data = self->data; - - while ((opt = getopt(argc, argv, "p:t:")) != -1) { - switch (opt) { - case 'p': - if (data->prompts == NULL) - data->prompts = xstrdup(optarg); - break; - case 't': - if (data->target == NULL) - data->target = xstrdup(optarg); - break; - default: - goto usage; - } - } - argc -= optind; - argv += optind; - if (argc != 0 && argc != 1) - goto usage; - - if (argc == 1) - data->template = xstrdup(argv[0]); - - return (0); - -usage: - xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); - - self->entry->free(self); - return (-1); -} - int cmd_command_prompt_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_command_prompt_data *data = self->data; + struct args *args = self->args; + const char *prompts; struct cmd_command_prompt_cdata *cdata; struct client *c; char *prompt, *ptr; size_t n; - if ((c = cmd_find_client(ctx, data->target)) == NULL) + if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL) return (-1); if (c->prompt_string != NULL) @@ -150,63 +98,33 @@ cmd_command_prompt_exec(struct cmd *self, struct cmd_ctx *ctx) cdata->prompts = NULL; cdata->template = NULL; - if (data->template != NULL) - cdata->template = xstrdup(data->template); + if (args->argc != 0) + cdata->template = xstrdup(args->argv[0]); else cdata->template = xstrdup("%1"); - if (data->prompts != NULL) - cdata->prompts = xstrdup(data->prompts); - else if (data->template != NULL) { - n = strcspn(data->template, " ,"); - xasprintf(&cdata->prompts, "(%.*s) ", (int) n, data->template); + + prompts = args_get(args, 'p'); + if (prompts != NULL) + cdata->prompts = xstrdup(prompts); + else if (args->argc != 0) { + n = strcspn(cdata->template, " ,"); + xasprintf(&cdata->prompts, "(%.*s) ", (int) n, cdata->template); } else cdata->prompts = xstrdup(":"); cdata->next_prompt = cdata->prompts; ptr = strsep(&cdata->next_prompt, ","); - if (data->prompts == NULL) + if (prompts == NULL) prompt = xstrdup(ptr); else xasprintf(&prompt, "%s ", ptr); status_prompt_set(c, prompt, cmd_command_prompt_callback, - cmd_command_prompt_cfree, cdata, 0); + cmd_command_prompt_free, cdata, 0); xfree(prompt); return (0); } -void -cmd_command_prompt_free(struct cmd *self) -{ - struct cmd_command_prompt_data *data = self->data; - - if (data->prompts != NULL) - xfree(data->prompts); - if (data->target != NULL) - xfree(data->target); - if (data->template != NULL) - xfree(data->template); - xfree(data); -} - -size_t -cmd_command_prompt_print(struct cmd *self, char *buf, size_t len) -{ - struct cmd_command_prompt_data *data = self->data; - size_t off = 0; - - off += xsnprintf(buf, len, "%s", self->entry->name); - if (data == NULL) - return (off); - if (off < len && data->prompts != NULL) - off += cmd_prarg(buf + off, len - off, " -p ", data->prompts); - if (off < len && data->target != NULL) - off += cmd_prarg(buf + off, len - off, " -t ", data->target); - if (off < len && data->template != NULL) - off += cmd_prarg(buf + off, len - off, " ", data->template); - return (off); -} - int cmd_command_prompt_callback(void *data, const char *s) { @@ -258,7 +176,7 @@ cmd_command_prompt_callback(void *data, const char *s) } void -cmd_command_prompt_cfree(void *data) +cmd_command_prompt_free(void *data) { struct cmd_command_prompt_cdata *cdata = data; diff --git a/cmd-confirm-before.c b/cmd-confirm-before.c index cdde81ac..b19d69d7 100644 --- a/cmd-confirm-before.c +++ b/cmd-confirm-before.c @@ -25,21 +25,20 @@ * Asks for confirmation before executing a command. */ +void cmd_confirm_before_key_binding(struct cmd *, int); int cmd_confirm_before_exec(struct cmd *, struct cmd_ctx *); -void cmd_confirm_before_init(struct cmd *, int); int cmd_confirm_before_callback(void *, const char *); void cmd_confirm_before_free(void *); const struct cmd_entry cmd_confirm_before_entry = { "confirm-before", "confirm", + "t:", 1, 1, CMD_TARGET_CLIENT_USAGE " command", - CMD_ARG1, "", - cmd_confirm_before_init, - cmd_target_parse, - cmd_confirm_before_exec, - cmd_target_free, - cmd_target_print + 0, + cmd_confirm_before_key_binding, + NULL, + cmd_confirm_before_exec }; struct cmd_confirm_before_data { @@ -48,19 +47,17 @@ struct cmd_confirm_before_data { }; void -cmd_confirm_before_init(struct cmd *self, int key) +cmd_confirm_before_key_binding(struct cmd *self, int key) { - struct cmd_target_data *data; - - cmd_target_init(self, key); - data = self->data; - switch (key) { case '&': - data->arg = xstrdup("kill-window"); + self->args = args_create(1, "kill-window"); break; case 'x': - data->arg = xstrdup("kill-pane"); + self->args = args_create(1, "kill-pane"); + break; + default: + self->args = args_create(0); break; } } @@ -68,7 +65,7 @@ cmd_confirm_before_init(struct cmd *self, int key) int cmd_confirm_before_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; + struct args *args = self->args; struct cmd_confirm_before_data *cdata; struct client *c; char *buf, *cmd, *ptr; @@ -78,17 +75,17 @@ cmd_confirm_before_exec(struct cmd *self, struct cmd_ctx *ctx) return (-1); } - if ((c = cmd_find_client(ctx, data->target)) == NULL) + if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL) return (-1); - ptr = xstrdup(data->arg); + ptr = xstrdup(args->argv[0]); if ((cmd = strtok(ptr, " \t")) == NULL) cmd = ptr; xasprintf(&buf, "Confirm '%s'? (y/n) ", cmd); xfree(ptr); cdata = xmalloc(sizeof *cdata); - cdata->cmd = xstrdup(data->arg); + cdata->cmd = xstrdup(args->argv[0]); cdata->c = c; status_prompt_set(cdata->c, buf, cmd_confirm_before_callback, cmd_confirm_before_free, cdata, diff --git a/cmd-copy-mode.c b/cmd-copy-mode.c index 3e858a33..b9290593 100644 --- a/cmd-copy-mode.c +++ b/cmd-copy-mode.c @@ -24,48 +24,40 @@ * Enter copy mode. */ -void cmd_copy_mode_init(struct cmd *, int); +void cmd_copy_mode_key_binding(struct cmd *, int); int cmd_copy_mode_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_copy_mode_entry = { "copy-mode", NULL, + "t:u", 0, 0, "[-u] " CMD_TARGET_PANE_USAGE, - 0, "u", - cmd_copy_mode_init, - cmd_target_parse, - cmd_copy_mode_exec, - cmd_target_free, - cmd_target_print + 0, + cmd_copy_mode_key_binding, + NULL, + cmd_copy_mode_exec }; void -cmd_copy_mode_init(struct cmd *self, int key) +cmd_copy_mode_key_binding(struct cmd *self, int key) { - struct cmd_target_data *data; - - cmd_target_init(self, key); - data = self->data; - - switch (key) { - case KEYC_PPAGE: - cmd_set_flag(&data->chflags, 'u'); - break; - } + self->args = args_create(0); + if (key == KEYC_PPAGE) + args_set(self->args, 'u', NULL); } int cmd_copy_mode_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; + struct args *args = self->args; struct window_pane *wp; - if (cmd_find_pane(ctx, data->target, NULL, &wp) == NULL) + if (cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp) == NULL) return (-1); if (window_pane_set_mode(wp, &window_copy_mode) != 0) return (0); window_copy_init_from_pane(wp); - if (wp->mode == &window_copy_mode && cmd_check_flag(data->chflags, 'u')) + if (wp->mode == &window_copy_mode && args_has(self->args, 'u')) window_copy_pageup(wp); return (0); diff --git a/cmd-delete-buffer.c b/cmd-delete-buffer.c index 0bfd77ae..3f0578ed 100644 --- a/cmd-delete-buffer.c +++ b/cmd-delete-buffer.c @@ -30,24 +30,35 @@ int cmd_delete_buffer_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_delete_buffer_entry = { "delete-buffer", "deleteb", + "b:", 0, 0, CMD_BUFFER_USAGE, - 0, "", - cmd_buffer_init, - cmd_buffer_parse, - cmd_delete_buffer_exec, - cmd_buffer_free, - cmd_buffer_print + 0, + NULL, + NULL, + cmd_delete_buffer_exec }; int cmd_delete_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_buffer_data *data = self->data; + struct args *args = self->args; + char *cause; + int buffer; - if (data->buffer == -1) + if (!args_has(args, 'b')) { paste_free_top(&global_buffers); - else if (paste_free_index(&global_buffers, data->buffer) != 0) { - ctx->error(ctx, "no buffer %d", data->buffer); + return (0); + } + + buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause); + if (cause != NULL) { + ctx->error(ctx, "buffer %s", cause); + xfree(cause); + return (-1); + } + + if (paste_free_index(&global_buffers, buffer) != 0) { + ctx->error(ctx, "no buffer %d", buffer); return (-1); } diff --git a/cmd-detach-client.c b/cmd-detach-client.c index a2288036..03789bd8 100644 --- a/cmd-detach-client.c +++ b/cmd-detach-client.c @@ -28,22 +28,21 @@ int cmd_detach_client_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_detach_client_entry = { "detach-client", "detach", + "t:", 0, 0, CMD_TARGET_CLIENT_USAGE, - CMD_READONLY, "", - cmd_target_init, - cmd_target_parse, - cmd_detach_client_exec, - cmd_target_free, - cmd_target_print + CMD_READONLY, + NULL, + NULL, + cmd_detach_client_exec }; int cmd_detach_client_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; - struct client *c; + struct args *args = self->args; + struct client *c; - if ((c = cmd_find_client(ctx, data->target)) == NULL) + if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL) return (-1); server_write_client(c, MSG_DETACH, NULL, 0); diff --git a/cmd-display-message.c b/cmd-display-message.c index 8c42ee6d..baf6fb9d 100644 --- a/cmd-display-message.c +++ b/cmd-display-message.c @@ -30,33 +30,32 @@ int cmd_display_message_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_display_message_entry = { "display-message", "display", + "pt:", 0, 1, "[-p] " CMD_TARGET_CLIENT_USAGE " [message]", - CMD_ARG01, "p", - cmd_target_init, - cmd_target_parse, - cmd_display_message_exec, - cmd_target_free, - cmd_target_print + 0, + NULL, + NULL, + cmd_display_message_exec }; int cmd_display_message_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; + struct args *args = self->args; struct client *c; const char *template; char *msg; - if ((c = cmd_find_client(ctx, data->target)) == NULL) + if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL) return (-1); - if (data->arg == NULL) + if (args->argc == 0) template = "[#S] #I:#W, current pane #P - (%H:%M %d-%b-%y)"; else - template = data->arg; + template = args->argv[0]; msg = status_replace(c, NULL, template, time(NULL), 0); - if (cmd_check_flag(data->chflags, 'p')) + if (args_has(self->args, 'p')) ctx->print(ctx, "%s", msg); else status_message_set(c, "%s", msg); diff --git a/cmd-display-panes.c b/cmd-display-panes.c index 42ecbb9b..bc64b4b5 100644 --- a/cmd-display-panes.c +++ b/cmd-display-panes.c @@ -28,22 +28,21 @@ int cmd_display_panes_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_display_panes_entry = { "display-panes", "displayp", + "t:", 0, 0, CMD_TARGET_CLIENT_USAGE, - 0, "", - cmd_target_init, - cmd_target_parse, - cmd_display_panes_exec, - cmd_target_free, - cmd_target_print + 0, + NULL, + NULL, + cmd_display_panes_exec }; int cmd_display_panes_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; - struct client *c; + struct args *args = self->args; + struct client *c; - if ((c = cmd_find_client(ctx, data->target)) == NULL) + if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL) return (-1); server_set_identify(c); diff --git a/cmd-find-window.c b/cmd-find-window.c index 482d9243..6c3c48ce 100644 --- a/cmd-find-window.c +++ b/cmd-find-window.c @@ -34,13 +34,12 @@ void cmd_find_window_free(void *); const struct cmd_entry cmd_find_window_entry = { "find-window", "findw", + "t:", 1, 1, CMD_TARGET_WINDOW_USAGE " match-string", - CMD_ARG1, "", - cmd_target_init, - cmd_target_parse, - cmd_find_window_exec, - cmd_target_free, - cmd_target_print + 0, + NULL, + NULL, + cmd_find_window_exec }; struct cmd_find_window_data { @@ -50,7 +49,7 @@ struct cmd_find_window_data { int cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; + struct args *args = self->args; struct cmd_find_window_data *cdata; struct session *s; struct winlink *wl, *wm; @@ -58,7 +57,7 @@ cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx) struct window_pane *wp; ARRAY_DECL(, u_int) list_idx; ARRAY_DECL(, char *) list_ctx; - char *sres, *sctx, *searchstr; + char *str, *sres, *sctx, *searchstr; u_int i, line; if (ctx->curclient == NULL) { @@ -67,13 +66,15 @@ cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx) } s = ctx->curclient->session; - if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) + if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL) return (-1); + str = args->argv[0]; + ARRAY_INIT(&list_idx); ARRAY_INIT(&list_ctx); - xasprintf(&searchstr, "*%s*", data->arg); + xasprintf(&searchstr, "*%s*", str); RB_FOREACH(wm, winlinks, &s->windows) { i = 0; TAILQ_FOREACH(wp, &wm->window->panes, entry) { @@ -82,7 +83,7 @@ cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx) if (fnmatch(searchstr, wm->window->name, 0) == 0) sctx = xstrdup(""); else { - sres = window_pane_search(wp, data->arg, &line); + sres = window_pane_search(wp, str, &line); if (sres == NULL && fnmatch(searchstr, wp->base.title, 0) != 0) continue; @@ -106,7 +107,7 @@ cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx) xfree(searchstr); if (ARRAY_LENGTH(&list_idx) == 0) { - ctx->error(ctx, "no windows matching: %s", data->arg); + ctx->error(ctx, "no windows matching: %s", str); ARRAY_FREE(&list_idx); ARRAY_FREE(&list_ctx); return (-1); diff --git a/cmd-generic.c b/cmd-generic.c deleted file mode 100644 index 97e731c9..00000000 --- a/cmd-generic.c +++ /dev/null @@ -1,414 +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 "tmux.h" - -int cmd_getopt(int, char **, const char *, const char *); -int cmd_parse_flags(int, const char *, uint64_t *); -size_t cmd_print_flags(char *, size_t, size_t, uint64_t); -int cmd_fill_argument(int, char **, char **, int, char **); - -size_t -cmd_prarg(char *buf, size_t len, const char *prefix, char *arg) -{ - if (strchr(arg, ' ') != NULL) - return (xsnprintf(buf, len, "%s\"%s\"", prefix, arg)); - return (xsnprintf(buf, len, "%s%s", prefix, arg)); -} - -/* Append two flag strings together and call getopt. */ -int -cmd_getopt(int argc, char **argv, const char *flagstr, const char *chflagstr) -{ - char tmp[BUFSIZ]; - - if (strlcpy(tmp, flagstr, sizeof tmp) >= sizeof tmp) - fatalx("strlcpy overflow"); - if (strlcat(tmp, chflagstr, sizeof tmp) >= sizeof tmp) - fatalx("strlcat overflow"); - return (getopt(argc, argv, tmp)); -} - -/* Return if flag character is set. */ -int -cmd_check_flag(uint64_t chflags, int flag) -{ - if (flag >= 'A' && flag <= 'Z') - flag = 26 + flag - 'A'; - else if (flag >= 'a' && flag <= 'z') - flag = flag - 'a'; - else - return (0); - return ((chflags & (1ULL << flag)) != 0); -} - -/* Set flag character. */ -void -cmd_set_flag(uint64_t *chflags, int flag) -{ - if (flag >= 'A' && flag <= 'Z') - flag = 26 + flag - 'A'; - else if (flag >= 'a' && flag <= 'z') - flag = flag - 'a'; - else - return; - (*chflags) |= (1ULL << flag); -} - -/* If this option is expected, set it in chflags, otherwise return -1. */ -int -cmd_parse_flags(int opt, const char *chflagstr, uint64_t *chflags) -{ - if (strchr(chflagstr, opt) == NULL) - return (-1); - cmd_set_flag(chflags, opt); - return (0); -} - -/* Print the flags present in chflags. */ -size_t -cmd_print_flags(char *buf, size_t len, size_t off, uint64_t chflags) -{ - u_char ch; - size_t boff = off; - - if (chflags == 0) - return (0); - off += xsnprintf(buf + off, len - off, " -"); - - for (ch = 0; ch < 26; ch++) { - if (cmd_check_flag(chflags, 'a' + ch)) - off += xsnprintf(buf + off, len - off, "%c", 'a' + ch); - if (cmd_check_flag(chflags, 'A' + ch)) - off += xsnprintf(buf + off, len - off, "%c", 'A' + ch); - } - return (off - boff); -} - -int -cmd_fill_argument(int flags, char **arg, char **arg2, int argc, char **argv) -{ - *arg = NULL; - *arg2 = NULL; - - if (flags & CMD_ARG1) { - if (argc != 1) - return (-1); - *arg = xstrdup(argv[0]); - return (0); - } - - if (flags & CMD_ARG01) { - if (argc != 0 && argc != 1) - return (-1); - if (argc == 1) - *arg = xstrdup(argv[0]); - return (0); - } - - if (flags & CMD_ARG2) { - if (argc != 2) - return (-1); - *arg = xstrdup(argv[0]); - *arg2 = xstrdup(argv[1]); - return (0); - } - - if (flags & CMD_ARG12) { - if (argc != 1 && argc != 2) - return (-1); - *arg = xstrdup(argv[0]); - if (argc == 2) - *arg2 = xstrdup(argv[1]); - return (0); - } - - if (argc != 0) - return (-1); - return (0); -} - -/* ARGSUSED */ -void -cmd_target_init(struct cmd *self, unused int key) -{ - struct cmd_target_data *data; - - self->data = data = xmalloc(sizeof *data); - data->chflags = 0; - data->target = NULL; - data->arg = NULL; - data->arg2 = NULL; -} - -int -cmd_target_parse(struct cmd *self, int argc, char **argv, char **cause) -{ - struct cmd_target_data *data; - const struct cmd_entry *entry = self->entry; - int opt; - - /* Don't use the entry version since it may be dependent on key. */ - cmd_target_init(self, 0); - data = self->data; - - while ((opt = cmd_getopt(argc, argv, "t:", entry->chflags)) != -1) { - if (cmd_parse_flags(opt, entry->chflags, &data->chflags) == 0) - continue; - switch (opt) { - case 't': - if (data->target == NULL) - data->target = xstrdup(optarg); - break; - default: - goto usage; - } - } - argc -= optind; - argv += optind; - - if (cmd_fill_argument( - self->entry->flags, &data->arg, &data->arg2, argc, argv) != 0) - goto usage; - return (0); - -usage: - xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); - - self->entry->free(self); - return (-1); -} - -void -cmd_target_free(struct cmd *self) -{ - struct cmd_target_data *data = self->data; - - if (data->target != NULL) - xfree(data->target); - if (data->arg != NULL) - xfree(data->arg); - if (data->arg2 != NULL) - xfree(data->arg2); - xfree(data); -} - -size_t -cmd_target_print(struct cmd *self, char *buf, size_t len) -{ - struct cmd_target_data *data = self->data; - size_t off = 0; - - off += xsnprintf(buf, len, "%s", self->entry->name); - if (data == NULL) - return (off); - off += cmd_print_flags(buf, len, off, data->chflags); - if (off < len && data->target != NULL) - off += cmd_prarg(buf + off, len - off, " -t ", data->target); - if (off < len && data->arg != NULL) - off += cmd_prarg(buf + off, len - off, " ", data->arg); - if (off < len && data->arg2 != NULL) - off += cmd_prarg(buf + off, len - off, " ", data->arg2); - return (off); -} - -/* ARGSUSED */ -void -cmd_srcdst_init(struct cmd *self, unused int key) -{ - struct cmd_srcdst_data *data; - - self->data = data = xmalloc(sizeof *data); - data->chflags = 0; - data->src = NULL; - data->dst = NULL; - data->arg = NULL; - data->arg2 = NULL; -} - -int -cmd_srcdst_parse(struct cmd *self, int argc, char **argv, char **cause) -{ - struct cmd_srcdst_data *data; - const struct cmd_entry *entry = self->entry; - int opt; - - cmd_srcdst_init(self, 0); - data = self->data; - - while ((opt = cmd_getopt(argc, argv, "s:t:", entry->chflags)) != -1) { - if (cmd_parse_flags(opt, entry->chflags, &data->chflags) == 0) - continue; - switch (opt) { - case 's': - if (data->src == NULL) - data->src = xstrdup(optarg); - break; - case 't': - if (data->dst == NULL) - data->dst = xstrdup(optarg); - break; - default: - goto usage; - } - } - argc -= optind; - argv += optind; - - if (cmd_fill_argument( - self->entry->flags, &data->arg, &data->arg2, argc, argv) != 0) - goto usage; - return (0); - -usage: - xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); - - self->entry->free(self); - return (-1); -} - -void -cmd_srcdst_free(struct cmd *self) -{ - struct cmd_srcdst_data *data = self->data; - - if (data->src != NULL) - xfree(data->src); - if (data->dst != NULL) - xfree(data->dst); - if (data->arg != NULL) - xfree(data->arg); - if (data->arg2 != NULL) - xfree(data->arg2); - xfree(data); -} - -size_t -cmd_srcdst_print(struct cmd *self, char *buf, size_t len) -{ - struct cmd_srcdst_data *data = self->data; - size_t off = 0; - - off += xsnprintf(buf, len, "%s", self->entry->name); - if (data == NULL) - return (off); - off += cmd_print_flags(buf, len, off, data->chflags); - if (off < len && data->src != NULL) - off += xsnprintf(buf + off, len - off, " -s %s", data->src); - if (off < len && data->dst != NULL) - off += xsnprintf(buf + off, len - off, " -t %s", data->dst); - if (off < len && data->arg != NULL) - off += cmd_prarg(buf + off, len - off, " ", data->arg); - if (off < len && data->arg2 != NULL) - off += cmd_prarg(buf + off, len - off, " ", data->arg2); - return (off); -} - -/* ARGSUSED */ -void -cmd_buffer_init(struct cmd *self, unused int key) -{ - struct cmd_buffer_data *data; - - self->data = data = xmalloc(sizeof *data); - data->chflags = 0; - data->buffer = -1; - data->arg = NULL; - data->arg2 = NULL; -} - -int -cmd_buffer_parse(struct cmd *self, int argc, char **argv, char **cause) -{ - struct cmd_buffer_data *data; - const struct cmd_entry *entry = self->entry; - int opt, n; - const char *errstr; - - cmd_buffer_init(self, 0); - data = self->data; - - while ((opt = cmd_getopt(argc, argv, "b:", entry->chflags)) != -1) { - if (cmd_parse_flags(opt, entry->chflags, &data->chflags) == 0) - continue; - switch (opt) { - case 'b': - if (data->buffer == -1) { - n = strtonum(optarg, 0, INT_MAX, &errstr); - if (errstr != NULL) { - xasprintf(cause, "buffer %s", errstr); - goto error; - } - data->buffer = n; - } - break; - default: - goto usage; - } - } - argc -= optind; - argv += optind; - - if (cmd_fill_argument( - self->entry->flags, &data->arg, &data->arg2, argc, argv) != 0) - goto usage; - return (0); - -usage: - xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); - -error: - self->entry->free(self); - return (-1); -} - -void -cmd_buffer_free(struct cmd *self) -{ - struct cmd_buffer_data *data = self->data; - - if (data->arg != NULL) - xfree(data->arg); - if (data->arg2 != NULL) - xfree(data->arg2); - xfree(data); -} - -size_t -cmd_buffer_print(struct cmd *self, char *buf, size_t len) -{ - struct cmd_buffer_data *data = self->data; - size_t off = 0; - - off += xsnprintf(buf, len, "%s", self->entry->name); - if (data == NULL) - return (off); - off += cmd_print_flags(buf, len, off, data->chflags); - if (off < len && data->buffer != -1) - off += xsnprintf(buf + off, len - off, " -b %d", data->buffer); - if (off < len && data->arg != NULL) - off += cmd_prarg(buf + off, len - off, " ", data->arg); - if (off < len && data->arg2 != NULL) - off += cmd_prarg(buf + off, len - off, " ", data->arg2); - return (off); -} diff --git a/cmd-has-session.c b/cmd-has-session.c index 00f171b7..d5d806a1 100644 --- a/cmd-has-session.c +++ b/cmd-has-session.c @@ -28,21 +28,20 @@ int cmd_has_session_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_has_session_entry = { "has-session", "has", + "t:", 0, 0, CMD_TARGET_SESSION_USAGE, - 0, "", - cmd_target_init, - cmd_target_parse, - cmd_has_session_exec, - cmd_target_free, - cmd_target_print + 0, + NULL, + NULL, + cmd_has_session_exec }; int cmd_has_session_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; + struct args *args = self->args; - if (cmd_find_session(ctx, data->target) == NULL) + if (cmd_find_session(ctx, args_get(args, 't')) == NULL) return (-1); return (0); diff --git a/cmd-if-shell.c b/cmd-if-shell.c index bf60fb23..b7671332 100644 --- a/cmd-if-shell.c +++ b/cmd-if-shell.c @@ -35,13 +35,12 @@ void cmd_if_shell_free(void *); const struct cmd_entry cmd_if_shell_entry = { "if-shell", "if", + "", 2, 2, "shell-command command", - CMD_ARG2, "", - cmd_target_init, - cmd_target_parse, - cmd_if_shell_exec, - cmd_target_free, - cmd_target_print + 0, + NULL, + NULL, + cmd_if_shell_exec }; struct cmd_if_shell_data { @@ -52,12 +51,12 @@ struct cmd_if_shell_data { int cmd_if_shell_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; + struct args *args = self->args; struct cmd_if_shell_data *cdata; struct job *job; cdata = xmalloc(sizeof *cdata); - cdata->cmd = xstrdup(data->arg2); + cdata->cmd = xstrdup(args->argv[1]); memcpy(&cdata->ctx, ctx, sizeof cdata->ctx); if (ctx->cmdclient != NULL) @@ -66,7 +65,7 @@ cmd_if_shell_exec(struct cmd *self, struct cmd_ctx *ctx) ctx->curclient->references++; job = job_add(NULL, 0, NULL, - data->arg, cmd_if_shell_callback, cmd_if_shell_free, cdata); + args->argv[0], cmd_if_shell_callback, cmd_if_shell_free, cdata); job_run(job); return (1); /* don't let client exit */ diff --git a/cmd-join-pane.c b/cmd-join-pane.c index d13c23e3..10b4dda3 100644 --- a/cmd-join-pane.c +++ b/cmd-join-pane.c @@ -28,139 +28,54 @@ * Join a pane into another (like split/swap/kill). */ -int cmd_join_pane_parse(struct cmd *, int, char **, char **); +void cmd_join_pane_key_binding(struct cmd *, int); int cmd_join_pane_exec(struct cmd *, struct cmd_ctx *); -void cmd_join_pane_free(struct cmd *); -void cmd_join_pane_init(struct cmd *, int); -size_t cmd_join_pane_print(struct cmd *, char *, size_t); - -struct cmd_join_pane_data { - char *src; - char *dst; - int flag_detached; - int flag_horizontal; - int percentage; - int size; -}; const struct cmd_entry cmd_join_pane_entry = { "join-pane", "joinp", + "dhvp:l:s:t:", 0, 0, "[-dhv] [-p percentage|-l size] [-s src-pane] [-t dst-pane]", - 0, "", - cmd_join_pane_init, - cmd_join_pane_parse, - cmd_join_pane_exec, - cmd_join_pane_free, - cmd_join_pane_print + 0, + cmd_join_pane_key_binding, + NULL, + cmd_join_pane_exec }; void -cmd_join_pane_init(struct cmd *self, int key) +cmd_join_pane_key_binding(struct cmd *self, int key) { - struct cmd_join_pane_data *data; - - self->data = data = xmalloc(sizeof *data); - data->src = NULL; - data->dst = NULL; - data->flag_detached = 0; - data->flag_horizontal = 0; - data->percentage = -1; - data->size = -1; - switch (key) { case '%': - data->flag_horizontal = 1; + self->args = args_create(0); + args_set(self->args, 'h', NULL); break; - case '"': - data->flag_horizontal = 0; + default: + self->args = args_create(0); break; } } -int -cmd_join_pane_parse(struct cmd *self, int argc, char **argv, char **cause) -{ - struct cmd_join_pane_data *data; - int opt; - const char *errstr; - - self->entry->init(self, KEYC_NONE); - data = self->data; - - while ((opt = getopt(argc, argv, "dhl:p:s:t:v")) != -1) { - switch (opt) { - case 'd': - data->flag_detached = 1; - break; - case 'h': - data->flag_horizontal = 1; - break; - case 's': - if (data->src == NULL) - data->src = xstrdup(optarg); - break; - case 't': - if (data->dst == NULL) - data->dst = xstrdup(optarg); - break; - case 'l': - if (data->percentage != -1 || data->size != -1) - break; - data->size = strtonum(optarg, 1, INT_MAX, &errstr); - if (errstr != NULL) { - xasprintf(cause, "size %s", errstr); - goto error; - } - break; - case 'p': - if (data->size != -1 || data->percentage != -1) - break; - data->percentage = strtonum(optarg, 1, 100, &errstr); - if (errstr != NULL) { - xasprintf(cause, "percentage %s", errstr); - goto error; - } - break; - case 'v': - data->flag_horizontal = 0; - break; - default: - goto usage; - } - } - argc -= optind; - argv += optind; - if (argc != 0) - goto usage; - - return (0); - -usage: - xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); - -error: - self->entry->free(self); - return (-1); -} - int cmd_join_pane_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_join_pane_data *data = self->data; - struct session *dst_s; - struct winlink *src_wl, *dst_wl; - struct window *src_w, *dst_w; - struct window_pane *src_wp, *dst_wp; - int size, dst_idx; - enum layout_type type; - struct layout_cell *lc; + struct args *args = self->args; + struct session *dst_s; + struct winlink *src_wl, *dst_wl; + struct window *src_w, *dst_w; + struct window_pane *src_wp, *dst_wp; + char *cause; + int size, percentage, dst_idx; + enum layout_type type; + struct layout_cell *lc; - if ((dst_wl = cmd_find_pane(ctx, data->dst, &dst_s, &dst_wp)) == NULL) + dst_wl = cmd_find_pane(ctx, args_get(args, 't'), &dst_s, &dst_wp); + if (dst_wl == NULL) return (-1); dst_w = dst_wl->window; dst_idx = dst_wl->idx; - if ((src_wl = cmd_find_pane(ctx, data->src, NULL, &src_wp)) == NULL) + src_wl = cmd_find_pane(ctx, args_get(args, 's'), NULL, &src_wp); + if (src_wl == NULL) return (-1); src_w = src_wl->window; @@ -170,17 +85,28 @@ cmd_join_pane_exec(struct cmd *self, struct cmd_ctx *ctx) } type = LAYOUT_TOPBOTTOM; - if (data->flag_horizontal) + if (args_has(args, 'h')) type = LAYOUT_LEFTRIGHT; size = -1; - if (data->size != -1) - size = data->size; - else if (data->percentage != -1) { + if (args_has(args, 's')) { + size = args_strtonum(args, 's', 0, INT_MAX, &cause); + if (cause != NULL) { + ctx->error(ctx, "size %s", cause); + xfree(cause); + return (-1); + } + } else if (args_has(args, 'p')) { + percentage = args_strtonum(args, 'p', 0, INT_MAX, &cause); + if (cause != NULL) { + ctx->error(ctx, "percentage %s", cause); + xfree(cause); + return (-1); + } if (type == LAYOUT_TOPBOTTOM) - size = (dst_wp->sy * data->percentage) / 100; + size = (dst_wp->sy * percentage) / 100; else - size = (dst_wp->sx * data->percentage) / 100; + size = (dst_wp->sx * percentage) / 100; } if ((lc = layout_split_pane(dst_wp, type, size)) == NULL) { @@ -209,7 +135,7 @@ cmd_join_pane_exec(struct cmd *self, struct cmd_ctx *ctx) server_redraw_window(src_w); server_redraw_window(dst_w); - if (!data->flag_detached) { + if (!args_has(args, 'd')) { window_set_active_pane(dst_w, src_wp); session_select(dst_s, dst_idx); server_redraw_session(dst_s); @@ -218,41 +144,3 @@ cmd_join_pane_exec(struct cmd *self, struct cmd_ctx *ctx) return (0); } - -void -cmd_join_pane_free(struct cmd *self) -{ - struct cmd_join_pane_data *data = self->data; - - if (data->src != NULL) - xfree(data->src); - if (data->dst != NULL) - xfree(data->dst); - xfree(data); -} - -size_t -cmd_join_pane_print(struct cmd *self, char *buf, size_t len) -{ - struct cmd_join_pane_data *data = self->data; - size_t off = 0; - - off += xsnprintf(buf, len, "%s", self->entry->name); - if (data == NULL) - return (off); - if (off < len && data->flag_detached) - off += xsnprintf(buf + off, len - off, " -d"); - if (off < len && data->flag_horizontal) - off += xsnprintf(buf + off, len - off, " -h"); - if (off < len && data->size > 0) - off += xsnprintf(buf + off, len - off, " -l %d", data->size); - if (off < len && data->percentage > 0) { - off += xsnprintf( - buf + off, len - off, " -p %d", data->percentage); - } - if (off < len && data->src != NULL) - off += cmd_prarg(buf + off, len - off, " -s ", data->src); - if (off < len && data->dst != NULL) - off += cmd_prarg(buf + off, len - off, " -t ", data->dst); - return (off); -} diff --git a/cmd-kill-pane.c b/cmd-kill-pane.c index c48e4d4e..215c8ed7 100644 --- a/cmd-kill-pane.c +++ b/cmd-kill-pane.c @@ -30,23 +30,22 @@ int cmd_kill_pane_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_kill_pane_entry = { "kill-pane", "killp", + "at:", 0, 0, "[-a] " CMD_TARGET_PANE_USAGE, - 0, "a", - cmd_target_init, - cmd_target_parse, - cmd_kill_pane_exec, - cmd_target_free, - cmd_target_print + 0, + NULL, + NULL, + cmd_kill_pane_exec }; int cmd_kill_pane_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; + struct args *args = self->args; struct winlink *wl; struct window_pane *loopwp, *nextwp, *wp; - if ((wl = cmd_find_pane(ctx, data->target, NULL, &wp)) == NULL) + if ((wl = cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp)) == NULL) return (-1); if (window_count_panes(wl->window) == 1) { @@ -56,7 +55,7 @@ cmd_kill_pane_exec(struct cmd *self, struct cmd_ctx *ctx) return (0); } - if (cmd_check_flag(data->chflags, 'a')) { + if (args_has(self->args, 'a')) { loopwp = TAILQ_FIRST(&wl->window->panes); while (loopwp != NULL) { nextwp = TAILQ_NEXT(loopwp, entry); diff --git a/cmd-kill-server.c b/cmd-kill-server.c index 9e6ddb21..800563a4 100644 --- a/cmd-kill-server.c +++ b/cmd-kill-server.c @@ -31,13 +31,12 @@ int cmd_kill_server_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_kill_server_entry = { "kill-server", NULL, + "", 0, 0, "", - 0, "", + 0, NULL, NULL, - cmd_kill_server_exec, - NULL, - NULL + cmd_kill_server_exec }; /* ARGSUSED */ diff --git a/cmd-kill-session.c b/cmd-kill-session.c index efd91801..086dbc67 100644 --- a/cmd-kill-session.c +++ b/cmd-kill-session.c @@ -31,22 +31,21 @@ int cmd_kill_session_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_kill_session_entry = { "kill-session", NULL, + "t:", 0, 0, CMD_TARGET_SESSION_USAGE, - 0, "", - cmd_target_init, - cmd_target_parse, - cmd_kill_session_exec, - cmd_target_free, - cmd_target_print + 0, + NULL, + NULL, + cmd_kill_session_exec }; int cmd_kill_session_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; - struct session *s; + struct args *args = self->args; + struct session *s; - if ((s = cmd_find_session(ctx, data->target)) == NULL) + if ((s = cmd_find_session(ctx, args_get(args, 't'))) == NULL) return (-1); server_destroy_session(s); diff --git a/cmd-kill-window.c b/cmd-kill-window.c index aae1cc85..30f4c40e 100644 --- a/cmd-kill-window.c +++ b/cmd-kill-window.c @@ -28,22 +28,21 @@ int cmd_kill_window_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_kill_window_entry = { "kill-window", "killw", + "t:", 0, 0, CMD_TARGET_WINDOW_USAGE, - 0, "", - cmd_target_init, - cmd_target_parse, - cmd_kill_window_exec, - cmd_target_free, - cmd_target_print + 0, + NULL, + NULL, + cmd_kill_window_exec }; int cmd_kill_window_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; - struct winlink *wl; + struct args *args = self->args; + struct winlink *wl; - if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) + if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL) return (-1); server_kill_window(wl->window); diff --git a/cmd-last-pane.c b/cmd-last-pane.c index b59843b7..f9f61495 100644 --- a/cmd-last-pane.c +++ b/cmd-last-pane.c @@ -28,23 +28,22 @@ int cmd_last_pane_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_last_pane_entry = { "last-pane", "lastp", + "t:", 0, 0, CMD_TARGET_WINDOW_USAGE, - 0, "", - cmd_target_init, - cmd_target_parse, - cmd_last_pane_exec, - cmd_target_free, - cmd_target_print + 0, + NULL, + NULL, + cmd_last_pane_exec }; int cmd_last_pane_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; - struct winlink *wl; - struct window *w; + struct args *args = self->args; + struct winlink *wl; + struct window *w; - if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) + if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL) return (-1); w = wl->window; diff --git a/cmd-last-window.c b/cmd-last-window.c index 5f065ccb..209f367b 100644 --- a/cmd-last-window.c +++ b/cmd-last-window.c @@ -28,22 +28,21 @@ int cmd_last_window_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_last_window_entry = { "last-window", "last", + "t:", 0, 0, CMD_TARGET_SESSION_USAGE, - 0, "", - cmd_target_init, - cmd_target_parse, - cmd_last_window_exec, - cmd_target_free, - cmd_target_print + 0, + NULL, + NULL, + cmd_last_window_exec }; int cmd_last_window_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; - struct session *s; + struct args *args = self->args; + struct session *s; - if ((s = cmd_find_session(ctx, data->target)) == NULL) + if ((s = cmd_find_session(ctx, args_get(args, 't'))) == NULL) return (-1); if (session_last(s) == 0) diff --git a/cmd-link-window.c b/cmd-link-window.c index f8da27dd..a278fe34 100644 --- a/cmd-link-window.c +++ b/cmd-link-window.c @@ -30,31 +30,30 @@ int cmd_link_window_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_link_window_entry = { "link-window", "linkw", + "dks:t:", 0, 0, "[-dk] " CMD_SRCDST_WINDOW_USAGE, - 0, "dk", - cmd_srcdst_init, - cmd_srcdst_parse, - cmd_link_window_exec, - cmd_srcdst_free, - cmd_srcdst_print + 0, + NULL, + NULL, + cmd_link_window_exec }; int cmd_link_window_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_srcdst_data *data = self->data; - struct session *src, *dst; - struct winlink *wl; - char *cause; - int idx, kflag, dflag; + struct args *args = self->args; + struct session *src, *dst; + struct winlink *wl; + char *cause; + int idx, kflag, dflag; - if ((wl = cmd_find_window(ctx, data->src, &src)) == NULL) + if ((wl = cmd_find_window(ctx, args_get(args, 's'), &src)) == NULL) return (-1); - if ((idx = cmd_find_index(ctx, data->dst, &dst)) == -2) + if ((idx = cmd_find_index(ctx, args_get(args, 't'), &dst)) == -2) return (-1); - kflag = cmd_check_flag(data->chflags, 'k'); - dflag = cmd_check_flag(data->chflags, 'd'); + kflag = args_has(self->args, 'k'); + dflag = args_has(self->args, 'd'); if (server_link_window(src, wl, dst, idx, kflag, !dflag, &cause) != 0) { ctx->error(ctx, "can't link window: %s", cause); xfree(cause); diff --git a/cmd-list-buffers.c b/cmd-list-buffers.c index efc86f97..d4ff9a22 100644 --- a/cmd-list-buffers.c +++ b/cmd-list-buffers.c @@ -30,13 +30,12 @@ int cmd_list_buffers_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_list_buffers_entry = { "list-buffers", "lsb", + "", 0, 0, "", - 0, "", + 0, NULL, NULL, - cmd_list_buffers_exec, - NULL, - NULL + cmd_list_buffers_exec }; /* ARGSUSED */ diff --git a/cmd-list-clients.c b/cmd-list-clients.c index 9c941b45..026f12a7 100644 --- a/cmd-list-clients.c +++ b/cmd-list-clients.c @@ -31,13 +31,12 @@ int cmd_list_clients_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_list_clients_entry = { "list-clients", "lsc", + "", 0, 0, "", - 0, "", + 0, NULL, NULL, - cmd_list_clients_exec, - NULL, - NULL + cmd_list_clients_exec }; /* ARGSUSED */ diff --git a/cmd-list-commands.c b/cmd-list-commands.c index a5c98ea7..87901210 100644 --- a/cmd-list-commands.c +++ b/cmd-list-commands.c @@ -28,13 +28,12 @@ int cmd_list_commands_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_list_commands_entry = { "list-commands", "lscm", + "", 0, 0, "", - 0, "", + 0, NULL, NULL, - cmd_list_commands_exec, - NULL, - NULL + cmd_list_commands_exec }; /* ARGSUSED */ diff --git a/cmd-list-keys.c b/cmd-list-keys.c index b60b4666..c6c391a2 100644 --- a/cmd-list-keys.c +++ b/cmd-list-keys.c @@ -32,26 +32,25 @@ int cmd_list_keys_table(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_list_keys_entry = { "list-keys", "lsk", + "t:", 0, 0, "[-t key-table]", - 0, "", - cmd_target_init, - cmd_target_parse, - cmd_list_keys_exec, - cmd_target_free, - cmd_target_print + 0, + NULL, + NULL, + cmd_list_keys_exec }; int cmd_list_keys_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; + struct args *args = self->args; struct key_binding *bd; const char *key; char tmp[BUFSIZ]; size_t used; int width, keywidth; - if (data->target != NULL) + if (args_has(args, 't')) return (cmd_list_keys_table(self, ctx)); width = 0; @@ -95,14 +94,16 @@ cmd_list_keys_exec(struct cmd *self, struct cmd_ctx *ctx) int cmd_list_keys_table(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; + struct args *args = self->args; + const char *tablename; const struct mode_key_table *mtab; struct mode_key_binding *mbind; const char *key, *cmdstr, *mode; int width, keywidth; - if ((mtab = mode_key_findtable(data->target)) == NULL) { - ctx->error(ctx, "unknown key table: %s", data->target); + tablename = args_get(args, 't'); + if ((mtab = mode_key_findtable(tablename)) == NULL) { + ctx->error(ctx, "unknown key table: %s", tablename); return (-1); } diff --git a/cmd-list-panes.c b/cmd-list-panes.c index e96d596b..03fd7afd 100644 --- a/cmd-list-panes.c +++ b/cmd-list-panes.c @@ -30,19 +30,18 @@ int cmd_list_panes_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_list_panes_entry = { "list-panes", "lsp", + "t:", 0, 0, CMD_TARGET_WINDOW_USAGE, - 0, "", - cmd_target_init, - cmd_target_parse, - cmd_list_panes_exec, - cmd_target_free, - cmd_target_print + 0, + NULL, + NULL, + cmd_list_panes_exec }; int cmd_list_panes_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; + struct args *args = self->args; struct winlink *wl; struct window_pane *wp; struct grid *gd; @@ -50,7 +49,7 @@ cmd_list_panes_exec(struct cmd *self, struct cmd_ctx *ctx) u_int i, n; unsigned long long size; - if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) + if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL) return (-1); n = 0; diff --git a/cmd-list-sessions.c b/cmd-list-sessions.c index e7aa22d7..6c0f2dae 100644 --- a/cmd-list-sessions.c +++ b/cmd-list-sessions.c @@ -30,13 +30,13 @@ int cmd_list_sessions_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_list_sessions_entry = { - "list-sessions", "ls", "", - 0, "", + "list-sessions", "ls", + "", 0, 0, + "", + 0, NULL, NULL, - cmd_list_sessions_exec, - NULL, - NULL + cmd_list_sessions_exec }; /* ARGSUSED */ diff --git a/cmd-list-windows.c b/cmd-list-windows.c index 7a4a28c2..331b521a 100644 --- a/cmd-list-windows.c +++ b/cmd-list-windows.c @@ -30,24 +30,23 @@ int cmd_list_windows_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_list_windows_entry = { "list-windows", "lsw", + "t:", 0, 0, CMD_TARGET_SESSION_USAGE, - 0, "", - cmd_target_init, - cmd_target_parse, - cmd_list_windows_exec, - cmd_target_free, - cmd_target_print + 0, + NULL, + NULL, + cmd_list_windows_exec }; int cmd_list_windows_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; - struct session *s; - struct winlink *wl; - char *layout; + struct args *args = self->args; + struct session *s; + struct winlink *wl; + char *layout; - if ((s = cmd_find_session(ctx, data->target)) == NULL) + if ((s = cmd_find_session(ctx, args_get(args, 't'))) == NULL) return (-1); RB_FOREACH(wl, winlinks, &s->windows) { diff --git a/cmd-load-buffer.c b/cmd-load-buffer.c index 13413e4b..55a5cd14 100644 --- a/cmd-load-buffer.c +++ b/cmd-load-buffer.c @@ -35,41 +35,57 @@ void cmd_load_buffer_callback(struct client *, void *); const struct cmd_entry cmd_load_buffer_entry = { "load-buffer", "loadb", + "b:", 1, 1, CMD_BUFFER_USAGE " path", - CMD_ARG1, "", - cmd_buffer_init, - cmd_buffer_parse, - cmd_load_buffer_exec, - cmd_buffer_free, - cmd_buffer_print + 0, + NULL, + NULL, + cmd_load_buffer_exec }; int cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_buffer_data *data = self->data; - struct client *c = ctx->cmdclient; - FILE *f; - char *pdata, *new_pdata; - size_t psize; - u_int limit; - int ch; + struct args *args = self->args; + struct client *c = ctx->cmdclient; + FILE *f; + const char *path; + char *pdata, *new_pdata, *cause; + size_t psize; + u_int limit; + int ch, buffer; + int *buffer_ptr; - if (strcmp(data->arg, "-") == 0) { + if (!args_has(args, 'b')) + buffer = -1; + else { + buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause); + if (cause != NULL) { + ctx->error(ctx, "buffer %s", cause); + xfree(cause); + return (-1); + } + } + + path = args->argv[0]; + if (strcmp(path, "-") == 0) { if (c == NULL) { - ctx->error(ctx, "%s: can't read from stdin", data->arg); + ctx->error(ctx, "%s: can't read from stdin", path); return (-1); } if (c->flags & CLIENT_TERMINAL) { - ctx->error(ctx, "%s: stdin is a tty", data->arg); + ctx->error(ctx, "%s: stdin is a tty", path); return (-1); } if (c->stdin_fd == -1) { - ctx->error(ctx, "%s: can't read from stdin", data->arg); + ctx->error(ctx, "%s: can't read from stdin", path); return (-1); } - c->stdin_data = &data->buffer; + buffer_ptr = xmalloc(sizeof *buffer_ptr); + *buffer_ptr = buffer; + + c->stdin_data = buffer_ptr; c->stdin_callback = cmd_load_buffer_callback; c->references++; @@ -77,8 +93,8 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) return (1); } - if ((f = fopen(data->arg, "rb")) == NULL) { - ctx->error(ctx, "%s: %s", data->arg, strerror(errno)); + if ((f = fopen(path, "rb")) == NULL) { + ctx->error(ctx, "%s: %s", path, strerror(errno)); return (-1); } @@ -94,7 +110,7 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) pdata[psize++] = ch; } if (ferror(f)) { - ctx->error(ctx, "%s: read error", data->arg); + ctx->error(ctx, "%s: read error", path); goto error; } if (pdata != NULL) @@ -103,12 +119,12 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) fclose(f); limit = options_get_number(&global_options, "buffer-limit"); - if (data->buffer == -1) { + if (buffer == -1) { paste_add(&global_buffers, pdata, psize, limit); return (0); } - if (paste_replace(&global_buffers, data->buffer, pdata, psize) != 0) { - ctx->error(ctx, "no buffer %d", data->buffer); + if (paste_replace(&global_buffers, buffer, pdata, psize) != 0) { + ctx->error(ctx, "no buffer %d", buffer); return (-1); } @@ -125,10 +141,10 @@ error: void cmd_load_buffer_callback(struct client *c, void *data) { + int *buffer = data; char *pdata; size_t psize; u_int limit; - int *buffer = data; /* * Event callback has already checked client is not dead and reduced @@ -137,12 +153,10 @@ cmd_load_buffer_callback(struct client *c, void *data) c->flags |= CLIENT_EXIT; psize = EVBUFFER_LENGTH(c->stdin_event->input); - if (psize == 0) - return; - - pdata = malloc(psize + 1); - if (pdata == NULL) + if (psize == 0 || (pdata = malloc(psize + 1)) == NULL) { + free(data); return; + } bufferevent_read(c->stdin_event, pdata, psize); pdata[psize] = '\0'; @@ -155,4 +169,6 @@ cmd_load_buffer_callback(struct client *c, void *data) c->stderr_event->output, "no buffer %d\n", *buffer); bufferevent_enable(c->stderr_event, EV_WRITE); } + + free (data); } diff --git a/cmd-lock-client.c b/cmd-lock-client.c index 607c9d22..bc5a1aa4 100644 --- a/cmd-lock-client.c +++ b/cmd-lock-client.c @@ -28,22 +28,21 @@ int cmd_lock_client_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_lock_client_entry = { "lock-client", "lockc", + "t:", 0, 0, CMD_TARGET_CLIENT_USAGE, - 0, "", - cmd_target_init, - cmd_target_parse, - cmd_lock_client_exec, - cmd_target_free, - cmd_target_print + 0, + NULL, + NULL, + cmd_lock_client_exec }; int cmd_lock_client_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; - struct client *c; + struct args *args = self->args; + struct client *c; - if ((c = cmd_find_client(ctx, data->target)) == NULL) + if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL) return (-1); server_lock_client(c); diff --git a/cmd-lock-server.c b/cmd-lock-server.c index b588e2b2..347cc128 100644 --- a/cmd-lock-server.c +++ b/cmd-lock-server.c @@ -32,13 +32,12 @@ int cmd_lock_server_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_lock_server_entry = { "lock-server", "lock", + "", 0, 0, "", - 0, "", - NULL, - NULL, - cmd_lock_server_exec, + 0, NULL, NULL, + cmd_lock_server_exec }; /* ARGSUSED */ diff --git a/cmd-lock-session.c b/cmd-lock-session.c index 279ab655..4b75c973 100644 --- a/cmd-lock-session.c +++ b/cmd-lock-session.c @@ -28,22 +28,21 @@ int cmd_lock_session_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_lock_session_entry = { "lock-session", "locks", + "t:", 0, 0, CMD_TARGET_SESSION_USAGE, - 0, "", - cmd_target_init, - cmd_target_parse, - cmd_lock_session_exec, - cmd_target_free, - cmd_target_print + 0, + NULL, + NULL, + cmd_lock_session_exec }; int cmd_lock_session_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; - struct session *s; + struct args *args = self->args; + struct session *s; - if ((s = cmd_find_session(ctx, data->target)) == NULL) + if ((s = cmd_find_session(ctx, args_get(args, 't'))) == NULL) return (-1); server_lock_session(s); diff --git a/cmd-move-window.c b/cmd-move-window.c index 6105812a..ee3ba59c 100644 --- a/cmd-move-window.c +++ b/cmd-move-window.c @@ -30,31 +30,30 @@ int cmd_move_window_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_move_window_entry = { "move-window", "movew", + "dks:t:", 0, 0, "[-dk] " CMD_SRCDST_WINDOW_USAGE, - 0, "dk", - cmd_srcdst_init, - cmd_srcdst_parse, - cmd_move_window_exec, - cmd_srcdst_free, - cmd_srcdst_print + 0, + NULL, + NULL, + cmd_move_window_exec }; int cmd_move_window_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_srcdst_data *data = self->data; - struct session *src, *dst; - struct winlink *wl; - char *cause; - int idx, kflag, dflag; + struct args *args = self->args; + struct session *src, *dst; + struct winlink *wl; + char *cause; + int idx, kflag, dflag; - if ((wl = cmd_find_window(ctx, data->src, &src)) == NULL) + if ((wl = cmd_find_window(ctx, args_get(args, 's'), &src)) == NULL) return (-1); - if ((idx = cmd_find_index(ctx, data->dst, &dst)) == -2) + if ((idx = cmd_find_index(ctx, args_get(args, 't'), &dst)) == -2) return (-1); - kflag = cmd_check_flag(data->chflags, 'k'); - dflag = cmd_check_flag(data->chflags, 'd'); + kflag = args_has(self->args, 'k'); + dflag = args_has(self->args, 'd'); if (server_link_window(src, wl, dst, idx, kflag, !dflag, &cause) != 0) { ctx->error(ctx, "can't move window: %s", cause); xfree(cause); diff --git a/cmd-new-session.c b/cmd-new-session.c index 53a50bbb..d53e2692 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -29,119 +29,55 @@ * Create a new session and attach to the current terminal unless -d is given. */ -int cmd_new_session_parse(struct cmd *, int, char **, char **); +int cmd_new_session_check(struct args *); int cmd_new_session_exec(struct cmd *, struct cmd_ctx *); -void cmd_new_session_free(struct cmd *); -void cmd_new_session_init(struct cmd *, int); -size_t cmd_new_session_print(struct cmd *, char *, size_t); - -struct cmd_new_session_data { - char *target; - char *newname; - char *winname; - char *cmd; - int flag_detached; -}; const struct cmd_entry cmd_new_session_entry = { "new-session", "new", + "dn:s:t:", 0, 1, "[-d] [-n window-name] [-s session-name] [-t target-session] [command]", - CMD_STARTSERVER|CMD_CANTNEST|CMD_SENDENVIRON, "", - cmd_new_session_init, - cmd_new_session_parse, - cmd_new_session_exec, - cmd_new_session_free, - cmd_new_session_print + CMD_STARTSERVER|CMD_CANTNEST|CMD_SENDENVIRON, + NULL, + cmd_new_session_check, + cmd_new_session_exec }; -/* ARGSUSED */ -void -cmd_new_session_init(struct cmd *self, unused int arg) -{ - struct cmd_new_session_data *data; - - self->data = data = xmalloc(sizeof *data); - data->flag_detached = 0; - data->target = NULL; - data->newname = NULL; - data->winname = NULL; - data->cmd = NULL; -} - int -cmd_new_session_parse(struct cmd *self, int argc, char **argv, char **cause) +cmd_new_session_check(struct args *args) { - struct cmd_new_session_data *data; - int opt; - - self->entry->init(self, KEYC_NONE); - data = self->data; - - while ((opt = getopt(argc, argv, "ds:t:n:")) != -1) { - switch (opt) { - case 'd': - data->flag_detached = 1; - break; - case 's': - if (data->newname == NULL) - data->newname = xstrdup(optarg); - break; - case 't': - if (data->target == NULL) - data->target = xstrdup(optarg); - break; - case 'n': - if (data->winname == NULL) - data->winname = xstrdup(optarg); - break; - default: - goto usage; - } - } - argc -= optind; - argv += optind; - if (argc != 0 && argc != 1) - goto usage; - - if (data->target != NULL && (argc == 1 || data->winname != NULL)) - goto usage; - - if (argc == 1) - data->cmd = xstrdup(argv[0]); - + if (args_has(args, 't') && (args->argc != 0 || args_has(args, 'n'))) + return (-1); return (0); - -usage: - xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); - - self->entry->free(self); - return (-1); } int cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_new_session_data *data = self->data; - struct session *s, *old_s, *groupwith; - struct window *w; - struct window_pane *wp; - struct environ env; - struct termios tio, *tiop; - struct passwd *pw; - const char *update, *cwd; - char *overrides, *cmd, *cause; - int detached, idx; - u_int sx, sy, i; + struct args *args = self->args; + struct session *s, *old_s, *groupwith; + struct window *w; + struct window_pane *wp; + struct environ env; + struct termios tio, *tiop; + struct passwd *pw; + const char *newname, *target, *update, *cwd; + char *overrides, *cmd, *cause; + int detached, idx; + u_int sx, sy, i; - if (data->newname != NULL && session_find(data->newname) != NULL) { - ctx->error(ctx, "duplicate session: %s", data->newname); + newname = args_get(args, 's'); + if (newname != NULL && session_find(newname) != NULL) { + ctx->error(ctx, "duplicate session: %s", newname); return (-1); } - groupwith = NULL; - if (data->target != NULL && - (groupwith = cmd_find_session(ctx, data->target)) == NULL) - return (-1); + target = args_get(args, 't'); + if (target != NULL) { + groupwith = cmd_find_session(ctx, target); + if (groupwith == NULL) + return (-1); + } else + groupwith = NULL; /* * There are three cases: @@ -162,7 +98,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) */ /* Set -d if no client. */ - detached = data->flag_detached; + detached = args_has(args, 'd'); if (ctx->cmdclient == NULL && ctx->curclient == NULL) detached = 1; @@ -228,10 +164,10 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) sy = 1; /* Figure out the command for the new window. */ - if (data->target != NULL) + if (target != NULL) cmd = NULL; - else if (data->cmd != NULL) - cmd = data->cmd; + else if (args->argc != 0) + cmd = args->argv[0]; else cmd = options_get_string(&global_s_options, "default-command"); @@ -243,8 +179,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) /* Create the new session. */ idx = -1 - options_get_number(&global_s_options, "base-index"); - s = session_create( - data->newname, cmd, cwd, &env, tiop, idx, sx, sy, &cause); + s = session_create(newname, cmd, cwd, &env, tiop, idx, sx, sy, &cause); if (s == NULL) { ctx->error(ctx, "create session failed: %s", cause); xfree(cause); @@ -253,11 +188,11 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) environ_free(&env); /* Set the initial window name if one given. */ - if (cmd != NULL && data->winname != NULL) { + if (cmd != NULL && args_has(args, 'n')) { w = s->curw->window; xfree(w->name); - w->name = xstrdup(data->winname); + w->name = xstrdup(args_get(args, 'n')); options_set_number(&w->options, "automatic-rename", 0); } @@ -316,39 +251,3 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) return (!detached); /* 1 means don't tell command client to exit */ } - -void -cmd_new_session_free(struct cmd *self) -{ - struct cmd_new_session_data *data = self->data; - - if (data->newname != NULL) - xfree(data->newname); - if (data->winname != NULL) - xfree(data->winname); - if (data->cmd != NULL) - xfree(data->cmd); - xfree(data); -} - -size_t -cmd_new_session_print(struct cmd *self, char *buf, size_t len) -{ - struct cmd_new_session_data *data = self->data; - size_t off = 0; - - off += xsnprintf(buf, len, "%s", self->entry->name); - if (data == NULL) - return (off); - if (off < len && data->flag_detached) - off += xsnprintf(buf + off, len - off, " -d"); - if (off < len && data->winname != NULL) - off += cmd_prarg(buf + off, len - off, " -n ", data->winname); - if (off < len && data->newname != NULL) - off += cmd_prarg(buf + off, len - off, " -s ", data->newname); - if (off < len && data->target != NULL) - off += cmd_prarg(buf + off, len - off, " -t ", data->target); - if (off < len && data->cmd != NULL) - off += cmd_prarg(buf + off, len - off, " ", data->cmd); - return (off); -} diff --git a/cmd-new-window.c b/cmd-new-window.c index e17cdf1d..955f6449 100644 --- a/cmd-new-window.c +++ b/cmd-new-window.c @@ -26,115 +26,30 @@ * Create a new window. */ -int cmd_new_window_parse(struct cmd *, int, char **, char **); int cmd_new_window_exec(struct cmd *, struct cmd_ctx *); -void cmd_new_window_free(struct cmd *); -void cmd_new_window_init(struct cmd *, int); -size_t cmd_new_window_print(struct cmd *, char *, size_t); - -struct cmd_new_window_data { - char *target; - char *name; - char *cmd; - int flag_insert_after; - int flag_detached; - int flag_kill; - int flag_print; -}; const struct cmd_entry cmd_new_window_entry = { "new-window", "neww", - "[-adkP] [-n window-name] [-t target-window] [command]", - 0, "", - cmd_new_window_init, - cmd_new_window_parse, - cmd_new_window_exec, - cmd_new_window_free, - cmd_new_window_print + "adkn:Pt:", 0, 1, + "[-adk] [-n window-name] [-t target-window] [command]", + 0, + NULL, + NULL, + cmd_new_window_exec }; -/* ARGSUSED */ -void -cmd_new_window_init(struct cmd *self, unused int arg) -{ - struct cmd_new_window_data *data; - - self->data = data = xmalloc(sizeof *data); - data->target = NULL; - data->name = NULL; - data->cmd = NULL; - data->flag_insert_after = 0; - data->flag_detached = 0; - data->flag_kill = 0; - data->flag_print = 0; -} - -int -cmd_new_window_parse(struct cmd *self, int argc, char **argv, char **cause) -{ - struct cmd_new_window_data *data; - int opt; - - self->entry->init(self, KEYC_NONE); - data = self->data; - - while ((opt = getopt(argc, argv, "adkt:n:P")) != -1) { - switch (opt) { - case 'a': - data->flag_insert_after = 1; - break; - case 'd': - data->flag_detached = 1; - break; - case 'k': - data->flag_kill = 1; - break; - case 't': - if (data->target == NULL) - data->target = xstrdup(optarg); - break; - case 'n': - if (data->name == NULL) - data->name = xstrdup(optarg); - break; - case 'P': - data->flag_print = 1; - break; - default: - goto usage; - } - } - argc -= optind; - argv += optind; - if (argc != 0 && argc != 1) - goto usage; - - if (argc == 1) - data->cmd = xstrdup(argv[0]); - - return (0); - -usage: - xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); - - self->entry->free(self); - return (-1); -} - int cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_new_window_data *data = self->data; - struct session *s; - struct winlink *wl; - char *cmd, *cwd, *cause; - int idx, last; + struct args *args = self->args; + struct session *s; + struct winlink *wl; + char *cmd, *cwd, *cause; + int idx, last, detached; - if (data == NULL) - return (0); - - if (data->flag_insert_after) { - if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL) + if (args_has(args, 'a')) { + wl = cmd_find_window(ctx, args_get(args, 't'), &s); + if (wl == NULL) return (-1); idx = wl->idx + 1; @@ -155,14 +70,15 @@ cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx) server_unlink_window(s, wl); } } else { - if ((idx = cmd_find_index(ctx, data->target, &s)) == -2) + if ((idx = cmd_find_index(ctx, args_get(args, 't'), &s)) == -2) return (-1); } + detached = args_has(args, 'd'); wl = NULL; if (idx != -1) wl = winlink_find_by_index(&s->windows, idx); - if (wl != NULL && data->flag_kill) { + if (wl != NULL && args_has(args, 'k')) { /* * Can't use session_detach as it will destroy session if this * makes it empty. @@ -173,14 +89,15 @@ cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx) /* Force select/redraw if current. */ if (wl == s->curw) { - data->flag_detached = 0; + detached = 0; s->curw = NULL; } } - cmd = data->cmd; - if (cmd == NULL) + if (args->argc == 0) cmd = options_get_string(&s->options, "default-command"); + else + cmd = args->argv[0]; cwd = options_get_string(&s->options, "default-path"); if (*cwd == '\0') { if (ctx->cmdclient != NULL && ctx->cmdclient->cwd != NULL) @@ -191,55 +108,19 @@ cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx) if (idx == -1) idx = -1 - options_get_number(&s->options, "base-index"); - wl = session_new(s, data->name, cmd, cwd, idx, &cause); + wl = session_new(s, args_get(args, 'n'), cmd, cwd, idx, &cause); if (wl == NULL) { ctx->error(ctx, "create window failed: %s", cause); xfree(cause); return (-1); } - if (!data->flag_detached) { + if (!detached) { session_select(s, wl->idx); server_redraw_session_group(s); } else server_status_session_group(s); - if (data->flag_print) + if (args_has(args, 'P')) ctx->print(ctx, "%s:%u", s->name, wl->idx); return (0); } - -void -cmd_new_window_free(struct cmd *self) -{ - struct cmd_new_window_data *data = self->data; - - if (data->target != NULL) - xfree(data->target); - if (data->name != NULL) - xfree(data->name); - if (data->cmd != NULL) - xfree(data->cmd); - xfree(data); -} - -size_t -cmd_new_window_print(struct cmd *self, char *buf, size_t len) -{ - struct cmd_new_window_data *data = self->data; - size_t off = 0; - - off += xsnprintf(buf, len, "%s", self->entry->name); - if (data == NULL) - return (off); - if (off < len && data->flag_detached) - off += xsnprintf(buf + off, len - off, " -d"); - if (off < len && data->flag_print) - off += xsnprintf(buf + off, len - off, " -P"); - if (off < len && data->target != NULL) - off += cmd_prarg(buf + off, len - off, " -t ", data->target); - if (off < len && data->name != NULL) - off += cmd_prarg(buf + off, len - off, " -n ", data->name); - if (off < len && data->cmd != NULL) - off += cmd_prarg(buf + off, len - off, " ", data->cmd); - return (off); -} diff --git a/cmd-next-layout.c b/cmd-next-layout.c index aa033a83..bdd6f3e5 100644 --- a/cmd-next-layout.c +++ b/cmd-next-layout.c @@ -28,23 +28,22 @@ int cmd_next_layout_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_next_layout_entry = { "next-layout", "nextl", + "t:", 0, 0, CMD_TARGET_WINDOW_USAGE, - 0, "", - cmd_target_init, - cmd_target_parse, - cmd_next_layout_exec, - cmd_target_free, - cmd_target_print + 0, + NULL, + NULL, + cmd_next_layout_exec }; int cmd_next_layout_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; - struct winlink *wl; - u_int layout; + struct args *args = self->args; + struct winlink *wl; + u_int layout; - if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) + if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL) return (-1); layout = layout_set_next(wl->window); diff --git a/cmd-next-window.c b/cmd-next-window.c index cc361b62..c9cb77a9 100644 --- a/cmd-next-window.c +++ b/cmd-next-window.c @@ -24,44 +24,39 @@ * Move to next window. */ -void cmd_next_window_init(struct cmd *, int); +void cmd_next_window_key_binding(struct cmd *, int); int cmd_next_window_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_next_window_entry = { "next-window", "next", + "at:", 0, 0, "[-a] " CMD_TARGET_SESSION_USAGE, - 0, "a", - cmd_next_window_init, - cmd_target_parse, - cmd_next_window_exec, - cmd_target_free, - cmd_target_print + 0, + cmd_next_window_key_binding, + NULL, + cmd_next_window_exec }; void -cmd_next_window_init(struct cmd *self, int key) +cmd_next_window_key_binding(struct cmd *self, int key) { - struct cmd_target_data *data; - - cmd_target_init(self, key); - data = self->data; - + self->args = args_create(0); if (key == ('n' | KEYC_ESCAPE)) - cmd_set_flag(&data->chflags, 'a'); + args_set(self->args, 'a', NULL); } int cmd_next_window_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; - struct session *s; - int activity; + struct args *args = self->args; + struct session *s; + int activity; - if ((s = cmd_find_session(ctx, data->target)) == NULL) + if ((s = cmd_find_session(ctx, args_get(args, 't'))) == NULL) return (-1); activity = 0; - if (cmd_check_flag(data->chflags, 'a')) + if (args_has(self->args, 'a')) activity = 1; if (session_next(s, activity) == 0) diff --git a/cmd-paste-buffer.c b/cmd-paste-buffer.c index 439d7190..0d145c7d 100644 --- a/cmd-paste-buffer.c +++ b/cmd-paste-buffer.c @@ -28,132 +28,73 @@ * Paste paste buffer if present. */ -struct cmd_paste_buffer_data { - char *target; - int buffer; - - int flag_delete; - char *sepstr; -}; - -void cmd_paste_buffer_init(struct cmd *, int); -int cmd_paste_buffer_parse(struct cmd *, int, char **, char **); int cmd_paste_buffer_exec(struct cmd *, struct cmd_ctx *); + void cmd_paste_buffer_filter( - struct window_pane *, const char *, size_t, char *); -void cmd_paste_buffer_free(struct cmd *); -size_t cmd_paste_buffer_print(struct cmd *, char *, size_t); + struct window_pane *, const char *, size_t, const char *); const struct cmd_entry cmd_paste_buffer_entry = { "paste-buffer", "pasteb", + "db:rs:t:", 0, 0, "[-dr] [-s separator] [-b buffer-index] [-t target-pane]", - 0, "", - cmd_paste_buffer_init, - cmd_paste_buffer_parse, - cmd_paste_buffer_exec, - cmd_paste_buffer_free, - cmd_paste_buffer_print + 0, + NULL, + NULL, + cmd_paste_buffer_exec }; -/* ARGSUSED */ -void -cmd_paste_buffer_init(struct cmd *self, unused int arg) -{ - struct cmd_paste_buffer_data *data; - - self->data = data = xmalloc(sizeof *data); - data->target = NULL; - data->buffer = -1; - data->flag_delete = 0; - data->sepstr = xstrdup("\r"); -} - -int -cmd_paste_buffer_parse(struct cmd *self, int argc, char **argv, char **cause) -{ - struct cmd_paste_buffer_data *data; - int opt, n; - const char *errstr; - - cmd_paste_buffer_init(self, 0); - data = self->data; - - while ((opt = getopt(argc, argv, "b:ds:t:r")) != -1) { - switch (opt) { - case 'b': - if (data->buffer == -1) { - n = strtonum(optarg, 0, INT_MAX, &errstr); - if (errstr != NULL) { - xasprintf(cause, "buffer %s", errstr); - goto error; - } - data->buffer = n; - } - break; - case 'd': - data->flag_delete = 1; - break; - case 's': - if (data->sepstr != NULL) - xfree(data->sepstr); - data->sepstr = xstrdup(optarg); - break; - case 't': - if (data->target == NULL) - data->target = xstrdup(optarg); - break; - case 'r': - if (data->sepstr != NULL) - xfree(data->sepstr); - data->sepstr = xstrdup("\n"); - break; - default: - goto usage; - } - } - argc -= optind; - argv += optind; - - return (0); - -usage: - xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); - -error: - self->entry->free(self); - return (-1); -} - int cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_paste_buffer_data *data = self->data; - struct window_pane *wp; - struct session *s; - struct paste_buffer *pb; + struct args *args = self->args; + struct window_pane *wp; + struct session *s; + struct paste_buffer *pb; + const char *sepstr; + char *cause; + int buffer; - if (cmd_find_pane(ctx, data->target, &s, &wp) == NULL) + if (cmd_find_pane(ctx, args_get(args, 't'), &s, &wp) == NULL) return (-1); - if (data->buffer == -1) - pb = paste_get_top(&global_buffers); + if (!args_has(args, 'b')) + buffer = -1; else { - pb = paste_get_index(&global_buffers, data->buffer); - if (pb == NULL) { - ctx->error(ctx, "no buffer %d", data->buffer); + buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause); + if (cause != NULL) { + ctx->error(ctx, "buffer %s", cause); + xfree(cause); return (-1); } } - if (pb != NULL) - cmd_paste_buffer_filter(wp, pb->data, pb->size, data->sepstr); + if (buffer == -1) + pb = paste_get_top(&global_buffers); + else { + pb = paste_get_index(&global_buffers, buffer); + if (pb == NULL) { + ctx->error(ctx, "no buffer %d", buffer); + return (-1); + } + } + + if (pb != NULL) { + sepstr = args_get(args, 's'); + if (sepstr == NULL) { + if (args_has(args, 'r')) + sepstr = "\n"; + else + sepstr = "\r"; + } + cmd_paste_buffer_filter(wp, pb->data, pb->size, sepstr); + } /* Delete the buffer if -d. */ - if (data->flag_delete) { - if (data->buffer == -1) + if (args_has(args, 'd')) { + if (buffer == -1) paste_free_top(&global_buffers); else - paste_free_index(&global_buffers, data->buffer); + paste_free_index(&global_buffers, buffer); } return (0); @@ -162,7 +103,7 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) /* Add bytes to a buffer and filter '\n' according to separator. */ void cmd_paste_buffer_filter( - struct window_pane *wp, const char *data, size_t size, char *sep) + struct window_pane *wp, const char *data, size_t size, const char *sep) { const char *end = data + size; const char *lf; @@ -179,46 +120,3 @@ cmd_paste_buffer_filter( if (end != data) bufferevent_write(wp->event, data, end - data); } - -void -cmd_paste_buffer_free(struct cmd *self) -{ - struct cmd_paste_buffer_data *data = self->data; - - if (data->target != NULL) - xfree(data->target); - if (data->sepstr != NULL) - xfree(data->sepstr); - xfree(data); -} - -size_t -cmd_paste_buffer_print(struct cmd *self, char *buf, size_t len) -{ - struct cmd_paste_buffer_data *data = self->data; - size_t off = 0; - char tmp[BUFSIZ]; - int r_flag; - - r_flag = 0; - if (data->sepstr != NULL) - r_flag = (data->sepstr[0] == '\n' && data->sepstr[1] == '\0'); - - off += xsnprintf(buf, len, "%s", self->entry->name); - if (data == NULL) - return (off); - if (off < len && data->flag_delete) - off += xsnprintf(buf + off, len - off, " -d"); - if (off < len && r_flag) - off += xsnprintf(buf + off, len - off, " -r"); - if (off < len && data->buffer != -1) - off += xsnprintf(buf + off, len - off, " -b %d", data->buffer); - if (off < len && data->sepstr != NULL && !r_flag) { - strnvis( - tmp, data->sepstr, sizeof tmp, VIS_OCTAL|VIS_TAB|VIS_NL); - off += cmd_prarg(buf + off, len - off, " -s ", tmp); - } - if (off < len && data->target != NULL) - off += cmd_prarg(buf + off, len - off, " -t ", data->target); - return (off); -} diff --git a/cmd-pipe-pane.c b/cmd-pipe-pane.c index d287d3b6..6284bf37 100644 --- a/cmd-pipe-pane.c +++ b/cmd-pipe-pane.c @@ -38,19 +38,18 @@ void cmd_pipe_pane_error_callback(struct bufferevent *, short, void *); const struct cmd_entry cmd_pipe_pane_entry = { "pipe-pane", "pipep", + "ot:", 0, 1, CMD_TARGET_PANE_USAGE "[-o] [command]", - CMD_ARG01, "o", - cmd_target_init, - cmd_target_parse, - cmd_pipe_pane_exec, - cmd_target_free, - cmd_target_print + 0, + NULL, + NULL, + cmd_pipe_pane_exec }; int cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; + struct args *args = self->args; struct client *c; struct window_pane *wp; char *command; @@ -59,7 +58,7 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx) if ((c = cmd_find_client(ctx, NULL)) == NULL) return (-1); - if (cmd_find_pane(ctx, data->target, NULL, &wp) == NULL) + if (cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp) == NULL) return (-1); /* Destroy the old pipe. */ @@ -71,7 +70,7 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx) } /* If no pipe command, that is enough. */ - if (data->arg == NULL || *data->arg == '\0') + if (args->argc == 0 || *args->argv[0] == '\0') return (0); /* @@ -80,7 +79,7 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx) * * bind ^p pipep -o 'cat >>~/output' */ - if (cmd_check_flag(data->chflags, 'o') && old_fd != -1) + if (args_has(self->args, 'o') && old_fd != -1) return (0); /* Open the new pipe. */ @@ -114,7 +113,7 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx) closefrom(STDERR_FILENO + 1); - command = status_replace(c, NULL, data->arg, time(NULL), 0); + command = status_replace(c, NULL, args->argv[0], time(NULL), 0); execl(_PATH_BSHELL, "sh", "-c", command, (char *) NULL); _exit(1); default: diff --git a/cmd-previous-layout.c b/cmd-previous-layout.c index 77e3ebbb..abe9e357 100644 --- a/cmd-previous-layout.c +++ b/cmd-previous-layout.c @@ -28,23 +28,22 @@ int cmd_previous_layout_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_previous_layout_entry = { "previous-layout", "prevl", + "t:", 0, 0, CMD_TARGET_WINDOW_USAGE, - 0, "", - cmd_target_init, - cmd_target_parse, - cmd_previous_layout_exec, - cmd_target_free, - cmd_target_print + 0, + NULL, + NULL, + cmd_previous_layout_exec }; int cmd_previous_layout_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; - struct winlink *wl; - u_int layout; + struct args *args = self->args; + struct winlink *wl; + u_int layout; - if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) + if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL) return (-1); layout = layout_set_previous(wl->window); diff --git a/cmd-previous-window.c b/cmd-previous-window.c index 0357e76d..c3f60a29 100644 --- a/cmd-previous-window.c +++ b/cmd-previous-window.c @@ -24,44 +24,39 @@ * Move to previous window. */ -void cmd_previous_window_init(struct cmd *, int); +void cmd_previous_window_key_binding(struct cmd *, int); int cmd_previous_window_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_previous_window_entry = { "previous-window", "prev", + "at:", 0, 0, "[-a] " CMD_TARGET_SESSION_USAGE, - 0, "a", - cmd_previous_window_init, - cmd_target_parse, - cmd_previous_window_exec, - cmd_target_free, - cmd_target_print + 0, + cmd_previous_window_key_binding, + NULL, + cmd_previous_window_exec }; void -cmd_previous_window_init(struct cmd *self, int key) +cmd_previous_window_key_binding(struct cmd *self, int key) { - struct cmd_target_data *data; - - cmd_target_init(self, key); - data = self->data; - + self->args = args_create(0); if (key == ('p' | KEYC_ESCAPE)) - cmd_set_flag(&data->chflags, 'a'); + args_set(self->args, 'a', NULL); } int cmd_previous_window_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; - struct session *s; - int activity; + struct args *args = self->args; + struct session *s; + int activity; - if ((s = cmd_find_session(ctx, data->target)) == NULL) + if ((s = cmd_find_session(ctx, args_get(args, 't'))) == NULL) return (-1); activity = 0; - if (cmd_check_flag(data->chflags, 'a')) + if (args_has(self->args, 'a')) activity = 1; if (session_previous(s, activity) == 0) diff --git a/cmd-refresh-client.c b/cmd-refresh-client.c index 03662a85..5186dcb9 100644 --- a/cmd-refresh-client.c +++ b/cmd-refresh-client.c @@ -28,22 +28,21 @@ int cmd_refresh_client_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_refresh_client_entry = { "refresh-client", "refresh", + "t:", 0, 0, CMD_TARGET_CLIENT_USAGE, - 0, "", - cmd_target_init, - cmd_target_parse, - cmd_refresh_client_exec, - cmd_target_free, - cmd_target_print + 0, + NULL, + NULL, + cmd_refresh_client_exec }; int cmd_refresh_client_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; - struct client *c; + struct args *args = self->args; + struct client *c; - if ((c = cmd_find_client(ctx, data->target)) == NULL) + if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL) return (-1); server_redraw_client(c); diff --git a/cmd-rename-session.c b/cmd-rename-session.c index bd9e787f..9ca43a7d 100644 --- a/cmd-rename-session.c +++ b/cmd-rename-session.c @@ -30,32 +30,33 @@ int cmd_rename_session_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_rename_session_entry = { "rename-session", "rename", + "t:", 1, 1, CMD_TARGET_SESSION_USAGE " new-name", - CMD_ARG1, "", - cmd_target_init, - cmd_target_parse, - cmd_rename_session_exec, - cmd_target_free, - cmd_target_print + 0, + NULL, + NULL, + cmd_rename_session_exec }; int cmd_rename_session_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; - struct session *s; + struct args *args = self->args; + struct session *s; + const char *newname; - if (data->arg != NULL && session_find(data->arg) != NULL) { - ctx->error(ctx, "duplicate session: %s", data->arg); + newname = args->argv[0]; + if (session_find(newname) != NULL) { + ctx->error(ctx, "duplicate session: %s", newname); return (-1); } - if ((s = cmd_find_session(ctx, data->target)) == NULL) + if ((s = cmd_find_session(ctx, args_get(args, 't'))) == NULL) return (-1); RB_REMOVE(sessions, &sessions, s); xfree(s->name); - s->name = xstrdup(data->arg); + s->name = xstrdup(newname); RB_INSERT(sessions, &sessions, s); server_status_session(s); diff --git a/cmd-rename-window.c b/cmd-rename-window.c index 112bd299..5f4783dd 100644 --- a/cmd-rename-window.c +++ b/cmd-rename-window.c @@ -30,27 +30,26 @@ int cmd_rename_window_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_rename_window_entry = { "rename-window", "renamew", + "t:", 1, 1, CMD_TARGET_WINDOW_USAGE " new-name", - CMD_ARG1, "", - cmd_target_init, - cmd_target_parse, - cmd_rename_window_exec, - cmd_target_free, - cmd_target_print + 0, + NULL, + NULL, + cmd_rename_window_exec }; int cmd_rename_window_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; - struct session *s; - struct winlink *wl; + struct args *args = self->args; + struct session *s; + struct winlink *wl; - if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL) + if ((wl = cmd_find_window(ctx, args_get(args, 't'), &s)) == NULL) return (-1); xfree(wl->window->name); - wl->window->name = xstrdup(data->arg); + wl->window->name = xstrdup(args->argv[0]); options_set_number(&wl->window->options, "automatic-rename", 0); server_status_window(wl->window); diff --git a/cmd-resize-pane.c b/cmd-resize-pane.c index 73a5f820..1380b283 100644 --- a/cmd-resize-pane.c +++ b/cmd-resize-pane.c @@ -26,84 +26,90 @@ * Increase or decrease pane size. */ -void cmd_resize_pane_init(struct cmd *, int); +void cmd_resize_pane_key_binding(struct cmd *, int); int cmd_resize_pane_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_resize_pane_entry = { "resize-pane", "resizep", + "DLRt:U", 0, 1, "[-DLRU] " CMD_TARGET_PANE_USAGE " [adjustment]", - CMD_ARG01, "DLRU", - cmd_resize_pane_init, - cmd_target_parse, - cmd_resize_pane_exec, - cmd_target_free, - cmd_target_print + 0, + cmd_resize_pane_key_binding, + NULL, + cmd_resize_pane_exec }; void -cmd_resize_pane_init(struct cmd *self, int key) +cmd_resize_pane_key_binding(struct cmd *self, int key) { - struct cmd_target_data *data; - - cmd_target_init(self, key); - data = self->data; - - if (key == (KEYC_UP | KEYC_CTRL)) - cmd_set_flag(&data->chflags, 'U'); - if (key == (KEYC_DOWN | KEYC_CTRL)) - cmd_set_flag(&data->chflags, 'D'); - if (key == (KEYC_LEFT | KEYC_CTRL)) - cmd_set_flag(&data->chflags, 'L'); - if (key == (KEYC_RIGHT | KEYC_CTRL)) - cmd_set_flag(&data->chflags, 'R'); - - if (key == (KEYC_UP | KEYC_ESCAPE)) { - cmd_set_flag(&data->chflags, 'U'); - data->arg = xstrdup("5"); - } - if (key == (KEYC_DOWN | KEYC_ESCAPE)) { - cmd_set_flag(&data->chflags, 'D'); - data->arg = xstrdup("5"); - } - if (key == (KEYC_LEFT | KEYC_ESCAPE)) { - cmd_set_flag(&data->chflags, 'L'); - data->arg = xstrdup("5"); - } - if (key == (KEYC_RIGHT | KEYC_ESCAPE)) { - cmd_set_flag(&data->chflags, 'R'); - data->arg = xstrdup("5"); + switch (key) { + case KEYC_UP | KEYC_CTRL: + self->args = args_create(0); + args_set(self->args, 'U', NULL); + break; + case KEYC_DOWN | KEYC_CTRL: + self->args = args_create(0); + args_set(self->args, 'D', NULL); + break; + case KEYC_LEFT | KEYC_CTRL: + self->args = args_create(0); + args_set(self->args, 'L', NULL); + break; + case KEYC_RIGHT | KEYC_CTRL: + self->args = args_create(0); + args_set(self->args, 'R', NULL); + break; + case KEYC_UP | KEYC_ESCAPE: + self->args = args_create(1, "5"); + args_set(self->args, 'U', NULL); + break; + case KEYC_DOWN | KEYC_ESCAPE: + self->args = args_create(1, "5"); + args_set(self->args, 'D', NULL); + break; + case KEYC_LEFT | KEYC_ESCAPE: + self->args = args_create(1, "5"); + args_set(self->args, 'L', NULL); + break; + case KEYC_RIGHT | KEYC_ESCAPE: + self->args = args_create(1, "5"); + args_set(self->args, 'R', NULL); + break; + default: + self->args = args_create(0); + break; } } int cmd_resize_pane_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; + struct args *args = self->args; struct winlink *wl; const char *errstr; struct window_pane *wp; u_int adjust; - if ((wl = cmd_find_pane(ctx, data->target, NULL, &wp)) == NULL) + if ((wl = cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp)) == NULL) return (-1); - if (data->arg == NULL) + if (args->argc == 0) adjust = 1; else { - adjust = strtonum(data->arg, 1, INT_MAX, &errstr); + adjust = strtonum(args->argv[0], 1, INT_MAX, &errstr); if (errstr != NULL) { - ctx->error(ctx, "adjustment %s: %s", errstr, data->arg); + ctx->error(ctx, "adjustment %s", errstr); return (-1); } } - if (cmd_check_flag(data->chflags, 'L')) + if (args_has(self->args, 'L')) layout_resize_pane(wp, LAYOUT_LEFTRIGHT, -adjust); - else if (cmd_check_flag(data->chflags, 'R')) + else if (args_has(self->args, 'R')) layout_resize_pane(wp, LAYOUT_LEFTRIGHT, adjust); - else if (cmd_check_flag(data->chflags, 'U')) + else if (args_has(self->args, 'U')) layout_resize_pane(wp, LAYOUT_TOPBOTTOM, -adjust); - else if (cmd_check_flag(data->chflags, 'D')) + else if (args_has(self->args, 'D')) layout_resize_pane(wp, LAYOUT_TOPBOTTOM, adjust); server_redraw_window(wl->window); diff --git a/cmd-respawn-window.c b/cmd-respawn-window.c index 4c8235e7..30601fe5 100644 --- a/cmd-respawn-window.c +++ b/cmd-respawn-window.c @@ -30,31 +30,31 @@ int cmd_respawn_window_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_respawn_window_entry = { "respawn-window", "respawnw", + "kt:", 0, 1, "[-k] " CMD_TARGET_WINDOW_USAGE " [command]", - CMD_ARG01, "k", - cmd_target_init, - cmd_target_parse, - cmd_respawn_window_exec, - cmd_target_free, - cmd_target_print + 0, + NULL, + NULL, + cmd_respawn_window_exec }; int cmd_respawn_window_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; + struct args *args = self->args; struct winlink *wl; struct window *w; struct window_pane *wp; struct session *s; struct environ env; + const char *cmd; char *cause; - if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL) + if ((wl = cmd_find_window(ctx, args_get(args, 't'), &s)) == NULL) return (-1); w = wl->window; - if (!cmd_check_flag(data->chflags, 'k')) { + if (!args_has(self->args, 'k')) { TAILQ_FOREACH(wp, &w->panes, entry) { if (wp->fd == -1) continue; @@ -75,8 +75,11 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_ctx *ctx) window_destroy_panes(w); TAILQ_INSERT_HEAD(&w->panes, wp, entry); window_pane_resize(wp, w->sx, w->sy); - if (window_pane_spawn( - wp, data->arg, NULL, NULL, &env, s->tio, &cause) != 0) { + if (args->argc != 0) + cmd = args->argv[0]; + else + cmd = NULL; + if (window_pane_spawn(wp, cmd, NULL, NULL, &env, s->tio, &cause) != 0) { ctx->error(ctx, "respawn window failed: %s", cause); xfree(cause); environ_free(&env); diff --git a/cmd-rotate-window.c b/cmd-rotate-window.c index fbfba099..1d752e74 100644 --- a/cmd-rotate-window.c +++ b/cmd-rotate-window.c @@ -24,47 +24,42 @@ * Rotate the panes in a window. */ -void cmd_rotate_window_init(struct cmd *, int); +void cmd_rotate_window_key_binding(struct cmd *, int); int cmd_rotate_window_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_rotate_window_entry = { "rotate-window", "rotatew", + "Dt:U", 0, 0, "[-DU] " CMD_TARGET_WINDOW_USAGE, - 0, "DU", - cmd_rotate_window_init, - cmd_target_parse, - cmd_rotate_window_exec, - cmd_target_free, - cmd_target_print + 0, + cmd_rotate_window_key_binding, + NULL, + cmd_rotate_window_exec }; void -cmd_rotate_window_init(struct cmd *self, int key) +cmd_rotate_window_key_binding(struct cmd *self, int key) { - struct cmd_target_data *data; - - cmd_target_init(self, key); - data = self->data; - + self->args = args_create(0); if (key == ('o' | KEYC_ESCAPE)) - cmd_set_flag(&data->chflags, 'D'); + args_set(self->args, 'D', NULL); } int cmd_rotate_window_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; + struct args *args = self->args; struct winlink *wl; struct window *w; struct window_pane *wp, *wp2; struct layout_cell *lc; u_int sx, sy, xoff, yoff; - if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) + if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL) return (-1); w = wl->window; - if (cmd_check_flag(data->chflags, 'D')) { + if (args_has(self->args, 'D')) { wp = TAILQ_LAST(&w->panes, window_panes); TAILQ_REMOVE(&w->panes, wp, entry); TAILQ_INSERT_HEAD(&w->panes, wp, entry); diff --git a/cmd-run-shell.c b/cmd-run-shell.c index 7bfb8916..189eeac9 100644 --- a/cmd-run-shell.c +++ b/cmd-run-shell.c @@ -35,13 +35,12 @@ void cmd_run_shell_free(void *); const struct cmd_entry cmd_run_shell_entry = { "run-shell", "run", + "", 1, 1, "command", - CMD_ARG1, "", - cmd_target_init, - cmd_target_parse, - cmd_run_shell_exec, - cmd_target_free, - cmd_target_print + 0, + NULL, + NULL, + cmd_run_shell_exec }; struct cmd_run_shell_data { @@ -52,12 +51,12 @@ struct cmd_run_shell_data { int cmd_run_shell_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; + struct args *args = self->args; struct cmd_run_shell_data *cdata; struct job *job; cdata = xmalloc(sizeof *cdata); - cdata->cmd = xstrdup(data->arg); + cdata->cmd = xstrdup(args->argv[0]); memcpy(&cdata->ctx, ctx, sizeof cdata->ctx); if (ctx->cmdclient != NULL) @@ -66,7 +65,7 @@ cmd_run_shell_exec(struct cmd *self, struct cmd_ctx *ctx) ctx->curclient->references++; job = job_add(NULL, 0, NULL, - data->arg, cmd_run_shell_callback, cmd_run_shell_free, cdata); + args->argv[0], cmd_run_shell_callback, cmd_run_shell_free, cdata); job_run(job); return (1); /* don't let client exit */ diff --git a/cmd-save-buffer.c b/cmd-save-buffer.c index 7a30d12b..6fd65696 100644 --- a/cmd-save-buffer.c +++ b/cmd-save-buffer.c @@ -32,56 +32,66 @@ int cmd_save_buffer_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_save_buffer_entry = { "save-buffer", "saveb", - "[-a] " CMD_BUFFER_USAGE " path", - CMD_ARG1, "a", - cmd_buffer_init, - cmd_buffer_parse, - cmd_save_buffer_exec, - cmd_buffer_free, - cmd_buffer_print + "ab:", 1, 1, + "[-a] " CMD_BUFFER_USAGE, + 0, + NULL, + NULL, + cmd_save_buffer_exec }; int cmd_save_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_buffer_data *data = self->data; + struct args *args = self->args; + struct client *c = ctx->cmdclient; struct paste_buffer *pb; + const char *path; + char *cause; + int buffer; mode_t mask; FILE *f; - if (data->buffer == -1) { + if (!args_has(args, 'b')) { if ((pb = paste_get_top(&global_buffers)) == NULL) { ctx->error(ctx, "no buffers"); return (-1); } } else { - pb = paste_get_index(&global_buffers, data->buffer); + buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause); + if (cause != NULL) { + ctx->error(ctx, "buffer %s", cause); + xfree(cause); + return (-1); + } + + pb = paste_get_index(&global_buffers, buffer); if (pb == NULL) { - ctx->error(ctx, "no buffer %d", data->buffer); + ctx->error(ctx, "no buffer %d", buffer); return (-1); } } - if (strcmp(data->arg, "-") == 0) { - if (ctx->cmdclient == NULL) { - ctx->error(ctx, "%s: can't write to stdout", data->arg); + path = args->argv[0]; + if (strcmp(path, "-") == 0) { + if (c == NULL) { + ctx->error(ctx, "%s: can't write to stdout", path); return (-1); } - bufferevent_write( - ctx->cmdclient->stdout_event, pb->data, pb->size); + bufferevent_write(c->stdout_event, pb->data, pb->size); } else { mask = umask(S_IRWXG | S_IRWXO); - if (cmd_check_flag(data->chflags, 'a')) - f = fopen(data->arg, "ab"); + if (args_has(self->args, 'a')) + f = fopen(path, "ab"); else - f = fopen(data->arg, "wb"); + f = fopen(path, "wb"); umask(mask); if (f == NULL) { - ctx->error(ctx, "%s: %s", data->arg, strerror(errno)); + ctx->error(ctx, "%s: %s", path, strerror(errno)); return (-1); } if (fwrite(pb->data, 1, pb->size, f) != pb->size) { - ctx->error(ctx, "%s: fwrite error", data->arg); + ctx->error(ctx, "%s: fwrite error", path); fclose(f); return (-1); } diff --git a/cmd-select-layout.c b/cmd-select-layout.c index 70f7125f..df977b0f 100644 --- a/cmd-select-layout.c +++ b/cmd-select-layout.c @@ -24,43 +24,40 @@ * Switch window to selected layout. */ -void cmd_select_layout_init(struct cmd *, int); +void cmd_select_layout_key_binding(struct cmd *, int); int cmd_select_layout_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_select_layout_entry = { "select-layout", "selectl", + "t:", 0, 1, CMD_TARGET_WINDOW_USAGE " [layout-name]", - CMD_ARG01, "", - cmd_select_layout_init, - cmd_target_parse, - cmd_select_layout_exec, - cmd_target_free, - cmd_target_print + 0, + cmd_select_layout_key_binding, + NULL, + cmd_select_layout_exec }; void -cmd_select_layout_init(struct cmd *self, int key) +cmd_select_layout_key_binding(struct cmd *self, int key) { - struct cmd_target_data *data; - - cmd_target_init(self, key); - data = self->data; - switch (key) { - case ('1' | KEYC_ESCAPE): - data->arg = xstrdup("even-horizontal"); + case '1' | KEYC_ESCAPE: + self->args = args_create(1, "even-horizontal"); break; - case ('2' | KEYC_ESCAPE): - data->arg = xstrdup("even-vertical"); + case '2' | KEYC_ESCAPE: + self->args = args_create(1, "even-vertical"); break; - case ('3' | KEYC_ESCAPE): - data->arg = xstrdup("main-horizontal"); + case '3' | KEYC_ESCAPE: + self->args = args_create(1, "main-horizontal"); break; - case ('4' | KEYC_ESCAPE): - data->arg = xstrdup("main-vertical"); + case '4' | KEYC_ESCAPE: + self->args = args_create(1, "main-vertical"); break; - case ('5' | KEYC_ESCAPE): - data->arg = xstrdup("tiled"); + case '5' | KEYC_ESCAPE: + self->args = args_create(1, "tiled"); + break; + default: + self->args = args_create(0); break; } } @@ -68,26 +65,32 @@ cmd_select_layout_init(struct cmd *self, int key) int cmd_select_layout_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; - struct winlink *wl; - int layout; + struct args *args = self->args; + struct winlink *wl; + const char *layoutname; + int layout; - if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) + if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL) return (-1); - if (data->arg == NULL) { + if (args->argc == 0) layout = wl->window->lastlayout; - if (layout == -1) - return (0); - } else if ((layout = layout_set_lookup(data->arg)) != -1) { + else + layout = layout_set_lookup(args->argv[0]); + if (layout != -1) { layout = layout_set_select(wl->window, layout); ctx->info(ctx, "arranging in: %s", layout_set_name(layout)); - } else { - if (layout_parse(wl->window, data->arg) == -1) { - ctx->error(ctx, "can't set layout: %s", data->arg); + return (0); + } + + if (args->argc != 0) { + layoutname = args->argv[0]; + if (layout_parse(wl->window, layoutname) == -1) { + ctx->error(ctx, "can't set layout: %s", layoutname); return (-1); } - ctx->info(ctx, "arranging in: %s", data->arg); + ctx->info(ctx, "arranging in: %s", layoutname); + return (0); } return (0); diff --git a/cmd-select-pane.c b/cmd-select-pane.c index b5defa2e..a250bb6e 100644 --- a/cmd-select-pane.c +++ b/cmd-select-pane.c @@ -24,62 +24,57 @@ * Select pane. */ -void cmd_select_pane_init(struct cmd *, int); +void cmd_select_pane_key_binding(struct cmd *, int); int cmd_select_pane_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_select_pane_entry = { "select-pane", "selectp", + "DLRt:U", 0, 0, "[-DLRU] " CMD_TARGET_PANE_USAGE, - 0, "DLRU", - cmd_select_pane_init, - cmd_target_parse, - cmd_select_pane_exec, - cmd_target_free, - cmd_target_print + 0, + cmd_select_pane_key_binding, + NULL, + cmd_select_pane_exec }; void -cmd_select_pane_init(struct cmd *self, int key) +cmd_select_pane_key_binding(struct cmd *self, int key) { - struct cmd_target_data *data; - - cmd_target_init(self, key); - data = self->data; - + self->args = args_create(0); if (key == KEYC_UP) - cmd_set_flag(&data->chflags, 'U'); + args_set(self->args, 'U', NULL); if (key == KEYC_DOWN) - cmd_set_flag(&data->chflags, 'D'); + args_set(self->args, 'D', NULL); if (key == KEYC_LEFT) - cmd_set_flag(&data->chflags, 'L'); + args_set(self->args, 'L', NULL); if (key == KEYC_RIGHT) - cmd_set_flag(&data->chflags, 'R'); + args_set(self->args, 'R', NULL); if (key == 'o') - data->target = xstrdup(":.+"); + args_set(self->args, 't', ":.+"); } int cmd_select_pane_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; + struct args *args = self->args; struct winlink *wl; struct window_pane *wp; - if ((wl = cmd_find_pane(ctx, data->target, NULL, &wp)) == NULL) + if ((wl = cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp)) == NULL) return (-1); if (!window_pane_visible(wp)) { - ctx->error(ctx, "pane not visible: %s", data->target); + ctx->error(ctx, "pane not visible"); return (-1); } - if (cmd_check_flag(data->chflags, 'L')) + if (args_has(self->args, 'L')) wp = window_pane_find_left(wp); - else if (cmd_check_flag(data->chflags, 'R')) + else if (args_has(self->args, 'R')) wp = window_pane_find_right(wp); - else if (cmd_check_flag(data->chflags, 'U')) + else if (args_has(self->args, 'U')) wp = window_pane_find_up(wp); - else if (cmd_check_flag(data->chflags, 'D')) + else if (args_has(self->args, 'D')) wp = window_pane_find_down(wp); if (wp == NULL) { ctx->error(ctx, "pane not found"); diff --git a/cmd-select-window.c b/cmd-select-window.c index 6aeaad22..c414af3a 100644 --- a/cmd-select-window.c +++ b/cmd-select-window.c @@ -26,39 +26,38 @@ * Select window by index. */ -void cmd_select_window_init(struct cmd *, int); +void cmd_select_window_key_binding(struct cmd *, int); int cmd_select_window_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_select_window_entry = { "select-window", "selectw", + "t:", 0, 0, CMD_TARGET_WINDOW_USAGE, - 0, "", - cmd_select_window_init, - cmd_target_parse, - cmd_select_window_exec, - cmd_target_free, - cmd_target_print + 0, + cmd_select_window_key_binding, + NULL, + cmd_select_window_exec }; void -cmd_select_window_init(struct cmd *self, int key) +cmd_select_window_key_binding(struct cmd *self, int key) { - struct cmd_target_data *data; + char tmp[16]; - cmd_target_init(self, key); - data = self->data; + xsnprintf(tmp, sizeof tmp, ":%d", key - '0'); - xasprintf(&data->target, ":%d", key - '0'); + self->args = args_create(0); + args_set(self->args, 't', tmp); } int cmd_select_window_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; - struct winlink *wl; - struct session *s; + struct args *args = self->args; + struct winlink *wl; + struct session *s; - if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL) + if ((wl = cmd_find_window(ctx, args_get(args, 't'), &s)) == NULL) return (-1); if (session_select(s, wl->idx) == 0) diff --git a/cmd-send-keys.c b/cmd-send-keys.c index 3c680524..8181e563 100644 --- a/cmd-send-keys.c +++ b/cmd-send-keys.c @@ -26,128 +26,40 @@ * Send keys to client. */ -int cmd_send_keys_parse(struct cmd *, int, char **, char **); int cmd_send_keys_exec(struct cmd *, struct cmd_ctx *); -void cmd_send_keys_free(struct cmd *); -size_t cmd_send_keys_print(struct cmd *, char *, size_t); - -struct cmd_send_keys_data { - char *target; - u_int nkeys; - int *keys; -}; const struct cmd_entry cmd_send_keys_entry = { "send-keys", "send", + "t:", 0, -1, "[-t target-pane] key ...", - 0, "", + 0, NULL, - cmd_send_keys_parse, - cmd_send_keys_exec, - cmd_send_keys_free, - cmd_send_keys_print + NULL, + cmd_send_keys_exec }; -int -cmd_send_keys_parse(struct cmd *self, int argc, char **argv, char **cause) -{ - struct cmd_send_keys_data *data; - int opt, key; - char *s; - - self->data = data = xmalloc(sizeof *data); - data->target = NULL; - data->nkeys = 0; - data->keys = NULL; - - while ((opt = getopt(argc, argv, "t:")) != -1) { - switch (opt) { - case 't': - if (data->target == NULL) - data->target = xstrdup(optarg); - break; - default: - goto usage; - } - } - argc -= optind; - argv += optind; - if (argc == 0) - goto usage; - - while (argc-- != 0) { - if ((key = key_string_lookup_string(*argv)) != KEYC_NONE) { - data->keys = xrealloc( - data->keys, data->nkeys + 1, sizeof *data->keys); - data->keys[data->nkeys++] = key; - } else { - for (s = *argv; *s != '\0'; s++) { - data->keys = xrealloc(data->keys, - data->nkeys + 1, sizeof *data->keys); - data->keys[data->nkeys++] = *s; - } - } - - argv++; - } - - return (0); - -usage: - xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); - - self->entry->free(self); - return (-1); -} - int cmd_send_keys_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_send_keys_data *data = self->data; - struct window_pane *wp; - struct session *s; - u_int i; + struct args *args = self->args; + struct window_pane *wp; + struct session *s; + const char *str; + int i, key; - if (data == NULL) + if (cmd_find_pane(ctx, args_get(args, 't'), &s, &wp) == NULL) return (-1); - if (cmd_find_pane(ctx, data->target, &s, &wp) == NULL) - return (-1); + for (i = 0; i < args->argc; i++) { + str = args->argv[i]; - for (i = 0; i < data->nkeys; i++) - window_pane_key(wp, s, data->keys[i]); + if ((key = key_string_lookup_string(str)) != KEYC_NONE) { + window_pane_key(wp, s, key); + } else { + for (; *str != '\0'; str++) + window_pane_key(wp, s, *str); + } + } return (0); } - -void -cmd_send_keys_free(struct cmd *self) -{ - struct cmd_send_keys_data *data = self->data; - - if (data->target != NULL) - xfree(data->target); - xfree(data); -} - -size_t -cmd_send_keys_print(struct cmd *self, char *buf, size_t len) -{ - struct cmd_send_keys_data *data = self->data; - size_t off = 0; - u_int i; - - off += xsnprintf(buf, len, "%s", self->entry->name); - if (data == NULL) - return (off); - if (off < len && data->target != NULL) - off += cmd_prarg(buf + off, len - off, " -t ", data->target); - - for (i = 0; i < data->nkeys; i++) { - if (off >= len) - break; - off += xsnprintf(buf + off, - len - off, " %s", key_string_lookup_key(data->keys[i])); - } - return (off); -} diff --git a/cmd-send-prefix.c b/cmd-send-prefix.c index c7f7e9fa..398f440e 100644 --- a/cmd-send-prefix.c +++ b/cmd-send-prefix.c @@ -28,24 +28,23 @@ int cmd_send_prefix_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_send_prefix_entry = { "send-prefix", NULL, + "t:", 0, 0, CMD_TARGET_PANE_USAGE, - 0, "", - cmd_target_init, - cmd_target_parse, - cmd_send_prefix_exec, - cmd_target_free, - cmd_target_print + 0, + NULL, + NULL, + cmd_send_prefix_exec }; int cmd_send_prefix_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; + struct args *args = self->args; struct session *s; struct window_pane *wp; struct keylist *keylist; - if (cmd_find_pane(ctx, data->target, &s, &wp) == NULL) + if (cmd_find_pane(ctx, args_get(args, 't'), &s, &wp) == NULL) return (-1); keylist = options_get_data(&s->options, "prefix"); diff --git a/cmd-server-info.c b/cmd-server-info.c index 51a42219..4bd65143 100644 --- a/cmd-server-info.c +++ b/cmd-server-info.c @@ -35,13 +35,12 @@ int cmd_server_info_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_server_info_entry = { "server-info", "info", + "", 0, 0, "", - 0, "", + 0, NULL, NULL, - cmd_server_info_exec, - NULL, - NULL + cmd_server_info_exec }; /* ARGSUSED */ diff --git a/cmd-set-buffer.c b/cmd-set-buffer.c index 376adb14..f31f8a06 100644 --- a/cmd-set-buffer.c +++ b/cmd-set-buffer.c @@ -30,36 +30,45 @@ int cmd_set_buffer_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_set_buffer_entry = { "set-buffer", "setb", + "b:", 1, 1, CMD_BUFFER_USAGE " data", - CMD_ARG1, "", - cmd_buffer_init, - cmd_buffer_parse, - cmd_set_buffer_exec, - cmd_buffer_free, - cmd_buffer_print + 0, + NULL, + NULL, + cmd_set_buffer_exec }; int cmd_set_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_buffer_data *data = self->data; - u_int limit; - char *pdata; - size_t psize; + struct args *args = self->args; + u_int limit; + char *pdata, *cause; + size_t psize; + int buffer; limit = options_get_number(&global_options, "buffer-limit"); - pdata = xstrdup(data->arg); + pdata = xstrdup(args->argv[0]); psize = strlen(pdata); - if (data->buffer == -1) { + if (!args_has(args, 'b')) { paste_add(&global_buffers, pdata, psize, limit); return (0); } - if (paste_replace(&global_buffers, data->buffer, pdata, psize) != 0) { - ctx->error(ctx, "no buffer %d", data->buffer); + + buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause); + if (cause != NULL) { + ctx->error(ctx, "buffer %s", cause); + xfree(cause); + return (-1); + } + + if (paste_replace(&global_buffers, buffer, pdata, psize) != 0) { + ctx->error(ctx, "no buffer %d", buffer); xfree(pdata); return (-1); } + return (0); } diff --git a/cmd-set-environment.c b/cmd-set-environment.c index fdd703c5..3075fb07 100644 --- a/cmd-set-environment.c +++ b/cmd-set-environment.c @@ -31,57 +31,63 @@ int cmd_set_environment_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_set_environment_entry = { "set-environment", "setenv", + "grt:u", 1, 2, "[-gru] " CMD_TARGET_SESSION_USAGE " name [value]", - CMD_ARG12, "gru", + 0, NULL, - cmd_target_parse, - cmd_set_environment_exec, - cmd_target_free, - cmd_target_print + NULL, + cmd_set_environment_exec }; int cmd_set_environment_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; - struct session *s; - struct environ *env; + struct args *args = self->args; + struct session *s; + struct environ *env; + const char *name, *value; - if (*data->arg == '\0') { + name = args->argv[0]; + if (*name == '\0') { ctx->error(ctx, "empty variable name"); return (-1); } - if (strchr(data->arg, '=') != NULL) { + if (strchr(name, '=') != NULL) { ctx->error(ctx, "variable name contains ="); return (-1); } - if (cmd_check_flag(data->chflags, 'g')) + if (args->argc < 1) + value = NULL; + else + value = args->argv[1]; + + if (args_has(self->args, 'g')) env = &global_environ; else { - if ((s = cmd_find_session(ctx, data->target)) == NULL) + if ((s = cmd_find_session(ctx, args_get(args, 't'))) == NULL) return (-1); env = &s->environ; } - if (cmd_check_flag(data->chflags, 'u')) { - if (data->arg2 != NULL) { + if (args_has(self->args, 'u')) { + if (value != NULL) { ctx->error(ctx, "can't specify a value with -u"); return (-1); } - environ_unset(env, data->arg); - } else if (cmd_check_flag(data->chflags, 'r')) { - if (data->arg2 != NULL) { + environ_unset(env, name); + } else if (args_has(self->args, 'r')) { + if (value != NULL) { ctx->error(ctx, "can't specify a value with -r"); return (-1); } - environ_set(env, data->arg, NULL); + environ_set(env, name, NULL); } else { - if (data->arg2 == NULL) { + if (value == NULL) { ctx->error(ctx, "no value specified"); return (-1); } - environ_set(env, data->arg, data->arg2); + environ_set(env, name, value); } return (0); diff --git a/cmd-set-option.c b/cmd-set-option.c index f15ce052..2aa99f10 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -30,40 +30,48 @@ int cmd_set_option_exec(struct cmd *, struct cmd_ctx *); int cmd_set_option_unset(struct cmd *, struct cmd_ctx *, - const struct options_table_entry *, struct options *); + const struct options_table_entry *, struct options *, + const char *); int cmd_set_option_set(struct cmd *, struct cmd_ctx *, - const struct options_table_entry *, struct options *); + const struct options_table_entry *, struct options *, + const char *); struct options_entry *cmd_set_option_string(struct cmd *, struct cmd_ctx *, - const struct options_table_entry *, struct options *); + const struct options_table_entry *, struct options *, + const char *); struct options_entry *cmd_set_option_number(struct cmd *, struct cmd_ctx *, - const struct options_table_entry *, struct options *); + const struct options_table_entry *, struct options *, + const char *); struct options_entry *cmd_set_option_keys(struct cmd *, struct cmd_ctx *, - const struct options_table_entry *, struct options *); + const struct options_table_entry *, struct options *, + const char *); struct options_entry *cmd_set_option_colour(struct cmd *, struct cmd_ctx *, - const struct options_table_entry *, struct options *); + const struct options_table_entry *, struct options *, + const char *); struct options_entry *cmd_set_option_attributes(struct cmd *, struct cmd_ctx *, - const struct options_table_entry *, struct options *); + const struct options_table_entry *, struct options *, + const char *); struct options_entry *cmd_set_option_flag(struct cmd *, struct cmd_ctx *, - const struct options_table_entry *, struct options *); + const struct options_table_entry *, struct options *, + const char *); struct options_entry *cmd_set_option_choice(struct cmd *, struct cmd_ctx *, - const struct options_table_entry *, struct options *); + const struct options_table_entry *, struct options *, + const char *); const struct cmd_entry cmd_set_option_entry = { "set-option", "set", + "agst:uw", 1, 2, "[-agsuw] [-t target-session|target-window] option [value]", - CMD_ARG12, "agsuw", + 0, NULL, - cmd_target_parse, - cmd_set_option_exec, - cmd_target_free, - cmd_target_print + NULL, + cmd_set_option_exec }; int cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; + struct args *args = self->args; const struct options_table_entry *table, *oe, *oe_loop; struct session *s; struct winlink *wl; @@ -71,61 +79,74 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) struct options *oo; struct jobs *jobs; struct job *job, *nextjob; + const char *optstr, *valstr; u_int i; int try_again; /* Work out the options tree and table to use. */ - if (cmd_check_flag(data->chflags, 's')) { + if (args_has(self->args, 's')) { oo = &global_options; table = server_options_table; - } else if (cmd_check_flag(data->chflags, 'w')) { + } else if (args_has(self->args, 'w')) { table = window_options_table; - if (cmd_check_flag(data->chflags, 'g')) + if (args_has(self->args, 'g')) oo = &global_w_options; else { - wl = cmd_find_window(ctx, data->target, NULL); + wl = cmd_find_window(ctx, args_get(args, 't'), NULL); if (wl == NULL) return (-1); oo = &wl->window->options; } } else { table = session_options_table; - if (cmd_check_flag(data->chflags, 'g')) + if (args_has(self->args, 'g')) oo = &global_s_options; else { - s = cmd_find_session(ctx, data->target); + s = cmd_find_session(ctx, args_get(args, 't')); if (s == NULL) return (-1); oo = &s->options; } } + /* Get the option name and value. */ + optstr = args->argv[0]; + if (*optstr == '\0') { + ctx->error(ctx, "invalid option"); + return (-1); + } + if (args->argc < 1) + valstr = NULL; + else + valstr = args->argv[1]; + /* Find the option table entry. */ oe = NULL; for (oe_loop = table; oe_loop->name != NULL; oe_loop++) { - if (strncmp(oe_loop->name, data->arg, strlen(data->arg)) != 0) + if (strncmp(oe_loop->name, optstr, strlen(optstr)) != 0) continue; + if (oe != NULL) { - ctx->error(ctx, "ambiguous option: %s", data->arg); + ctx->error(ctx, "ambiguous option: %s", optstr); return (-1); } oe = oe_loop; /* Bail now if an exact match. */ - if (strcmp(oe->name, data->arg) == 0) + if (strcmp(oe->name, optstr) == 0) break; } if (oe == NULL) { - ctx->error(ctx, "unknown option: %s", data->arg); + ctx->error(ctx, "unknown option: %s", optstr); return (-1); } /* Unset or set the option. */ - if (cmd_check_flag(data->chflags, 'u')) { - if (cmd_set_option_unset(self, ctx, oe, oo) != 0) + if (args_has(args, 'u')) { + if (cmd_set_option_unset(self, ctx, oe, oo, valstr) != 0) return (-1); } else { - if (cmd_set_option_set(self, ctx, oe, oo) != 0) + if (cmd_set_option_set(self, ctx, oe, oo, valstr) != 0) return (-1); } @@ -176,15 +197,15 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) /* Unset an option. */ int cmd_set_option_unset(struct cmd *self, struct cmd_ctx *ctx, - const struct options_table_entry *oe, struct options *oo) + const struct options_table_entry *oe, struct options *oo, const char *value) { - struct cmd_target_data *data = self->data; + struct args *args = self->args; - if (cmd_check_flag(data->chflags, 'g')) { + if (args_has(args, 'g')) { ctx->error(ctx, "can't unset global option: %s", oe->name); return (-1); } - if (data->arg2 != NULL) { + if (value != NULL) { ctx->error(ctx, "value passed to unset option: %s", oe->name); return (-1); } @@ -197,39 +218,38 @@ cmd_set_option_unset(struct cmd *self, struct cmd_ctx *ctx, /* Set an option. */ int cmd_set_option_set(struct cmd *self, struct cmd_ctx *ctx, - const struct options_table_entry *oe, struct options *oo) + const struct options_table_entry *oe, struct options *oo, const char *value) { - struct cmd_target_data *data = self->data; struct options_entry *o; const char *s; - if (oe->type != OPTIONS_TABLE_FLAG && data->arg2 == NULL) { - ctx->error(ctx, "empty data->arg2"); + if (oe->type != OPTIONS_TABLE_FLAG && value == NULL) { + ctx->error(ctx, "empty value"); return (-1); } o = NULL; switch (oe->type) { case OPTIONS_TABLE_STRING: - o = cmd_set_option_string(self, ctx, oe, oo); + o = cmd_set_option_string(self, ctx, oe, oo, value); break; case OPTIONS_TABLE_NUMBER: - o = cmd_set_option_number(self, ctx, oe, oo); + o = cmd_set_option_number(self, ctx, oe, oo, value); break; case OPTIONS_TABLE_KEYS: - o = cmd_set_option_keys(self, ctx, oe, oo); + o = cmd_set_option_keys(self, ctx, oe, oo, value); break; case OPTIONS_TABLE_COLOUR: - o = cmd_set_option_colour(self, ctx, oe, oo); + o = cmd_set_option_colour(self, ctx, oe, oo, value); break; case OPTIONS_TABLE_ATTRIBUTES: - o = cmd_set_option_attributes(self, ctx, oe, oo); + o = cmd_set_option_attributes(self, ctx, oe, oo, value); break; case OPTIONS_TABLE_FLAG: - o = cmd_set_option_flag(self, ctx, oe, oo); + o = cmd_set_option_flag(self, ctx, oe, oo, value); break; case OPTIONS_TABLE_CHOICE: - o = cmd_set_option_choice(self, ctx, oe, oo); + o = cmd_set_option_choice(self, ctx, oe, oo, value); break; } if (o == NULL) @@ -243,37 +263,35 @@ cmd_set_option_set(struct cmd *self, struct cmd_ctx *ctx, /* Set a string option. */ struct options_entry * cmd_set_option_string(struct cmd *self, unused struct cmd_ctx *ctx, - const struct options_table_entry *oe, struct options *oo) + const struct options_table_entry *oe, struct options *oo, const char *value) { - struct cmd_target_data *data = self->data; + struct args *args = self->args; struct options_entry *o; char *oldval, *newval; - if (cmd_check_flag(data->chflags, 'a')) { + if (args_has(args, 'a')) { oldval = options_get_string(oo, oe->name); - xasprintf(&newval, "%s%s", oldval, data->arg2); + xasprintf(&newval, "%s%s", oldval, value); } else - newval = data->arg2; + newval = xstrdup(value); o = options_set_string(oo, oe->name, "%s", newval); - if (newval != data->arg2) - xfree(newval); + xfree(newval); return (o); } /* Set a number option. */ struct options_entry * -cmd_set_option_number(struct cmd *self, struct cmd_ctx *ctx, - const struct options_table_entry *oe, struct options *oo) +cmd_set_option_number(unused struct cmd *self, struct cmd_ctx *ctx, + const struct options_table_entry *oe, struct options *oo, const char *value) { - struct cmd_target_data *data = self->data; - long long ll; - const char *errstr; + long long ll; + const char *errstr; - ll = strtonum(data->arg2, oe->minimum, oe->maximum, &errstr); + ll = strtonum(value, oe->minimum, oe->maximum, &errstr); if (errstr != NULL) { - ctx->error(ctx, "value is %s: %s", errstr, data->arg2); + ctx->error(ctx, "value is %s: %s", errstr, value); return (NULL); } @@ -282,18 +300,17 @@ cmd_set_option_number(struct cmd *self, struct cmd_ctx *ctx, /* Set a keys option. */ struct options_entry * -cmd_set_option_keys(struct cmd *self, struct cmd_ctx *ctx, - const struct options_table_entry *oe, struct options *oo) +cmd_set_option_keys(unused struct cmd *self, struct cmd_ctx *ctx, + const struct options_table_entry *oe, struct options *oo, const char *value) { - struct cmd_target_data *data = self->data; - struct keylist *keylist; - char *copy, *ptr, *s; - int key; + struct keylist *keylist; + char *copy, *ptr, *s; + int key; keylist = xmalloc(sizeof *keylist); ARRAY_INIT(keylist); - ptr = copy = xstrdup(data->arg2); + ptr = copy = xstrdup(value); while ((s = strsep(&ptr, ",")) != NULL) { if ((key = key_string_lookup_string(s)) == KEYC_NONE) { ctx->error(ctx, "unknown key: %s", s); @@ -310,14 +327,13 @@ cmd_set_option_keys(struct cmd *self, struct cmd_ctx *ctx, /* Set a colour option. */ struct options_entry * -cmd_set_option_colour(struct cmd *self, struct cmd_ctx *ctx, - const struct options_table_entry *oe, struct options *oo) +cmd_set_option_colour(unused struct cmd *self, struct cmd_ctx *ctx, + const struct options_table_entry *oe, struct options *oo, const char *value) { - struct cmd_target_data *data = self->data; - int colour; + int colour; - if ((colour = colour_fromstring(data->arg2)) == -1) { - ctx->error(ctx, "bad colour: %s", data->arg2); + if ((colour = colour_fromstring(value)) == -1) { + ctx->error(ctx, "bad colour: %s", value); return (NULL); } @@ -326,14 +342,13 @@ cmd_set_option_colour(struct cmd *self, struct cmd_ctx *ctx, /* Set an attributes option. */ struct options_entry * -cmd_set_option_attributes(struct cmd *self, struct cmd_ctx *ctx, - const struct options_table_entry *oe, struct options *oo) +cmd_set_option_attributes(unused struct cmd *self, struct cmd_ctx *ctx, + const struct options_table_entry *oe, struct options *oo, const char *value) { - struct cmd_target_data *data = self->data; - int attr; + int attr; - if ((attr = attributes_fromstring(data->arg2)) == -1) { - ctx->error(ctx, "bad attributes: %s", data->arg2); + if ((attr = attributes_fromstring(value)) == -1) { + ctx->error(ctx, "bad attributes: %s", value); return (NULL); } @@ -342,25 +357,24 @@ cmd_set_option_attributes(struct cmd *self, struct cmd_ctx *ctx, /* Set a flag option. */ struct options_entry * -cmd_set_option_flag(struct cmd *self, struct cmd_ctx *ctx, - const struct options_table_entry *oe, struct options *oo) +cmd_set_option_flag(unused struct cmd *self, struct cmd_ctx *ctx, + const struct options_table_entry *oe, struct options *oo, const char *value) { - struct cmd_target_data *data = self->data; - int flag; + int flag; - if (data->arg2 == NULL || *data->arg2 == '\0') + if (value == NULL || *value == '\0') flag = !options_get_number(oo, oe->name); else { - if ((data->arg2[0] == '1' && data->arg2[1] == '\0') || - strcasecmp(data->arg2, "on") == 0 || - strcasecmp(data->arg2, "yes") == 0) + if ((value[0] == '1' && value[1] == '\0') || + strcasecmp(value, "on") == 0 || + strcasecmp(value, "yes") == 0) flag = 1; - else if ((data->arg2[0] == '0' && data->arg2[1] == '\0') || - strcasecmp(data->arg2, "off") == 0 || - strcasecmp(data->arg2, "no") == 0) + else if ((value[0] == '0' && value[1] == '\0') || + strcasecmp(value, "off") == 0 || + strcasecmp(value, "no") == 0) flag = 0; else { - ctx->error(ctx, "bad value: %s", data->arg2); + ctx->error(ctx, "bad value: %s", value); return (NULL); } } @@ -370,27 +384,26 @@ cmd_set_option_flag(struct cmd *self, struct cmd_ctx *ctx, /* Set a choice option. */ struct options_entry * -cmd_set_option_choice(struct cmd *self, struct cmd_ctx *ctx, - const struct options_table_entry *oe, struct options *oo) +cmd_set_option_choice(unused struct cmd *self, struct cmd_ctx *ctx, + const struct options_table_entry *oe, struct options *oo, const char *value) { - struct cmd_target_data *data = self->data; - const char **choicep; - int n, choice = -1; + const char **choicep; + int n, choice = -1; n = 0; for (choicep = oe->choices; *choicep != NULL; choicep++) { n++; - if (strncmp(*choicep, data->arg2, strlen(data->arg2)) != 0) + if (strncmp(*choicep, value, strlen(value)) != 0) continue; if (choice != -1) { - ctx->error(ctx, "ambiguous value: %s", data->arg2); + ctx->error(ctx, "ambiguous value: %s", value); return (NULL); } choice = n - 1; } if (choice == -1) { - ctx->error(ctx, "unknown value: %s", data->arg2); + ctx->error(ctx, "unknown value: %s", value); return (NULL); } diff --git a/cmd-set-window-option.c b/cmd-set-window-option.c index 559d6485..3a750476 100644 --- a/cmd-set-window-option.c +++ b/cmd-set-window-option.c @@ -28,20 +28,19 @@ int cmd_set_window_option_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_set_window_option_entry = { "set-window-option", "setw", + "agt:u", 1, 2, "[-agu] " CMD_TARGET_WINDOW_USAGE " option [value]", - CMD_ARG12, "agu", + 0, NULL, - cmd_target_parse, - cmd_set_window_option_exec, - cmd_target_free, - cmd_target_print + NULL, + cmd_set_window_option_exec }; int cmd_set_window_option_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; + struct args *args = self->args; - cmd_set_flag(&data->chflags, 'w'); + args_set(args, 'w', NULL); return (cmd_set_option_entry.exec(self, ctx)); } diff --git a/cmd-show-buffer.c b/cmd-show-buffer.c index b6d0c231..256818f5 100644 --- a/cmd-show-buffer.c +++ b/cmd-show-buffer.c @@ -30,37 +30,44 @@ int cmd_show_buffer_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_show_buffer_entry = { "show-buffer", "showb", + "b:", 0, 0, CMD_BUFFER_USAGE, - 0, "", - cmd_buffer_init, - cmd_buffer_parse, - cmd_show_buffer_exec, - cmd_buffer_free, - cmd_buffer_print + 0, + NULL, + NULL, + cmd_show_buffer_exec }; int cmd_show_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_buffer_data *data = self->data; + struct args *args = self->args; struct session *s; struct paste_buffer *pb; - char *in, *buf, *ptr; + int buffer; + char *in, *buf, *ptr, *cause; size_t size, len; u_int width; if ((s = cmd_find_session(ctx, NULL)) == NULL) return (-1); - if (data->buffer == -1) { + if (!args_has(args, 'b')) { if ((pb = paste_get_top(&global_buffers)) == NULL) { ctx->error(ctx, "no buffers"); return (-1); } } else { - pb = paste_get_index(&global_buffers, data->buffer); + buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause); + if (cause != NULL) { + ctx->error(ctx, "buffer %s", cause); + xfree(cause); + return (-1); + } + + pb = paste_get_index(&global_buffers, buffer); if (pb == NULL) { - ctx->error(ctx, "no buffer %d", data->buffer); + ctx->error(ctx, "no buffer %d", buffer); return (-1); } } diff --git a/cmd-show-environment.c b/cmd-show-environment.c index 6d0f364c..f52efbca 100644 --- a/cmd-show-environment.c +++ b/cmd-show-environment.c @@ -31,27 +31,26 @@ int cmd_show_environment_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_show_environment_entry = { "show-environment", "showenv", + "gt:", 0, 0, "[-g] " CMD_TARGET_SESSION_USAGE, - 0, "g", - cmd_target_init, - cmd_target_parse, - cmd_show_environment_exec, - cmd_target_free, - cmd_target_print + 0, + NULL, + NULL, + cmd_show_environment_exec }; int cmd_show_environment_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; - struct session *s; - struct environ *env; - struct environ_entry *envent; + struct args *args = self->args; + struct session *s; + struct environ *env; + struct environ_entry *envent; - if (cmd_check_flag(data->chflags, 'g')) + if (args_has(self->args, 'g')) env = &global_environ; else { - if ((s = cmd_find_session(ctx, data->target)) == NULL) + if ((s = cmd_find_session(ctx, args_get(args, 't'))) == NULL) return (-1); env = &s->environ; } diff --git a/cmd-show-messages.c b/cmd-show-messages.c index 84c2d6ce..5979e8c3 100644 --- a/cmd-show-messages.c +++ b/cmd-show-messages.c @@ -31,25 +31,24 @@ int cmd_show_messages_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_show_messages_entry = { "show-messages", "showmsgs", + "t:", 0, 0, CMD_TARGET_CLIENT_USAGE, - 0, "", - cmd_target_init, - cmd_target_parse, - cmd_show_messages_exec, - cmd_target_free, - cmd_target_print + 0, + NULL, + NULL, + cmd_show_messages_exec }; int cmd_show_messages_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; - struct client *c; - struct message_entry *msg; - char *tim; - u_int i; + struct args *args = self->args; + struct client *c; + struct message_entry *msg; + char *tim; + u_int i; - if ((c = cmd_find_client(ctx, data->target)) == NULL) + if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL) return (-1); for (i = 0; i < ARRAY_LENGTH(&c->message_log); i++) { diff --git a/cmd-show-options.c b/cmd-show-options.c index 02ca91e3..a36bebdf 100644 --- a/cmd-show-options.c +++ b/cmd-show-options.c @@ -31,19 +31,18 @@ int cmd_show_options_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_show_options_entry = { "show-options", "show", + "gst:w", 0, 0, "[-gsw] [-t target-session|target-window]", - 0, "gsw", - cmd_target_init, - cmd_target_parse, - cmd_show_options_exec, - cmd_target_free, - cmd_target_print + 0, + NULL, + NULL, + cmd_show_options_exec }; int cmd_show_options_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; + struct args *args = self->args; const struct options_table_entry *table, *oe; struct session *s; struct winlink *wl; @@ -51,25 +50,25 @@ cmd_show_options_exec(struct cmd *self, struct cmd_ctx *ctx) struct options_entry *o; const char *optval; - if (cmd_check_flag(data->chflags, 's')) { + if (args_has(self->args, 's')) { oo = &global_options; table = server_options_table; - } else if (cmd_check_flag(data->chflags, 'w')) { + } else if (args_has(self->args, 'w')) { table = window_options_table; - if (cmd_check_flag(data->chflags, 'g')) + if (args_has(self->args, 'g')) oo = &global_w_options; else { - wl = cmd_find_window(ctx, data->target, NULL); + wl = cmd_find_window(ctx, args_get(args, 't'), NULL); if (wl == NULL) return (-1); oo = &wl->window->options; } } else { table = session_options_table; - if (cmd_check_flag(data->chflags, 'g')) + if (args_has(self->args, 'g')) oo = &global_s_options; else { - s = cmd_find_session(ctx, data->target); + s = cmd_find_session(ctx, args_get(args, 't')); if (s == NULL) return (-1); oo = &s->options; diff --git a/cmd-show-window-options.c b/cmd-show-window-options.c index b81f887c..4412499a 100644 --- a/cmd-show-window-options.c +++ b/cmd-show-window-options.c @@ -31,20 +31,19 @@ int cmd_show_window_options_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_show_window_options_entry = { "show-window-options", "showw", + "gt:", 0, 0, "[-g] " CMD_TARGET_WINDOW_USAGE, - 0, "g", - cmd_target_init, - cmd_target_parse, - cmd_show_window_options_exec, - cmd_target_free, - cmd_target_print + 0, + NULL, + NULL, + cmd_show_window_options_exec }; int cmd_show_window_options_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; + struct args *args = self->args; - cmd_set_flag(&data->chflags, 'w'); + args_set(args, 'w', NULL); return (cmd_show_options_entry.exec(self, ctx)); } diff --git a/cmd-source-file.c b/cmd-source-file.c index 5ba7ed8b..aa05d362 100644 --- a/cmd-source-file.c +++ b/cmd-source-file.c @@ -24,80 +24,31 @@ * Sources a configuration file. */ -int cmd_source_file_parse(struct cmd *, int, char **, char **); int cmd_source_file_exec(struct cmd *, struct cmd_ctx *); -void cmd_source_file_free(struct cmd *); -void cmd_source_file_init(struct cmd *, int); -size_t cmd_source_file_print(struct cmd *, char *, size_t); - -struct cmd_source_file_data { - char *path; -}; const struct cmd_entry cmd_source_file_entry = { "source-file", "source", + "", 1, 1, "path", - 0, "", - cmd_source_file_init, - cmd_source_file_parse, - cmd_source_file_exec, - cmd_source_file_free, - cmd_source_file_print + 0, + NULL, + NULL, + cmd_source_file_exec }; -/* ARGSUSED */ -void -cmd_source_file_init(struct cmd *self, unused int arg) -{ - struct cmd_source_file_data *data; - - self->data = data = xmalloc(sizeof *data); - data->path = NULL; -} - -int -cmd_source_file_parse(struct cmd *self, int argc, char **argv, char **cause) -{ - struct cmd_source_file_data *data; - int opt; - - self->entry->init(self, KEYC_NONE); - data = self->data; - - while ((opt = getopt(argc, argv, "")) != -1) { - switch (opt) { - default: - goto usage; - } - } - argc -= optind; - argv += optind; - if (argc != 1) - goto usage; - - data->path = xstrdup(argv[0]); - return (0); - -usage: - xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); - - self->entry->free(self); - return (-1); -} - int cmd_source_file_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_source_file_data *data = self->data; - struct causelist causes; - char *cause; - struct window_pane *wp; - int retval; - u_int i; + struct args *args = self->args; + struct causelist causes; + char *cause; + struct window_pane *wp; + int retval; + u_int i; ARRAY_INIT(&causes); - retval = load_cfg(data->path, ctx, &causes); + retval = load_cfg(args->argv[0], ctx, &causes); if (ARRAY_EMPTY(&causes)) return (retval); @@ -121,27 +72,3 @@ cmd_source_file_exec(struct cmd *self, struct cmd_ctx *ctx) return (retval); } - -void -cmd_source_file_free(struct cmd *self) -{ - struct cmd_source_file_data *data = self->data; - - if (data->path != NULL) - xfree(data->path); - xfree(data); -} - -size_t -cmd_source_file_print(struct cmd *self, char *buf, size_t len) -{ - struct cmd_source_file_data *data = self->data; - size_t off = 0; - - off += xsnprintf(buf, len, "%s", self->entry->name); - if (data == NULL) - return (off); - if (off < len && data->path != NULL) - off += cmd_prarg(buf + off, len - off, " ", data->path); - return (off); -} diff --git a/cmd-split-window.c b/cmd-split-window.c index e9a6eb4e..b7be4078 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -28,142 +28,44 @@ * Split a window (add a new pane). */ -int cmd_split_window_parse(struct cmd *, int, char **, char **); +void cmd_split_window_key_binding(struct cmd *, int); int cmd_split_window_exec(struct cmd *, struct cmd_ctx *); -void cmd_split_window_free(struct cmd *); -void cmd_split_window_init(struct cmd *, int); -size_t cmd_split_window_print(struct cmd *, char *, size_t); - -struct cmd_split_window_data { - char *target; - char *cmd; - int flag_detached; - int flag_horizontal; - int flag_print; - int percentage; - int size; -}; const struct cmd_entry cmd_split_window_entry = { "split-window", "splitw", + "dl:hp:Pt:v", 0, 1, "[-dhvP] [-p percentage|-l size] [-t target-pane] [command]", - 0, "", - cmd_split_window_init, - cmd_split_window_parse, - cmd_split_window_exec, - cmd_split_window_free, - cmd_split_window_print + 0, + cmd_split_window_key_binding, + NULL, + cmd_split_window_exec }; void -cmd_split_window_init(struct cmd *self, int key) +cmd_split_window_key_binding(struct cmd *self, int key) { - struct cmd_split_window_data *data; - - self->data = data = xmalloc(sizeof *data); - data->target = NULL; - data->cmd = NULL; - data->flag_detached = 0; - data->flag_horizontal = 0; - data->flag_print = 0; - data->percentage = -1; - data->size = -1; - - switch (key) { - case '%': - data->flag_horizontal = 1; - break; - case '"': - data->flag_horizontal = 0; - break; - } -} - -int -cmd_split_window_parse(struct cmd *self, int argc, char **argv, char **cause) -{ - struct cmd_split_window_data *data; - int opt; - const char *errstr; - - self->entry->init(self, KEYC_NONE); - data = self->data; - - while ((opt = getopt(argc, argv, "dhl:p:Pt:v")) != -1) { - switch (opt) { - case 'd': - data->flag_detached = 1; - break; - case 'h': - data->flag_horizontal = 1; - break; - case 't': - if (data->target == NULL) - data->target = xstrdup(optarg); - break; - case 'l': - if (data->percentage != -1 || data->size != -1) - break; - data->size = strtonum(optarg, 1, INT_MAX, &errstr); - if (errstr != NULL) { - xasprintf(cause, "size %s", errstr); - goto error; - } - break; - case 'p': - if (data->size != -1 || data->percentage != -1) - break; - data->percentage = strtonum(optarg, 1, 100, &errstr); - if (errstr != NULL) { - xasprintf(cause, "percentage %s", errstr); - goto error; - } - break; - case 'P': - data->flag_print = 1; - break; - case 'v': - data->flag_horizontal = 0; - break; - default: - goto usage; - } - } - argc -= optind; - argv += optind; - if (argc != 0 && argc != 1) - goto usage; - - if (argc == 1) - data->cmd = xstrdup(argv[0]); - - return (0); - -usage: - xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); - -error: - self->entry->free(self); - return (-1); + self->args = args_create(0); + if (key == '%') + args_set(self->args, 'h', NULL); } int cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_split_window_data *data = self->data; - struct session *s; - struct winlink *wl; - struct window *w; - struct window_pane *wp, *new_wp = NULL; - struct environ env; - char *cmd, *cwd, *cause; - const char *shell; - u_int hlimit, paneidx; - int size; - enum layout_type type; - struct layout_cell *lc; + struct args *args = self->args; + struct session *s; + struct winlink *wl; + struct window *w; + struct window_pane *wp, *new_wp = NULL; + struct environ env; + char *cmd, *cwd, *cause; + const char *shell; + u_int hlimit, paneidx; + int size, percentage; + enum layout_type type; + struct layout_cell *lc; - if ((wl = cmd_find_pane(ctx, data->target, &s, &wp)) == NULL) + if ((wl = cmd_find_pane(ctx, args_get(args, 't'), &s, &wp)) == NULL) return (-1); w = wl->window; @@ -172,9 +74,10 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) environ_copy(&s->environ, &env); server_fill_environ(s, &env); - cmd = data->cmd; - if (cmd == NULL) + if (args->argc == 0) cmd = options_get_string(&s->options, "default-command"); + else + cmd = args->argv[0]; cwd = options_get_string(&s->options, "default-path"); if (*cwd == '\0') { if (ctx->cmdclient != NULL && ctx->cmdclient->cwd != NULL) @@ -184,17 +87,28 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) } type = LAYOUT_TOPBOTTOM; - if (data->flag_horizontal) + if (args_has(args, 'h')) type = LAYOUT_LEFTRIGHT; size = -1; - if (data->size != -1) - size = data->size; - else if (data->percentage != -1) { + if (args_has(args, 's')) { + size = args_strtonum(args, 's', 0, INT_MAX, &cause); + if (cause != NULL) { + ctx->error(ctx, "size %s", cause); + xfree(cause); + return (-1); + } + } else if (args_has(args, 'p')) { + percentage = args_strtonum(args, 'p', 0, INT_MAX, &cause); + if (cause != NULL) { + ctx->error(ctx, "percentage %s", cause); + xfree(cause); + return (-1); + } if (type == LAYOUT_TOPBOTTOM) - size = (wp->sy * data->percentage) / 100; + size = (wp->sy * percentage) / 100; else - size = (wp->sx * data->percentage) / 100; + size = (wp->sx * percentage) / 100; } hlimit = options_get_number(&s->options, "history-limit"); @@ -214,7 +128,7 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) server_redraw_window(w); - if (!data->flag_detached) { + if (!args_has(args, 'd')) { window_set_active_pane(w, new_wp); session_select(s, wl->idx); server_redraw_session(s); @@ -223,7 +137,7 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) environ_free(&env); - if (data->flag_print) { + if (args_has(args, 'P')) { paneidx = window_pane_index(wl->window, new_wp); ctx->print(ctx, "%s:%u.%u", s->name, wl->idx, paneidx); } @@ -237,43 +151,3 @@ error: xfree(cause); return (-1); } - -void -cmd_split_window_free(struct cmd *self) -{ - struct cmd_split_window_data *data = self->data; - - if (data->target != NULL) - xfree(data->target); - if (data->cmd != NULL) - xfree(data->cmd); - xfree(data); -} - -size_t -cmd_split_window_print(struct cmd *self, char *buf, size_t len) -{ - struct cmd_split_window_data *data = self->data; - size_t off = 0; - - off += xsnprintf(buf, len, "%s", self->entry->name); - if (data == NULL) - return (off); - if (off < len && data->flag_detached) - off += xsnprintf(buf + off, len - off, " -d"); - if (off < len && data->flag_horizontal) - off += xsnprintf(buf + off, len - off, " -h"); - if (off < len && data->flag_print) - off += xsnprintf(buf + off, len - off, " -P"); - if (off < len && data->size > 0) - off += xsnprintf(buf + off, len - off, " -l %d", data->size); - if (off < len && data->percentage > 0) { - off += xsnprintf( - buf + off, len - off, " -p %d", data->percentage); - } - if (off < len && data->target != NULL) - off += cmd_prarg(buf + off, len - off, " -t ", data->target); - if (off < len && data->cmd != NULL) - off += cmd_prarg(buf + off, len - off, " ", data->cmd); - return (off); -} diff --git a/cmd-start-server.c b/cmd-start-server.c index b93c9e6c..a69e77ea 100644 --- a/cmd-start-server.c +++ b/cmd-start-server.c @@ -28,13 +28,12 @@ int cmd_start_server_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_start_server_entry = { "start-server", "start", + "", 0, 0, "", - CMD_STARTSERVER, "", + CMD_STARTSERVER, NULL, NULL, - cmd_start_server_exec, - NULL, - NULL + cmd_start_server_exec }; /* ARGSUSED */ diff --git a/cmd-suspend-client.c b/cmd-suspend-client.c index b90121a0..2a4dac1b 100644 --- a/cmd-suspend-client.c +++ b/cmd-suspend-client.c @@ -31,22 +31,21 @@ int cmd_suspend_client_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_suspend_client_entry = { "suspend-client", "suspendc", + "t:", 0, 0, CMD_TARGET_CLIENT_USAGE, - 0, "", - cmd_target_init, - cmd_target_parse, - cmd_suspend_client_exec, - cmd_target_free, - cmd_target_print + 0, + NULL, + NULL, + cmd_suspend_client_exec }; int cmd_suspend_client_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; - struct client *c; + struct args *args = self->args; + struct client *c; - if ((c = cmd_find_client(ctx, data->target)) == NULL) + if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL) return (-1); tty_stop_tty(&c->tty); diff --git a/cmd-swap-pane.c b/cmd-swap-pane.c index bf4b048e..8e0662dd 100644 --- a/cmd-swap-pane.c +++ b/cmd-swap-pane.c @@ -26,66 +26,58 @@ * Swap two panes. */ -void cmd_swap_pane_init(struct cmd *, int); +void cmd_swap_pane_key_binding(struct cmd *, int); int cmd_swap_pane_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_swap_pane_entry = { "swap-pane", "swapp", + "dDs:t:U", 0, 0, "[-dDU] " CMD_SRCDST_PANE_USAGE, - 0, "dDU", - cmd_swap_pane_init, - cmd_srcdst_parse, - cmd_swap_pane_exec, - cmd_srcdst_free, - cmd_srcdst_print + 0, + cmd_swap_pane_key_binding, + NULL, + cmd_swap_pane_exec }; void -cmd_swap_pane_init(struct cmd *self, int key) +cmd_swap_pane_key_binding(struct cmd *self, int key) { - struct cmd_target_data *data; - - cmd_srcdst_init(self, key); - data = self->data; - + self->args = args_create(0); if (key == '{') - cmd_set_flag(&data->chflags, 'U'); + args_set(self->args, 'U', NULL); else if (key == '}') - cmd_set_flag(&data->chflags, 'D'); + args_set(self->args, 'D', NULL); } - int cmd_swap_pane_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_srcdst_data *data = self->data; + struct args *args = self->args; struct winlink *src_wl, *dst_wl; struct window *src_w, *dst_w; struct window_pane *tmp_wp, *src_wp, *dst_wp; struct layout_cell *src_lc, *dst_lc; u_int sx, sy, xoff, yoff; - if (data == NULL) - return (0); - - if ((dst_wl = cmd_find_pane(ctx, data->dst, NULL, &dst_wp)) == NULL) + dst_wl = cmd_find_pane(ctx, args_get(args, 't'), NULL, &dst_wp); + if (dst_wl == NULL) return (-1); dst_w = dst_wl->window; - if (data->src == NULL) { + if (!args_has(args, 's')) { src_w = dst_w; - if (cmd_check_flag(data->chflags, 'D')) { + if (args_has(self->args, 'D')) { src_wp = TAILQ_NEXT(dst_wp, entry); if (src_wp == NULL) src_wp = TAILQ_FIRST(&dst_w->panes); - } else if (cmd_check_flag(data->chflags, 'U')) { + } else if (args_has(self->args, 'U')) { src_wp = TAILQ_PREV(dst_wp, window_panes, entry); if (src_wp == NULL) src_wp = TAILQ_LAST(&dst_w->panes, window_panes); } else return (0); } else { - src_wl = cmd_find_pane(ctx, data->src, NULL, &src_wp); + src_wl = cmd_find_pane(ctx, args_get(args, 's'), NULL, &src_wp); if (src_wl == NULL) return (-1); src_w = src_wl->window; @@ -121,7 +113,7 @@ cmd_swap_pane_exec(struct cmd *self, struct cmd_ctx *ctx) dst_wp->xoff = xoff; dst_wp->yoff = yoff; window_pane_resize(dst_wp, sx, sy); - if (!cmd_check_flag(data->chflags, 'd')) { + if (!args_has(self->args, 'd')) { if (src_w != dst_w) { window_set_active_pane(src_w, dst_wp); window_set_active_pane(dst_w, src_wp); diff --git a/cmd-swap-window.c b/cmd-swap-window.c index ab532eb0..7583bdff 100644 --- a/cmd-swap-window.c +++ b/cmd-swap-window.c @@ -30,27 +30,29 @@ int cmd_swap_window_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_swap_window_entry = { "swap-window", "swapw", + "ds:t:", 0, 0, "[-d] " CMD_SRCDST_WINDOW_USAGE, - 0, "d", - cmd_srcdst_init, - cmd_srcdst_parse, - cmd_swap_window_exec, - cmd_srcdst_free, - cmd_srcdst_print + 0, + NULL, + NULL, + cmd_swap_window_exec }; int cmd_swap_window_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_srcdst_data *data = self->data; + struct args *args = self->args; + const char *target_src, *target_dst; struct session *src, *dst; struct session_group *sg_src, *sg_dst; struct winlink *wl_src, *wl_dst; struct window *w; - if ((wl_src = cmd_find_window(ctx, data->src, &src)) == NULL) + target_src = args_get(args, 's'); + if ((wl_src = cmd_find_window(ctx, target_src, &src)) == NULL) return (-1); - if ((wl_dst = cmd_find_window(ctx, data->dst, &dst)) == NULL) + target_dst = args_get(args, 't'); + if ((wl_dst = cmd_find_window(ctx, target_dst, &dst)) == NULL) return (-1); sg_src = session_group_find(src); @@ -68,7 +70,7 @@ cmd_swap_window_exec(struct cmd *self, struct cmd_ctx *ctx) wl_dst->window = wl_src->window; wl_src->window = w; - if (!cmd_check_flag(data->chflags, 'd')) { + if (!args_has(self->args, 'd')) { session_select(dst, wl_dst->idx); if (src != dst) session_select(src, wl_src->idx); diff --git a/cmd-switch-client.c b/cmd-switch-client.c index d695ce42..66eae88b 100644 --- a/cmd-switch-client.c +++ b/cmd-switch-client.c @@ -27,138 +27,58 @@ * Switch client to a different session. */ -void cmd_switch_client_init(struct cmd *, int); -int cmd_switch_client_parse(struct cmd *, int, char **, char **); +void cmd_switch_client_key_binding(struct cmd *, int); int cmd_switch_client_exec(struct cmd *, struct cmd_ctx *); -void cmd_switch_client_free(struct cmd *); -size_t cmd_switch_client_print(struct cmd *, char *, size_t); - -struct cmd_switch_client_data { - char *name; - char *target; - int flag_last; - int flag_next; - int flag_previous; -}; const struct cmd_entry cmd_switch_client_entry = { "switch-client", "switchc", + "lc:npt:", 0, 0, "[-lnp] [-c target-client] [-t target-session]", - 0, "", - cmd_switch_client_init, - cmd_switch_client_parse, - cmd_switch_client_exec, - cmd_switch_client_free, - cmd_switch_client_print + 0, + cmd_switch_client_key_binding, + NULL, + cmd_switch_client_exec }; void -cmd_switch_client_init(struct cmd *self, int key) +cmd_switch_client_key_binding(struct cmd *self, int key) { - struct cmd_switch_client_data *data; - - self->data = data = xmalloc(sizeof *data); - data->name = NULL; - data->target = NULL; - data->flag_last = 0; - data->flag_next = 0; - data->flag_previous = 0; - + self->args = args_create(0); switch (key) { case '(': - data->flag_previous = 1; + args_set(self->args, 'p', NULL); break; case ')': - data->flag_next = 1; + args_set(self->args, 'n', NULL); break; case 'L': - data->flag_last = 1; + args_set(self->args, 'l', NULL); break; } } -int -cmd_switch_client_parse(struct cmd *self, int argc, char **argv, char **cause) -{ - struct cmd_switch_client_data *data; - int opt; - - self->entry->init(self, KEYC_NONE); - data = self->data; - - while ((opt = getopt(argc, argv, "c:lnpt:")) != -1) { - switch (opt) { - case 'c': - if (data->name == NULL) - data->name = xstrdup(optarg); - break; - case 'l': - if (data->flag_next || data->flag_previous || - data->target != NULL) - goto usage; - data->flag_last = 1; - break; - case 'n': - if (data->flag_previous || data->flag_last || - data->target != NULL) - goto usage; - data->flag_next = 1; - break; - case 'p': - if (data->flag_next || data->flag_last || - data->target != NULL) - goto usage; - data->flag_next = 1; - break; - case 't': - if (data->flag_next || data->flag_previous) - goto usage; - if (data->target == NULL) - data->target = xstrdup(optarg); - break; - default: - goto usage; - } - } - argc -= optind; - argv += optind; - if (argc != 0) - goto usage; - - return (0); - -usage: - xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); - - self->entry->free(self); - return (-1); -} - int cmd_switch_client_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_switch_client_data *data = self->data; - struct client *c; - struct session *s; + struct args *args = self->args; + struct client *c; + struct session *s; - if (data == NULL) - return (0); - - if ((c = cmd_find_client(ctx, data->name)) == NULL) + if ((c = cmd_find_client(ctx, args_get(args, 'c'))) == NULL) return (-1); s = NULL; - if (data->flag_next) { + if (args_has(args, 'n')) { if ((s = session_next_session(c->session)) == NULL) { ctx->error(ctx, "can't find next session"); return (-1); } - } else if (data->flag_previous) { + } else if (args_has(args, 'p')) { if ((s = session_previous_session(c->session)) == NULL) { ctx->error(ctx, "can't find previous session"); return (-1); } - } else if (data->flag_last) { + } else if (args_has(args, 'l')) { if (c->last_session != NULL && session_alive(c->last_session)) s = c->last_session; if (s == NULL) { @@ -166,7 +86,7 @@ cmd_switch_client_exec(struct cmd *self, struct cmd_ctx *ctx) return (-1); } } else - s = cmd_find_session(ctx, data->target); + s = cmd_find_session(ctx, args_get(args, 't')); if (s == NULL) return (-1); @@ -181,37 +101,3 @@ cmd_switch_client_exec(struct cmd *self, struct cmd_ctx *ctx) return (0); } - -void -cmd_switch_client_free(struct cmd *self) -{ - struct cmd_switch_client_data *data = self->data; - - if (data->name != NULL) - xfree(data->name); - if (data->target != NULL) - xfree(data->target); - xfree(data); -} - -size_t -cmd_switch_client_print(struct cmd *self, char *buf, size_t len) -{ - struct cmd_switch_client_data *data = self->data; - size_t off = 0; - - off += xsnprintf(buf, len, "%s", self->entry->name); - if (data == NULL) - return (off); - if (off < len && data->flag_last) - off += xsnprintf(buf + off, len - off, "%s", " -l"); - if (off < len && data->flag_next) - off += xsnprintf(buf + off, len - off, "%s", " -n"); - if (off < len && data->flag_previous) - off += xsnprintf(buf + off, len - off, "%s", " -p"); - if (off < len && data->name != NULL) - off += cmd_prarg(buf + off, len - off, " -c ", data->name); - if (off < len && data->target != NULL) - off += cmd_prarg(buf + off, len - off, " -t ", data->target); - return (off); -} diff --git a/cmd-unbind-key.c b/cmd-unbind-key.c index f95342b9..7dab5683 100644 --- a/cmd-unbind-key.c +++ b/cmd-unbind-key.c @@ -24,140 +24,80 @@ * Unbind key from command. */ -int cmd_unbind_key_parse(struct cmd *, int, char **, char **); +int cmd_unbind_key_check(struct args *); int cmd_unbind_key_exec(struct cmd *, struct cmd_ctx *); -void cmd_unbind_key_free(struct cmd *); -int cmd_unbind_key_table(struct cmd *, struct cmd_ctx *); - -struct cmd_unbind_key_data { - int key; - - int flag_all; - int command_key; - char *tablename; -}; +int cmd_unbind_key_table(struct cmd *, struct cmd_ctx *, int); const struct cmd_entry cmd_unbind_key_entry = { "unbind-key", "unbind", + "acnt:", 1, 1, "[-acn] [-t key-table] key", - 0, "", + 0, NULL, - cmd_unbind_key_parse, - cmd_unbind_key_exec, - cmd_unbind_key_free, - NULL + cmd_unbind_key_check, + cmd_unbind_key_exec }; int -cmd_unbind_key_parse(struct cmd *self, int argc, char **argv, char **cause) +cmd_unbind_key_check(struct args *args) { - struct cmd_unbind_key_data *data; - int opt, no_prefix = 0; - - self->data = data = xmalloc(sizeof *data); - data->flag_all = 0; - data->command_key = 0; - data->tablename = NULL; - - while ((opt = getopt(argc, argv, "acnt:")) != -1) { - switch (opt) { - case 'a': - data->flag_all = 1; - break; - case 'c': - data->command_key = 1; - break; - case 'n': - no_prefix = 1; - break; - case 't': - if (data->tablename == NULL) - data->tablename = xstrdup(optarg); - break; - default: - goto usage; - } - } - argc -= optind; - argv += optind; - if (data->flag_all && (argc != 0 || data->tablename)) - goto usage; - if (!data->flag_all && argc != 1) - goto usage; - - if (!data->flag_all) { - data->key = key_string_lookup_string(argv[0]); - if (data->key == KEYC_NONE) { - xasprintf(cause, "unknown key: %s", argv[0]); - goto error; - } - if (!no_prefix) - data->key |= KEYC_PREFIX; - } - + if (args_has(args, 'a') && (args->argc != 0 || args_has(args, 't'))) + return (-1); return (0); - -usage: - xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); - -error: - xfree(data); - return (-1); } int cmd_unbind_key_exec(struct cmd *self, unused struct cmd_ctx *ctx) { - struct cmd_unbind_key_data *data = self->data; - struct key_binding *bd; + struct args *args = self->args; + struct key_binding *bd; + int key; - if (data == NULL) - return (0); - if (data->flag_all) { + if (args_has(args, 'a')) { while (!SPLAY_EMPTY(&key_bindings)) { bd = SPLAY_ROOT(&key_bindings); SPLAY_REMOVE(key_bindings, &key_bindings, bd); cmd_list_free(bd->cmdlist); xfree(bd); } - } else { - if (data->tablename != NULL) - return (cmd_unbind_key_table(self, ctx)); - - key_bindings_remove(data->key); + return (0); } + key = key_string_lookup_string(args->argv[0]); + if (key == KEYC_NONE) { + ctx->error(ctx, "unknown key: %s", args->argv[0]); + return (-1); + } + + if (args_has(args, 't')) + return (cmd_unbind_key_table(self, ctx, key)); + + if (!args_has(args, 'n')) + key |= KEYC_PREFIX; + key_bindings_remove(key); return (0); } int -cmd_unbind_key_table(struct cmd *self, struct cmd_ctx *ctx) +cmd_unbind_key_table(struct cmd *self, struct cmd_ctx *ctx, int key) { - struct cmd_unbind_key_data *data = self->data; + struct args *args = self->args; + const char *tablename; const struct mode_key_table *mtab; struct mode_key_binding *mbind, mtmp; - if ((mtab = mode_key_findtable(data->tablename)) == NULL) { - ctx->error(ctx, "unknown key table: %s", data->tablename); + tablename = args_get(args, 't'); + if ((mtab = mode_key_findtable(tablename)) == NULL) { + ctx->error(ctx, "unknown key table: %s", tablename); return (-1); } - mtmp.key = data->key & ~KEYC_PREFIX; - mtmp.mode = data->command_key ? 1 : 0; + mtmp.key = key; + mtmp.mode = !!args_has(args, 'c'); if ((mbind = SPLAY_FIND(mode_key_tree, mtab->tree, &mtmp)) != NULL) { SPLAY_REMOVE(mode_key_tree, mtab->tree, mbind); xfree(mbind); } return (0); } - -void -cmd_unbind_key_free(struct cmd *self) -{ - struct cmd_unbind_key_data *data = self->data; - - if (data->tablename != NULL) - xfree(data->tablename); - xfree(data); -} diff --git a/cmd-unlink-window.c b/cmd-unlink-window.c index a7ca23da..2b44ea8a 100644 --- a/cmd-unlink-window.c +++ b/cmd-unlink-window.c @@ -28,26 +28,25 @@ int cmd_unlink_window_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_unlink_window_entry = { "unlink-window", "unlinkw", + "kt:", 0, 0, "[-k] " CMD_TARGET_WINDOW_USAGE, - 0, "k", - cmd_target_init, - cmd_target_parse, - cmd_unlink_window_exec, - cmd_target_free, - cmd_target_print + 0, + NULL, + NULL, + cmd_unlink_window_exec }; int cmd_unlink_window_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; + struct args *args = self->args; struct winlink *wl; struct window *w; struct session *s, *s2; struct session_group *sg; u_int references; - if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL) + if ((wl = cmd_find_window(ctx, args_get(args, 't'), &s)) == NULL) return (-1); w = wl->window; @@ -59,7 +58,7 @@ cmd_unlink_window_exec(struct cmd *self, struct cmd_ctx *ctx) } else references = 1; - if (!cmd_check_flag(data->chflags, 'k') && w->references == references) { + if (!args_has(self->args, 'k') && w->references == references) { ctx->error(ctx, "window is only linked to one session"); return (-1); } diff --git a/cmd.c b/cmd.c index cff10f9a..6c4a06f4 100644 --- a/cmd.c +++ b/cmd.c @@ -167,7 +167,7 @@ cmd_unpack_argv(char *buf, size_t len, int argc, char ***argv) } char ** -cmd_copy_argv(int argc, char **argv) +cmd_copy_argv(int argc, char *const *argv) { char **new_argv; int i; @@ -201,8 +201,9 @@ cmd_parse(int argc, char **argv, char **cause) { const struct cmd_entry **entryp, *entry; struct cmd *cmd; + struct args *args; char s[BUFSIZ]; - int opt, ambiguous = 0; + int ambiguous = 0; *cause = NULL; if (argc == 0) { @@ -236,30 +237,19 @@ cmd_parse(int argc, char **argv, char **cause) return (NULL); } - optreset = 1; - optind = 1; - if (entry->parse == NULL) { - while ((opt = getopt(argc, argv, "")) != -1) { - switch (opt) { - default: - goto usage; - } - } - argc -= optind; - argv += optind; - if (argc != 0) - goto usage; - } + args = args_parse(entry->args_template, argc, argv); + if (args == NULL) + goto usage; + if (entry->args_lower != -1 && args->argc < entry->args_lower) + goto usage; + if (entry->args_upper != -1 && args->argc > entry->args_upper) + goto usage; + if (entry->check != NULL && entry->check(args) != 0) + goto usage; cmd = xmalloc(sizeof *cmd); cmd->entry = entry; - cmd->data = NULL; - if (entry->parse != NULL) { - if (entry->parse(cmd, argc, argv, cause) != 0) { - xfree(cmd); - return (NULL); - } - } + cmd->args = args; return (cmd); ambiguous: @@ -277,6 +267,8 @@ ambiguous: return (NULL); usage: + if (args != NULL) + args_free(args); xasprintf(cause, "usage: %s %s", entry->name, entry->usage); return (NULL); } @@ -290,17 +282,27 @@ cmd_exec(struct cmd *cmd, struct cmd_ctx *ctx) void cmd_free(struct cmd *cmd) { - if (cmd->data != NULL && cmd->entry->free != NULL) - cmd->entry->free(cmd); + if (cmd->args != NULL) + args_free(cmd->args); xfree(cmd); } size_t cmd_print(struct cmd *cmd, char *buf, size_t len) { - if (cmd->entry->print == NULL) - return (xsnprintf(buf, len, "%s", cmd->entry->name)); - return (cmd->entry->print(cmd, buf, len)); + size_t off, used; + + off = xsnprintf(buf, len, "%s ", cmd->entry->name); + if (off < len) { + used = args_print(cmd->args, buf + off, len - off); + if (used == 0) + buf[off - 1] = '\0'; + else { + off += used; + buf[off] = '\0'; + } + } + return (off); } /* diff --git a/key-bindings.c b/key-bindings.c index 32e81e94..a3f7fb42 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -187,9 +187,10 @@ key_bindings_init(void) cmd = xmalloc(sizeof *cmd); cmd->entry = table[i].entry; - cmd->data = NULL; - if (cmd->entry->init != NULL) - cmd->entry->init(cmd, table[i].key); + if (cmd->entry->key_binding != NULL) + cmd->entry->key_binding(cmd, table[i].key); + else + cmd->args = args_create(0); TAILQ_INSERT_HEAD(&cmdlist->list, cmd, qentry); key_bindings_add( diff --git a/tmux.h b/tmux.h index 09999b00..3e6ecec2 100644 --- a/tmux.h +++ b/tmux.h @@ -1168,6 +1168,15 @@ struct client { }; ARRAY_DECL(clients, struct client *); +/* Parsed arguments. */ +struct args { + bitstr_t *flags; + char *values[SCHAR_MAX]; /* XXX This is awfully big. */ + + int argc; + char **argv; +}; + /* Key/command line command. */ struct cmd_ctx { /* @@ -1198,67 +1207,35 @@ struct cmd_ctx { }; struct cmd { - const struct cmd_entry *entry; - void *data; + const struct cmd_entry *entry; + struct args *args; - TAILQ_ENTRY(cmd) qentry; + TAILQ_ENTRY(cmd) qentry; }; struct cmd_list { - int references; - TAILQ_HEAD(, cmd) list; + int references; + TAILQ_HEAD(, cmd) list; }; struct cmd_entry { const char *name; const char *alias; + + const char *args_template; + int args_lower; + int args_upper; + const char *usage; #define CMD_STARTSERVER 0x1 #define CMD_CANTNEST 0x2 #define CMD_SENDENVIRON 0x4 -#define CMD_ARG1 0x8 -#define CMD_ARG01 0x10 -#define CMD_ARG2 0x20 -#define CMD_ARG12 0x40 -#define CMD_READONLY 0x80 +#define CMD_READONLY 0x8 int flags; - const char *chflags; - - void (*init)(struct cmd *, int); - int (*parse)(struct cmd *, int, char **, char **); + void (*key_binding)(struct cmd *, int); + int (*check)(struct args *); int (*exec)(struct cmd *, struct cmd_ctx *); - void (*free)(struct cmd *); - size_t (*print)(struct cmd *, char *, size_t); -}; - -/* Generic command data. */ -struct cmd_target_data { - uint64_t chflags; - - char *target; - - char *arg; - char *arg2; -}; - -struct cmd_srcdst_data { - uint64_t chflags; - - char *src; - char *dst; - - char *arg; - char *arg2; -}; - -struct cmd_buffer_data { - uint64_t chflags; - - int buffer; - - char *arg; - char *arg2; }; /* Key binding. */ @@ -1301,6 +1278,17 @@ struct options_table_entry { /* List of configuration causes. */ ARRAY_DECL(causelist, char *); +/* Common command usages. */ +#define CMD_TARGET_PANE_USAGE "[-t target-pane]" +#define CMD_TARGET_WINDOW_USAGE "[-t target-window]" +#define CMD_TARGET_SESSION_USAGE "[-t target-session]" +#define CMD_TARGET_CLIENT_USAGE "[-t target-client]" +#define CMD_SRCDST_PANE_USAGE "[-s src-pane] [-t dst-pane]" +#define CMD_SRCDST_WINDOW_USAGE "[-s src-window] [-t dst-window]" +#define CMD_SRCDST_SESSION_USAGE "[-s src-session] [-t dst-session]" +#define CMD_SRCDST_CLIENT_USAGE "[-s src-client] [-t dst-client]" +#define CMD_BUFFER_USAGE "[-b buffer-index]" + /* tmux.c */ extern struct options global_options; extern struct options global_s_options; @@ -1479,10 +1467,21 @@ char *paste_print(struct paste_buffer *, size_t); extern const char clock_table[14][5][5]; void clock_draw(struct screen_write_ctx *, int, int); +/* arguments.c */ +struct args *args_create(int, ...); +struct args *args_parse(const char *, int, char **); +void args_free(struct args *); +size_t args_print(struct args *, char *, size_t); +int args_has(struct args *, u_char); +void args_set(struct args *, u_char, const char *); +const char *args_get(struct args *, u_char); +long long args_strtonum( + struct args *, u_char, long long, long long, char **); + /* cmd.c */ int cmd_pack_argv(int, char **, char *, size_t); int cmd_unpack_argv(char *, size_t, int, char ***); -char **cmd_copy_argv(int, char **); +char **cmd_copy_argv(int, char *const *); void cmd_free_argv(int, char **); struct cmd *cmd_parse(int, char **, char **); int cmd_exec(struct cmd *, struct cmd_ctx *); @@ -1592,32 +1591,6 @@ size_t cmd_list_print(struct cmd_list *, char *, size_t); /* cmd-string.c */ int cmd_string_parse(const char *, struct cmd_list **, char **); -/* cmd-generic.c */ -size_t cmd_prarg(char *, size_t, const char *, char *); -int cmd_check_flag(uint64_t, int); -void cmd_set_flag(uint64_t *, int); -#define CMD_TARGET_PANE_USAGE "[-t target-pane]" -#define CMD_TARGET_WINDOW_USAGE "[-t target-window]" -#define CMD_TARGET_SESSION_USAGE "[-t target-session]" -#define CMD_TARGET_CLIENT_USAGE "[-t target-client]" -void cmd_target_init(struct cmd *, int); -int cmd_target_parse(struct cmd *, int, char **, char **); -void cmd_target_free(struct cmd *); -size_t cmd_target_print(struct cmd *, char *, size_t); -#define CMD_SRCDST_PANE_USAGE "[-s src-pane] [-t dst-pane]" -#define CMD_SRCDST_WINDOW_USAGE "[-s src-window] [-t dst-window]" -#define CMD_SRCDST_SESSION_USAGE "[-s src-session] [-t dst-session]" -#define CMD_SRCDST_CLIENT_USAGE "[-s src-client] [-t dst-client]" -void cmd_srcdst_init(struct cmd *, int); -int cmd_srcdst_parse(struct cmd *, int, char **, char **); -void cmd_srcdst_free(struct cmd *); -size_t cmd_srcdst_print(struct cmd *, char *, size_t); -#define CMD_BUFFER_USAGE "[-b buffer-index]" -void cmd_buffer_init(struct cmd *, int); -int cmd_buffer_parse(struct cmd *, int, char **, char **); -void cmd_buffer_free(struct cmd *); -size_t cmd_buffer_print(struct cmd *, char *, size_t); - /* client.c */ int client_main(int, char **, int); From 55346b0d103016e8ee633e08e41b8b977b5904ef Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 4 Jan 2011 01:58:12 +0000 Subject: [PATCH 0829/1180] argc will be 1 not 2 with no option value. --- cmd-set-option.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd-set-option.c b/cmd-set-option.c index 2aa99f10..efd5797a 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -115,7 +115,7 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) ctx->error(ctx, "invalid option"); return (-1); } - if (args->argc < 1) + if (args->argc < 2) valstr = NULL; else valstr = args->argv[1]; From 96c37fa80a46e189b9b6535242aa1966f4d375c8 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 4 Jan 2011 02:03:41 +0000 Subject: [PATCH 0830/1180] Now that parsing is common, merge some of the small, related commands together to use the same code. Also add some arguments (such as -n and -p) to some commands to match existing commands. --- Makefile | 12 +++--- cmd-last-pane.c | 57 ------------------------- cmd-last-window.c | 57 ------------------------- cmd-lock-client.c | 52 ----------------------- cmd-lock-server.c | 40 ++++++++++++++++-- cmd-lock-session.c | 52 ----------------------- cmd-next-layout.c | 53 ------------------------ cmd-next-window.c | 71 -------------------------------- cmd-previous-layout.c | 53 ------------------------ cmd-previous-window.c | 71 -------------------------------- cmd-select-layout.c | 42 +++++++++++++++++-- cmd-select-pane.c | 27 +++++++++++- cmd-select-window.c | 87 +++++++++++++++++++++++++++++++++++---- cmd-set-option.c | 13 +++++- cmd-set-window-option.c | 46 --------------------- cmd-show-options.c | 13 +++++- cmd-show-window-options.c | 49 ---------------------- tmux.1 | 30 +++++++++++++- 18 files changed, 238 insertions(+), 587 deletions(-) delete mode 100644 cmd-last-pane.c delete mode 100644 cmd-last-window.c delete mode 100644 cmd-lock-client.c delete mode 100644 cmd-lock-session.c delete mode 100644 cmd-next-layout.c delete mode 100644 cmd-next-window.c delete mode 100644 cmd-previous-layout.c delete mode 100644 cmd-previous-window.c delete mode 100644 cmd-set-window-option.c delete mode 100644 cmd-show-window-options.c diff --git a/Makefile b/Makefile index 0f7f403e..4c48ccdb 100644 --- a/Makefile +++ b/Makefile @@ -9,20 +9,20 @@ SRCS= arguments.c attributes.c cfg.c client.c clock.c \ cmd-choose-buffer.c cmd-delete-buffer.c cmd-detach-client.c \ cmd-find-window.c cmd-has-session.c cmd-kill-pane.c \ cmd-kill-server.c cmd-kill-session.c cmd-kill-window.c \ - cmd-last-pane.c cmd-last-window.c cmd-link-window.c cmd-list-buffers.c \ + cmd-link-window.c cmd-list-buffers.c \ cmd-list-clients.c cmd-list-commands.c cmd-list-keys.c \ cmd-list-sessions.c cmd-list-windows.c cmd-list-panes.c \ cmd-list.c cmd-load-buffer.c cmd-join-pane.c \ - cmd-lock-server.c cmd-lock-client.c cmd-lock-session.c \ + cmd-lock-server.c \ cmd-move-window.c cmd-new-session.c cmd-new-window.c \ - cmd-next-layout.c cmd-next-window.c cmd-paste-buffer.c \ - cmd-previous-layout.c cmd-previous-window.c cmd-refresh-client.c \ + cmd-paste-buffer.c \ + cmd-refresh-client.c \ cmd-rename-session.c cmd-rename-window.c cmd-resize-pane.c \ cmd-respawn-window.c cmd-rotate-window.c cmd-save-buffer.c \ cmd-select-layout.c cmd-select-pane.c cmd-select-window.c \ cmd-send-keys.c cmd-send-prefix.c cmd-server-info.c cmd-set-buffer.c \ - cmd-set-option.c cmd-set-window-option.c cmd-show-buffer.c \ - cmd-show-messages.c cmd-show-options.c cmd-show-window-options.c \ + cmd-set-option.c cmd-show-buffer.c \ + cmd-show-messages.c cmd-show-options.c \ cmd-source-file.c cmd-split-window.c cmd-start-server.c cmd-string.c \ cmd-run-shell.c cmd-suspend-client.c cmd-swap-pane.c cmd-swap-window.c \ cmd-switch-client.c cmd-unbind-key.c cmd-unlink-window.c \ diff --git a/cmd-last-pane.c b/cmd-last-pane.c deleted file mode 100644 index f9f61495..00000000 --- a/cmd-last-pane.c +++ /dev/null @@ -1,57 +0,0 @@ -/* $OpenBSD$ */ - -/* - * Copyright (c) 2010 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" - -/* - * Move to last pane. - */ - -int cmd_last_pane_exec(struct cmd *, struct cmd_ctx *); - -const struct cmd_entry cmd_last_pane_entry = { - "last-pane", "lastp", - "t:", 0, 0, - CMD_TARGET_WINDOW_USAGE, - 0, - NULL, - NULL, - cmd_last_pane_exec -}; - -int -cmd_last_pane_exec(struct cmd *self, struct cmd_ctx *ctx) -{ - struct args *args = self->args; - struct winlink *wl; - struct window *w; - - if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL) - return (-1); - w = wl->window; - - if (w->last == NULL) { - ctx->error(ctx, "no last pane"); - return (-1); - } - window_set_active_pane(w, w->last); - - return (0); -} diff --git a/cmd-last-window.c b/cmd-last-window.c deleted file mode 100644 index 209f367b..00000000 --- a/cmd-last-window.c +++ /dev/null @@ -1,57 +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" - -/* - * Move to last window. - */ - -int cmd_last_window_exec(struct cmd *, struct cmd_ctx *); - -const struct cmd_entry cmd_last_window_entry = { - "last-window", "last", - "t:", 0, 0, - CMD_TARGET_SESSION_USAGE, - 0, - NULL, - NULL, - cmd_last_window_exec -}; - -int -cmd_last_window_exec(struct cmd *self, struct cmd_ctx *ctx) -{ - struct args *args = self->args; - struct session *s; - - if ((s = cmd_find_session(ctx, args_get(args, 't'))) == NULL) - return (-1); - - if (session_last(s) == 0) - server_redraw_session(s); - else { - ctx->error(ctx, "no last window"); - return (-1); - } - recalculate_sizes(); - - return (0); -} diff --git a/cmd-lock-client.c b/cmd-lock-client.c deleted file mode 100644 index bc5a1aa4..00000000 --- a/cmd-lock-client.c +++ /dev/null @@ -1,52 +0,0 @@ -/* $OpenBSD$ */ - -/* - * Copyright (c) 2009 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" - -/* - * Lock a single client. - */ - -int cmd_lock_client_exec(struct cmd *, struct cmd_ctx *); - -const struct cmd_entry cmd_lock_client_entry = { - "lock-client", "lockc", - "t:", 0, 0, - CMD_TARGET_CLIENT_USAGE, - 0, - NULL, - NULL, - cmd_lock_client_exec -}; - -int -cmd_lock_client_exec(struct cmd *self, struct cmd_ctx *ctx) -{ - struct args *args = self->args; - struct client *c; - - if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL) - return (-1); - - server_lock_client(c); - recalculate_sizes(); - - return (0); -} diff --git a/cmd-lock-server.c b/cmd-lock-server.c index 347cc128..955de11f 100644 --- a/cmd-lock-server.c +++ b/cmd-lock-server.c @@ -25,7 +25,7 @@ #include "tmux.h" /* - * Lock server. + * Lock commands. */ int cmd_lock_server_exec(struct cmd *, struct cmd_ctx *); @@ -40,11 +40,45 @@ const struct cmd_entry cmd_lock_server_entry = { cmd_lock_server_exec }; +const struct cmd_entry cmd_lock_session_entry = { + "lock-session", "locks", + "t:", 0, 0, + CMD_TARGET_SESSION_USAGE, + 0, + NULL, + NULL, + cmd_lock_server_exec +}; + +const struct cmd_entry cmd_lock_client_entry = { + "lock-client", "lockc", + "t:", 0, 0, + CMD_TARGET_CLIENT_USAGE, + 0, + NULL, + NULL, + cmd_lock_server_exec +}; + /* ARGSUSED */ int -cmd_lock_server_exec(unused struct cmd *self, unused struct cmd_ctx *ctx) +cmd_lock_server_exec(struct cmd *self, unused struct cmd_ctx *ctx) { - server_lock(); + struct args *args = self->args; + struct client *c; + struct session *s; + + if (self->entry == &cmd_lock_server_entry) + server_lock(); + else if (self->entry == &cmd_lock_session_entry) { + if ((s = cmd_find_session(ctx, args_get(args, 't'))) == NULL) + return (-1); + server_lock_session(s); + } else { + if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL) + return (-1); + server_lock_client(c); + } recalculate_sizes(); return (0); diff --git a/cmd-lock-session.c b/cmd-lock-session.c deleted file mode 100644 index 4b75c973..00000000 --- a/cmd-lock-session.c +++ /dev/null @@ -1,52 +0,0 @@ -/* $OpenBSD$ */ - -/* - * Copyright (c) 2009 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" - -/* - * Lock all clients attached to a session. - */ - -int cmd_lock_session_exec(struct cmd *, struct cmd_ctx *); - -const struct cmd_entry cmd_lock_session_entry = { - "lock-session", "locks", - "t:", 0, 0, - CMD_TARGET_SESSION_USAGE, - 0, - NULL, - NULL, - cmd_lock_session_exec -}; - -int -cmd_lock_session_exec(struct cmd *self, struct cmd_ctx *ctx) -{ - struct args *args = self->args; - struct session *s; - - if ((s = cmd_find_session(ctx, args_get(args, 't'))) == NULL) - return (-1); - - server_lock_session(s); - recalculate_sizes(); - - return (0); -} diff --git a/cmd-next-layout.c b/cmd-next-layout.c deleted file mode 100644 index bdd6f3e5..00000000 --- a/cmd-next-layout.c +++ /dev/null @@ -1,53 +0,0 @@ -/* $OpenBSD$ */ - -/* - * Copyright (c) 2009 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" - -/* - * Switch window to next layout. - */ - -int cmd_next_layout_exec(struct cmd *, struct cmd_ctx *); - -const struct cmd_entry cmd_next_layout_entry = { - "next-layout", "nextl", - "t:", 0, 0, - CMD_TARGET_WINDOW_USAGE, - 0, - NULL, - NULL, - cmd_next_layout_exec -}; - -int -cmd_next_layout_exec(struct cmd *self, struct cmd_ctx *ctx) -{ - struct args *args = self->args; - struct winlink *wl; - u_int layout; - - if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL) - return (-1); - - layout = layout_set_next(wl->window); - ctx->info(ctx, "arranging in: %s", layout_set_name(layout)); - - return (0); -} diff --git a/cmd-next-window.c b/cmd-next-window.c deleted file mode 100644 index c9cb77a9..00000000 --- a/cmd-next-window.c +++ /dev/null @@ -1,71 +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" - -/* - * Move to next window. - */ - -void cmd_next_window_key_binding(struct cmd *, int); -int cmd_next_window_exec(struct cmd *, struct cmd_ctx *); - -const struct cmd_entry cmd_next_window_entry = { - "next-window", "next", - "at:", 0, 0, - "[-a] " CMD_TARGET_SESSION_USAGE, - 0, - cmd_next_window_key_binding, - NULL, - cmd_next_window_exec -}; - -void -cmd_next_window_key_binding(struct cmd *self, int key) -{ - self->args = args_create(0); - if (key == ('n' | KEYC_ESCAPE)) - args_set(self->args, 'a', NULL); -} - -int -cmd_next_window_exec(struct cmd *self, struct cmd_ctx *ctx) -{ - struct args *args = self->args; - struct session *s; - int activity; - - if ((s = cmd_find_session(ctx, args_get(args, 't'))) == NULL) - return (-1); - - activity = 0; - if (args_has(self->args, 'a')) - activity = 1; - - if (session_next(s, activity) == 0) - server_redraw_session(s); - else { - ctx->error(ctx, "no next window"); - return (-1); - } - recalculate_sizes(); - - return (0); -} diff --git a/cmd-previous-layout.c b/cmd-previous-layout.c deleted file mode 100644 index abe9e357..00000000 --- a/cmd-previous-layout.c +++ /dev/null @@ -1,53 +0,0 @@ -/* $OpenBSD$ */ - -/* - * Copyright (c) 2009 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" - -/* - * Switch window to previous layout. - */ - -int cmd_previous_layout_exec(struct cmd *, struct cmd_ctx *); - -const struct cmd_entry cmd_previous_layout_entry = { - "previous-layout", "prevl", - "t:", 0, 0, - CMD_TARGET_WINDOW_USAGE, - 0, - NULL, - NULL, - cmd_previous_layout_exec -}; - -int -cmd_previous_layout_exec(struct cmd *self, struct cmd_ctx *ctx) -{ - struct args *args = self->args; - struct winlink *wl; - u_int layout; - - if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL) - return (-1); - - layout = layout_set_previous(wl->window); - ctx->info(ctx, "arranging in: %s", layout_set_name(layout)); - - return (0); -} diff --git a/cmd-previous-window.c b/cmd-previous-window.c deleted file mode 100644 index c3f60a29..00000000 --- a/cmd-previous-window.c +++ /dev/null @@ -1,71 +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" - -/* - * Move to previous window. - */ - -void cmd_previous_window_key_binding(struct cmd *, int); -int cmd_previous_window_exec(struct cmd *, struct cmd_ctx *); - -const struct cmd_entry cmd_previous_window_entry = { - "previous-window", "prev", - "at:", 0, 0, - "[-a] " CMD_TARGET_SESSION_USAGE, - 0, - cmd_previous_window_key_binding, - NULL, - cmd_previous_window_exec -}; - -void -cmd_previous_window_key_binding(struct cmd *self, int key) -{ - self->args = args_create(0); - if (key == ('p' | KEYC_ESCAPE)) - args_set(self->args, 'a', NULL); -} - -int -cmd_previous_window_exec(struct cmd *self, struct cmd_ctx *ctx) -{ - struct args *args = self->args; - struct session *s; - int activity; - - if ((s = cmd_find_session(ctx, args_get(args, 't'))) == NULL) - return (-1); - - activity = 0; - if (args_has(self->args, 'a')) - activity = 1; - - if (session_previous(s, activity) == 0) - server_redraw_session(s); - else { - ctx->error(ctx, "no previous window"); - return (-1); - } - recalculate_sizes(); - - return (0); -} diff --git a/cmd-select-layout.c b/cmd-select-layout.c index df977b0f..b030c311 100644 --- a/cmd-select-layout.c +++ b/cmd-select-layout.c @@ -29,14 +29,34 @@ int cmd_select_layout_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_select_layout_entry = { "select-layout", "selectl", - "t:", 0, 1, - CMD_TARGET_WINDOW_USAGE " [layout-name]", + "npt:", 0, 1, + "[-np] " CMD_TARGET_WINDOW_USAGE " [layout-name]", 0, cmd_select_layout_key_binding, NULL, cmd_select_layout_exec }; +const struct cmd_entry cmd_next_layout_entry = { + "next-layout", "nextl", + "t:", 0, 0, + CMD_TARGET_WINDOW_USAGE, + 0, + NULL, + NULL, + cmd_select_layout_exec +}; + +const struct cmd_entry cmd_previous_layout_entry = { + "previous-layout", "prevl", + "t:", 0, 0, + CMD_TARGET_WINDOW_USAGE, + 0, + NULL, + NULL, + cmd_select_layout_exec +}; + void cmd_select_layout_key_binding(struct cmd *self, int key) { @@ -68,11 +88,27 @@ cmd_select_layout_exec(struct cmd *self, struct cmd_ctx *ctx) struct args *args = self->args; struct winlink *wl; const char *layoutname; - int layout; + int next, previous, layout; if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL) return (-1); + next = self->entry == &cmd_next_layout_entry; + if (args_has(self->args, 'n')) + next = 1; + previous = self->entry == &cmd_previous_layout_entry; + if (args_has(self->args, 'p')) + previous = 1; + + if (next || previous) { + if (next) + layout = layout_set_next(wl->window); + else + layout = layout_set_previous(wl->window); + ctx->info(ctx, "arranging in: %s", layout_set_name(layout)); + return (0); + } + if (args->argc == 0) layout = wl->window->lastlayout; else diff --git a/cmd-select-pane.c b/cmd-select-pane.c index a250bb6e..9aed0a92 100644 --- a/cmd-select-pane.c +++ b/cmd-select-pane.c @@ -29,14 +29,24 @@ int cmd_select_pane_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_select_pane_entry = { "select-pane", "selectp", - "DLRt:U", 0, 0, - "[-DLRU] " CMD_TARGET_PANE_USAGE, + "lDLRt:U", 0, 0, + "[-lDLRU] " CMD_TARGET_PANE_USAGE, 0, cmd_select_pane_key_binding, NULL, cmd_select_pane_exec }; +const struct cmd_entry cmd_last_pane_entry = { + "last-pane", "lastp", + "t:", 0, 0, + CMD_TARGET_WINDOW_USAGE, + 0, + NULL, + NULL, + cmd_select_pane_exec +}; + void cmd_select_pane_key_binding(struct cmd *self, int key) { @@ -60,6 +70,19 @@ cmd_select_pane_exec(struct cmd *self, struct cmd_ctx *ctx) struct winlink *wl; struct window_pane *wp; + if (self->entry == &cmd_last_pane_entry || args_has(args, 'l')) { + wl = cmd_find_window(ctx, args_get(args, 't'), NULL); + if (wl == NULL) + return (-1); + + if (wl->window->last == NULL) { + ctx->error(ctx, "no last pane"); + return (-1); + } + window_set_active_pane(wl->window, wl->window->last); + return (0); + } + if ((wl = cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp)) == NULL) return (-1); diff --git a/cmd-select-window.c b/cmd-select-window.c index c414af3a..0e1b9543 100644 --- a/cmd-select-window.c +++ b/cmd-select-window.c @@ -31,23 +31,56 @@ int cmd_select_window_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_select_window_entry = { "select-window", "selectw", - "t:", 0, 0, - CMD_TARGET_WINDOW_USAGE, + "lnpt:", 0, 0, + "[-lnp] " CMD_TARGET_WINDOW_USAGE, 0, cmd_select_window_key_binding, NULL, cmd_select_window_exec }; +const struct cmd_entry cmd_next_window_entry = { + "next-window", "next", + "at:", 0, 0, + "[-a] " CMD_TARGET_SESSION_USAGE, + 0, + cmd_select_window_key_binding, + NULL, + cmd_select_window_exec +}; + +const struct cmd_entry cmd_previous_window_entry = { + "previous-window", "prev", + "at:", 0, 0, + "[-a] " CMD_TARGET_SESSION_USAGE, + 0, + cmd_select_window_key_binding, + NULL, + cmd_select_window_exec +}; + +const struct cmd_entry cmd_last_window_entry = { + "last-window", "last", + "t:", 0, 0, + CMD_TARGET_SESSION_USAGE, + 0, + NULL, + NULL, + cmd_select_window_exec +}; + void cmd_select_window_key_binding(struct cmd *self, int key) { char tmp[16]; - xsnprintf(tmp, sizeof tmp, ":%d", key - '0'); - self->args = args_create(0); - args_set(self->args, 't', tmp); + if (key >= '0' && key <= '9') { + xsnprintf(tmp, sizeof tmp, ":%d", key - '0'); + args_set(self->args, 't', tmp); + } + if (key == ('n' | KEYC_ESCAPE) || key == ('p' | KEYC_ESCAPE)) + args_set(self->args, 'a', NULL); } int @@ -56,12 +89,50 @@ cmd_select_window_exec(struct cmd *self, struct cmd_ctx *ctx) struct args *args = self->args; struct winlink *wl; struct session *s; + int next, previous, last, activity; - if ((wl = cmd_find_window(ctx, args_get(args, 't'), &s)) == NULL) - return (-1); + next = self->entry == &cmd_next_window_entry; + if (args_has(self->args, 'n')) + next = 1; + previous = self->entry == &cmd_previous_window_entry; + if (args_has(self->args, 'p')) + previous = 1; + last = self->entry == &cmd_last_window_entry; + if (args_has(self->args, 'l')) + last = 1; + + if (next || previous || last) { + s = cmd_find_session(ctx, args_get(args, 't')); + if (s == NULL) + return (-1); + + activity = args_has(self->args, 'a'); + if (next) { + if (session_next(s, activity) != 0) { + ctx->error(ctx, "no next window"); + return (-1); + } + } else if (previous) { + if (session_previous(s, activity) != 0) { + ctx->error(ctx, "no previous window"); + return (-1); + } + } else { + if (session_last(s) != 0) { + ctx->error(ctx, "no last window"); + return (-1); + } + } - if (session_select(s, wl->idx) == 0) server_redraw_session(s); + } else { + wl = cmd_find_window(ctx, args_get(args, 't'), &s); + if (wl == NULL) + return (-1); + + if (session_select(s, wl->idx) == 0) + server_redraw_session(s); + } recalculate_sizes(); return (0); diff --git a/cmd-set-option.c b/cmd-set-option.c index efd5797a..436e529e 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -68,6 +68,16 @@ const struct cmd_entry cmd_set_option_entry = { cmd_set_option_exec }; +const struct cmd_entry cmd_set_window_option_entry = { + "set-window-option", "setw", + "agt:u", 1, 2, + "[-agu] " CMD_TARGET_WINDOW_USAGE " option [value]", + 0, + NULL, + NULL, + cmd_set_option_exec +}; + int cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) { @@ -87,7 +97,8 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) if (args_has(self->args, 's')) { oo = &global_options; table = server_options_table; - } else if (args_has(self->args, 'w')) { + } else if (args_has(self->args, 'w') || + self->entry == &cmd_set_window_option_entry) { table = window_options_table; if (args_has(self->args, 'g')) oo = &global_w_options; diff --git a/cmd-set-window-option.c b/cmd-set-window-option.c deleted file mode 100644 index 3a750476..00000000 --- a/cmd-set-window-option.c +++ /dev/null @@ -1,46 +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 "tmux.h" - -/* - * Set a window option. This is just an alias for set-option -w. - */ - -int cmd_set_window_option_exec(struct cmd *, struct cmd_ctx *); - -const struct cmd_entry cmd_set_window_option_entry = { - "set-window-option", "setw", - "agt:u", 1, 2, - "[-agu] " CMD_TARGET_WINDOW_USAGE " option [value]", - 0, - NULL, - NULL, - cmd_set_window_option_exec -}; - -int -cmd_set_window_option_exec(struct cmd *self, struct cmd_ctx *ctx) -{ - struct args *args = self->args; - - args_set(args, 'w', NULL); - return (cmd_set_option_entry.exec(self, ctx)); -} diff --git a/cmd-show-options.c b/cmd-show-options.c index a36bebdf..cc11ed64 100644 --- a/cmd-show-options.c +++ b/cmd-show-options.c @@ -39,6 +39,16 @@ const struct cmd_entry cmd_show_options_entry = { cmd_show_options_exec }; +const struct cmd_entry cmd_show_window_options_entry = { + "show-window-options", "showw", + "gt:", 0, 0, + "[-g] " CMD_TARGET_WINDOW_USAGE, + 0, + NULL, + NULL, + cmd_show_options_exec +}; + int cmd_show_options_exec(struct cmd *self, struct cmd_ctx *ctx) { @@ -53,7 +63,8 @@ cmd_show_options_exec(struct cmd *self, struct cmd_ctx *ctx) if (args_has(self->args, 's')) { oo = &global_options; table = server_options_table; - } else if (args_has(self->args, 'w')) { + } else if (args_has(self->args, 'w') || + self->entry == &cmd_show_window_options_entry) { table = window_options_table; if (args_has(self->args, 'g')) oo = &global_w_options; diff --git a/cmd-show-window-options.c b/cmd-show-window-options.c deleted file mode 100644 index 4412499a..00000000 --- a/cmd-show-window-options.c +++ /dev/null @@ -1,49 +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 "tmux.h" - -/* - * Show window options. This is an alias for show-options -w. - */ - -int cmd_show_window_options_exec(struct cmd *, struct cmd_ctx *); - -const struct cmd_entry cmd_show_window_options_entry = { - "show-window-options", "showw", - "gt:", 0, 0, - "[-g] " CMD_TARGET_WINDOW_USAGE, - 0, - NULL, - NULL, - cmd_show_window_options_exec -}; - -int -cmd_show_window_options_exec(struct cmd *self, struct cmd_ctx *ctx) -{ - struct args *args = self->args; - - args_set(args, 'w', NULL); - return (cmd_show_options_entry.exec(self, ctx)); -} diff --git a/tmux.1 b/tmux.1 index 0f86e195..64ca5ed3 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1255,6 +1255,7 @@ lower) with .Fl U or downward (numerically higher). .It Xo Ic select-layout +.Op Fl np .Op Fl t Ar target-window .Op Ar layout-name .Xc @@ -1263,8 +1264,16 @@ Choose a specific layout for a window. If .Ar layout-name is not given, the last preset layout used (if any) is reapplied. +.Fl n +and +.Fl p +are equivalent to the +.Ic next-layout +and +.Ic previous-layout +commands. .It Xo Ic select-pane -.Op Fl DLRU +.Op Fl lDLRU .Op Fl t Ar target-pane .Xc .D1 (alias: Ic selectp ) @@ -1280,10 +1289,27 @@ or .Fl U is used, respectively the pane below, to the left, to the right, or above the target pane is used. -.It Ic select-window Op Fl t Ar target-window +.Fl l +is the same as using the +.Ic last-pane +command. +.It Xo Ic select-window +.Op Fl lnp +.Op Fl t Ar target-window +.Xc .D1 (alias: Ic selectw ) Select the window at .Ar target-window . +.Fl l , +.Fl n +and +.Fl p +are equivalent to the +.Ic last-window , +.Ic next-window +and +.Ic previous-window +commands. .It Xo Ic split-window .Op Fl dhvP .Oo Fl l From 64f02dab7cab4848a00da4aca39dd307b1ce792c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 5 Jan 2011 22:38:28 +0000 Subject: [PATCH 0831/1180] Whoops, command-prompt can take 0 or 1 argument. --- cmd-command-prompt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd-command-prompt.c b/cmd-command-prompt.c index db50adc7..0bb4e209 100644 --- a/cmd-command-prompt.c +++ b/cmd-command-prompt.c @@ -36,7 +36,7 @@ void cmd_command_prompt_free(void *); const struct cmd_entry cmd_command_prompt_entry = { "command-prompt", NULL, - "p:t:", 0, 0, + "p:t:", 0, 1, CMD_TARGET_CLIENT_USAGE " [-p prompts] [template]", 0, cmd_command_prompt_key_binding, From 703160b5d6b64e45a684894260693c60b5524d51 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 8 Jan 2011 00:48:54 +0000 Subject: [PATCH 0832/1180] Accept colours of the hex form #ffffff and translate to the nearest from the xterm(1) 256-colour set. --- Makefile | 4 +- colour.c | 119 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- tmux.1 | 7 +++- 3 files changed, 124 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 4c48ccdb..c103d766 100644 --- a/Makefile +++ b/Makefile @@ -44,7 +44,7 @@ CDIAGFLAGS+= -Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations CDIAGFLAGS+= -Wwrite-strings -Wshadow -Wpointer-arith -Wsign-compare CDIAGFLAGS+= -Wundef -Wbad-function-cast -Winline -Wcast-align -LDADD= -lutil -lcurses -levent -DPADD= ${LIBUTIL} ${LIBCURSES} ${LIBEVENT} +LDADD= -lutil -lcurses -levent -lm +DPADD= ${LIBUTIL} ${LIBCURSES} ${LIBEVENT} ${LIBM} .include diff --git a/colour.c b/colour.c index 5e31f815..3530686a 100644 --- a/colour.c +++ b/colour.c @@ -18,6 +18,8 @@ #include +#include +#include #include #include @@ -28,6 +30,101 @@ * of the 256 colour palette. */ +/* An RGB colour. */ +struct colour_rgb { + u_char r; + u_char g; + u_char b; +}; + +/* 256 colour RGB table, generated on first use. */ +struct colour_rgb *colour_rgb_256; + +void colour_rgb_generate256(void); +double colour_rgb_distance(struct colour_rgb *, struct colour_rgb *); +int colour_rgb_find(struct colour_rgb *); + +/* Generate 256 colour RGB table. */ +void +colour_rgb_generate256(void) +{ + struct colour_rgb *rgb; + u_int i, r, g, b; + + /* + * Allocate the table. The first 16 colours are often changed by users + * and terminals so don't include them. + */ + colour_rgb_256 = xcalloc(240, sizeof *colour_rgb_256); + + /* Add the colours first. */ + r = g = b = 0; + for (i = 240; i > 24; i--) { + rgb = &colour_rgb_256[240 - i]; + + if (r != 0) + rgb->r = (r * 40) + 55; + if (g != 0) + rgb->g = (g * 40) + 55; + if (b != 0) + rgb->b = (b * 40) + 55; + + b++; + if (b > 5) { + b = 0; + g++; + } + if (g > 5) { + g = 0; + r++; + } + } + + /* Then add the greys. */ + for (i = 24; i > 0; i--) { + rgb = &colour_rgb_256[240 - i]; + + rgb->r = 8 + (24 - i) * 10; + rgb->g = 8 + (24 - i) * 10; + rgb->b = 8 + (24 - i) * 10; + } +} + +/* Get colour RGB distance. */ +double +colour_rgb_distance(struct colour_rgb *rgb1, struct colour_rgb *rgb2) +{ + int r, g, b; + + r = rgb1->r - rgb2->r; + g = rgb1->g - rgb2->g; + b = rgb1->b - rgb2->b; + return (sqrt(r * r + g * g + b * b)); +} + +/* Work out the nearest colour from the 256 colour set. */ +int +colour_rgb_find(struct colour_rgb *rgb) +{ + double distance, lowest; + u_int colour, i; + + if (colour_rgb_256 == NULL) + colour_rgb_generate256(); + + colour = 16; + lowest = INFINITY; + for (i = 0; i < 240; i++) { + distance = colour_rgb_distance(&colour_rgb_256[i], rgb); + if (distance < lowest) { + lowest = distance; + colour = 16 + i; + } + } + return (colour); +} + +/* Set grid cell foreground colour. */ void colour_set_fg(struct grid_cell *gc, int c) { @@ -36,6 +133,7 @@ colour_set_fg(struct grid_cell *gc, int c) gc->fg = c; } +/* Set grid cell background colour. */ void colour_set_bg(struct grid_cell *gc, int c) { @@ -44,6 +142,7 @@ colour_set_bg(struct grid_cell *gc, int c) gc->bg = c; } +/* Convert colour to a string. */ const char * colour_tostring(int c) { @@ -77,11 +176,25 @@ colour_tostring(int c) return (NULL); } +/* Convert colour from string. */ int colour_fromstring(const char *s) { - const char *errstr; - int n; + const char *errstr; + const char *cp; + struct colour_rgb rgb; + int n; + + if (*s == '#' && strlen(s) == 7) { + for (cp = s + 1; isxdigit((u_char) *cp); cp++) + ; + if (*cp != '\0') + return (-1); + n = sscanf(s + 1, "%2hhx%2hhx%2hhx", &rgb.r, &rgb.g, &rgb.b); + if (n != 3) + return (-1); + return (colour_rgb_find(&rgb) | 0x100); + } if (strncasecmp(s, "colour", (sizeof "colour") - 1) == 0) { n = strtonum(s + (sizeof "colour") - 1, 0, 255, &errstr); @@ -111,6 +224,7 @@ colour_fromstring(const char *s) return (-1); } +/* Convert 256 colour palette to 16. */ u_char colour_256to16(u_char c) { @@ -136,6 +250,7 @@ colour_256to16(u_char c) return (table[c]); } +/* Convert 256 colour palette to 88. */ u_char colour_256to88(u_char c) { diff --git a/tmux.1 b/tmux.1 index 64ca5ed3..95ebfb45 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1793,8 +1793,11 @@ is one of: .Ic colour0 to .Ic colour255 -from the 256-colour palette, or -.Ic default . +from the 256-colour set, +.Ic default , +or a hexadecimal RGB string such as +.Ql #ffffff , +which chooses the closest match from the default 256-colour set. .It Ic message-fg Ar colour Set status line message foreground colour. .It Ic message-limit Ar number From 69cb1f830e4fd2282ddcbc7ee2bbe30069b9e4cd Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 8 Jan 2011 01:52:36 +0000 Subject: [PATCH 0833/1180] Move all calls to fcntl(...O_NONBLOCK) into a function and clear the flag on the stdio file descriptors before closing them (fixes things like "tmux ls && cat"). --- client.c | 7 ++----- cmd-pipe-pane.c | 7 ++----- job.c | 7 ++----- server-client.c | 32 ++++++++++++++++---------------- server.c | 8 ++------ tmux.c | 24 +++++++++++++++++------- tmux.h | 1 + tty.c | 10 ++-------- window.c | 7 ++----- 9 files changed, 46 insertions(+), 57 deletions(-) diff --git a/client.c b/client.c index 35a2e4e8..1ff3e1f1 100644 --- a/client.c +++ b/client.c @@ -54,7 +54,7 @@ client_connect(char *path, int start_server) { struct sockaddr_un sa; size_t size; - int fd, mode; + int fd; memset(&sa, 0, sizeof sa); sa.sun_family = AF_UNIX; @@ -84,10 +84,7 @@ client_connect(char *path, int start_server) } } - if ((mode = fcntl(fd, F_GETFL)) == -1) - fatal("fcntl failed"); - if (fcntl(fd, F_SETFL, mode|O_NONBLOCK) == -1) - fatal("fcntl failed"); + setblocking(fd, 0); return (fd); failed: diff --git a/cmd-pipe-pane.c b/cmd-pipe-pane.c index 6284bf37..d0e47541 100644 --- a/cmd-pipe-pane.c +++ b/cmd-pipe-pane.c @@ -53,7 +53,7 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx) struct client *c; struct window_pane *wp; char *command; - int old_fd, pipe_fd[2], null_fd, mode; + int old_fd, pipe_fd[2], null_fd; if ((c = cmd_find_client(ctx, NULL)) == NULL) return (-1); @@ -127,10 +127,7 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx) NULL, NULL, cmd_pipe_pane_error_callback, wp); bufferevent_enable(wp->pipe_event, EV_WRITE); - if ((mode = fcntl(wp->pipe_fd, F_GETFL)) == -1) - fatal("fcntl failed"); - if (fcntl(wp->pipe_fd, F_SETFL, mode|O_NONBLOCK) == -1) - fatal("fcntl failed"); + setblocking(wp->pipe_fd, 0); return (0); } } diff --git a/job.c b/job.c index ef4066e5..c7181964 100644 --- a/job.c +++ b/job.c @@ -137,7 +137,7 @@ job_free(struct job *job) int job_run(struct job *job) { - int nullfd, out[2], mode; + int nullfd, out[2]; if (job->fd != -1 || job->pid != -1) return (0); @@ -177,10 +177,7 @@ job_run(struct job *job) close(out[1]); job->fd = out[0]; - if ((mode = fcntl(job->fd, F_GETFL)) == -1) - fatal("fcntl failed"); - if (fcntl(job->fd, F_SETFL, mode|O_NONBLOCK) == -1) - fatal("fcntl failed"); + setblocking(job->fd, 0); if (job->event != NULL) bufferevent_free(job->event); diff --git a/server-client.c b/server-client.c index 24a85b56..055f192c 100644 --- a/server-client.c +++ b/server-client.c @@ -53,13 +53,9 @@ void server_client_create(int fd) { struct client *c; - int mode; u_int i; - if ((mode = fcntl(fd, F_GETFL)) == -1) - fatal("fcntl failed"); - if (fcntl(fd, F_SETFL, mode|O_NONBLOCK) == -1) - fatal("fcntl failed"); + setblocking(fd, 0); c = xcalloc(1, sizeof *c); c->references = 0; @@ -124,16 +120,22 @@ server_client_lost(struct client *c) if (c->flags & CLIENT_TERMINAL) tty_free(&c->tty); - if (c->stdin_fd != -1) + if (c->stdin_fd != -1) { + setblocking(c->stdin_fd, 1); close(c->stdin_fd); + } if (c->stdin_event != NULL) bufferevent_free(c->stdin_event); - if (c->stdout_fd != -1) + if (c->stdout_fd != -1) { + setblocking(c->stdout_fd, 1); close(c->stdout_fd); + } if (c->stdout_event != NULL) bufferevent_free(c->stdout_event); - if (c->stderr_fd != -1) + if (c->stderr_fd != -1) { + setblocking(c->stderr_fd, 1); close(c->stderr_fd); + } if (c->stderr_event != NULL) bufferevent_free(c->stderr_event); @@ -632,6 +634,7 @@ server_client_in_callback( return; bufferevent_disable(c->stdin_event, EV_READ|EV_WRITE); + setblocking(c->stdin_fd, 1); close(c->stdin_fd); c->stdin_fd = -1; @@ -647,6 +650,7 @@ server_client_out_callback( struct client *c = data; bufferevent_disable(c->stdout_event, EV_READ|EV_WRITE); + setblocking(c->stdout_fd, 1); close(c->stdout_fd); c->stdout_fd = -1; } @@ -659,6 +663,7 @@ server_client_err_callback( struct client *c = data; bufferevent_disable(c->stderr_event, EV_READ|EV_WRITE); + setblocking(c->stderr_fd, 1); close(c->stderr_fd); c->stderr_fd = -1; } @@ -672,7 +677,6 @@ server_client_msg_dispatch(struct client *c) struct msg_identify_data identifydata; struct msg_environ_data environdata; ssize_t n, datalen; - int mode; if ((n = imsg_read(&c->ibuf)) == -1 || n == 0) return (-1); @@ -712,9 +716,7 @@ server_client_msg_dispatch(struct client *c) NULL, NULL, server_client_in_callback, c); if (c->stdin_event == NULL) fatalx("failed to create stdin event"); - - if ((mode = fcntl(c->stdin_fd, F_GETFL)) != -1) - fcntl(c->stdin_fd, F_SETFL, mode|O_NONBLOCK); + setblocking(c->stdin_fd, 0); server_client_msg_identify(c, &identifydata, imsg.fd); break; @@ -729,9 +731,8 @@ server_client_msg_dispatch(struct client *c) NULL, NULL, server_client_out_callback, c); if (c->stdout_event == NULL) fatalx("failed to create stdout event"); + setblocking(c->stdout_fd, 0); - if ((mode = fcntl(c->stdout_fd, F_GETFL)) != -1) - fcntl(c->stdout_fd, F_SETFL, mode|O_NONBLOCK); break; case MSG_STDERR: if (datalen != 0) @@ -744,9 +745,8 @@ server_client_msg_dispatch(struct client *c) NULL, NULL, server_client_err_callback, c); if (c->stderr_event == NULL) fatalx("failed to create stderr event"); + setblocking(c->stderr_fd, 0); - if ((mode = fcntl(c->stderr_fd, F_GETFL)) != -1) - fcntl(c->stderr_fd, F_SETFL, mode|O_NONBLOCK); break; case MSG_RESIZE: if (datalen != 0) diff --git a/server.c b/server.c index 3b35454d..8f6ee149 100644 --- a/server.c +++ b/server.c @@ -74,7 +74,7 @@ server_create_socket(void) struct sockaddr_un sa; size_t size; mode_t mask; - int fd, mode; + int fd; memset(&sa, 0, sizeof sa); sa.sun_family = AF_UNIX; @@ -95,11 +95,7 @@ server_create_socket(void) if (listen(fd, 16) == -1) fatal("listen failed"); - - if ((mode = fcntl(fd, F_GETFL)) == -1) - fatal("fcntl failed"); - if (fcntl(fd, F_SETFL, mode|O_NONBLOCK) == -1) - fatal("fcntl failed"); + setblocking(fd, 0); server_update_socket(); diff --git a/tmux.c b/tmux.c index 007d81fd..3b40da12 100644 --- a/tmux.c +++ b/tmux.c @@ -194,12 +194,25 @@ makesocketpath(const char *label) return (path); } +void +setblocking(int fd, int state) +{ + int mode; + + if ((mode = fcntl(fd, F_GETFL)) != -1) { + if (!state) + mode |= O_NONBLOCK; + else + mode &= ~O_NONBLOCK; + fcntl(fd, F_SETFL, mode); + } +} + __dead void shell_exec(const char *shell, const char *shellcmd) { const char *shellname, *ptr; char *argv0; - int mode; ptr = strrchr(shell, '/'); if (ptr != NULL && *(ptr + 1) != '\0') @@ -212,12 +225,9 @@ shell_exec(const char *shell, const char *shellcmd) xasprintf(&argv0, "%s", shellname); setenv("SHELL", shell, 1); - if ((mode = fcntl(STDIN_FILENO, F_GETFL)) != -1) - fcntl(STDIN_FILENO, F_SETFL, mode & ~O_NONBLOCK); - if ((mode = fcntl(STDOUT_FILENO, F_GETFL)) != -1) - fcntl(STDOUT_FILENO, F_SETFL, mode & ~O_NONBLOCK); - if ((mode = fcntl(STDERR_FILENO, F_GETFL)) != -1) - fcntl(STDERR_FILENO, F_SETFL, mode & ~O_NONBLOCK); + setblocking(STDIN_FILENO, 1); + setblocking(STDOUT_FILENO, 1); + setblocking(STDERR_FILENO, 1); closefrom(STDERR_FILENO + 1); execl(shell, argv0, "-c", shellcmd, (char *) NULL); diff --git a/tmux.h b/tmux.h index 3e6ecec2..b1f733aa 100644 --- a/tmux.h +++ b/tmux.h @@ -1308,6 +1308,7 @@ void logfile(const char *); const char *getshell(void); int checkshell(const char *); int areshell(const char *); +void setblocking(int, int); __dead void shell_exec(const char *, const char *); /* cfg.c */ diff --git a/tty.c b/tty.c index 80afa2d4..451a5df6 100644 --- a/tty.c +++ b/tty.c @@ -165,15 +165,11 @@ void tty_start_tty(struct tty *tty) { struct termios tio; - int mode; if (tty->fd == -1) return; - if ((mode = fcntl(tty->fd, F_GETFL)) == -1) - fatal("fcntl failed"); - if (fcntl(tty->fd, F_SETFL, mode|O_NONBLOCK) == -1) - fatal("fcntl failed"); + setblocking(tty->fd, 0); bufferevent_enable(tty->event, EV_READ|EV_WRITE); @@ -220,7 +216,6 @@ void tty_stop_tty(struct tty *tty) { struct winsize ws; - int mode; if (!(tty->flags & TTY_STARTED)) return; @@ -251,8 +246,7 @@ tty_stop_tty(struct tty *tty) tty_raw(tty, tty_term_string(tty->term, TTYC_RMCUP)); - if ((mode = fcntl(tty->fd, F_GETFL)) != -1) - fcntl(tty->fd, F_SETFL, mode & ~O_NONBLOCK); + setblocking(tty->fd, 1); } void diff --git a/window.c b/window.c index ebd3976b..f965d27f 100644 --- a/window.c +++ b/window.c @@ -563,7 +563,6 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell, const char *cwd, struct environ *env, struct termios *tio, char **cause) { struct winsize ws; - int mode; char *argv0; const char *ptr; struct termios tio2; @@ -637,10 +636,8 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell, fatal("execl failed"); } - if ((mode = fcntl(wp->fd, F_GETFL)) == -1) - fatal("fcntl failed"); - if (fcntl(wp->fd, F_SETFL, mode|O_NONBLOCK) == -1) - fatal("fcntl failed"); + setblocking(wp->fd, 0); + wp->event = bufferevent_new(wp->fd, window_pane_read_callback, NULL, window_pane_error_callback, wp); bufferevent_enable(wp->event, EV_READ|EV_WRITE); From c3041eb9f055fb3479fb52934c6afaf6207e96f6 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 9 Jan 2011 18:42:19 +0000 Subject: [PATCH 0834/1180] Add missing arguments to some options. --- tmux.1 | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/tmux.1 b/tmux.1 index 95ebfb45..9f5aa30a 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1628,16 +1628,20 @@ Available server options are: Set the number of buffers; as new buffers are added to the top of the stack, old ones are removed from the bottom if necessary to maintain this maximum length. -.It Ic escape-time +.It Ic escape-time Ar time Set the time in milliseconds for which .Nm waits after an escape is input to determine if it is part of a function or meta key sequences. The default is 500 milliseconds. -.It Ic exit-unattached +.It Xo Ic exit-unattached +.Op Ic on | off +.Xc If enabled, the server will exit when there are no attached clients, rather than when there are no attached sessions. -.It Ic quiet +.It Xo Ic quiet +.Op Ic on | off +.Xc Enable or disable the display of various informational messages (see also the .Fl q command line flag). @@ -1705,10 +1709,14 @@ to work correctly, this be set to .Ql screen or a derivative of it. -.It Ic destroy-unattached +.It Xo Ic destroy-unattached +.Op Ic on | off +.Xc If enabled and the session is no longer attached to any clients, it is destroyed. -.It Ic detach-on-destroy +.It Xo Ic detach-on-destroy +.Op Ic on | off +.Xc If on (the default), the client is detached when the session it is attached to is destroyed. If off, the client is switched to the most recently active of the remaining From 17f1cd5be81eddf34139f24263a9e00d2dd372e5 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 9 Jan 2011 18:46:46 +0000 Subject: [PATCH 0835/1180] Remove a bit of text that makes exit-unattached description unclear. --- tmux.1 | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tmux.1 b/tmux.1 index 9f5aa30a..27a0c997 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1637,8 +1637,7 @@ The default is 500 milliseconds. .It Xo Ic exit-unattached .Op Ic on | off .Xc -If enabled, the server will exit when there are no attached clients, rather -than when there are no attached sessions. +If enabled, the server will exit when there are no attached clients. .It Xo Ic quiet .Op Ic on | off .Xc From 47e18f4ceacc4c207dc0d392f51d55b2286672f2 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 10 Jan 2011 21:28:47 +0000 Subject: [PATCH 0836/1180] unbind-key -a is allowed no arguments. --- cmd-unbind-key.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cmd-unbind-key.c b/cmd-unbind-key.c index 7dab5683..8eb829d4 100644 --- a/cmd-unbind-key.c +++ b/cmd-unbind-key.c @@ -31,7 +31,7 @@ int cmd_unbind_key_table(struct cmd *, struct cmd_ctx *, int); const struct cmd_entry cmd_unbind_key_entry = { "unbind-key", "unbind", - "acnt:", 1, 1, + "acnt:", 0, 1, "[-acn] [-t key-table] key", 0, NULL, @@ -43,6 +43,8 @@ int cmd_unbind_key_check(struct args *args) { if (args_has(args, 'a') && (args->argc != 0 || args_has(args, 't'))) + return (-1); + if (!args_has(args, 'a') && args->argc != 1) return (-1); return (0); } From b3438c86bfb69bfdda55e15525abcacd33738686 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 12 Jan 2011 22:23:58 +0000 Subject: [PATCH 0837/1180] Use TMPDIR if set, from Han Boetes. --- tmux.1 | 5 ++++- tmux.c | 7 +++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/tmux.1 b/tmux.1 index 27a0c997..cf244782 100644 --- a/tmux.1 +++ b/tmux.1 @@ -134,7 +134,10 @@ will report an error and exit without executing further commands. .It Fl L Ar socket-name .Nm stores the server socket in a directory under -.Pa /tmp ; +.Pa /tmp +(or +.Ev TMPDIR +if set); the default socket is named .Em default . This option allows a different socket name to be specified, allowing several diff --git a/tmux.c b/tmux.c index 3b40da12..0225f5f6 100644 --- a/tmux.c +++ b/tmux.c @@ -169,12 +169,15 @@ parseenvironment(void) char * makesocketpath(const char *label) { - char base[MAXPATHLEN], *path; + char base[MAXPATHLEN], *path, *s; struct stat sb; u_int uid; uid = getuid(); - xsnprintf(base, MAXPATHLEN, "%s/tmux-%d", _PATH_TMP, uid); + if ((s = getenv("TMPDIR")) == NULL || *s == '\0') + xsnprintf(base, sizeof base, "%s/tmux-%u", _PATH_TMP, uid); + else + xsnprintf(base, sizeof base, "%s/tmux-%u", s, uid); if (mkdir(base, S_IRWXU) != 0 && errno != EEXIST) return (NULL); From 96ab50a701f0266dce610dc3a9d4aacb595065b0 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 13 Jan 2011 00:54:32 +0000 Subject: [PATCH 0838/1180] Log termios backspace for each client since it is used to recognise backspace input. --- cmd-server-info.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cmd-server-info.c b/cmd-server-info.c index 4bd65143..2eaf142f 100644 --- a/cmd-server-info.c +++ b/cmd-server-info.c @@ -88,10 +88,11 @@ cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx) if (c == NULL || c->session == NULL) continue; - ctx->print(ctx, "%2d: %s (%d, %d): %s [%ux%u %s] " + ctx->print(ctx,"%2d: %s (%d, %d): %s [%ux%u %s bs=%hho] " "[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->flags, + c->tty.sx, c->tty.sy, c->tty.termname, + c->tty.tio.c_cc[VERASE], c->flags, c->tty.flags, c->references); } ctx->print(ctx, "%s", ""); From 588ebb5393902fc02cb2eab010753d9649761325 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 13 Jan 2011 02:07:06 +0000 Subject: [PATCH 0839/1180] Fix next and previous session functions to actually work. --- session.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/session.c b/session.c index fc0d9f07..31f195f5 100644 --- a/session.c +++ b/session.c @@ -181,12 +181,9 @@ session_next_session(struct session *s) if (RB_EMPTY(&sessions) || !session_alive(s)) return (NULL); - s2 = s; - do { - s2 = RB_NEXT(sessions, &sessions, s2); - if (s2 == NULL) - s2 = RB_MIN(sessions, &sessions); - } while (s2 != s); + s2 = RB_NEXT(sessions, &sessions, s2); + if (s2 == NULL) + s2 = RB_MIN(sessions, &sessions); if (s2 == s) return (NULL); return (s2); @@ -201,12 +198,9 @@ session_previous_session(struct session *s) if (RB_EMPTY(&sessions) || !session_alive(s)) return (NULL); - s2 = s; - do { - s2 = RB_PREV(sessions, &sessions, s2); - if (s2 == NULL) - s2 = RB_MAX(sessions, &sessions); - } while (s2 != s); + s2 = RB_PREV(sessions, &sessions, s2); + if (s2 == NULL) + s2 = RB_MAX(sessions, &sessions); if (s2 == s) return (NULL); return (s2); From 2d82567070c36fe7229d38c0ad328014715d6f4a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 13 Jan 2011 02:08:14 +0000 Subject: [PATCH 0840/1180] Er, fix next and previous session functions to actually work, part 2. --- session.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/session.c b/session.c index 31f195f5..6cd141ef 100644 --- a/session.c +++ b/session.c @@ -181,7 +181,7 @@ session_next_session(struct session *s) if (RB_EMPTY(&sessions) || !session_alive(s)) return (NULL); - s2 = RB_NEXT(sessions, &sessions, s2); + s2 = RB_NEXT(sessions, &sessions, s); if (s2 == NULL) s2 = RB_MIN(sessions, &sessions); if (s2 == s) @@ -198,7 +198,7 @@ session_previous_session(struct session *s) if (RB_EMPTY(&sessions) || !session_alive(s)) return (NULL); - s2 = RB_PREV(sessions, &sessions, s2); + s2 = RB_PREV(sessions, &sessions, s); if (s2 == NULL) s2 = RB_MAX(sessions, &sessions); if (s2 == s) From fa4a75cdabbac1751df30138a4f62f526225aacc Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 13 Jan 2011 09:50:11 +0000 Subject: [PATCH 0841/1180] Clarify alternate-screen description a little. --- tmux.1 | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tmux.1 b/tmux.1 index cf244782..a20b8341 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2153,8 +2153,11 @@ may use the terminal alternate screen feature, which allows the and .Em rmcup .Xr terminfo 5 -capabilities to be issued to preserve the existing window content on start and -restore it on exit. +capabilities. +The alternate screen feature preserves the contents of the window when an +interactive application starts and restores it on exit, so that any output +visible before the application starts reappears unchanged after it exits. +The default is on. .Pp .It Xo Ic automatic-rename .Op Ic on | off From 9ad9e8c5dded2e9134a8386bacd1ddd6625e07d1 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 13 Jan 2011 13:38:57 +0000 Subject: [PATCH 0842/1180] The maximum history-limit was accidentally reduced, fix it back to INT_MAX. --- options-table.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/options-table.c b/options-table.c index 4e2b8f61..f8f99314 100644 --- a/options-table.c +++ b/options-table.c @@ -150,7 +150,7 @@ const struct options_table_entry session_options_table[] = { { .name = "history-limit", .type = OPTIONS_TABLE_NUMBER, .minimum = 0, - .maximum = SHRT_MAX, + .maximum = INT_MAX, .default_num = 2000 }, From 4f34e25dd867e30652682d9aac01d8b1af220fa6 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 14 Jan 2011 23:49:23 +0000 Subject: [PATCH 0843/1180] Support -x and -y for new-session to specify the initial size of the window if created detached with -d. --- cmd-new-session.c | 27 ++++++++++++++++++++++++--- tmux.1 | 9 +++++++++ 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/cmd-new-session.c b/cmd-new-session.c index d53e2692..1aa1c087 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -34,8 +35,9 @@ int cmd_new_session_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_new_session_entry = { "new-session", "new", - "dn:s:t:", 0, 1, - "[-d] [-n window-name] [-s session-name] [-t target-session] [command]", + "dn:s:t:x:y:", 0, 1, + "[-d] [-n window-name] [-s session-name] [-t target-session] " + "[-x width] [-y height] [command]", CMD_STARTSERVER|CMD_CANTNEST|CMD_SENDENVIRON, NULL, cmd_new_session_check, @@ -47,6 +49,9 @@ cmd_new_session_check(struct args *args) { if (args_has(args, 't') && (args->argc != 0 || args_has(args, 'n'))) return (-1); + if (!args_has(args, 'd') && + (args_has(args, 'x') || args_has(args, 'y'))) + return (-1); return (0); } @@ -60,7 +65,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) struct environ env; struct termios tio, *tiop; struct passwd *pw; - const char *newname, *target, *update, *cwd; + const char *newname, *target, *update, *cwd, *errstr; char *overrides, *cmd, *cause; int detached, idx; u_int sx, sy, i; @@ -149,6 +154,22 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) if (detached) { sx = 80; sy = 24; + if (args_has(args, 'x')) { + sx = strtonum( + args_get(args, 'x'), 1, USHRT_MAX, &errstr); + if (errstr != NULL) { + ctx->error(ctx, "width %s", errstr); + return (-1); + } + } + if (args_has(args, 'y')) { + sy = strtonum( + args_get(args, 'y'), 1, USHRT_MAX, &errstr); + if (errstr != NULL) { + ctx->error(ctx, "height %s", errstr); + return (-1); + } + } } else if (ctx->cmdclient != NULL) { sx = ctx->cmdclient->tty.sx; sy = ctx->cmdclient->tty.sy; diff --git a/tmux.1 b/tmux.1 index a20b8341..36253d17 100644 --- a/tmux.1 +++ b/tmux.1 @@ -591,6 +591,8 @@ Lock all clients attached to .Op Fl n Ar window-name .Op Fl s Ar session-name .Op Fl t Ar target-session +.Op Fl x Ar width +.Op Fl y Ar height .Op Ar shell-command .Xc .D1 (alias: Ic new ) @@ -604,6 +606,13 @@ is given. and .Ar shell-command are the name of and shell command to execute in the initial window. +If +.Fl d +is used, +.Fl x +and +.Fl y +specify the size of the initial window (80 by 24 if not given). .Pp If run from a terminal, any .Xr termios 4 From 8f8e81c0c9a39b2977e3b2737d4825ab00bef52a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 15 Jan 2011 00:16:00 +0000 Subject: [PATCH 0844/1180] Mouse highlight mode (1001) requires a program to cooperate so supporting it through tmux is not as easy as this, remove it for now. --- input.c | 4 ---- tmux.h | 10 ++++------ tty.c | 4 ---- 3 files changed, 4 insertions(+), 14 deletions(-) diff --git a/input.c b/input.c index cb8c4e52..df387dad 100644 --- a/input.c +++ b/input.c @@ -1201,10 +1201,6 @@ input_csi_dispatch(struct input_ctx *ictx) screen_write_mousemode_on( &ictx->ctx, MODE_MOUSE_STANDARD); break; - case 1001: - screen_write_mousemode_on( - &ictx->ctx, MODE_MOUSE_HIGHLIGHT); - break; case 1002: screen_write_mousemode_on( &ictx->ctx, MODE_MOUSE_BUTTON); diff --git a/tmux.h b/tmux.h index b1f733aa..4eab285c 100644 --- a/tmux.h +++ b/tmux.h @@ -547,13 +547,11 @@ struct mode_key_table { #define MODE_KKEYPAD 0x8 /* set = application, clear = number */ #define MODE_WRAP 0x10 /* whether lines wrap */ #define MODE_MOUSE_STANDARD 0x20 -#define MODE_MOUSE_HIGHLIGHT 0x40 -#define MODE_MOUSE_BUTTON 0x80 -#define MODE_MOUSE_ANY 0x100 -#define MODE_MOUSE_UTF8 0x200 +#define MODE_MOUSE_BUTTON 0x40 +#define MODE_MOUSE_ANY 0x80 +#define MODE_MOUSE_UTF8 0x100 -#define ALL_MOUSE_MODES (MODE_MOUSE_STANDARD| \ - MODE_MOUSE_HIGHLIGHT|MODE_MOUSE_BUTTON|MODE_MOUSE_ANY) +#define ALL_MOUSE_MODES (MODE_MOUSE_STANDARD|MODE_MOUSE_BUTTON|MODE_MOUSE_ANY) /* * A single UTF-8 character. diff --git a/tty.c b/tty.c index 451a5df6..aff0d08a 100644 --- a/tty.c +++ b/tty.c @@ -403,8 +403,6 @@ tty_update_mode(struct tty *tty, int mode) tty_puts(tty, "\033[?1005h"); if (mode & MODE_MOUSE_STANDARD) tty_puts(tty, "\033[?1000h"); - else if (mode & MODE_MOUSE_HIGHLIGHT) - tty_puts(tty, "\033[?1001h"); else if (mode & MODE_MOUSE_BUTTON) tty_puts(tty, "\033[?1002h"); else if (mode & MODE_MOUSE_ANY) @@ -412,8 +410,6 @@ tty_update_mode(struct tty *tty, int mode) } else { if (tty->mode & MODE_MOUSE_STANDARD) tty_puts(tty, "\033[?1000l"); - else if (tty->mode & MODE_MOUSE_HIGHLIGHT) - tty_puts(tty, "\033[?1001l"); else if (tty->mode & MODE_MOUSE_BUTTON) tty_puts(tty, "\033[?1002l"); else if (tty->mode & MODE_MOUSE_ANY) From 3de1700f616a60a7c7d15a66b0637012b5cdb00a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 15 Jan 2011 00:46:19 +0000 Subject: [PATCH 0845/1180] Only set a mouse mode for mouse-select-pane if none already set by the mode (any will do). --- server-client.c | 7 ++++++- tty.c | 16 ++++++++-------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/server-client.c b/server-client.c index 055f192c..9b83fe13 100644 --- a/server-client.c +++ b/server-client.c @@ -449,9 +449,14 @@ server_client_reset_state(struct client *c) else tty_cursor(&c->tty, wp->xoff + s->cx, wp->yoff + s->cy); + /* + * Any mode will do for mouse-select-pane, but set standard mode if + * none. + */ mode = s->mode; if (TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry) != NULL && - options_get_number(oo, "mouse-select-pane")) + options_get_number(oo, "mouse-select-pane") && + (mode & ALL_MOUSE_MODES) == 0) mode |= MODE_MOUSE_STANDARD; /* diff --git a/tty.c b/tty.c index aff0d08a..497dacc6 100644 --- a/tty.c +++ b/tty.c @@ -401,19 +401,19 @@ tty_update_mode(struct tty *tty, int mode) if (mode & ALL_MOUSE_MODES) { if (mode & MODE_MOUSE_UTF8) tty_puts(tty, "\033[?1005h"); - if (mode & MODE_MOUSE_STANDARD) - tty_puts(tty, "\033[?1000h"); + if (mode & MODE_MOUSE_ANY) + tty_puts(tty, "\033[?1003h"); else if (mode & MODE_MOUSE_BUTTON) tty_puts(tty, "\033[?1002h"); - else if (mode & MODE_MOUSE_ANY) - tty_puts(tty, "\033[?1003h"); + else if (mode & MODE_MOUSE_STANDARD) + tty_puts(tty, "\033[?1000h"); } else { - if (tty->mode & MODE_MOUSE_STANDARD) - tty_puts(tty, "\033[?1000l"); + if (tty->mode & MODE_MOUSE_ANY) + tty_puts(tty, "\033[?1003l"); else if (tty->mode & MODE_MOUSE_BUTTON) tty_puts(tty, "\033[?1002l"); - else if (tty->mode & MODE_MOUSE_ANY) - tty_puts(tty, "\033[?1003l"); + else if (tty->mode & MODE_MOUSE_STANDARD) + tty_puts(tty, "\033[?1000l"); if (tty->mode & MODE_MOUSE_UTF8) tty_puts(tty, "\033[?1005l"); } From 1377427e708f23275c40a7b86d999bf6f8dd4a94 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 15 Jan 2011 20:14:41 +0000 Subject: [PATCH 0846/1180] Fix bind-key -t. --- cmd-bind-key.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd-bind-key.c b/cmd-bind-key.c index 025f6c79..30421115 100644 --- a/cmd-bind-key.c +++ b/cmd-bind-key.c @@ -45,7 +45,7 @@ int cmd_bind_key_check(struct args *args) { if (args_has(args, 't')) { - if (args->argc != 1) + if (args->argc != 2) return (-1); } else { if (args->argc < 2) @@ -99,9 +99,9 @@ cmd_bind_key_table(struct cmd *self, struct cmd_ctx *ctx, int key) return (-1); } - cmd = mode_key_fromstring(mtab->cmdstr, args->argv[0]); + cmd = mode_key_fromstring(mtab->cmdstr, args->argv[1]); if (cmd == MODEKEY_NONE) { - ctx->error(ctx, "unknown command: %s", args->argv[0]); + ctx->error(ctx, "unknown command: %s", args->argv[1]); return (-1); } From b8023044c35f3099e67793e3573e9e001a43b1fe Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 23 Jan 2011 11:03:43 +0000 Subject: [PATCH 0847/1180] Set $TMUX without the session when background jobs are run. --- cmd.c | 2 +- job.c | 12 ++++++++++-- server-fn.c | 18 ++++++++++++------ tmux.c | 45 +++++++++------------------------------------ tmux.h | 6 +++--- 5 files changed, 35 insertions(+), 48 deletions(-) diff --git a/cmd.c b/cmd.c index 6c4a06f4..5333a023 100644 --- a/cmd.c +++ b/cmd.c @@ -356,7 +356,7 @@ cmd_current_session(struct cmd_ctx *ctx) } /* Use the session from the TMUX environment variable. */ - if (data != NULL && data->pid == getpid()) { + if (data != NULL && data->pid == getpid() && data->idx != -1) { s = session_find_by_index(data->idx); if (s != NULL) return (s); diff --git a/job.c b/job.c index c7181964..ce7961a1 100644 --- a/job.c +++ b/job.c @@ -137,7 +137,8 @@ job_free(struct job *job) int job_run(struct job *job) { - int nullfd, out[2]; + struct environ env; + int nullfd, out[2]; if (job->fd != -1 || job->pid != -1) return (0); @@ -145,13 +146,19 @@ job_run(struct job *job) if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, out) != 0) return (-1); + environ_init(&env); + environ_copy(&global_environ, &env); + server_fill_environ(NULL, &env); + switch (job->pid = fork()) { case -1: + environ_free(&env); return (-1); case 0: /* child */ clear_signals(1); - environ_push(&global_environ); + environ_push(&env); + environ_free(&env); if (dup2(out[1], STDOUT_FILENO) == -1) fatal("dup2 failed"); @@ -174,6 +181,7 @@ job_run(struct job *job) execl(_PATH_BSHELL, "sh", "-c", job->cmd, (char *) NULL); fatal("execl failed"); default: /* parent */ + environ_free(&env); close(out[1]); job->fd = out[0]; diff --git a/server-fn.c b/server-fn.c index 7064c1ed..002d56ac 100644 --- a/server-fn.c +++ b/server-fn.c @@ -30,14 +30,20 @@ void server_callback_identify(int, short, void *); void server_fill_environ(struct session *s, struct environ *env) { - char tmuxvar[MAXPATHLEN], *term; + char var[MAXPATHLEN], *term; + u_int idx; + long pid; - xsnprintf(tmuxvar, sizeof tmuxvar, - "%s,%ld,%u", socket_path, (long) getpid(), s->idx); - environ_set(env, "TMUX", tmuxvar); + if (s != NULL) { + term = options_get_string(&s->options, "default-terminal"); + environ_set(env, "TERM", term); - term = options_get_string(&s->options, "default-terminal"); - environ_set(env, "TERM", term); + idx = s->idx; + } else + idx = -1; + pid = getpid(); + xsnprintf(var, sizeof var, "%s,%ld,%d", socket_path, pid, idx); + environ_set(env, "TMUX", var); } void diff --git a/tmux.c b/tmux.c index 0225f5f6..31070f00 100644 --- a/tmux.c +++ b/tmux.c @@ -48,8 +48,8 @@ time_t start_time; char socket_path[MAXPATHLEN]; int login_shell; char *environ_path; -pid_t environ_pid; -u_int environ_idx; +pid_t environ_pid = -1; +int environ_idx = -1; __dead void usage(void); void parseenvironment(void); @@ -125,45 +125,18 @@ areshell(const char *shell) void parseenvironment(void) { - char *env, *path_pid, *pid_idx, buf[256]; - size_t len; - const char *errstr; - long long ll; + char *env, path[256]; + long pid; + int idx; - environ_pid = -1; if ((env = getenv("TMUX")) == NULL) return; - if ((path_pid = strchr(env, ',')) == NULL || path_pid == env) + if (sscanf(env, "%255s,%ld,%d", path, &pid, &idx) != 3) return; - if ((pid_idx = strchr(path_pid + 1, ',')) == NULL) - return; - if ((pid_idx == path_pid + 1 || pid_idx[1] == '\0')) - return; - - /* path */ - len = path_pid - env; - environ_path = xmalloc(len + 1); - memcpy(environ_path, env, len); - environ_path[len] = '\0'; - - /* pid */ - len = pid_idx - path_pid - 1; - if (len > (sizeof buf) - 1) - return; - memcpy(buf, path_pid + 1, len); - buf[len] = '\0'; - - ll = strtonum(buf, 0, LONG_MAX, &errstr); - if (errstr != NULL) - return; - environ_pid = ll; - - /* idx */ - ll = strtonum(pid_idx + 1, 0, UINT_MAX, &errstr); - if (errstr != NULL) - return; - environ_idx = ll; + environ_path = xstrdup(path); + environ_pid = pid; + environ_idx = idx; } char * diff --git a/tmux.h b/tmux.h index 4eab285c..f6a45d33 100644 --- a/tmux.h +++ b/tmux.h @@ -383,8 +383,8 @@ enum msgtype { * Don't forget to bump PROTOCOL_VERSION if any of these change! */ struct msg_command_data { - pid_t pid; /* pid from $TMUX or -1 */ - u_int idx; /* index from $TMUX */ + pid_t pid; /* PID from $TMUX or -1 */ + int idx; /* index from $TMUX or -1 */ int argc; char argv[COMMAND_LENGTH]; @@ -1301,7 +1301,7 @@ extern char socket_path[MAXPATHLEN]; extern int login_shell; extern char *environ_path; extern pid_t environ_pid; -extern u_int environ_idx; +extern int environ_idx; void logfile(const char *); const char *getshell(void); int checkshell(const char *); From 3872e2484741d5b7e9b7facc0d364408ee548f9e Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 23 Jan 2011 11:04:25 +0000 Subject: [PATCH 0848/1180] Allow top-bit-set characters to be used for key bindings, from Tiago Cunha. --- key-string.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/key-string.c b/key-string.c index 2d768aef..ad7d4edd 100644 --- a/key-string.c +++ b/key-string.c @@ -147,7 +147,7 @@ key_string_lookup_string(const char *string) /* Is this a standard ASCII key? */ if (string[1] == '\0') { key = (u_char) string[0]; - if (key < 32 || key > 126) + if (key < 32 || key == 127 || key > 255) return (KEYC_NONE); } else { /* Otherwise look the key up in the table. */ @@ -213,7 +213,7 @@ key_string_lookup_key(int key) } /* Invalid keys are errors. */ - if (key >= 127) + if (key == 127 || key > 255) return (NULL); /* Check for standard or control key. */ @@ -225,7 +225,9 @@ key_string_lookup_key(int key) } else if (key >= 32 && key <= 126) { tmp[0] = key; tmp[1] = '\0'; - } + } else if (key >= 128) + xsnprintf(tmp, sizeof tmp, "\\%o", key); + strlcat(out, tmp, sizeof out); return (out); } From 8820aa9f6511cb245dd8c735294e7a0c6fdb0870 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 23 Jan 2011 15:46:49 +0000 Subject: [PATCH 0849/1180] Size is -l not -s. --- cmd-join-pane.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd-join-pane.c b/cmd-join-pane.c index 10b4dda3..be4335fc 100644 --- a/cmd-join-pane.c +++ b/cmd-join-pane.c @@ -89,8 +89,8 @@ cmd_join_pane_exec(struct cmd *self, struct cmd_ctx *ctx) type = LAYOUT_LEFTRIGHT; size = -1; - if (args_has(args, 's')) { - size = args_strtonum(args, 's', 0, INT_MAX, &cause); + if (args_has(args, 'l')) { + size = args_strtonum(args, 'l', 0, INT_MAX, &cause); if (cause != NULL) { ctx->error(ctx, "size %s", cause); xfree(cause); From 1df33554382a09aaca4879e4857f42b91ca3bbc6 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 23 Jan 2011 15:49:10 +0000 Subject: [PATCH 0850/1180] While here, maximum percentage is 100 not INT_MAX. Oops. --- cmd-join-pane.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd-join-pane.c b/cmd-join-pane.c index be4335fc..0bfefd2f 100644 --- a/cmd-join-pane.c +++ b/cmd-join-pane.c @@ -97,7 +97,7 @@ cmd_join_pane_exec(struct cmd *self, struct cmd_ctx *ctx) return (-1); } } else if (args_has(args, 'p')) { - percentage = args_strtonum(args, 'p', 0, INT_MAX, &cause); + percentage = args_strtonum(args, 'p', 0, 100, &cause); if (cause != NULL) { ctx->error(ctx, "percentage %s", cause); xfree(cause); From 1270f8fed8642ac61d14be6a3aeb8d002db82a78 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 25 Jan 2011 22:31:50 +0000 Subject: [PATCH 0851/1180] Check if the index is in use and fail before creating the child process, rather than leaving a stray child on failure. --- session.c | 20 +++++++++++++++++--- tmux.h | 3 ++- window.c | 24 +++++++++++++++--------- 3 files changed, 34 insertions(+), 13 deletions(-) diff --git a/session.c b/session.c index 6cd141ef..9babd81c 100644 --- a/session.c +++ b/session.c @@ -212,10 +212,16 @@ session_new(struct session *s, const char *name, const char *cmd, const char *cwd, int idx, char **cause) { struct window *w; + struct winlink *wl; struct environ env; const char *shell; u_int hlimit; + if ((wl = winlink_add(&s->windows, idx)) == NULL) { + xasprintf(cause, "index in use: %d", idx); + return (NULL); + } + environ_init(&env); environ_copy(&global_environ, &env); environ_copy(&s->environ, &env); @@ -229,15 +235,18 @@ session_new(struct session *s, w = window_create( name, cmd, shell, cwd, &env, s->tio, s->sx, s->sy, hlimit, cause); if (w == NULL) { + winlink_remove(&s->windows, wl); environ_free(&env); return (NULL); } + winlink_set_window(wl, w); environ_free(&env); if (options_get_number(&s->options, "set-remain-on-exit")) options_set_number(&w->options, "remain-on-exit", 1); - return (session_attach(s, w, idx, cause)); + session_group_synchronize_from(s); + return (wl); } /* Attach a window to a session. */ @@ -246,8 +255,12 @@ session_attach(struct session *s, struct window *w, int idx, char **cause) { struct winlink *wl; - if ((wl = winlink_add(&s->windows, w, idx)) == NULL) + if ((wl = winlink_add(&s->windows, idx)) == NULL) { xasprintf(cause, "index in use: %d", idx); + return (NULL); + } + winlink_set_window(wl, w); + session_group_synchronize_from(s); return (wl); } @@ -526,7 +539,8 @@ session_group_synchronize1(struct session *target, struct session *s) /* Link all the windows from the target. */ RB_FOREACH(wl, winlinks, ww) { - wl2 = winlink_add(&s->windows, wl->window, wl->idx); + wl2 = winlink_add(&s->windows, wl->idx); + winlink_set_window(wl2, wl->window); wl2->flags |= wl->flags & WINLINK_ALERTFLAGS; } diff --git a/tmux.h b/tmux.h index f6a45d33..a1e31e32 100644 --- a/tmux.h +++ b/tmux.h @@ -1828,7 +1828,8 @@ struct winlink *winlink_find_by_index(struct winlinks *, int); struct winlink *winlink_find_by_window(struct winlinks *, struct window *); int winlink_next_index(struct winlinks *, int); u_int winlink_count(struct winlinks *); -struct winlink *winlink_add(struct winlinks *, struct window *, int); +struct winlink *winlink_add(struct winlinks *, int); +void winlink_set_window(struct winlink *, struct window *); void winlink_remove(struct winlinks *, struct winlink *); struct winlink *winlink_next(struct winlink *); struct winlink *winlink_previous(struct winlink *); diff --git a/window.c b/window.c index f965d27f..2d332c40 100644 --- a/window.c +++ b/window.c @@ -123,7 +123,7 @@ winlink_count(struct winlinks *wwl) } struct winlink * -winlink_add(struct winlinks *wwl, struct window *w, int idx) +winlink_add(struct winlinks *wwl, int idx) { struct winlink *wl; @@ -135,14 +135,18 @@ winlink_add(struct winlinks *wwl, struct window *w, int idx) wl = xcalloc(1, sizeof *wl); wl->idx = idx; - wl->window = w; RB_INSERT(winlinks, wwl, wl); - w->references++; - return (wl); } +void +winlink_set_window(struct winlink *wl, struct window *w) +{ + wl->window = w; + w->references++; +} + void winlink_remove(struct winlinks *wwl, struct winlink *wl) { @@ -153,11 +157,13 @@ winlink_remove(struct winlinks *wwl, struct winlink *wl) xfree(wl->status_text); xfree(wl); - if (w->references == 0) - fatal("bad reference count"); - w->references--; - if (w->references == 0) - window_destroy(w); + if (w != NULL) { + if (w->references == 0) + fatal("bad reference count"); + w->references--; + if (w->references == 0) + window_destroy(w); + } } struct winlink * From ecc22c521d83f8ce480c0e2866fdf3ed14bd6131 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 25 Jan 2011 23:40:26 +0000 Subject: [PATCH 0852/1180] When clearing the entire screen, clear lines that are used into the history like xterm does. Requested ages ago by someone I've forgotten. --- grid-view.c | 24 ++++++++++++++++++++++++ screen-write.c | 19 +++++++++++++++---- tmux.h | 1 + 3 files changed, 40 insertions(+), 4 deletions(-) diff --git a/grid-view.c b/grid-view.c index ba142a1c..075feb6b 100644 --- a/grid-view.c +++ b/grid-view.c @@ -74,6 +74,30 @@ grid_view_set_utf8( grid_set_utf8(gd, grid_view_x(gd, px), grid_view_y(gd, py), gu); } +/* Clear into history. */ +void +grid_view_clear_history(struct grid *gd) +{ + struct grid_line *gl; + u_int yy, last; + + GRID_DEBUG(gd, ""); + + /* Find the last used line. */ + last = 0; + for (yy = 0; yy < gd->sy; yy++) { + gl = &gd->linedata[grid_view_y(gd, yy)]; + if (gl->cellsize != 0 || gl->utf8size != 0) + last = yy + 1; + } + if (last == 0) + return; + + /* Scroll the lines into the history. */ + for (yy = 0; yy < last; yy++) + grid_scroll_history(gd); +} + /* Clear area. */ void grid_view_clear(struct grid *gd, u_int px, u_int py, u_int nx, u_int ny) diff --git a/screen-write.c b/screen-write.c index 88c183ae..4c8382de 100644 --- a/screen-write.c +++ b/screen-write.c @@ -931,9 +931,14 @@ screen_write_clearendofscreen(struct screen_write_ctx *ctx) sx = screen_size_x(s); sy = screen_size_y(s); - if (s->cx <= sx - 1) - grid_view_clear(s->grid, s->cx, s->cy, sx - s->cx, 1); - grid_view_clear(s->grid, 0, s->cy + 1, sx, sy - (s->cy + 1)); + /* Scroll into history if it is enabled and clearing entire screen. */ + if (s->cy == 0 && s->grid->flags & GRID_HISTORY) + grid_view_clear_history(s->grid); + else { + if (s->cx <= sx - 1) + grid_view_clear(s->grid, s->cx, s->cy, sx - s->cx, 1); + grid_view_clear(s->grid, 0, s->cy + 1, sx, sy - (s->cy + 1)); + } tty_write(tty_cmd_clearendofscreen, &ttyctx); } @@ -969,7 +974,13 @@ screen_write_clearscreen(struct screen_write_ctx *ctx) screen_write_initctx(ctx, &ttyctx, 0); - grid_view_clear(s->grid, 0, 0, screen_size_x(s), screen_size_y(s)); + /* Scroll into history if it is enabled. */ + if (s->grid->flags & GRID_HISTORY) + grid_view_clear_history(s->grid); + else { + grid_view_clear( + s->grid, 0, 0, screen_size_x(s), screen_size_y(s)); + } tty_write(tty_cmd_clearscreen, &ttyctx); } diff --git a/tmux.h b/tmux.h index a1e31e32..89cf2b99 100644 --- a/tmux.h +++ b/tmux.h @@ -1741,6 +1741,7 @@ const struct grid_utf8 *grid_view_peek_utf8(struct grid *, u_int, u_int); struct grid_utf8 *grid_view_get_utf8(struct grid *, u_int, u_int); void grid_view_set_utf8( struct grid *, u_int, u_int, const struct grid_utf8 *); +void grid_view_clear_history(struct grid *); void grid_view_clear(struct grid *, u_int, u_int, u_int, u_int); void grid_view_scroll_region_up(struct grid *, u_int, u_int); void grid_view_scroll_region_down(struct grid *, u_int, u_int); From 4dfb29fa38a22615eda253b1124261379f6fbbcc Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 26 Jan 2011 00:11:47 +0000 Subject: [PATCH 0853/1180] Use LIST_* not SLIST_*. --- cmd-server-info.c | 4 ++-- job.c | 6 +++--- server.c | 2 +- tmux.h | 8 ++++---- tty-term.c | 8 ++++---- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/cmd-server-info.c b/cmd-server-info.c index 2eaf142f..5e95757d 100644 --- a/cmd-server-info.c +++ b/cmd-server-info.c @@ -142,7 +142,7 @@ cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx) ctx->print(ctx, "%s", ""); ctx->print(ctx, "Terminals:"); - SLIST_FOREACH(term, &tty_terms, entry) { + LIST_FOREACH(term, &tty_terms, entry) { ctx->print(ctx, "%s [references=%u, flags=0x%x]:", term->name, term->references, term->flags); for (i = 0; i < NTTYCODE; i++) { @@ -174,7 +174,7 @@ cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx) ctx->print(ctx, "%s", ""); ctx->print(ctx, "Jobs:"); - SLIST_FOREACH(job, &all_jobs, lentry) { + LIST_FOREACH(job, &all_jobs, lentry) { ctx->print(ctx, "%s [fd=%d, pid=%d, status=%d, flags=0x%x]", job->cmd, job->fd, job->pid, job->status, job->flags); } diff --git a/job.c b/job.c index ce7961a1..43eb254a 100644 --- a/job.c +++ b/job.c @@ -32,7 +32,7 @@ */ /* All jobs list. */ -struct joblist all_jobs = SLIST_HEAD_INITIALIZER(all_jobs); +struct joblist all_jobs = LIST_HEAD_INITIALIZER(all_jobs); RB_GENERATE(jobs, job, entry, job_cmp); @@ -99,7 +99,7 @@ job_add(struct jobs *jobs, int flags, struct client *c, const char *cmd, if (jobs != NULL) RB_INSERT(jobs, jobs, job); - SLIST_INSERT_HEAD(&all_jobs, job, lentry); + LIST_INSERT_HEAD(&all_jobs, job, lentry); return (job); } @@ -119,7 +119,7 @@ job_free(struct job *job) { job_kill(job); - SLIST_REMOVE(&all_jobs, job, job, lentry); + LIST_REMOVE(job, lentry); xfree(job->cmd); if (job->freefn != NULL && job->data != NULL) diff --git a/server.c b/server.c index 8f6ee149..72f3880d 100644 --- a/server.c +++ b/server.c @@ -415,7 +415,7 @@ server_child_exited(pid_t pid, int status) } } - SLIST_FOREACH(job, &all_jobs, lentry) { + LIST_FOREACH(job, &all_jobs, lentry) { if (pid == job->pid) { job_died(job, status); /* might free job */ break; diff --git a/tmux.h b/tmux.h index 89cf2b99..ff87f502 100644 --- a/tmux.h +++ b/tmux.h @@ -684,10 +684,10 @@ struct job { #define JOB_PERSIST 0x1 /* don't free after callback */ RB_ENTRY(job) entry; - SLIST_ENTRY(job) lentry; + LIST_ENTRY(job) lentry; }; RB_HEAD(jobs, job); -SLIST_HEAD(joblist, job); +LIST_HEAD(joblist, job); /* Screen selection. */ struct screen_sel { @@ -990,9 +990,9 @@ struct tty_term { #define TERM_EARLYWRAP 0x4 int flags; - SLIST_ENTRY(tty_term) entry; + LIST_ENTRY(tty_term) entry; }; -SLIST_HEAD(tty_terms, tty_term); +LIST_HEAD(tty_terms, tty_term); struct tty { char *path; diff --git a/tty-term.c b/tty-term.c index efc962ec..943f1e4d 100644 --- a/tty-term.c +++ b/tty-term.c @@ -30,7 +30,7 @@ void tty_term_override(struct tty_term *, const char *); char *tty_term_strip(const char *); -struct tty_terms tty_terms = SLIST_HEAD_INITIALIZER(tty_terms); +struct tty_terms tty_terms = LIST_HEAD_INITIALIZER(tty_terms); const struct tty_term_code_entry tty_term_codes[NTTYCODE] = { { TTYC_ACSC, TTYCODE_STRING, "acsc" }, @@ -305,7 +305,7 @@ tty_term_find(char *name, int fd, const char *overrides, char **cause) char *s; const char *acs; - SLIST_FOREACH(term, &tty_terms, entry) { + LIST_FOREACH(term, &tty_terms, entry) { if (strcmp(term->name, name) == 0) { term->references++; return (term); @@ -318,7 +318,7 @@ tty_term_find(char *name, int fd, const char *overrides, char **cause) term->references = 1; term->flags = 0; memset(term->codes, 0, sizeof term->codes); - SLIST_INSERT_HEAD(&tty_terms, term, entry); + LIST_INSERT_HEAD(&tty_terms, term, entry); /* Set up curses terminal. */ if (setupterm(name, fd, &error) != OK) { @@ -437,7 +437,7 @@ tty_term_free(struct tty_term *term) if (--term->references != 0) return; - SLIST_REMOVE(&tty_terms, term, tty_term, entry); + LIST_REMOVE(term, entry); for (i = 0; i < NTTYCODE; i++) { if (term->codes[i].type == TTYCODE_STRING) From db7a89b1ee4c11006cdf607465b6c0fc13333fd1 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 26 Jan 2011 01:54:56 +0000 Subject: [PATCH 0854/1180] Simplify the way jobs work and drop the persist type, so all jobs are fire-and-forget. Status jobs now managed with two trees of output (new and old), rather than storing the output in the jobs themselves. When the status line is processed any jobs which don't appear in the new tree are started and the output from the old tree displayed. When a job finishes it updates the new tree with its output and that is used for any subsequent redraws. When the status interval expires, the new tree is moved to the old so that all jobs are run again. This fixes the "#(echo %H:%M:%S)" problem which would lead to thousands of identical persistent jobs and high memory use (this can still be achieved by adding "sleep 30" but that is much less likely to happen by accident). --- cmd-if-shell.c | 6 +- cmd-run-shell.c | 6 +- cmd-server-info.c | 4 +- cmd-set-option.c | 23 +---- job.c | 209 +++++++++++++++------------------------------- server-client.c | 10 +-- status.c | 124 ++++++++++++++++++++------- tmux.h | 33 ++++---- 8 files changed, 193 insertions(+), 222 deletions(-) diff --git a/cmd-if-shell.c b/cmd-if-shell.c index b7671332..b81985f8 100644 --- a/cmd-if-shell.c +++ b/cmd-if-shell.c @@ -53,7 +53,7 @@ cmd_if_shell_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; struct cmd_if_shell_data *cdata; - struct job *job; + const char *shellcmd = args->argv[0]; cdata = xmalloc(sizeof *cdata); cdata->cmd = xstrdup(args->argv[1]); @@ -64,9 +64,7 @@ cmd_if_shell_exec(struct cmd *self, struct cmd_ctx *ctx) if (ctx->curclient != NULL) ctx->curclient->references++; - job = job_add(NULL, 0, NULL, - args->argv[0], cmd_if_shell_callback, cmd_if_shell_free, cdata); - job_run(job); + job_run(shellcmd, cmd_if_shell_callback, cmd_if_shell_free, cdata); return (1); /* don't let client exit */ } diff --git a/cmd-run-shell.c b/cmd-run-shell.c index 189eeac9..85cd1e29 100644 --- a/cmd-run-shell.c +++ b/cmd-run-shell.c @@ -53,7 +53,7 @@ cmd_run_shell_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; struct cmd_run_shell_data *cdata; - struct job *job; + const char *shellcmd = args->argv[0]; cdata = xmalloc(sizeof *cdata); cdata->cmd = xstrdup(args->argv[0]); @@ -64,9 +64,7 @@ cmd_run_shell_exec(struct cmd *self, struct cmd_ctx *ctx) if (ctx->curclient != NULL) ctx->curclient->references++; - job = job_add(NULL, 0, NULL, - args->argv[0], cmd_run_shell_callback, cmd_run_shell_free, cdata); - job_run(job); + job_run(shellcmd, cmd_run_shell_callback, cmd_run_shell_free, cdata); return (1); /* don't let client exit */ } diff --git a/cmd-server-info.c b/cmd-server-info.c index 5e95757d..3edb9d2b 100644 --- a/cmd-server-info.c +++ b/cmd-server-info.c @@ -175,8 +175,8 @@ cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx) ctx->print(ctx, "Jobs:"); LIST_FOREACH(job, &all_jobs, lentry) { - ctx->print(ctx, "%s [fd=%d, pid=%d, status=%d, flags=0x%x]", - job->cmd, job->fd, job->pid, job->status, job->flags); + ctx->print(ctx, "%s [fd=%d, pid=%d, status=%d]", + job->cmd, job->fd, job->pid, job->status); } return (0); diff --git a/cmd-set-option.c b/cmd-set-option.c index 436e529e..2155bba0 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -87,11 +87,8 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) struct winlink *wl; struct client *c; struct options *oo; - struct jobs *jobs; - struct job *job, *nextjob; const char *optstr, *valstr; u_int i; - int try_again; /* Work out the options tree and table to use. */ if (args_has(self->args, 's')) { @@ -181,24 +178,8 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) strcmp(oe->name, "window-status-format") == 0) { for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); - if (c == NULL || c->session == NULL) - continue; - - jobs = &c->status_jobs; - do { - try_again = 0; - job = RB_ROOT(jobs); - while (job != NULL) { - nextjob = RB_NEXT(jobs, jobs, job); - if (job->flags & JOB_PERSIST) { - job_remove(jobs, job); - try_again = 1; - break; - } - job = nextjob; - } - } while (try_again); - server_redraw_client(c); + if (c != NULL && c->session != NULL) + server_redraw_client(c); } } diff --git a/job.c b/job.c index 43eb254a..b167d456 100644 --- a/job.c +++ b/job.c @@ -31,129 +31,32 @@ * output. */ +void job_callback(struct bufferevent *, short, void *); + /* All jobs list. */ struct joblist all_jobs = LIST_HEAD_INITIALIZER(all_jobs); -RB_GENERATE(jobs, job, entry, job_cmp); - -void job_callback(struct bufferevent *, short, void *); - -int -job_cmp(struct job *job1, struct job *job2) -{ - return (strcmp(job1->cmd, job2->cmd)); -} - -/* Initialise job tree. */ -void -job_tree_init(struct jobs *jobs) -{ - RB_INIT(jobs); -} - -/* Destroy a job tree. */ -void -job_tree_free(struct jobs *jobs) -{ - struct job *job; - - while (!RB_EMPTY(jobs)) { - job = RB_ROOT(jobs); - RB_REMOVE(jobs, jobs, job); - job_free(job); - } -} - -/* Find a job and return it. */ +/* Start a job running, if it isn't already. */ struct job * -job_get(struct jobs *jobs, const char *cmd) -{ - struct job job; - - job.cmd = (char *) cmd; - return (RB_FIND(jobs, jobs, &job)); -} - -/* Add a job. */ -struct job * -job_add(struct jobs *jobs, int flags, struct client *c, const char *cmd, +job_run(const char *cmd, void (*callbackfn)(struct job *), void (*freefn)(void *), void *data) { struct job *job; - - job = xmalloc(sizeof *job); - job->cmd = xstrdup(cmd); - job->pid = -1; - job->status = 0; - - job->client = c; - - job->fd = -1; - job->event = NULL; - - job->callbackfn = callbackfn; - job->freefn = freefn; - job->data = data; - - job->flags = flags; - - if (jobs != NULL) - RB_INSERT(jobs, jobs, job); - LIST_INSERT_HEAD(&all_jobs, job, lentry); - - return (job); -} - -/* Remove job from tree and free. */ -void -job_remove(struct jobs *jobs, struct job *job) -{ - if (jobs != NULL) - RB_REMOVE(jobs, jobs, job); - job_free(job); -} - -/* Kill and free an individual job. */ -void -job_free(struct job *job) -{ - job_kill(job); - - LIST_REMOVE(job, lentry); - xfree(job->cmd); - - if (job->freefn != NULL && job->data != NULL) - job->freefn(job->data); - - if (job->fd != -1) - close(job->fd); - if (job->event != NULL) - bufferevent_free(job->event); - - xfree(job); -} - -/* Start a job running, if it isn't already. */ -int -job_run(struct job *job) -{ - struct environ env; - int nullfd, out[2]; - - if (job->fd != -1 || job->pid != -1) - return (0); + struct environ env; + pid_t pid; + int nullfd, out[2]; if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, out) != 0) - return (-1); + return (NULL); environ_init(&env); environ_copy(&global_environ, &env); server_fill_environ(NULL, &env); - switch (job->pid = fork()) { + switch (pid = fork()) { case -1: environ_free(&env); - return (-1); + return (NULL); case 0: /* child */ clear_signals(1); @@ -178,23 +81,55 @@ job_run(struct job *job) closefrom(STDERR_FILENO + 1); - execl(_PATH_BSHELL, "sh", "-c", job->cmd, (char *) NULL); + execl(_PATH_BSHELL, "sh", "-c", cmd, (char *) NULL); fatal("execl failed"); - default: /* parent */ - environ_free(&env); - close(out[1]); - - job->fd = out[0]; - setblocking(job->fd, 0); - - if (job->event != NULL) - bufferevent_free(job->event); - job->event = - bufferevent_new(job->fd, NULL, NULL, job_callback, job); - bufferevent_enable(job->event, EV_READ); - - return (0); } + + /* parent */ + environ_free(&env); + close(out[1]); + + job = xmalloc(sizeof *job); + job->cmd = xstrdup(cmd); + job->pid = pid; + job->status = 0; + + LIST_INSERT_HEAD(&all_jobs, job, lentry); + + job->callbackfn = callbackfn; + job->freefn = freefn; + job->data = data; + + job->fd = out[0]; + setblocking(job->fd, 0); + + job->event = bufferevent_new(job->fd, NULL, NULL, job_callback, job); + bufferevent_enable(job->event, EV_READ); + + log_debug("run job %p: %s, pid %ld", job, job->cmd, (long) job->pid); + return (job); +} + +/* Kill and free an individual job. */ +void +job_free(struct job *job) +{ + log_debug("free job %p: %s", job, job->cmd); + + LIST_REMOVE(job, lentry); + xfree(job->cmd); + + if (job->freefn != NULL && job->data != NULL) + job->freefn(job->data); + + if (job->pid != -1) + kill(job->pid, SIGTERM); + if (job->fd != -1) + close(job->fd); + if (job->event != NULL) + bufferevent_free(job->event); + + xfree(job); } /* Job buffer error callback. */ @@ -204,15 +139,16 @@ job_callback(unused struct bufferevent *bufev, unused short events, void *data) { struct job *job = data; - bufferevent_disable(job->event, EV_READ); - close(job->fd); - job->fd = -1; + log_debug("job error %p: %s, pid %ld", job, job->cmd, (long) job->pid); if (job->pid == -1) { if (job->callbackfn != NULL) job->callbackfn(job); - if ((!job->flags & JOB_PERSIST)) - job_free(job); + job_free(job); + } else { + bufferevent_disable(job->event, EV_READ); + close(job->fd); + job->fd = -1; } } @@ -220,23 +156,14 @@ job_callback(unused struct bufferevent *bufev, unused short events, void *data) void job_died(struct job *job, int status) { + log_debug("job died %p: %s, pid %ld", job, job->cmd, (long) job->pid); + job->status = status; - job->pid = -1; if (job->fd == -1) { if (job->callbackfn != NULL) job->callbackfn(job); - if ((!job->flags & JOB_PERSIST)) - job_free(job); - } -} - -/* Kill a job. */ -void -job_kill(struct job *job) -{ - if (job->pid == -1) - return; - kill(job->pid, SIGTERM); - job->pid = -1; + job_free(job); + } else + job->pid = -1; } diff --git a/server-client.c b/server-client.c index 9b83fe13..2b67ef5d 100644 --- a/server-client.c +++ b/server-client.c @@ -79,7 +79,8 @@ server_client_create(int fd) c->tty.sy = 24; screen_init(&c->status, c->tty.sx, 1, 0); - job_tree_init(&c->status_jobs); + RB_INIT(&c->status_new); + RB_INIT(&c->status_old); c->message_string = NULL; ARRAY_INIT(&c->message_log); @@ -139,8 +140,9 @@ server_client_lost(struct client *c) if (c->stderr_event != NULL) bufferevent_free(c->stderr_event); + status_free_jobs(&c->status_new); + status_free_jobs(&c->status_old); screen_free(&c->status); - job_tree_free(&c->status_jobs); if (c->title != NULL) xfree(c->title); @@ -221,7 +223,6 @@ server_client_status_timer(void) { struct client *c; struct session *s; - struct job *job; struct timeval tv; u_int i; int interval; @@ -250,8 +251,7 @@ server_client_status_timer(void) difference = tv.tv_sec - c->status_timer.tv_sec; if (difference >= interval) { - RB_FOREACH(job, jobs, &c->status_jobs) - job_run(job); + status_update_jobs(c); c->flags |= CLIENT_STATUS; } } diff --git a/status.c b/status.c index c23f9ac3..60442fce 100644 --- a/status.c +++ b/status.c @@ -33,7 +33,8 @@ char *status_redraw_get_left( struct client *, time_t, int, struct grid_cell *, size_t *); char *status_redraw_get_right( struct client *, time_t, int, struct grid_cell *, size_t *); -char *status_job(struct client *, char **); +char *status_find_job(struct client *, char **); +void status_job_free(void *); void status_job_callback(struct job *); char *status_print( struct client *, struct winlink *, time_t, struct grid_cell *); @@ -49,6 +50,16 @@ char *status_prompt_complete(const char *); /* Status prompt history. */ ARRAY_DECL(, char *) status_prompt_history = ARRAY_INITIALIZER; +/* Status output tree. */ +RB_GENERATE(status_out_tree, status_out, entry, status_out_cmp); + +/* Output tree comparison function. */ +int +status_out_cmp(struct status_out *so1, struct status_out *so2) +{ + return (strcmp(so1->cmd, so2->cmd)); +} + /* Retrieve options for left string. */ char * status_redraw_get_left(struct client *c, @@ -365,9 +376,8 @@ status_replace1(struct client *c,struct winlink *wl, ch = ')'; goto skip_to; } - if ((ptr = status_job(c, iptr)) == NULL) + if ((ptr = status_find_job(c, iptr)) == NULL) return; - freeptr = ptr; goto do_replace; case 'H': if (gethostname(tmp, sizeof tmp) != 0) @@ -469,12 +479,12 @@ status_replace(struct client *c, /* Figure out job name and get its result, starting it off if necessary. */ char * -status_job(struct client *c, char **iptr) +status_find_job(struct client *c, char **iptr) { - struct job *job; - char *cmd; - int lastesc; - size_t len; + struct status_out *so, so_find; + char *cmd; + int lastesc; + size_t len; if (**iptr == '\0') return (NULL); @@ -504,24 +514,88 @@ status_job(struct client *c, char **iptr) (*iptr)++; /* skip final ) */ cmd[len] = '\0'; - job = job_get(&c->status_jobs, cmd); - if (job == NULL) { - job = job_add(&c->status_jobs, - JOB_PERSIST, c, cmd, status_job_callback, xfree, NULL); - job_run(job); + /* First try in the new tree. */ + so_find.cmd = cmd; + so = RB_FIND(status_out_tree, &c->status_new, &so_find); + if (so != NULL && so->out != NULL) + return (so->out); + + /* If not found at all, start the job and add to the tree. */ + if (so == NULL) { + job_run(cmd, status_job_callback, status_job_free, c); + c->references++; + + so = xmalloc(sizeof *so); + so->cmd = xstrdup(cmd); + so->out = NULL; + RB_INSERT(status_out_tree, &c->status_new, so); } + + /* Lookup in the old tree. */ + so_find.cmd = cmd; + so = RB_FIND(status_out_tree, &c->status_old, &so_find); xfree(cmd); - if (job->data == NULL) - return (xstrdup("")); - return (xstrdup(job->data)); + if (so != NULL) + return (so->out); + return (NULL); +} + +/* Free job tree. */ +void +status_free_jobs(struct status_out_tree *sotree) +{ + struct status_out *so, *so_next; + + so_next = RB_MIN(status_out_tree, sotree); + while (so_next != NULL) { + so = so_next; + so_next = RB_NEXT(status_out_tree, sotree, so); + + RB_REMOVE(status_out_tree, sotree, so); + if (so->out != NULL) + xfree(so->out); + xfree(so->cmd); + xfree(so); + } +} + +/* Update jobs on status interval. */ +void +status_update_jobs(struct client *c) +{ + /* Free the old tree. */ + status_free_jobs(&c->status_old); + + /* Move the new to old. */ + memcpy(&c->status_old, &c->status_new, sizeof c->status_old); + RB_INIT(&c->status_new); +} + +/* Free status job. */ +void +status_job_free(void *data) +{ + struct client *c = data; + + c->references--; } /* Job has finished: save its result. */ void status_job_callback(struct job *job) { - char *line, *buf; - size_t len; + struct client *c = job->data; + struct status_out *so, so_find; + char *line, *buf; + size_t len; + + if (c->flags & CLIENT_DEAD) + return; + + so_find.cmd = job->cmd; + so = RB_FIND(status_out_tree, &c->status_new, &so_find); + if (so == NULL || so->out != NULL) + return; buf = NULL; if ((line = evbuffer_readline(job->event->input)) == NULL) { @@ -530,17 +604,11 @@ status_job_callback(struct job *job) if (len != 0) memcpy(buf, EVBUFFER_DATA(job->event->input), len); buf[len] = '\0'; - } + } else + buf = xstrdup(line); - if (job->data != NULL) - xfree(job->data); - else - server_redraw_client(job->client); - - if (line == NULL) - job->data = buf; - else - job->data = xstrdup(line); + so->out = buf; + server_redraw_client(c); } /* Return winlink status line entry and adjust gc as necessary. */ diff --git a/tmux.h b/tmux.h index ff87f502..5ac3c172 100644 --- a/tmux.h +++ b/tmux.h @@ -671,8 +671,6 @@ struct job { pid_t pid; int status; - struct client *client; - int fd; struct bufferevent *event; @@ -680,13 +678,8 @@ struct job { void (*freefn)(void *); void *data; - int flags; -#define JOB_PERSIST 0x1 /* don't free after callback */ - - RB_ENTRY(job) entry; LIST_ENTRY(job) lentry; }; -RB_HEAD(jobs, job); LIST_HEAD(joblist, job); /* Screen selection. */ @@ -1091,6 +1084,15 @@ struct message_entry { time_t msg_time; }; +/* Status output data from a job. */ +struct status_out { + char *cmd; + char *out; + + RB_ENTRY(status_out) entry; +}; +RB_HEAD(status_out_tree, status_out); + /* Client connection. */ struct client { struct imsgbuf ibuf; @@ -1120,8 +1122,9 @@ struct client { struct event repeat_timer; + struct status_out_tree status_old; + struct status_out_tree status_new; struct timeval status_timer; - struct jobs status_jobs; struct screen status; #define CLIENT_TERMINAL 0x1 @@ -1363,18 +1366,10 @@ const char *options_table_print_entry( /* job.c */ extern struct joblist all_jobs; -int job_cmp(struct job *, struct job *); -RB_PROTOTYPE(jobs, job, entry, job_cmp); -void job_tree_init(struct jobs *); -void job_tree_free(struct jobs *); -struct job *job_get(struct jobs *, const char *); -struct job *job_add(struct jobs *, int, struct client *, +struct job *job_run( const char *, void (*)(struct job *), void (*)(void *), void *); -void job_remove(struct jobs *, struct job *); void job_free(struct job *); -int job_run(struct job *); void job_died(struct job *, int); -void job_kill(struct job *); /* environ.c */ int environ_cmp(struct environ_entry *, struct environ_entry *); @@ -1660,6 +1655,10 @@ void server_clear_identify(struct client *); void server_update_event(struct client *); /* status.c */ +int status_out_cmp(struct status_out *, struct status_out *); +RB_PROTOTYPE(status_out_tree, status_out, entry, status_out_cmp); +void status_free_jobs(struct status_out_tree *); +void status_update_jobs(struct client *); int status_redraw(struct client *); char *status_replace( struct client *, struct winlink *, const char *, time_t, int); From bcc7c689c163173086882fdd1f069b0da9bb53f6 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 26 Jan 2011 02:55:34 +0000 Subject: [PATCH 0855/1180] Unused declaration. --- server-window.c | 1 - 1 file changed, 1 deletion(-) diff --git a/server-window.c b/server-window.c index d415e0d7..b081355c 100644 --- a/server-window.c +++ b/server-window.c @@ -23,7 +23,6 @@ #include "tmux.h" -int server_window_backoff(struct window_pane *); int server_window_check_bell(struct session *, struct winlink *); int server_window_check_activity(struct session *, struct winlink *); int server_window_check_silence(struct session *, struct winlink *); From b6bb350289f9eec1c6486ef356033e6f2b542ad0 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 28 Jan 2011 20:39:22 +0000 Subject: [PATCH 0856/1180] Use input_clear to reset the APC, DCS, OSC state or it could be reused improperly by a later state. From Kevin Goodsell. --- input.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/input.c b/input.c index df387dad..73e02099 100644 --- a/input.c +++ b/input.c @@ -812,6 +812,9 @@ input_clear(struct input_ctx *ictx) *ictx->param_buf = '\0'; ictx->param_len = 0; + *ictx->input_buf = '\0'; + ictx->input_len = 0; + ictx->flags &= ~INPUT_DISCARD; } @@ -1394,7 +1397,7 @@ input_enter_dcs(struct input_ctx *ictx) { log_debug("%s", __func__); - ictx->input_len = 0; + input_clear(ictx); } /* DCS terminator (ST) received. */ @@ -1410,7 +1413,7 @@ input_enter_osc(struct input_ctx *ictx) { log_debug("%s", __func__); - ictx->input_len = 0; + input_clear(ictx); } /* OSC terminator (ST) received. */ @@ -1436,7 +1439,7 @@ input_enter_apc(struct input_ctx *ictx) { log_debug("%s", __func__); - ictx->input_len = 0; + input_clear(ictx); } /* APC terminator (ST) received. */ @@ -1457,7 +1460,7 @@ input_enter_rename(struct input_ctx *ictx) { log_debug("%s", __func__); - ictx->input_len = 0; + input_clear(ictx); } /* Rename terminator (ST) received. */ From 9fc2c34a3b794b6724c1e3fc96f55ee199286c44 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 29 Jan 2011 08:39:43 +0000 Subject: [PATCH 0857/1180] Accept tcgetattr/tcsetattr failure, fixes problems with fatal() if the terminal disappears while locked. --- tty.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/tty.c b/tty.c index 497dacc6..b44c5974 100644 --- a/tty.c +++ b/tty.c @@ -166,15 +166,13 @@ tty_start_tty(struct tty *tty) { struct termios tio; - if (tty->fd == -1) + if (tty->fd == -1 || tcgetattr(tty->fd, &tty->tio) != 0) return; setblocking(tty->fd, 0); bufferevent_enable(tty->event, EV_READ|EV_WRITE); - if (tcgetattr(tty->fd, &tty->tio) != 0) - fatal("tcgetattr failed"); memcpy(&tio, &tty->tio, sizeof tio); tio.c_iflag &= ~(IXON|IXOFF|ICRNL|INLCR|IGNCR|IMAXBEL|ISTRIP); tio.c_iflag |= IGNBRK; @@ -183,9 +181,8 @@ tty_start_tty(struct tty *tty) ECHOPRT|ECHOKE|ECHOCTL|ISIG); tio.c_cc[VMIN] = 1; tio.c_cc[VTIME] = 0; - if (tcsetattr(tty->fd, TCSANOW, &tio) != 0) - fatal("tcsetattr failed"); - tcflush(tty->fd, TCIOFLUSH); + if (tcsetattr(tty->fd, TCSANOW, &tio) == 0) + tcflush(tty->fd, TCIOFLUSH); tty_putcode(tty, TTYC_SMCUP); From 567741caf57749205d9c190a901430541e5b1fdf Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 30 Jan 2011 12:09:30 +0000 Subject: [PATCH 0858/1180] Free old argument even if setting to NULL. --- arguments.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/arguments.c b/arguments.c index ebd09580..97ffec13 100644 --- a/arguments.c +++ b/arguments.c @@ -183,11 +183,12 @@ args_has(struct args *args, u_char ch) void args_set(struct args *args, u_char ch, const char *value) { - if (value != NULL) { - if (args->values[ch] != NULL) - xfree(args->values[ch]); + if (args->values[ch] != NULL) + xfree(args->values[ch]); + if (value != NULL) args->values[ch] = xstrdup(value); - } + else + args->values[ch] = NULL; bit_set(args->flags, ch); } From 7462c03281718a0a9947b6e7cddc29a1393bfdac Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 31 Jan 2011 20:54:42 +0000 Subject: [PATCH 0859/1180] Redraw pane borders when switching to last pane. --- cmd-select-pane.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cmd-select-pane.c b/cmd-select-pane.c index 9aed0a92..0dd847d6 100644 --- a/cmd-select-pane.c +++ b/cmd-select-pane.c @@ -79,7 +79,11 @@ cmd_select_pane_exec(struct cmd *self, struct cmd_ctx *ctx) ctx->error(ctx, "no last pane"); return (-1); } + window_set_active_pane(wl->window, wl->window->last); + server_status_window(wl->window); + server_redraw_window_borders(wl->window); + return (0); } From 8ec3e5725cd4b64b05223e885b2b4d5618bf46da Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 3 Feb 2011 20:50:03 +0000 Subject: [PATCH 0860/1180] Don't require -d with -x or -y since it could be in the config file. --- cmd-new-session.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/cmd-new-session.c b/cmd-new-session.c index 1aa1c087..f5e1316f 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -49,9 +49,6 @@ cmd_new_session_check(struct args *args) { if (args_has(args, 't') && (args->argc != 0 || args_has(args, 'n'))) return (-1); - if (!args_has(args, 'd') && - (args_has(args, 'x') || args_has(args, 'y'))) - return (-1); return (0); } From ce91520e12d1f7460fb52df27b38a3e2937e325f Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 10 Feb 2011 12:12:14 +0000 Subject: [PATCH 0861/1180] Size on split-window is -l not -s. Doh. --- cmd-split-window.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd-split-window.c b/cmd-split-window.c index b7be4078..e34645a4 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -91,8 +91,8 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) type = LAYOUT_LEFTRIGHT; size = -1; - if (args_has(args, 's')) { - size = args_strtonum(args, 's', 0, INT_MAX, &cause); + if (args_has(args, 'l')) { + size = args_strtonum(args, 'l', 0, INT_MAX, &cause); if (cause != NULL) { ctx->error(ctx, "size %s", cause); xfree(cause); From 7954126dcd6ec52020fde92c8be997482fa55ab6 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 3 Mar 2011 08:51:47 +0000 Subject: [PATCH 0862/1180] Add a -P option to detach to HUP the client's parent process (usually causing it to exit as well). --- client.c | 19 ++++++++++++++++--- cmd-detach-client.c | 9 ++++++--- tmux.1 | 9 ++++++++- tmux.h | 1 + 4 files changed, 31 insertions(+), 7 deletions(-) diff --git a/client.c b/client.c index 1ff3e1f1..eea45177 100644 --- a/client.c +++ b/client.c @@ -36,6 +36,7 @@ struct imsgbuf client_ibuf; struct event client_event; const char *client_exitmsg; int client_exitval; +enum msgtype client_exittype; int client_attached; int client_connect(char *, int); @@ -100,6 +101,7 @@ client_main(int argc, char **argv, int flags) struct cmd_list *cmdlist; struct msg_command_data cmddata; int cmdflags, fd; + pid_t ppid; enum msgtype msg; char *cause; @@ -192,8 +194,14 @@ client_main(int argc, char **argv, int flags) event_dispatch(); /* Print the exit message, if any, and exit. */ - if (client_attached && client_exitmsg != NULL && !login_shell) - printf("[%s]\n", client_exitmsg); + if (client_attached) { + if (client_exitmsg != NULL && !login_shell) + printf("[%s]\n", client_exitmsg); + + ppid = getppid(); + if (client_exittype == MSG_DETACHKILL && ppid > 1) + kill(ppid, SIGHUP); + } return (client_exitval); } @@ -434,12 +442,17 @@ client_dispatch_attached(void) log_debug("client got %d", imsg.hdr.type); switch (imsg.hdr.type) { + case MSG_DETACHKILL: case MSG_DETACH: if (datalen != 0) fatalx("bad MSG_DETACH size"); + client_exittype = imsg.hdr.type; + if (imsg.hdr.type == MSG_DETACHKILL) + client_exitmsg = "detached and SIGHUP"; + else + client_exitmsg = "detached"; client_write_server(MSG_EXITING, NULL, 0); - client_exitmsg = "detached"; break; case MSG_EXIT: if (datalen != 0 && diff --git a/cmd-detach-client.c b/cmd-detach-client.c index 03789bd8..12723ac4 100644 --- a/cmd-detach-client.c +++ b/cmd-detach-client.c @@ -28,8 +28,8 @@ int cmd_detach_client_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_detach_client_entry = { "detach-client", "detach", - "t:", 0, 0, - CMD_TARGET_CLIENT_USAGE, + "t:P", 0, 0, + "[-P] " CMD_TARGET_CLIENT_USAGE, CMD_READONLY, NULL, NULL, @@ -45,7 +45,10 @@ cmd_detach_client_exec(struct cmd *self, struct cmd_ctx *ctx) if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL) return (-1); - server_write_client(c, MSG_DETACH, NULL, 0); + if (args_has(args, 'P')) + server_write_client(c, MSG_DETACHKILL, NULL, 0); + else + server_write_client(c, MSG_DETACH, NULL, 0); return (0); } diff --git a/tmux.1 b/tmux.1 index 36253d17..7d42984a 100644 --- a/tmux.1 +++ b/tmux.1 @@ -550,10 +550,17 @@ If no server is started, .Ic attach-session will attempt to start it; this will fail unless sessions are created in the configuration file. -.It Ic detach-client Op Fl t Ar target-client +.It Xo Ic detach-client +.Op Fl P +.Op Fl t Ar target-client +.Xc .D1 (alias: Ic detach ) Detach the current client if bound to a key, or the specified client with .Fl t . +If +.Fl P +is given, send SIGHUP to the parent process of the client, typically causing it +to exit. .It Ic has-session Op Fl t Ar target-session .D1 (alias: Ic has ) Report an error and exit with 1 if the specified session does not exist. diff --git a/tmux.h b/tmux.h index 5ac3c172..61022983 100644 --- a/tmux.h +++ b/tmux.h @@ -375,6 +375,7 @@ enum msgtype { MSG_SHELL, MSG_STDERR, MSG_STDOUT, + MSG_DETACHKILL }; /* From c36f67a2889ae0f5792ea88e8206d5d7db8c4839 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 3 Mar 2011 08:53:14 +0000 Subject: [PATCH 0863/1180] Fix a typo that meant we did not reset the background colour when it was omitted in a 256-colour SGR ([48;5m). From Yusuke ENDOH. --- input.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/input.c b/input.c index 73e02099..f80e7fc1 100644 --- a/input.c +++ b/input.c @@ -1277,7 +1277,7 @@ input_csi_dispatch_sgr(struct input_ctx *ictx) gc->fg = 8; } else if (n == 48) { gc->flags &= ~GRID_FLAG_BG256; - gc->fg = 8; + gc->bg = 8; } } else { From d5ed5fb08ff83a2cc38292b3eb0addab21ce6282 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 4 Mar 2011 23:26:44 +0000 Subject: [PATCH 0864/1180] Two fixes by Micah Cowan: make mouse work properly beyond >127 on signed char architectures and properly parse $TMUX by stopping the socket path at the first comma. --- tmux.c | 2 +- tty-keys.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tmux.c b/tmux.c index 31070f00..196edf6c 100644 --- a/tmux.c +++ b/tmux.c @@ -132,7 +132,7 @@ parseenvironment(void) if ((env = getenv("TMUX")) == NULL) return; - if (sscanf(env, "%255s,%ld,%d", path, &pid, &idx) != 3) + if (sscanf(env, "%255[^,],%ld,%d", path, &pid, &idx) != 3) return; environ_path = xstrdup(path); environ_pid = pid; diff --git a/tty-keys.c b/tty-keys.c index 3381aefe..223d574e 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -630,10 +630,10 @@ tty_keys_mouse(struct tty *tty, utf8_append(&utf8data, buf[*size]); value = utf8_combine(&utf8data); } else - value = buf[*size]; + value = (unsigned char)buf[*size]; (*size)++; } else { - value = buf[*size]; + value = (unsigned char)buf[*size]; (*size)++; } From 79e30daeae1d49a1cf1dc4618edf1ec82804a80c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 7 Mar 2011 23:46:27 +0000 Subject: [PATCH 0865/1180] Support passing through escape sequences to the underlying terminal by using DCS with a "tmux;" prefix. Escape characters in the sequences must be doubled. For example: $ printf '\033Ptmux;\033\033]12;red\007\033\\' Will pass \033]12;red\007 to the terminal (and change the cursor colour in xterm). From Kevin Goodsell. --- input.c | 73 +++++++++++++++++++++++++++++++++----------------- screen-write.c | 12 +++++++++ tmux.h | 2 ++ tty.c | 10 +++++++ 4 files changed, 73 insertions(+), 24 deletions(-) diff --git a/input.c b/input.c index f80e7fc1..3da950d5 100644 --- a/input.c +++ b/input.c @@ -41,6 +41,9 @@ * * - A state for the screen \033k...\033\\ sequence to rename a window. This is * pretty stupid but not supporting it is more trouble than it is worth. + * + * - Special handling for ESC inside a DCS to allow arbitrary byte sequences to + * be passed to the underlying teminal(s). */ /* Helper functions. */ @@ -50,8 +53,6 @@ void input_reply(struct input_ctx *, const char *, ...); /* Transition entry/exit handlers. */ void input_clear(struct input_ctx *); -void input_enter_dcs(struct input_ctx *); -void input_exit_dcs(struct input_ctx *); void input_enter_osc(struct input_ctx *); void input_exit_osc(struct input_ctx *); void input_enter_apc(struct input_ctx *); @@ -68,6 +69,7 @@ int input_c0_dispatch(struct input_ctx *); int input_esc_dispatch(struct input_ctx *); int input_csi_dispatch(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 *); int input_utf8_add(struct input_ctx *); int input_utf8_close(struct input_ctx *); @@ -204,6 +206,7 @@ const struct input_transition input_state_dcs_enter_table[]; const struct input_transition input_state_dcs_parameter_table[]; const struct input_transition input_state_dcs_intermediate_table[]; const struct input_transition input_state_dcs_handler_table[]; +const struct input_transition input_state_dcs_escape_table[]; const struct input_transition input_state_dcs_ignore_table[]; const struct input_transition input_state_osc_string_table[]; const struct input_transition input_state_apc_string_table[]; @@ -286,10 +289,17 @@ const struct input_state input_state_dcs_intermediate = { /* dcs_handler state definition. */ const struct input_state input_state_dcs_handler = { "dcs_handler", - input_enter_dcs, input_exit_dcs, + NULL, NULL, input_state_dcs_handler_table }; +/* dcs_escape state definition. */ +const struct input_state input_state_dcs_escape = { + "dcs_escape", + NULL, NULL, + input_state_dcs_escape_table +}; + /* dcs_ignore state definition. */ const struct input_state input_state_dcs_ignore = { "dcs_ignore", @@ -482,7 +492,7 @@ const struct input_transition input_state_dcs_enter_table[] = { { 0x3a, 0x3a, NULL, &input_state_dcs_ignore }, { 0x3b, 0x3b, input_parameter, &input_state_dcs_parameter }, { 0x3c, 0x3f, input_intermediate, &input_state_dcs_parameter }, - { 0x40, 0x7e, NULL, &input_state_dcs_handler }, + { 0x40, 0x7e, input_input, &input_state_dcs_handler }, { 0x7f, 0xff, NULL, NULL }, { -1, -1, NULL, NULL } @@ -500,7 +510,7 @@ const struct input_transition input_state_dcs_parameter_table[] = { { 0x3a, 0x3a, NULL, &input_state_dcs_ignore }, { 0x3b, 0x3b, input_parameter, NULL }, { 0x3c, 0x3f, NULL, &input_state_dcs_ignore }, - { 0x40, 0x7e, NULL, &input_state_dcs_handler }, + { 0x40, 0x7e, input_input, &input_state_dcs_handler }, { 0x7f, 0xff, NULL, NULL }, { -1, -1, NULL, NULL } @@ -515,7 +525,7 @@ const struct input_transition input_state_dcs_intermediate_table[] = { { 0x1c, 0x1f, NULL, NULL }, { 0x20, 0x2f, input_intermediate, NULL }, { 0x30, 0x3f, NULL, &input_state_dcs_ignore }, - { 0x40, 0x7e, NULL, &input_state_dcs_handler }, + { 0x40, 0x7e, input_input, &input_state_dcs_handler }, { 0x7f, 0xff, NULL, NULL }, { -1, -1, NULL, NULL } @@ -523,13 +533,22 @@ const struct input_transition input_state_dcs_intermediate_table[] = { /* dcs_handler state table. */ const struct input_transition input_state_dcs_handler_table[] = { - INPUT_STATE_ANYWHERE, + /* No INPUT_STATE_ANYWHERE */ - { 0x00, 0x17, NULL, NULL }, - { 0x19, 0x19, input_input, NULL }, - { 0x1c, 0x1f, input_input, NULL }, - { 0x20, 0x7e, input_input, NULL }, - { 0x7f, 0xff, NULL, NULL }, + { 0x00, 0x1a, input_input, NULL }, + { 0x1b, 0x1b, NULL, &input_state_dcs_escape }, + { 0x1c, 0xff, input_input, NULL }, + + { -1, -1, NULL, NULL } +}; + +/* dcs_escape state table. */ +const struct input_transition input_state_dcs_escape_table[] = { + /* No INPUT_STATE_ANYWHERE */ + + { 0x00, 0x5b, input_input, &input_state_dcs_handler }, + { 0x5c, 0x5c, input_dcs_dispatch, &input_state_ground }, + { 0x5d, 0xff, input_input, &input_state_dcs_handler }, { -1, -1, NULL, NULL } }; @@ -1391,20 +1410,26 @@ input_csi_dispatch_sgr(struct input_ctx *ictx) } } -/* DCS string started. */ -void -input_enter_dcs(struct input_ctx *ictx) -{ - log_debug("%s", __func__); - - input_clear(ictx); -} - /* DCS terminator (ST) received. */ -void -input_exit_dcs(unused struct input_ctx *ictx) +int +input_dcs_dispatch(struct input_ctx *ictx) { - log_debug("%s", __func__); + const char prefix[] = "tmux;"; + const u_int prefix_len = (sizeof prefix) - 1; + + if (ictx->flags & INPUT_DISCARD) + return (0); + + log_debug("%s: \"%s\"", __func__, ictx->input_buf); + + /* Check for tmux prefix. */ + if (ictx->input_len >= prefix_len && + strncmp(ictx->input_buf, prefix, prefix_len) == 0) { + screen_write_rawstring(&ictx->ctx, + ictx->input_buf + prefix_len, ictx->input_len - prefix_len); + } + + return (0); } /* OSC string started. */ diff --git a/screen-write.c b/screen-write.c index 4c8382de..09f84bfd 100644 --- a/screen-write.c +++ b/screen-write.c @@ -1191,3 +1191,15 @@ screen_write_overwrite(struct screen_write_ctx *ctx, u_int width) grid_view_set_cell(gd, xx, s->cy, &grid_default_cell); } } + +void +screen_write_rawstring(struct screen_write_ctx *ctx, u_char *str, u_int len) +{ + struct tty_ctx ttyctx; + + screen_write_initctx(ctx, &ttyctx, 0); + ttyctx.ptr = str; + ttyctx.num = len; + + tty_write(tty_cmd_rawstring, &ttyctx); +} diff --git a/tmux.h b/tmux.h index 61022983..2e53a24a 100644 --- a/tmux.h +++ b/tmux.h @@ -1426,6 +1426,7 @@ void tty_cmd_insertline(struct tty *, const struct tty_ctx *); void tty_cmd_linefeed(struct tty *, const struct tty_ctx *); void tty_cmd_utf8character(struct tty *, const struct tty_ctx *); void tty_cmd_reverseindex(struct tty *, const struct tty_ctx *); +void tty_cmd_rawstring(struct tty *, const struct tty_ctx *); /* tty-term.c */ extern struct tty_terms tty_terms; @@ -1804,6 +1805,7 @@ void screen_write_clearstartofscreen(struct screen_write_ctx *); void screen_write_clearscreen(struct screen_write_ctx *); void screen_write_cell(struct screen_write_ctx *, const struct grid_cell *, const struct utf8_data *); +void screen_write_rawstring(struct screen_write_ctx *, u_char *, u_int); /* screen-redraw.c */ void screen_redraw_screen(struct client *, int, int); diff --git a/tty.c b/tty.c index b44c5974..46b8a475 100644 --- a/tty.c +++ b/tty.c @@ -931,6 +931,16 @@ tty_cmd_utf8character(struct tty *tty, const struct tty_ctx *ctx) tty_draw_line(tty, wp->screen, ctx->ocy, wp->xoff, wp->yoff); } +void +tty_cmd_rawstring(struct tty *tty, const struct tty_ctx *ctx) +{ + u_int i; + u_char *str = ctx->ptr; + + for (i = 0; i < ctx->num; i++) + tty_putc(tty, str[i]); +} + void tty_cell( struct tty *tty, const struct grid_cell *gc, const struct grid_utf8 *gu) From 0a404aabd3d0e383b8f05ba6090ca927f4baccb2 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 7 Mar 2011 23:55:16 +0000 Subject: [PATCH 0866/1180] Prevent tiled producing a corrupt layout when only one column is needed, from Karl Ferdinand Ebert. --- layout-set.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/layout-set.c b/layout-set.c index 63a6a69e..eb75233a 100644 --- a/layout-set.c +++ b/layout-set.c @@ -519,7 +519,7 @@ layout_set_tiled(struct window *w) TAILQ_INSERT_TAIL(&lc->cells, lcrow, entry); /* If only one column, just use the row directly. */ - if (n - (j * columns) == 1) { + if (n - (j * columns) == 1 || columns == 1) { layout_make_leaf(lcrow, wp); wp = TAILQ_NEXT(wp, entry); continue; From 54456d5602fb05ac30af0167242deaa44adf83ae Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 8 Mar 2011 19:23:49 +0000 Subject: [PATCH 0867/1180] Fix an incorrect test which was always true (oupper is always < olower), from Yusuke ENDOH. --- tty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tty.c b/tty.c index 46b8a475..82162097 100644 --- a/tty.c +++ b/tty.c @@ -454,7 +454,7 @@ tty_redraw_region(struct tty *tty, const struct tty_ctx *ctx) * without this, the entire pane ends up being redrawn many times which * can be much more data. */ - if (ctx->orupper - ctx->orlower >= screen_size_y(s) / 2) { + if (ctx->orlower - ctx->orupper >= screen_size_y(s) / 2) { wp->flags |= PANE_REDRAW; return; } From d74e5bffbad33df742749b5983479dc2cfac273b Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 26 Mar 2011 19:07:33 +0000 Subject: [PATCH 0868/1180] Fix to properly wrap wide characters, from Micah Cowan. --- screen-write.c | 10 ++++++---- tty.c | 14 +++++++++++--- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/screen-write.c b/screen-write.c index 09f84bfd..fd4c7846 100644 --- a/screen-write.c +++ b/screen-write.c @@ -1012,8 +1012,10 @@ screen_write_cell(struct screen_write_ctx *ctx, * If this is a wide character and there is no room on the screen, for * the entire character, don't print it. */ - if (width > 1 && (width > screen_size_x(s) || - (s->cx != screen_size_x(s) && s->cx > screen_size_x(s) - width))) + if (!(s->mode & MODE_WRAP) + && (width > 1 && (width > screen_size_x(s) || + (s->cx != screen_size_x(s) + && s->cx > screen_size_x(s) - width)))) return; /* @@ -1045,8 +1047,8 @@ screen_write_cell(struct screen_write_ctx *ctx, } /* Sanity checks. */ - if (((s->mode & MODE_WRAP) && s->cx > screen_size_x(s) - 1) - || s->cy > screen_size_y(s) - 1) + if (((s->mode & MODE_WRAP) && s->cx > screen_size_x(s) - width) + || s->cy > screen_size_y(s) - width) return; /* Handle overwriting of UTF-8 characters. */ diff --git a/tty.c b/tty.c index 82162097..57f0d217 100644 --- a/tty.c +++ b/tty.c @@ -892,11 +892,19 @@ tty_cmd_cell(struct tty *tty, const struct tty_ctx *ctx) struct window_pane *wp = ctx->wp; struct screen *s = wp->screen; u_int cx; + u_int width; + const struct grid_cell *gc = ctx->cell; + const struct grid_utf8 *gu = ctx->utf8; + + if (gc->flags & GRID_FLAG_UTF8) + width = gu->width; + else + width = 1; tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower); /* Is the cursor in the very last position? */ - if (ctx->ocx > wp->sx - ctx->last_width) { + if (ctx->ocx > wp->sx - width) { if (wp->xoff != 0 || wp->sx != tty->sx) { /* * The pane doesn't fill the entire line, the linefeed @@ -906,10 +914,10 @@ tty_cmd_cell(struct tty *tty, const struct tty_ctx *ctx) } else if (tty->cx < tty->sx) { /* * The cursor isn't in the last position already, so - * move as far left as possinble and redraw the last + * move as far left as possible and redraw the last * cell to move into the last position. */ - cx = screen_size_x(s) - ctx->last_width; + cx = screen_size_x(s) - width; tty_cursor_pane(tty, ctx, cx, ctx->ocy); tty_cell(tty, &ctx->last_cell, &ctx->last_utf8); } From 808502ac3d86193d9a371728b2ea2055100c76c3 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 27 Mar 2011 20:27:26 +0000 Subject: [PATCH 0869/1180] Give each pane created in a tmux server a unique id (starting from 0), put it in the TMUX_PANE environment variable and accept it as a target. Suggested by and with testing and tweaks from Ben Boeckel. --- cmd-list-panes.c | 4 +- cmd.c | 99 ++++++++++++++++++++++++++++++++++++++++++------ server.c | 1 + tmux.1 | 11 ++++++ tmux.h | 8 ++++ window.c | 31 ++++++++++++++- 6 files changed, 140 insertions(+), 14 deletions(-) diff --git a/cmd-list-panes.c b/cmd-list-panes.c index 03fd7afd..e58fd671 100644 --- a/cmd-list-panes.c +++ b/cmd-list-panes.c @@ -64,8 +64,8 @@ cmd_list_panes_exec(struct cmd *self, struct cmd_ctx *ctx) } size += gd->hsize * sizeof *gd->linedata; - ctx->print(ctx, "%u: [%ux%u] [history %u/%u, %llu bytes]%s%s", - n, wp->sx, wp->sy, gd->hsize, gd->hlimit, size, + ctx->print(ctx, "%u: [%ux%u] [history %u/%u, %llu bytes] %%%u%s%s", + n, wp->sx, wp->sy, gd->hsize, gd->hlimit, size, wp->id, wp == wp->window->active ? " (active)" : "", wp->fd == -1 ? " (dead)" : ""); n++; diff --git a/cmd.c b/cmd.c index 5333a023..11910aac 100644 --- a/cmd.c +++ b/cmd.c @@ -118,9 +118,12 @@ struct client *cmd_lookup_client(const char *); struct session *cmd_lookup_session(const char *, int *); struct winlink *cmd_lookup_window(struct session *, const char *, int *); int cmd_lookup_index(struct session *, const char *, int *); +struct window_pane *cmd_lookup_paneid(const char *); +struct session *cmd_pane_session(struct cmd_ctx *, + struct window_pane *, struct winlink **); struct winlink *cmd_find_window_offset(const char *, struct session *, int *); int cmd_find_index_offset(const char *, struct session *, int *); -struct window_pane *cmd_find_pane_offset(const char *, struct winlink *); +struct window_pane *cmd_find_pane_offset(const char *, struct winlink *); int cmd_pack_argv(int argc, char **argv, char *buf, size_t len) @@ -639,21 +642,78 @@ cmd_lookup_index(struct session *s, const char *name, int *ambiguous) return (-1); } +/* + * Lookup pane id. An initial % means a pane id. sp must already point to the + * current session. + */ +struct window_pane * +cmd_lookup_paneid(const char *arg) +{ + const char *errstr; + u_int paneid; + + if (*arg != '%') + return (NULL); + + paneid = strtonum(arg + 1, 0, UINT_MAX, &errstr); + if (errstr != NULL) + return (NULL); + return (window_pane_find_by_id(paneid)); +} + +/* Find session and winlink for pane. */ +struct session * +cmd_pane_session(struct cmd_ctx *ctx, struct window_pane *wp, + struct winlink **wlp) +{ + struct session *s; + struct sessionslist ss; + struct winlink *wl; + + /* If this pane is in the current session, return that winlink. */ + s = cmd_current_session(ctx); + if (s != NULL) { + wl = winlink_find_by_window(&s->windows, wp->window); + if (wl != NULL) { + if (wlp != NULL) + *wlp = wl; + return (s); + } + } + + /* Otherwise choose from all sessions with this pane. */ + ARRAY_INIT(&ss); + RB_FOREACH(s, sessions, &sessions) { + if (winlink_find_by_window(&s->windows, wp->window) != NULL) + ARRAY_ADD(&ss, s); + } + s = cmd_choose_session_list(&ss); + ARRAY_FREE(&ss); + if (wlp != NULL) + *wlp = winlink_find_by_window(&s->windows, wp->window); + return (s); +} + /* Find the target session or report an error and return NULL. */ struct session * cmd_find_session(struct cmd_ctx *ctx, const char *arg) { - struct session *s; - struct client *c; - char *tmparg; - size_t arglen; - int ambiguous; + struct session *s; + struct window_pane *wp; + struct client *c; + char *tmparg; + size_t arglen; + int ambiguous; /* A NULL argument means the current session. */ if (arg == NULL) return (cmd_current_session(ctx)); tmparg = xstrdup(arg); + /* Lookup as pane id. */ + if ((wp = cmd_lookup_paneid(arg)) != NULL) + return (cmd_pane_session(ctx, wp, NULL)); + /* Trim a single trailing colon if any. */ arglen = strlen(tmparg); if (arglen != 0 && tmparg[arglen - 1] == ':') @@ -682,11 +742,12 @@ cmd_find_session(struct cmd_ctx *ctx, const char *arg) struct winlink * cmd_find_window(struct cmd_ctx *ctx, const char *arg, struct session **sp) { - struct session *s; - struct winlink *wl; - const char *winptr; - char *sessptr = NULL; - int ambiguous = 0; + struct session *s; + struct winlink *wl; + struct window_pane *wp; + const char *winptr; + char *sessptr = NULL; + int ambiguous = 0; /* * Find the current session. There must always be a current session, if @@ -704,6 +765,14 @@ cmd_find_window(struct cmd_ctx *ctx, const char *arg, struct session **sp) return (s->curw); } + /* Lookup as pane id. */ + if ((wp = cmd_lookup_paneid(arg)) != NULL) { + s = cmd_pane_session(ctx, wp, &wl); + if (sp != NULL) + *sp = s; + return (wl); + } + /* Time to look at the argument. If it is empty, that is an error. */ if (*arg == '\0') goto not_found; @@ -998,6 +1067,14 @@ cmd_find_pane(struct cmd_ctx *ctx, return (s->curw); } + /* Lookup as pane id. */ + if ((*wpp = cmd_lookup_paneid(arg)) != NULL) { + s = cmd_pane_session(ctx, *wpp, &wl); + if (sp != NULL) + *sp = s; + return (wl); + } + /* Look for a separating period. */ if ((period = strrchr(arg, '.')) == NULL) goto no_period; diff --git a/server.c b/server.c index 72f3880d..a548a694 100644 --- a/server.c +++ b/server.c @@ -143,6 +143,7 @@ server_start(void) log_debug("server started, pid %ld", (long) getpid()); ARRAY_INIT(&windows); + RB_INIT(&all_window_panes); ARRAY_INIT(&clients); ARRAY_INIT(&dead_clients); RB_INIT(&sessions); diff --git a/tmux.1 b/tmux.1 index 7d42984a..d69321dd 100644 --- a/tmux.1 +++ b/tmux.1 @@ -449,6 +449,17 @@ select-window -t:+2 When dealing with a session that doesn't contain sequential window indexes, they will be correctly skipped. .Pp +.Nm +also gives each pane created in a server an identifier consisting of a +.Ql % +and a number, starting from zero. +A pane's identifier is unique for the life of the +.Nm +server and is passed to the child process of the pane in the +.Ev TMUX_PANE +environment variable. +It may be used alone to target a pane or the window containing it. +.Pp .Ar shell-command arguments are .Xr sh 1 diff --git a/tmux.h b/tmux.h index 2e53a24a..2d9e992a 100644 --- a/tmux.h +++ b/tmux.h @@ -779,6 +779,8 @@ struct window_mode { /* Child window structure. */ struct window_pane { + u_int id; + struct window *window; struct layout_cell *layout_cell; @@ -821,8 +823,10 @@ struct window_pane { void *modedata; TAILQ_ENTRY(window_pane) entry; + RB_ENTRY(window_pane) tree_entry; }; TAILQ_HEAD(window_panes, window_pane); +RB_HEAD(window_pane_tree, window_pane); /* Window structure. */ struct window { @@ -1825,8 +1829,11 @@ int screen_check_selection(struct screen *, u_int, u_int); /* window.c */ extern struct windows windows; +extern struct window_pane_tree all_window_panes; int winlink_cmp(struct winlink *, struct winlink *); RB_PROTOTYPE(winlinks, winlink, entry, winlink_cmp); +int window_pane_cmp(struct window_pane *, struct window_pane *); +RB_PROTOTYPE(window_pane_tree, window_pane, tree_entry, window_pane_cmp); struct winlink *winlink_find_by_index(struct winlinks *, int); struct winlink *winlink_find_by_window(struct winlinks *, struct window *); int winlink_next_index(struct winlinks *, int); @@ -1861,6 +1868,7 @@ struct window_pane *window_pane_previous_by_number(struct window *, u_int window_pane_index(struct window *, struct window_pane *); u_int window_count_panes(struct window *); void window_destroy_panes(struct window *); +struct window_pane *window_pane_find_by_id(u_int); struct window_pane *window_pane_create(struct window *, u_int, u_int, u_int); void window_pane_destroy(struct window_pane *); int window_pane_spawn(struct window_pane *, const char *, diff --git a/window.c b/window.c index 2d332c40..4270013f 100644 --- a/window.c +++ b/window.c @@ -56,6 +56,10 @@ /* Global window list. */ struct windows windows; +/* Global panes tree. */ +struct window_pane_tree all_window_panes; +u_int next_window_pane; + void window_pane_read_callback(struct bufferevent *, void *); void window_pane_error_callback(struct bufferevent *, short, void *); @@ -67,6 +71,14 @@ winlink_cmp(struct winlink *wl1, struct winlink *wl2) return (wl1->idx - wl2->idx); } +RB_GENERATE(window_pane_tree, window_pane, tree_entry, window_pane_cmp); + +int +window_pane_cmp(struct window_pane *wp1, struct window_pane *wp2) +{ + return (wp1->id - wp2->id); +} + struct winlink * winlink_find_by_window(struct winlinks *wwl, struct window *w) { @@ -495,6 +507,16 @@ window_printable_flags(struct session *s, struct winlink *wl) return (xstrdup(flags)); } +/* Find pane in global tree by id. */ +struct window_pane * +window_pane_find_by_id(u_int id) +{ + struct window_pane wp; + + wp.id = id; + return (RB_FIND(window_pane_tree, &all_window_panes, &wp)); +} + struct window_pane * window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit) { @@ -503,6 +525,9 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit) wp = xcalloc(1, sizeof *wp); wp->window = w; + wp->id = next_window_pane++; + RB_INSERT(window_pane_tree, &all_window_panes, wp); + wp->cmd = NULL; wp->shell = NULL; wp->cwd = NULL; @@ -555,6 +580,8 @@ window_pane_destroy(struct window_pane *wp) bufferevent_free(wp->pipe_event); } + RB_REMOVE(window_pane_tree, &all_window_panes, wp); + if (wp->cwd != NULL) xfree(wp->cwd); if (wp->shell != NULL) @@ -569,7 +596,7 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell, const char *cwd, struct environ *env, struct termios *tio, char **cause) { struct winsize ws; - char *argv0; + char *argv0, paneid[16]; const char *ptr; struct termios tio2; @@ -616,6 +643,8 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell, closefrom(STDERR_FILENO + 1); + xsnprintf(paneid, sizeof paneid, "%%%u", wp->id); + environ_set(env, "TMUX_PANE", paneid); environ_push(env); clear_signals(1); From 7ce8fee4f3ea4a480ffa18cd5d66ba9a7f3626db Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 27 Mar 2011 20:31:25 +0000 Subject: [PATCH 0870/1180] Don't include meta twice when working out the flags to output for xterm-style keys - bit 3 is accepted on input but not on output. Also a style nit in the header. --- tmux.h | 2 +- xterm-keys.c | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/tmux.h b/tmux.h index 2d9e992a..1333bdf0 100644 --- a/tmux.h +++ b/tmux.h @@ -110,7 +110,7 @@ extern char **environ; #define KEYC_SHIFT 0x8000 #define KEYC_PREFIX 0x10000 -/* Mask to obtain key w/o modifiers */ +/* Mask to obtain key w/o modifiers. */ #define KEYC_MASK_MOD (KEYC_ESCAPE|KEYC_CTRL|KEYC_SHIFT|KEYC_PREFIX) #define KEYC_MASK_KEY (~KEYC_MASK_MOD) diff --git a/xterm-keys.c b/xterm-keys.c index 1e5583f7..fd9fee8a 100644 --- a/xterm-keys.c +++ b/xterm-keys.c @@ -174,8 +174,6 @@ xterm_keys_lookup(int key) modifiers += 2; if (key & KEYC_CTRL) modifiers += 4; - if (key & KEYC_ESCAPE) - modifiers += 8; /* * If the key has no modifiers, return NULL and let it fall through to From 71e8e26ccc85a07c59d9b607c0e248376fa0a447 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 27 Mar 2011 20:36:19 +0000 Subject: [PATCH 0871/1180] Set the terminal blocking again earlier, before sending the reset sequences. --- tty.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tty.c b/tty.c index 57f0d217..bffb1f93 100644 --- a/tty.c +++ b/tty.c @@ -230,6 +230,8 @@ tty_stop_tty(struct tty *tty) if (tcsetattr(tty->fd, TCSANOW, &tty->tio) == -1) return; + setblocking(tty->fd, 1); + tty_raw(tty, tty_term_string2(tty->term, TTYC_CSR, 0, ws.ws_row - 1)); if (tty_use_acs(tty)) tty_raw(tty, tty_term_string(tty->term, TTYC_RMACS)); @@ -242,8 +244,6 @@ tty_stop_tty(struct tty *tty) tty_raw(tty, "\033[?1000l"); tty_raw(tty, tty_term_string(tty->term, TTYC_RMCUP)); - - setblocking(tty->fd, 1); } void From fa6abac98d03891f4651ca6d23da11f20fa35ace Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 28 Mar 2011 19:44:31 +0000 Subject: [PATCH 0872/1180] Style: uint -> u_int and a missing else. --- paste.c | 2 +- tmux.h | 2 +- window-copy.c | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/paste.c b/paste.c index a5489552..cc43d6e9 100644 --- a/paste.c +++ b/paste.c @@ -31,7 +31,7 @@ /* Return each item of the stack in turn. */ struct paste_buffer * -paste_walk_stack(struct paste_stack *ps, uint *idx) +paste_walk_stack(struct paste_stack *ps, u_int *idx) { struct paste_buffer *pb; diff --git a/tmux.h b/tmux.h index 1333bdf0..5d271a57 100644 --- a/tmux.h +++ b/tmux.h @@ -1454,7 +1454,7 @@ void tty_keys_free(struct tty *); int tty_keys_next(struct tty *); /* paste.c */ -struct paste_buffer *paste_walk_stack(struct paste_stack *, uint *); +struct paste_buffer *paste_walk_stack(struct paste_stack *, u_int *); struct paste_buffer *paste_get_top(struct paste_stack *); struct paste_buffer *paste_get_index(struct paste_stack *, u_int); int paste_free_top(struct paste_stack *); diff --git a/window-copy.c b/window-copy.c index 1cdb88d8..d21e4124 100644 --- a/window-copy.c +++ b/window-copy.c @@ -368,8 +368,8 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key) if (np == 0) np = 1; - if (data->inputtype == WINDOW_COPY_JUMPFORWARD - || data->inputtype == WINDOW_COPY_JUMPBACK) { + if (data->inputtype == WINDOW_COPY_JUMPFORWARD || + data->inputtype == WINDOW_COPY_JUMPBACK) { /* Ignore keys with modifiers. */ if ((key & KEYC_MASK_MOD) == 0) { data->jumpchar = key; @@ -385,7 +385,7 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key) data->inputtype = WINDOW_COPY_OFF; window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1); return; - } if (data->inputtype == WINDOW_COPY_NUMERICPREFIX) { + } else if (data->inputtype == WINDOW_COPY_NUMERICPREFIX) { if (window_copy_key_numeric_prefix(wp, key) == 0) return; data->inputtype = WINDOW_COPY_OFF; @@ -1617,7 +1617,7 @@ window_copy_cursor_jump(struct window_pane *wp) struct window_copy_mode_data *data = wp->modedata; struct screen *back_s = data->backing; const struct grid_cell *gc; - uint px, py, xx; + u_int px, py, xx; px = data->cx + 1; py = screen_hsize(back_s) + data->cy - data->oy; @@ -1643,7 +1643,7 @@ window_copy_cursor_jump_back(struct window_pane *wp) struct window_copy_mode_data *data = wp->modedata; struct screen *back_s = data->backing; const struct grid_cell *gc; - uint px, py; + u_int px, py; px = data->cx; py = screen_hsize(back_s) + data->cy - data->oy; From 82e0165c49b85ab95663d677fc7d0249b2a4efae Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 28 Mar 2011 20:17:39 +0000 Subject: [PATCH 0873/1180] Allow a start and end line to be specified for capture-pane which may be negative to capture part of the history. Prompted by request from Victor J Orlikowski. --- cmd-capture-pane.c | 40 ++++++++++++++++++++++++++++++++++------ tmux.1 | 9 +++++++++ 2 files changed, 43 insertions(+), 6 deletions(-) diff --git a/cmd-capture-pane.c b/cmd-capture-pane.c index 6efbfe97..52f5455c 100644 --- a/cmd-capture-pane.c +++ b/cmd-capture-pane.c @@ -31,8 +31,8 @@ int cmd_capture_pane_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_capture_pane_entry = { "capture-pane", "capturep", - "b:t:", 0, 0, - "[-b buffer-index] [-t target-pane]", + "b:E:S:t:", 0, 0, + "[-b buffer-index] [-E end-line] [-S start-line] [-t target-pane]", 0, NULL, NULL, @@ -46,19 +46,47 @@ cmd_capture_pane_exec(struct cmd *self, struct cmd_ctx *ctx) struct window_pane *wp; char *buf, *line, *cause; struct screen *s; - int buffer; - u_int i, limit; + struct grid *gd; + int buffer, n; + u_int i, limit, top, bottom, tmp; size_t len, linelen; if (cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp) == NULL) return (-1); s = &wp->base; + gd = s->grid; buf = NULL; len = 0; - for (i = 0; i < screen_size_y(s); i++) { - line = grid_view_string_cells(s->grid, 0, i, screen_size_x(s)); + n = args_strtonum(args, 'S', SHRT_MIN, SHRT_MAX, &cause); + if (cause != NULL) + top = gd->hsize; + else if (n < 0 && (u_int) -n > gd->hsize) + top = 0; + else + top = gd->hsize + n; + if (top > gd->hsize + gd->sy - 1) + top = gd->hsize + gd->sy - 1; + + n = args_strtonum(args, 'E', SHRT_MIN, SHRT_MAX, &cause); + if (cause != NULL) + bottom = gd->hsize + gd->sy - 1; + else if (n < 0 && (u_int) -n > gd->hsize) + bottom = 0; + else + bottom = gd->hsize + n; + if (bottom > gd->hsize + gd->sy - 1) + bottom = gd->hsize + gd->sy - 1; + + if (bottom < top) { + tmp = bottom; + bottom = top; + top = tmp; + } + + for (i = top; i <= bottom; i++) { + line = grid_string_cells(s->grid, 0, i, screen_size_x(s)); linelen = strlen(line); buf = xrealloc(buf, 1, len + linelen + 1); diff --git a/tmux.1 b/tmux.1 index d69321dd..bbd8a80e 100644 --- a/tmux.1 +++ b/tmux.1 @@ -953,11 +953,20 @@ If is given, the new window does not become the current window. .It Xo Ic capture-pane .Op Fl b Ar buffer-index +.Op Fl E Ar end-line +.Op Fl S Ar start-line .Op Fl t Ar target-pane .Xc .D1 (alias: Ic capturep ) Capture the contents of a pane to the specified buffer, or a new buffer if none is specified. +.Pp +.Fl S +and +.Fl E +specify the starting and ending line numbers, zero is the first line of the +visible pane and negative numbers are lines in the history. +The default is to capture only the visible contents of the pane. .It Xo .Ic choose-client .Op Fl t Ar target-window From f19a4bf9d1af2f512b841ca9dabdf81592e0f4ea Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 28 Mar 2011 23:13:00 +0000 Subject: [PATCH 0874/1180] Add -a and -s options to lsp to list all panes in the server or session respectively. Likewise add -s to lsw. From Ben Boeckel. --- cmd-list-panes.c | 60 ++++++++++++++++++++++++++++++++++++++-------- cmd-list-windows.c | 37 ++++++++++++++++++++++------ tmux.1 | 30 +++++++++++++++++++---- 3 files changed, 105 insertions(+), 22 deletions(-) diff --git a/cmd-list-panes.c b/cmd-list-panes.c index e58fd671..830b8620 100644 --- a/cmd-list-panes.c +++ b/cmd-list-panes.c @@ -28,10 +28,14 @@ int cmd_list_panes_exec(struct cmd *, struct cmd_ctx *); +void cmd_list_panes_server(struct cmd_ctx *); +void cmd_list_panes_session(struct session *, struct cmd_ctx *); +void cmd_list_panes_window(struct winlink *, struct cmd_ctx *); + const struct cmd_entry cmd_list_panes_entry = { "list-panes", "lsp", - "t:", 0, 0, - CMD_TARGET_WINDOW_USAGE, + "ast:", 0, 0, + "[-as] [-t target]", 0, NULL, NULL, @@ -41,17 +45,54 @@ const struct cmd_entry cmd_list_panes_entry = { int cmd_list_panes_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct args *args = self->args; - struct winlink *wl; + struct args *args = self->args; + struct session *s; + struct winlink *wl; + + if (args_has(args, 'a')) + cmd_list_panes_server(ctx); + else if (args_has(args, 's')) { + s = cmd_find_session(ctx, args_get(args, 't')); + if (s == NULL) + return (-1); + cmd_list_panes_session(s, ctx); + } else { + wl = cmd_find_window(ctx, args_get(args, 't'), NULL); + if (wl == NULL) + return (-1); + cmd_list_panes_window(wl, ctx); + } + + return (0); +} + +void +cmd_list_panes_server(struct cmd_ctx *ctx) +{ + struct session *s; + + RB_FOREACH(s, sessions, &sessions) + cmd_list_panes_session(s, ctx); +} + +void +cmd_list_panes_session(struct session *s, struct cmd_ctx *ctx) +{ + struct winlink *wl; + + RB_FOREACH(wl, winlinks, &s->windows) + cmd_list_panes_window(wl, ctx); +} + +void +cmd_list_panes_window(struct winlink *wl, struct cmd_ctx *ctx) +{ struct window_pane *wp; struct grid *gd; struct grid_line *gl; u_int i, n; unsigned long long size; - if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL) - return (-1); - n = 0; TAILQ_FOREACH(wp, &wl->window->panes, entry) { gd = wp->base.grid; @@ -64,12 +105,11 @@ cmd_list_panes_exec(struct cmd *self, struct cmd_ctx *ctx) } size += gd->hsize * sizeof *gd->linedata; - ctx->print(ctx, "%u: [%ux%u] [history %u/%u, %llu bytes] %%%u%s%s", + ctx->print(ctx, + "%u: [%ux%u] [history %u/%u, %llu bytes] %%%u%s%s", n, wp->sx, wp->sy, gd->hsize, gd->hlimit, size, wp->id, wp == wp->window->active ? " (active)" : "", wp->fd == -1 ? " (dead)" : ""); n++; } - - return (0); } diff --git a/cmd-list-windows.c b/cmd-list-windows.c index 331b521a..9233ab75 100644 --- a/cmd-list-windows.c +++ b/cmd-list-windows.c @@ -28,10 +28,13 @@ int cmd_list_windows_exec(struct cmd *, struct cmd_ctx *); +void cmd_list_windows_server(struct cmd_ctx *); +void cmd_list_windows_session(struct session *, struct cmd_ctx *); + const struct cmd_entry cmd_list_windows_entry = { "list-windows", "lsw", - "t:", 0, 0, - CMD_TARGET_SESSION_USAGE, + "at:", 0, 0, + "[-a] " CMD_TARGET_SESSION_USAGE, 0, NULL, NULL, @@ -43,12 +46,34 @@ cmd_list_windows_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; struct session *s; + + if (args_has(args, 'a')) + cmd_list_windows_server(ctx); + else { + s = cmd_find_session(ctx, args_get(args, 't')); + if (s == NULL) + return (-1); + cmd_list_windows_session(s, ctx); + } + + return (0); +} + +void +cmd_list_windows_server(struct cmd_ctx *ctx) +{ + struct session *s; + + RB_FOREACH(s, sessions, &sessions) + cmd_list_windows_session(s, ctx); +} + +void +cmd_list_windows_session(struct session *s, struct cmd_ctx *ctx) +{ struct winlink *wl; char *layout; - if ((s = cmd_find_session(ctx, args_get(args, 't'))) == NULL) - return (-1); - RB_FOREACH(wl, winlinks, &s->windows) { layout = layout_dump(wl->window); ctx->print(ctx, "%d: %s [%ux%u] [layout %s]%s", @@ -56,6 +81,4 @@ cmd_list_windows_exec(struct cmd *self, struct cmd_ctx *ctx) layout, wl == s->curw ? " (active)" : ""); xfree(layout); } - - return (0); } diff --git a/tmux.1 b/tmux.1 index bbd8a80e..939a4333 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1115,13 +1115,33 @@ exists, it is killed, otherwise an error is generated. If .Fl d is given, the newly linked window is not selected. -.It Ic list-panes Op Fl t Ar target-window +.It Xo Ic list-panes +.Op Fl as +.Op Fl t Ar target +.Xc .D1 (alias: Ic lsp ) -List the panes in the current window or in -.Ar target-window . -.It Ic list-windows Op Fl t Ar target-session +If +.Fl a +is given, +.Ar target +is ignored and all panes on the server are listed. +If +.Fl s +is given, +.Ar target +is a session (or the current session). +If neither is given, +.Ar target +is a window (or the current window). +.It Xo Ic list-windows +.Op Fl a +.Op Fl t Ar target-session +.Xc .D1 (alias: Ic lsw ) -List windows in the current session or in +If +.Fl a +is given, list all windows on the server. +Otherwise, list windows in the current session or in .Ar target-session . .It Xo Ic move-window .Op Fl dk From d88c20e718f71acf146cb91eda2f818f37003ad0 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 29 Mar 2011 19:30:16 +0000 Subject: [PATCH 0875/1180] Change -t on display-message to be target-pane for the #[A-Z] replacements and add -c as target-client. --- cmd-display-message.c | 21 +++++++++++++++---- cmd-pipe-pane.c | 3 ++- server-client.c | 2 +- status.c | 47 ++++++++++++++++++++++++++----------------- tmux.1 | 10 +++++++-- tmux.h | 4 ++-- 6 files changed, 58 insertions(+), 29 deletions(-) diff --git a/cmd-display-message.c b/cmd-display-message.c index baf6fb9d..dfa8312f 100644 --- a/cmd-display-message.c +++ b/cmd-display-message.c @@ -30,8 +30,8 @@ int cmd_display_message_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_display_message_entry = { "display-message", "display", - "pt:", 0, 1, - "[-p] " CMD_TARGET_CLIENT_USAGE " [message]", + "c:pt:", 0, 1, + "[-p] [-c target-client] [-t target-pane] [message]", 0, NULL, NULL, @@ -43,18 +43,31 @@ cmd_display_message_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; struct client *c; + struct session *s; + struct winlink *wl; + struct window_pane *wp; const char *template; char *msg; - if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL) + if ((c = cmd_find_client(ctx, args_get(args, 'c'))) == NULL) return (-1); + if (args_has(args, 't') != NULL) { + wl = cmd_find_pane(ctx, args_get(args, 't'), &s, &wp); + if (wl == NULL) + return (-1); + } else { + s = NULL; + wl = NULL; + wp = NULL; + } + if (args->argc == 0) template = "[#S] #I:#W, current pane #P - (%H:%M %d-%b-%y)"; else template = args->argv[0]; - msg = status_replace(c, NULL, template, time(NULL), 0); + msg = status_replace(c, s, wl, wp, template, time(NULL), 0); if (args_has(self->args, 'p')) ctx->print(ctx, "%s", msg); else diff --git a/cmd-pipe-pane.c b/cmd-pipe-pane.c index d0e47541..1f27e6d9 100644 --- a/cmd-pipe-pane.c +++ b/cmd-pipe-pane.c @@ -113,7 +113,8 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx) closefrom(STDERR_FILENO + 1); - command = status_replace(c, NULL, args->argv[0], time(NULL), 0); + command = status_replace( + c, NULL, NULL, NULL, args->argv[0], time(NULL), 0); execl(_PATH_BSHELL, "sh", "-c", command, (char *) NULL); _exit(1); default: diff --git a/server-client.c b/server-client.c index 2b67ef5d..66e5caf0 100644 --- a/server-client.c +++ b/server-client.c @@ -614,7 +614,7 @@ server_client_set_title(struct client *c) template = options_get_string(&s->options, "set-titles-string"); - title = status_replace(c, NULL, template, time(NULL), 1); + title = status_replace(c, NULL, NULL, NULL, template, time(NULL), 1); if (c->title == NULL || strcmp(title, c->title) != 0) { if (c->title != NULL) xfree(c->title); diff --git a/status.c b/status.c index 60442fce..0a777ce8 100644 --- a/status.c +++ b/status.c @@ -38,8 +38,8 @@ void status_job_free(void *); void status_job_callback(struct job *); char *status_print( struct client *, struct winlink *, time_t, struct grid_cell *); -void status_replace1(struct client *, - struct winlink *, char **, char **, char *, size_t, int); +void status_replace1(struct client *, struct session *, struct winlink *, + struct window_pane *, char **, char **, char *, size_t, int); void status_message_callback(int, short, void *); const char *status_prompt_up_history(u_int *); @@ -80,8 +80,8 @@ status_redraw_get_left(struct client *c, if (attr != 0) gc->attr = attr; - left = status_replace( - c, NULL, options_get_string(&s->options, "status-left"), t, 1); + left = status_replace(c, NULL, + NULL, NULL, options_get_string(&s->options, "status-left"), t, 1); *size = options_get_number(&s->options, "status-left-length"); leftlen = screen_write_cstrlen(utf8flag, "%s", left); @@ -110,8 +110,8 @@ status_redraw_get_right(struct client *c, if (attr != 0) gc->attr = attr; - right = status_replace( - c, NULL, options_get_string(&s->options, "status-right"), t, 1); + right = status_replace(c, NULL, + NULL, NULL, options_get_string(&s->options, "status-right"), t, 1); *size = options_get_number(&s->options, "status-right-length"); rightlen = screen_write_cstrlen(utf8flag, "%s", right); @@ -347,16 +347,20 @@ out: /* Replace a single special sequence (prefixed by #). */ void -status_replace1(struct client *c,struct winlink *wl, - char **iptr, char **optr, char *out, size_t outsize, int jobsflag) +status_replace1(struct client *c, struct session *s, struct winlink *wl, + struct window_pane *wp, char **iptr, char **optr, char *out, + size_t outsize, int jobsflag) { - struct session *s = c->session; - char ch, tmp[256], *ptr, *endptr, *freeptr; - size_t ptrlen; - long limit; + char ch, tmp[256], *ptr, *endptr, *freeptr; + size_t ptrlen; + long limit; + if (s == NULL) + s = c->session; if (wl == NULL) wl = s->curw; + if (wp == NULL) + wp = wl->window->active; errno = 0; limit = strtol(*iptr, &endptr, 10); @@ -379,6 +383,10 @@ status_replace1(struct client *c,struct winlink *wl, if ((ptr = status_find_job(c, iptr)) == NULL) return; goto do_replace; + case 'D': + xsnprintf(tmp, sizeof tmp, "%%%u", wp->id); + ptr = tmp; + goto do_replace; case 'H': if (gethostname(tmp, sizeof tmp) != 0) fatal("gethostname failed"); @@ -389,15 +397,15 @@ status_replace1(struct client *c,struct winlink *wl, ptr = tmp; goto do_replace; case 'P': - xsnprintf(tmp, sizeof tmp, "%u", - window_pane_index(wl->window, wl->window->active)); + xsnprintf( + tmp, sizeof tmp, "%u", window_pane_index(wl->window, wp)); ptr = tmp; goto do_replace; case 'S': ptr = s->name; goto do_replace; case 'T': - ptr = wl->window->active->base.title; + ptr = wp->base.title; goto do_replace; case 'W': ptr = wl->window->name; @@ -449,8 +457,8 @@ skip_to: /* Replace special sequences in fmt. */ char * -status_replace(struct client *c, - struct winlink *wl, const char *fmt, time_t t, int jobsflag) +status_replace(struct client *c, struct session *s, struct winlink *wl, + struct window_pane *wp, const char *fmt, time_t t, int jobsflag) { static char out[BUFSIZ]; char in[BUFSIZ], ch, *iptr, *optr; @@ -470,7 +478,8 @@ status_replace(struct client *c, *optr++ = ch; continue; } - status_replace1(c, wl, &iptr, &optr, out, sizeof out, jobsflag); + status_replace1( + c, s, wl, wp, &iptr, &optr, out, sizeof out, jobsflag); } *optr = '\0'; @@ -657,7 +666,7 @@ status_print( gc->attr = attr; } - text = status_replace(c, wl, fmt, t, 1); + text = status_replace(c, NULL, wl, NULL, fmt, t, 1); return (text); } diff --git a/tmux.1 b/tmux.1 index 939a4333..d2842374 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2611,7 +2611,8 @@ This command works only from inside .Nm . .It Xo Ic display-message .Op Fl p -.Op Fl t Ar target-client +.Op Fl c Ar target-client +.Op Fl t Ar target-pane .Op Ar message .Xc .D1 (alias: Ic display ) @@ -2625,7 +2626,12 @@ The format of .Ar message is as for .Ic status-left , -with the exception that #() are not handled. +with the exception that #() are not handled; information is taken from +.Ar target-pane +if +.Fl t +is given, otherwise the active pane for the session attached to +.Ar target-client . .El .Sh BUFFERS .Nm diff --git a/tmux.h b/tmux.h index 5d271a57..b3e9868f 100644 --- a/tmux.h +++ b/tmux.h @@ -1666,8 +1666,8 @@ RB_PROTOTYPE(status_out_tree, status_out, entry, status_out_cmp); void status_free_jobs(struct status_out_tree *); void status_update_jobs(struct client *); int status_redraw(struct client *); -char *status_replace( - struct client *, struct winlink *, const char *, time_t, int); +char *status_replace(struct client *, struct session *, + struct winlink *, struct window_pane *, const char *, time_t, int); void printflike2 status_message_set(struct client *, const char *, ...); void status_message_clear(struct client *); int status_message_redraw(struct client *); From 25d551e8b257699a3066b6aae247d97d8ddf7c7a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 29 Mar 2011 20:31:22 +0000 Subject: [PATCH 0876/1180] Update an out-of-date and inaccurate comment. --- cmd-set-option.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/cmd-set-option.c b/cmd-set-option.c index 2155bba0..13fc5eb8 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -166,11 +166,7 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) server_redraw_client(c); } - /* - * Special-case: kill all persistent jobs if status-left, status-right - * or set-titles-string have changed. Persistent jobs are only used by - * the status line at the moment so this works XXX. - */ + /* Force redraw when some special cases change. */ if (strcmp(oe->name, "status-left") == 0 || strcmp(oe->name, "status-right") == 0 || strcmp(oe->name, "status") == 0 || From beb6db9b5f60b34b69b8cbe44a6422e84f582465 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 29 Mar 2011 21:07:08 +0000 Subject: [PATCH 0877/1180] Checking for particular options and redrawing is not necessary as we already redraw unconditionally. --- cmd-set-option.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/cmd-set-option.c b/cmd-set-option.c index 13fc5eb8..fffbc5b4 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -166,19 +166,6 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) server_redraw_client(c); } - /* Force redraw when some special cases change. */ - if (strcmp(oe->name, "status-left") == 0 || - strcmp(oe->name, "status-right") == 0 || - strcmp(oe->name, "status") == 0 || - strcmp(oe->name, "set-titles-string") == 0 || - strcmp(oe->name, "window-status-format") == 0) { - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - c = ARRAY_ITEM(&clients, i); - if (c != NULL && c->session != NULL) - server_redraw_client(c); - } - } - return (0); } From f7e9aedf10b2165838daf40b6a71ab764f0a0dee Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 29 Mar 2011 21:09:13 +0000 Subject: [PATCH 0878/1180] For convenience, work out what type of option is being set by name regardless of the -s or -w flags (these remain documented however). --- cmd-set-option.c | 111 +++++++++++++++++++++++++++++------------------ 1 file changed, 68 insertions(+), 43 deletions(-) diff --git a/cmd-set-option.c b/cmd-set-option.c index fffbc5b4..a0f7f447 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -29,6 +29,9 @@ int cmd_set_option_exec(struct cmd *, struct cmd_ctx *); +int cmd_set_option_find(const char *, const struct options_table_entry **, + const struct options_table_entry **); + int cmd_set_option_unset(struct cmd *, struct cmd_ctx *, const struct options_table_entry *, struct options *, const char *); @@ -78,11 +81,44 @@ const struct cmd_entry cmd_set_window_option_entry = { cmd_set_option_exec }; +/* Look for an option in all three tables. */ +int +cmd_set_option_find( + const char *optstr, const struct options_table_entry **table, + const struct options_table_entry **oe) +{ + static const struct options_table_entry *tables[] = { + server_options_table, + window_options_table, + session_options_table + }; + const struct options_table_entry *oe_loop; + u_int i; + + for (i = 0; i < nitems(tables); i++) { + for (oe_loop = tables[i]; oe_loop->name != NULL; oe_loop++) { + if (strncmp(oe_loop->name, optstr, strlen(optstr)) != 0) + continue; + + /* If already found, ambiguous. */ + if (*oe != NULL) + return (-1); + *oe = oe_loop; + *table = tables[i]; + + /* Bail now if an exact match. */ + if (strcmp((*oe)->name, optstr) == 0) + break; + } + } + return (0); +} + int cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; - const struct options_table_entry *table, *oe, *oe_loop; + const struct options_table_entry *table, *oe; struct session *s; struct winlink *wl; struct client *c; @@ -90,33 +126,6 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) const char *optstr, *valstr; u_int i; - /* Work out the options tree and table to use. */ - if (args_has(self->args, 's')) { - oo = &global_options; - table = server_options_table; - } else if (args_has(self->args, 'w') || - self->entry == &cmd_set_window_option_entry) { - table = window_options_table; - if (args_has(self->args, 'g')) - oo = &global_w_options; - else { - wl = cmd_find_window(ctx, args_get(args, 't'), NULL); - if (wl == NULL) - return (-1); - oo = &wl->window->options; - } - } else { - table = session_options_table; - if (args_has(self->args, 'g')) - oo = &global_s_options; - else { - s = cmd_find_session(ctx, args_get(args, 't')); - if (s == NULL) - return (-1); - oo = &s->options; - } - } - /* Get the option name and value. */ optstr = args->argv[0]; if (*optstr == '\0') { @@ -128,27 +137,43 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) else valstr = args->argv[1]; - /* Find the option table entry. */ - oe = NULL; - for (oe_loop = table; oe_loop->name != NULL; oe_loop++) { - if (strncmp(oe_loop->name, optstr, strlen(optstr)) != 0) - continue; - - if (oe != NULL) { - ctx->error(ctx, "ambiguous option: %s", optstr); - return (-1); - } - oe = oe_loop; - - /* Bail now if an exact match. */ - if (strcmp(oe->name, optstr) == 0) - break; + /* Find the option entry, try each table. */ + table = oe = NULL; + if (cmd_set_option_find(optstr, &table, &oe) != 0) { + ctx->error(ctx, "ambiguous option: %s", optstr); + return (-1); } if (oe == NULL) { ctx->error(ctx, "unknown option: %s", optstr); return (-1); } + /* Work out the tree from the table. */ + if (table == server_options_table) + oo = &global_options; + else if (table == window_options_table) { + if (args_has(self->args, 'g')) + oo = &global_w_options; + else { + wl = cmd_find_window(ctx, args_get(args, 't'), NULL); + if (wl == NULL) + return (-1); + oo = &wl->window->options; + } + } else if (table == session_options_table) { + if (args_has(self->args, 'g')) + oo = &global_s_options; + else { + s = cmd_find_session(ctx, args_get(args, 't')); + if (s == NULL) + return (-1); + oo = &s->options; + } + } else { + ctx->error(ctx, "unknown table"); + return (-1); + } + /* Unset or set the option. */ if (args_has(args, 'u')) { if (cmd_set_option_unset(self, ctx, oe, oo, valstr) != 0) From f8a218882af6dbdbf0fb8edb0db2962c3eb095a4 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 1 Apr 2011 16:59:11 +0000 Subject: [PATCH 0879/1180] "or" should be on a line on its own here so it is not emphasised as well. --- tmux.1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tmux.1 b/tmux.1 index d2842374..3b563b2c 100644 --- a/tmux.1 +++ b/tmux.1 @@ -433,7 +433,8 @@ One of the strings .Em right , .Em top-left , .Em top-right , -.Em bottom-left or +.Em bottom-left +or .Em bottom-right may be used instead of a pane index. .Pp From f16ea60cc0eceeb1e0bd580129d99aff4423ec19 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 5 Apr 2011 18:55:38 +0000 Subject: [PATCH 0880/1180] Bind C-u to delete-line in vi mode like ksh does, suggested by thib. --- mode-key.c | 1 + 1 file changed, 1 insertion(+) diff --git a/mode-key.c b/mode-key.c index 1edccbef..823c4429 100644 --- a/mode-key.c +++ b/mode-key.c @@ -123,6 +123,7 @@ const struct mode_key_cmdstr mode_key_cmdstr_copy[] = { const struct mode_key_entry mode_key_vi_edit[] = { { '\003' /* C-c */, 0, MODEKEYEDIT_CANCEL }, { '\010' /* C-h */, 0, MODEKEYEDIT_BACKSPACE }, + { '\025' /* C-u */, 0, MODEKEYEDIT_DELETELINE }, { '\011' /* Tab */, 0, MODEKEYEDIT_COMPLETE }, { '\033' /* Escape */, 0, MODEKEYEDIT_SWITCHMODE }, { '\r', 0, MODEKEYEDIT_ENTER }, From 5d519ba526feffb08003e2c11c7230a6f2cc1d9e Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 5 Apr 2011 19:37:01 +0000 Subject: [PATCH 0881/1180] Add a flag to cmd_find_session so that attach-session can prefer unattached sessions when choosing the most recently used (if -t is not given). Suggested by claudio@. --- cmd-attach-session.c | 2 +- cmd-has-session.c | 2 +- cmd-kill-session.c | 2 +- cmd-list-panes.c | 2 +- cmd-list-windows.c | 2 +- cmd-lock-server.c | 2 +- cmd-new-session.c | 2 +- cmd-rename-session.c | 2 +- cmd-select-window.c | 2 +- cmd-set-environment.c | 2 +- cmd-set-option.c | 2 +- cmd-show-buffer.c | 2 +- cmd-show-environment.c | 2 +- cmd-show-options.c | 2 +- cmd-switch-client.c | 2 +- cmd.c | 32 +++++++++++++++++++------------- tmux.1 | 11 +++++++++++ tmux.h | 4 ++-- 18 files changed, 47 insertions(+), 30 deletions(-) diff --git a/cmd-attach-session.c b/cmd-attach-session.c index f320056d..1a1e3c5c 100644 --- a/cmd-attach-session.c +++ b/cmd-attach-session.c @@ -51,7 +51,7 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx) return (-1); } - if ((s = cmd_find_session(ctx, args_get(args, 't'))) == NULL) + if ((s = cmd_find_session(ctx, args_get(args, 't'), 1)) == NULL) return (-1); if (ctx->cmdclient == NULL && ctx->curclient == NULL) diff --git a/cmd-has-session.c b/cmd-has-session.c index d5d806a1..cfaf032b 100644 --- a/cmd-has-session.c +++ b/cmd-has-session.c @@ -41,7 +41,7 @@ cmd_has_session_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; - if (cmd_find_session(ctx, args_get(args, 't')) == NULL) + if (cmd_find_session(ctx, args_get(args, 't'), 0) == NULL) return (-1); return (0); diff --git a/cmd-kill-session.c b/cmd-kill-session.c index 086dbc67..69caef9e 100644 --- a/cmd-kill-session.c +++ b/cmd-kill-session.c @@ -45,7 +45,7 @@ cmd_kill_session_exec(struct cmd *self, struct cmd_ctx *ctx) struct args *args = self->args; struct session *s; - if ((s = cmd_find_session(ctx, args_get(args, 't'))) == NULL) + if ((s = cmd_find_session(ctx, args_get(args, 't'), 0)) == NULL) return (-1); server_destroy_session(s); diff --git a/cmd-list-panes.c b/cmd-list-panes.c index 830b8620..60324e64 100644 --- a/cmd-list-panes.c +++ b/cmd-list-panes.c @@ -52,7 +52,7 @@ cmd_list_panes_exec(struct cmd *self, struct cmd_ctx *ctx) if (args_has(args, 'a')) cmd_list_panes_server(ctx); else if (args_has(args, 's')) { - s = cmd_find_session(ctx, args_get(args, 't')); + s = cmd_find_session(ctx, args_get(args, 't'), 0); if (s == NULL) return (-1); cmd_list_panes_session(s, ctx); diff --git a/cmd-list-windows.c b/cmd-list-windows.c index 9233ab75..11d38412 100644 --- a/cmd-list-windows.c +++ b/cmd-list-windows.c @@ -50,7 +50,7 @@ cmd_list_windows_exec(struct cmd *self, struct cmd_ctx *ctx) if (args_has(args, 'a')) cmd_list_windows_server(ctx); else { - s = cmd_find_session(ctx, args_get(args, 't')); + s = cmd_find_session(ctx, args_get(args, 't'), 0); if (s == NULL) return (-1); cmd_list_windows_session(s, ctx); diff --git a/cmd-lock-server.c b/cmd-lock-server.c index 955de11f..ecbcee9b 100644 --- a/cmd-lock-server.c +++ b/cmd-lock-server.c @@ -71,7 +71,7 @@ cmd_lock_server_exec(struct cmd *self, unused struct cmd_ctx *ctx) if (self->entry == &cmd_lock_server_entry) server_lock(); else if (self->entry == &cmd_lock_session_entry) { - if ((s = cmd_find_session(ctx, args_get(args, 't'))) == NULL) + if ((s = cmd_find_session(ctx, args_get(args, 't'), 0)) == NULL) return (-1); server_lock_session(s); } else { diff --git a/cmd-new-session.c b/cmd-new-session.c index f5e1316f..fc847bd2 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -75,7 +75,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) target = args_get(args, 't'); if (target != NULL) { - groupwith = cmd_find_session(ctx, target); + groupwith = cmd_find_session(ctx, target, 0); if (groupwith == NULL) return (-1); } else diff --git a/cmd-rename-session.c b/cmd-rename-session.c index 9ca43a7d..018e537f 100644 --- a/cmd-rename-session.c +++ b/cmd-rename-session.c @@ -51,7 +51,7 @@ cmd_rename_session_exec(struct cmd *self, struct cmd_ctx *ctx) return (-1); } - if ((s = cmd_find_session(ctx, args_get(args, 't'))) == NULL) + if ((s = cmd_find_session(ctx, args_get(args, 't'), 0)) == NULL) return (-1); RB_REMOVE(sessions, &sessions, s); diff --git a/cmd-select-window.c b/cmd-select-window.c index 0e1b9543..2e076ae9 100644 --- a/cmd-select-window.c +++ b/cmd-select-window.c @@ -102,7 +102,7 @@ cmd_select_window_exec(struct cmd *self, struct cmd_ctx *ctx) last = 1; if (next || previous || last) { - s = cmd_find_session(ctx, args_get(args, 't')); + s = cmd_find_session(ctx, args_get(args, 't'), 0); if (s == NULL) return (-1); diff --git a/cmd-set-environment.c b/cmd-set-environment.c index 3075fb07..b43de458 100644 --- a/cmd-set-environment.c +++ b/cmd-set-environment.c @@ -65,7 +65,7 @@ cmd_set_environment_exec(struct cmd *self, struct cmd_ctx *ctx) if (args_has(self->args, 'g')) env = &global_environ; else { - if ((s = cmd_find_session(ctx, args_get(args, 't'))) == NULL) + if ((s = cmd_find_session(ctx, args_get(args, 't'), 0)) == NULL) return (-1); env = &s->environ; } diff --git a/cmd-set-option.c b/cmd-set-option.c index a0f7f447..9ddfba9c 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -164,7 +164,7 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) if (args_has(self->args, 'g')) oo = &global_s_options; else { - s = cmd_find_session(ctx, args_get(args, 't')); + s = cmd_find_session(ctx, args_get(args, 't'), 0); if (s == NULL) return (-1); oo = &s->options; diff --git a/cmd-show-buffer.c b/cmd-show-buffer.c index 256818f5..23490169 100644 --- a/cmd-show-buffer.c +++ b/cmd-show-buffer.c @@ -49,7 +49,7 @@ cmd_show_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) size_t size, len; u_int width; - if ((s = cmd_find_session(ctx, NULL)) == NULL) + if ((s = cmd_find_session(ctx, NULL, 0)) == NULL) return (-1); if (!args_has(args, 'b')) { diff --git a/cmd-show-environment.c b/cmd-show-environment.c index f52efbca..e84ff685 100644 --- a/cmd-show-environment.c +++ b/cmd-show-environment.c @@ -50,7 +50,7 @@ cmd_show_environment_exec(struct cmd *self, struct cmd_ctx *ctx) if (args_has(self->args, 'g')) env = &global_environ; else { - if ((s = cmd_find_session(ctx, args_get(args, 't'))) == NULL) + if ((s = cmd_find_session(ctx, args_get(args, 't'), 0)) == NULL) return (-1); env = &s->environ; } diff --git a/cmd-show-options.c b/cmd-show-options.c index cc11ed64..2a4adb0f 100644 --- a/cmd-show-options.c +++ b/cmd-show-options.c @@ -79,7 +79,7 @@ cmd_show_options_exec(struct cmd *self, struct cmd_ctx *ctx) if (args_has(self->args, 'g')) oo = &global_s_options; else { - s = cmd_find_session(ctx, args_get(args, 't')); + s = cmd_find_session(ctx, args_get(args, 't'), 0); if (s == NULL) return (-1); oo = &s->options; diff --git a/cmd-switch-client.c b/cmd-switch-client.c index 66eae88b..25a57965 100644 --- a/cmd-switch-client.c +++ b/cmd-switch-client.c @@ -86,7 +86,7 @@ cmd_switch_client_exec(struct cmd *self, struct cmd_ctx *ctx) return (-1); } } else - s = cmd_find_session(ctx, args_get(args, 't')); + s = cmd_find_session(ctx, args_get(args, 't'), 0); if (s == NULL) return (-1); diff --git a/cmd.c b/cmd.c index 11910aac..ac66f6e8 100644 --- a/cmd.c +++ b/cmd.c @@ -112,7 +112,7 @@ const struct cmd_entry *cmd_table[] = { }; struct session *cmd_choose_session_list(struct sessionslist *); -struct session *cmd_choose_session(void); +struct session *cmd_choose_session(int); struct client *cmd_choose_client(struct clients *); struct client *cmd_lookup_client(const char *); struct session *cmd_lookup_session(const char *, int *); @@ -316,7 +316,7 @@ cmd_print(struct cmd *cmd, char *buf, size_t len) * session from all sessions. */ struct session * -cmd_current_session(struct cmd_ctx *ctx) +cmd_current_session(struct cmd_ctx *ctx, int prefer_unattached) { struct msg_command_data *data = ctx->msgdata; struct client *c = ctx->cmdclient; @@ -365,19 +365,25 @@ cmd_current_session(struct cmd_ctx *ctx) return (s); } - return (cmd_choose_session()); + return (cmd_choose_session(prefer_unattached)); } -/* Find the most recently used session. */ +/* + * Find the most recently used session, preferring unattached if the flag is + * set. + */ struct session * -cmd_choose_session(void) +cmd_choose_session(int prefer_unattached) { struct session *s, *sbest; struct timeval *tv = NULL; sbest = NULL; RB_FOREACH(s, sessions, &sessions) { - if (tv == NULL || timercmp(&s->activity_time, tv, >)) { + if (tv == NULL || timercmp(&s->activity_time, tv, >) || + (prefer_unattached && + !(sbest->flags & SESSION_UNATTACHED) && + (s->flags & SESSION_UNATTACHED))) { sbest = s; tv = &s->activity_time; } @@ -428,7 +434,7 @@ cmd_current_client(struct cmd_ctx *ctx) * No current client set. Find the current session and return the * newest of its clients. */ - s = cmd_current_session(ctx); + s = cmd_current_session(ctx, 0); if (s != NULL && !(s->flags & SESSION_UNATTACHED)) { ARRAY_INIT(&cc); for (i = 0; i < ARRAY_LENGTH(&clients); i++) { @@ -671,7 +677,7 @@ cmd_pane_session(struct cmd_ctx *ctx, struct window_pane *wp, struct winlink *wl; /* If this pane is in the current session, return that winlink. */ - s = cmd_current_session(ctx); + s = cmd_current_session(ctx, 0); if (s != NULL) { wl = winlink_find_by_window(&s->windows, wp->window); if (wl != NULL) { @@ -696,7 +702,7 @@ cmd_pane_session(struct cmd_ctx *ctx, struct window_pane *wp, /* Find the target session or report an error and return NULL. */ struct session * -cmd_find_session(struct cmd_ctx *ctx, const char *arg) +cmd_find_session(struct cmd_ctx *ctx, const char *arg, int prefer_unattached) { struct session *s; struct window_pane *wp; @@ -707,7 +713,7 @@ cmd_find_session(struct cmd_ctx *ctx, const char *arg) /* A NULL argument means the current session. */ if (arg == NULL) - return (cmd_current_session(ctx)); + return (cmd_current_session(ctx, prefer_unattached)); tmparg = xstrdup(arg); /* Lookup as pane id. */ @@ -753,7 +759,7 @@ cmd_find_window(struct cmd_ctx *ctx, const char *arg, struct session **sp) * Find the current session. There must always be a current session, if * it can't be found, report an error. */ - if ((s = cmd_current_session(ctx)) == NULL) { + if ((s = cmd_current_session(ctx, 0)) == NULL) { ctx->error(ctx, "can't establish current session"); return (NULL); } @@ -900,7 +906,7 @@ cmd_find_index(struct cmd_ctx *ctx, const char *arg, struct session **sp) * Find the current session. There must always be a current session, if * it can't be found, report an error. */ - if ((s = cmd_current_session(ctx)) == NULL) { + if ((s = cmd_current_session(ctx, 0)) == NULL) { ctx->error(ctx, "can't establish current session"); return (-2); } @@ -1054,7 +1060,7 @@ cmd_find_pane(struct cmd_ctx *ctx, u_int idx; /* Get the current session. */ - if ((s = cmd_current_session(ctx)) == NULL) { + if ((s = cmd_current_session(ctx, 0)) == NULL) { ctx->error(ctx, "can't establish current session"); return (NULL); } diff --git a/tmux.1 b/tmux.1 index 3b563b2c..7c5ea455 100644 --- a/tmux.1 +++ b/tmux.1 @@ -562,6 +562,17 @@ If no server is started, .Ic attach-session will attempt to start it; this will fail unless sessions are created in the configuration file. +.Pp +The +.Ar target-session +rules for +.Ic attach-session +are slightly adjusted: if +.Nm +needs to select the most recently used session, it will prefer the most +recently used +.Em unattached +session. .It Xo Ic detach-client .Op Fl P .Op Fl t Ar target-client diff --git a/tmux.h b/tmux.h index b3e9868f..a2af2a87 100644 --- a/tmux.h +++ b/tmux.h @@ -1487,10 +1487,10 @@ struct cmd *cmd_parse(int, char **, char **); int cmd_exec(struct cmd *, struct cmd_ctx *); void cmd_free(struct cmd *); size_t cmd_print(struct cmd *, char *, size_t); -struct session *cmd_current_session(struct cmd_ctx *); +struct session *cmd_current_session(struct cmd_ctx *, int); struct client *cmd_current_client(struct cmd_ctx *); struct client *cmd_find_client(struct cmd_ctx *, const char *); -struct session *cmd_find_session(struct cmd_ctx *, const char *); +struct session *cmd_find_session(struct cmd_ctx *, const char *, int); struct winlink *cmd_find_window( struct cmd_ctx *, const char *, struct session **); int cmd_find_index( From c8a14def9f2273c13d081c891d76e5f32323fc40 Mon Sep 17 00:00:00 2001 From: Miod Vallat Date: Wed, 6 Apr 2011 11:36:26 +0000 Subject: [PATCH 0882/1180] Avoid using NULL in non-pointer contexts: use 0 for integer values and '\0' for chars. --- cmd-display-message.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd-display-message.c b/cmd-display-message.c index dfa8312f..b2cf832b 100644 --- a/cmd-display-message.c +++ b/cmd-display-message.c @@ -52,7 +52,7 @@ cmd_display_message_exec(struct cmd *self, struct cmd_ctx *ctx) if ((c = cmd_find_client(ctx, args_get(args, 'c'))) == NULL) return (-1); - if (args_has(args, 't') != NULL) { + if (args_has(args, 't') != 0) { wl = cmd_find_pane(ctx, args_get(args, 't'), &s, &wp); if (wl == NULL) return (-1); From ec89eb955236f91e63febe1764123e605641fc52 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 6 Apr 2011 21:51:31 +0000 Subject: [PATCH 0883/1180] Change so that an empty session name always means the current sessions even if given with, for example, -t '', and explicitly forbid empty session names and those containing a : when they are created. --- cmd-new-session.c | 12 +++++++++--- cmd-rename-session.c | 4 ++++ cmd.c | 10 ++++++++-- session.c | 7 +++++++ tmux.h | 1 + 5 files changed, 29 insertions(+), 5 deletions(-) diff --git a/cmd-new-session.c b/cmd-new-session.c index fc847bd2..5eaa5393 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -68,9 +68,15 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) u_int sx, sy, i; newname = args_get(args, 's'); - if (newname != NULL && session_find(newname) != NULL) { - ctx->error(ctx, "duplicate session: %s", newname); - return (-1); + if (newname != NULL) { + if (!session_check_name(newname)) { + ctx->error(ctx, "bad session name: %s", newname); + return (-1); + } + if (session_find(newname) != NULL) { + ctx->error(ctx, "duplicate session: %s", newname); + return (-1); + } } target = args_get(args, 't'); diff --git a/cmd-rename-session.c b/cmd-rename-session.c index 018e537f..cbda700f 100644 --- a/cmd-rename-session.c +++ b/cmd-rename-session.c @@ -46,6 +46,10 @@ cmd_rename_session_exec(struct cmd *self, struct cmd_ctx *ctx) const char *newname; newname = args->argv[0]; + if (!session_check_name(newname)) { + ctx->error(ctx, "bad session name: %s", newname); + return (-1); + } if (session_find(newname) != NULL) { ctx->error(ctx, "duplicate session: %s", newname); return (-1); diff --git a/cmd.c b/cmd.c index ac66f6e8..ee893a25 100644 --- a/cmd.c +++ b/cmd.c @@ -725,6 +725,12 @@ cmd_find_session(struct cmd_ctx *ctx, const char *arg, int prefer_unattached) if (arglen != 0 && tmparg[arglen - 1] == ':') tmparg[arglen - 1] = '\0'; + /* An empty session name is the current session. */ + if (*tmparg == '\0') { + xfree (tmparg); + return (cmd_current_session(ctx, prefer_unattached)); + } + /* Find the session, if any. */ s = cmd_lookup_session(tmparg, &ambiguous); @@ -840,7 +846,7 @@ no_colon: lookup_session: if (ambiguous) goto not_found; - if ((s = cmd_lookup_session(arg, &ambiguous)) == NULL) + if (*arg != '\0' && (s = cmd_lookup_session(arg, &ambiguous)) == NULL) goto no_session; if (sp != NULL) @@ -981,7 +987,7 @@ no_colon: lookup_session: if (ambiguous) goto not_found; - if ((s = cmd_lookup_session(arg, &ambiguous)) == NULL) + if (*arg != '\0' && (s = cmd_lookup_session(arg, &ambiguous)) == NULL) goto no_session; if (sp != NULL) diff --git a/session.c b/session.c index 9babd81c..e9bffed2 100644 --- a/session.c +++ b/session.c @@ -164,6 +164,13 @@ session_destroy(struct session *s) RB_INSERT(sessions, &dead_sessions, s); } +/* Check a session name is valid: not empty and no colons. */ +int +session_check_name(const char *name) +{ + return (*name != '\0' && strchr(name, ':') == NULL); +} + /* Update session active time. */ void session_update_activity(struct session *s) diff --git a/tmux.h b/tmux.h index a2af2a87..12f68085 100644 --- a/tmux.h +++ b/tmux.h @@ -1978,6 +1978,7 @@ struct session *session_create(const char *, const char *, const char *, struct environ *, struct termios *, int, u_int, u_int, char **); void session_destroy(struct session *); +int session_check_name(const char *); void session_update_activity(struct session *); struct session *session_next_session(struct session *); struct session *session_previous_session(struct session *); From 0a09d04e1b63f816fb2bf16570ef63418349a4bf Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 9 Apr 2011 07:48:08 +0000 Subject: [PATCH 0884/1180] If the terminal supports sitm for italics, use it instead of standout (smso). From Tiago Resende. --- tmux.h | 1 + tty-term.c | 1 + tty.c | 7 ++++++- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/tmux.h b/tmux.h index 12f68085..36dcf273 100644 --- a/tmux.h +++ b/tmux.h @@ -323,6 +323,7 @@ enum tty_code_code { TTYC_SMKX, /* keypad_xmit, ks */ TTYC_SMSO, /* enter_standout_mode, so */ TTYC_SMUL, /* enter_underline_mode, us */ + TTYC_SITM, /* enter_italics_mode, it */ TTYC_VPA, /* row_address, cv */ TTYC_XENL, /* eat_newline_glitch, xn */ }; diff --git a/tty-term.c b/tty-term.c index 943f1e4d..59a1bbba 100644 --- a/tty-term.c +++ b/tty-term.c @@ -178,6 +178,7 @@ const struct tty_term_code_entry tty_term_codes[NTTYCODE] = { { TTYC_SMKX, TTYCODE_STRING, "smkx" }, { TTYC_SMSO, TTYCODE_STRING, "smso" }, { TTYC_SMUL, TTYCODE_STRING, "smul" }, + { TTYC_SITM, TTYCODE_STRING, "sitm" }, { TTYC_VPA, TTYCODE_STRING, "vpa" }, { TTYC_XENL, TTYCODE_FLAG, "xenl" }, }; diff --git a/tty.c b/tty.c index bffb1f93..73dff0be 100644 --- a/tty.c +++ b/tty.c @@ -1218,7 +1218,12 @@ tty_attributes(struct tty *tty, const struct grid_cell *gc) if (changed & GRID_ATTR_DIM) tty_putcode(tty, TTYC_DIM); if (changed & GRID_ATTR_ITALICS) - tty_putcode(tty, TTYC_SMSO); + { + if (tty_term_has(tty->term, TTYC_SITM)) + tty_putcode(tty, TTYC_SITM); + else + tty_putcode(tty, TTYC_SMSO); + } if (changed & GRID_ATTR_UNDERSCORE) tty_putcode(tty, TTYC_SMUL); if (changed & GRID_ATTR_BLINK) From 48a1169f4e16ac90a28cafeca15c3237fe9591b1 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 9 Apr 2011 20:00:29 +0000 Subject: [PATCH 0885/1180] Since buffers are now global, bump the default buffer-limit a bit higher to 20 rather than 9. --- options-table.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/options-table.c b/options-table.c index f8f99314..e91222d3 100644 --- a/options-table.c +++ b/options-table.c @@ -55,7 +55,7 @@ const struct options_table_entry server_options_table[] = { .type = OPTIONS_TABLE_NUMBER, .minimum = 1, .maximum = INT_MAX, - .default_num = 9 + .default_num = 20 }, { .name = "escape-time", From 98d450ac3adddd87b306a9f16d4738523b60a4ab Mon Sep 17 00:00:00 2001 From: Philip Guenther Date: Sun, 10 Apr 2011 03:20:59 +0000 Subject: [PATCH 0886/1180] Switch back from KERN_PROC2/kinfo_proc2 to KERN_PROC/kinfo_proc now that we've got name we want for the API we want "ZAP!" deraadt@ --- procname.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/procname.c b/procname.c index 064e0db2..30f71847 100644 --- a/procname.c +++ b/procname.c @@ -34,11 +34,11 @@ #define is_stopped(p) \ ((p)->p_stat == SSTOP || (p)->p_stat == SZOMB || (p)->p_stat == SDEAD) -struct kinfo_proc2 *cmp_procs(struct kinfo_proc2 *, struct kinfo_proc2 *); +struct kinfo_proc *cmp_procs(struct kinfo_proc *, struct kinfo_proc *); char *get_proc_name(int, char *); -struct kinfo_proc2 * -cmp_procs(struct kinfo_proc2 *p1, struct kinfo_proc2 *p2) +struct kinfo_proc * +cmp_procs(struct kinfo_proc *p1, struct kinfo_proc *p2) { if (is_runnable(p1) && !is_runnable(p2)) return (p1); @@ -78,11 +78,11 @@ cmp_procs(struct kinfo_proc2 *p1, struct kinfo_proc2 *p2) char * get_proc_name(int fd, char *tty) { - int mib[6] = { CTL_KERN, KERN_PROC2, KERN_PROC_PGRP, 0, - sizeof(struct kinfo_proc2), 0 }; + int mib[6] = { CTL_KERN, KERN_PROC, KERN_PROC_PGRP, 0, + sizeof(struct kinfo_proc), 0 }; struct stat sb; size_t len; - struct kinfo_proc2 *buf, *newbuf, *bestp; + struct kinfo_proc *buf, *newbuf, *bestp; u_int i; char *name; @@ -102,7 +102,7 @@ retry: goto error; buf = newbuf; - mib[5] = (int)(len / sizeof(struct kinfo_proc2)); + mib[5] = (int)(len / sizeof(struct kinfo_proc)); if (sysctl(mib, nitems(mib), buf, &len, NULL, 0) == -1) { if (errno == ENOMEM) goto retry; @@ -110,7 +110,7 @@ retry: } bestp = NULL; - for (i = 0; i < len / sizeof (struct kinfo_proc2); i++) { + for (i = 0; i < len / sizeof (struct kinfo_proc); i++) { if ((dev_t)buf[i].p_tdev != sb.st_rdev) continue; if (bestp == NULL) From 735f87bc668f72fa8c62e579fda82cca2a27f48e Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 11 Apr 2011 06:44:39 +0000 Subject: [PATCH 0887/1180] Add -s option to detach all clients attached to a session, from Zac Sprackett. --- cmd-detach-client.c | 30 ++++++++++++++++++++++++------ tmux.1 | 7 +++++-- 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/cmd-detach-client.c b/cmd-detach-client.c index 12723ac4..b9a2a910 100644 --- a/cmd-detach-client.c +++ b/cmd-detach-client.c @@ -28,7 +28,7 @@ int cmd_detach_client_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_detach_client_entry = { "detach-client", "detach", - "t:P", 0, 0, + "s:t:P", 0, 0, "[-P] " CMD_TARGET_CLIENT_USAGE, CMD_READONLY, NULL, @@ -41,14 +41,32 @@ cmd_detach_client_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; struct client *c; - - if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL) - return (-1); + struct session *s; + enum msgtype msgtype; + u_int i; if (args_has(args, 'P')) - server_write_client(c, MSG_DETACHKILL, NULL, 0); + msgtype = MSG_DETACHKILL; else - server_write_client(c, MSG_DETACH, NULL, 0); + msgtype = MSG_DETACH; + + if (args_has(args, 's')) { + s = cmd_find_session(ctx, args_get(args, 's'), 0); + if (s == NULL) + return (-1); + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c != NULL && c->session == s) + server_write_client(c, msgtype, NULL, 0); + } + } else { + c = cmd_find_client(ctx, args_get(args, 't')); + if (c == NULL) + return (-1); + + server_write_client(c, msgtype, NULL, 0); + } return (0); } diff --git a/tmux.1 b/tmux.1 index 7c5ea455..3450418c 100644 --- a/tmux.1 +++ b/tmux.1 @@ -576,10 +576,13 @@ session. .It Xo Ic detach-client .Op Fl P .Op Fl t Ar target-client +.Op Fl s Ar target-session .Xc .D1 (alias: Ic detach ) -Detach the current client if bound to a key, or the specified client with -.Fl t . +Detach the current client if bound to a key, the client specified with +.Fl t , +or all clients currently attached to to the session specified by +.Fl s . If .Fl P is given, send SIGHUP to the parent process of the client, typically causing it From 3dc7b805d3c5a5174b7dd431e4ac8099342c664f Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 11 Apr 2011 16:44:36 +0000 Subject: [PATCH 0888/1180] -s comes before -t and also add -s to command syntax. Prompted by jmc. --- cmd-detach-client.c | 2 +- tmux.1 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd-detach-client.c b/cmd-detach-client.c index b9a2a910..d8642757 100644 --- a/cmd-detach-client.c +++ b/cmd-detach-client.c @@ -29,7 +29,7 @@ int cmd_detach_client_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_detach_client_entry = { "detach-client", "detach", "s:t:P", 0, 0, - "[-P] " CMD_TARGET_CLIENT_USAGE, + "[-P] [-s target-session] " CMD_TARGET_CLIENT_USAGE, CMD_READONLY, NULL, NULL, diff --git a/tmux.1 b/tmux.1 index 3450418c..af0469c8 100644 --- a/tmux.1 +++ b/tmux.1 @@ -575,8 +575,8 @@ recently used session. .It Xo Ic detach-client .Op Fl P -.Op Fl t Ar target-client .Op Fl s Ar target-session +.Op Fl t Ar target-client .Xc .D1 (alias: Ic detach ) Detach the current client if bound to a key, the client specified with From 044c0f978f8faee76af943a11a93e46232b01e74 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 17 Apr 2011 19:21:19 +0000 Subject: [PATCH 0889/1180] Fix character position check, from Tiago Resende. --- screen-write.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/screen-write.c b/screen-write.c index fd4c7846..1fee190d 100644 --- a/screen-write.c +++ b/screen-write.c @@ -1048,7 +1048,7 @@ screen_write_cell(struct screen_write_ctx *ctx, /* Sanity checks. */ if (((s->mode & MODE_WRAP) && s->cx > screen_size_x(s) - width) - || s->cy > screen_size_y(s) - width) + || s->cy > screen_size_y(s) - 1) return; /* Handle overwriting of UTF-8 characters. */ From f4432030eedd6c628f34c20ff0a1a8abb2f73013 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 17 Apr 2011 19:28:09 +0000 Subject: [PATCH 0890/1180] Add -t to list-clients, based on a diff from Zac Sprackett. --- cmd-list-clients.c | 18 +++++++++++++++--- tmux.1 | 6 ++++-- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/cmd-list-clients.c b/cmd-list-clients.c index 026f12a7..2a4728b8 100644 --- a/cmd-list-clients.c +++ b/cmd-list-clients.c @@ -31,8 +31,8 @@ int cmd_list_clients_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_list_clients_entry = { "list-clients", "lsc", - "", 0, 0, - "", + "t:", 0, 0, + CMD_TARGET_SESSION_USAGE, 0, NULL, NULL, @@ -41,12 +41,21 @@ const struct cmd_entry cmd_list_clients_entry = { /* ARGSUSED */ int -cmd_list_clients_exec(unused struct cmd *self, struct cmd_ctx *ctx) +cmd_list_clients_exec(struct cmd *self, struct cmd_ctx *ctx) { + struct args *args = self->args; struct client *c; + struct session *s; u_int i; const char *s_utf8; + if (args_has(args, 't')) { + s = cmd_find_session(ctx, args_get(args, 't'), 0); + if (s == NULL) + return (-1); + } else + s = NULL; + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); if (c == NULL || c->session == NULL) @@ -56,6 +65,9 @@ cmd_list_clients_exec(unused struct cmd *self, struct cmd_ctx *ctx) s_utf8 = " (utf8)"; else s_utf8 = ""; + + if (s != NULL && s != c->session) + continue; ctx->print(ctx, "%s: %s [%ux%u %s]%s", c->tty.path, c->session->name, c->tty.sx, c->tty.sy, c->tty.termname, s_utf8); diff --git a/tmux.1 b/tmux.1 index af0469c8..8e9da6fe 100644 --- a/tmux.1 +++ b/tmux.1 @@ -598,9 +598,11 @@ server and clients and destroy all sessions. .It Ic kill-session Op Fl t Ar target-session Destroy the given session, closing any windows linked to it and no other sessions, and detaching all clients attached to it. -.It Ic list-clients +.It Ic list-clients Op Fl t Ar target-session .D1 (alias: Ic lsc ) -List all clients attached to the server. +List all clients attached to the server. If +.Ar target-session +is specified, list only clients connected to that session. .It Ic list-commands .D1 (alias: Ic lscm ) List the syntax of all commands supported by From 4e75e82cc35050a244193830bd4d252eee9ad323 Mon Sep 17 00:00:00 2001 From: Jason McIntyre Date: Sun, 17 Apr 2011 20:39:44 +0000 Subject: [PATCH 0891/1180] new sentence, new line; --- tmux.1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tmux.1 b/tmux.1 index 8e9da6fe..86332a2c 100644 --- a/tmux.1 +++ b/tmux.1 @@ -600,7 +600,8 @@ Destroy the given session, closing any windows linked to it and no other sessions, and detaching all clients attached to it. .It Ic list-clients Op Fl t Ar target-session .D1 (alias: Ic lsc ) -List all clients attached to the server. If +List all clients attached to the server. +If .Ar target-session is specified, list only clients connected to that session. .It Ic list-commands From 0bb211978121292518d59430e3547685882078bc Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 18 Apr 2011 19:49:05 +0000 Subject: [PATCH 0892/1180] Add an option (mouse-select-window) which allows the mouse to be used by clicking on the status line, written by hsim at gmx dot li. --- options-table.c | 5 +++++ server-client.c | 10 ++++++++++ status.c | 18 ++++++++++++++++++ tmux.1 | 5 +++++ tmux.h | 3 +++ 5 files changed, 41 insertions(+) diff --git a/options-table.c b/options-table.c index e91222d3..454dbffa 100644 --- a/options-table.c +++ b/options-table.c @@ -198,6 +198,11 @@ const struct options_table_entry session_options_table[] = { .default_num = 0 }, + { .name = "mouse-select-window", + .type = OPTIONS_TABLE_FLAG, + .default_num = 0 + }, + { .name = "mouse-utf8", .type = OPTIONS_TABLE_FLAG, .default_num = 0 diff --git a/server-client.c b/server-client.c index 66e5caf0..36bce79b 100644 --- a/server-client.c +++ b/server-client.c @@ -319,6 +319,12 @@ server_client_handle_key(int key, struct mouse_event *mouse, void *data) server_redraw_window_borders(w); wp = w->active; } + if (mouse->y + 1 == c->tty.sy && mouse->b == MOUSE_UP && + options_get_number(oo, "mouse-select-window") && + options_get_number(oo, "status")) { + status_set_window_at(c, mouse->x); + return; + } window_pane_mouse(wp, c->session, mouse); return; } @@ -459,6 +465,10 @@ server_client_reset_state(struct client *c) (mode & ALL_MOUSE_MODES) == 0) mode |= MODE_MOUSE_STANDARD; + if (options_get_number(oo, "mouse-select-window") && + (mode & ALL_MOUSE_MODES) == 0) + mode |= MODE_MOUSE_STANDARD; + /* * Set UTF-8 mouse input if required. If the terminal is UTF-8, the * user has set mouse-utf8 and any mouse mode is in effect, turn on diff --git a/status.c b/status.c index 0a777ce8..ecf19b25 100644 --- a/status.c +++ b/status.c @@ -120,6 +120,23 @@ status_redraw_get_right(struct client *c, return (right); } +/* Set window at window list position. */ +void +status_set_window_at(struct client *c, u_int x) +{ + struct session *s = c->session; + struct winlink *wl; + + x += s->wlmouse; + RB_FOREACH(wl, winlinks, &s->windows) { + if (x < wl->status_width && + session_select(s, wl->idx) == 0) { + server_redraw_session(s); + } + x -= wl->status_width + 1; + } +} + /* Draw status for client on the last lines of given context. */ int status_redraw(struct client *c) @@ -325,6 +342,7 @@ draw: wloffset++; /* Copy the window list. */ + s->wlmouse = -wloffset + wlstart; screen_write_cursormove(&ctx, wloffset, 0); screen_write_copy(&ctx, &window_list, wlstart, 0, wlwidth, 1); screen_free(&window_list); diff --git a/tmux.1 b/tmux.1 index 86332a2c..45292ed9 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1896,6 +1896,11 @@ If on, captures the mouse and when a window is split into multiple panes the mouse may be used to select the current pane. The mouse click is also passed through to the application as normal. +.It Xo Ic mouse-select-window +.Op Ic on | off +.Xc +If on, clicking the mouse on a window name in the status line will select that +window. .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. diff --git a/tmux.h b/tmux.h index 36dcf273..82bdc296 100644 --- a/tmux.h +++ b/tmux.h @@ -957,6 +957,8 @@ struct session { struct environ environ; + int wlmouse; + int references; TAILQ_ENTRY(session) gentry; @@ -1666,6 +1668,7 @@ int status_out_cmp(struct status_out *, struct status_out *); RB_PROTOTYPE(status_out_tree, status_out, entry, status_out_cmp); void status_free_jobs(struct status_out_tree *); void status_update_jobs(struct client *); +void status_set_window_at(struct client *, u_int); int status_redraw(struct client *); char *status_replace(struct client *, struct session *, struct winlink *, struct window_pane *, const char *, time_t, int); From 0f97ac42210a9eedb21c5add9b8c2fb52ef84881 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 18 Apr 2011 20:57:16 +0000 Subject: [PATCH 0893/1180] The mouse should only work in copy mode if mode-mouse is set, not just mouse-select-pane. --- window.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/window.c b/window.c index 4270013f..d5f56898 100644 --- a/window.c +++ b/window.c @@ -884,7 +884,8 @@ window_pane_mouse( m->y -= wp->yoff; if (wp->mode != NULL) { - if (wp->mode->mouse != NULL) + if (wp->mode->mouse != NULL && + options_get_number(&wp->window->options, "mode-mouse")) wp->mode->mouse(wp, sess, m); } else if (wp->fd != -1) input_mouse(wp, m); From 3970853febf1a371d68d27c331e81a2afe1a63bb Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Tue, 19 Apr 2011 20:12:47 +0000 Subject: [PATCH 0894/1180] POSIX only guarantees uname() will return a non-negative value on success. ok nicm@ --- cmd-server-info.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd-server-info.c b/cmd-server-info.c index 3edb9d2b..776b137d 100644 --- a/cmd-server-info.c +++ b/cmd-server-info.c @@ -71,7 +71,7 @@ cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx) ctx->print(ctx, "pid %ld, started %s", (long) getpid(), tim); ctx->print( ctx, "socket path %s, debug level %d", socket_path, debug_level); - if (uname(&un) == 0) { + if (uname(&un) >= 0) { ctx->print(ctx, "system is %s %s %s %s", un.sysname, un.release, un.version, un.machine); } From 8738141913517ae50d71b17ec531ce9f85dceb4d Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 19 Apr 2011 21:31:33 +0000 Subject: [PATCH 0895/1180] When mode-mouse is on (it is off by default), automatically enter copy mode when the mouse is dragged or the mouse wheel is used. Also exit copy mode when the mouse wheel is scrolled off the bottom. Discussed with and written by hsim at gmx dot li. --- input-keys.c | 7 +++++++ server-client.c | 26 +++++++++++++++++--------- tmux.1 | 5 +++-- tmux.h | 2 ++ window-copy.c | 27 +++++++++++++++++---------- 5 files changed, 46 insertions(+), 21 deletions(-) diff --git a/input-keys.c b/input-keys.c index f73ce397..dfcc8273 100644 --- a/input-keys.c +++ b/input-keys.c @@ -220,5 +220,12 @@ input_mouse(struct window_pane *wp, struct mouse_event *m) buf[len++] = m->y + 33; } bufferevent_write(wp->event, buf, len); + } else if ((m->b & MOUSE_BUTTON) != MOUSE_2) { + if (options_get_number(&wp->window->options, "mode-mouse") && + window_pane_set_mode(wp, &window_copy_mode) == 0) { + window_copy_init_from_pane(wp); + if (wp->mode->mouse != NULL) + wp->mode->mouse(wp, NULL, m); + } } } diff --git a/server-client.c b/server-client.c index 36bce79b..ef4946a1 100644 --- a/server-client.c +++ b/server-client.c @@ -314,7 +314,13 @@ server_client_handle_key(int key, struct mouse_event *mouse, void *data) if (key == KEYC_MOUSE) { if (c->flags & CLIENT_READONLY) return; - if (options_get_number(oo, "mouse-select-pane")) { + if (options_get_number(oo, "mouse-select-pane") && + ((!(mouse->b & MOUSE_DRAG) && mouse->b != MOUSE_UP) || + wp->mode != &window_copy_mode)) { + /* + * Allow pane switching in copy mode only by mouse down + * (click). + */ window_set_active_at(w, mouse->x, mouse->y); server_redraw_window_borders(w); wp = w->active; @@ -445,6 +451,7 @@ server_client_reset_state(struct client *c) struct window_pane *wp = w->active; struct screen *s = wp->screen; struct options *oo = &c->session->options; + struct options *wo = &w->options; int status, mode; tty_region(&c->tty, 0, c->tty.sy - 1); @@ -460,14 +467,15 @@ server_client_reset_state(struct client *c) * none. */ mode = s->mode; - if (TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry) != NULL && - options_get_number(oo, "mouse-select-pane") && - (mode & ALL_MOUSE_MODES) == 0) - mode |= MODE_MOUSE_STANDARD; - - if (options_get_number(oo, "mouse-select-window") && - (mode & ALL_MOUSE_MODES) == 0) - mode |= MODE_MOUSE_STANDARD; + if ((mode & ALL_MOUSE_MODES) == 0) { + if (TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry) != NULL && + options_get_number(oo, "mouse-select-pane") == 0) + mode |= MODE_MOUSE_STANDARD; + else if (options_get_number(oo, "mouse-select-window")) + mode |= MODE_MOUSE_STANDARD; + else if (options_get_number(wo, "mode-mouse")) + mode |= MODE_MOUSE_STANDARD; + } /* * Set UTF-8 mouse input if required. If the terminal is UTF-8, the diff --git a/tmux.1 b/tmux.1 index 45292ed9..af6b78e2 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2310,8 +2310,9 @@ contains .Op Ic on | off .Xc Mouse state in modes. -If on, the mouse may be used to copy a selection by dragging in copy mode, or -to select an option in choice mode. +If on, the mouse may be used to enter copy mode and copy a selection by +dragging, to enter copy mode and scroll with the mouse wheel, or to select an +option in choice mode. .Pp .It Xo Ic monitor-activity .Op Ic on | off diff --git a/tmux.h b/tmux.h index 82bdc296..def69db5 100644 --- a/tmux.h +++ b/tmux.h @@ -1081,6 +1081,7 @@ struct mouse_event { #define MOUSE_3 2 #define MOUSE_UP 3 #define MOUSE_BUTTON 3 +#define MOUSE_DRAG 32 #define MOUSE_45 64 u_int x; u_int y; @@ -1428,6 +1429,7 @@ void tty_cmd_clearstartofline(struct tty *, const struct tty_ctx *); void tty_cmd_clearstartofscreen(struct tty *, const struct tty_ctx *); void tty_cmd_deletecharacter(struct tty *, const struct tty_ctx *); void tty_cmd_deleteline(struct tty *, const struct tty_ctx *); +void tty_cmd_erasecharacter(struct tty *, const struct tty_ctx *); void tty_cmd_insertcharacter(struct tty *, const struct tty_ctx *); void tty_cmd_insertline(struct tty *, const struct tty_ctx *); void tty_cmd_linefeed(struct tty *, const struct tty_ctx *); diff --git a/window-copy.c b/window-copy.c index d21e4124..b3879f62 100644 --- a/window-copy.c +++ b/window-copy.c @@ -760,11 +760,11 @@ window_copy_key_numeric_prefix(struct window_pane *wp, int key) /* ARGSUSED */ void window_copy_mouse( - struct window_pane *wp, unused struct session *sess, struct mouse_event *m) + struct window_pane *wp, struct session *sess, struct mouse_event *m) { struct window_copy_mode_data *data = wp->modedata; struct screen *s = &data->screen; - u_int i; + u_int i, old_cy; if (m->x >= screen_size_x(s)) return; @@ -777,8 +777,11 @@ window_copy_mouse( for (i = 0; i < 5; i++) window_copy_cursor_up(wp, 0); } else if ((m->b & MOUSE_BUTTON) == MOUSE_2) { + old_cy = data->cy; for (i = 0; i < 5; i++) window_copy_cursor_down(wp, 0); + if (old_cy == data->cy) + goto reset_mode; } return; } @@ -792,15 +795,9 @@ window_copy_mouse( window_copy_update_cursor(wp, m->x, m->y); if (window_copy_update_selection(wp)) window_copy_redraw_screen(wp); - } else { - s->mode &= ~MODE_MOUSE_ANY; - s->mode |= MODE_MOUSE_STANDARD; - if (sess != NULL) { - window_copy_copy_selection(wp); - window_pane_reset_mode(wp); - } + return; } - return; + goto reset_mode; } /* Otherwise if other buttons pressed, start selection and motion. */ @@ -812,6 +809,16 @@ window_copy_mouse( window_copy_start_selection(wp); window_copy_redraw_screen(wp); } + + return; + +reset_mode: + s->mode &= ~MODE_MOUSE_ANY; + s->mode |= MODE_MOUSE_STANDARD; + if (sess != NULL) { + window_copy_copy_selection(wp); + window_pane_reset_mode(wp); + } } void From dc8fb9fb23f22ef4f2aedaee55d6e008b0089be3 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 24 Apr 2011 21:06:12 +0000 Subject: [PATCH 0896/1180] Tweak copy behaviour slightly in vi mode to be closer to real vi. From Tiago Resende. --- window-copy.c | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/window-copy.c b/window-copy.c index b3879f62..329a6f76 100644 --- a/window-copy.c +++ b/window-copy.c @@ -1225,6 +1225,7 @@ window_copy_copy_selection(struct window_pane *wp) size_t off; u_int i, xx, yy, sx, sy, ex, ey, limit; u_int firstsx, lastex, restex, restsx; + int keys; if (!s->sel.flag) return; @@ -1261,6 +1262,14 @@ window_copy_copy_selection(struct window_pane *wp) * end (restex) of all other lines. */ xx = screen_size_x(s); + + /* + * Behave according to mode-keys. If it is emacs, copy like emacs, + * keeping the top-left-most character, and dropping the + * bottom-right-most, regardless of copy direction. If it is vi, also + * keep bottom-right-most character. + */ + keys = options_get_number(&wp->window->options, "mode-keys"); if (data->rectflag) { /* * Need to ignore the column with the cursor in it, which for @@ -1268,8 +1277,14 @@ window_copy_copy_selection(struct window_pane *wp) */ if (data->selx < data->cx) { /* Selection start is on the left. */ - lastex = data->cx; - restex = data->cx; + if (keys == MODEKEY_EMACS) { + lastex = data->cx; + restex = data->cx; + } + else { + lastex = data->cx + 1; + restex = data->cx + 1; + } firstsx = data->selx; restsx = data->selx; } else { @@ -1280,11 +1295,10 @@ window_copy_copy_selection(struct window_pane *wp) restsx = data->cx; } } else { - /* - * Like emacs, keep the top-left-most character, and drop the - * bottom-right-most, regardless of copy direction. - */ - lastex = ex; + if (keys == MODEKEY_EMACS) + lastex = ex; + else + lastex = ex + 1; restex = xx; firstsx = sx; restsx = 0; From eb288aae3223576ebe3f68f5faaa1c4fd02cb73b Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 24 Apr 2011 21:32:07 +0000 Subject: [PATCH 0897/1180] Provide #h for short hostname (no domain) from Michal Mazurek. --- status.c | 7 +++++++ tmux.1 | 1 + 2 files changed, 8 insertions(+) diff --git a/status.c b/status.c index ecf19b25..3e5c69ce 100644 --- a/status.c +++ b/status.c @@ -410,6 +410,13 @@ status_replace1(struct client *c, struct session *s, struct winlink *wl, fatal("gethostname failed"); ptr = tmp; goto do_replace; + case 'h': + if (gethostname(tmp, sizeof tmp) != 0) + fatal("gethostname failed"); + if ((ptr = strchr(tmp, '.')) != NULL) + *ptr = '\0'; + ptr = tmp; + goto do_replace; case 'I': xsnprintf(tmp, sizeof tmp, "%d", wl->idx); ptr = tmp; diff --git a/tmux.1 b/tmux.1 index af6b78e2..45db380a 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2005,6 +2005,7 @@ may contain any of the following special character sequences: .It Li "#(shell-command)" Ta "First line of the command's output" .It Li "#[attributes]" Ta "Colour or attribute change" .It Li "#H" Ta "Hostname of local host" +.It Li "#h" Ta "Hostname of local host without the domain name" .It Li "#F" Ta "Current window flag" .It Li "#I" Ta "Current window index" .It Li "#P" Ta "Current pane index" From 075816eb72f859177b81e027e2241d50dbadec7b Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 29 Apr 2011 07:07:31 +0000 Subject: [PATCH 0898/1180] Only redraw the status line on command update, not the entire client (big DOH). --- status.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/status.c b/status.c index 3e5c69ce..46ff3633 100644 --- a/status.c +++ b/status.c @@ -642,7 +642,7 @@ status_job_callback(struct job *job) buf = xstrdup(line); so->out = buf; - server_redraw_client(c); + server_status_client(c); } /* Return winlink status line entry and adjust gc as necessary. */ From 7dddf56c081cf1e51dbcbf5e8881701122a1f22f Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 4 May 2011 17:40:32 +0000 Subject: [PATCH 0899/1180] Check if mouse-select-pane is ON not off when setting mouse flags, reported by oga. --- server-client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server-client.c b/server-client.c index ef4946a1..454859e6 100644 --- a/server-client.c +++ b/server-client.c @@ -469,7 +469,7 @@ server_client_reset_state(struct client *c) mode = s->mode; if ((mode & ALL_MOUSE_MODES) == 0) { if (TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry) != NULL && - options_get_number(oo, "mouse-select-pane") == 0) + options_get_number(oo, "mouse-select-pane")) mode |= MODE_MOUSE_STANDARD; else if (options_get_number(oo, "mouse-select-window")) mode |= MODE_MOUSE_STANDARD; From b1dfc740a38060c029dbc4fc505b5ffdb3a2fafd Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 4 May 2011 17:43:11 +0000 Subject: [PATCH 0900/1180] Don't use strnvis for the title as it breaks UTF-8. set-titles is now off by default and we have to trust the terminal can understand what we send it anyway so there isn't any harm. --- screen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/screen.c b/screen.c index 1860e247..4228d4ab 100644 --- a/screen.c +++ b/screen.c @@ -96,7 +96,7 @@ screen_set_title(struct screen *s, const char *title) { char tmp[BUFSIZ]; - strnvis(tmp, title, sizeof tmp, VIS_OCTAL|VIS_TAB|VIS_NL); + strlcpy(tmp, title, sizeof tmp); xfree(s->title); s->title = xstrdup(tmp); From a70df70d20381c57d26448c7526940145713234f Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 4 May 2011 17:43:35 +0000 Subject: [PATCH 0901/1180] Don't need vis.h anymore. --- screen.c | 1 - 1 file changed, 1 deletion(-) diff --git a/screen.c b/screen.c index 4228d4ab..abfbe100 100644 --- a/screen.c +++ b/screen.c @@ -21,7 +21,6 @@ #include #include #include -#include #include "tmux.h" From b0a88ebeadd56ebcb0cdbe9967a869d361b96c6f Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 4 May 2011 18:10:28 +0000 Subject: [PATCH 0902/1180] Change window with mouse wheel over status line if mouse-select-window is on, from marcel partap. --- server-client.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/server-client.c b/server-client.c index 454859e6..f21f9c36 100644 --- a/server-client.c +++ b/server-client.c @@ -325,11 +325,24 @@ server_client_handle_key(int key, struct mouse_event *mouse, void *data) server_redraw_window_borders(w); wp = w->active; } - if (mouse->y + 1 == c->tty.sy && mouse->b == MOUSE_UP && + if (mouse->y + 1 == c->tty.sy && options_get_number(oo, "mouse-select-window") && options_get_number(oo, "status")) { - status_set_window_at(c, mouse->x); - return; + if (mouse->b == MOUSE_UP) { + status_set_window_at(c, mouse->x); + return; + } + if (mouse->b & MOUSE_45) { + if ((mouse->b & MOUSE_BUTTON) == MOUSE_1) { + session_previous(c->session, 0); + server_redraw_session(s); + } + if ((mouse->b & MOUSE_BUTTON) == MOUSE_2) { + session_next(c->session, 0); + server_redraw_session(s); + } + return; + } } window_pane_mouse(wp, c->session, mouse); return; From 295ace682020769be8a6a6a02835099d93c392ef Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 8 May 2011 19:53:06 +0000 Subject: [PATCH 0903/1180] Use the tsl and fsl terminfo(5) capabilities to update terminal title and automatically fill them in on terminals with the XT capability (which means their title setting is xterm-compatible). From hsim at gmx.li. --- options-table.c | 2 +- tmux.1 | 2 +- tmux.h | 7 +++++-- tty-term.c | 19 +++++++++++++++++-- tty.c | 9 ++++----- 5 files changed, 28 insertions(+), 11 deletions(-) diff --git a/options-table.c b/options-table.c index 454dbffa..8da5d3a2 100644 --- a/options-table.c +++ b/options-table.c @@ -355,7 +355,7 @@ const struct options_table_entry session_options_table[] = { { .name = "terminal-overrides", .type = OPTIONS_TABLE_STRING, - .default_str = "*88col*:colors=88,*256col*:colors=256" + .default_str = "*88col*:colors=88,*256col*:colors=256,xterm*:XT" }, { .name = "update-environment", diff --git a/tmux.1 b/tmux.1 index 45db380a..b7fb5180 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2145,7 +2145,7 @@ The default value forcibly corrects the .Ql colors entry for terminals which support 88 or 256 colours: .Bd -literal -offset indent -"*88col*:colors=88,*256col*:colors=256" +"*88col*:colors=88,*256col*:colors=256,xterm*:XT" .Ed .It Ic update-environment Ar variables Set a space-separated string containing a list of environment variables to be diff --git a/tmux.h b/tmux.h index def69db5..42460640 100644 --- a/tmux.h +++ b/tmux.h @@ -205,6 +205,7 @@ enum tty_code_code { TTYC_EL, /* clr_eol, ce */ TTYC_EL1, /* clr_bol, cb */ TTYC_ENACS, /* ena_acs, eA */ + TTYC_FSL, /* from_status_line, fsl */ TTYC_HOME, /* cursor_home, ho */ TTYC_HPA, /* column_address, ch */ TTYC_ICH, /* parm_ich, IC */ @@ -317,17 +318,19 @@ enum tty_code_code { TTYC_SETAB, /* set_a_background, AB */ TTYC_SETAF, /* set_a_foreground, AF */ TTYC_SGR0, /* exit_attribute_mode, me */ + TTYC_SITM, /* enter_italics_mode, it */ TTYC_SMACS, /* enter_alt_charset_mode, as */ TTYC_SMCUP, /* enter_ca_mode, ti */ TTYC_SMIR, /* enter_insert_mode, im */ TTYC_SMKX, /* keypad_xmit, ks */ TTYC_SMSO, /* enter_standout_mode, so */ TTYC_SMUL, /* enter_underline_mode, us */ - TTYC_SITM, /* enter_italics_mode, it */ + TTYC_TSL, /* to_status_line, tsl */ TTYC_VPA, /* row_address, cv */ TTYC_XENL, /* eat_newline_glitch, xn */ + TTYC_XT, /* xterm(1)-compatible title, XT */ }; -#define NTTYCODE (TTYC_XENL + 1) +#define NTTYCODE (TTYC_XT + 1) /* Termcap types. */ enum tty_code_type { diff --git a/tty-term.c b/tty-term.c index 59a1bbba..f1e6d878 100644 --- a/tty-term.c +++ b/tty-term.c @@ -60,6 +60,7 @@ const struct tty_term_code_entry tty_term_codes[NTTYCODE] = { { TTYC_EL, TTYCODE_STRING, "el" }, { TTYC_EL1, TTYCODE_STRING, "el1" }, { TTYC_ENACS, TTYCODE_STRING, "enacs" }, + { TTYC_FSL, TTYCODE_STRING, "fsl" }, { TTYC_HOME, TTYCODE_STRING, "home" }, { TTYC_HPA, TTYCODE_STRING, "hpa" }, { TTYC_ICH, TTYCODE_STRING, "ich" }, @@ -172,15 +173,17 @@ const struct tty_term_code_entry tty_term_codes[NTTYCODE] = { { TTYC_SETAB, TTYCODE_STRING, "setab" }, { TTYC_SETAF, TTYCODE_STRING, "setaf" }, { TTYC_SGR0, TTYCODE_STRING, "sgr0" }, + { TTYC_SITM, TTYCODE_STRING, "sitm" }, { TTYC_SMACS, TTYCODE_STRING, "smacs" }, { TTYC_SMCUP, TTYCODE_STRING, "smcup" }, { TTYC_SMIR, TTYCODE_STRING, "smir" }, { TTYC_SMKX, TTYCODE_STRING, "smkx" }, { TTYC_SMSO, TTYCODE_STRING, "smso" }, { TTYC_SMUL, TTYCODE_STRING, "smul" }, - { TTYC_SITM, TTYCODE_STRING, "sitm" }, + { TTYC_TSL, TTYCODE_STRING, "tsl" }, { TTYC_VPA, TTYCODE_STRING, "vpa" }, { TTYC_XENL, TTYCODE_FLAG, "xenl" }, + { TTYC_XT, TTYCODE_FLAG, "XT" }, }; char * @@ -252,7 +255,7 @@ tty_term_override(struct tty_term *term, const char *overrides) entstr[strlen(entstr) - 1] = '\0'; removeflag = 1; } else - continue; + val = xstrdup(""); for (i = 0; i < NTTYCODE; i++) { ent = &tty_term_codes[i]; @@ -423,6 +426,18 @@ tty_term_find(char *name, int fd, const char *overrides, char **cause) for (; acs[0] != '\0' && acs[1] != '\0'; acs += 2) term->acs[(u_char) acs[0]][0] = acs[1]; + /* On terminals with xterm titles (XT), fill in tsl and fsl. */ + if (tty_term_flag(term, TTYC_XT) && + !tty_term_has(term, TTYC_TSL) && + !tty_term_has(term, TTYC_FSL)) { + code = &term->codes[TTYC_TSL]; + code->value.string = xstrdup("\033]0;"); + code->type = TTYCODE_STRING; + code = &term->codes[TTYC_FSL]; + code->value.string = xstrdup("\007"); + code->type = TTYCODE_STRING; + } + return (term); error: diff --git a/tty.c b/tty.c index 73dff0be..b423f6d8 100644 --- a/tty.c +++ b/tty.c @@ -369,14 +369,13 @@ tty_pututf8(struct tty *tty, const struct grid_utf8 *gu) void tty_set_title(struct tty *tty, const char *title) { - if (strstr(tty->termname, "xterm") == NULL && - strstr(tty->termname, "rxvt") == NULL && - strcmp(tty->termname, "screen") != 0) + if (!tty_term_has(tty->term, TTYC_TSL) || + !tty_term_has(tty->term, TTYC_FSL)) return; - tty_puts(tty, "\033]0;"); + tty_putcode(tty, TTYC_TSL); tty_puts(tty, title); - tty_putc(tty, '\007'); + tty_putcode(tty, TTYC_FSL); } void From f3741f0653e2a38b9d52851fb187d2592612a7c1 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 8 May 2011 20:34:12 +0000 Subject: [PATCH 0904/1180] Add a new option, mouse-resize-pane. When on, panes may be resized by dragging their borders. From hsim at gmx.li. --- layout.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ options-table.c | 5 +++++ server-client.c | 18 +++++++++++++++++- tmux.1 | 6 ++++++ tmux.h | 5 +++++ 5 files changed, 80 insertions(+), 1 deletion(-) diff --git a/layout.c b/layout.c index eee29905..a07ae2d5 100644 --- a/layout.c +++ b/layout.c @@ -485,6 +485,53 @@ layout_resize_pane(struct window_pane *wp, enum layout_type type, int change) layout_fix_panes(wp->window, wp->window->sx, wp->window->sy); } +void +layout_resize_pane_mouse(struct client *c, struct mouse_event *mouse) +{ + struct window *w; + struct window_pane *wp; + int pane_border; + + w = c->session->curw->window; + + pane_border = 0; + if ((c->last_mouse.b & MOUSE_BUTTON) != MOUSE_UP && + (c->last_mouse.b & MOUSE_RESIZE_PANE)) { + TAILQ_FOREACH(wp, &w->panes, entry) { + if (wp->xoff + wp->sx == c->last_mouse.x && + wp->yoff <= 1 + c->last_mouse.y && + wp->yoff + wp->sy >= c->last_mouse.y) { + layout_resize_pane(wp, LAYOUT_LEFTRIGHT, + mouse->x - c->last_mouse.x); + pane_border = 1; + } + if (wp->yoff + wp->sy == c->last_mouse.y && + wp->xoff <= 1 + c->last_mouse.x && + wp->xoff + wp->sx >= c->last_mouse.x) { + layout_resize_pane(wp, LAYOUT_TOPBOTTOM, + mouse->y - c->last_mouse.y); + pane_border = 1; + } + } + if (pane_border) + server_redraw_window(w); + } else if (mouse->b != MOUSE_UP && + mouse->b == (mouse->b & MOUSE_BUTTON)) { + TAILQ_FOREACH(wp, &w->panes, entry) { + if ((wp->xoff + wp->sx == mouse->x && + wp->yoff <= 1 + mouse->y && + wp->yoff + wp->sy >= mouse->y) || + (wp->yoff + wp->sy == mouse->y && + wp->xoff <= 1 + mouse->x && + wp->xoff + wp->sx >= mouse->x)) { + pane_border = 1; + } + } + } + if (pane_border) + mouse->b |= MOUSE_RESIZE_PANE; +} + int layout_resize_pane_grow( struct layout_cell *lc, enum layout_type type, int needed) diff --git a/options-table.c b/options-table.c index 8da5d3a2..8e8b8b5d 100644 --- a/options-table.c +++ b/options-table.c @@ -193,6 +193,11 @@ const struct options_table_entry session_options_table[] = { .default_num = 20 }, + { .name = "mouse-resize-pane", + .type = OPTIONS_TABLE_FLAG, + .default_num = 0 + }, + { .name = "mouse-select-pane", .type = OPTIONS_TABLE_FLAG, .default_num = 0 diff --git a/server-client.c b/server-client.c index f21f9c36..7ef91236 100644 --- a/server-client.c +++ b/server-client.c @@ -89,6 +89,9 @@ server_client_create(int fd) c->prompt_buffer = NULL; c->prompt_index = 0; + c->last_mouse.b = MOUSE_UP; + c->last_mouse.x = c->last_mouse.y = -1; + evtimer_set(&c->repeat_timer, server_client_repeat_timer, c); for (i = 0; i < ARRAY_LENGTH(&clients); i++) { @@ -344,6 +347,9 @@ server_client_handle_key(int key, struct mouse_event *mouse, void *data) return; } } + if (options_get_number(oo, "mouse-resize-pane")) + layout_resize_pane_mouse(c, mouse); + memcpy(&c->last_mouse, mouse, sizeof c->last_mouse); window_pane_mouse(wp, c->session, mouse); return; } @@ -475,15 +481,25 @@ server_client_reset_state(struct client *c) else tty_cursor(&c->tty, wp->xoff + s->cx, wp->yoff + s->cy); + /* + * Resizing panes with the mouse requires at least button mode to give + * a smooth appearance. + */ + mode = s->mode; + if ((c->last_mouse.b & MOUSE_RESIZE_PANE) && + !(mode & (MODE_MOUSE_BUTTON|MODE_MOUSE_ANY))) + mode |= MODE_MOUSE_BUTTON; + /* * Any mode will do for mouse-select-pane, but set standard mode if * none. */ - mode = s->mode; if ((mode & ALL_MOUSE_MODES) == 0) { if (TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry) != NULL && options_get_number(oo, "mouse-select-pane")) mode |= MODE_MOUSE_STANDARD; + else if (options_get_number(oo, "mouse-resize-pane")) + mode |= MODE_MOUSE_STANDARD; else if (options_get_number(oo, "mouse-select-window")) mode |= MODE_MOUSE_STANDARD; else if (options_get_number(wo, "mode-mouse")) diff --git a/tmux.1 b/tmux.1 index b7fb5180..7e7ec28e 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1888,6 +1888,12 @@ Set status line message foreground colour. Set the number of error or information messages to save in the message log for each client. The default is 20. +.It Xo Ic mouse-resize-pane +.Op Ic on | off +.Xc +If on, +.Nm +captures the mouse and allows panes to be resized by dragging on their borders. .It Xo Ic mouse-select-pane .Op Ic on | off .Xc diff --git a/tmux.h b/tmux.h index 42460640..cc398b45 100644 --- a/tmux.h +++ b/tmux.h @@ -1086,6 +1086,7 @@ struct mouse_event { #define MOUSE_BUTTON 3 #define MOUSE_DRAG 32 #define MOUSE_45 64 +#define MOUSE_RESIZE_PANE 128 /* marker for resizing */ u_int x; u_int y; }; @@ -1177,6 +1178,8 @@ struct client { struct session *session; struct session *last_session; + struct mouse_event last_mouse; + int references; }; ARRAY_DECL(clients, struct client *); @@ -1925,6 +1928,8 @@ void layout_free(struct window *); void layout_resize(struct window *, u_int, u_int); void layout_resize_pane( struct window_pane *, enum layout_type, int); +void layout_resize_pane_mouse( + struct client *c, struct mouse_event *mouse); void layout_assign_pane(struct layout_cell *, struct window_pane *); struct layout_cell *layout_split_pane( struct window_pane *, enum layout_type, int); From 6f0847204995b831a74a5826be4272fc03d27746 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 8 May 2011 20:35:58 +0000 Subject: [PATCH 0905/1180] Fix a memory leak if cmd_pane_session succeeds, from Tiago Cunha. --- cmd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd.c b/cmd.c index ee893a25..f1cba109 100644 --- a/cmd.c +++ b/cmd.c @@ -714,20 +714,20 @@ cmd_find_session(struct cmd_ctx *ctx, const char *arg, int prefer_unattached) /* A NULL argument means the current session. */ if (arg == NULL) return (cmd_current_session(ctx, prefer_unattached)); - tmparg = xstrdup(arg); /* Lookup as pane id. */ if ((wp = cmd_lookup_paneid(arg)) != NULL) return (cmd_pane_session(ctx, wp, NULL)); /* Trim a single trailing colon if any. */ + tmparg = xstrdup(arg); arglen = strlen(tmparg); if (arglen != 0 && tmparg[arglen - 1] == ':') tmparg[arglen - 1] = '\0'; /* An empty session name is the current session. */ if (*tmparg == '\0') { - xfree (tmparg); + xfree(tmparg); return (cmd_current_session(ctx, prefer_unattached)); } From 538af37c356de783ceb01fff456eb379a2ff0d07 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 8 May 2011 20:37:04 +0000 Subject: [PATCH 0906/1180] Fix a couple of memory leaks, from Tiago Cunha. --- cmd-capture-pane.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/cmd-capture-pane.c b/cmd-capture-pane.c index 52f5455c..bdf74106 100644 --- a/cmd-capture-pane.c +++ b/cmd-capture-pane.c @@ -60,9 +60,10 @@ cmd_capture_pane_exec(struct cmd *self, struct cmd_ctx *ctx) len = 0; n = args_strtonum(args, 'S', SHRT_MIN, SHRT_MAX, &cause); - if (cause != NULL) + if (cause != NULL) { top = gd->hsize; - else if (n < 0 && (u_int) -n > gd->hsize) + xfree(cause); + } else if (n < 0 && (u_int) -n > gd->hsize) top = 0; else top = gd->hsize + n; @@ -70,9 +71,10 @@ cmd_capture_pane_exec(struct cmd *self, struct cmd_ctx *ctx) top = gd->hsize + gd->sy - 1; n = args_strtonum(args, 'E', SHRT_MIN, SHRT_MAX, &cause); - if (cause != NULL) + if (cause != NULL) { bottom = gd->hsize + gd->sy - 1; - else if (n < 0 && (u_int) -n > gd->hsize) + xfree(cause); + } else if (n < 0 && (u_int) -n > gd->hsize) bottom = 0; else bottom = gd->hsize + n; From acfabf3a50c05a576435c1bc86f36af07362b529 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 8 May 2011 20:45:35 +0000 Subject: [PATCH 0907/1180] Only select pane on click, not drag. From hsim at gmx.li. --- server-client.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server-client.c b/server-client.c index 7ef91236..8b2ea00f 100644 --- a/server-client.c +++ b/server-client.c @@ -331,7 +331,8 @@ server_client_handle_key(int key, struct mouse_event *mouse, void *data) if (mouse->y + 1 == c->tty.sy && options_get_number(oo, "mouse-select-window") && options_get_number(oo, "status")) { - if (mouse->b == MOUSE_UP) { + if (mouse->b == MOUSE_UP && + c->last_mouse.b != MOUSE_UP) { status_set_window_at(c, mouse->x); return; } From 583c885d68bc567789451db25e49a3fac36f194c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 8 May 2011 21:12:52 +0000 Subject: [PATCH 0908/1180] Reset last pane on swap-pane across windows, fixes crash noticed by hsim at gmx.li. --- cmd-swap-pane.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cmd-swap-pane.c b/cmd-swap-pane.c index 8e0662dd..aa133faf 100644 --- a/cmd-swap-pane.c +++ b/cmd-swap-pane.c @@ -129,6 +129,12 @@ cmd_swap_pane_exec(struct cmd *self, struct cmd_ctx *ctx) if (dst_w->active == dst_wp) window_set_active_pane(dst_w, src_wp); } + if (src_w != dst_w) { + if (src_w->last == src_wp) + src_w->last = NULL; + if (dst_w->last == dst_wp) + dst_w->last = NULL; + } server_redraw_window(src_w); server_redraw_window(dst_w); From ec3efab01ec12aaf6ee0cf8174efdb71b2293190 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 8 May 2011 21:30:00 +0000 Subject: [PATCH 0909/1180] Reset last pane properly when using break-pane as well, fixes a problem reported to Debian by Hannes von Haugwitz (bug 622677). --- cmd-break-pane.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/cmd-break-pane.c b/cmd-break-pane.c index 4c57a116..f6663149 100644 --- a/cmd-break-pane.c +++ b/cmd-break-pane.c @@ -57,12 +57,18 @@ cmd_break_pane_exec(struct cmd *self, struct cmd_ctx *ctx) return (-1); } - TAILQ_REMOVE(&wl->window->panes, wp, entry); - if (wl->window->active == wp) { - wl->window->active = TAILQ_PREV(wp, window_panes, entry); - if (wl->window->active == NULL) - wl->window->active = TAILQ_NEXT(wp, entry); - } + w = wl->window; + TAILQ_REMOVE(&w->panes, wp, entry); + if (wp == w->active) { + w->active = w->last; + w->last = NULL; + if (w->active == NULL) { + w->active = TAILQ_PREV(wp, window_panes, entry); + if (w->active == NULL) + w->active = TAILQ_NEXT(wp, entry); + } + } else if (wp == w->last) + w->last = NULL; layout_close_pane(wp); w = wp->window = window_create1(s->sx, s->sy); From fb527c1bad96b77bfae7b0b6bf3540dad5cd89e2 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 18 May 2011 08:04:47 +0000 Subject: [PATCH 0910/1180] Use button mouse mode not any for copy mode, fixes issues with putty. From Ailin Nemui. --- window-copy.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/window-copy.c b/window-copy.c index 329a6f76..de0346d0 100644 --- a/window-copy.c +++ b/window-copy.c @@ -790,7 +790,7 @@ window_copy_mouse( * If already reading motion, move the cursor while buttons are still * pressed, or stop the selection on their release. */ - if (s->mode & MODE_MOUSE_ANY) { + if (s->mode & MODE_MOUSE_BUTTON) { if ((m->b & MOUSE_BUTTON) != MOUSE_UP) { window_copy_update_cursor(wp, m->x, m->y); if (window_copy_update_selection(wp)) @@ -803,7 +803,7 @@ window_copy_mouse( /* Otherwise if other buttons pressed, start selection and motion. */ if ((m->b & MOUSE_BUTTON) != MOUSE_UP) { s->mode &= ~MODE_MOUSE_STANDARD; - s->mode |= MODE_MOUSE_ANY; + s->mode |= MODE_MOUSE_BUTTON; window_copy_update_cursor(wp, m->x, m->y); window_copy_start_selection(wp); @@ -813,7 +813,7 @@ window_copy_mouse( return; reset_mode: - s->mode &= ~MODE_MOUSE_ANY; + s->mode &= ~MODE_MOUSE_BUTTON; s->mode |= MODE_MOUSE_STANDARD; if (sess != NULL) { window_copy_copy_selection(wp); From f702dbfea27a05eafcb6c8b8f67073a90c1e9a8a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 18 May 2011 08:07:44 +0000 Subject: [PATCH 0911/1180] Use xfree not free, from Tiago Cunha. --- cmd-load-buffer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd-load-buffer.c b/cmd-load-buffer.c index 55a5cd14..34792048 100644 --- a/cmd-load-buffer.c +++ b/cmd-load-buffer.c @@ -154,7 +154,7 @@ cmd_load_buffer_callback(struct client *c, void *data) psize = EVBUFFER_LENGTH(c->stdin_event->input); if (psize == 0 || (pdata = malloc(psize + 1)) == NULL) { - free(data); + xfree(data); return; } bufferevent_read(c->stdin_event, pdata, psize); @@ -170,5 +170,5 @@ cmd_load_buffer_callback(struct client *c, void *data) bufferevent_enable(c->stderr_event, EV_WRITE); } - free (data); + xfree(data); } From 58908fd8c54a3c8d2878a7c6f9ca566093302f92 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 18 May 2011 18:06:36 +0000 Subject: [PATCH 0912/1180] Add three new copy-mode commands - select-line, copy-line, copy-end-of-line. From Dave Disser and Randy Stauner a while back. --- mode-key.c | 5 +++++ tmux.1 | 2 +- tmux.h | 3 +++ window-copy.c | 20 ++++++++++++++++++++ 4 files changed, 29 insertions(+), 1 deletion(-) diff --git a/mode-key.c b/mode-key.c index 823c4429..7c8cb37f 100644 --- a/mode-key.c +++ b/mode-key.c @@ -82,6 +82,8 @@ const struct mode_key_cmdstr mode_key_cmdstr_copy[] = { { MODEKEYCOPY_BOTTOMLINE, "bottom-line" }, { MODEKEYCOPY_CANCEL, "cancel" }, { MODEKEYCOPY_CLEARSELECTION, "clear-selection" }, + { MODEKEYCOPY_COPYLINE, "copy-line" }, + { MODEKEYCOPY_COPYENDOFLINE, "copy-end-of-line" }, { MODEKEYCOPY_COPYSELECTION, "copy-selection" }, { MODEKEYCOPY_DOWN, "cursor-down" }, { MODEKEYCOPY_ENDOFLINE, "end-of-line" }, @@ -110,6 +112,7 @@ const struct mode_key_cmdstr mode_key_cmdstr_copy[] = { { MODEKEYCOPY_SEARCHDOWN, "search-forward" }, { MODEKEYCOPY_SEARCHREVERSE, "search-reverse" }, { MODEKEYCOPY_SEARCHUP, "search-backward" }, + { MODEKEYCOPY_SELECTLINE, "select-line" }, { MODEKEYCOPY_STARTNUMBERPREFIX, "start-number-prefix" }, { MODEKEYCOPY_STARTOFLINE, "start-of-line" }, { MODEKEYCOPY_STARTSELECTION, "begin-selection" }, @@ -198,6 +201,7 @@ const struct mode_key_entry mode_key_vi_copy[] = { { ':', 0, MODEKEYCOPY_GOTOLINE }, { '?', 0, MODEKEYCOPY_SEARCHUP }, { 'B', 0, MODEKEYCOPY_PREVIOUSSPACE }, + { 'D', 0, MODEKEYCOPY_COPYENDOFLINE }, { 'E', 0, MODEKEYCOPY_NEXTSPACEEND }, { 'F', 0, MODEKEYCOPY_JUMPBACK }, { 'G', 0, MODEKEYCOPY_HISTORYBOTTOM }, @@ -323,6 +327,7 @@ const struct mode_key_entry mode_key_emacs_copy[] = { { '\005' /* C-e */, 0, MODEKEYCOPY_ENDOFLINE }, { '\006' /* C-f */, 0, MODEKEYCOPY_RIGHT }, { '\007' /* C-g */, 0, MODEKEYCOPY_CLEARSELECTION }, + { '\013' /* C-k */, 0, MODEKEYCOPY_COPYENDOFLINE }, { '\016' /* C-n */, 0, MODEKEYCOPY_DOWN }, { '\020' /* C-p */, 0, MODEKEYCOPY_UP }, { '\022' /* C-r */, 0, MODEKEYCOPY_SEARCHUP }, diff --git a/tmux.1 b/tmux.1 index 7e7ec28e..4b0083a0 100644 --- a/tmux.1 +++ b/tmux.1 @@ -766,7 +766,7 @@ The following keys are supported as appropriate for the mode: .It Li "Cursor to top line" Ta "H" Ta "M-R" .It Li "Cursor up" Ta "k" Ta "Up" .It Li "Delete entire line" Ta "d" Ta "C-u" -.It Li "Delete to end of line" Ta "D" Ta "C-k" +.It Li "Delete/Copy to end of line" Ta "D" Ta "C-k" .It Li "End of line" Ta "$" Ta "C-e" .It Li "Go to line" Ta ":" Ta "g" .It Li "Half page down" Ta "C-d" Ta "M-Down" diff --git a/tmux.h b/tmux.h index cc398b45..c7875df7 100644 --- a/tmux.h +++ b/tmux.h @@ -461,6 +461,8 @@ enum mode_key_cmd { MODEKEYCOPY_BOTTOMLINE, MODEKEYCOPY_CANCEL, MODEKEYCOPY_CLEARSELECTION, + MODEKEYCOPY_COPYLINE, + MODEKEYCOPY_COPYENDOFLINE, MODEKEYCOPY_COPYSELECTION, MODEKEYCOPY_DOWN, MODEKEYCOPY_ENDOFLINE, @@ -491,6 +493,7 @@ enum mode_key_cmd { MODEKEYCOPY_SEARCHDOWN, MODEKEYCOPY_SEARCHREVERSE, MODEKEYCOPY_SEARCHUP, + MODEKEYCOPY_SELECTLINE, MODEKEYCOPY_STARTNUMBERPREFIX, MODEKEYCOPY_STARTOFLINE, MODEKEYCOPY_STARTSELECTION, diff --git a/window-copy.c b/window-copy.c index de0346d0..4ee3c3e3 100644 --- a/window-copy.c +++ b/window-copy.c @@ -500,6 +500,26 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key) window_copy_start_selection(wp); window_copy_redraw_screen(wp); break; + case MODEKEYCOPY_COPYLINE: + case MODEKEYCOPY_SELECTLINE: + window_copy_cursor_start_of_line(wp); + /* FALLTHROUGH */ + case MODEKEYCOPY_COPYENDOFLINE: + window_copy_start_selection(wp); + for (; np > 1; np--) + window_copy_cursor_down(wp, 0); + window_copy_cursor_end_of_line(wp); + window_copy_redraw_screen(wp); + + /* If a copy command then copy the selection and exit. */ + if (sess != NULL && + (cmd == MODEKEYCOPY_COPYLINE || + cmd == MODEKEYCOPY_COPYENDOFLINE)) { + window_copy_copy_selection(wp); + window_pane_reset_mode(wp); + return; + } + break; case MODEKEYCOPY_CLEARSELECTION: window_copy_clear_selection(wp); window_copy_redraw_screen(wp); From 96e7f33da3078facc504c6c66d42956bc44b2e54 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 18 May 2011 20:24:29 +0000 Subject: [PATCH 0913/1180] Support setting the xterm clipboard when copying from copy mode using the xterm escape sequence for the purpose (if xterm is configured to allow it). Written by and much discussed Ailin Nemui, guidance on xterm/termcap/terminfo from Thomas Dickey. --- options-table.c | 8 +++++++- screen-write.c | 12 ++++++++++++ tmux.1 | 37 +++++++++++++++++++++++++++++++++++++ tmux.h | 6 ++++++ tty-term.c | 7 +++++++ tty.c | 28 ++++++++++++++++++++++++++++ window-copy.c | 3 +++ 7 files changed, 100 insertions(+), 1 deletion(-) diff --git a/options-table.c b/options-table.c index 8e8b8b5d..8a611460 100644 --- a/options-table.c +++ b/options-table.c @@ -75,6 +75,11 @@ const struct options_table_entry server_options_table[] = { .default_num = 0 /* overridden in main() */ }, + { .name = "set-clipboard", + .type = OPTIONS_TABLE_FLAG, + .default_num = 1 + }, + { .name = NULL } }; @@ -360,7 +365,8 @@ const struct options_table_entry session_options_table[] = { { .name = "terminal-overrides", .type = OPTIONS_TABLE_STRING, - .default_str = "*88col*:colors=88,*256col*:colors=256,xterm*:XT" + .default_str = "*88col*:colors=88,*256col*:colors=256" + ",xterm*:XT:Ms=\\E]52;%p1%s;%p2%s\\007" }, { .name = "update-environment", diff --git a/screen-write.c b/screen-write.c index 1fee190d..60623701 100644 --- a/screen-write.c +++ b/screen-write.c @@ -1194,6 +1194,18 @@ screen_write_overwrite(struct screen_write_ctx *ctx, u_int width) } } +void +screen_write_setselection(struct screen_write_ctx *ctx, u_char *str, u_int len) +{ + struct tty_ctx ttyctx; + + screen_write_initctx(ctx, &ttyctx, 0); + ttyctx.ptr = str; + ttyctx.num = len; + + tty_write(tty_cmd_setselection, &ttyctx); +} + void screen_write_rawstring(struct screen_write_ctx *ctx, u_char *str, u_int len) { diff --git a/tmux.1 b/tmux.1 index 4b0083a0..c6a286a8 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1705,6 +1705,28 @@ Available server options are: Set the number of buffers; as new buffers are added to the top of the stack, old ones are removed from the bottom if necessary to maintain this maximum length. +.It Xo Ic set-clipboard +.Op Ic on | off +.Xc +Attempt to set the terminal clipboard content using the +\ee]52;...\e007 +.Xr xterm 1 +escape sequences. +This option is on by default if there is an +.Em \&Ms +entry in the +.Xr terminfo 5 +description for the client terminal. +Note that this feature needs to be enabled in +.Xr xterm 1 +by setting the resource: +.Bd -literal -offset indent +disallowedWindowOps: 20,21,SetXprop +.Ed +.Pp +Or changing this property from the +.Xr xterm 1 +interactive menu when required. .It Ic escape-time Ar time Set the time in milliseconds for which .Nm @@ -2796,6 +2818,21 @@ If the command doesn't return success, the exit status is also displayed. .D1 (alias: Ic info ) Show server information and terminal details. .El +.Sh TERMINFO EXTENSIONS +.Nm +understands some extensions to +.Xr terminfo 5 : +.Bl -tag -width Ds +.It Em \&Ms +This sequence can be used by +.Nm +to store the current buffer in the host terminal's selection (clipboard). +See the +.Em set-clipboard +option above and the +.Xr xterm 1 +man page. +.El .Sh FILES .Bl -tag -width "/etc/tmux.confXXX" -compact .It Pa ~/.tmux.conf diff --git a/tmux.h b/tmux.h index c7875df7..3056ac94 100644 --- a/tmux.h +++ b/tmux.h @@ -308,6 +308,7 @@ enum tty_code_code { TTYC_KUP5, TTYC_KUP6, TTYC_KUP7, + TTYC_MS, /* modify xterm(1) selection */ TTYC_OP, /* orig_pair, op */ TTYC_REV, /* enter_reverse_mode, mr */ TTYC_RI, /* scroll_reverse, sr */ @@ -1413,6 +1414,7 @@ void tty_cursor(struct tty *, u_int, u_int); void tty_putcode(struct tty *, enum tty_code_code); void tty_putcode1(struct tty *, enum tty_code_code, int); void tty_putcode2(struct tty *, enum tty_code_code, int, int); +void tty_putcode_ptr2(struct tty *, enum tty_code_code, const void *, const void *); void tty_puts(struct tty *, const char *); void tty_putc(struct tty *, u_char); void tty_pututf8(struct tty *, const struct grid_utf8 *); @@ -1444,6 +1446,7 @@ void tty_cmd_insertline(struct tty *, const struct tty_ctx *); void tty_cmd_linefeed(struct tty *, const struct tty_ctx *); void tty_cmd_utf8character(struct tty *, const struct tty_ctx *); void tty_cmd_reverseindex(struct tty *, const struct tty_ctx *); +void tty_cmd_setselection(struct tty *, const struct tty_ctx *); void tty_cmd_rawstring(struct tty *, const struct tty_ctx *); /* tty-term.c */ @@ -1456,6 +1459,8 @@ const char *tty_term_string(struct tty_term *, enum tty_code_code); const char *tty_term_string1(struct tty_term *, enum tty_code_code, int); const char *tty_term_string2( struct tty_term *, enum tty_code_code, int, int); +const char *tty_term_ptr2( + struct tty_term *, enum tty_code_code, const void *, const void *); int tty_term_number(struct tty_term *, enum tty_code_code); int tty_term_flag(struct tty_term *, enum tty_code_code); @@ -1824,6 +1829,7 @@ void screen_write_clearstartofscreen(struct screen_write_ctx *); void screen_write_clearscreen(struct screen_write_ctx *); void screen_write_cell(struct screen_write_ctx *, const struct grid_cell *, const struct utf8_data *); +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 */ diff --git a/tty-term.c b/tty-term.c index f1e6d878..7ad4628f 100644 --- a/tty-term.c +++ b/tty-term.c @@ -163,6 +163,7 @@ const struct tty_term_code_entry tty_term_codes[NTTYCODE] = { { TTYC_KUP5, TTYCODE_STRING, "kUP5" }, { TTYC_KUP6, TTYCODE_STRING, "kUP6" }, { TTYC_KUP7, TTYCODE_STRING, "kUP7" }, + { TTYC_MS, TTYCODE_STRING, "Ms" }, { TTYC_OP, TTYCODE_STRING, "op" }, { TTYC_REV, TTYCODE_STRING, "rev" }, { TTYC_RI, TTYCODE_STRING, "ri" }, @@ -492,6 +493,12 @@ tty_term_string2(struct tty_term *term, enum tty_code_code code, int a, int b) return (tparm((char *) tty_term_string(term, code), a, b)); } +const char * +tty_term_ptr2(struct tty_term *term, enum tty_code_code code, const void *a, const void *b) +{ + return (tparm((char *) tty_term_string(term, code), a, b)); +} + int tty_term_number(struct tty_term *term, enum tty_code_code code) { diff --git a/tty.c b/tty.c index b423f6d8..04503b60 100644 --- a/tty.c +++ b/tty.c @@ -19,8 +19,11 @@ #include #include +#include + #include #include +#include #include #include #include @@ -311,6 +314,13 @@ tty_putcode2(struct tty *tty, enum tty_code_code code, int a, int b) tty_puts(tty, tty_term_string2(tty->term, code, a, b)); } +void +tty_putcode_ptr2(struct tty *tty, enum tty_code_code code, const void *a, const void *b) +{ + if (a != NULL && b != NULL) + tty_puts(tty, tty_term_ptr2(tty->term, code, a, b)); +} + void tty_puts(struct tty *tty, const char *s) { @@ -938,6 +948,24 @@ tty_cmd_utf8character(struct tty *tty, const struct tty_ctx *ctx) tty_draw_line(tty, wp->screen, ctx->ocy, wp->xoff, wp->yoff); } +void +tty_cmd_setselection(struct tty *tty, const struct tty_ctx *ctx) +{ + char *buf; + size_t off; + + if (!tty_term_has(tty->term, TTYC_MS)) + return; + + off = 4 * ((ctx->num + 2) / 3) + 1; /* storage for base64 */ + buf = xmalloc(off); + + b64_ntop(ctx->ptr, ctx->num, buf, off); + tty_putcode_ptr2(tty, TTYC_MS, "", buf); + + xfree(buf); +} + void tty_cmd_rawstring(struct tty *tty, const struct tty_ctx *ctx) { diff --git a/window-copy.c b/window-copy.c index 4ee3c3e3..1c060dc0 100644 --- a/window-copy.c +++ b/window-copy.c @@ -1345,6 +1345,9 @@ window_copy_copy_selection(struct window_pane *wp) } off--; /* remove final \n */ + if (options_get_number(&global_options, "set-clipboard")) + screen_write_setselection(&wp->ictx.ctx, buf, off); + /* Add the buffer to the stack. */ limit = options_get_number(&global_options, "buffer-limit"); paste_add(&global_buffers, buf, off, limit); From 944b5e6fa04e014501f465e3898315c84d10bd9e Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 20 May 2011 19:03:58 +0000 Subject: [PATCH 0914/1180] Support xterm(1) cursor colour change sequences through terminfo(5) Cc (set) and Cr (reset) extensions. Originally by Sean Estabrooks, tweaked by me and Ailin Nemui. --- input.c | 36 +++++++++++++++++++++++++++++------- options-table.c | 5 +++-- screen.c | 10 ++++++++++ server-client.c | 2 +- tmux.1 | 9 +++++++++ tmux.h | 12 +++++++++++- tty-term.c | 8 ++++++++ tty.c | 34 ++++++++++++++++++++++++++++++---- 8 files changed, 101 insertions(+), 15 deletions(-) diff --git a/input.c b/input.c index 3da950d5..86d34b74 100644 --- a/input.c +++ b/input.c @@ -1445,17 +1445,39 @@ input_enter_osc(struct input_ctx *ictx) void input_exit_osc(struct input_ctx *ictx) { + u_char *p = ictx->input_buf; + int option; + if (ictx->flags & INPUT_DISCARD) return; - log_debug("%s: \"%s\"", __func__, ictx->input_buf); - - if (ictx->input_len < 2 || ictx->input_buf[1] != ';') - return; - if (ictx->input_buf[0] != '0' && ictx->input_buf[0] != '2') + if (ictx->input_len < 1 || *p < '0' || *p > '9') return; - screen_set_title(ictx->ctx.s, ictx->input_buf + 2); - server_status_window(ictx->wp->window); + log_debug("%s: \"%s\"", __func__, p); + + option = 0; + while (*p >= '0' && *p <= '9') + option = option * 10 + *p++ - '0'; + if (*p == ';') + p++; + + switch (option) { + case 0: + case 2: + screen_set_title(ictx->ctx.s, p); + server_status_window(ictx->wp->window); + break; + case 12: + screen_set_cursor_colour(ictx->ctx.s, p); + break; + case 112: + if (*p == '\0') /* No arguments allowed. */ + screen_set_cursor_colour(ictx->ctx.s, ""); + break; + default: + log_debug("%s: unknown '%u'", __func__, option); + break; + } } /* APC string started. */ diff --git a/options-table.c b/options-table.c index 8a611460..c84c56a1 100644 --- a/options-table.c +++ b/options-table.c @@ -366,13 +366,14 @@ const struct options_table_entry session_options_table[] = { { .name = "terminal-overrides", .type = OPTIONS_TABLE_STRING, .default_str = "*88col*:colors=88,*256col*:colors=256" - ",xterm*:XT:Ms=\\E]52;%p1%s;%p2%s\\007" + ",xterm*:XT:Ms=\\E]52;%p1%s;%p2%s\\007" + ":Cc=\\E]12;%p1%s\\007:Cr=\\E]112\\007" }, { .name = "update-environment", .type = OPTIONS_TABLE_STRING, .default_str = "DISPLAY SSH_ASKPASS SSH_AUTH_SOCK SSH_AGENT_PID " - "SSH_CONNECTION WINDOWID XAUTHORITY" + "SSH_CONNECTION WINDOWID XAUTHORITY" }, diff --git a/screen.c b/screen.c index abfbe100..5e3be88c 100644 --- a/screen.c +++ b/screen.c @@ -40,6 +40,7 @@ screen_init(struct screen *s, u_int sx, u_int sy, u_int hlimit) else s->title = xstrdup(""); + s->ccolour = xstrdup(""); s->tabs = NULL; screen_reinit(s); @@ -71,6 +72,7 @@ screen_free(struct screen *s) if (s->tabs != NULL) xfree(s->tabs); xfree(s->title); + xfree(s->ccolour); grid_destroy(s->grid); } @@ -89,6 +91,14 @@ screen_reset_tabs(struct screen *s) bit_set(s->tabs, i); } +/* Set screen cursor colour. */ +void +screen_set_cursor_colour(struct screen *s, const char *colour_string) +{ + xfree(s->ccolour); + s->ccolour = xstrdup(colour_string); +} + /* Set screen title. */ void screen_set_title(struct screen *s, const char *title) diff --git a/server-client.c b/server-client.c index 8b2ea00f..f4dd1fb2 100644 --- a/server-client.c +++ b/server-client.c @@ -521,7 +521,7 @@ server_client_reset_state(struct client *c) mode &= ~MODE_MOUSE_UTF8; /* Set the terminal mode and reset attributes. */ - tty_update_mode(&c->tty, mode); + tty_update_mode(&c->tty, mode, s); tty_reset(&c->tty); } diff --git a/tmux.1 b/tmux.1 index c6a286a8..dbe54d52 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2832,6 +2832,15 @@ See the option above and the .Xr xterm 1 man page. +.It Em Cc, Cr +The first takes one string argument and is used to set the cursor colour; +the second takes no arguments and restores the default cursor colour. +If they present, a sequence such as this may be used to change the +cursor colour from inside +.Nm : +.Bd -literal -offset indent +$ printf '\e033]12;red\e033\e\e' +.Ed .El .Sh FILES .Bl -tag -width "/etc/tmux.confXXX" -compact diff --git a/tmux.h b/tmux.h index 3056ac94..0444b56d 100644 --- a/tmux.h +++ b/tmux.h @@ -183,10 +183,12 @@ enum tty_code_code { TTYC_BEL, /* bell, bl */ TTYC_BLINK, /* enter_blink_mode, mb */ TTYC_BOLD, /* enter_bold_mode, md */ + TTYC_CC, /* set colour cursor, Cc */ TTYC_CIVIS, /* cursor_invisible, vi */ TTYC_CLEAR, /* clear_screen, cl */ TTYC_CNORM, /* cursor_normal, ve */ TTYC_COLORS, /* max_colors, Co */ + TTYC_CR, /* restore cursor colour, Cr */ TTYC_CSR, /* change_scroll_region, cs */ TTYC_CUB, /* parm_left_cursor, LE */ TTYC_CUB1, /* cursor_left, le */ @@ -714,6 +716,8 @@ struct screen { u_int cx; /* cursor x */ u_int cy; /* cursor y */ + char *ccolour; /* cursor colour string */ + u_int rupper; /* scroll region top */ u_int rlower; /* scroll region bottom */ @@ -1010,6 +1014,7 @@ struct tty { u_int cx; u_int cy; + char *ccolour; int mode; @@ -1414,6 +1419,7 @@ void tty_cursor(struct tty *, u_int, u_int); void tty_putcode(struct tty *, enum tty_code_code); void tty_putcode1(struct tty *, enum tty_code_code, int); void tty_putcode2(struct tty *, enum tty_code_code, int, int); +void tty_putcode_ptr1(struct tty *, enum tty_code_code, const void *); void tty_putcode_ptr2(struct tty *, enum tty_code_code, const void *, const void *); void tty_puts(struct tty *, const char *); void tty_putc(struct tty *, u_char); @@ -1423,7 +1429,8 @@ int tty_resize(struct tty *); void tty_start_tty(struct tty *); void tty_stop_tty(struct tty *); void tty_set_title(struct tty *, const char *); -void tty_update_mode(struct tty *, int); +void tty_update_mode(struct tty *, int, struct screen *); +void tty_force_cursor_colour(struct tty *, const char *); void tty_draw_line(struct tty *, struct screen *, u_int, u_int, u_int); int tty_open(struct tty *, const char *, char **); void tty_close(struct tty *); @@ -1459,6 +1466,8 @@ const char *tty_term_string(struct tty_term *, enum tty_code_code); const char *tty_term_string1(struct tty_term *, enum tty_code_code, int); const char *tty_term_string2( struct tty_term *, enum tty_code_code, int, int); +const char *tty_term_ptr1( + struct tty_term *, enum tty_code_code, const void *); const char *tty_term_ptr2( struct tty_term *, enum tty_code_code, const void *, const void *); int tty_term_number(struct tty_term *, enum tty_code_code); @@ -1841,6 +1850,7 @@ void screen_init(struct screen *, u_int, u_int, u_int); void screen_reinit(struct screen *); void screen_free(struct screen *); void screen_reset_tabs(struct screen *); +void screen_set_cursor_colour(struct screen *, const char *); void screen_set_title(struct screen *, const char *); void screen_resize(struct screen *, u_int, u_int); void screen_set_selection(struct screen *, diff --git a/tty-term.c b/tty-term.c index 7ad4628f..7083e2ab 100644 --- a/tty-term.c +++ b/tty-term.c @@ -38,10 +38,12 @@ const struct tty_term_code_entry tty_term_codes[NTTYCODE] = { { TTYC_BEL, TTYCODE_STRING, "bel" }, { TTYC_BLINK, TTYCODE_STRING, "blink" }, { TTYC_BOLD, TTYCODE_STRING, "bold" }, + { TTYC_CC, TTYCODE_STRING, "Cc" }, { TTYC_CIVIS, TTYCODE_STRING, "civis" }, { TTYC_CLEAR, TTYCODE_STRING, "clear" }, { TTYC_CNORM, TTYCODE_STRING, "cnorm" }, { TTYC_COLORS, TTYCODE_NUMBER, "colors" }, + { TTYC_CR, TTYCODE_STRING, "Cr" }, { TTYC_CSR, TTYCODE_STRING, "csr" }, { TTYC_CUB, TTYCODE_STRING, "cub" }, { TTYC_CUB1, TTYCODE_STRING, "cub1" }, @@ -493,6 +495,12 @@ tty_term_string2(struct tty_term *term, enum tty_code_code code, int a, int b) return (tparm((char *) tty_term_string(term, code), a, b)); } +const char * +tty_term_ptr1(struct tty_term *term, enum tty_code_code code, const void *a) +{ + return (tparm((char *) tty_term_string(term, code), a)); +} + const char * tty_term_ptr2(struct tty_term *term, enum tty_code_code code, const void *a, const void *b) { diff --git a/tty.c b/tty.c index 04503b60..5f3ada8e 100644 --- a/tty.c +++ b/tty.c @@ -69,6 +69,7 @@ tty_init(struct tty *tty, int fd, char *term) if ((path = ttyname(fd)) == NULL) fatalx("ttyname failed"); tty->path = xstrdup(path); + tty->ccolour = xstrdup(""); tty->flags = 0; tty->term_flags = 0; @@ -210,6 +211,8 @@ tty_start_tty(struct tty *tty) tty->mode = MODE_CURSOR; tty->flags |= TTY_STARTED; + + tty_force_cursor_colour(tty, ""); } void @@ -241,6 +244,7 @@ tty_stop_tty(struct tty *tty) tty_raw(tty, tty_term_string(tty->term, TTYC_SGR0)); tty_raw(tty, tty_term_string(tty->term, TTYC_RMKX)); tty_raw(tty, tty_term_string(tty->term, TTYC_CLEAR)); + tty_raw(tty, tty_term_string(tty->term, TTYC_CR)); tty_raw(tty, tty_term_string(tty->term, TTYC_CNORM)); if (tty_term_has(tty->term, TTYC_KMOUS)) @@ -280,6 +284,7 @@ tty_free(struct tty *tty) { tty_close(tty); + xfree(tty->ccolour); if (tty->path != NULL) xfree(tty->path); if (tty->termname != NULL) @@ -314,6 +319,13 @@ tty_putcode2(struct tty *tty, enum tty_code_code code, int a, int b) tty_puts(tty, tty_term_string2(tty->term, code, a, b)); } +void +tty_putcode_ptr1(struct tty *tty, enum tty_code_code code, const void *a) +{ + if (a != NULL) + tty_puts(tty, tty_term_ptr1(tty->term, code, a)); +} + void tty_putcode_ptr2(struct tty *tty, enum tty_code_code code, const void *a, const void *b) { @@ -389,10 +401,24 @@ tty_set_title(struct tty *tty, const char *title) } void -tty_update_mode(struct tty *tty, int mode) +tty_force_cursor_colour(struct tty *tty, const char *ccolour) +{ + if (*ccolour == '\0') + tty_putcode(tty, TTYC_CR); + else + tty_putcode_ptr1(tty, TTYC_CC, ccolour); + xfree(tty->ccolour); + tty->ccolour = xstrdup(ccolour); +} + +void +tty_update_mode(struct tty *tty, int mode, struct screen *s) { int changed; + if (strcmp(s->ccolour, tty->ccolour)) + tty_force_cursor_colour(tty, s->ccolour); + if (tty->flags & TTY_NOCURSOR) mode &= ~MODE_CURSOR; @@ -486,7 +512,7 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int py, u_int ox, u_int oy) const struct grid_utf8 *gu; u_int i, sx; - tty_update_mode(tty, tty->mode & ~MODE_CURSOR); + tty_update_mode(tty, tty->mode & ~MODE_CURSOR, s); sx = screen_size_x(s); if (sx > s->grid->linedata[s->grid->hsize + py].cellsize) @@ -526,7 +552,7 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int py, u_int ox, u_int oy) } if (sx >= tty->sx) { - tty_update_mode(tty, tty->mode); + tty_update_mode(tty, tty->mode, s); return; } tty_reset(tty); @@ -538,7 +564,7 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int py, u_int ox, u_int oy) for (i = sx; i < screen_size_x(s); i++) tty_putc(tty, ' '); } - tty_update_mode(tty, tty->mode); + tty_update_mode(tty, tty->mode, s); } void From 3ea5e06bfb04278fa53885e551bc363a84bad8d1 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 20 May 2011 19:17:39 +0000 Subject: [PATCH 0915/1180] Support DECSCUSR sequence to set the cursor style with two new terminfo(5) extensions, Cs and Csr. Written by Ailin Nemui. --- input.c | 6 ++++++ options-table.c | 1 + screen.c | 9 +++++++++ tmux.1 | 13 +++++++++++++ tmux.h | 5 +++++ tty-term.c | 2 ++ tty.c | 17 +++++++++++++++++ 7 files changed, 53 insertions(+) diff --git a/input.c b/input.c index 86d34b74..9c1c4dca 100644 --- a/input.c +++ b/input.c @@ -126,6 +126,7 @@ enum input_csi_type { INPUT_CSI_CUU, INPUT_CSI_DA, INPUT_CSI_DCH, + INPUT_CSI_DECSCUSR, INPUT_CSI_DECSTBM, INPUT_CSI_DL, INPUT_CSI_DSR, @@ -168,6 +169,7 @@ const struct input_table_entry input_csi_table[] = { { 'l', "?", INPUT_CSI_RM_PRIVATE }, { 'm', "", INPUT_CSI_SGR }, { 'n', "", INPUT_CSI_DSR }, + { 'q', " ", INPUT_CSI_DECSCUSR }, { 'r', "", INPUT_CSI_DECSTBM }, }; @@ -1259,6 +1261,10 @@ input_csi_dispatch(struct input_ctx *ictx) n = input_get(ictx, 0, 1, 1); screen_write_cursormove(sctx, s->cx, n - 1); break; + case INPUT_CSI_DECSCUSR: + n = input_get(ictx, 0, 0, 0); + screen_set_cursor_style(s, n); + break; } return (0); diff --git a/options-table.c b/options-table.c index c84c56a1..4b2f40bc 100644 --- a/options-table.c +++ b/options-table.c @@ -368,6 +368,7 @@ const struct options_table_entry session_options_table[] = { .default_str = "*88col*:colors=88,*256col*:colors=256" ",xterm*:XT:Ms=\\E]52;%p1%s;%p2%s\\007" ":Cc=\\E]12;%p1%s\\007:Cr=\\E]112\\007" + ":Cs=\\E[%p1%d q:Csr=\\E[2 q" }, { .name = "update-environment", diff --git a/screen.c b/screen.c index 5e3be88c..3c8a5235 100644 --- a/screen.c +++ b/screen.c @@ -40,6 +40,7 @@ screen_init(struct screen *s, u_int sx, u_int sy, u_int hlimit) else s->title = xstrdup(""); + s->cstyle = 0; s->ccolour = xstrdup(""); s->tabs = NULL; @@ -91,6 +92,14 @@ screen_reset_tabs(struct screen *s) bit_set(s->tabs, i); } +/* Set screen cursor style. */ +void +screen_set_cursor_style(struct screen *s, u_int style) +{ + if (style <= 4) + s->cstyle = style; +} + /* Set screen cursor colour. */ void screen_set_cursor_colour(struct screen *s, const char *colour_string) diff --git a/tmux.1 b/tmux.1 index dbe54d52..1e3c57b2 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2832,6 +2832,19 @@ See the option above and the .Xr xterm 1 man page. +.It Em Cs, Csr +Change the cursor style. +If set allows a sequence such as: +.Bd -literal -offset indent +$ printf '\e033[4 q' +.Ed +.Pp +To change the cursor to an underline. +If +.Em Csr +is set, it will be used to reset the cursor style instead +of +.Em Cs . .It Em Cc, Cr The first takes one string argument and is used to set the cursor colour; the second takes no arguments and restores the default cursor colour. diff --git a/tmux.h b/tmux.h index 0444b56d..adad1d7f 100644 --- a/tmux.h +++ b/tmux.h @@ -189,7 +189,9 @@ enum tty_code_code { TTYC_CNORM, /* cursor_normal, ve */ TTYC_COLORS, /* max_colors, Co */ TTYC_CR, /* restore cursor colour, Cr */ + TTYC_CS1, /* set cursor style, Cs */ TTYC_CSR, /* change_scroll_region, cs */ + TTYC_CSR1, /* reset cursor style, Csr */ TTYC_CUB, /* parm_left_cursor, LE */ TTYC_CUB1, /* cursor_left, le */ TTYC_CUD, /* parm_down_cursor, DO */ @@ -716,6 +718,7 @@ struct screen { u_int cx; /* cursor x */ u_int cy; /* cursor y */ + u_int cstyle; /* cursor style */ char *ccolour; /* cursor colour string */ u_int rupper; /* scroll region top */ @@ -1014,6 +1017,7 @@ struct tty { u_int cx; u_int cy; + u_int cstyle; char *ccolour; int mode; @@ -1850,6 +1854,7 @@ void screen_init(struct screen *, u_int, u_int, u_int); void screen_reinit(struct screen *); void screen_free(struct screen *); void screen_reset_tabs(struct screen *); +void screen_set_cursor_style(struct screen *, u_int); void screen_set_cursor_colour(struct screen *, const char *); void screen_set_title(struct screen *, const char *); void screen_resize(struct screen *, u_int, u_int); diff --git a/tty-term.c b/tty-term.c index 7083e2ab..41cb97c4 100644 --- a/tty-term.c +++ b/tty-term.c @@ -44,7 +44,9 @@ const struct tty_term_code_entry tty_term_codes[NTTYCODE] = { { TTYC_CNORM, TTYCODE_STRING, "cnorm" }, { TTYC_COLORS, TTYCODE_NUMBER, "colors" }, { TTYC_CR, TTYCODE_STRING, "Cr" }, + { TTYC_CS1, TTYCODE_STRING, "Cs" }, { TTYC_CSR, TTYCODE_STRING, "csr" }, + { TTYC_CSR1, TTYCODE_STRING, "Csr" }, { TTYC_CUB, TTYCODE_STRING, "cub" }, { TTYC_CUB1, TTYCODE_STRING, "cub1" }, { TTYC_CUD, TTYCODE_STRING, "cud" }, diff --git a/tty.c b/tty.c index 5f3ada8e..4fcf6f55 100644 --- a/tty.c +++ b/tty.c @@ -69,6 +69,7 @@ tty_init(struct tty *tty, int fd, char *term) if ((path = ttyname(fd)) == NULL) fatalx("ttyname failed"); tty->path = xstrdup(path); + tty->cstyle = 0; tty->ccolour = xstrdup(""); tty->flags = 0; @@ -244,6 +245,12 @@ tty_stop_tty(struct tty *tty) tty_raw(tty, tty_term_string(tty->term, TTYC_SGR0)); tty_raw(tty, tty_term_string(tty->term, TTYC_RMKX)); tty_raw(tty, tty_term_string(tty->term, TTYC_CLEAR)); + if (tty_term_has(tty->term, TTYC_CS1) && tty->cstyle != 0) { + if (tty_term_has(tty->term, TTYC_CSR1)) + tty_raw(tty, tty_term_string(tty->term, TTYC_CSR1)); + else if (tty_term_has(tty->term, TTYC_CS1)) + tty_raw(tty, tty_term_string1(tty->term, TTYC_CS1, 0)); + } tty_raw(tty, tty_term_string(tty->term, TTYC_CR)); tty_raw(tty, tty_term_string(tty->term, TTYC_CNORM)); @@ -429,6 +436,16 @@ tty_update_mode(struct tty *tty, int mode, struct screen *s) else tty_putcode(tty, TTYC_CIVIS); } + if (tty->cstyle != s->cstyle) { + if (tty_term_has(tty->term, TTYC_CS1)) { + if (s->cstyle == 0 && + tty_term_has(tty->term, TTYC_CSR1)) + tty_putcode(tty, TTYC_CSR1); + else + tty_putcode1(tty, TTYC_CS1, s->cstyle); + } + tty->cstyle = s->cstyle; + } if (changed & ALL_MOUSE_MODES) { if (mode & ALL_MOUSE_MODES) { if (mode & MODE_MOUSE_UTF8) From 1af2021de6b004c932832061c2c0a03581a52af4 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 20 May 2011 19:29:13 +0000 Subject: [PATCH 0916/1180] Pass prompts through status_replace so that they can be more helpful (such as showing the previous session name when renaming). From Tiago Cunha. --- cmd-command-prompt.c | 17 +++++++++++++---- tmux.1 | 9 ++++++++- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/cmd-command-prompt.c b/cmd-command-prompt.c index 0bb4e209..52ee747f 100644 --- a/cmd-command-prompt.c +++ b/cmd-command-prompt.c @@ -82,7 +82,7 @@ cmd_command_prompt_exec(struct cmd *self, struct cmd_ctx *ctx) const char *prompts; struct cmd_command_prompt_cdata *cdata; struct client *c; - char *prompt, *ptr; + char *prompt, *prompt_replaced, *ptr; size_t n; if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL) @@ -116,8 +116,12 @@ cmd_command_prompt_exec(struct cmd *self, struct cmd_ctx *ctx) ptr = strsep(&cdata->next_prompt, ","); if (prompts == NULL) prompt = xstrdup(ptr); - else - xasprintf(&prompt, "%s ", ptr); + else { + prompt_replaced = status_replace(c, NULL, NULL, NULL, ptr, + time(NULL), 0); + xasprintf(&prompt, "%s ", prompt_replaced); + xfree(prompt_replaced); + } status_prompt_set(c, prompt, cmd_command_prompt_callback, cmd_command_prompt_free, cdata, 0); xfree(prompt); @@ -133,6 +137,7 @@ cmd_command_prompt_callback(void *data, const char *s) struct cmd_list *cmdlist; struct cmd_ctx ctx; char *cause, *newtempl, *prompt, *ptr; + char *prompt_replaced; if (s == NULL) return (0); @@ -142,8 +147,12 @@ cmd_command_prompt_callback(void *data, const char *s) cdata->template = newtempl; if ((ptr = strsep(&cdata->next_prompt, ",")) != NULL) { - xasprintf(&prompt, "%s ", ptr); + prompt_replaced = status_replace(c, NULL, NULL, NULL, ptr, + time(NULL), 0); + xasprintf(&prompt, "%s ", prompt_replaced); status_prompt_update(c, prompt); + + xfree(prompt_replaced); xfree(prompt); cdata->idx++; return (1); diff --git a/tmux.1 b/tmux.1 index 1e3c57b2..87949d34 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1255,7 +1255,7 @@ The .Ar shell-command string may contain the special character sequences supported by the .Ic status-left -command. +option. If no .Ar shell-command is given, the current pipe (if any) is closed. @@ -2624,6 +2624,7 @@ Open the command prompt in a client. This may be used from inside .Nm to execute commands interactively. +.Pp If .Ar template is specified, it is used as the command. @@ -2637,6 +2638,12 @@ a single prompt is displayed, constructed from if it is present, or .Ql \&: if not. +The +.Ar prompts +may contain the special character sequences supported by the +.Ic status-left +option. +.Pp Before the command is executed, the first occurrence of the string .Ql %% and all occurrences of From 240cae4c92529ded71e13c5b5ae0a2f4bbe5ff95 Mon Sep 17 00:00:00 2001 From: Jason McIntyre Date: Sat, 21 May 2011 10:04:17 +0000 Subject: [PATCH 0917/1180] tweak the TERMINFO section; ok nicm --- tmux.1 | 45 +++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/tmux.1 b/tmux.1 index 87949d34..c5866c95 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2830,6 +2830,29 @@ Show server information and terminal details. understands some extensions to .Xr terminfo 5 : .Bl -tag -width Ds +.It Em Cc , Cr +Set the cursor color. +The first takes a single string argument and is used to set the colour; +the second takes no arguments and restores the default cursor colour. +If set, a sequence such as this may be used +to change the cursor colour from inside +.Nm : +.Bd -literal -offset indent +$ printf '\e033]12;red\e033\e\e' +.Ed +.It Em Cs , Csr +Change the cursor style. +If set, a sequence such as this may be used +to change the cursor to an underline: +.Bd -literal -offset indent +$ printf '\e033[4 q' +.Ed +.Pp +If +.Em Csr +is set, it will be used to reset the cursor style instead +of +.Em Cs . .It Em \&Ms This sequence can be used by .Nm @@ -2839,28 +2862,6 @@ See the option above and the .Xr xterm 1 man page. -.It Em Cs, Csr -Change the cursor style. -If set allows a sequence such as: -.Bd -literal -offset indent -$ printf '\e033[4 q' -.Ed -.Pp -To change the cursor to an underline. -If -.Em Csr -is set, it will be used to reset the cursor style instead -of -.Em Cs . -.It Em Cc, Cr -The first takes one string argument and is used to set the cursor colour; -the second takes no arguments and restores the default cursor colour. -If they present, a sequence such as this may be used to change the -cursor colour from inside -.Nm : -.Bd -literal -offset indent -$ printf '\e033]12;red\e033\e\e' -.Ed .El .Sh FILES .Bl -tag -width "/etc/tmux.confXXX" -compact From 70d232289b500300a63a4ac2c45dbe4acf15c2db Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 25 May 2011 17:50:52 +0000 Subject: [PATCH 0918/1180] Nuke a redundant if statement, from Tiago Cunha. --- cmd-if-shell.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/cmd-if-shell.c b/cmd-if-shell.c index b81985f8..f2b015d2 100644 --- a/cmd-if-shell.c +++ b/cmd-if-shell.c @@ -88,11 +88,7 @@ cmd_if_shell_callback(struct job *job) return; } - if (cmd_list_exec(cmdlist, ctx) < 0) { - cmd_list_free(cmdlist); - return; - } - + cmd_list_exec(cmdlist, ctx); cmd_list_free(cmdlist); } From 480e48aa66b094c68e9f058073b7c10319ac98d5 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 25 May 2011 17:51:31 +0000 Subject: [PATCH 0919/1180] Memory leak in error path, from Tiago Cunha. --- cmd-set-buffer.c | 1 + 1 file changed, 1 insertion(+) diff --git a/cmd-set-buffer.c b/cmd-set-buffer.c index f31f8a06..14fef135 100644 --- a/cmd-set-buffer.c +++ b/cmd-set-buffer.c @@ -61,6 +61,7 @@ cmd_set_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) if (cause != NULL) { ctx->error(ctx, "buffer %s", cause); xfree(cause); + xfree(pdata); return (-1); } From 34e5ec18074b05f8ffc95bdefe7f7037ff046ecf Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 26 May 2011 07:08:48 +0000 Subject: [PATCH 0920/1180] Trim another useless if statement, from Ailin Nemui. --- tty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tty.c b/tty.c index 4fcf6f55..efd779a6 100644 --- a/tty.c +++ b/tty.c @@ -248,7 +248,7 @@ tty_stop_tty(struct tty *tty) if (tty_term_has(tty->term, TTYC_CS1) && tty->cstyle != 0) { if (tty_term_has(tty->term, TTYC_CSR1)) tty_raw(tty, tty_term_string(tty->term, TTYC_CSR1)); - else if (tty_term_has(tty->term, TTYC_CS1)) + else tty_raw(tty, tty_term_string1(tty->term, TTYC_CS1, 0)); } tty_raw(tty, tty_term_string(tty->term, TTYC_CR)); From f537870909c024ff5aaa7b9d15f3af469811ab3c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 30 May 2011 21:02:28 +0000 Subject: [PATCH 0921/1180] Fix a typo, spotted by Michal Mazurek.. --- tmux.1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tmux.1 b/tmux.1 index c5866c95..f58b8863 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2831,7 +2831,7 @@ understands some extensions to .Xr terminfo 5 : .Bl -tag -width Ds .It Em Cc , Cr -Set the cursor color. +Set the cursor colour. The first takes a single string argument and is used to set the colour; the second takes no arguments and restores the default cursor colour. If set, a sequence such as this may be used From 2b60c648c4e0202ca2743fe958e0eabfc0479f55 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 5 Jun 2011 10:53:05 +0000 Subject: [PATCH 0922/1180] Get rid of the layout string code which tries to walk through the layout hierarchy and instead just look at what panes are actually in the window. --- Makefile | 2 +- cmd.c | 18 ++---- layout-custom.c | 11 ++++ layout-string.c | 168 ------------------------------------------------ tmux.h | 6 +- window.c | 62 +++++++++++++++--- 6 files changed, 74 insertions(+), 193 deletions(-) delete mode 100644 layout-string.c diff --git a/Makefile b/Makefile index c103d766..8bc766e1 100644 --- a/Makefile +++ b/Makefile @@ -31,7 +31,7 @@ SRCS= arguments.c attributes.c cfg.c client.c clock.c \ cmd-pipe-pane.c cmd-capture-pane.c cmd.c \ colour.c environ.c grid-view.c grid-utf8.c grid.c input-keys.c \ input.c key-bindings.c key-string.c \ - layout-custom.c layout-set.c layout-string.c layout.c log.c job.c \ + layout-custom.c layout-set.c layout.c log.c job.c \ mode-key.c names.c options.c options-table.c paste.c procname.c \ resize.c screen-redraw.c screen-write.c screen.c session.c status.c \ signal.c server-fn.c server.c server-client.c server-window.c \ diff --git a/cmd.c b/cmd.c index f1cba109..869fa0f5 100644 --- a/cmd.c +++ b/cmd.c @@ -1058,12 +1058,11 @@ struct winlink * cmd_find_pane(struct cmd_ctx *ctx, const char *arg, struct session **sp, struct window_pane **wpp) { - struct session *s; - struct winlink *wl; - struct layout_cell *lc; - const char *period, *errstr; - char *winptr, *paneptr; - u_int idx; + struct session *s; + struct winlink *wl; + const char *period, *errstr; + char *winptr, *paneptr; + u_int idx; /* Get the current session. */ if ((s = cmd_current_session(ctx, 0)) == NULL) { @@ -1119,11 +1118,10 @@ cmd_find_pane(struct cmd_ctx *ctx, lookup_string: /* Try pane string description. */ - if ((lc = layout_find_string(wl->window, paneptr)) == NULL) { + if ((*wpp = window_find_string(wl->window, paneptr)) == NULL) { ctx->error(ctx, "can't find pane: %s", paneptr); goto error; } - *wpp = lc->wp; xfree(winptr); return (wl); @@ -1142,10 +1140,8 @@ no_period: lookup_window: /* Try pane string description. */ - if ((lc = layout_find_string(s->curw->window, arg)) != NULL) { - *wpp = lc->wp; + if ((*wpp = window_find_string(s->curw->window, arg)) != NULL) return (s->curw); - } /* Try as a window and use the active pane. */ if ((wl = cmd_find_window(ctx, arg, sp)) != NULL) diff --git a/layout-custom.c b/layout-custom.c index 617e3170..9fb9cebd 100644 --- a/layout-custom.c +++ b/layout-custom.c @@ -23,11 +23,22 @@ #include "tmux.h" +struct layout_cell *layout_find_bottomright(struct layout_cell *); u_short layout_checksum(const char *); int layout_append(struct layout_cell *, char *, size_t); struct layout_cell *layout_construct(struct layout_cell *, const char **); void layout_assign(struct window_pane **, struct layout_cell *); +/* Find the bottom-right cell. */ +struct layout_cell * +layout_find_bottomright(struct layout_cell *lc) +{ + if (lc->type == LAYOUT_WINDOWPANE) + return (lc); + lc = TAILQ_LAST(&lc->cells, layout_cells); + return (layout_find_bottomright(lc)); +} + /* Calculate layout checksum. */ u_short layout_checksum(const char *layout) diff --git a/layout-string.c b/layout-string.c deleted file mode 100644 index 4b63f19a..00000000 --- a/layout-string.c +++ /dev/null @@ -1,168 +0,0 @@ -/* $OpenBSD$ */ - -/* - * Copyright (c) 2009 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 "tmux.h" - -/* - * Figure out the pane position based on a description. Fairly simple right - * now, just understands a set of strings: left, right, top, bottom, top-left - * top-right, bottom-left, bottom-right. - */ - -struct layout_cell *layout_find_top(struct layout_cell *); -struct layout_cell *layout_find_bottom(struct layout_cell *); -struct layout_cell *layout_find_left(struct layout_cell *); -struct layout_cell *layout_find_right(struct layout_cell *); -struct layout_cell *layout_find_topleft(struct layout_cell *); -struct layout_cell *layout_find_topright(struct layout_cell *); -struct layout_cell *layout_find_bottomleft(struct layout_cell *); - -/* Find the cell; returns NULL if string not understood. */ -struct layout_cell * -layout_find_string(struct window *w, const char *s) -{ - struct layout_cell *lc; - - lc = NULL; - - if (strcasecmp(s, "top") == 0) - lc = layout_find_top(w->layout_root); - else if (strcasecmp(s, "bottom") == 0) - lc = layout_find_bottom(w->layout_root); - else if (strcasecmp(s, "left") == 0) - lc = layout_find_left(w->layout_root); - else if (strcasecmp(s, "right") == 0) - lc = layout_find_right(w->layout_root); - else if (strcasecmp(s, "top-left") == 0) - lc = layout_find_topleft(w->layout_root); - else if (strcasecmp(s, "top-right") == 0) - lc = layout_find_topright(w->layout_root); - else if (strcasecmp(s, "bottom-left") == 0) - lc = layout_find_bottomleft(w->layout_root); - else if (strcasecmp(s, "bottom-right") == 0) - lc = layout_find_bottomright(w->layout_root); - - if (lc == NULL || lc->type != LAYOUT_WINDOWPANE) - return (NULL); - return (lc); -} - -/* - * Find the top cell. Because splits in the same direction are stored as a - * list, this is just the first in the list. Return NULL if no topmost cell. - * For an unnested cell (not split), the top cell is always itself. - */ -struct layout_cell * -layout_find_top(struct layout_cell *lc) -{ - if (lc->type == LAYOUT_WINDOWPANE) - return (lc); - else if (lc->type == LAYOUT_TOPBOTTOM) - return (TAILQ_FIRST(&lc->cells)); - return (NULL); -} - -/* - * Find the bottom cell. Similarly to the top cell, this is just the last in - * the list. - */ -struct layout_cell * -layout_find_bottom(struct layout_cell *lc) -{ - if (lc->type == LAYOUT_WINDOWPANE) - return (lc); - else if (lc->type == LAYOUT_TOPBOTTOM) - return (TAILQ_LAST(&lc->cells, layout_cells)); - return (NULL); -} - -/* Find the left cell. */ -struct layout_cell * -layout_find_left(struct layout_cell *lc) -{ - if (lc->type == LAYOUT_WINDOWPANE) - return (lc); - else if (lc->type == LAYOUT_LEFTRIGHT) - return (TAILQ_FIRST(&lc->cells)); - return (NULL); -} - -/* Find the right cell. */ -struct layout_cell * -layout_find_right(struct layout_cell *lc) -{ - if (lc->type == LAYOUT_WINDOWPANE) - return (lc); - else if (lc->type == LAYOUT_LEFTRIGHT) - return (TAILQ_LAST(&lc->cells, layout_cells)); - return (NULL); -} - -/* - * Find the top-left cell. This means recursing until there are no more moves - * to be made. - */ -struct layout_cell * -layout_find_topleft(struct layout_cell *lc) -{ - if (lc->type == LAYOUT_WINDOWPANE) - return (lc); - lc = TAILQ_FIRST(&lc->cells); - return (layout_find_topleft(lc)); -} - -/* Find the top-right cell. */ -struct layout_cell * -layout_find_topright(struct layout_cell *lc) -{ - if (lc->type == LAYOUT_WINDOWPANE) - return (lc); - if (lc->type == LAYOUT_LEFTRIGHT) - lc = TAILQ_LAST(&lc->cells, layout_cells); - else - lc = TAILQ_FIRST(&lc->cells); - return (layout_find_topright(lc)); -} - -/* Find the bottom-left cell. */ -struct layout_cell * -layout_find_bottomleft(struct layout_cell *lc) -{ - if (lc->type == LAYOUT_WINDOWPANE) - return (lc); - if (lc->type == LAYOUT_LEFTRIGHT) - lc = TAILQ_FIRST(&lc->cells); - else - lc = TAILQ_LAST(&lc->cells, layout_cells); - return (layout_find_bottomleft(lc)); -} - -/* Find the bottom-right cell. */ -struct layout_cell * -layout_find_bottomright(struct layout_cell *lc) -{ - if (lc->type == LAYOUT_WINDOWPANE) - return (lc); - lc = TAILQ_LAST(&lc->cells, layout_cells); - return (layout_find_bottomright(lc)); -} diff --git a/tmux.h b/tmux.h index adad1d7f..0634470e 100644 --- a/tmux.h +++ b/tmux.h @@ -1891,7 +1891,9 @@ struct window *window_create(const char *, const char *, const char *, const char *, struct environ *, struct termios *, u_int, u_int, u_int, char **); void window_destroy(struct window *); +struct window_pane *window_get_active_at(struct window *, u_int, u_int); void window_set_active_at(struct window *, u_int, u_int); +struct window_pane *window_find_string(struct window *, const char *); void window_set_active_pane(struct window *, struct window_pane *); struct window_pane *window_add_pane(struct window *, u_int); void window_resize(struct window *, u_int, u_int); @@ -1971,10 +1973,6 @@ u_int layout_set_next(struct window *); u_int layout_set_previous(struct window *); void layout_set_active_changed(struct window *); -/* layout-string.c */ -struct layout_cell *layout_find_string(struct window *, const char *); -struct layout_cell *layout_find_bottomright(struct layout_cell *); - /* window-clock.c */ extern const struct window_mode window_clock_mode; diff --git a/window.c b/window.c index d5f56898..ab3177e6 100644 --- a/window.c +++ b/window.c @@ -356,21 +356,65 @@ window_set_active_pane(struct window *w, struct window_pane *wp) } } +struct window_pane * +window_get_active_at(struct window *w, u_int x, u_int y) +{ + struct window_pane *wp; + + TAILQ_FOREACH(wp, &w->panes, entry) { + if (!window_pane_visible(wp)) + continue; + if (x < wp->xoff || x > wp->xoff + wp->sx) + continue; + if (y < wp->yoff || y > wp->yoff + wp->sy) + continue; + return (wp); + } + return (NULL); +} + void window_set_active_at(struct window *w, u_int x, u_int y) { struct window_pane *wp; - TAILQ_FOREACH(wp, &w->panes, entry) { - if (wp == w->active || !window_pane_visible(wp)) - continue; - if (x < wp->xoff || x >= wp->xoff + wp->sx) - continue; - if (y < wp->yoff || y >= wp->yoff + wp->sy) - continue; + wp = window_get_active_at(w, x, y); + if (wp != NULL && wp != w->active) window_set_active_pane(w, wp); - break; - } +} + +struct window_pane * +window_find_string(struct window *w, const char *s) +{ + u_int x, y; + + x = w->sx / 2; + y = w->sy / 2; + + if (strcasecmp(s, "top") == 0) + y = 0; + else if (strcasecmp(s, "bottom") == 0) + y = w->sy - 1; + else if (strcasecmp(s, "left") == 0) + x = 0; + else if (strcasecmp(s, "right") == 0) + x = w->sx - 1; + else if (strcasecmp(s, "top-left") == 0) { + x = 0; + y = 0; + } else if (strcasecmp(s, "top-right") == 0) { + x = w->sx - 1; + y = 0; + } else if (strcasecmp(s, "bottom-left") == 0) { + x = 0; + y = w->sy - 1; + } else if (strcasecmp(s, "bottom-right") == 0) { + x = w->sx - 1; + y = w->sy - 1; + } else + return (NULL); + + return (window_get_active_at(w, x, y)); } struct window_pane * From 65177b82be7eca053ce12eb05e7d0049124ff659 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 5 Jun 2011 11:19:03 +0000 Subject: [PATCH 0923/1180] Add a respawn-pane command, from Marcel Partap. --- Makefile | 2 +- cmd-respawn-pane.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++ cmd.c | 1 + tmux.1 | 15 ++++++++ tmux.h | 1 + 5 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 cmd-respawn-pane.c diff --git a/Makefile b/Makefile index 8bc766e1..4aea4841 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ SRCS= arguments.c attributes.c cfg.c client.c clock.c \ cmd-lock-server.c \ cmd-move-window.c cmd-new-session.c cmd-new-window.c \ cmd-paste-buffer.c \ - cmd-refresh-client.c \ + cmd-refresh-client.c cmd-respawn-pane.c \ cmd-rename-session.c cmd-rename-window.c cmd-resize-pane.c \ cmd-respawn-window.c cmd-rotate-window.c cmd-save-buffer.c \ cmd-select-layout.c cmd-select-pane.c cmd-select-window.c \ diff --git a/cmd-respawn-pane.c b/cmd-respawn-pane.c new file mode 100644 index 00000000..0201fafc --- /dev/null +++ b/cmd-respawn-pane.c @@ -0,0 +1,92 @@ +/* $Id$ */ + +/* + * Copyright (c) 2008 Nicholas Marriott + * Copyright (c) 2011 Marcel P. Partap + * + * 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 "tmux.h" + +/* + * Respawn a pane (restart the command). Kill existing if -k given. + */ + +int cmd_respawn_pane_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_respawn_pane_entry = { + "respawn-pane", "respawnp", + "kt:", 0, 1, + "[-k] " CMD_TARGET_PANE_USAGE " [command]", + 0, + NULL, + NULL, + cmd_respawn_pane_exec +}; + +int +cmd_respawn_pane_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct args *args = self->args; + struct winlink *wl; + struct window *w; + struct window_pane *wp; + u_int hlimit; + struct session *s; + struct environ env; + const char *cmd; + char *cause; + + if ((wl = cmd_find_pane(ctx, args_get(args, 't'), &s, &wp)) == NULL) + return (-1); + w = wl->window; + + if (!args_has(self->args, 'k') && wp->fd != -1) { + ctx->error(ctx, "pane still active: %s:%u.%u", + s->name, wl->idx, window_pane_index(w, wp)); + return (-1); + } + + environ_init(&env); + environ_copy(&global_environ, &env); + environ_copy(&s->environ, &env); + server_fill_environ(s, &env); + + window_pane_reset_mode(wp); + screen_free(&wp->base); + hlimit = options_get_number(&s->options, "history-limit"); + screen_init(&wp->base, wp->sx, wp->sy, hlimit); + wp->screen = &wp->base; + input_init(wp); + + if (args->argc != 0) + cmd = args->argv[0]; + else + cmd = NULL; + if (window_pane_spawn(wp, cmd, NULL, NULL, &env, s->tio, &cause) != 0) { + ctx->error(ctx, "respawn pane failed: %s", cause); + xfree(cause); + environ_free(&env); + return (-1); + } + wp->flags |= PANE_REDRAW; + server_status_window(w); + + environ_free(&env); + return (0); +} diff --git a/cmd.c b/cmd.c index 869fa0f5..db72337d 100644 --- a/cmd.c +++ b/cmd.c @@ -80,6 +80,7 @@ const struct cmd_entry *cmd_table[] = { &cmd_rename_session_entry, &cmd_rename_window_entry, &cmd_resize_pane_entry, + &cmd_respawn_pane_entry, &cmd_respawn_window_entry, &cmd_rotate_window_entry, &cmd_run_shell_entry, diff --git a/tmux.1 b/tmux.1 index f58b8863..7574a521 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1307,6 +1307,21 @@ and to the right with The .Ar adjustment is given in lines or cells (the default is 1). +.It Xo Ic respawn-pane +.Op Fl k +.Op Fl t Ar target-pane +.Op Ar shell-command +.Xc +.D1 (alias: Ic respawnp ) +Reactivate a pane in which the command has exited (see the +.Ic remain-on-exit +window option). +If +.Ar shell-command +is not given, the command used when the pane was created is executed. +The pane must be already inactive, unless +.Fl k +is given, in which case any existing command is killed. .It Xo Ic respawn-window .Op Fl k .Op Fl t Ar target-window diff --git a/tmux.h b/tmux.h index 0634470e..da50205a 100644 --- a/tmux.h +++ b/tmux.h @@ -1584,6 +1584,7 @@ extern const struct cmd_entry cmd_refresh_client_entry; extern const struct cmd_entry cmd_rename_session_entry; extern const struct cmd_entry cmd_rename_window_entry; extern const struct cmd_entry cmd_resize_pane_entry; +extern const struct cmd_entry cmd_respawn_pane_entry; extern const struct cmd_entry cmd_respawn_window_entry; extern const struct cmd_entry cmd_rotate_window_entry; extern const struct cmd_entry cmd_run_shell_entry; From 0503f83c64229b38f40e1ed6d0148c64521bf364 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 23 Jun 2011 10:02:49 +0000 Subject: [PATCH 0924/1180] Add a couple of extra xterm-style keys that gnome terminal provides, from Dustin Kirkland. --- xterm-keys.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/xterm-keys.c b/xterm-keys.c index fd9fee8a..1956c0b4 100644 --- a/xterm-keys.c +++ b/xterm-keys.c @@ -36,8 +36,8 @@ * * Rather than parsing them, just match against a table. * - * There are two forms for F1-F4 (\\033O_P or \\033[1;_P). We accept either but - * always output the latter (it comes first in the table). + * There are three forms for F1-F4 (\\033O_P and \\033O1;_P and \\033[1;_P). + * We accept any but always output the latter (it comes first in the table). */ int xterm_keys_match(const char *, const char *, size_t); @@ -50,12 +50,16 @@ struct xterm_keys_entry { const struct xterm_keys_entry xterm_keys_table[] = { { KEYC_F1, "\033[1;_P" }, + { KEYC_F1, "\033O1;_P" }, { KEYC_F1, "\033O_P" }, { KEYC_F2, "\033[1;_Q" }, + { KEYC_F2, "\033O1;_Q" }, { KEYC_F2, "\033O_Q" }, { KEYC_F3, "\033[1;_R" }, + { KEYC_F3, "\033O1;_R" }, { KEYC_F3, "\033O_R" }, { KEYC_F4, "\033[1;_S" }, + { KEYC_F4, "\033O1;_S" }, { KEYC_F4, "\033O_S" }, { KEYC_F5, "\033[15;_~" }, { KEYC_F6, "\033[17;_~" }, From 1202284f3728f98e2c40648f6813c64676547ef9 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 27 Jun 2011 00:04:49 +0000 Subject: [PATCH 0925/1180] PANE_FREEZE doesn't do anything anymore, so remove it. --- tmux.h | 1 - window-copy.c | 2 -- 2 files changed, 3 deletions(-) diff --git a/tmux.h b/tmux.h index da50205a..2f7fcd6a 100644 --- a/tmux.h +++ b/tmux.h @@ -807,7 +807,6 @@ struct window_pane { int flags; #define PANE_REDRAW 0x1 -#define PANE_FREEZE 0x2 char *cmd; char *shell; diff --git a/window-copy.c b/window-copy.c index 1c060dc0..a129118c 100644 --- a/window-copy.c +++ b/window-copy.c @@ -170,7 +170,6 @@ window_copy_init(struct window_pane *wp) data->searchtype = WINDOW_COPY_OFF; data->searchstr = NULL; - wp->flags |= PANE_FREEZE; if (wp->fd != -1) bufferevent_disable(wp->event, EV_READ|EV_WRITE); @@ -234,7 +233,6 @@ window_copy_free(struct window_pane *wp) { struct window_copy_mode_data *data = wp->modedata; - wp->flags &= ~PANE_FREEZE; if (wp->fd != -1) bufferevent_enable(wp->event, EV_READ|EV_WRITE); From ad60a2c952694919ed3985855ef5a00939a937b8 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 2 Jul 2011 21:05:44 +0000 Subject: [PATCH 0926/1180] Allow the initial context on prompts to be set with the new -I option to command-prompt. From Tiago Cunha. --- cmd-command-prompt.c | 60 +++++++++++++++++++++++++++++++++++--------- cmd-confirm-before.c | 5 ++-- status.c | 19 +++++++++----- tmux.1 | 9 ++++++- tmux.h | 4 +-- 5 files changed, 73 insertions(+), 24 deletions(-) diff --git a/cmd-command-prompt.c b/cmd-command-prompt.c index 52ee747f..48a11916 100644 --- a/cmd-command-prompt.c +++ b/cmd-command-prompt.c @@ -20,6 +20,7 @@ #include #include +#include #include "tmux.h" @@ -36,8 +37,8 @@ void cmd_command_prompt_free(void *); const struct cmd_entry cmd_command_prompt_entry = { "command-prompt", NULL, - "p:t:", 0, 1, - CMD_TARGET_CLIENT_USAGE " [-p prompts] [template]", + "I:p:t:", 0, 1, + "[-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE " [template]", 0, cmd_command_prompt_key_binding, NULL, @@ -46,6 +47,8 @@ const struct cmd_entry cmd_command_prompt_entry = { struct cmd_command_prompt_cdata { struct client *c; + char *inputs; + char *next_input; char *next_prompt; char *prompts; char *template; @@ -79,9 +82,10 @@ int cmd_command_prompt_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; - const char *prompts; + const char *inputs, *prompts; struct cmd_command_prompt_cdata *cdata; struct client *c; + char *input = NULL; char *prompt, *prompt_replaced, *ptr; size_t n; @@ -94,6 +98,8 @@ cmd_command_prompt_exec(struct cmd *self, struct cmd_ctx *ctx) cdata = xmalloc(sizeof *cdata); cdata->c = c; cdata->idx = 1; + cdata->inputs = NULL; + cdata->next_input = NULL; cdata->next_prompt = NULL; cdata->prompts = NULL; cdata->template = NULL; @@ -103,8 +109,7 @@ cmd_command_prompt_exec(struct cmd *self, struct cmd_ctx *ctx) else cdata->template = xstrdup("%1"); - prompts = args_get(args, 'p'); - if (prompts != NULL) + if ((prompts = args_get(args, 'p')) != NULL) cdata->prompts = xstrdup(prompts); else if (args->argc != 0) { n = strcspn(cdata->template, " ,"); @@ -112,6 +117,7 @@ cmd_command_prompt_exec(struct cmd *self, struct cmd_ctx *ctx) } else cdata->prompts = xstrdup(":"); + /* Get first prompt. */ cdata->next_prompt = cdata->prompts; ptr = strsep(&cdata->next_prompt, ","); if (prompts == NULL) @@ -122,8 +128,22 @@ cmd_command_prompt_exec(struct cmd *self, struct cmd_ctx *ctx) xasprintf(&prompt, "%s ", prompt_replaced); xfree(prompt_replaced); } - status_prompt_set(c, prompt, cmd_command_prompt_callback, + + /* Get initial prompt input. */ + if ((inputs = args_get(args, 'I')) != NULL) { + cdata->inputs = xstrdup(inputs); + cdata->next_input = cdata->inputs; + ptr = strsep(&cdata->next_input, ","); + + input = status_replace(c, NULL, NULL, NULL, ptr, time(NULL), + 0); + } + + status_prompt_set(c, prompt, input, cmd_command_prompt_callback, cmd_command_prompt_free, cdata, 0); + + if (input != NULL) + xfree(input); xfree(prompt); return (0); @@ -136,29 +156,43 @@ cmd_command_prompt_callback(void *data, const char *s) struct client *c = cdata->c; struct cmd_list *cmdlist; struct cmd_ctx ctx; - char *cause, *newtempl, *prompt, *ptr; - char *prompt_replaced; + char *cause, *new_template, *prompt; + char *prompt_replaced, *ptr, *input = NULL; if (s == NULL) return (0); - newtempl = cmd_template_replace(cdata->template, s, cdata->idx); + new_template = cmd_template_replace(cdata->template, s, cdata->idx); xfree(cdata->template); - cdata->template = newtempl; + cdata->template = new_template; + /* + * Check if there are more prompts; if so, get its respective input + * and update the prompt data. + */ if ((ptr = strsep(&cdata->next_prompt, ",")) != NULL) { prompt_replaced = status_replace(c, NULL, NULL, NULL, ptr, time(NULL), 0); xasprintf(&prompt, "%s ", prompt_replaced); - status_prompt_update(c, prompt); + /* Find next input and expand special sequences. */ + if ((ptr = strsep(&cdata->next_input, ",")) != NULL) { + input = status_replace(c, NULL, NULL, NULL, ptr, + time(NULL), 0); + } + + status_prompt_update(c, prompt, input); + + if (input != NULL) + xfree(input); xfree(prompt_replaced); xfree(prompt); + cdata->idx++; return (1); } - if (cmd_string_parse(newtempl, &cmdlist, &cause) != 0) { + if (cmd_string_parse(new_template, &cmdlist, &cause) != 0) { if (cause != NULL) { *cause = toupper((u_char) *cause); status_message_set(c, "%s", cause); @@ -189,6 +223,8 @@ cmd_command_prompt_free(void *data) { struct cmd_command_prompt_cdata *cdata = data; + if (cdata->inputs != NULL) + xfree(cdata->inputs); if (cdata->prompts != NULL) xfree(cdata->prompts); if (cdata->template != NULL) diff --git a/cmd-confirm-before.c b/cmd-confirm-before.c index b19d69d7..958453e2 100644 --- a/cmd-confirm-before.c +++ b/cmd-confirm-before.c @@ -87,9 +87,8 @@ cmd_confirm_before_exec(struct cmd *self, struct cmd_ctx *ctx) cdata = xmalloc(sizeof *cdata); cdata->cmd = xstrdup(args->argv[0]); cdata->c = c; - status_prompt_set(cdata->c, buf, - cmd_confirm_before_callback, cmd_confirm_before_free, cdata, - PROMPT_SINGLE); + status_prompt_set(cdata->c, buf, NULL, cmd_confirm_before_callback, + cmd_confirm_before_free, cdata, PROMPT_SINGLE); xfree(buf); return (1); diff --git a/status.c b/status.c index 46ff3633..6cf4e3dc 100644 --- a/status.c +++ b/status.c @@ -815,7 +815,7 @@ status_message_redraw(struct client *c) /* Enable status line prompt. */ void -status_prompt_set(struct client *c, const char *msg, +status_prompt_set(struct client *c, const char *msg, const char *input, int (*callbackfn)(void *, const char *), void (*freefn)(void *), void *data, int flags) { @@ -826,8 +826,11 @@ status_prompt_set(struct client *c, const char *msg, c->prompt_string = xstrdup(msg); - c->prompt_buffer = xstrdup(""); - c->prompt_index = 0; + if (input != NULL) + c->prompt_buffer = xstrdup(input); + else + c->prompt_buffer = xstrdup(""); + c->prompt_index = strlen(c->prompt_buffer); c->prompt_callbackfn = callbackfn; c->prompt_freefn = freefn; @@ -871,13 +874,17 @@ status_prompt_clear(struct client *c) /* Update status line prompt with a new prompt string. */ void -status_prompt_update(struct client *c, const char *msg) +status_prompt_update(struct client *c, const char *msg, const char *input) { xfree(c->prompt_string); c->prompt_string = xstrdup(msg); - *c->prompt_buffer = '\0'; - c->prompt_index = 0; + xfree(c->prompt_buffer); + if (input != NULL) + c->prompt_buffer = xstrdup(input); + else + c->prompt_buffer = xstrdup(""); + c->prompt_index = strlen(c->prompt_buffer); c->prompt_hindex = 0; diff --git a/tmux.1 b/tmux.1 index 7574a521..d33f7857 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2631,6 +2631,7 @@ session option. Commands related to the status line are as follows: .Bl -tag -width Ds .It Xo Ic command-prompt +.Op Fl I Ar inputs .Op Fl p Ar prompts .Op Fl t Ar target-client .Op Ar template @@ -2643,6 +2644,9 @@ to execute commands interactively. If .Ar template is specified, it is used as the command. +If present, +.Fl I +is a comma-separated list of the initial text for each prompt. If .Fl p is given, @@ -2653,7 +2657,10 @@ a single prompt is displayed, constructed from if it is present, or .Ql \&: if not. -The +.Pp +Both +.Ar inputs +and .Ar prompts may contain the special character sequences supported by the .Ic status-left diff --git a/tmux.h b/tmux.h index 2f7fcd6a..5c2a5a81 100644 --- a/tmux.h +++ b/tmux.h @@ -1704,12 +1704,12 @@ char *status_replace(struct client *, struct session *, void printflike2 status_message_set(struct client *, const char *, ...); void status_message_clear(struct client *); int status_message_redraw(struct client *); -void status_prompt_set(struct client *, const char *, +void status_prompt_set(struct client *, const char *, const char *, int (*)(void *, const char *), void (*)(void *), void *, int); void status_prompt_clear(struct client *); int status_prompt_redraw(struct client *); void status_prompt_key(struct client *, int); -void status_prompt_update(struct client *, const char *); +void status_prompt_update(struct client *, const char *, const char *); /* resize.c */ void recalculate_sizes(void); From 94f86edfee9480b0e35af8adc2e4371b3caa3bca Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 3 Jul 2011 18:18:15 +0000 Subject: [PATCH 0927/1180] Include the existing window and session name in the prompt when renaming and add a new key binding ($) for rename session. From Tiago Cunha. --- cmd-command-prompt.c | 5 +++++ key-bindings.c | 1 + tmux.1 | 2 ++ 3 files changed, 8 insertions(+) diff --git a/cmd-command-prompt.c b/cmd-command-prompt.c index 48a11916..f0f1d12d 100644 --- a/cmd-command-prompt.c +++ b/cmd-command-prompt.c @@ -59,8 +59,13 @@ void cmd_command_prompt_key_binding(struct cmd *self, int key) { switch (key) { + case '$': + self->args = args_create(1, "rename-session '%%'"); + args_set(self->args, 'I', "#S"); + break; case ',': self->args = args_create(1, "rename-window '%%'"); + args_set(self->args, 'I', "#W"); break; case '.': self->args = args_create(1, "move-window -t '%%'"); diff --git a/key-bindings.c b/key-bindings.c index a3f7fb42..fe8a7576 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -106,6 +106,7 @@ key_bindings_init(void) { '!', 0, &cmd_break_pane_entry }, { '"', 0, &cmd_split_window_entry }, { '#', 0, &cmd_list_buffers_entry }, + { '$', 0, &cmd_command_prompt_entry }, { '%', 0, &cmd_split_window_entry }, { '&', 0, &cmd_confirm_before_entry }, { '(', 0, &cmd_switch_client_entry }, diff --git a/tmux.1 b/tmux.1 index d33f7857..60d900a3 100644 --- a/tmux.1 +++ b/tmux.1 @@ -233,6 +233,8 @@ Break the current pane out of the window. Split the current pane into two, top and bottom. .It # List all paste buffers. +.It $ +Rename the current session. .It % Split the current pane into two, left and right. .It & From f12158bc258c9d1e1d64d55c436b5a94adabd3e8 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 3 Jul 2011 19:07:54 +0000 Subject: [PATCH 0928/1180] Add an option to trigger the terminal bell when there is an alert, from Marco Beck. --- options-table.c | 5 +++++ server-window.c | 22 ++++++++++++++++++++++ tmux.1 | 5 +++++ 3 files changed, 32 insertions(+) diff --git a/options-table.c b/options-table.c index 4b2f40bc..4a385051 100644 --- a/options-table.c +++ b/options-table.c @@ -98,6 +98,11 @@ const struct options_table_entry session_options_table[] = { .default_num = BELL_ANY }, + { .name = "bell-on-alert", + .type = OPTIONS_TABLE_FLAG, + .default_num = 0 + }, + { .name = "default-command", .type = OPTIONS_TABLE_STRING, .default_str = "" diff --git a/server-window.c b/server-window.c index b081355c..b444982d 100644 --- a/server-window.c +++ b/server-window.c @@ -28,6 +28,7 @@ int server_window_check_activity(struct session *, struct winlink *); int server_window_check_silence(struct session *, struct winlink *); int server_window_check_content( struct session *, struct winlink *, struct window_pane *); +void ring_bell(struct session *); /* Window functions that need to happen every loop. */ void @@ -134,6 +135,8 @@ server_window_check_activity(struct session *s, struct winlink *wl) if (!options_get_number(&w->options, "monitor-activity")) return (0); + if (options_get_number(&s->options, "bell-on-alert")) + ring_bell(s); wl->flags |= WINLINK_ACTIVITY; if (options_get_number(&s->options, "visual-activity")) { @@ -183,6 +186,9 @@ server_window_check_silence(struct session *s, struct winlink *wl) timer_difference = timer.tv_sec - w->silence_timer.tv_sec; if (timer_difference <= silence_interval) return (0); + + if (options_get_number(&s->options, "bell-on-alert")) + ring_bell(s); wl->flags |= WINLINK_SILENCE; if (options_get_number(&s->options, "visual-silence")) { @@ -221,6 +227,8 @@ server_window_check_content( return (0); xfree(found); + if (options_get_number(&s->options, "bell-on-alert")) + ring_bell(s); wl->flags |= WINLINK_CONTENT; if (options_get_number(&s->options, "visual-content")) { @@ -235,3 +243,17 @@ server_window_check_content( return (1); } + +/* Ring terminal bell. */ +void +ring_bell(struct session *s) +{ + struct client *c; + u_int i; + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c != NULL && c->session == s) + tty_putcode(&c->tty, TTYC_BEL); + } +} diff --git a/tmux.1 b/tmux.1 index 60d900a3..69ea5819 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1779,6 +1779,11 @@ window of that session, means all bells are ignored and .Ic current means only bell in windows other than the current window are ignored. +.It Xo Ic bell-on-alert +.Op Ic on | off +.Xc +If on, ring the terminal bell when an activity, content or silence alert +occurs. .It Ic default-command Ar shell-command Set the command used for new windows (if not specified when the window is created) to From 5e90476b25d6fc0b6f7e869a63c7cce855e68c27 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 4 Jul 2011 00:31:57 +0000 Subject: [PATCH 0929/1180] Change the list-keys format so that it shows the keys using actual tmux commands which should be able to be directly copied into the config file. From Markus Schnalke, tweaked by me. --- cmd-list-keys.c | 54 ++++++++++++++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 21 deletions(-) diff --git a/cmd-list-keys.c b/cmd-list-keys.c index c6c391a2..8838060e 100644 --- a/cmd-list-keys.c +++ b/cmd-list-keys.c @@ -46,7 +46,7 @@ cmd_list_keys_exec(struct cmd *self, struct cmd_ctx *ctx) struct args *args = self->args; struct key_binding *bd; const char *key; - char tmp[BUFSIZ]; + char tmp[BUFSIZ], flags[8]; size_t used; int width, keywidth; @@ -59,9 +59,14 @@ cmd_list_keys_exec(struct cmd *self, struct cmd_ctx *ctx) if (key == NULL) continue; - keywidth = strlen(key) + 1; - if (!(bd->key & KEYC_PREFIX)) - keywidth += 2; + keywidth = strlen(key); + if (!(bd->key & KEYC_PREFIX)) { + if (bd->can_repeat) + keywidth += 4; + else + keywidth += 3; + } else if (bd->can_repeat) + keywidth += 3; if (keywidth > width) width = keywidth; } @@ -70,22 +75,22 @@ cmd_list_keys_exec(struct cmd *self, struct cmd_ctx *ctx) key = key_string_lookup_key(bd->key & ~KEYC_PREFIX); if (key == NULL) continue; - used = xsnprintf(tmp, sizeof tmp, "%*s: ", width, key); + + if (!(bd->key & KEYC_PREFIX)) { + if (bd->can_repeat) + xsnprintf(flags, sizeof flags, "-rn "); + else + xsnprintf(flags, sizeof flags, "-n "); + } else if (bd->can_repeat) + xsnprintf(flags, sizeof flags, "-r "); + + used = xsnprintf(tmp, sizeof tmp, "%s%*s ", + flags, (int) (width - strlen(flags)), key); if (used >= sizeof tmp) continue; - if (!(bd->key & KEYC_PREFIX)) { - used = strlcat(tmp, "(no prefix) ", sizeof tmp); - if (used >= sizeof tmp) - continue; - } - if (bd->can_repeat) { - used = strlcat(tmp, "(repeat) ", sizeof tmp); - if (used >= sizeof tmp) - continue; - } cmd_list_print(bd->cmdlist, tmp + used, (sizeof tmp) - used); - ctx->print(ctx, "%s", tmp); + ctx->print(ctx, "bind-key %s", tmp); } return (0); @@ -99,7 +104,7 @@ cmd_list_keys_table(struct cmd *self, struct cmd_ctx *ctx) const struct mode_key_table *mtab; struct mode_key_binding *mbind; const char *key, *cmdstr, *mode; - int width, keywidth; + int width, keywidth, any_mode; tablename = args_get(args, 't'); if ((mtab = mode_key_findtable(tablename)) == NULL) { @@ -108,12 +113,16 @@ cmd_list_keys_table(struct cmd *self, struct cmd_ctx *ctx) } width = 0; + any_mode = 0; SPLAY_FOREACH(mbind, mode_key_tree, mtab->tree) { key = key_string_lookup_key(mbind->key); if (key == NULL) continue; - keywidth = strlen(key) + 1; + if (mbind->mode != 0) + any_mode = 1; + + keywidth = strlen(key); if (keywidth > width) width = keywidth; } @@ -125,10 +134,13 @@ cmd_list_keys_table(struct cmd *self, struct cmd_ctx *ctx) mode = ""; if (mbind->mode != 0) - mode = "(command mode) "; + mode = "c"; cmdstr = mode_key_tostring(mtab->cmdstr, mbind->cmd); - if (cmdstr != NULL) - ctx->print(ctx, "%*s: %s%s", width, key, mode, cmdstr); + if (cmdstr != NULL) { + ctx->print(ctx, "bind-key -%st %s%s %*s %s", + mode, any_mode && *mode == '\0' ? " " : "", + mtab->name, (int) width, key, cmdstr); + } } return (0); From a70379d8f9579614b1faf286f3766e3f48693cc8 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 4 Jul 2011 13:35:37 +0000 Subject: [PATCH 0930/1180] Use screen_reinit for respawn-pane to keep history and call input_init for respawn-window to break out of waiting for DCS/OSC to finish. --- cmd-respawn-pane.c | 5 +---- cmd-respawn-window.c | 2 ++ 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/cmd-respawn-pane.c b/cmd-respawn-pane.c index 0201fafc..5e0d16bc 100644 --- a/cmd-respawn-pane.c +++ b/cmd-respawn-pane.c @@ -68,10 +68,7 @@ cmd_respawn_pane_exec(struct cmd *self, struct cmd_ctx *ctx) server_fill_environ(s, &env); window_pane_reset_mode(wp); - screen_free(&wp->base); - hlimit = options_get_number(&s->options, "history-limit"); - screen_init(&wp->base, wp->sx, wp->sy, hlimit); - wp->screen = &wp->base; + screen_reinit(&wp->base); input_init(wp); if (args->argc != 0) diff --git a/cmd-respawn-window.c b/cmd-respawn-window.c index 30601fe5..319262e5 100644 --- a/cmd-respawn-window.c +++ b/cmd-respawn-window.c @@ -87,7 +87,9 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_ctx *ctx) return (-1); } layout_init(w); + window_pane_reset_mode(wp); screen_reinit(&wp->base); + input_init(wp); window_set_active_pane(w, wp); recalculate_sizes(); From 26aa0689a52a9c93089c5fc7e68203c4209201cd Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 4 Jul 2011 14:04:40 +0000 Subject: [PATCH 0931/1180] Show full targets for lsp/lsw -a. --- cmd-list-panes.c | 50 +++++++++++++++++++++++++++++++++------------- cmd-list-windows.c | 22 +++++++++++++------- 2 files changed, 51 insertions(+), 21 deletions(-) diff --git a/cmd-list-panes.c b/cmd-list-panes.c index 60324e64..ce4b4906 100644 --- a/cmd-list-panes.c +++ b/cmd-list-panes.c @@ -29,8 +29,9 @@ int cmd_list_panes_exec(struct cmd *, struct cmd_ctx *); void cmd_list_panes_server(struct cmd_ctx *); -void cmd_list_panes_session(struct session *, struct cmd_ctx *); -void cmd_list_panes_window(struct winlink *, struct cmd_ctx *); +void cmd_list_panes_session(struct session *, struct cmd_ctx *, int); +void cmd_list_panes_window( + struct session *, struct winlink *, struct cmd_ctx *, int); const struct cmd_entry cmd_list_panes_entry = { "list-panes", "lsp", @@ -55,12 +56,12 @@ cmd_list_panes_exec(struct cmd *self, struct cmd_ctx *ctx) s = cmd_find_session(ctx, args_get(args, 't'), 0); if (s == NULL) return (-1); - cmd_list_panes_session(s, ctx); + cmd_list_panes_session(s, ctx, 1); } else { - wl = cmd_find_window(ctx, args_get(args, 't'), NULL); + wl = cmd_find_window(ctx, args_get(args, 't'), &s); if (wl == NULL) return (-1); - cmd_list_panes_window(wl, ctx); + cmd_list_panes_window(s, wl, ctx, 0); } return (0); @@ -72,20 +73,21 @@ cmd_list_panes_server(struct cmd_ctx *ctx) struct session *s; RB_FOREACH(s, sessions, &sessions) - cmd_list_panes_session(s, ctx); + cmd_list_panes_session(s, ctx, 2); } void -cmd_list_panes_session(struct session *s, struct cmd_ctx *ctx) +cmd_list_panes_session(struct session *s, struct cmd_ctx *ctx, int type) { struct winlink *wl; RB_FOREACH(wl, winlinks, &s->windows) - cmd_list_panes_window(wl, ctx); + cmd_list_panes_window(s, wl, ctx, type); } void -cmd_list_panes_window(struct winlink *wl, struct cmd_ctx *ctx) +cmd_list_panes_window( + struct session *s, struct winlink *wl, struct cmd_ctx *ctx, int type) { struct window_pane *wp; struct grid *gd; @@ -105,11 +107,31 @@ cmd_list_panes_window(struct winlink *wl, struct cmd_ctx *ctx) } size += gd->hsize * sizeof *gd->linedata; - ctx->print(ctx, - "%u: [%ux%u] [history %u/%u, %llu bytes] %%%u%s%s", - n, wp->sx, wp->sy, gd->hsize, gd->hlimit, size, wp->id, - wp == wp->window->active ? " (active)" : "", - wp->fd == -1 ? " (dead)" : ""); + switch (type) { + case 0: + ctx->print(ctx, + "%u: [%ux%u] [history %u/%u, %llu bytes] %%%u%s%s", + n, wp->sx, wp->sy, gd->hsize, gd->hlimit, size, + wp->id, wp == wp->window->active ? " (active)" : "", + wp->fd == -1 ? " (dead)" : ""); + break; + case 1: + ctx->print(ctx, + "%d.%u: [%ux%u] [history %u/%u, %llu bytes] " + "%%%u%s%s", wl->idx, + n, wp->sx, wp->sy, gd->hsize, gd->hlimit, size, + wp->id, wp == wp->window->active ? " (active)" : "", + wp->fd == -1 ? " (dead)" : ""); + break; + case 2: + ctx->print(ctx, + "%s:%d.%u: [%ux%u] [history %u/%u, %llu bytes] " + "%%%u%s%s", s->name, wl->idx, + n, wp->sx, wp->sy, gd->hsize, gd->hlimit, size, + wp->id, wp == wp->window->active ? " (active)" : "", + wp->fd == -1 ? " (dead)" : ""); + break; + } n++; } } diff --git a/cmd-list-windows.c b/cmd-list-windows.c index 11d38412..239f69f7 100644 --- a/cmd-list-windows.c +++ b/cmd-list-windows.c @@ -29,7 +29,7 @@ int cmd_list_windows_exec(struct cmd *, struct cmd_ctx *); void cmd_list_windows_server(struct cmd_ctx *); -void cmd_list_windows_session(struct session *, struct cmd_ctx *); +void cmd_list_windows_session(struct session *, struct cmd_ctx *, int); const struct cmd_entry cmd_list_windows_entry = { "list-windows", "lsw", @@ -53,7 +53,7 @@ cmd_list_windows_exec(struct cmd *self, struct cmd_ctx *ctx) s = cmd_find_session(ctx, args_get(args, 't'), 0); if (s == NULL) return (-1); - cmd_list_windows_session(s, ctx); + cmd_list_windows_session(s, ctx, 0); } return (0); @@ -65,20 +65,28 @@ cmd_list_windows_server(struct cmd_ctx *ctx) struct session *s; RB_FOREACH(s, sessions, &sessions) - cmd_list_windows_session(s, ctx); + cmd_list_windows_session(s, ctx, 1); } void -cmd_list_windows_session(struct session *s, struct cmd_ctx *ctx) +cmd_list_windows_session(struct session *s, struct cmd_ctx *ctx, int type) { struct winlink *wl; char *layout; RB_FOREACH(wl, winlinks, &s->windows) { layout = layout_dump(wl->window); - ctx->print(ctx, "%d: %s [%ux%u] [layout %s]%s", - wl->idx, wl->window->name, wl->window->sx, wl->window->sy, - layout, wl == s->curw ? " (active)" : ""); + if (type) { + ctx->print(ctx, "%s:%d: %s [%ux%u] [layout %s]%s", + s->name, wl->idx, wl->window->name, wl->window->sx, + wl->window->sy, layout, + wl == s->curw ? " (active)" : ""); + } else { + ctx->print(ctx, "%d: %s [%ux%u] [layout %s]%s", + wl->idx, wl->window->name, wl->window->sx, + wl->window->sy, layout, + wl == s->curw ? " (active)" : ""); + } xfree(layout); } } From b4b3d9c936b9e22eb835dd1d8b65e689fc66fb6c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 8 Jul 2011 06:28:05 +0000 Subject: [PATCH 0932/1180] Fix a couple of comments. --- input.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/input.c b/input.c index 9c1c4dca..9237ef5c 100644 --- a/input.c +++ b/input.c @@ -555,7 +555,7 @@ const struct input_transition input_state_dcs_escape_table[] = { { -1, -1, NULL, NULL } }; -/* device_ignore state table. */ +/* dcs_ignore state table. */ const struct input_transition input_state_dcs_ignore_table[] = { INPUT_STATE_ANYWHERE, @@ -791,7 +791,7 @@ input_split(struct input_ctx *ictx) return (0); } -/* Get an argument or return default value..*/ +/* Get an argument or return default value. */ int input_get(struct input_ctx *ictx, u_int validx, int minval, int defval) { From 2de9b1e005be97c6f1acdd6e24803e01badff52c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 8 Jul 2011 06:37:57 +0000 Subject: [PATCH 0933/1180] Make confirm-before prompt customizable with -p option like command-prompt. Also move responsibility for calling status_replace into status_prompt_{set,update} and add #W and #P to the default kill-window and kill-pane prompts. By Tiago Cunha. --- cmd-command-prompt.c | 39 ++++++++------------------------------- cmd-confirm-before.c | 29 ++++++++++++++++++----------- status.c | 22 ++++++++++++---------- tmux.1 | 11 +++++++++++ 4 files changed, 49 insertions(+), 52 deletions(-) diff --git a/cmd-command-prompt.c b/cmd-command-prompt.c index f0f1d12d..cd4d07ed 100644 --- a/cmd-command-prompt.c +++ b/cmd-command-prompt.c @@ -90,8 +90,7 @@ cmd_command_prompt_exec(struct cmd *self, struct cmd_ctx *ctx) const char *inputs, *prompts; struct cmd_command_prompt_cdata *cdata; struct client *c; - char *input = NULL; - char *prompt, *prompt_replaced, *ptr; + char *prompt, *ptr, *input = NULL; size_t n; if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL) @@ -127,28 +126,18 @@ cmd_command_prompt_exec(struct cmd *self, struct cmd_ctx *ctx) ptr = strsep(&cdata->next_prompt, ","); if (prompts == NULL) prompt = xstrdup(ptr); - else { - prompt_replaced = status_replace(c, NULL, NULL, NULL, ptr, - time(NULL), 0); - xasprintf(&prompt, "%s ", prompt_replaced); - xfree(prompt_replaced); - } + else + xasprintf(&prompt, "%s ", ptr); /* Get initial prompt input. */ if ((inputs = args_get(args, 'I')) != NULL) { cdata->inputs = xstrdup(inputs); cdata->next_input = cdata->inputs; - ptr = strsep(&cdata->next_input, ","); - - input = status_replace(c, NULL, NULL, NULL, ptr, time(NULL), - 0); + input = strsep(&cdata->next_input, ","); } status_prompt_set(c, prompt, input, cmd_command_prompt_callback, cmd_command_prompt_free, cdata, 0); - - if (input != NULL) - xfree(input); xfree(prompt); return (0); @@ -161,8 +150,8 @@ cmd_command_prompt_callback(void *data, const char *s) struct client *c = cdata->c; struct cmd_list *cmdlist; struct cmd_ctx ctx; - char *cause, *new_template, *prompt; - char *prompt_replaced, *ptr, *input = NULL; + char *cause, *new_template, *prompt, *ptr; + char *input = NULL; if (s == NULL) return (0); @@ -176,23 +165,11 @@ cmd_command_prompt_callback(void *data, const char *s) * and update the prompt data. */ if ((ptr = strsep(&cdata->next_prompt, ",")) != NULL) { - prompt_replaced = status_replace(c, NULL, NULL, NULL, ptr, - time(NULL), 0); - xasprintf(&prompt, "%s ", prompt_replaced); - - /* Find next input and expand special sequences. */ - if ((ptr = strsep(&cdata->next_input, ",")) != NULL) { - input = status_replace(c, NULL, NULL, NULL, ptr, - time(NULL), 0); - } - + xasprintf(&prompt, "%s ", ptr); + input = strsep(&cdata->next_input, ","); status_prompt_update(c, prompt, input); - if (input != NULL) - xfree(input); - xfree(prompt_replaced); xfree(prompt); - cdata->idx++; return (1); } diff --git a/cmd-confirm-before.c b/cmd-confirm-before.c index 958453e2..048465da 100644 --- a/cmd-confirm-before.c +++ b/cmd-confirm-before.c @@ -33,8 +33,8 @@ void cmd_confirm_before_free(void *); const struct cmd_entry cmd_confirm_before_entry = { "confirm-before", "confirm", - "t:", 1, 1, - CMD_TARGET_CLIENT_USAGE " command", + "p:t:", 1, 1, + "[-p prompt] " CMD_TARGET_CLIENT_USAGE " command", 0, cmd_confirm_before_key_binding, NULL, @@ -52,9 +52,11 @@ cmd_confirm_before_key_binding(struct cmd *self, int key) switch (key) { case '&': self->args = args_create(1, "kill-window"); + args_set(self->args, 'p', "kill-window #W? (y/n)"); break; case 'x': self->args = args_create(1, "kill-pane"); + args_set(self->args, 'p', "kill-pane #P? (y/n)"); break; default: self->args = args_create(0); @@ -68,7 +70,8 @@ cmd_confirm_before_exec(struct cmd *self, struct cmd_ctx *ctx) struct args *args = self->args; struct cmd_confirm_before_data *cdata; struct client *c; - char *buf, *cmd, *ptr; + char *cmd, *copy, *new_prompt, *ptr; + const char *prompt; if (ctx->curclient == NULL) { ctx->error(ctx, "must be run interactively"); @@ -78,19 +81,23 @@ cmd_confirm_before_exec(struct cmd *self, struct cmd_ctx *ctx) if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL) return (-1); - ptr = xstrdup(args->argv[0]); - if ((cmd = strtok(ptr, " \t")) == NULL) - cmd = ptr; - xasprintf(&buf, "Confirm '%s'? (y/n) ", cmd); - xfree(ptr); + if ((prompt = args_get(args, 'p')) != NULL) + xasprintf(&new_prompt, "%s ", prompt); + else { + ptr = copy = xstrdup(args->argv[0]); + cmd = strsep(&ptr, " \t"); + xasprintf(&new_prompt, "Confirm '%s'? (y/n) ", cmd); + xfree(copy); + } cdata = xmalloc(sizeof *cdata); cdata->cmd = xstrdup(args->argv[0]); cdata->c = c; - status_prompt_set(cdata->c, buf, NULL, cmd_confirm_before_callback, - cmd_confirm_before_free, cdata, PROMPT_SINGLE); + status_prompt_set(cdata->c, new_prompt, NULL, + cmd_confirm_before_callback, cmd_confirm_before_free, cdata, + PROMPT_SINGLE); - xfree(buf); + xfree(new_prompt); return (1); } diff --git a/status.c b/status.c index 6cf4e3dc..8810fa34 100644 --- a/status.c +++ b/status.c @@ -824,12 +824,13 @@ status_prompt_set(struct client *c, const char *msg, const char *input, status_message_clear(c); status_prompt_clear(c); - c->prompt_string = xstrdup(msg); + c->prompt_string = status_replace(c, NULL, NULL, NULL, msg, + time(NULL), 0); - if (input != NULL) - c->prompt_buffer = xstrdup(input); - else - c->prompt_buffer = xstrdup(""); + if (input == NULL) + input = ""; + c->prompt_buffer = status_replace(c, NULL, NULL, NULL, input, + time(NULL), 0); c->prompt_index = strlen(c->prompt_buffer); c->prompt_callbackfn = callbackfn; @@ -877,13 +878,14 @@ void status_prompt_update(struct client *c, const char *msg, const char *input) { xfree(c->prompt_string); - c->prompt_string = xstrdup(msg); + c->prompt_string = status_replace(c, NULL, NULL, NULL, msg, + time(NULL), 0); xfree(c->prompt_buffer); - if (input != NULL) - c->prompt_buffer = xstrdup(input); - else - c->prompt_buffer = xstrdup(""); + if (input == NULL) + input = ""; + c->prompt_buffer = status_replace(c, NULL, NULL, NULL, input, + time(NULL), 0); c->prompt_index = strlen(c->prompt_buffer); c->prompt_hindex = 0; diff --git a/tmux.1 b/tmux.1 index 69ea5819..028051e4 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2690,12 +2690,23 @@ to .Ql %9 .Pc . .It Xo Ic confirm-before +.Op Fl p Ar prompt .Op Fl t Ar target-client .Ar command .Xc .D1 (alias: Ic confirm ) Ask for confirmation before executing .Ar command . +If +.Fl p +is given, +.Ar prompt +is the prompt to display; otherwise a prompt is constructed from +.Ar command . +It may contain the special character sequences supported by the +.Ic status-left +option. +.Pp This command works only from inside .Nm . .It Xo Ic display-message From a8e9654b65c7b6de5240f9df23f0d12bca8e02ec Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 8 Jul 2011 15:18:20 +0000 Subject: [PATCH 0934/1180] flags[] should be initialized. From Thomas Adam. --- cmd-list-keys.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmd-list-keys.c b/cmd-list-keys.c index 8838060e..6e359e5b 100644 --- a/cmd-list-keys.c +++ b/cmd-list-keys.c @@ -54,6 +54,8 @@ cmd_list_keys_exec(struct cmd *self, struct cmd_ctx *ctx) return (cmd_list_keys_table(self, ctx)); width = 0; + *flags = '\0'; + SPLAY_FOREACH(bd, key_bindings, &key_bindings) { key = key_string_lookup_key(bd->key & ~KEYC_PREFIX); if (key == NULL) From d5269a2eedecc57b3ead2e502a729821aa7e2c3c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 8 Jul 2011 21:51:40 +0000 Subject: [PATCH 0935/1180] Do not continue to send data to suspended/locked clients or there will be a huge rush of it after they are resumed/unlocked. The main output path was fine but status line updates and the terminal state reset code were missed. --- screen-redraw.c | 4 ++++ server-client.c | 3 +++ 2 files changed, 7 insertions(+) diff --git a/screen-redraw.c b/screen-redraw.c index 2024e675..1abd719c 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -176,6 +176,10 @@ screen_redraw_screen(struct client *c, int status_only, int borders_only) u_int i, j, type; int status, fg, bg; + /* Suspended clients should not be updated. */ + if (c->flags & CLIENT_SUSPENDED) + return; + /* Get status line, er, status. */ if (c->message_string != NULL || c->prompt_string != NULL) status = 1; diff --git a/server-client.c b/server-client.c index f4dd1fb2..9dfcac02 100644 --- a/server-client.c +++ b/server-client.c @@ -474,6 +474,9 @@ server_client_reset_state(struct client *c) struct options *wo = &w->options; int status, mode; + if (c->flags & CLIENT_SUSPENDED) + return; + tty_region(&c->tty, 0, c->tty.sy - 1); status = options_get_number(oo, "status"); From 9dacc1700bc1d34c507e786dc316a199300616da Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 9 Jul 2011 01:36:42 +0000 Subject: [PATCH 0936/1180] Pass the right size to calloc (* not **). --- arguments.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arguments.c b/arguments.c index 97ffec13..72a8577f 100644 --- a/arguments.c +++ b/arguments.c @@ -40,7 +40,7 @@ args_create(int argc, ...) if (argc == 0) args->argv = NULL; else - args->argv = xcalloc(argc, sizeof **args->argv); + args->argv = xcalloc(argc, sizeof *args->argv); va_start(ap, argc); for (i = 0; i < argc; i++) From 7e423ea491d3bfcaebb4f8cbd7e90d363a5a3f88 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 9 Jul 2011 01:37:00 +0000 Subject: [PATCH 0937/1180] Unused variable. --- cmd-respawn-pane.c | 1 - 1 file changed, 1 deletion(-) diff --git a/cmd-respawn-pane.c b/cmd-respawn-pane.c index 5e0d16bc..7e272a80 100644 --- a/cmd-respawn-pane.c +++ b/cmd-respawn-pane.c @@ -46,7 +46,6 @@ cmd_respawn_pane_exec(struct cmd *self, struct cmd_ctx *ctx) struct winlink *wl; struct window *w; struct window_pane *wp; - u_int hlimit; struct session *s; struct environ env; const char *cmd; From 0252796a5750bc4cc3adc06c8c10eacb7136df6c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 25 Jul 2011 09:57:28 +0000 Subject: [PATCH 0938/1180] Sort options alphabetically, from Tiago Cunha. --- tmux.1 | 74 +++++++++++++++++++++++++++++----------------------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/tmux.1 b/tmux.1 index 028051e4..c6863839 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1722,6 +1722,22 @@ Available server options are: Set the number of buffers; as new buffers are added to the top of the stack, old ones are removed from the bottom if necessary to maintain this maximum length. +.It Ic escape-time Ar time +Set the time in milliseconds for which +.Nm +waits after an escape is input to determine if it is part of a function or meta +key sequences. +The default is 500 milliseconds. +.It Xo Ic exit-unattached +.Op Ic on | off +.Xc +If enabled, the server will exit when there are no attached clients. +.It Xo Ic quiet +.Op Ic on | off +.Xc +Enable or disable the display of various informational messages (see also the +.Fl q +command line flag). .It Xo Ic set-clipboard .Op Ic on | off .Xc @@ -1744,22 +1760,6 @@ disallowedWindowOps: 20,21,SetXprop Or changing this property from the .Xr xterm 1 interactive menu when required. -.It Ic escape-time Ar time -Set the time in milliseconds for which -.Nm -waits after an escape is input to determine if it is part of a function or meta -key sequences. -The default is 500 milliseconds. -.It Xo Ic exit-unattached -.Op Ic on | off -.Xc -If enabled, the server will exit when there are no attached clients. -.It Xo Ic quiet -.Op Ic on | off -.Xc -Enable or disable the display of various informational messages (see also the -.Fl q -command line flag). .El .Pp Available session options are: @@ -1951,6 +1951,10 @@ The mouse click is also passed through to the application as normal. .Xc If on, clicking the mouse on a window name in the status line will select that window. +.It Xo Ic mouse-utf8 +.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. @@ -1974,10 +1978,6 @@ flag to Repeat is enabled for the default keys bound to the .Ic resize-pane command. -.It Xo Ic mouse-utf8 -.Op Ic on | off -.Xc -If enabled, request mouse input as UTF-8 on UTF-8 terminals. .It Xo Ic set-remain-on-exit .Op Ic on | off .Xc @@ -2430,23 +2430,6 @@ Instructs .Nm to expect UTF-8 sequences to appear in this window. .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-fg Ar colour -Set status line foreground colour for a single window. -.Pp -.It Ic window-status-format Ar string -Set the format in which the window is displayed in the status line window list. -See the -.Ar status-left -option for details of special character sequences available. -The default is -.Ql #I:#W#F . -.Pp .It Ic window-status-alert-attr Ar attributes Set status line attributes for windows which have an alert (bell, activity or content). @@ -2457,6 +2440,12 @@ Set status line background colour for windows with an alert. .It Ic window-status-alert-fg Ar colour Set status line foreground colour for windows with an 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 @@ -2471,6 +2460,17 @@ Like .Ar window-status-format , but is the format used when the window is the current window. .Pp +.It Ic window-status-fg Ar colour +Set status line foreground colour for a single window. +.Pp +.It Ic window-status-format Ar string +Set the format in which the window is displayed in the status line window list. +See the +.Ar status-left +option for details of special character sequences available. +The default is +.Ql #I:#W#F . +.Pp .It Ic word-separators Ar string Sets the window's conception of what characters are considered word separators, for the purposes of the next and previous word commands in From be179f6d7eec39c63d6b8d7aa90a2acefe4e7e04 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 30 Jul 2011 17:52:32 +0000 Subject: [PATCH 0939/1180] Do not require a client here, or pipe-pane will not work from the command line. --- cmd-pipe-pane.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cmd-pipe-pane.c b/cmd-pipe-pane.c index 1f27e6d9..00f0378a 100644 --- a/cmd-pipe-pane.c +++ b/cmd-pipe-pane.c @@ -55,11 +55,9 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx) char *command; int old_fd, pipe_fd[2], null_fd; - if ((c = cmd_find_client(ctx, NULL)) == NULL) - return (-1); - if (cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp) == NULL) return (-1); + c = cmd_find_client(ctx, NULL); /* Destroy the old pipe. */ old_fd = wp->pipe_fd; From cc5bcbfb593db8a1a4dda0eba51f059b85a6abec Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 30 Jul 2011 18:01:26 +0000 Subject: [PATCH 0940/1180] Extend the mode-mouse option to add a third choice which means the mouse does not enter copy mode. Patch from SF bug 3374493. In future the mode-mouse option is likely to die and be broken into several smaller options. --- input-keys.c | 4 +++- options-table.c | 6 +++++- tmux.1 | 7 ++++++- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/input-keys.c b/input-keys.c index dfcc8273..d875f523 100644 --- a/input-keys.c +++ b/input-keys.c @@ -204,6 +204,7 @@ input_mouse(struct window_pane *wp, struct mouse_event *m) { char buf[10]; size_t len; + int value; if (wp->screen->mode & ALL_MOUSE_MODES) { if (wp->screen->mode & MODE_MOUSE_UTF8) { @@ -221,7 +222,8 @@ input_mouse(struct window_pane *wp, struct mouse_event *m) } bufferevent_write(wp->event, buf, len); } else if ((m->b & MOUSE_BUTTON) != MOUSE_2) { - if (options_get_number(&wp->window->options, "mode-mouse") && + value = options_get_number(&wp->window->options, "mode-mouse"); + if (value == 1 && window_pane_set_mode(wp, &window_copy_mode) == 0) { window_copy_init_from_pane(wp); if (wp->mode->mouse != NULL) diff --git a/options-table.c b/options-table.c index 4a385051..ed06dd54 100644 --- a/options-table.c +++ b/options-table.c @@ -36,6 +36,9 @@ const char *options_table_mode_keys_list[] = { "emacs", "vi", NULL }; +const char *options_table_mode_mouse_list[] = { + "off", "on", "copy-mode", NULL +}; const char *options_table_clock_mode_style_list[] = { "12", "24", NULL }; @@ -484,7 +487,8 @@ const struct options_table_entry window_options_table[] = { }, { .name = "mode-mouse", - .type = OPTIONS_TABLE_FLAG, + .type = OPTIONS_TABLE_CHOICE, + .choices = options_table_mode_mouse_list, .default_num = 0 }, diff --git a/tmux.1 b/tmux.1 index c6863839..697b1e94 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2358,12 +2358,17 @@ contains .Ql vi . .Pp .It Xo Ic mode-mouse -.Op Ic on | off +.Op Ic on | off | copy-mode .Xc Mouse state in modes. If on, the mouse may be used to enter copy mode and copy a selection by dragging, to enter copy mode and scroll with the mouse wheel, or to select an option in choice mode. +If set to +.Em +copy-mode , +the mouse behaves as set to on, but cannot be used to enter copy +mode. .Pp .It Xo Ic monitor-activity .Op Ic on | off From cf90f2a29c4b09585f69d36571555a950e3c1f20 Mon Sep 17 00:00:00 2001 From: Jason McIntyre Date: Sat, 30 Jul 2011 18:27:57 +0000 Subject: [PATCH 0941/1180] fix error in previous; --- tmux.1 | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tmux.1 b/tmux.1 index 697b1e94..2f1bd90e 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2365,8 +2365,7 @@ If on, the mouse may be used to enter copy mode and copy a selection by dragging, to enter copy mode and scroll with the mouse wheel, or to select an option in choice mode. If set to -.Em -copy-mode , +.Em copy-mode , the mouse behaves as set to on, but cannot be used to enter copy mode. .Pp From 6b734d10746ac86a13b05ad48b79e92ca8ccc96b Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 16 Aug 2011 09:36:23 +0000 Subject: [PATCH 0942/1180] Correctly skip existing numbers when generating the name for a new session. --- session.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/session.c b/session.c index e9bffed2..2545d868 100644 --- a/session.c +++ b/session.c @@ -119,11 +119,18 @@ session_create(const char *name, const char *cmd, const char *cwd, s->sx = sx; s->sy = sy; - s->idx = next_session++; - if (name != NULL) + if (name != NULL) { s->name = xstrdup(name); - else - xasprintf(&s->name, "%u", s->idx); + s->idx = next_session++; + } else { + s->name = NULL; + do { + s->idx = next_session++; + if (s->name != NULL) + xfree (s->name); + xasprintf(&s->name, "%u", s->idx); + } while (RB_FIND(sessions, &sessions, s) != NULL); + } RB_INSERT(sessions, &sessions, s); if (cmd != NULL) { From 2fc84c7c34f599f913109c94f85eb682138a64ec Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 16 Aug 2011 09:37:48 +0000 Subject: [PATCH 0943/1180] Use key_bindings_remove for unbind-key -a to allow it to work from key bindings. From "miaout17" SF bug 3392063. --- cmd-unbind-key.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cmd-unbind-key.c b/cmd-unbind-key.c index 8eb829d4..7e8c183c 100644 --- a/cmd-unbind-key.c +++ b/cmd-unbind-key.c @@ -59,9 +59,7 @@ cmd_unbind_key_exec(struct cmd *self, unused struct cmd_ctx *ctx) if (args_has(args, 'a')) { while (!SPLAY_EMPTY(&key_bindings)) { bd = SPLAY_ROOT(&key_bindings); - SPLAY_REMOVE(key_bindings, &key_bindings, bd); - cmd_list_free(bd->cmdlist); - xfree(bd); + key_bindings_remove(bd->key); } return (0); } From f95f792ddf208e24e1f979b1bf5d373a8052af68 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 16 Aug 2011 09:47:18 +0000 Subject: [PATCH 0944/1180] Add up/down/left/right keys in vi edit mode. From "livibetter" SF bug 3385651. --- mode-key.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/mode-key.c b/mode-key.c index 7c8cb37f..960971ff 100644 --- a/mode-key.c +++ b/mode-key.c @@ -126,12 +126,16 @@ const struct mode_key_cmdstr mode_key_cmdstr_copy[] = { const struct mode_key_entry mode_key_vi_edit[] = { { '\003' /* C-c */, 0, MODEKEYEDIT_CANCEL }, { '\010' /* C-h */, 0, MODEKEYEDIT_BACKSPACE }, - { '\025' /* C-u */, 0, MODEKEYEDIT_DELETELINE }, { '\011' /* Tab */, 0, MODEKEYEDIT_COMPLETE }, + { '\025' /* C-u */, 0, MODEKEYEDIT_DELETELINE }, { '\033' /* Escape */, 0, MODEKEYEDIT_SWITCHMODE }, { '\r', 0, MODEKEYEDIT_ENTER }, { KEYC_BSPACE, 0, MODEKEYEDIT_BACKSPACE }, { KEYC_DC, 0, MODEKEYEDIT_DELETE }, + { KEYC_DOWN, 0, MODEKEYEDIT_HISTORYDOWN }, + { KEYC_LEFT, 0, MODEKEYEDIT_CURSORLEFT }, + { KEYC_RIGHT, 0, MODEKEYEDIT_CURSORRIGHT }, + { KEYC_UP, 0, MODEKEYEDIT_HISTORYUP }, { '$', 1, MODEKEYEDIT_ENDOFLINE }, { '0', 1, MODEKEYEDIT_STARTOFLINE }, From 88e9079870a770c39dd8f96302602a792db9a90a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 16 Aug 2011 10:00:52 +0000 Subject: [PATCH 0945/1180] Add a -r flag to switch-client to toggle the client read-only flag. From Johan Commelin. --- cmd-choose-client.c | 6 ++++-- cmd-list-clients.c | 7 ++++--- cmd-switch-client.c | 16 +++++++++++++--- tmux.1 | 10 ++++++++-- 4 files changed, 29 insertions(+), 10 deletions(-) diff --git a/cmd-choose-client.c b/cmd-choose-client.c index ac766ab5..6ad1b495 100644 --- a/cmd-choose-client.c +++ b/cmd-choose-client.c @@ -76,9 +76,11 @@ cmd_choose_client_exec(struct cmd *self, struct cmd_ctx *ctx) idx++; window_choose_add(wl->window->active, i, - "%s: %s [%ux%u %s]%s", c->tty.path, + "%s: %s [%ux%u %s]%s%s", c->tty.path, c->session->name, c->tty.sx, c->tty.sy, - c->tty.termname, c->tty.flags & TTY_UTF8 ? " (utf8)" : ""); + c->tty.termname, + c->tty.flags & TTY_UTF8 ? " (utf8)" : "", + c->flags & CLIENT_READONLY ? " (ro)" : ""); } cdata = xmalloc(sizeof *cdata); diff --git a/cmd-list-clients.c b/cmd-list-clients.c index 2a4728b8..c24ec660 100644 --- a/cmd-list-clients.c +++ b/cmd-list-clients.c @@ -33,7 +33,7 @@ const struct cmd_entry cmd_list_clients_entry = { "list-clients", "lsc", "t:", 0, 0, CMD_TARGET_SESSION_USAGE, - 0, + CMD_READONLY, NULL, NULL, cmd_list_clients_exec @@ -68,9 +68,10 @@ cmd_list_clients_exec(struct cmd *self, struct cmd_ctx *ctx) if (s != NULL && s != c->session) continue; - ctx->print(ctx, "%s: %s [%ux%u %s]%s", c->tty.path, + ctx->print(ctx, "%s: %s [%ux%u %s]%s%s", c->tty.path, c->session->name, c->tty.sx, c->tty.sy, - c->tty.termname, s_utf8); + c->tty.termname, s_utf8, + c->flags & CLIENT_READONLY ? " (ro)" : ""); } return (0); diff --git a/cmd-switch-client.c b/cmd-switch-client.c index 25a57965..ab940dc4 100644 --- a/cmd-switch-client.c +++ b/cmd-switch-client.c @@ -32,9 +32,9 @@ int cmd_switch_client_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_switch_client_entry = { "switch-client", "switchc", - "lc:npt:", 0, 0, - "[-lnp] [-c target-client] [-t target-session]", - 0, + "lc:npt:r", 0, 0, + "[-lnpr] [-c target-client] [-t target-session]", + CMD_READONLY, cmd_switch_client_key_binding, NULL, cmd_switch_client_exec @@ -67,6 +67,16 @@ cmd_switch_client_exec(struct cmd *self, struct cmd_ctx *ctx) if ((c = cmd_find_client(ctx, args_get(args, 'c'))) == NULL) return (-1); + if (args_has(args, 'r')) { + if (c->flags & CLIENT_READONLY) { + c->flags &= ~CLIENT_READONLY; + ctx->info(ctx, "made client writable"); + } else { + c->flags |= CLIENT_READONLY; + ctx->info(ctx, "made client read-only"); + } + } + s = NULL; if (args_has(args, 'n')) { if ((s = session_next_session(c->session)) == NULL) { diff --git a/tmux.1 b/tmux.1 index 2f1bd90e..8b7639ae 100644 --- a/tmux.1 +++ b/tmux.1 @@ -558,7 +558,9 @@ is specified, any other clients attached to the session are detached. .Fl r signifies the client is read-only (only keys bound to the .Ic detach-client -command have any effect) +or +.Ic switch-client +commands have any effect) .Pp If no server is started, .Ic attach-session @@ -714,7 +716,7 @@ Suspend a client by sending .Dv SIGTSTP (tty stop). .It Xo Ic switch-client -.Op Fl lnp +.Op Fl lnpr .Op Fl c Ar target-client .Op Fl t Ar target-session .Xc @@ -730,6 +732,10 @@ or .Fl p is used, the client is moved to the last, next or previous session respectively. +.Fl r +toggles whether a client is read-only (see the +.Ic attach-session +command). .El .Sh WINDOWS AND PANES A From 3657aa675e47eafcfa1e1186c3f4c51c4e5b6a7e Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 20 Aug 2011 20:37:30 +0000 Subject: [PATCH 0946/1180] Fix a couple of memory leaks, from marcel partap. --- server-client.c | 2 ++ status.c | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/server-client.c b/server-client.c index 9dfcac02..cf2a4c54 100644 --- a/server-client.c +++ b/server-client.c @@ -171,6 +171,8 @@ server_client_lost(struct client *c) if (c->cwd != NULL) xfree(c->cwd); + environ_free(&c->environ); + close(c->ibuf.fd); imsg_clear(&c->ibuf); event_del(&c->event); diff --git a/status.c b/status.c index 8810fa34..50e7302e 100644 --- a/status.c +++ b/status.c @@ -551,8 +551,10 @@ status_find_job(struct client *c, char **iptr) /* First try in the new tree. */ so_find.cmd = cmd; so = RB_FIND(status_out_tree, &c->status_new, &so_find); - if (so != NULL && so->out != NULL) + if (so != NULL && so->out != NULL) { + xfree(cmd); return (so->out); + } /* If not found at all, start the job and add to the tree. */ if (so == NULL) { From 47d41d0203894c6792caf7f71108e8c5a9086776 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 22 Aug 2011 10:14:15 +0000 Subject: [PATCH 0947/1180] There is no need to use sqrt()/INFINITY here which simplifies the code and makes it more portable, from Havard Eidnes. --- colour.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/colour.c b/colour.c index 3530686a..ae69e88f 100644 --- a/colour.c +++ b/colour.c @@ -19,7 +19,6 @@ #include #include -#include #include #include @@ -41,7 +40,7 @@ struct colour_rgb { struct colour_rgb *colour_rgb_256; void colour_rgb_generate256(void); -double colour_rgb_distance(struct colour_rgb *, struct colour_rgb *); +u_int colour_rgb_distance(struct colour_rgb *, struct colour_rgb *); int colour_rgb_find(struct colour_rgb *); /* Generate 256 colour RGB table. */ @@ -91,7 +90,7 @@ colour_rgb_generate256(void) } /* Get colour RGB distance. */ -double +u_int colour_rgb_distance(struct colour_rgb *rgb1, struct colour_rgb *rgb2) { int r, g, b; @@ -99,21 +98,20 @@ colour_rgb_distance(struct colour_rgb *rgb1, struct colour_rgb *rgb2) r = rgb1->r - rgb2->r; g = rgb1->g - rgb2->g; b = rgb1->b - rgb2->b; - return (sqrt(r * r + g * g + b * b)); + return (r * r + g * g + b * b); } /* Work out the nearest colour from the 256 colour set. */ int colour_rgb_find(struct colour_rgb *rgb) { - double distance, lowest; - u_int colour, i; + u_int distance, lowest, colour, i; if (colour_rgb_256 == NULL) colour_rgb_generate256(); colour = 16; - lowest = INFINITY; + lowest = UINT_MAX; for (i = 0; i < 240; i++) { distance = colour_rgb_distance(&colour_rgb_256[i], rgb); if (distance < lowest) { From 029c34ce6bc76168d06726bc81bda4514d245054 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 24 Aug 2011 09:58:44 +0000 Subject: [PATCH 0948/1180] Add a tty_bell wrapper function, from Dylan Alex Simon. --- server-window.c | 6 +++--- tmux.h | 1 + tty.c | 6 ++++++ 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/server-window.c b/server-window.c index b444982d..a44e32fa 100644 --- a/server-window.c +++ b/server-window.c @@ -86,7 +86,7 @@ server_window_check_bell(struct session *s, struct winlink *wl) if (c == NULL || c->session != s) continue; if (!visual) { - tty_putcode(&c->tty, TTYC_BEL); + tty_bell(&c->tty); continue; } if (c->session->curw->window == w) { @@ -108,7 +108,7 @@ server_window_check_bell(struct session *s, struct winlink *wl) if (c->session->curw->window != w) continue; if (!visual) { - tty_putcode(&c->tty, TTYC_BEL); + tty_bell(&c->tty); continue; } status_message_set(c, "Bell in current window"); @@ -254,6 +254,6 @@ ring_bell(struct session *s) for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); if (c != NULL && c->session == s) - tty_putcode(&c->tty, TTYC_BEL); + tty_bell(&c->tty); } } diff --git a/tmux.h b/tmux.h index 5c2a5a81..7f0390d5 100644 --- a/tmux.h +++ b/tmux.h @@ -1458,6 +1458,7 @@ void tty_cmd_utf8character(struct tty *, const struct tty_ctx *); void tty_cmd_reverseindex(struct tty *, const struct tty_ctx *); void tty_cmd_setselection(struct tty *, const struct tty_ctx *); void tty_cmd_rawstring(struct tty *, const struct tty_ctx *); +void tty_bell(struct tty *); /* tty-term.c */ extern struct tty_terms tty_terms; diff --git a/tty.c b/tty.c index efd779a6..dce4887b 100644 --- a/tty.c +++ b/tty.c @@ -1546,3 +1546,9 @@ tty_try_88(struct tty *tty, u_char colour, const char *type) tty_puts(tty, s); return (0); } + +void +tty_bell(struct tty *tty) +{ + tty_putcode(tty, TTYC_BEL); +} From f01b7191a328193646885f2bb5f7ce50625385b1 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 24 Aug 2011 10:29:57 +0000 Subject: [PATCH 0949/1180] Add pane-base-index option, from Ben Barbour. --- options-table.c | 7 +++++++ tmux.1 | 5 +++++ window.c | 4 ++-- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/options-table.c b/options-table.c index ed06dd54..352cdc18 100644 --- a/options-table.c +++ b/options-table.c @@ -523,6 +523,13 @@ const struct options_table_entry window_options_table[] = { .default_num = 0 }, + { .name = "pane-base-index", + .type = OPTIONS_TABLE_NUMBER, + .minimum = 0, + .maximum = USHRT_MAX, + .default_num = 0 + }, + { .name = "remain-on-exit", .type = OPTIONS_TABLE_FLAG, .default_num = 0 diff --git a/tmux.1 b/tmux.1 index 8b7639ae..b86612c5 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2418,6 +2418,11 @@ but set the width of other panes in the .Ic main-vertical layout. .Pp +.It Ic pane-base-index Ar index +Like +.Ic base-index , +but set the starting index for pane numbers. +.Pp .It Xo Ic remain-on-exit .Op Ic on | off .Xc diff --git a/window.c b/window.c index ab3177e6..0736daeb 100644 --- a/window.c +++ b/window.c @@ -454,7 +454,7 @@ window_pane_at_index(struct window *w, u_int idx) struct window_pane *wp; u_int n; - n = 0; + n = options_get_number(&w->options, "pane-base-index"); TAILQ_FOREACH(wp, &w->panes, entry) { if (n == idx) return (wp); @@ -492,7 +492,7 @@ window_pane_index(struct window *w, struct window_pane *wp) struct window_pane *wq; u_int n; - n = 0; + n = options_get_number(&w->options, "pane-base-index"); TAILQ_FOREACH(wq, &w->panes, entry) { if (wp == wq) break; From 0588168a64d9da2eb618b1e87e9774e33828e8c1 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 24 Aug 2011 10:46:01 +0000 Subject: [PATCH 0950/1180] Support \ for line continuation in the configuration file, from Julius Plenz. --- cfg.c | 35 +++++++++++++++++++++++++++-------- tmux.1 | 6 +++++- 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/cfg.c b/cfg.c index 75e0414f..d49bfa61 100644 --- a/cfg.c +++ b/cfg.c @@ -92,22 +92,37 @@ load_cfg(const char *path, struct cmd_ctx *ctxin, struct causelist *causes) retval = 0; while ((buf = fgetln(f, &len))) { if (buf[len - 1] == '\n') - buf[len - 1] = '\0'; + len--; + + if (line != NULL) + line = xrealloc(line, 1, strlen(line) + len + 1); else { - line = xrealloc(line, 1, len + 1); - memcpy(line, buf, len); - line[len] = '\0'; - buf = line; + line = xmalloc(len + 1); + *line = '\0'; } + + /* Append buffer to line. strncat will terminate. */ + strncat(line, buf, len); n++; + /* Continuation: get next line? */ + len = strlen(line); + if (len > 0 && line[len - 1] == '\\') { + line[len - 1] = '\0'; + continue; + } + buf = line; + line = NULL; + if (cmd_string_parse(buf, &cmdlist, &cause) != 0) { + xfree(buf); if (cause == NULL) continue; cfg_add_cause(causes, "%s: %u: %s", path, n, cause); xfree(cause); continue; - } + } else + xfree(buf); if (cmdlist == NULL) continue; cfg_cause = NULL; @@ -131,12 +146,16 @@ load_cfg(const char *path, struct cmd_ctx *ctxin, struct causelist *causes) retval = 1; cmd_list_free(cmdlist); if (cfg_cause != NULL) { - cfg_add_cause(causes, "%s: %d: %s", path, n, cfg_cause); + cfg_add_cause( + causes, "%s: %d: %s", path, n, cfg_cause); xfree(cfg_cause); } } - if (line != NULL) + if (line != NULL) { + cfg_add_cause(causes, + "%s: %d: line continuation at end of file", path, n); xfree(line); + } fclose(f); return (retval); diff --git a/tmux.1 b/tmux.1 index b86612c5..4543bd39 100644 --- a/tmux.1 +++ b/tmux.1 @@ -491,7 +491,8 @@ $ tmux bind-key F1 set-window-option force-width 81 Multiple commands may be specified together as part of a .Em command sequence . Each command should be separated by spaces and a semicolon; -commands are executed sequentially from left to right. +commands are executed sequentially from left to right and +lines ending with a backslash continue on to the next line. A literal semicolon may be included by escaping it with a backslash (for example, when specifying a command sequence to .Ic bind-key ) . @@ -507,6 +508,9 @@ rename-session -tfirst newname set-window-option -t:0 monitor-activity on new-window ; split-window -d + +bind-key R source-file ~/.tmux.conf \e; \e + display-message "source-file done" .Ed .Pp Or from From 4697b35d4f84efb5ecd618d62cfa915535fd8020 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 25 Aug 2011 10:52:23 +0000 Subject: [PATCH 0951/1180] -lm is no longer needed, from Tiago Cunha. --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 4aea4841..817d8009 100644 --- a/Makefile +++ b/Makefile @@ -44,7 +44,7 @@ CDIAGFLAGS+= -Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations CDIAGFLAGS+= -Wwrite-strings -Wshadow -Wpointer-arith -Wsign-compare CDIAGFLAGS+= -Wundef -Wbad-function-cast -Winline -Wcast-align -LDADD= -lutil -lcurses -levent -lm -DPADD= ${LIBUTIL} ${LIBCURSES} ${LIBEVENT} ${LIBM} +LDADD= -lutil -lcurses -levent +DPADD= ${LIBUTIL} ${LIBCURSES} ${LIBEVENT} .include From 4a5dff3f114c9d548a762fb4c5b3003d0a6f406f Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 26 Aug 2011 10:53:16 +0000 Subject: [PATCH 0952/1180] Add initial framework for more powerful formatting of command output and use it for list-{panes,windows,sessions}. This allows more descriptive replacements (such as #{session_name}) and conditionals. Later this will be used for status_replace and list-keys and other places. --- Makefile | 2 +- cmd-list-panes.c | 106 +++++++------- cmd-list-sessions.c | 47 +++--- cmd-list-windows.c | 73 +++++++--- format.c | 346 ++++++++++++++++++++++++++++++++++++++++++++ tmux.1 | 77 ++++++++++ tmux.h | 23 +++ 7 files changed, 578 insertions(+), 96 deletions(-) create mode 100644 format.c diff --git a/Makefile b/Makefile index 817d8009..dd2e4e98 100644 --- a/Makefile +++ b/Makefile @@ -30,7 +30,7 @@ SRCS= arguments.c attributes.c cfg.c client.c clock.c \ cmd-display-message.c cmd-display-panes.c cmd-if-shell.c \ cmd-pipe-pane.c cmd-capture-pane.c cmd.c \ colour.c environ.c grid-view.c grid-utf8.c grid.c input-keys.c \ - input.c key-bindings.c key-string.c \ + input.c key-bindings.c key-string.c format.c \ layout-custom.c layout-set.c layout.c log.c job.c \ mode-key.c names.c options.c options-table.c paste.c procname.c \ resize.c screen-redraw.c screen-write.c screen.c session.c status.c \ diff --git a/cmd-list-panes.c b/cmd-list-panes.c index ce4b4906..d0942ad8 100644 --- a/cmd-list-panes.c +++ b/cmd-list-panes.c @@ -28,15 +28,16 @@ int cmd_list_panes_exec(struct cmd *, struct cmd_ctx *); -void cmd_list_panes_server(struct cmd_ctx *); -void cmd_list_panes_session(struct session *, struct cmd_ctx *, int); -void cmd_list_panes_window( +void cmd_list_panes_server(struct cmd *, struct cmd_ctx *); +void cmd_list_panes_session( + struct cmd *, struct session *, struct cmd_ctx *, int); +void cmd_list_panes_window(struct cmd *, struct session *, struct winlink *, struct cmd_ctx *, int); const struct cmd_entry cmd_list_panes_entry = { "list-panes", "lsp", - "ast:", 0, 0, - "[-as] [-t target]", + "asF:t:", 0, 0, + "[-as] [-F format] [-t target]", 0, NULL, NULL, @@ -51,87 +52,92 @@ cmd_list_panes_exec(struct cmd *self, struct cmd_ctx *ctx) struct winlink *wl; if (args_has(args, 'a')) - cmd_list_panes_server(ctx); + cmd_list_panes_server(self, ctx); else if (args_has(args, 's')) { s = cmd_find_session(ctx, args_get(args, 't'), 0); if (s == NULL) return (-1); - cmd_list_panes_session(s, ctx, 1); + cmd_list_panes_session(self, s, ctx, 1); } else { wl = cmd_find_window(ctx, args_get(args, 't'), &s); if (wl == NULL) return (-1); - cmd_list_panes_window(s, wl, ctx, 0); + cmd_list_panes_window(self, s, wl, ctx, 0); } return (0); } void -cmd_list_panes_server(struct cmd_ctx *ctx) +cmd_list_panes_server(struct cmd *self, struct cmd_ctx *ctx) { struct session *s; RB_FOREACH(s, sessions, &sessions) - cmd_list_panes_session(s, ctx, 2); + cmd_list_panes_session(self, s, ctx, 2); } void -cmd_list_panes_session(struct session *s, struct cmd_ctx *ctx, int type) +cmd_list_panes_session( + struct cmd *self, struct session *s, struct cmd_ctx *ctx, int type) { struct winlink *wl; RB_FOREACH(wl, winlinks, &s->windows) - cmd_list_panes_window(s, wl, ctx, type); + cmd_list_panes_window(self, s, wl, ctx, type); } void -cmd_list_panes_window( +cmd_list_panes_window(struct cmd *self, struct session *s, struct winlink *wl, struct cmd_ctx *ctx, int type) { + struct args *args = self->args; struct window_pane *wp; - struct grid *gd; - struct grid_line *gl; - u_int i, n; - unsigned long long size; + u_int n; + struct format_tree *ft; + const char *template; + char *line; + + template = args_get(args, 'F'); + if (template == NULL) { + switch (type) { + case 0: + template = "#{line}: " + "[#{pane_width}x#{pane_height}] [history " + "#{history_size}/#{history_limit}, " + "#{history_bytes} bytes] #{pane_id}" + "#{?pane_active, (active),}#{?pane_dead, (dead),}"; + break; + case 1: + template = "#{window_index}.#{line}: " + "[#{pane_width}x#{pane_height}] [history " + "#{history_size}/#{history_limit}, " + "#{history_bytes} bytes] #{pane_id}" + "#{?pane_active, (active),}#{?pane_dead, (dead),}"; + break; + case 2: + template = "#{session_name}:#{window_index}.#{line}: " + "[#{pane_width}x#{pane_height}] [history " + "#{history_size}/#{history_limit}, " + "#{history_bytes} bytes] #{pane_id}" + "#{?pane_active, (active),}#{?pane_dead, (dead),}"; + break; + } + } n = 0; TAILQ_FOREACH(wp, &wl->window->panes, entry) { - gd = wp->base.grid; + ft = format_create(); + format_add(ft, "line", "%u", n); + format_session(ft, s); + format_winlink(ft, s, wl); + format_window_pane(ft, wp); - size = 0; - for (i = 0; i < gd->hsize; i++) { - gl = &gd->linedata[i]; - size += gl->cellsize * sizeof *gl->celldata; - size += gl->utf8size * sizeof *gl->utf8data; - } - size += gd->hsize * sizeof *gd->linedata; + line = format_expand(ft, template); + ctx->print(ctx, "%s", line); + xfree(line); - switch (type) { - case 0: - ctx->print(ctx, - "%u: [%ux%u] [history %u/%u, %llu bytes] %%%u%s%s", - n, wp->sx, wp->sy, gd->hsize, gd->hlimit, size, - wp->id, wp == wp->window->active ? " (active)" : "", - wp->fd == -1 ? " (dead)" : ""); - break; - case 1: - ctx->print(ctx, - "%d.%u: [%ux%u] [history %u/%u, %llu bytes] " - "%%%u%s%s", wl->idx, - n, wp->sx, wp->sy, gd->hsize, gd->hlimit, size, - wp->id, wp == wp->window->active ? " (active)" : "", - wp->fd == -1 ? " (dead)" : ""); - break; - case 2: - ctx->print(ctx, - "%s:%d.%u: [%ux%u] [history %u/%u, %llu bytes] " - "%%%u%s%s", s->name, wl->idx, - n, wp->sx, wp->sy, gd->hsize, gd->hlimit, size, - wp->id, wp == wp->window->active ? " (active)" : "", - wp->fd == -1 ? " (dead)" : ""); - break; - } + format_free(ft); n++; } } diff --git a/cmd-list-sessions.c b/cmd-list-sessions.c index 6c0f2dae..10e6b16d 100644 --- a/cmd-list-sessions.c +++ b/cmd-list-sessions.c @@ -31,40 +31,45 @@ int cmd_list_sessions_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_list_sessions_entry = { "list-sessions", "ls", - "", 0, 0, - "", + "F:", 0, 0, + "[-F format]", 0, NULL, NULL, cmd_list_sessions_exec }; -/* ARGSUSED */ int -cmd_list_sessions_exec(unused struct cmd *self, struct cmd_ctx *ctx) +cmd_list_sessions_exec(struct cmd *self, struct cmd_ctx *ctx) { + struct args *args = self->args; struct session *s; - struct session_group *sg; - char *tim, tmp[64]; - u_int idx; - time_t t; + u_int n; + struct format_tree *ft; + const char *template; + char *line; + template = args_get(args, 'F'); + if (template == NULL) { + template = "#{session_name}: #{session_windows} windows " + "(created #{session_created_string}) [#{session_width}x" + "#{session_height}]#{?session_grouped, (group ,}" + "#{session_group}#{?session_grouped,),}" + "#{?session_attached, (attached),}"; + } + + n = 0; RB_FOREACH(s, sessions, &sessions) { - sg = session_group_find(s); - if (sg == NULL) - *tmp = '\0'; - else { - idx = session_group_index(sg); - xsnprintf(tmp, sizeof tmp, " (group %u)", idx); - } + ft = format_create(); + format_add(ft, "line", "%u", n); + format_session(ft, s); - t = s->creation_time.tv_sec; - tim = ctime(&t); - *strchr(tim, '\n') = '\0'; + line = format_expand(ft, template); + ctx->print(ctx, "%s", line); + xfree(line); - ctx->print(ctx, "%s: %u windows (created %s) [%ux%u]%s%s", - s->name, winlink_count(&s->windows), tim, s->sx, s->sy, - tmp, s->flags & SESSION_UNATTACHED ? "" : " (attached)"); + format_free(ft); + n++; } return (0); diff --git a/cmd-list-windows.c b/cmd-list-windows.c index 239f69f7..30adeb6e 100644 --- a/cmd-list-windows.c +++ b/cmd-list-windows.c @@ -28,13 +28,14 @@ int cmd_list_windows_exec(struct cmd *, struct cmd_ctx *); -void cmd_list_windows_server(struct cmd_ctx *); -void cmd_list_windows_session(struct session *, struct cmd_ctx *, int); +void cmd_list_windows_server(struct cmd *, struct cmd_ctx *); +void cmd_list_windows_session( + struct cmd *, struct session *, struct cmd_ctx *, int); const struct cmd_entry cmd_list_windows_entry = { "list-windows", "lsw", - "at:", 0, 0, - "[-a] " CMD_TARGET_SESSION_USAGE, + "aF:t:", 0, 0, + "[-a] [-F format] " CMD_TARGET_SESSION_USAGE, 0, NULL, NULL, @@ -48,45 +49,69 @@ cmd_list_windows_exec(struct cmd *self, struct cmd_ctx *ctx) struct session *s; if (args_has(args, 'a')) - cmd_list_windows_server(ctx); + cmd_list_windows_server(self, ctx); else { s = cmd_find_session(ctx, args_get(args, 't'), 0); if (s == NULL) return (-1); - cmd_list_windows_session(s, ctx, 0); + cmd_list_windows_session(self, s, ctx, 0); } return (0); } void -cmd_list_windows_server(struct cmd_ctx *ctx) +cmd_list_windows_server(struct cmd *self, struct cmd_ctx *ctx) { struct session *s; RB_FOREACH(s, sessions, &sessions) - cmd_list_windows_session(s, ctx, 1); + cmd_list_windows_session(self, s, ctx, 1); } void -cmd_list_windows_session(struct session *s, struct cmd_ctx *ctx, int type) +cmd_list_windows_session( + struct cmd *self, struct session *s, struct cmd_ctx *ctx, int type) { - struct winlink *wl; - char *layout; + struct args *args = self->args; + struct winlink *wl; + u_int n; + struct format_tree *ft; + const char *template; + char *line; - RB_FOREACH(wl, winlinks, &s->windows) { - layout = layout_dump(wl->window); - if (type) { - ctx->print(ctx, "%s:%d: %s [%ux%u] [layout %s]%s", - s->name, wl->idx, wl->window->name, wl->window->sx, - wl->window->sy, layout, - wl == s->curw ? " (active)" : ""); - } else { - ctx->print(ctx, "%d: %s [%ux%u] [layout %s]%s", - wl->idx, wl->window->name, wl->window->sx, - wl->window->sy, layout, - wl == s->curw ? " (active)" : ""); + template = args_get(args, 'F'); + if (template == NULL) { + switch (type) { + case 0: + template = "#{window_index}: " + "#{window_name} " + "[#{window_width}x#{window_height}] " + "[layout #{window_layout}]" + "#{?window_active, (active),}"; + break; + case 1: + template = "#{session_name):#{window_index}: " + "#{window_name} " + "[#{window_width}x#{window_height}] " + "[layout #{window_layout}]" + "#{?window_active, (active),}"; + break; } - xfree(layout); + } + + n = 0; + RB_FOREACH(wl, winlinks, &s->windows) { + ft = format_create(); + format_add(ft, "line", "%u", n); + format_session(ft, s); + format_winlink(ft, s, wl); + + line = format_expand(ft, template); + ctx->print(ctx, "%s", line); + xfree(line); + + format_free(ft); + n++; } } diff --git a/format.c b/format.c new file mode 100644 index 00000000..0c1be744 --- /dev/null +++ b/format.c @@ -0,0 +1,346 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2011 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 "tmux.h" + +/* + * Build a list of key-value pairs and use them to expand #{key} entries in a + * string. + */ + +int format_replace(struct format_tree *, + const char *, size_t, char **, size_t *, size_t *); + +/* Format key-value replacement entry. */ +RB_GENERATE(format_tree, format_entry, entry, format_cmp); + +/* Format tree comparison function. */ +int +format_cmp(struct format_entry *fe1, struct format_entry *fe2) +{ + return (strcmp(fe1->key, fe2->key)); +} + +/* Single-character aliases. */ +const char *format_aliases[26] = { + NULL, /* A */ + NULL, /* B */ + NULL, /* C */ + "pane_id", /* D */ + NULL, /* E */ + "window_flags", /* F */ + NULL, /* G */ + "host", /* H */ + "window_index", /* I */ + NULL, /* J */ + NULL, /* K */ + NULL, /* L */ + NULL, /* M */ + NULL, /* N */ + NULL, /* O */ + "pane_index", /* P */ + NULL, /* Q */ + NULL, /* R */ + "session_name", /* S */ + "pane_title", /* T */ + NULL, /* U */ + NULL, /* V */ + "window_name", /* W */ + NULL, /* X */ + NULL, /* Y */ + NULL /* Z */ +}; + +/* Create a new tree. */ +struct format_tree * +format_create(void) +{ + struct format_tree *ft; + char host[MAXHOSTNAMELEN]; + + ft = xmalloc(sizeof *ft); + RB_INIT(ft); + + if (gethostname(host, sizeof host) == 0) + format_add(ft, "host", "%s", host); + + return (ft); +} + +/* Free a tree. */ +void +format_free(struct format_tree *ft) +{ + struct format_entry *fe, *fe_next; + + fe_next = RB_MIN(format_tree, ft); + while (fe_next != NULL) { + fe = fe_next; + fe_next = RB_NEXT(format_tree, ft, fe); + + RB_REMOVE(format_tree, ft, fe); + xfree(fe->value); + xfree(fe->key); + xfree(fe); + } + + xfree (ft); +} + +/* Add a key-value pair. */ +void +format_add(struct format_tree *ft, const char *key, const char *fmt, ...) +{ + struct format_entry *fe; + va_list ap; + + fe = xmalloc(sizeof *fe); + fe->key = xstrdup(key); + + va_start(ap, fmt); + xvasprintf(&fe->value, fmt, ap); + va_end(ap); + + RB_INSERT(format_tree, ft, fe); +} + +/* Find a format entry. */ +const char * +format_find(struct format_tree *ft, const char *key) +{ + struct format_entry *fe, fe_find; + + fe_find.key = (char *) key; + fe = RB_FIND(format_tree, ft, &fe_find); + if (fe == NULL) + return (NULL); + return (fe->value); +} + +/* + * Replace a key/value pair in buffer. #{blah} is expanded directly, + * #{?blah,a,b} is replace with a if blah exists and is nonzero else b. + */ +int +format_replace(struct format_tree *ft, + const char *key, size_t keylen, char **buf, size_t *len, size_t *off) +{ + char *copy, *ptr; + const char *value; + size_t valuelen; + + /* Make a copy of the key. */ + copy = xmalloc(keylen + 1); + memcpy(copy, key, keylen); + copy[keylen] = '\0'; + + /* + * Is this a conditional? If so, check it exists and extract either the + * first or second element. If not, look up the key directly. + */ + if (*copy == '?') { + ptr = strchr(copy, ','); + if (ptr == NULL) + goto fail; + *ptr = '\0'; + + value = format_find(ft, copy + 1); + if (value != NULL && (value[0] != '0' || value[1] != '\0')) { + value = ptr + 1; + ptr = strchr(value, ','); + if (ptr == NULL) + goto fail; + *ptr = '\0'; + } else { + ptr = strchr(ptr + 1, ','); + if (ptr == NULL) + goto fail; + value = ptr + 1; + } + } else { + value = format_find(ft, copy); + if (value == NULL) + value = ""; + } + valuelen = strlen(value); + + /* Expand the buffer and copy in the value. */ + while (*len - *off < valuelen + 1) { + *buf = xrealloc(*buf, 2, *len); + *len *= 2; + } + memcpy(*buf + *off, value, valuelen); + *off += valuelen; + + xfree(copy); + return (0); + +fail: + xfree(copy); + return (-1); +} + +/* Expand keys in a template. */ +char * +format_expand(struct format_tree *ft, const char *fmt) +{ + char *buf, *ptr; + const char *s; + size_t off, len, n; + int ch; + + len = 64; + buf = xmalloc(len); + off = 0; + + while (*fmt != '\0') { + if (*fmt != '#') { + while (len - off < 2) { + buf = xrealloc(buf, 2, len); + len *= 2; + } + buf[off++] = *fmt++; + continue; + } + fmt++; + + ch = (u_char) *fmt++; + switch (ch) { + case '{': + ptr = strchr(fmt, '}'); + if (ptr == NULL) + break; + n = ptr - fmt; + + if (format_replace(ft, fmt, n, &buf, &len, &off) != 0) + break; + fmt += n + 1; + continue; + default: + if (ch >= 'A' && ch <= 'Z') { + s = format_aliases[ch - 'A']; + if (s != NULL) { + n = strlen(s); + if (format_replace ( + ft, s, n, &buf, &len, &off) != 0) + break; + continue; + } + } + while (len - off < 2) { + buf = xrealloc(buf, 2, len); + len *= 2; + } + buf[off++] = ch; + continue; + } + + break; + } + buf[off] = '\0'; + + return (buf); +} + +/* Set default format keys for a session. */ +void +format_session(struct format_tree *ft, struct session *s) +{ + struct session_group *sg; + char *tim; + time_t t; + + format_add(ft, "session_name", "%s", s->name); + format_add(ft, "session_windows", "%u", winlink_count(&s->windows)); + format_add(ft, "session_width", "%u", s->sx); + format_add(ft, "session_height", "%u", s->sy); + + sg = session_group_find(s); + format_add(ft, "session_grouped", "%d", sg != NULL); + if (sg != NULL) + format_add(ft, "session_group", "%u", session_group_index(sg)); + + t = s->creation_time.tv_sec; + format_add(ft, "session_created", "%ld", (long) t); + tim = ctime(&t); + *strchr(tim, '\n') = '\0'; + format_add(ft, "session_created_string", "%s", tim); + + if (s->flags & SESSION_UNATTACHED) + format_add(ft, "session_attached", "%d", 0); + else + format_add(ft, "session_attached", "%d", 1); +} + +/* Set default format keys for a winlink. */ +void +format_winlink(struct format_tree *ft, struct session *s, struct winlink *wl) +{ + struct window *w = wl->window; + char *layout, *flags; + + layout = layout_dump(w); + flags = window_printable_flags(s, wl); + + format_add(ft, "window_index", "%d", wl->idx); + format_add(ft, "window_name", "%s", w->name); + format_add(ft, "window_width", "%u", w->sx); + format_add(ft, "window_height", "%u", w->sy); + format_add(ft, "window_flags", "%s", flags); + format_add(ft, "window_layout", "%s", layout); + format_add(ft, "window_active", "%d", wl == s->curw); + + xfree(flags); + xfree(layout); +} + +/* Set default format keys for a window pane. */ +void +format_window_pane(struct format_tree *ft, struct window_pane *wp) +{ + struct grid *gd = wp->base.grid; + struct grid_line *gl; + unsigned long long size; + u_int i; + + size = 0; + for (i = 0; i < gd->hsize; i++) { + gl = &gd->linedata[i]; + size += gl->cellsize * sizeof *gl->celldata; + size += gl->utf8size * sizeof *gl->utf8data; + } + size += gd->hsize * sizeof *gd->linedata; + + format_add(ft, "pane_width", "%u", wp->sx); + format_add(ft, "pane_height", "%u", wp->sy); + format_add(ft, "pane_title", "%s", wp->base.title); + format_add(ft, "history_size", "%u", gd->hsize); + format_add(ft, "history_limit", "%u", gd->hlimit); + format_add(ft, "history_bytes", "%llu", size); + format_add(ft, "pane_id", "%%%u", wp->id); + format_add(ft, "pane_active", "%d", wp == wp->window->active); + format_add(ft, "pane_dead", "%d", wp->fd == -1); +} diff --git a/tmux.1 b/tmux.1 index 4543bd39..abbc06bf 100644 --- a/tmux.1 +++ b/tmux.1 @@ -617,6 +617,7 @@ is specified, list only clients connected to that session. List the syntax of all commands supported by .Nm . .It Ic list-sessions +.Op Fl F Ar format .D1 (alias: Ic ls ) List all sessions managed by the server. .It Ic lock-client Op Fl t Ar target-client @@ -626,6 +627,11 @@ Lock see the .Ic lock-server command. +For the meaning of the +.Fl F +flag, see the +.Sx FORMATS +section. .It Ic lock-session Op Fl t Ar target-session .D1 (alias: Ic locks ) Lock all clients attached to @@ -1147,6 +1153,7 @@ If is given, the newly linked window is not selected. .It Xo Ic list-panes .Op Fl as +.Op Fl F Ar format .Op Fl t Ar target .Xc .D1 (alias: Ic lsp ) @@ -1165,6 +1172,7 @@ If neither is given, is a window (or the current window). .It Xo Ic list-windows .Op Fl a +.Op Fl F Ar format .Op Fl t Ar target-session .Xc .D1 (alias: Ic lsw ) @@ -1173,6 +1181,11 @@ If is given, list all windows on the server. Otherwise, list windows in the current session or in .Ar target-session . +For the meaning of the +.Fl F +flag, see the +.Sx FORMATS +section. .It Xo Ic move-window .Op Fl dk .Op Fl s Ar src-window @@ -2535,6 +2548,70 @@ or the global window options if .Fl g is used. .El +.Sh FORMATS +The +.Ic list-sessions , +.Ic list-windows +and +.Ic list-panes +commands accept the +.Fl F +flag with a +.Ar format +argument. +This is a string which controls the output format of the command. +Special character sequences are replaced as documented under the +.Ic status-left +option and an additional long form is accepted. +Replacement variables are enclosed in +.Ql #{ +and +.Ql } , +for example +.Ql #{session_name} +is equivalent to +.Ql #S . +Conditionals are also accepted by prefixing with +.Ql ? +and separating two alternatives with a comma; +if the specified variable exists and is not zero, the first alternative +is chosen, otherwise the second is used. For example +.Ql #{?session_attached,attached,not attached} +will include the string +.Ql attached +if the session is attached and the string +.Ql not attached +if it is unattached. +.Pp +The following variables are available, where appropriate: +.Bl -column "session_created_string" "Replaced with" -offset indent +.It Sy "Variable name" Ta Sy "Replaced with" +.It Li "host" Ta "Hostname of local host" +.It Li "line" Ta "Line number in the list" +.It Li "pane_active" Ta "1 if active pane" +.It Li "pane_dead" Ta "1 if pane is dead" +.It Li "pane_height" Ta "Height of pane" +.It Li "pane_id" Ta "Unique pane id" +.It Li "pane_title" Ta "Title of pane" +.It Li "pane_width" Ta "Width of pane" +.It Li "session_attached" Ta "1 if session attached" +.It Li "session_created" Ta "Integer time session created" +.It Li "session_created_string" Ta "String time session created" +.It Li "session_group" Ta "Number of session group" +.It Li "session_grouped" Ta "1 if session in a group" +.It Li "session_height" Ta "Height of session" +.It Li "session_name" Ta "Name of session" +.It Li "session_width" Ta "Width of session" +.It Li "session_windows" Ta "Number of windows in session" +.It Li "window_active" Ta "1 if window active" +.It Li "window_flags" Ta "Window flags" +.It Li "window_height" Ta "Height of window" +.It Li "window_index" Ta "Index of window" +.It Li "window_layout" Ta "Window layout description" +.It Li "window_name" Ta "Name of window" +.It Li "window_width" Ta "Width of window" +.El +.Pp .Sh ENVIRONMENT When the server is started, .Nm diff --git a/tmux.h b/tmux.h index 7f0390d5..995e4989 100644 --- a/tmux.h +++ b/tmux.h @@ -1303,6 +1303,15 @@ struct options_table_entry { long long default_num; }; +/* Tree of format entries. */ +struct format_entry { + char *key; + char *value; + + RB_ENTRY(format_entry) entry; +}; +RB_HEAD(format_tree, format_entry); + /* List of configuration causes. */ ARRAY_DECL(causelist, char *); @@ -1345,6 +1354,20 @@ extern struct causelist cfg_causes; void printflike2 cfg_add_cause(struct causelist *, const char *, ...); int load_cfg(const char *, struct cmd_ctx *, struct causelist *); +/* format.c */ +int format_cmp(struct format_entry *, struct format_entry *); +RB_PROTOTYPE(format_tree, format_entry, entry, format_cmp); +struct format_tree *format_create(void); +void format_free(struct format_tree *); +void format_add( + struct format_tree *, const char *, const char *, ...); +const char *format_find(struct format_tree *, const char *); +char *format_expand(struct format_tree *, const char *); +void format_session(struct format_tree *, struct session *); +void format_winlink( + struct format_tree *, struct session *, struct winlink *); +void format_window_pane(struct format_tree *, struct window_pane *); + /* mode-key.c */ extern const struct mode_key_table mode_key_tables[]; extern struct mode_key_tree mode_key_tree_vi_edit; From 2888843a188c796dd230c5eb15916cd381f68d56 Mon Sep 17 00:00:00 2001 From: Jason McIntyre Date: Fri, 26 Aug 2011 13:07:49 +0000 Subject: [PATCH 0953/1180] tweak previous; --- tmux.1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tmux.1 b/tmux.1 index abbc06bf..fa630321 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2572,10 +2572,11 @@ for example is equivalent to .Ql #S . Conditionals are also accepted by prefixing with -.Ql ? +.Ql \&? and separating two alternatives with a comma; if the specified variable exists and is not zero, the first alternative -is chosen, otherwise the second is used. For example +is chosen, otherwise the second is used. +For example .Ql #{?session_attached,attached,not attached} will include the string .Ql attached @@ -2611,7 +2612,6 @@ The following variables are available, where appropriate: .It Li "window_name" Ta "Name of window" .It Li "window_width" Ta "Width of window" .El -.Pp .Sh ENVIRONMENT When the server is started, .Nm From 423649b2c61eaa976490bfa331b35cec7de92d48 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 30 Aug 2011 09:18:52 +0000 Subject: [PATCH 0954/1180] Plug memory leak, from Tiago Cunha. --- cmd-split-window.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/cmd-split-window.c b/cmd-split-window.c index e34645a4..31654771 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -58,7 +58,7 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) struct window *w; struct window_pane *wp, *new_wp = NULL; struct environ env; - char *cmd, *cwd, *cause; + char *cmd, *cwd, *cause, *new_cause; const char *shell; u_int hlimit, paneidx; int size, percentage; @@ -94,16 +94,18 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) if (args_has(args, 'l')) { size = args_strtonum(args, 'l', 0, INT_MAX, &cause); if (cause != NULL) { - ctx->error(ctx, "size %s", cause); + xasprintf(&new_cause, "size %s", cause); xfree(cause); - return (-1); + cause = new_cause; + goto error; } } else if (args_has(args, 'p')) { percentage = args_strtonum(args, 'p', 0, INT_MAX, &cause); if (cause != NULL) { - ctx->error(ctx, "percentage %s", cause); + xasprintf(&new_cause, "percentage %s", cause); xfree(cause); - return (-1); + cause = new_cause; + goto error; } if (type == LAYOUT_TOPBOTTOM) size = (wp->sy * percentage) / 100; From 9800eaa63fc4f593d5781ef202c2ace8f2ab7a0b Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 30 Aug 2011 09:20:17 +0000 Subject: [PATCH 0955/1180] Another memory leak from Tiago Cunha. --- cmd-capture-pane.c | 1 + 1 file changed, 1 insertion(+) diff --git a/cmd-capture-pane.c b/cmd-capture-pane.c index bdf74106..32c6007b 100644 --- a/cmd-capture-pane.c +++ b/cmd-capture-pane.c @@ -109,6 +109,7 @@ cmd_capture_pane_exec(struct cmd *self, struct cmd_ctx *ctx) buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause); if (cause != NULL) { ctx->error(ctx, "buffer %s", cause); + xfree(buf); xfree(cause); return (-1); } From 5985143813e331215ba08742e62476f76e48f554 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 5 Sep 2011 23:40:51 +0000 Subject: [PATCH 0956/1180] Mark dead panes with some text saying they are dead, suggested by and with help from Randy Stauner. --- server-fn.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/server-fn.c b/server-fn.c index 002d56ac..e697af77 100644 --- a/server-fn.c +++ b/server-fn.c @@ -329,16 +329,32 @@ server_unlink_window(struct session *s, struct winlink *wl) void server_destroy_pane(struct window_pane *wp) { - struct window *w = wp->window; + struct window *w = wp->window; + int old_fd; + struct screen_write_ctx ctx; + struct grid_cell gc; + old_fd = wp->fd; if (wp->fd != -1) { close(wp->fd); bufferevent_free(wp->event); wp->fd = -1; } - if (options_get_number(&w->options, "remain-on-exit")) + if (options_get_number(&w->options, "remain-on-exit")) { + if (old_fd == -1) + return; + screen_write_start(&ctx, wp, &wp->base); + screen_write_scrollregion(&ctx, 0, screen_size_y(ctx.s) - 1); + screen_write_cursormove(&ctx, 0, screen_size_y(ctx.s) - 1); + screen_write_linefeed(&ctx, 1); + memcpy(&gc, &grid_default_cell, sizeof gc); + gc.attr |= GRID_ATTR_BRIGHT; + screen_write_puts(&ctx, &gc, "Pane is dead"); + screen_write_stop(&ctx); + wp->flags |= PANE_REDRAW; return; + } layout_close_pane(wp); window_remove_pane(w, wp); From b6bd9515eae347878fb002f445175fe820406b27 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 23 Sep 2011 12:23:24 +0000 Subject: [PATCH 0957/1180] Fix typo: ) -> }. --- cmd-list-windows.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd-list-windows.c b/cmd-list-windows.c index 30adeb6e..0c3a9e64 100644 --- a/cmd-list-windows.c +++ b/cmd-list-windows.c @@ -91,7 +91,7 @@ cmd_list_windows_session( "#{?window_active, (active),}"; break; case 1: - template = "#{session_name):#{window_index}: " + template = "#{session_name}:#{window_index}: " "#{window_name} " "[#{window_width}x#{window_height}] " "[layout #{window_layout}]" From f14da260c8903a37215a220f4d22965f6fd1820b Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 23 Sep 2011 18:33:43 +0000 Subject: [PATCH 0958/1180] Tweaks to the format parts, from Tiago Cunha. --- tmux.1 | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/tmux.1 b/tmux.1 index fa630321..18480aaa 100644 --- a/tmux.1 +++ b/tmux.1 @@ -616,10 +616,14 @@ is specified, list only clients connected to that session. .D1 (alias: Ic lscm ) List the syntax of all commands supported by .Nm . -.It Ic list-sessions -.Op Fl F Ar format +.It Ic list-sessions Op Fl F Ar format .D1 (alias: Ic ls ) List all sessions managed by the server. +For the meaning of the +.Fl F +flag, see the +.Sx FORMATS +section. .It Ic lock-client Op Fl t Ar target-client .D1 (alias: Ic lockc ) Lock @@ -627,11 +631,6 @@ Lock see the .Ic lock-server command. -For the meaning of the -.Fl F -flag, see the -.Sx FORMATS -section. .It Ic lock-session Op Fl t Ar target-session .D1 (alias: Ic locks ) Lock all clients attached to @@ -1170,6 +1169,11 @@ is a session (or the current session). If neither is given, .Ar target is a window (or the current window). +For the meaning of the +.Fl F +flag, see the +.Sx FORMATS +section. .It Xo Ic list-windows .Op Fl a .Op Fl F Ar format From e6a59c4bee6ab5da56e3ff6b27a5e16d868d638f Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 25 Sep 2011 18:53:04 +0000 Subject: [PATCH 0959/1180] Reject $SHELL if it is not a full path. --- tmux.c | 4 +++- window.c | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tmux.c b/tmux.c index 196edf6c..5d4fda72 100644 --- a/tmux.c +++ b/tmux.c @@ -98,7 +98,9 @@ getshell(void) int checkshell(const char *shell) { - if (shell == NULL || *shell == '\0' || areshell(shell)) + if (shell == NULL || *shell == '\0' || *shell != '/') + return (0); + if (areshell(shell)) return (0); if (access(shell, X_OK) != 0) return (0); diff --git a/window.c b/window.c index 0736daeb..4f55c513 100644 --- a/window.c +++ b/window.c @@ -697,7 +697,7 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell, if (*wp->cmd != '\0') { /* Set SHELL but only if it is currently not useful. */ shell = getenv("SHELL"); - if (shell == NULL || *shell == '\0' || areshell(shell)) + if (checkshell(shell)) setenv("SHELL", wp->shell, 1); execl(_PATH_BSHELL, "sh", "-c", wp->cmd, (char *) NULL); From b1ed2d5bd9ce9ac52581faa59497836c0a54966c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 28 Sep 2011 20:11:21 +0000 Subject: [PATCH 0960/1180] Add -S option to refresh-client to redraw status line, from Marco Beck. --- cmd-refresh-client.c | 10 +++++++--- tmux.1 | 8 +++++++- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/cmd-refresh-client.c b/cmd-refresh-client.c index 5186dcb9..e7e10696 100644 --- a/cmd-refresh-client.c +++ b/cmd-refresh-client.c @@ -28,8 +28,8 @@ int cmd_refresh_client_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_refresh_client_entry = { "refresh-client", "refresh", - "t:", 0, 0, - CMD_TARGET_CLIENT_USAGE, + "St:", 0, 0, + "[-S] " CMD_TARGET_CLIENT_USAGE, 0, NULL, NULL, @@ -45,7 +45,11 @@ cmd_refresh_client_exec(struct cmd *self, struct cmd_ctx *ctx) if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL) return (-1); - server_redraw_client(c); + if (args_has(args, 'S')) { + status_update_jobs(c); + server_status_client(c); + } else + server_redraw_client(c); return (0); } diff --git a/tmux.1 b/tmux.1 index 18480aaa..9dc8bb04 100644 --- a/tmux.1 +++ b/tmux.1 @@ -686,11 +686,17 @@ or are invalid if .Fl t is used. -.It Ic refresh-client Op Fl t Ar target-client +.It Xo Ic refresh-client +.Op Fl S +.Op Fl t Ar target-client +.Xc .D1 (alias: Ic refresh ) Refresh the current client if bound to a key, or a single client if one is given with .Fl t . +If +.Fl S +is specified, only update the client's status bar. .It Xo Ic rename-session .Op Fl t Ar target-session .Ar new-name From 49ef0b4af31ed67a38d2e70e6ac60d48b0730519 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 2 Oct 2011 06:55:48 +0000 Subject: [PATCH 0961/1180] Add a few more formats for panes (tty, pid, start cmd/cwd). --- format.c | 6 ++++++ tmux.1 | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/format.c b/format.c index 0c1be744..21f359ab 100644 --- a/format.c +++ b/format.c @@ -343,4 +343,10 @@ format_window_pane(struct format_tree *ft, struct window_pane *wp) format_add(ft, "pane_id", "%%%u", wp->id); format_add(ft, "pane_active", "%d", wp == wp->window->active); format_add(ft, "pane_dead", "%d", wp->fd == -1); + if (wp->cmd != NULL) + format_add(ft, "pane_start_command", "%s", wp->cmd); + if (wp->cwd != NULL) + format_add(ft, "pane_start_path", "%s", wp->cwd); + format_add(ft, "pane_pid", "%ld", (long) wp->pid); + format_add(ft, "pane_tty", "%s", wp->tty); } diff --git a/tmux.1 b/tmux.1 index 9dc8bb04..e554254e 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2603,7 +2603,11 @@ The following variables are available, where appropriate: .It Li "pane_dead" Ta "1 if pane is dead" .It Li "pane_height" Ta "Height of pane" .It Li "pane_id" Ta "Unique pane id" +.It Li "pane_pid" Ta "PID of first process in pane" +.It Li "pane_start_command" Ta "Command pane started with" +.It Li "pane_start_path" Ta "Path pane started with" .It Li "pane_title" Ta "Title of pane" +.It Li "pane_tty" Ta "Pseudo terminal of pane" .It Li "pane_width" Ta "Width of pane" .It Li "session_attached" Ta "1 if session attached" .It Li "session_created" Ta "Integer time session created" From 6821ccc8824588652db3d5805cf2e2fd143e8d42 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 18 Oct 2011 08:57:01 +0000 Subject: [PATCH 0962/1180] Add an else clause for if-shell, from "arno-" on SourceForge. --- cmd-if-shell.c | 42 ++++++++++++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/cmd-if-shell.c b/cmd-if-shell.c index f2b015d2..9bd86f01 100644 --- a/cmd-if-shell.c +++ b/cmd-if-shell.c @@ -28,6 +28,7 @@ * Executes a tmux command if a shell command returns true. */ +int cmd_if_shell_check(struct args *); int cmd_if_shell_exec(struct cmd *, struct cmd_ctx *); void cmd_if_shell_callback(struct job *); @@ -35,19 +36,30 @@ void cmd_if_shell_free(void *); const struct cmd_entry cmd_if_shell_entry = { "if-shell", "if", - "", 2, 2, - "shell-command command", + "", 2, 4, + "shell-command command [else command]", 0, NULL, - NULL, + cmd_if_shell_check, cmd_if_shell_exec }; struct cmd_if_shell_data { - char *cmd; + char *cmd_if; + char *cmd_else; struct cmd_ctx ctx; }; +int +cmd_if_shell_check(struct args *args) +{ + if (args->argc == 3) + return (-1); + if (args->argc == 4 && strcmp(args->argv[2], "else") != 0) + return (-1); + return (0); +} + int cmd_if_shell_exec(struct cmd *self, struct cmd_ctx *ctx) { @@ -56,7 +68,11 @@ cmd_if_shell_exec(struct cmd *self, struct cmd_ctx *ctx) const char *shellcmd = args->argv[0]; cdata = xmalloc(sizeof *cdata); - cdata->cmd = xstrdup(args->argv[1]); + cdata->cmd_if = xstrdup(args->argv[1]); + if (args->argc == 4) + cdata->cmd_else = xstrdup(args->argv[3]); + else + cdata->cmd_else = NULL; memcpy(&cdata->ctx, ctx, sizeof cdata->ctx); if (ctx->cmdclient != NULL) @@ -75,12 +91,16 @@ cmd_if_shell_callback(struct job *job) struct cmd_if_shell_data *cdata = job->data; struct cmd_ctx *ctx = &cdata->ctx; struct cmd_list *cmdlist; + char *cmd; char *cause; - if (!WIFEXITED(job->status) || WEXITSTATUS(job->status) != 0) - return; - - if (cmd_string_parse(cdata->cmd, &cmdlist, &cause) != 0) { + if (!WIFEXITED(job->status) || WEXITSTATUS(job->status) != 0) { + cmd = cdata->cmd_else; + if (cmd == NULL) + return; + } else + cmd = cdata->cmd_if; + if (cmd_string_parse(cmd, &cmdlist, &cause) != 0) { if (cause != NULL) { ctx->error(ctx, "%s", cause); xfree(cause); @@ -107,6 +127,8 @@ cmd_if_shell_free(void *data) if (ctx->curclient != NULL) ctx->curclient->references--; - xfree(cdata->cmd); + if (cdata->cmd_else != NULL) + xfree(cdata->cmd_else); + xfree(cdata->cmd_if); xfree(cdata); } From e63909655cf2fa3afa1513f5c54f9fd7322d43a6 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 23 Oct 2011 00:49:25 +0000 Subject: [PATCH 0963/1180] Plug a memory leak and update some comments, from Tiago Cunha. --- cmd-load-buffer.c | 3 ++- cmd-save-buffer.c | 2 +- cmd-set-buffer.c | 2 +- cmd-show-buffer.c | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/cmd-load-buffer.c b/cmd-load-buffer.c index 34792048..a14f699e 100644 --- a/cmd-load-buffer.c +++ b/cmd-load-buffer.c @@ -27,7 +27,7 @@ #include "tmux.h" /* - * Loads a session paste buffer from a file. + * Loads a paste buffer from a file. */ int cmd_load_buffer_exec(struct cmd *, struct cmd_ctx *); @@ -125,6 +125,7 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) } if (paste_replace(&global_buffers, buffer, pdata, psize) != 0) { ctx->error(ctx, "no buffer %d", buffer); + xfree(pdata); return (-1); } diff --git a/cmd-save-buffer.c b/cmd-save-buffer.c index 6fd65696..586fbbba 100644 --- a/cmd-save-buffer.c +++ b/cmd-save-buffer.c @@ -25,7 +25,7 @@ #include "tmux.h" /* - * Saves a session paste buffer to a file. + * Saves a paste buffer to a file. */ int cmd_save_buffer_exec(struct cmd *, struct cmd_ctx *); diff --git a/cmd-set-buffer.c b/cmd-set-buffer.c index 14fef135..4f3d87a7 100644 --- a/cmd-set-buffer.c +++ b/cmd-set-buffer.c @@ -23,7 +23,7 @@ #include "tmux.h" /* - * Add or set a session paste buffer. + * Add or set a paste buffer. */ int cmd_set_buffer_exec(struct cmd *, struct cmd_ctx *); diff --git a/cmd-show-buffer.c b/cmd-show-buffer.c index 23490169..17d4509d 100644 --- a/cmd-show-buffer.c +++ b/cmd-show-buffer.c @@ -23,7 +23,7 @@ #include "tmux.h" /* - * Show a session paste buffer. + * Show a paste buffer. */ int cmd_show_buffer_exec(struct cmd *, struct cmd_ctx *); From 16d75a6bf2273bbe58c6d82b65f231152919fef2 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 23 Oct 2011 01:12:46 +0000 Subject: [PATCH 0964/1180] Add client formats, from Ben Boeckel. --- cmd-list-clients.c | 44 ++++++++++++++++++++++++++++---------------- format.c | 36 ++++++++++++++++++++++++++++++++++++ tmux.1 | 21 ++++++++++++++++++++- tmux.h | 1 + 4 files changed, 85 insertions(+), 17 deletions(-) diff --git a/cmd-list-clients.c b/cmd-list-clients.c index c24ec660..04d756b5 100644 --- a/cmd-list-clients.c +++ b/cmd-list-clients.c @@ -31,8 +31,8 @@ int cmd_list_clients_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_list_clients_entry = { "list-clients", "lsc", - "t:", 0, 0, - CMD_TARGET_SESSION_USAGE, + "F:t:", 0, 0, + "[-F format] " CMD_TARGET_SESSION_USAGE, CMD_READONLY, NULL, NULL, @@ -43,11 +43,13 @@ const struct cmd_entry cmd_list_clients_entry = { int cmd_list_clients_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct args *args = self->args; - struct client *c; - struct session *s; - u_int i; - const char *s_utf8; + struct args *args = self->args; + struct client *c; + struct session *s; + struct format_tree *ft; + const char *template; + u_int i; + char *line; if (args_has(args, 't')) { s = cmd_find_session(ctx, args_get(args, 't'), 0); @@ -56,22 +58,32 @@ cmd_list_clients_exec(struct cmd *self, struct cmd_ctx *ctx) } else s = NULL; + template = args_get(args, 'F'); + if (template == NULL) { + template = "#{client_tty}: #{session_name} " + "[#{client_width}x#{client_height} #{client_termname}]" + "#{?client_utf8, (utf8),}" + "#{?client_readonly, (ro),}"; + } + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); if (c == NULL || c->session == NULL) continue; - if (c->tty.flags & TTY_UTF8) - s_utf8 = " (utf8)"; - else - s_utf8 = ""; - if (s != NULL && s != c->session) continue; - ctx->print(ctx, "%s: %s [%ux%u %s]%s%s", c->tty.path, - c->session->name, c->tty.sx, c->tty.sy, - c->tty.termname, s_utf8, - c->flags & CLIENT_READONLY ? " (ro)" : ""); + + ft = format_create(); + format_add(ft, "line", "%u", i); + format_session(ft, c->session); + format_client(ft, c); + + line = format_expand(ft, template); + ctx->print(ctx, "%s", line); + xfree(line); + + format_free(ft); } return (0); diff --git a/format.c b/format.c index 21f359ab..e7442e4c 100644 --- a/format.c +++ b/format.c @@ -295,6 +295,42 @@ format_session(struct format_tree *ft, struct session *s) format_add(ft, "session_attached", "%d", 1); } +/* Set default format keys for a client. */ +void +format_client(struct format_tree *ft, struct client *c) +{ + char *tim; + time_t t; + + format_add(ft, "client_cwd", "%s", c->cwd); + format_add(ft, "client_height", "%u", c->tty.sx); + format_add(ft, "client_width", "%u", c->tty.sy); + format_add(ft, "client_tty", "%s", c->tty.path); + format_add(ft, "client_termname", "%s", c->tty.termname); + + t = c->creation_time.tv_sec; + format_add(ft, "client_created", "%ld", (long) t); + tim = ctime(&t); + *strchr(tim, '\n') = '\0'; + format_add(ft, "client_created_string", "%s", tim); + + t = c->activity_time.tv_sec; + format_add(ft, "client_activity", "%ld", (long) t); + tim = ctime(&t); + *strchr(tim, '\n') = '\0'; + format_add(ft, "client_activity_string", "%s", tim); + + if (c->tty.flags & TTY_UTF8) + format_add(ft, "client_utf8", "%d", 1); + else + format_add(ft, "client_utf8", "%d", 0); + + if (c->flags & CLIENT_READONLY) + format_add(ft, "client_readonly", "%d", 1); + else + format_add(ft, "client_readonly", "%d", 0); +} + /* Set default format keys for a winlink. */ void format_winlink(struct format_tree *ft, struct session *s, struct winlink *wl) diff --git a/tmux.1 b/tmux.1 index e554254e..0ea97e95 100644 --- a/tmux.1 +++ b/tmux.1 @@ -606,9 +606,16 @@ server and clients and destroy all sessions. .It Ic kill-session Op Fl t Ar target-session Destroy the given session, closing any windows linked to it and no other sessions, and detaching all clients attached to it. -.It Ic list-clients Op Fl t Ar target-session +.It Xo Ic list-clients +.Op Fl F Ar format +.Op Fl t Ar target-session +.Xc .D1 (alias: Ic lsc ) List all clients attached to the server. +For the meaning of the +.Fl F +flag, see the +.Sx FORMATS section. If .Ar target-session is specified, list only clients connected to that session. @@ -2560,6 +2567,7 @@ is used. .El .Sh FORMATS The +.Ic list-clients , .Ic list-sessions , .Ic list-windows and @@ -2597,6 +2605,17 @@ if it is unattached. The following variables are available, where appropriate: .Bl -column "session_created_string" "Replaced with" -offset indent .It Sy "Variable name" Ta Sy "Replaced with" +.It Li "client_activity" Ta "Integer time client last had activity" +.It Li "client_activity_string" Ta "String time client last had activity" +.It Li "client_created" Ta "Integer time client created" +.It Li "client_created_string" Ta "String time client created" +.It Li "client_cwd" Ta "Working directory of client" +.It Li "client_height" Ta "Height of client" +.It Li "client_readonly" Ta "1 if client is readonly" +.It Li "client_termname" Ta "Terminal name of client" +.It Li "client_tty" Ta "Pseudo terminal of client" +.It Li "client_utf8" Ta "1 if client supports utf8" +.It Li "client_width" Ta "Width of client" .It Li "host" Ta "Hostname of local host" .It Li "line" Ta "Line number in the list" .It Li "pane_active" Ta "1 if active pane" diff --git a/tmux.h b/tmux.h index 995e4989..5fef5dfe 100644 --- a/tmux.h +++ b/tmux.h @@ -1364,6 +1364,7 @@ void format_add( const char *format_find(struct format_tree *, const char *); char *format_expand(struct format_tree *, const char *); void format_session(struct format_tree *, struct session *); +void format_client(struct format_tree *, struct client *); void format_winlink( struct format_tree *, struct session *, struct winlink *); void format_window_pane(struct format_tree *, struct window_pane *); From b32254acda43bc4966565f482ccf911b74a95345 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 23 Oct 2011 08:03:27 +0000 Subject: [PATCH 0965/1180] Ignore LC_ALL and LC_CTYPE if they are empty as well as unset. --- tmux.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tmux.c b/tmux.c index 5d4fda72..0c161490 100644 --- a/tmux.c +++ b/tmux.c @@ -289,8 +289,8 @@ main(int argc, char **argv) * if not they know that output from UTF-8-capable programs may * be wrong. */ - if ((s = getenv("LC_ALL")) == NULL) { - if ((s = getenv("LC_CTYPE")) == NULL) + if ((s = getenv("LC_ALL")) == NULL || *s == '\0') { + if ((s = getenv("LC_CTYPE")) == NULL || *s == '\0') s = getenv("LANG"); } if (s != NULL && (strcasestr(s, "UTF-8") != NULL || From 179d0686d78ec6489572e122dbb50220471531a2 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 23 Oct 2011 08:10:11 +0000 Subject: [PATCH 0966/1180] For initial session, use size of command client even if detached. --- cmd-new-session.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/cmd-new-session.c b/cmd-new-session.c index 5eaa5393..d576dc61 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -154,9 +154,17 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) } /* Find new session size. */ - if (detached) { + if (ctx->cmdclient != NULL) { + sx = ctx->cmdclient->tty.sx; + sy = ctx->cmdclient->tty.sy; + } else if (ctx->curclient != NULL) { + sx = ctx->curclient->tty.sx; + sy = ctx->curclient->tty.sy; + } else { sx = 80; sy = 24; + } + if (detached) { if (args_has(args, 'x')) { sx = strtonum( args_get(args, 'x'), 1, USHRT_MAX, &errstr); @@ -173,12 +181,6 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) return (-1); } } - } else if (ctx->cmdclient != NULL) { - sx = ctx->cmdclient->tty.sx; - sy = ctx->cmdclient->tty.sy; - } else { - sx = ctx->curclient->tty.sx; - sy = ctx->curclient->tty.sy; } if (sy > 0 && options_get_number(&global_s_options, "status")) sy--; From 7ff4cf94050e11517bb6fa89be2f5f4c85af12e3 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 23 Oct 2011 08:34:01 +0000 Subject: [PATCH 0967/1180] Try to resolve relative paths for loadb and saveb (first using client working directory if any then default-path or session wd). --- cmd-load-buffer.c | 16 +++++++++++++++- cmd-save-buffer.c | 17 ++++++++++++++++- tmux.c | 16 ++++++++++++++++ tmux.h | 1 + 4 files changed, 48 insertions(+), 2 deletions(-) diff --git a/cmd-load-buffer.c b/cmd-load-buffer.c index a14f699e..09fddbf7 100644 --- a/cmd-load-buffer.c +++ b/cmd-load-buffer.c @@ -48,8 +48,9 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; struct client *c = ctx->cmdclient; + struct session *s; FILE *f; - const char *path; + const char *path, *newpath, *wd; char *pdata, *new_pdata, *cause; size_t psize; u_int limit; @@ -93,6 +94,19 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) return (1); } + if (c != NULL) + wd = c->cwd; + else if ((s = cmd_current_session(ctx, 0)) != NULL) { + wd = options_get_string(&s->options, "default-path"); + if (*wd == '\0') + wd = s->cwd; + } else + wd = NULL; + if (wd != NULL && *wd != '\0') { + newpath = get_full_path(wd, path); + if (newpath != NULL) + path = newpath; + } if ((f = fopen(path, "rb")) == NULL) { ctx->error(ctx, "%s: %s", path, strerror(errno)); return (-1); diff --git a/cmd-save-buffer.c b/cmd-save-buffer.c index 586fbbba..f45902aa 100644 --- a/cmd-save-buffer.c +++ b/cmd-save-buffer.c @@ -45,8 +45,9 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; struct client *c = ctx->cmdclient; + struct session *s; struct paste_buffer *pb; - const char *path; + const char *path, *newpath, *wd; char *cause; int buffer; mode_t mask; @@ -80,6 +81,20 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) } bufferevent_write(c->stdout_event, pb->data, pb->size); } else { + if (c != NULL) + wd = c->cwd; + else if ((s = cmd_current_session(ctx, 0)) != NULL) { + wd = options_get_string(&s->options, "default-path"); + if (*wd == '\0') + wd = s->cwd; + } else + wd = NULL; + if (wd != NULL && *wd != '\0') { + newpath = get_full_path(wd, path); + if (newpath != NULL) + path = newpath; + } + mask = umask(S_IRWXG | S_IRWXO); if (args_has(self->args, 'a')) f = fopen(path, "ab"); diff --git a/tmux.c b/tmux.c index 0c161490..cab9d54e 100644 --- a/tmux.c +++ b/tmux.c @@ -124,6 +124,22 @@ areshell(const char *shell) return (0); } +const char* +get_full_path(const char *wd, const char *path) +{ + static char newpath[MAXPATHLEN]; + char oldpath[MAXPATHLEN]; + + if (getcwd(oldpath, sizeof oldpath) == NULL) + return (NULL); + if (chdir(wd) != 0) + return (NULL); + if (realpath(path, newpath) != 0) + return (NULL); + chdir(oldpath); + return (newpath); +} + void parseenvironment(void) { diff --git a/tmux.h b/tmux.h index 5fef5dfe..a94bbaf9 100644 --- a/tmux.h +++ b/tmux.h @@ -1345,6 +1345,7 @@ void logfile(const char *); const char *getshell(void); int checkshell(const char *); int areshell(const char *); +const char* get_full_path(const char *, const char *); void setblocking(int, int); __dead void shell_exec(const char *, const char *); From f0aad68aeef493954d3a840bea134abd22b37c2d Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 23 Oct 2011 10:16:14 +0000 Subject: [PATCH 0968/1180] Support for \e[3J to clear the history. Also send the corresponding terminfo code (E3) before locking. --- input.c | 11 +++++++++++ screen-write.c | 11 +++++++++++ server-fn.c | 1 + tmux.h | 2 ++ tty-term.c | 1 + 5 files changed, 26 insertions(+) diff --git a/input.c b/input.c index 9237ef5c..a914aa5a 100644 --- a/input.c +++ b/input.c @@ -1126,6 +1126,17 @@ input_csi_dispatch(struct input_ctx *ictx) case 2: screen_write_clearscreen(sctx); break; + case 3: + switch (input_get(ictx, 1, 0, 0)) { + case 0: + /* + * Linux console extension to clear history + * (for example before locking the screen). + */ + screen_write_clearhistory(sctx); + break; + } + break; default: log_debug("%s: unknown '%c'", __func__, ictx->ch); break; diff --git a/screen-write.c b/screen-write.c index 60623701..d1d02c7c 100644 --- a/screen-write.c +++ b/screen-write.c @@ -985,6 +985,17 @@ screen_write_clearscreen(struct screen_write_ctx *ctx) tty_write(tty_cmd_clearscreen, &ttyctx); } +/* Clear entire history. */ +void +screen_write_clearhistory(struct screen_write_ctx *ctx) +{ + struct screen *s = ctx->s; + struct grid *gd = s->grid; + + grid_move_lines(gd, 0, gd->hsize, gd->sy); + gd->hsize = 0; +} + /* Write cell data. */ void screen_write_cell(struct screen_write_ctx *ctx, diff --git a/server-fn.c b/server-fn.c index e697af77..c8f85cd0 100644 --- a/server-fn.c +++ b/server-fn.c @@ -237,6 +237,7 @@ server_lock_client(struct client *c) tty_stop_tty(&c->tty); tty_raw(&c->tty, tty_term_string(c->tty.term, TTYC_SMCUP)); tty_raw(&c->tty, tty_term_string(c->tty.term, TTYC_CLEAR)); + tty_raw(&c->tty, tty_term_string(c->tty.term, TTYC_E3)); c->flags |= CLIENT_SUSPENDED; server_write_client(c, MSG_LOCK, &lockdata, sizeof lockdata); diff --git a/tmux.h b/tmux.h index a94bbaf9..87bb6852 100644 --- a/tmux.h +++ b/tmux.h @@ -206,6 +206,7 @@ enum tty_code_code { TTYC_DIM, /* enter_dim_mode, mh */ TTYC_DL, /* parm_delete_line, DL */ TTYC_DL1, /* delete_line, dl */ + TTYC_E3, TTYC_EL, /* clr_eol, ce */ TTYC_EL1, /* clr_bol, cb */ TTYC_ENACS, /* ena_acs, eA */ @@ -1866,6 +1867,7 @@ void screen_write_kkeypadmode(struct screen_write_ctx *, int); void screen_write_clearendofscreen(struct screen_write_ctx *); void screen_write_clearstartofscreen(struct screen_write_ctx *); void screen_write_clearscreen(struct screen_write_ctx *); +void screen_write_clearhistory(struct screen_write_ctx *); void screen_write_cell(struct screen_write_ctx *, const struct grid_cell *, const struct utf8_data *); void screen_write_setselection(struct screen_write_ctx *, u_char *, u_int); diff --git a/tty-term.c b/tty-term.c index 41cb97c4..201d0e1d 100644 --- a/tty-term.c +++ b/tty-term.c @@ -61,6 +61,7 @@ const struct tty_term_code_entry tty_term_codes[NTTYCODE] = { { TTYC_DIM, TTYCODE_STRING, "dim" }, { TTYC_DL, TTYCODE_STRING, "dl" }, { TTYC_DL1, TTYCODE_STRING, "dl1" }, + { TTYC_E3, TTYCODE_STRING, "E3" }, { TTYC_EL, TTYCODE_STRING, "el" }, { TTYC_EL1, TTYCODE_STRING, "el1" }, { TTYC_ENACS, TTYCODE_STRING, "enacs" }, From e3225bc4e3f3b0ee5d58d14a7cfad382cadca886 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 23 Oct 2011 10:19:26 +0000 Subject: [PATCH 0969/1180] Alias NPage/PPage as PageDown/PgDn/PageUp/PgUp to reduce occasional confusion. --- key-string.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/key-string.c b/key-string.c index ad7d4edd..29b6a844 100644 --- a/key-string.c +++ b/key-string.c @@ -55,7 +55,11 @@ const struct { { "Home", KEYC_HOME }, { "End", KEYC_END }, { "NPage", KEYC_NPAGE }, + { "PageDown", KEYC_NPAGE }, + { "PgDn", KEYC_NPAGE }, { "PPage", KEYC_PPAGE }, + { "PageUp", KEYC_PPAGE }, + { "PgUp", KEYC_PPAGE }, { "Tab", '\011' }, { "BTab", KEYC_BTAB }, { "Space", ' ' }, From f5a73c54331df1b187760b6d8207dc1390ee1927 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 23 Oct 2011 23:38:16 +0000 Subject: [PATCH 0970/1180] When copying, make repeat count indicate buffer to replace if used. --- window-copy.c | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/window-copy.c b/window-copy.c index a129118c..b9221405 100644 --- a/window-copy.c +++ b/window-copy.c @@ -52,7 +52,7 @@ void window_copy_goto_line(struct window_pane *, const char *); void window_copy_update_cursor(struct window_pane *, u_int, u_int); void window_copy_start_selection(struct window_pane *); int window_copy_update_selection(struct window_pane *); -void window_copy_copy_selection(struct window_pane *); +void window_copy_copy_selection(struct window_pane *, int); void window_copy_clear_selection(struct window_pane *); void window_copy_copy_line( struct window_pane *, char **, size_t *, u_int, u_int, u_int); @@ -134,7 +134,7 @@ struct window_copy_mode_data { const char *inputprompt; char *inputstr; - u_int numprefix; + int numprefix; enum window_copy_input_type searchtype; char *searchstr; @@ -165,7 +165,7 @@ window_copy_init(struct window_pane *wp) data->inputtype = WINDOW_COPY_OFF; data->inputprompt = NULL; data->inputstr = xstrdup(""); - data->numprefix = 0; + data->numprefix = -1; data->searchtype = WINDOW_COPY_OFF; data->searchstr = NULL; @@ -358,12 +358,12 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key) const char *word_separators; struct window_copy_mode_data *data = wp->modedata; struct screen *s = &data->screen; - u_int n, np; - int keys; + u_int n; + int np, keys; enum mode_key_cmd cmd; np = data->numprefix; - if (np == 0) + if (np <= 0) np = 1; if (data->inputtype == WINDOW_COPY_JUMPFORWARD || @@ -513,7 +513,7 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key) if (sess != NULL && (cmd == MODEKEYCOPY_COPYLINE || cmd == MODEKEYCOPY_COPYENDOFLINE)) { - window_copy_copy_selection(wp); + window_copy_copy_selection(wp, -1); window_pane_reset_mode(wp); return; } @@ -524,7 +524,7 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key) break; case MODEKEYCOPY_COPYSELECTION: if (sess != NULL) { - window_copy_copy_selection(wp); + window_copy_copy_selection(wp, data->numprefix); window_pane_reset_mode(wp); return; } @@ -664,7 +664,7 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key) break; } - data->numprefix = 0; + data->numprefix = -1; return; input_on: @@ -696,11 +696,11 @@ 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; - u_int np; + int np; switch (mode_key_lookup(&data->mdata, key)) { case MODEKEYEDIT_CANCEL: - data->numprefix = 0; + data->numprefix = -1; return (-1); case MODEKEYEDIT_BACKSPACE: inputlen = strlen(data->inputstr); @@ -712,7 +712,7 @@ window_copy_key_input(struct window_pane *wp, int key) break; case MODEKEYEDIT_ENTER: np = data->numprefix; - if (np == 0) + if (np <= 0) np = 1; switch (data->inputtype) { @@ -738,7 +738,7 @@ window_copy_key_input(struct window_pane *wp, int key) *data->inputstr = '\0'; break; } - data->numprefix = 0; + data->numprefix = -1; return (1); case MODEKEY_OTHER: if (key < 32 || key > 126) @@ -767,7 +767,7 @@ window_copy_key_numeric_prefix(struct window_pane *wp, int key) if (key < '0' || key > '9') return 1; - if (data->numprefix >= 100) /* no more than three digits */ + if (data->numprefix >= 100) /* no more than three digits */ return 0; data->numprefix = data->numprefix * 10 + key - '0'; @@ -834,7 +834,7 @@ reset_mode: s->mode &= ~MODE_MOUSE_BUTTON; s->mode |= MODE_MOUSE_STANDARD; if (sess != NULL) { - window_copy_copy_selection(wp); + window_copy_copy_selection(wp, -1); window_pane_reset_mode(wp); } } @@ -1235,7 +1235,7 @@ window_copy_update_selection(struct window_pane *wp) } void -window_copy_copy_selection(struct window_pane *wp) +window_copy_copy_selection(struct window_pane *wp, int idx) { struct window_copy_mode_data *data = wp->modedata; struct screen *s = &data->screen; @@ -1315,7 +1315,7 @@ window_copy_copy_selection(struct window_pane *wp) } else { if (keys == MODEKEY_EMACS) lastex = ex; - else + else lastex = ex + 1; restex = xx; firstsx = sx; @@ -1347,8 +1347,11 @@ window_copy_copy_selection(struct window_pane *wp) screen_write_setselection(&wp->ictx.ctx, buf, off); /* Add the buffer to the stack. */ - limit = options_get_number(&global_options, "buffer-limit"); - paste_add(&global_buffers, buf, off, limit); + if (idx == -1) { + limit = options_get_number(&global_options, "buffer-limit"); + paste_add(&global_buffers, buf, off, limit); + } else + paste_replace(&global_buffers, idx, buf, off); } void From 5ed3daf28bc2a2677206425cbdfeda88c8c92624 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 27 Oct 2011 22:40:15 +0000 Subject: [PATCH 0971/1180] Didn't really think the else behaviour through - requiring argv to contain "else" is silly so just omit that, also some manpage tweaks. From Tiago Cunha. --- cmd-if-shell.c | 26 +++++++------------------- tmux.1 | 8 +++++--- 2 files changed, 12 insertions(+), 22 deletions(-) diff --git a/cmd-if-shell.c b/cmd-if-shell.c index 9bd86f01..6692a99c 100644 --- a/cmd-if-shell.c +++ b/cmd-if-shell.c @@ -25,10 +25,9 @@ #include "tmux.h" /* - * Executes a tmux command if a shell command returns true. + * Executes a tmux command if a shell command returns true or false. */ -int cmd_if_shell_check(struct args *); int cmd_if_shell_exec(struct cmd *, struct cmd_ctx *); void cmd_if_shell_callback(struct job *); @@ -36,11 +35,11 @@ void cmd_if_shell_free(void *); const struct cmd_entry cmd_if_shell_entry = { "if-shell", "if", - "", 2, 4, - "shell-command command [else command]", + "", 2, 3, + "shell-command command [command]", 0, NULL, - cmd_if_shell_check, + NULL, cmd_if_shell_exec }; @@ -50,16 +49,6 @@ struct cmd_if_shell_data { struct cmd_ctx ctx; }; -int -cmd_if_shell_check(struct args *args) -{ - if (args->argc == 3) - return (-1); - if (args->argc == 4 && strcmp(args->argv[2], "else") != 0) - return (-1); - return (0); -} - int cmd_if_shell_exec(struct cmd *self, struct cmd_ctx *ctx) { @@ -69,8 +58,8 @@ cmd_if_shell_exec(struct cmd *self, struct cmd_ctx *ctx) cdata = xmalloc(sizeof *cdata); cdata->cmd_if = xstrdup(args->argv[1]); - if (args->argc == 4) - cdata->cmd_else = xstrdup(args->argv[3]); + if (args->argc == 3) + cdata->cmd_else = xstrdup(args->argv[2]); else cdata->cmd_else = NULL; memcpy(&cdata->ctx, ctx, sizeof cdata->ctx); @@ -91,8 +80,7 @@ cmd_if_shell_callback(struct job *job) struct cmd_if_shell_data *cdata = job->data; struct cmd_ctx *ctx = &cdata->ctx; struct cmd_list *cmdlist; - char *cmd; - char *cause; + char *cause, *cmd; if (!WIFEXITED(job->status) || WEXITSTATUS(job->status) != 0) { cmd = cdata->cmd_else; diff --git a/tmux.1 b/tmux.1 index 0ea97e95..8c368bdf 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2971,13 +2971,15 @@ Miscellaneous commands are as follows: .Bl -tag -width Ds .It Ic clock-mode Op Fl t Ar target-pane Display a large clock. -.It Ic if-shell Ar shell-command command +.It Ic if-shell Ar shell-command command Op Ar command .D1 (alias: Ic if ) -Execute +Execute the first .Ar command if .Ar shell-command -returns success. +returns success or the second +.Ar command +otherwise. .It Ic lock-server .D1 (alias: Ic lock ) Lock each client individually by running the command specified by the From 0ff42d975bd7bde6f83d2768aeac2e9ed9f0e6b2 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 27 Oct 2011 22:41:03 +0000 Subject: [PATCH 0972/1180] Missing -o on usage for pipe-pane, from Tiago Cunha. --- cmd-pipe-pane.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd-pipe-pane.c b/cmd-pipe-pane.c index 00f0378a..0a52ae5d 100644 --- a/cmd-pipe-pane.c +++ b/cmd-pipe-pane.c @@ -39,7 +39,7 @@ void cmd_pipe_pane_error_callback(struct bufferevent *, short, void *); const struct cmd_entry cmd_pipe_pane_entry = { "pipe-pane", "pipep", "ot:", 0, 1, - CMD_TARGET_PANE_USAGE "[-o] [command]", + "[-o] " CMD_TARGET_PANE_USAGE " [command]", 0, NULL, NULL, From b2ee98b8d7403f213eec7bb8de502a843b284586 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 27 Oct 2011 22:54:06 +0000 Subject: [PATCH 0973/1180] Add screen*:XT to terminal-overrides for tmux-in-tmux, from Romain Francoise. --- options-table.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/options-table.c b/options-table.c index 352cdc18..2658f251 100644 --- a/options-table.c +++ b/options-table.c @@ -376,7 +376,7 @@ const struct options_table_entry session_options_table[] = { .default_str = "*88col*:colors=88,*256col*:colors=256" ",xterm*:XT:Ms=\\E]52;%p1%s;%p2%s\\007" ":Cc=\\E]12;%p1%s\\007:Cr=\\E]112\\007" - ":Cs=\\E[%p1%d q:Csr=\\E[2 q" + ":Cs=\\E[%p1%d q:Csr=\\E[2 q,screen*:XT" }, { .name = "update-environment", From e5d6df8979dfbfb390511f31dcc40126bc5b5c6d Mon Sep 17 00:00:00 2001 From: Jason McIntyre Date: Thu, 27 Oct 2011 23:33:35 +0000 Subject: [PATCH 0974/1180] minor formatting fix; --- tmux.1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tmux.1 b/tmux.1 index 8c368bdf..47e89bf3 100644 --- a/tmux.1 +++ b/tmux.1 @@ -615,7 +615,8 @@ List all clients attached to the server. For the meaning of the .Fl F flag, see the -.Sx FORMATS section. +.Sx FORMATS +section. If .Ar target-session is specified, list only clients connected to that session. From e5bf63cb59981657e5140c0f542ec3c1f69dcd5a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 5 Nov 2011 09:06:31 +0000 Subject: [PATCH 0975/1180] Option to change status line (message) background when using vi keys and in command mode. From Ben Boeckel. --- options-table.c | 15 +++++++++++++++ status.c | 18 +++++++++++++++--- tmux.1 | 6 ++++++ 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/options-table.c b/options-table.c index 2658f251..0129b0b9 100644 --- a/options-table.c +++ b/options-table.c @@ -194,6 +194,21 @@ const struct options_table_entry session_options_table[] = { .default_num = 3 }, + { .name = "message-command-attr", + .type = OPTIONS_TABLE_ATTRIBUTES, + .default_num = 0 + }, + + { .name = "message-command-bg", + .type = OPTIONS_TABLE_COLOUR, + .default_num = 0 + }, + + { .name = "message-command-fg", + .type = OPTIONS_TABLE_COLOUR, + .default_num = 3 + }, + { .name = "message-fg", .type = OPTIONS_TABLE_COLOUR, .default_num = 0 diff --git a/status.c b/status.c index 50e7302e..86f7e8c9 100644 --- a/status.c +++ b/status.c @@ -919,9 +919,16 @@ status_prompt_redraw(struct client *c) off = 0; 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"); + /* 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"); + } screen_write_start(&ctx, NULL, &c->status); @@ -977,7 +984,12 @@ status_prompt_key(struct client *c, int key) c->flags |= CLIENT_STATUS; } break; + case MODEKEYEDIT_SWITCHMODE: + c->flags |= CLIENT_STATUS; + break; case MODEKEYEDIT_SWITCHMODEAPPEND: + c->flags |= CLIENT_STATUS; + /* FALLTHROUGH */ case MODEKEYEDIT_CURSORRIGHT: if (c->prompt_index < size) { c->prompt_index++; diff --git a/tmux.1 b/tmux.1 index 47e89bf3..47f3692d 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1967,6 +1967,12 @@ 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. .It Ic message-limit Ar number From 6c1c304fc3e2197922fa7659110c3e78c4fbce6f Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 5 Nov 2011 09:13:00 +0000 Subject: [PATCH 0976/1180] Missing bits for new keys and buffer indexes, from Tiago Cunha --- tmux.1 | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tmux.1 b/tmux.1 index 47f3692d..0de1f3e3 100644 --- a/tmux.1 +++ b/tmux.1 @@ -864,6 +864,9 @@ in emacs mode, and .Ql 10w in vi. .Pp +When copying the selection, the repeat count indicates the buffer index to +replace, if used. +.Pp Mode key bindings are defined in a set of named tables: .Em vi-edit and @@ -1548,10 +1551,8 @@ to .Em Home , .Em IC (Insert), -.Em NPage -(Page Up), -.Em PPage -(Page Down), +.Em NPage/PageDown/PgDn , +.Em PPage/PageUp/PgUp , .Em Space , and .Em Tab . From 9f738dd2fe01b5b70c07280450eed32614c561c2 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 9 Nov 2011 12:02:07 +0000 Subject: [PATCH 0977/1180] Fix a trivial copy-and-paste error (sx->sy), from Chris Johnsen. --- layout-set.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/layout-set.c b/layout-set.c index eb75233a..98ed9736 100644 --- a/layout-set.c +++ b/layout-set.c @@ -260,8 +260,8 @@ layout_set_main_h(struct window *w) * If an other pane height was specified, honour it so long as it * doesn't shrink the main height to less than the main-pane-height */ - if (otherheight > 1 && w->sx - otherheight > mainheight) - mainheight = w->sx - otherheight; + if (otherheight > 1 && w->sy - otherheight > mainheight) + mainheight = w->sy - otherheight; if (mainheight < PANE_MINIMUM + 1) mainheight = PANE_MINIMUM + 1; From 57df44291634e1083fccf29ecccc8b1793647e50 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 15 Nov 2011 23:19:51 +0000 Subject: [PATCH 0978/1180] Make window_pane_index work the same as window_index, from Ben Boeckel. --- cmd-respawn-pane.c | 7 +++++-- cmd-split-window.c | 3 ++- screen-redraw.c | 5 +++-- status.c | 5 ++++- tmux.h | 2 +- window.c | 18 ++++++++++-------- 6 files changed, 25 insertions(+), 15 deletions(-) diff --git a/cmd-respawn-pane.c b/cmd-respawn-pane.c index 7e272a80..d4d67d54 100644 --- a/cmd-respawn-pane.c +++ b/cmd-respawn-pane.c @@ -49,15 +49,18 @@ cmd_respawn_pane_exec(struct cmd *self, struct cmd_ctx *ctx) struct session *s; struct environ env; const char *cmd; - char *cause; + char *cause; + u_int idx; if ((wl = cmd_find_pane(ctx, args_get(args, 't'), &s, &wp)) == NULL) return (-1); w = wl->window; if (!args_has(self->args, 'k') && wp->fd != -1) { + if (window_pane_index(wp, &idx) != 0) + fatalx("index not found"); ctx->error(ctx, "pane still active: %s:%u.%u", - s->name, wl->idx, window_pane_index(w, wp)); + s->name, wl->idx, idx); return (-1); } diff --git a/cmd-split-window.c b/cmd-split-window.c index 31654771..b1b738b1 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -140,7 +140,8 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) environ_free(&env); if (args_has(args, 'P')) { - paneidx = window_pane_index(wl->window, new_wp); + if (window_pane_index(new_wp, &paneidx) != 0) + fatalx("index not found"); ctx->print(ctx, "%s:%u.%u", s->name, wl->idx, paneidx); } return (0); diff --git a/screen-redraw.c b/screen-redraw.c index 1abd719c..0a546bf7 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -264,7 +264,7 @@ screen_redraw_draw_number(struct client *c, struct window_pane *wp) { struct tty *tty = &c->tty; struct session *s = c->session; - struct options *oo = &s->options; + struct options *oo = &s->options; struct window *w = wp->window; struct grid_cell gc; u_int idx, px, py, i, j, xoff, yoff; @@ -272,7 +272,8 @@ screen_redraw_draw_number(struct client *c, struct window_pane *wp) char buf[16], *ptr; size_t len; - idx = window_pane_index(w, wp); + if (window_pane_index(wp, &idx) != 0) + fatalx("index not found"); len = xsnprintf(buf, sizeof buf, "%u", idx); if (wp->sx < len) diff --git a/status.c b/status.c index 86f7e8c9..487d3f56 100644 --- a/status.c +++ b/status.c @@ -372,6 +372,7 @@ status_replace1(struct client *c, struct session *s, struct winlink *wl, char ch, tmp[256], *ptr, *endptr, *freeptr; size_t ptrlen; long limit; + u_int idx; if (s == NULL) s = c->session; @@ -422,8 +423,10 @@ status_replace1(struct client *c, struct session *s, struct winlink *wl, ptr = tmp; goto do_replace; case 'P': + if (window_pane_index(wp, &idx) != 0) + fatalx("index not found"); xsnprintf( - tmp, sizeof tmp, "%u", window_pane_index(wl->window, wp)); + tmp, sizeof tmp, "%u", idx); ptr = tmp; goto do_replace; case 'S': diff --git a/tmux.h b/tmux.h index 87bb6852..74861abb 100644 --- a/tmux.h +++ b/tmux.h @@ -1931,7 +1931,7 @@ struct window_pane *window_pane_next_by_number(struct window *, struct window_pane *, u_int); struct window_pane *window_pane_previous_by_number(struct window *, struct window_pane *, u_int); -u_int window_pane_index(struct window *, struct window_pane *); +int window_pane_index(struct window_pane *, u_int *); u_int window_count_panes(struct window *); void window_destroy_panes(struct window *); struct window_pane *window_pane_find_by_id(u_int); diff --git a/window.c b/window.c index 4f55c513..f46e302f 100644 --- a/window.c +++ b/window.c @@ -486,19 +486,21 @@ window_pane_previous_by_number(struct window *w, struct window_pane *wp, return (wp); } -u_int -window_pane_index(struct window *w, struct window_pane *wp) +int +window_pane_index(struct window_pane *wp, u_int *i) { struct window_pane *wq; - u_int n; + struct window *w = wp->window; - n = options_get_number(&w->options, "pane-base-index"); + *i = options_get_number(&w->options, "pane-base-index"); TAILQ_FOREACH(wq, &w->panes, entry) { - if (wp == wq) - break; - n++; + if (wp == wq) { + return (0); + } + (*i)++; } - return (n); + + return (-1); } u_int From 7c9bc377a351db561322353848be2ffeffef84db Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 15 Nov 2011 23:21:52 +0000 Subject: [PATCH 0979/1180] Add a pane_index format string and use it, from Ben Boeckel. --- cmd-list-panes.c | 6 +++--- format.c | 5 +++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/cmd-list-panes.c b/cmd-list-panes.c index d0942ad8..55559db7 100644 --- a/cmd-list-panes.c +++ b/cmd-list-panes.c @@ -102,21 +102,21 @@ cmd_list_panes_window(struct cmd *self, if (template == NULL) { switch (type) { case 0: - template = "#{line}: " + template = "#{pane_index}: " "[#{pane_width}x#{pane_height}] [history " "#{history_size}/#{history_limit}, " "#{history_bytes} bytes] #{pane_id}" "#{?pane_active, (active),}#{?pane_dead, (dead),}"; break; case 1: - template = "#{window_index}.#{line}: " + template = "#{window_index}.#{pane_index}: " "[#{pane_width}x#{pane_height}] [history " "#{history_size}/#{history_limit}, " "#{history_bytes} bytes] #{pane_id}" "#{?pane_active, (active),}#{?pane_dead, (dead),}"; break; case 2: - template = "#{session_name}:#{window_index}.#{line}: " + template = "#{session_name}:#{window_index}.#{pane_index}: " "[#{pane_width}x#{pane_height}] [history " "#{history_size}/#{history_limit}, " "#{history_bytes} bytes] #{pane_id}" diff --git a/format.c b/format.c index e7442e4c..3c8aea6e 100644 --- a/format.c +++ b/format.c @@ -361,6 +361,7 @@ format_window_pane(struct format_tree *ft, struct window_pane *wp) struct grid_line *gl; unsigned long long size; u_int i; + u_int idx; size = 0; for (i = 0; i < gd->hsize; i++) { @@ -370,9 +371,13 @@ format_window_pane(struct format_tree *ft, struct window_pane *wp) } size += gd->hsize * sizeof *gd->linedata; + if (window_pane_index(wp, &idx) != 0) + fatalx("index not found"); + format_add(ft, "pane_width", "%u", wp->sx); format_add(ft, "pane_height", "%u", wp->sy); format_add(ft, "pane_title", "%s", wp->base.title); + format_add(ft, "pane_index", "%u", idx); format_add(ft, "history_size", "%u", gd->hsize); format_add(ft, "history_limit", "%u", gd->hlimit); format_add(ft, "history_bytes", "%llu", size); From fd25d358681a8373e67d4f3649628913dcd87000 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 15 Nov 2011 23:24:04 +0000 Subject: [PATCH 0980/1180] Move word-separators to be a session rather than window option, from Ben Boeckel. --- options-table.c | 10 +++++----- tmux.1 | 15 +++++++-------- window-copy.c | 6 +++--- 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/options-table.c b/options-table.c index 0129b0b9..fa5dc71f 100644 --- a/options-table.c +++ b/options-table.c @@ -421,6 +421,11 @@ const struct options_table_entry session_options_table[] = { .default_num = 0 }, + { .name = "word-separators", + .type = OPTIONS_TABLE_STRING, + .default_str = " -_@" + }, + { .name = NULL } }; @@ -615,11 +620,6 @@ const struct options_table_entry window_options_table[] = { .default_str = "#I:#W#F" }, - { .name = "word-separators", - .type = OPTIONS_TABLE_STRING, - .default_str = " -_@" - }, - { .name = "xterm-keys", .type = OPTIONS_TABLE_FLAG, .default_num = 0 diff --git a/tmux.1 b/tmux.1 index 0de1f3e3..5e5fd751 100644 --- a/tmux.1 +++ b/tmux.1 @@ -837,7 +837,7 @@ and characters as word delimiters by default, but this can be adjusted by setting the .Em word-separators -window option. +session option. Next word moves to the start of the next word, next word end to the end of the next word and previous word to the start of the previous word. The three next and previous space keys work similarly but use a space alone as @@ -2288,6 +2288,12 @@ window option is enabled. If .Ic monitor-silence is enabled, prints a message after the interval has expired on a given window. +.It Ic word-separators Ar string +Sets the session's conception of what characters are considered word +separators, for the purposes of the next and previous word commands in +copy mode. +The default is +.Ql \ -_@ . .El .It Xo Ic set-window-option .Op Fl agu @@ -2528,13 +2534,6 @@ option for details of special character sequences available. The default is .Ql #I:#W#F . .Pp -.It Ic word-separators Ar string -Sets the window's conception of what characters are considered word -separators, for the purposes of the next and previous word commands in -copy mode. -The default is -.Ql \ -_@ . -.Pp .It Xo Ic xterm-keys .Op Ic on | off .Xc diff --git a/window-copy.c b/window-copy.c index b9221405..212b5c3a 100644 --- a/window-copy.c +++ b/window-copy.c @@ -548,13 +548,13 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key) break; case MODEKEYCOPY_NEXTWORD: word_separators = - options_get_string(&wp->window->options, "word-separators"); + options_get_string(&sess->options, "word-separators"); for (; np != 0; np--) window_copy_cursor_next_word(wp, word_separators); break; case MODEKEYCOPY_NEXTWORDEND: word_separators = - options_get_string(&wp->window->options, "word-separators"); + options_get_string(&sess->options, "word-separators"); for (; np != 0; np--) window_copy_cursor_next_word_end(wp, word_separators); break; @@ -564,7 +564,7 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key) break; case MODEKEYCOPY_PREVIOUSWORD: word_separators = - options_get_string(&wp->window->options, "word-separators"); + options_get_string(&sess->options, "word-separators"); for (; np != 0; np--) window_copy_cursor_previous_word(wp, word_separators); break; From fc5f8804ec92389fcc9f3aab1fa0c7777e3f0a56 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 15 Nov 2011 23:34:12 +0000 Subject: [PATCH 0981/1180] Add word movement and editing command for command prompt editing, from Ben Boeckel. --- mode-key.c | 23 ++++++++---- status.c | 101 +++++++++++++++++++++++++++++++++++++++++++++++++++-- tmux.h | 4 +++ 3 files changed, 119 insertions(+), 9 deletions(-) diff --git a/mode-key.c b/mode-key.c index 960971ff..f15bbe12 100644 --- a/mode-key.c +++ b/mode-key.c @@ -49,11 +49,15 @@ const struct mode_key_cmdstr mode_key_cmdstr_edit[] = { { MODEKEYEDIT_DELETE, "delete" }, { MODEKEYEDIT_DELETELINE, "delete-line" }, { MODEKEYEDIT_DELETETOENDOFLINE, "delete-end-of-line" }, + { MODEKEYEDIT_DELETEWORD, "delete-word" }, { MODEKEYEDIT_ENDOFLINE, "end-of-line" }, { MODEKEYEDIT_ENTER, "enter" }, { MODEKEYEDIT_HISTORYDOWN, "history-down" }, { MODEKEYEDIT_HISTORYUP, "history-up" }, + { MODEKEYEDIT_NEXTWORD, "next-word" }, + { MODEKEYEDIT_NEXTWORDEND, "next-word-end" }, { MODEKEYEDIT_PASTE, "paste" }, + { MODEKEYEDIT_PREVIOUSWORD, "previous-word" }, { MODEKEYEDIT_STARTOFLINE, "start-of-line" }, { MODEKEYEDIT_SWITCHMODE, "switch-mode" }, { MODEKEYEDIT_SWITCHMODEAPPEND, "switch-mode-append" }, @@ -127,7 +131,8 @@ const struct mode_key_entry mode_key_vi_edit[] = { { '\003' /* C-c */, 0, MODEKEYEDIT_CANCEL }, { '\010' /* C-h */, 0, MODEKEYEDIT_BACKSPACE }, { '\011' /* Tab */, 0, MODEKEYEDIT_COMPLETE }, - { '\025' /* C-u */, 0, MODEKEYEDIT_DELETELINE }, + { '\025' /* C-u */, 0, MODEKEYEDIT_DELETELINE }, + { '\027' /* C-w */, 0, MODEKEYEDIT_DELETEWORD }, { '\033' /* Escape */, 0, MODEKEYEDIT_SWITCHMODE }, { '\r', 0, MODEKEYEDIT_ENTER }, { KEYC_BSPACE, 0, MODEKEYEDIT_BACKSPACE }, @@ -145,13 +150,16 @@ const struct mode_key_entry mode_key_vi_edit[] = { { '\r', 1, MODEKEYEDIT_ENTER }, { '^', 1, MODEKEYEDIT_STARTOFLINE }, { 'a', 1, MODEKEYEDIT_SWITCHMODEAPPEND }, + { 'b', 1, MODEKEYEDIT_PREVIOUSWORD }, { 'd', 1, MODEKEYEDIT_DELETELINE }, + { 'e', 1, MODEKEYEDIT_NEXTWORDEND }, { 'h', 1, MODEKEYEDIT_CURSORLEFT }, { 'i', 1, MODEKEYEDIT_SWITCHMODE }, { 'j', 1, MODEKEYEDIT_HISTORYDOWN }, { 'k', 1, MODEKEYEDIT_HISTORYUP }, { 'l', 1, MODEKEYEDIT_CURSORRIGHT }, { 'p', 1, MODEKEYEDIT_PASTE }, + { 'w', 1, MODEKEYEDIT_NEXTWORD }, { KEYC_BSPACE, 1, MODEKEYEDIT_BACKSPACE }, { KEYC_DC, 1, MODEKEYEDIT_DELETE }, { KEYC_DOWN, 1, MODEKEYEDIT_HISTORYDOWN }, @@ -259,18 +267,21 @@ const struct mode_key_entry mode_key_emacs_edit[] = { { '\002' /* C-b */, 0, MODEKEYEDIT_CURSORLEFT }, { '\003' /* C-c */, 0, MODEKEYEDIT_CANCEL }, { '\004' /* C-d */, 0, MODEKEYEDIT_DELETE }, - { '\005' /* C-e */, 0, MODEKEYEDIT_ENDOFLINE }, + { '\005' /* C-e */, 0, MODEKEYEDIT_ENDOFLINE }, { '\006' /* C-f */, 0, MODEKEYEDIT_CURSORRIGHT }, - { '\010' /* C-H */, 0, MODEKEYEDIT_BACKSPACE }, - { '\011' /* Tab */, 0, MODEKEYEDIT_COMPLETE }, - { '\013' /* C-k */, 0, MODEKEYEDIT_DELETETOENDOFLINE }, + { '\010' /* C-H */, 0, MODEKEYEDIT_BACKSPACE }, + { '\011' /* Tab */, 0, MODEKEYEDIT_COMPLETE }, + { '\013' /* C-k */, 0, MODEKEYEDIT_DELETETOENDOFLINE }, { '\016' /* C-n */, 0, MODEKEYEDIT_HISTORYDOWN }, { '\020' /* C-p */, 0, MODEKEYEDIT_HISTORYUP }, { '\024' /* C-t */, 0, MODEKEYEDIT_TRANSPOSECHARS }, - { '\025' /* C-u */, 0, MODEKEYEDIT_DELETELINE }, + { '\025' /* C-u */, 0, MODEKEYEDIT_DELETELINE }, + { '\027' /* C-w */, 0, MODEKEYEDIT_DELETEWORD }, { '\031' /* C-y */, 0, MODEKEYEDIT_PASTE }, { '\033' /* Escape */, 0, MODEKEYEDIT_CANCEL }, { '\r', 0, MODEKEYEDIT_ENTER }, + { 'b' | KEYC_ESCAPE, 0, MODEKEYEDIT_PREVIOUSWORD }, + { 'f' | KEYC_ESCAPE, 0, MODEKEYEDIT_NEXTWORDEND }, { 'm' | KEYC_ESCAPE, 0, MODEKEYEDIT_STARTOFLINE }, { KEYC_BSPACE, 0, MODEKEYEDIT_BACKSPACE }, { KEYC_DC, 0, MODEKEYEDIT_DELETE }, diff --git a/status.c b/status.c index 487d3f56..631597da 100644 --- a/status.c +++ b/status.c @@ -973,9 +973,12 @@ status_prompt_redraw(struct client *c) void status_prompt_key(struct client *c, int key) { + struct session *sess = c->session; + struct options *oo = &sess->options; struct paste_buffer *pb; - char *s, *first, *last, word[64], swapc; - const char *histstr; + char *s, *first, *last, word[64], swapc; + const char *histstr; + const char *wsep; u_char ch; size_t size, n, off, idx; @@ -1092,11 +1095,103 @@ status_prompt_key(struct client *c, int key) c->flags |= CLIENT_STATUS; } break; + case MODEKEYEDIT_DELETEWORD: + wsep = options_get_string(oo, "word-separators"); + idx = c->prompt_index; + + /* Find a non-separator. */ + while (idx != 0) { + idx--; + if (!strchr(wsep, c->prompt_buffer[idx])) + break; + } + + /* Find the separator at the beginning of the word. */ + while (idx != 0) { + idx--; + if (strchr(wsep, c->prompt_buffer[idx])) { + /* Go back to the word. */ + idx++; + break; + } + } + + memmove(c->prompt_buffer + idx, + c->prompt_buffer + c->prompt_index, + size + 1 - c->prompt_index); + memset(c->prompt_buffer + size - (c->prompt_index - idx), + '\0', c->prompt_index - idx); + c->prompt_index = idx; + c->flags |= CLIENT_STATUS; + break; + case MODEKEYEDIT_NEXTWORD: + wsep = options_get_string(oo, "word-separators"); + + /* Find a separator. */ + while (c->prompt_index != size) { + c->prompt_index++; + if (strchr(wsep, c->prompt_buffer[c->prompt_index])) + break; + } + + /* Find the word right after the separation. */ + while (c->prompt_index != size) { + c->prompt_index++; + if (!strchr(wsep, c->prompt_buffer[c->prompt_index])) + break; + } + + c->flags |= CLIENT_STATUS; + break; + case MODEKEYEDIT_NEXTWORDEND: + wsep = options_get_string(oo, "word-separators"); + + /* Find a word. */ + while (c->prompt_index != size) { + c->prompt_index++; + if (!strchr(wsep, c->prompt_buffer[c->prompt_index])) + break; + } + + /* Find the separator at the end of the word. */ + while (c->prompt_index != size) { + c->prompt_index++; + if (strchr(wsep, c->prompt_buffer[c->prompt_index])) { + /* Go back to the word. */ + c->prompt_index--; + break; + } + } + + c->flags |= CLIENT_STATUS; + break; + case MODEKEYEDIT_PREVIOUSWORD: + wsep = options_get_string(oo, "word-separators"); + + /* Find a non-separator. */ + while (c->prompt_index != 0) { + c->prompt_index--; + if (!strchr(wsep, c->prompt_buffer[c->prompt_index])) + break; + } + + /* Find the separator at the beginning of the word. */ + while (c->prompt_index != 0) { + c->prompt_index--; + if (strchr(wsep, c->prompt_buffer[c->prompt_index])) { + /* Go back to the word. */ + c->prompt_index++; + break; + } + } + + c->flags |= CLIENT_STATUS; + break; case MODEKEYEDIT_HISTORYUP: histstr = status_prompt_up_history(&c->prompt_hindex); if (histstr == NULL) break; - xfree(c->prompt_buffer); + xfree(c->prompt_buffer); c->prompt_buffer = xstrdup(histstr); c->prompt_index = strlen(c->prompt_buffer); c->flags |= CLIENT_STATUS; diff --git a/tmux.h b/tmux.h index 74861abb..d5d79002 100644 --- a/tmux.h +++ b/tmux.h @@ -442,11 +442,15 @@ enum mode_key_cmd { MODEKEYEDIT_DELETE, MODEKEYEDIT_DELETELINE, MODEKEYEDIT_DELETETOENDOFLINE, + MODEKEYEDIT_DELETEWORD, MODEKEYEDIT_ENDOFLINE, MODEKEYEDIT_ENTER, MODEKEYEDIT_HISTORYDOWN, MODEKEYEDIT_HISTORYUP, + MODEKEYEDIT_NEXTWORD, + MODEKEYEDIT_NEXTWORDEND, MODEKEYEDIT_PASTE, + MODEKEYEDIT_PREVIOUSWORD, MODEKEYEDIT_STARTOFLINE, MODEKEYEDIT_SWITCHMODE, MODEKEYEDIT_SWITCHMODEAPPEND, From 2397083f7e9dd219f45c370d662b3c44a0799456 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 1 Dec 2011 20:42:31 +0000 Subject: [PATCH 0982/1180] Make M-f and M-b work the same at the command prompt as in copy mode, pointed out by Romain Francoise. --- status.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/status.c b/status.c index 631597da..ebfde9ef 100644 --- a/status.c +++ b/status.c @@ -1156,11 +1156,8 @@ status_prompt_key(struct client *c, int key) /* Find the separator at the end of the word. */ while (c->prompt_index != size) { c->prompt_index++; - if (strchr(wsep, c->prompt_buffer[c->prompt_index])) { - /* Go back to the word. */ - c->prompt_index--; + if (strchr(wsep, c->prompt_buffer[c->prompt_index])) break; - } } c->flags |= CLIENT_STATUS; From 31f13e49d8534c893590e0a1e1fbcae1adf03d02 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 1 Dec 2011 20:44:12 +0000 Subject: [PATCH 0983/1180] Add home and end keys for command prompt, from Matthias Lederhofer. --- mode-key.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mode-key.c b/mode-key.c index f15bbe12..95b4c232 100644 --- a/mode-key.c +++ b/mode-key.c @@ -141,6 +141,8 @@ const struct mode_key_entry mode_key_vi_edit[] = { { KEYC_LEFT, 0, MODEKEYEDIT_CURSORLEFT }, { KEYC_RIGHT, 0, MODEKEYEDIT_CURSORRIGHT }, { KEYC_UP, 0, MODEKEYEDIT_HISTORYUP }, + { KEYC_HOME, 0, MODEKEYEDIT_STARTOFLINE }, + { KEYC_END, 0, MODEKEYEDIT_ENDOFLINE }, { '$', 1, MODEKEYEDIT_ENDOFLINE }, { '0', 1, MODEKEYEDIT_STARTOFLINE }, @@ -289,6 +291,8 @@ const struct mode_key_entry mode_key_emacs_edit[] = { { KEYC_LEFT, 0, MODEKEYEDIT_CURSORLEFT }, { KEYC_RIGHT, 0, MODEKEYEDIT_CURSORRIGHT }, { KEYC_UP, 0, MODEKEYEDIT_HISTORYUP }, + { KEYC_HOME, 0, MODEKEYEDIT_STARTOFLINE }, + { KEYC_END, 0, MODEKEYEDIT_ENDOFLINE }, { 0, -1, 0 } }; From c44d2d854fb2d7ed305b14d9a57b1da1c45e425c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 1 Dec 2011 23:47:08 +0000 Subject: [PATCH 0984/1180] Log terminal overrides. --- tty-term.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tty-term.c b/tty-term.c index 201d0e1d..5338d0d9 100644 --- a/tty-term.c +++ b/tty-term.c @@ -263,6 +263,8 @@ tty_term_override(struct tty_term *term, const char *overrides) } else val = xstrdup(""); + log_debug("%s override: %s %s", + term->name, entstr, removeflag ? "@" : val); for (i = 0; i < NTTYCODE; i++) { ent = &tty_term_codes[i]; if (strcmp(entstr, ent->name) != 0) From e04d13f6a6591351b1184e7801604137f6a72b1d Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 4 Dec 2011 16:18:01 +0000 Subject: [PATCH 0985/1180] Support "jump to" like vi in copy mode using t and T keys. Also add x and X for delete in edit mode. From Ben Boeckel, thanks. --- mode-key.c | 8 ++++ tmux.1 | 2 + tmux.h | 2 + window-copy.c | 102 ++++++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 111 insertions(+), 3 deletions(-) diff --git a/mode-key.c b/mode-key.c index 95b4c232..de5664c7 100644 --- a/mode-key.c +++ b/mode-key.c @@ -98,6 +98,8 @@ const struct mode_key_cmdstr mode_key_cmdstr_copy[] = { { MODEKEYCOPY_JUMPAGAIN, "jump-again" }, { MODEKEYCOPY_JUMPREVERSE, "jump-reverse" }, { MODEKEYCOPY_JUMPBACK, "jump-backward" }, + { MODEKEYCOPY_JUMPTO, "jump-to-forward" }, + { MODEKEYCOPY_JUMPTOBACK, "jump-to-backward" }, { MODEKEYCOPY_LEFT, "cursor-left" }, { MODEKEYCOPY_RECTANGLETOGGLE, "rectangle-toggle" }, { MODEKEYCOPY_MIDDLELINE, "middle-line" }, @@ -147,6 +149,7 @@ const struct mode_key_entry mode_key_vi_edit[] = { { '$', 1, MODEKEYEDIT_ENDOFLINE }, { '0', 1, MODEKEYEDIT_STARTOFLINE }, { 'D', 1, MODEKEYEDIT_DELETETOENDOFLINE }, + { 'X', 1, MODEKEYEDIT_BACKSPACE }, { '\003' /* C-c */, 1, MODEKEYEDIT_CANCEL }, { '\010' /* C-h */, 1, MODEKEYEDIT_BACKSPACE }, { '\r', 1, MODEKEYEDIT_ENTER }, @@ -162,6 +165,7 @@ const struct mode_key_entry mode_key_vi_edit[] = { { 'l', 1, MODEKEYEDIT_CURSORRIGHT }, { 'p', 1, MODEKEYEDIT_PASTE }, { 'w', 1, MODEKEYEDIT_NEXTWORD }, + { 'x', 1, MODEKEYEDIT_DELETE }, { KEYC_BSPACE, 1, MODEKEYEDIT_BACKSPACE }, { KEYC_DC, 1, MODEKEYEDIT_DELETE }, { KEYC_DOWN, 1, MODEKEYEDIT_HISTORYDOWN }, @@ -225,6 +229,7 @@ const struct mode_key_entry mode_key_vi_copy[] = { { 'L', 0, MODEKEYCOPY_BOTTOMLINE }, { 'M', 0, MODEKEYCOPY_MIDDLELINE }, { 'N', 0, MODEKEYCOPY_SEARCHREVERSE }, + { 'T', 0, MODEKEYCOPY_JUMPTOBACK }, { 'W', 0, MODEKEYCOPY_NEXTSPACE }, { '\002' /* C-b */, 0, MODEKEYCOPY_PREVIOUSPAGE }, { '\003' /* C-c */, 0, MODEKEYCOPY_CANCEL }, @@ -246,6 +251,7 @@ const struct mode_key_entry mode_key_vi_copy[] = { { 'k', 0, MODEKEYCOPY_UP }, { 'l', 0, MODEKEYCOPY_RIGHT }, { 'n', 0, MODEKEYCOPY_SEARCHAGAIN }, + { 't', 0, MODEKEYCOPY_JUMPTO }, { 'q', 0, MODEKEYCOPY_CANCEL }, { 'v', 0, MODEKEYCOPY_RECTANGLETOGGLE }, { 'w', 0, MODEKEYCOPY_NEXTWORD }, @@ -339,6 +345,7 @@ const struct mode_key_entry mode_key_emacs_copy[] = { { 'N', 0, MODEKEYCOPY_SEARCHREVERSE }, { 'R' | KEYC_ESCAPE, 0, MODEKEYCOPY_TOPLINE }, { 'R', 0, MODEKEYCOPY_RECTANGLETOGGLE }, + { 'T', 0, MODEKEYCOPY_JUMPTOBACK }, { '\000' /* C-Space */, 0, MODEKEYCOPY_STARTSELECTION }, { '\001' /* C-a */, 0, MODEKEYCOPY_STARTOFLINE }, { '\002' /* C-b */, 0, MODEKEYCOPY_LEFT }, @@ -363,6 +370,7 @@ const struct mode_key_entry mode_key_emacs_copy[] = { { 'n', 0, MODEKEYCOPY_SEARCHAGAIN }, { 'q', 0, MODEKEYCOPY_CANCEL }, { 'r' | KEYC_ESCAPE, 0, MODEKEYCOPY_MIDDLELINE }, + { 't', 0, MODEKEYCOPY_JUMPTO }, { 'v' | KEYC_ESCAPE, 0, MODEKEYCOPY_PREVIOUSPAGE }, { 'w' | KEYC_ESCAPE, 0, MODEKEYCOPY_COPYSELECTION }, { KEYC_DOWN | KEYC_CTRL,0, MODEKEYCOPY_SCROLLDOWN }, diff --git a/tmux.1 b/tmux.1 index 5e5fd751..29a2a92d 100644 --- a/tmux.1 +++ b/tmux.1 @@ -803,7 +803,9 @@ The following keys are supported as appropriate for the mode: .It Li "Half page down" Ta "C-d" Ta "M-Down" .It Li "Half page up" Ta "C-u" Ta "M-Up" .It Li "Jump forward" Ta "f" Ta "f" +.It Li "Jump to forward" Ta "t" Ta "" .It Li "Jump backward" Ta "F" Ta "F" +.It Li "Jump to backward" Ta "T" Ta "" .It Li "Jump again" Ta ";" Ta ";" .It Li "Jump again in reverse" Ta "," Ta "," .It Li "Next page" Ta "C-f" Ta "Page down" diff --git a/tmux.h b/tmux.h index d5d79002..83b07ba7 100644 --- a/tmux.h +++ b/tmux.h @@ -485,6 +485,8 @@ enum mode_key_cmd { MODEKEYCOPY_JUMPAGAIN, MODEKEYCOPY_JUMPREVERSE, MODEKEYCOPY_JUMPBACK, + MODEKEYCOPY_JUMPTO, + MODEKEYCOPY_JUMPTOBACK, MODEKEYCOPY_LEFT, MODEKEYCOPY_MIDDLELINE, MODEKEYCOPY_NEXTPAGE, diff --git a/window-copy.c b/window-copy.c index 212b5c3a..3ba11f2a 100644 --- a/window-copy.c +++ b/window-copy.c @@ -67,6 +67,8 @@ void window_copy_cursor_up(struct window_pane *, int); void window_copy_cursor_down(struct window_pane *, int); void window_copy_cursor_jump(struct window_pane *); void window_copy_cursor_jump_back(struct window_pane *); +void window_copy_cursor_jump_to(struct window_pane *); +void window_copy_cursor_jump_to_back(struct window_pane *); void window_copy_cursor_next_word(struct window_pane *, const char *); void window_copy_cursor_next_word_end(struct window_pane *, const char *); void window_copy_cursor_previous_word(struct window_pane *, const char *); @@ -90,6 +92,8 @@ enum window_copy_input_type { WINDOW_COPY_SEARCHDOWN, WINDOW_COPY_JUMPFORWARD, WINDOW_COPY_JUMPBACK, + WINDOW_COPY_JUMPTOFORWARD, + WINDOW_COPY_JUMPTOBACK, WINDOW_COPY_GOTOLINE, }; @@ -132,7 +136,7 @@ struct window_copy_mode_data { enum window_copy_input_type inputtype; const char *inputprompt; - char *inputstr; + char *inputstr; int numprefix; @@ -367,16 +371,24 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key) np = 1; if (data->inputtype == WINDOW_COPY_JUMPFORWARD || - data->inputtype == WINDOW_COPY_JUMPBACK) { + data->inputtype == WINDOW_COPY_JUMPBACK || + data->inputtype == WINDOW_COPY_JUMPTOFORWARD || + data->inputtype == WINDOW_COPY_JUMPTOBACK) { /* Ignore keys with modifiers. */ if ((key & KEYC_MASK_MOD) == 0) { data->jumpchar = key; if (data->inputtype == WINDOW_COPY_JUMPFORWARD) { for (; np != 0; np--) window_copy_cursor_jump(wp); - } else { + } else if (data->inputtype == WINDOW_COPY_JUMPBACK) { for (; np != 0; np--) window_copy_cursor_jump_back(wp); + } else if (data->inputtype == WINDOW_COPY_JUMPTOFORWARD) { + for (; np != 0; np--) + window_copy_cursor_jump_to(wp); + } else if (data->inputtype == WINDOW_COPY_JUMPTOBACK) { + for (; np != 0; np--) + window_copy_cursor_jump_to_back(wp); } } data->jumptype = data->inputtype; @@ -581,6 +593,12 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key) } else if (data->jumptype == WINDOW_COPY_JUMPBACK) { for (; np != 0; np--) window_copy_cursor_jump_back(wp); + } else if (data->jumptype == WINDOW_COPY_JUMPTOFORWARD) { + for (; np != 0; np--) + window_copy_cursor_jump_to(wp); + } else if (data->jumptype == WINDOW_COPY_JUMPTOBACK) { + for (; np != 0; np--) + window_copy_cursor_jump_to_back(wp); } break; case MODEKEYCOPY_JUMPREVERSE: @@ -590,6 +608,12 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key) } else if (data->jumptype == WINDOW_COPY_JUMPBACK) { for (; np != 0; np--) window_copy_cursor_jump(wp); + } else if (data->jumptype == WINDOW_COPY_JUMPTOFORWARD) { + for (; np != 0; np--) + window_copy_cursor_jump_to_back(wp); + } else if (data->jumptype == WINDOW_COPY_JUMPTOBACK) { + for (; np != 0; np--) + window_copy_cursor_jump_to(wp); } break; case MODEKEYCOPY_JUMPBACK: @@ -598,6 +622,18 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key) *data->inputstr = '\0'; window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1); return; /* skip numprefix reset */ + case MODEKEYCOPY_JUMPTO: + data->inputtype = WINDOW_COPY_JUMPTOFORWARD; + data->inputprompt = "Jump To"; + *data->inputstr = '\0'; + window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1); + return; /* skip numprefix reset */ + case MODEKEYCOPY_JUMPTOBACK: + data->inputtype = WINDOW_COPY_JUMPTOBACK; + data->inputprompt = "Jump To Back"; + *data->inputstr = '\0'; + window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1); + return; /* skip numprefix reset */ case MODEKEYCOPY_SEARCHUP: data->inputtype = WINDOW_COPY_SEARCHUP; data->inputprompt = "Search Up"; @@ -613,6 +649,8 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key) case WINDOW_COPY_GOTOLINE: case WINDOW_COPY_JUMPFORWARD: case WINDOW_COPY_JUMPBACK: + case WINDOW_COPY_JUMPTOFORWARD: + case WINDOW_COPY_JUMPTOBACK: case WINDOW_COPY_NUMERICPREFIX: break; case WINDOW_COPY_SEARCHUP: @@ -719,6 +757,8 @@ window_copy_key_input(struct window_pane *wp, int key) case WINDOW_COPY_OFF: case WINDOW_COPY_JUMPFORWARD: case WINDOW_COPY_JUMPBACK: + case WINDOW_COPY_JUMPTOFORWARD: + case WINDOW_COPY_JUMPTOBACK: case WINDOW_COPY_NUMERICPREFIX: break; case WINDOW_COPY_SEARCHUP: @@ -1712,6 +1752,62 @@ window_copy_cursor_jump_back(struct window_pane *wp) } } +void +window_copy_cursor_jump_to(struct window_pane *wp) +{ + struct window_copy_mode_data *data = wp->modedata; + struct screen *back_s = data->backing; + const struct grid_cell *gc; + u_int px, py, xx; + + px = data->cx + 1; + py = screen_hsize(back_s) + data->cy - data->oy; + xx = window_copy_find_length(wp, py); + + while (px < xx) { + gc = grid_peek_cell(back_s->grid, px, py); + if ((gc->flags & (GRID_FLAG_PADDING|GRID_FLAG_UTF8)) == 0 + && gc->data == data->jumpchar) { + + window_copy_update_cursor(wp, px - 1, data->cy); + if (window_copy_update_selection(wp)) + window_copy_redraw_lines(wp, data->cy, 1); + return; + } + px++; + } +} + +void +window_copy_cursor_jump_to_back(struct window_pane *wp) +{ + struct window_copy_mode_data *data = wp->modedata; + struct screen *back_s = data->backing; + const struct grid_cell *gc; + u_int px, py; + + px = data->cx; + py = screen_hsize(back_s) + data->cy - data->oy; + + if (px > 0) + px--; + + for (;;) { + gc = grid_peek_cell(back_s->grid, px, py); + if ((gc->flags & (GRID_FLAG_PADDING|GRID_FLAG_UTF8)) == 0 + && gc->data == data->jumpchar) { + + window_copy_update_cursor(wp, px + 1, data->cy); + if (window_copy_update_selection(wp)) + window_copy_redraw_lines(wp, data->cy, 1); + return; + } + if (px == 0) + break; + px--; + } +} + void window_copy_cursor_next_word(struct window_pane *wp, const char *separators) { From f308ba93aae9de462b1b46e68b47bd77a843eed6 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 9 Dec 2011 16:28:18 +0000 Subject: [PATCH 0986/1180] Change the way the working directory for new processes is discovered. If default-path isn't empty, it is used. Otherwise: 1) If tmux neww is run from the command line, the working directory of the client is used. 2) Otherwise sysctl KERN_PROC_CWD is used to retrieve the current working directory of the process in the active pane. 3) If that fails, the directory where the session was created is used. Support code by Romain Francois, OpenBSD specific bits by me. Note this requires a recent userland and kernel with KERN_PROC_CWD. --- cmd-new-window.c | 8 +------- cmd-split-window.c | 8 +------- cmd.c | 25 +++++++++++++++++++++++++ procname.c | 15 ++++++++++++++- tmux.1 | 8 ++++---- tmux.h | 2 ++ 6 files changed, 47 insertions(+), 19 deletions(-) diff --git a/cmd-new-window.c b/cmd-new-window.c index 955f6449..cdf45006 100644 --- a/cmd-new-window.c +++ b/cmd-new-window.c @@ -98,13 +98,7 @@ cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx) cmd = options_get_string(&s->options, "default-command"); else cmd = args->argv[0]; - cwd = options_get_string(&s->options, "default-path"); - if (*cwd == '\0') { - if (ctx->cmdclient != NULL && ctx->cmdclient->cwd != NULL) - cwd = ctx->cmdclient->cwd; - else - cwd = s->cwd; - } + cwd = cmd_get_default_path(ctx); if (idx == -1) idx = -1 - options_get_number(&s->options, "base-index"); diff --git a/cmd-split-window.c b/cmd-split-window.c index b1b738b1..7184d964 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -78,13 +78,7 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) cmd = options_get_string(&s->options, "default-command"); else cmd = args->argv[0]; - cwd = options_get_string(&s->options, "default-path"); - if (*cwd == '\0') { - if (ctx->cmdclient != NULL && ctx->cmdclient->cwd != NULL) - cwd = ctx->cmdclient->cwd; - else - cwd = s->cwd; - } + cwd = cmd_get_default_path(ctx); type = LAYOUT_TOPBOTTOM; if (args_has(args, 'h')) diff --git a/cmd.c b/cmd.c index db72337d..6a87f90f 100644 --- a/cmd.c +++ b/cmd.c @@ -1213,3 +1213,28 @@ cmd_template_replace(char *template, const char *s, int idx) return (buf); } + +/* Return the default path for a new pane. */ +char * +cmd_get_default_path(struct cmd_ctx *ctx) +{ + char *cwd; + struct session *s; + struct window_pane *wp; + + if ((s = cmd_current_session(ctx, 0)) == NULL) + return (NULL); + + cwd = options_get_string(&s->options, "default-path"); + if (*cwd == '\0') { + if (ctx->cmdclient != NULL && ctx->cmdclient->cwd != NULL) + return (ctx->cmdclient->cwd); + if (ctx->curclient != NULL) { + wp = s->curw->window->active; + if ((cwd = get_proc_cwd(wp->pid)) != NULL) + return (cwd); + } + return (s->cwd); + } + return (cwd); +} diff --git a/procname.c b/procname.c index 30f71847..370fe342 100644 --- a/procname.c +++ b/procname.c @@ -35,7 +35,8 @@ ((p)->p_stat == SSTOP || (p)->p_stat == SZOMB || (p)->p_stat == SDEAD) struct kinfo_proc *cmp_procs(struct kinfo_proc *, struct kinfo_proc *); -char *get_proc_name(int, char *); +char *get_proc_name(int, char *); +char *get_proc_cwd(pid_t); struct kinfo_proc * cmp_procs(struct kinfo_proc *p1, struct kinfo_proc *p2) @@ -130,3 +131,15 @@ error: free(buf); return (NULL); } + +char* +get_proc_cwd(pid_t pid) +{ + int name[] = { CTL_KERN, KERN_PROC_CWD, (int)pid }; + static char path[MAXPATHLEN]; + size_t pathlen = sizeof path; + + if (sysctl(name, 3, path, &pathlen, NULL, 0) != 0) + return (NULL); + return (path); +} diff --git a/tmux.1 b/tmux.1 index 29a2a92d..4c09de68 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1841,10 +1841,10 @@ to create a login shell using the value of the .Ic default-shell option. .It Ic default-path Ar path -Set the default working directory for processes created from keys, or -interactively from the prompt. -The default is empty, which means to use the working directory of the shell -from which the server was started if it is available or the user's home if not. +Set the default working directory for new panes. +If empty (the default), the working directory is determined from the process +running in the active pane, from the command line environment or from the +working directory where the session was created. .It Ic default-shell Ar path Specify the default shell. This is used as the login shell for new windows when the diff --git a/tmux.h b/tmux.h index 83b07ba7..45e41888 100644 --- a/tmux.h +++ b/tmux.h @@ -1562,6 +1562,7 @@ int cmd_find_index( struct winlink *cmd_find_pane(struct cmd_ctx *, const char *, struct session **, struct window_pane **); char *cmd_template_replace(char *, const char *, int); +char *cmd_get_default_path(struct cmd_ctx *ctx); 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; @@ -2079,6 +2080,7 @@ u_int utf8_split2(u_int, u_char *); /* procname.c */ char *get_proc_name(int, char *); +char *get_proc_cwd(pid_t); /* log.c */ void log_open_tty(int); From d655566ce728c3d2396d174947b5067a79e79e73 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 24 Dec 2011 08:26:59 +0000 Subject: [PATCH 0987/1180] Fix so that when mouse-select-pane and mouse-select-window are both enabled, clicking on the status line does not change the current pane. From Romain Francoise. --- server-client.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/server-client.c b/server-client.c index cf2a4c54..1ea1da91 100644 --- a/server-client.c +++ b/server-client.c @@ -320,6 +320,8 @@ server_client_handle_key(int key, struct mouse_event *mouse, void *data) if (c->flags & CLIENT_READONLY) return; if (options_get_number(oo, "mouse-select-pane") && + (!(options_get_number(oo, "status") && + mouse->y + 1 == c->tty.sy)) && ((!(mouse->b & MOUSE_DRAG) && mouse->b != MOUSE_UP) || wp->mode != &window_copy_mode)) { /* From da145e7c2068e1729a7e3c2c191c504fc416ca57 Mon Sep 17 00:00:00 2001 From: Jason McIntyre Date: Sat, 24 Dec 2011 08:46:48 +0000 Subject: [PATCH 0988/1180] formatting errors, found using freebsd's "igor"; --- tmux.1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tmux.1 b/tmux.1 index 4c09de68..70900014 100644 --- a/tmux.1 +++ b/tmux.1 @@ -589,7 +589,7 @@ session. .D1 (alias: Ic detach ) Detach the current client if bound to a key, the client specified with .Fl t , -or all clients currently attached to to the session specified by +or all clients currently attached to the session specified by .Fl s . If .Fl P From d71e4b9aca9c2c07832b9f12f63360a4b84a973a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 27 Dec 2011 13:41:50 +0000 Subject: [PATCH 0989/1180] Reset flags on every loop or it is displayed too often, from Chris Johnsen. --- cmd-list-keys.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd-list-keys.c b/cmd-list-keys.c index 6e359e5b..73ecf458 100644 --- a/cmd-list-keys.c +++ b/cmd-list-keys.c @@ -54,7 +54,6 @@ cmd_list_keys_exec(struct cmd *self, struct cmd_ctx *ctx) return (cmd_list_keys_table(self, ctx)); width = 0; - *flags = '\0'; SPLAY_FOREACH(bd, key_bindings, &key_bindings) { key = key_string_lookup_key(bd->key & ~KEYC_PREFIX); @@ -78,6 +77,7 @@ cmd_list_keys_exec(struct cmd *self, struct cmd_ctx *ctx) if (key == NULL) continue; + *flags = '\0'; if (!(bd->key & KEYC_PREFIX)) { if (bd->can_repeat) xsnprintf(flags, sizeof flags, "-rn "); From 5db593e5c2dc9ccfb279d0855dd92cc9923ffbed Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 27 Dec 2011 13:46:26 +0000 Subject: [PATCH 0990/1180] Extend history that can be captured to INT_MIN rather than SHRT_MIN. From Chris Johnsen. --- cmd-capture-pane.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd-capture-pane.c b/cmd-capture-pane.c index 32c6007b..7c974f1f 100644 --- a/cmd-capture-pane.c +++ b/cmd-capture-pane.c @@ -59,7 +59,7 @@ cmd_capture_pane_exec(struct cmd *self, struct cmd_ctx *ctx) buf = NULL; len = 0; - n = args_strtonum(args, 'S', SHRT_MIN, SHRT_MAX, &cause); + n = args_strtonum(args, 'S', INT_MIN, SHRT_MAX, &cause); if (cause != NULL) { top = gd->hsize; xfree(cause); @@ -70,7 +70,7 @@ cmd_capture_pane_exec(struct cmd *self, struct cmd_ctx *ctx) if (top > gd->hsize + gd->sy - 1) top = gd->hsize + gd->sy - 1; - n = args_strtonum(args, 'E', SHRT_MIN, SHRT_MAX, &cause); + n = args_strtonum(args, 'E', INT_MIN, SHRT_MAX, &cause); if (cause != NULL) { bottom = gd->hsize + gd->sy - 1; xfree(cause); From d377a68593d354da327db9b15059f94f2306a7e4 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 27 Dec 2011 14:06:19 +0000 Subject: [PATCH 0991/1180] Add \033[s and \033[u to save and restore cursor position. --- input.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/input.c b/input.c index a914aa5a..ed1f8760 100644 --- a/input.c +++ b/input.c @@ -135,8 +135,10 @@ enum input_csi_type { INPUT_CSI_HPA, INPUT_CSI_ICH, INPUT_CSI_IL, + INPUT_CSI_RCP, INPUT_CSI_RM, INPUT_CSI_RM_PRIVATE, + INPUT_CSI_SCP, INPUT_CSI_SGR, INPUT_CSI_SM, INPUT_CSI_SM_PRIVATE, @@ -171,6 +173,8 @@ const struct input_table_entry input_csi_table[] = { { 'n', "", INPUT_CSI_DSR }, { 'q', " ", INPUT_CSI_DECSCUSR }, { 'r', "", INPUT_CSI_DECSTBM }, + { 's', "", INPUT_CSI_SCP }, + { 'u', "", INPUT_CSI_RCP }, }; /* Input transition. */ @@ -1168,6 +1172,10 @@ input_csi_dispatch(struct input_ctx *ictx) case INPUT_CSI_IL: screen_write_insertline(sctx, input_get(ictx, 0, 1, 1)); break; + case INPUT_CSI_RCP: + memcpy(&ictx->cell, &ictx->old_cell, sizeof ictx->cell); + screen_write_cursormove(sctx, ictx->old_cx, ictx->old_cy); + break; case INPUT_CSI_RM: switch (input_get(ictx, 0, 0, -1)) { case 4: /* IRM */ @@ -1207,6 +1215,11 @@ input_csi_dispatch(struct input_ctx *ictx) break; } break; + case INPUT_CSI_SCP: + memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell); + ictx->old_cx = s->cx; + ictx->old_cy = s->cy; + break; case INPUT_CSI_SGR: input_csi_dispatch_sgr(ictx); break; From fdd1d0b72e3aa178653ed8733d4efcb6b14b0c86 Mon Sep 17 00:00:00 2001 From: Stefan Sperling Date: Tue, 27 Dec 2011 14:07:20 +0000 Subject: [PATCH 0992/1180] Allow $HOME as default-path in tmux.conf so the same config file can be used on different machines regardless of where the user's home directory is. ok nicm --- cmd.c | 7 +++++++ tmux.1 | 5 +++++ 2 files changed, 12 insertions(+) diff --git a/cmd.c b/cmd.c index 6a87f90f..65617a6c 100644 --- a/cmd.c +++ b/cmd.c @@ -1221,11 +1221,18 @@ cmd_get_default_path(struct cmd_ctx *ctx) char *cwd; struct session *s; struct window_pane *wp; + struct environ_entry *envent; if ((s = cmd_current_session(ctx, 0)) == NULL) return (NULL); cwd = options_get_string(&s->options, "default-path"); + if ((cwd[0] == '~' && cwd[1] == '\0') || !strcmp(cwd, "$HOME")) { + envent = environ_find(&global_environ, "HOME"); + if (envent != NULL && *envent->value != '\0') + return envent->value; + cwd = ""; + } if (*cwd == '\0') { if (ctx->cmdclient != NULL && ctx->cmdclient->cwd != NULL) return (ctx->cmdclient->cwd); diff --git a/tmux.1 b/tmux.1 index 70900014..331a104f 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1845,6 +1845,11 @@ Set the default working directory for new panes. If empty (the default), the working directory is determined from the process running in the active pane, from the command line environment or from the working directory where the session was created. +If +.Ar path +is "$HOME" or "~", the value of the +.Ev HOME +environment variable is used. .It Ic default-shell Ar path Specify the default shell. This is used as the login shell for new windows when the From 92aef64c5a582cbd785e3d8ad0801153e129a5c7 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 29 Dec 2011 08:06:24 +0000 Subject: [PATCH 0993/1180] Add CNL and CPL escape sequences. --- input.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/input.c b/input.c index ed1f8760..b113bc2a 100644 --- a/input.c +++ b/input.c @@ -119,6 +119,8 @@ const struct input_table_entry input_esc_table[] = { /* Control (CSI) commands. */ enum input_csi_type { INPUT_CSI_CBT, + INPUT_CSI_CNL, + INPUT_CSI_CPL, INPUT_CSI_CUB, INPUT_CSI_CUD, INPUT_CSI_CUF, @@ -153,6 +155,8 @@ const struct input_table_entry input_csi_table[] = { { 'B', "", INPUT_CSI_CUD }, { 'C', "", INPUT_CSI_CUF }, { 'D', "", INPUT_CSI_CUB }, + { 'E', "", INPUT_CSI_CNL }, + { 'F', "", INPUT_CSI_CPL }, { 'G', "", INPUT_CSI_HPA }, { 'H', "", INPUT_CSI_CUP }, { 'J', "", INPUT_CSI_ED }, @@ -1085,6 +1089,14 @@ input_csi_dispatch(struct input_ctx *ictx) case INPUT_CSI_CUU: screen_write_cursorup(sctx, input_get(ictx, 0, 1, 1)); break; + case INPUT_CSI_CNL: + screen_write_carriagereturn(sctx); + screen_write_cursordown(sctx, input_get(ictx, 0, 1, 1)); + break; + case INPUT_CSI_CPL: + screen_write_carriagereturn(sctx); + screen_write_cursorup(sctx, input_get(ictx, 0, 1, 1)); + break; case INPUT_CSI_DA: switch (input_get(ictx, 0, 0, 0)) { case 0: From 16f96676205e3261f6b30dcf1c3ec99f739f727e Mon Sep 17 00:00:00 2001 From: Stuart Henderson Date: Fri, 30 Dec 2011 14:59:13 +0000 Subject: [PATCH 0994/1180] Show how to set default-path to revert to tmux's old behaviour of opening new windows in the current working directory at the time tmux was started, it's not obvious. naddy@ agrees this is a useful inclusion. --- tmux.1 | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tmux.1 b/tmux.1 index 331a104f..d1f2415a 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1850,6 +1850,11 @@ If is "$HOME" or "~", the value of the .Ev HOME environment variable is used. +If +.Ar path +is ".", the working directory when +.Nm +was started is used. .It Ic default-shell Ar path Specify the default shell. This is used as the login shell for new windows when the From eeaf92ad066927cd06569ceb5e100004c8bf99df Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 31 Dec 2011 03:40:15 +0000 Subject: [PATCH 0995/1180] Add a man page section on window names and pane titles, from Felix Rosencrantz. --- tmux.1 | 84 +++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 72 insertions(+), 12 deletions(-) diff --git a/tmux.1 b/tmux.1 index d1f2415a..d04d789c 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2054,7 +2054,14 @@ command to destroy it. .It Xo Ic set-titles .Op Ic on | off .Xc -Attempt to set the window title using the \ee]2;...\e007 xterm code if +Attempt to set the client terminal title using the +.Em tsl +and +.Em fsl +.Xr terminfo 5 +entries if they exist. +.Nm +automatically sets these to the \ee]2;...\e007 sequence if the terminal appears to be an xterm. This option is off by default. Note that elinks @@ -2120,7 +2127,7 @@ may contain any of the following special character sequences: .It Li "#I" Ta "Current window index" .It Li "#P" Ta "Current pane index" .It Li "#S" Ta "Session name" -.It Li "#T" Ta "Current window title" +.It Li "#T" Ta "Current pane title" .It Li "#W" Ta "Current window name" .It Li "##" Ta "A literal" Ql # .El @@ -2139,13 +2146,9 @@ global environment set (see the .Sx ENVIRONMENT section). .Pp -The window title (#T) is the title set by the program running within the window -using the OSC title setting sequence, for example: -.Bd -literal -offset indent -$ printf '\e033]2;My Title\e033\e\e' -.Ed -.Pp -When a window is first created, its title is the hostname. +For details on how the names and titles can be set see the +.Sx "NAMES AND TITLES" +section. .Pp #[attributes] allows a comma-separated list of attributes to be specified, these may be @@ -2369,7 +2372,8 @@ is specified at creation with or .Ic new-session , or later with -.Ic rename-window . +.Ic rename-window , +or with a terminal escape sequence. It may be switched off globally with: .Bd -literal -offset indent set-window-option -g automatic-rename off @@ -2664,6 +2668,62 @@ The following variables are available, where appropriate: .It Li "window_name" Ta "Name of window" .It Li "window_width" Ta "Width of window" .El +.Sh NAMES AND TITLES +.Nm +distinguishes between names and titles. +Windows and sessions have names, which may be used to specify them in targets +and are displayed in the status line and various lists: the name is the +.Nm +identifier for a window or session. +Only panes have titles. +A pane's title is typically set by the program running inside the pane and +is not modified by +.Nm . +It is the same mechanism used to set for example the +.Xr xterm 1 +window title in an +.Xr X 7 +window manager. +Windows themselves do not have titles - a window's title is the title of it's +active pane. +.Nm +itself may set the title of the terminal in which the client is running, see +the +.Ic set-titles +option. +.Pp +A session's name is set with the +.Ic new-session +and +.Ic rename-session +commands. +A window's name is set with one of: +.Bl -enum -width Ds +.It +A command argument (such as +.Fl n +for +.Ic new-window +or +.Ic new-session ) . +.It +An escape sequence: +.Bd -literal -offset indent +$ printf '\e033kWINDOW_NAME\e033\e\e' +.Ed +.It +Automatic renaming, which sets the name to the active command in the window's +active pane. +See the +.Ic automatic-rename +option. +.El +.Pp +When a pane is first created, its title is the hostname. +A pane's title can be set via the OSC title setting sequence, for example: +.Bd -literal -offset indent +$ printf '\e033]2;My Title\e033\e\e' +.Ed .Sh ENVIRONMENT When the server is started, .Nm @@ -2727,8 +2787,8 @@ terminal. By default, the status line is enabled (it may be disabled with the .Ic status session option) and contains, from left-to-right: the name of the current -session in square brackets; the window list; the current window title in double -quotes; and the time and date. +session in square brackets; the window list; the title of the active pane +in double quotes; and the time and date. .Pp The status line is made of three parts: configurable left and right sections (which may contain dynamic content such as the time or output from a shell From 299a8fd4a3ced13ed678f888aa1b61484a2b613d Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 15 Jan 2012 19:39:42 +0000 Subject: [PATCH 0996/1180] Calculate last position correctly for UTF-8 wide characters, reported by Matthias Lederhofer. --- tty.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tty.c b/tty.c index dce4887b..d5fc106e 100644 --- a/tty.c +++ b/tty.c @@ -969,7 +969,10 @@ tty_cmd_cell(struct tty *tty, const struct tty_ctx *ctx) * move as far left as possible and redraw the last * cell to move into the last position. */ - cx = screen_size_x(s) - width; + if (ctx->last_cell.flags & GRID_FLAG_UTF8) + cx = screen_size_x(s) - ctx->last_utf8.width; + else + cx = screen_size_x(s) - 1; tty_cursor_pane(tty, ctx, cx, ctx->ocy); tty_cell(tty, &ctx->last_cell, &ctx->last_utf8); } From e6519d3e279ba12d44633c3162dd183148aea9f0 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 20 Jan 2012 19:10:29 +0000 Subject: [PATCH 0997/1180] Add space movement keys for vi mode in the status line from Ben Boeckel. --- mode-key.c | 6 ++++++ status.c | 20 ++++++++++++++++---- tmux.h | 3 +++ 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/mode-key.c b/mode-key.c index de5664c7..6115d630 100644 --- a/mode-key.c +++ b/mode-key.c @@ -54,9 +54,12 @@ const struct mode_key_cmdstr mode_key_cmdstr_edit[] = { { MODEKEYEDIT_ENTER, "enter" }, { MODEKEYEDIT_HISTORYDOWN, "history-down" }, { MODEKEYEDIT_HISTORYUP, "history-up" }, + { MODEKEYEDIT_NEXTSPACE, "next-space" }, + { MODEKEYEDIT_NEXTSPACEEND, "next-space-end" }, { MODEKEYEDIT_NEXTWORD, "next-word" }, { MODEKEYEDIT_NEXTWORDEND, "next-word-end" }, { MODEKEYEDIT_PASTE, "paste" }, + { MODEKEYEDIT_PREVIOUSSPACE, "previous-space" }, { MODEKEYEDIT_PREVIOUSWORD, "previous-word" }, { MODEKEYEDIT_STARTOFLINE, "start-of-line" }, { MODEKEYEDIT_SWITCHMODE, "switch-mode" }, @@ -148,7 +151,10 @@ const struct mode_key_entry mode_key_vi_edit[] = { { '$', 1, MODEKEYEDIT_ENDOFLINE }, { '0', 1, MODEKEYEDIT_STARTOFLINE }, + { 'B', 1, MODEKEYEDIT_PREVIOUSSPACE }, { 'D', 1, MODEKEYEDIT_DELETETOENDOFLINE }, + { 'E', 1, MODEKEYEDIT_NEXTSPACEEND }, + { 'W', 1, MODEKEYEDIT_NEXTSPACE }, { 'X', 1, MODEKEYEDIT_BACKSPACE }, { '\003' /* C-c */, 1, MODEKEYEDIT_CANCEL }, { '\010' /* C-h */, 1, MODEKEYEDIT_BACKSPACE }, diff --git a/status.c b/status.c index ebfde9ef..041382fb 100644 --- a/status.c +++ b/status.c @@ -978,7 +978,7 @@ status_prompt_key(struct client *c, int key) struct paste_buffer *pb; char *s, *first, *last, word[64], swapc; const char *histstr; - const char *wsep; + const char *wsep = NULL; u_char ch; size_t size, n, off, idx; @@ -1124,8 +1124,12 @@ status_prompt_key(struct client *c, int key) c->prompt_index = idx; c->flags |= CLIENT_STATUS; break; + case MODEKEYEDIT_NEXTSPACE: + wsep = " "; + /* FALLTHROUGH */ case MODEKEYEDIT_NEXTWORD: - wsep = options_get_string(oo, "word-separators"); + if (wsep == NULL) + wsep = options_get_string(oo, "word-separators"); /* Find a separator. */ while (c->prompt_index != size) { @@ -1143,8 +1147,12 @@ status_prompt_key(struct client *c, int key) c->flags |= CLIENT_STATUS; break; + case MODEKEYEDIT_NEXTSPACEEND: + wsep = " "; + /* FALLTHROUGH */ case MODEKEYEDIT_NEXTWORDEND: - wsep = options_get_string(oo, "word-separators"); + if (wsep == NULL) + wsep = options_get_string(oo, "word-separators"); /* Find a word. */ while (c->prompt_index != size) { @@ -1162,8 +1170,12 @@ status_prompt_key(struct client *c, int key) c->flags |= CLIENT_STATUS; break; + case MODEKEYEDIT_PREVIOUSSPACE: + wsep = " "; + /* FALLTHROUGH */ case MODEKEYEDIT_PREVIOUSWORD: - wsep = options_get_string(oo, "word-separators"); + if (wsep == NULL) + wsep = options_get_string(oo, "word-separators"); /* Find a non-separator. */ while (c->prompt_index != 0) { diff --git a/tmux.h b/tmux.h index 45e41888..dbb28c7e 100644 --- a/tmux.h +++ b/tmux.h @@ -447,9 +447,12 @@ enum mode_key_cmd { MODEKEYEDIT_ENTER, MODEKEYEDIT_HISTORYDOWN, MODEKEYEDIT_HISTORYUP, + MODEKEYEDIT_NEXTSPACE, + MODEKEYEDIT_NEXTSPACEEND, MODEKEYEDIT_NEXTWORD, MODEKEYEDIT_NEXTWORDEND, MODEKEYEDIT_PASTE, + MODEKEYEDIT_PREVIOUSSPACE, MODEKEYEDIT_PREVIOUSWORD, MODEKEYEDIT_STARTOFLINE, MODEKEYEDIT_SWITCHMODE, From dcad13155b319e1ca2fafd3f0644e8efb15ac764 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 20 Jan 2012 19:15:40 +0000 Subject: [PATCH 0998/1180] Add an option to disable the window rename escape sequence, from Romain Francoise. --- input.c | 2 ++ options-table.c | 5 +++++ tmux.1 | 7 +++++++ 3 files changed, 14 insertions(+) diff --git a/input.c b/input.c index b113bc2a..6fd2d90a 100644 --- a/input.c +++ b/input.c @@ -1558,6 +1558,8 @@ input_exit_rename(struct input_ctx *ictx) { if (ictx->flags & INPUT_DISCARD) return; + if (!options_get_number(&ictx->wp->window->options, "allow-rename")) + return; log_debug("%s: \"%s\"", __func__, ictx->input_buf); xfree(ictx->wp->window->name); diff --git a/options-table.c b/options-table.c index fa5dc71f..20f5ae01 100644 --- a/options-table.c +++ b/options-table.c @@ -436,6 +436,11 @@ const struct options_table_entry window_options_table[] = { .default_num = 0 }, + { .name = "allow-rename", + .type = OPTIONS_TABLE_FLAG, + .default_num = 1 + }, + { .name = "alternate-screen", .type = OPTIONS_TABLE_FLAG, .default_num = 1 diff --git a/tmux.1 b/tmux.1 index d04d789c..fcc19baa 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2342,6 +2342,13 @@ this option is good for full-screen programs which support .Dv SIGWINCH and poor for interactive programs such as shells. .Pp +.It Xo Ic allow-rename +.Op Ic on | off +.Xc +Allow programs to change the window name using a terminal escape +sequence (\\033k...\\033\\\\). +The default is on. +.Pp .It Xo Ic alternate-screen .Op Ic on | off .Xc From 199d148740877c5cf066fc26f72d4f4c21d68373 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 20 Jan 2012 19:16:16 +0000 Subject: [PATCH 0999/1180] Remove trailing spaces. --- tmux.1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tmux.1 b/tmux.1 index fcc19baa..6b036bb3 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2146,7 +2146,7 @@ global environment set (see the .Sx ENVIRONMENT section). .Pp -For details on how the names and titles can be set see the +For details on how the names and titles can be set see the .Sx "NAMES AND TITLES" section. .Pp From 8cf19ab770e03f0dccc4731852a23d670b3ebad2 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 20 Jan 2012 19:51:28 +0000 Subject: [PATCH 1000/1180] Add some trivial additional status line attributes from jwcxz at users dot sourceforge dot net. --- options-table.c | 36 +++++++++++++++++++++++++++++++++--- status.c | 28 ++++++++++++++++++++++++---- tmux.1 | 31 ++++++++++++++++++++++++------- 3 files changed, 81 insertions(+), 14 deletions(-) diff --git a/options-table.c b/options-table.c index 20f5ae01..8bc61149 100644 --- a/options-table.c +++ b/options-table.c @@ -570,17 +570,47 @@ const struct options_table_entry window_options_table[] = { .default_num = 0 /* overridden in main() */ }, - { .name = "window-status-alert-attr", + { .name = "window-status-bell-attr", .type = OPTIONS_TABLE_ATTRIBUTES, .default_num = GRID_ATTR_REVERSE }, - { .name = "window-status-alert-bg", + { .name = "window-status-bell-bg", .type = OPTIONS_TABLE_COLOUR, .default_num = 8 }, - { .name = "window-status-alert-fg", + { .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-attr", + .type = OPTIONS_TABLE_ATTRIBUTES, + .default_num = GRID_ATTR_REVERSE + }, + + { .name = "window-status-activity-bg", + .type = OPTIONS_TABLE_COLOUR, + .default_num = 8 + }, + + { .name = "window-status-activity-fg", .type = OPTIONS_TABLE_COLOUR, .default_num = 8 }, diff --git a/status.c b/status.c index 041382fb..2fb89d1f 100644 --- a/status.c +++ b/status.c @@ -684,14 +684,34 @@ status_print( fmt = options_get_string(oo, "window-status-current-format"); } - if (wl->flags & WINLINK_ALERTFLAGS) { - fg = options_get_number(oo, "window-status-alert-fg"); + 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-alert-bg"); + bg = options_get_number(oo, "window-status-bell-bg"); if (bg != 8) colour_set_bg(gc, bg); - attr = options_get_number(oo, "window-status-alert-attr"); + 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; } diff --git a/tmux.1 b/tmux.1 index 6b036bb3..6a73949a 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2516,15 +2516,32 @@ Instructs .Nm to expect UTF-8 sequences to appear in this window. .Pp -.It Ic window-status-alert-attr Ar attributes -Set status line attributes for windows which have an alert (bell, activity -or content). +.It Ic window-status-bell-attr Ar attributes +Set status line attributes for windows which have a bell alert. .Pp -.It Ic window-status-alert-bg Ar colour -Set status line background colour for windows with an alert. +.It Ic window-status-bell-bg Ar colour +Set status line background colour for windows with a bell alert. .Pp -.It Ic window-status-alert-fg Ar colour -Set status line foreground colour for windows with an alert. +.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. From 83324133055d9906d99f9709970d0e258ac87f79 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 20 Jan 2012 19:54:07 +0000 Subject: [PATCH 1001/1180] Add some const and fix a warning. --- cmd-new-window.c | 3 ++- cmd-split-window.c | 4 ++-- cmd.c | 4 ++-- tmux.h | 2 +- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/cmd-new-window.c b/cmd-new-window.c index cdf45006..d858ee30 100644 --- a/cmd-new-window.c +++ b/cmd-new-window.c @@ -44,7 +44,8 @@ cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx) struct args *args = self->args; struct session *s; struct winlink *wl; - char *cmd, *cwd, *cause; + const char *cmd, *cwd; + char *cause; int idx, last, detached; if (args_has(args, 'a')) { diff --git a/cmd-split-window.c b/cmd-split-window.c index 7184d964..05de0955 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -58,8 +58,8 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) struct window *w; struct window_pane *wp, *new_wp = NULL; struct environ env; - char *cmd, *cwd, *cause, *new_cause; - const char *shell; + const char *cmd, *cwd, *shell; + char *cause, *new_cause; u_int hlimit, paneidx; int size, percentage; enum layout_type type; diff --git a/cmd.c b/cmd.c index 65617a6c..f5d863d7 100644 --- a/cmd.c +++ b/cmd.c @@ -1215,10 +1215,10 @@ cmd_template_replace(char *template, const char *s, int idx) } /* Return the default path for a new pane. */ -char * +const char * cmd_get_default_path(struct cmd_ctx *ctx) { - char *cwd; + const char *cwd; struct session *s; struct window_pane *wp; struct environ_entry *envent; diff --git a/tmux.h b/tmux.h index dbb28c7e..effa15a1 100644 --- a/tmux.h +++ b/tmux.h @@ -1565,7 +1565,7 @@ int cmd_find_index( struct winlink *cmd_find_pane(struct cmd_ctx *, const char *, struct session **, struct window_pane **); char *cmd_template_replace(char *, const char *, int); -char *cmd_get_default_path(struct cmd_ctx *ctx); +const char *cmd_get_default_path(struct cmd_ctx *ctx); 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 cd10f7322a5b33195a8864fa6b7a410387284d16 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 21 Jan 2012 06:13:16 +0000 Subject: [PATCH 1002/1180] Only hide flags on the current window when the session is attached, from Roland Walker. --- cmd-attach-session.c | 2 ++ cmd-switch-client.c | 1 + server-window.c | 12 +++++++----- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/cmd-attach-session.c b/cmd-attach-session.c index 1a1e3c5c..18e06323 100644 --- a/cmd-attach-session.c +++ b/cmd-attach-session.c @@ -76,6 +76,7 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx) ctx->curclient->session = s; session_update_activity(s); server_redraw_client(ctx->curclient); + s->curw->flags &= ~WINLINK_ALERTFLAGS; } else { if (!(ctx->cmdclient->flags & CLIENT_TERMINAL)) { ctx->error(ctx, "not a terminal"); @@ -104,6 +105,7 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx) environ_update(update, &ctx->cmdclient->environ, &s->environ); server_redraw_client(ctx->cmdclient); + s->curw->flags &= ~WINLINK_ALERTFLAGS; } recalculate_sizes(); server_update_socket(); diff --git a/cmd-switch-client.c b/cmd-switch-client.c index ab940dc4..7e9516bc 100644 --- a/cmd-switch-client.c +++ b/cmd-switch-client.c @@ -108,6 +108,7 @@ cmd_switch_client_exec(struct cmd *self, struct cmd_ctx *ctx) recalculate_sizes(); server_check_unattached(); server_redraw_client(c); + s->curw->flags &= ~WINLINK_ALERTFLAGS; return (0); } diff --git a/server-window.c b/server-window.c index a44e32fa..47dec89a 100644 --- a/server-window.c +++ b/server-window.c @@ -56,8 +56,10 @@ server_window_loop(void) server_status_session(s); TAILQ_FOREACH(wp, &w->panes, entry) server_window_check_content(s, wl, wp); + + if (!(s->flags & SESSION_UNATTACHED)) + w->flags &= ~(WINDOW_BELL|WINDOW_ACTIVITY); } - w->flags &= ~(WINDOW_BELL|WINDOW_ACTIVITY); } } @@ -72,7 +74,7 @@ server_window_check_bell(struct session *s, struct winlink *wl) if (!(w->flags & WINDOW_BELL) || wl->flags & WINLINK_BELL) return (0); - if (s->curw != wl) + if (s->curw != wl || s->flags & SESSION_UNATTACHED) wl->flags |= WINLINK_BELL; action = options_get_number(&s->options, "bell-action"); @@ -129,7 +131,7 @@ server_window_check_activity(struct session *s, struct winlink *wl) if (!(w->flags & WINDOW_ACTIVITY) || wl->flags & WINLINK_ACTIVITY) return (0); - if (s->curw == wl) + if (s->curw == wl && !(s->flags & SESSION_UNATTACHED)) return (0); if (!options_get_number(&w->options, "monitor-activity")) @@ -165,7 +167,7 @@ server_window_check_silence(struct session *s, struct winlink *wl) if (!(w->flags & WINDOW_SILENCE) || wl->flags & WINLINK_SILENCE) return (0); - if (s->curw == wl) { + if (s->curw == wl && !(s->flags & SESSION_UNATTACHED)) { /* * Reset the timer for this window if we've focused it. We * don't want the timer tripping as soon as we've switched away @@ -217,7 +219,7 @@ server_window_check_content( /* Activity flag must be set for new content. */ if (!(w->flags & WINDOW_ACTIVITY) || wl->flags & WINLINK_CONTENT) return (0); - if (s->curw == wl) + if (s->curw == wl && !(s->flags & SESSION_UNATTACHED)) return (0); ptr = options_get_string(&w->options, "monitor-content"); From 66f04514cf23a6202ad2dae3cdb96cd0ae74010c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 21 Jan 2012 08:10:21 +0000 Subject: [PATCH 1003/1180] Add a -R flag to send-keys to reset the terminal. Written ages ago and Suggested by someone, I forget who. --- cmd-send-keys.c | 22 ++++++++++++++++++++-- input.c | 12 +----------- screen-write.c | 18 ++++++++++++++++++ tmux.1 | 4 ++++ tmux.h | 1 + 5 files changed, 44 insertions(+), 13 deletions(-) diff --git a/cmd-send-keys.c b/cmd-send-keys.c index 8181e563..2e4775aa 100644 --- a/cmd-send-keys.c +++ b/cmd-send-keys.c @@ -19,6 +19,7 @@ #include #include +#include #include "tmux.h" @@ -30,8 +31,8 @@ int cmd_send_keys_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_send_keys_entry = { "send-keys", "send", - "t:", 0, -1, - "[-t target-pane] key ...", + "Rt:", 0, -1, + "[-R] [-t target-pane] key ...", 0, NULL, NULL, @@ -44,12 +45,29 @@ cmd_send_keys_exec(struct cmd *self, struct cmd_ctx *ctx) struct args *args = self->args; struct window_pane *wp; struct session *s; + struct input_ctx *ictx; const char *str; int i, key; if (cmd_find_pane(ctx, args_get(args, 't'), &s, &wp) == NULL) return (-1); + if (args_has(args, 'R')) { + ictx = &wp->ictx; + + memcpy(&ictx->cell, &grid_default_cell, sizeof ictx->cell); + memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell); + ictx->old_cx = 0; + ictx->old_cy = 0; + + if (wp->mode == NULL) + screen_write_start(&ictx->ctx, wp, &wp->base); + else + screen_write_start(&ictx->ctx, NULL, &wp->base); + screen_write_reset(&ictx->ctx); + screen_write_stop(&ictx->ctx); + } + for (i = 0; i < args->argc; i++) { str = args->argv[i]; diff --git a/input.c b/input.c index 6fd2d90a..f5ffe8f2 100644 --- a/input.c +++ b/input.c @@ -978,17 +978,7 @@ input_esc_dispatch(struct input_ctx *ictx) ictx->old_cx = 0; ictx->old_cy = 0; - screen_reset_tabs(sctx->s); - - screen_write_scrollregion(sctx, 0, screen_size_y(sctx->s) - 1); - - screen_write_insertmode(sctx, 0); - screen_write_kcursormode(sctx, 0); - screen_write_kkeypadmode(sctx, 0); - screen_write_mousemode_off(sctx); - - screen_write_clearscreen(sctx); - screen_write_cursormove(sctx, 0, 0); + screen_write_reset(sctx->s); break; case INPUT_ESC_IND: screen_write_linefeed(sctx, 0); diff --git a/screen-write.c b/screen-write.c index d1d02c7c..784f02e2 100644 --- a/screen-write.c +++ b/screen-write.c @@ -46,6 +46,24 @@ screen_write_stop(unused struct screen_write_ctx *ctx) { } + +/* Reset screen state. */ +void +screen_write_reset(struct screen_write_ctx *ctx) +{ + screen_reset_tabs(ctx->s); + + screen_write_scrollregion(ctx, 0, screen_size_y(ctx->s) - 1); + + screen_write_insertmode(ctx, 0); + screen_write_kcursormode(ctx, 0); + screen_write_kkeypadmode(ctx, 0); + screen_write_mousemode_off(ctx); + + screen_write_clearscreen(ctx); + screen_write_cursormove(ctx, 0, 0); +} + /* Write character. */ void screen_write_putc( diff --git a/tmux.1 b/tmux.1 index 6a73949a..b72c636d 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1634,6 +1634,7 @@ are listed; this may be one of: or .Em emacs-copy . .It Xo Ic send-keys +.Fl R .Op Fl t Ar target-pane .Ar key Ar ... .Xc @@ -1648,6 +1649,9 @@ or ) to send; if the string is not recognised as a key, it is sent as a series of characters. All arguments are sent sequentially from first to last. +The +.Fl R +flag causes the terminal state to be reset. .It Ic send-prefix Op Fl t Ar target-pane Send the prefix key to a window as if it was pressed. If multiple prefix keys are configured, only the first is sent. diff --git a/tmux.h b/tmux.h index effa15a1..617741d7 100644 --- a/tmux.h +++ b/tmux.h @@ -1832,6 +1832,7 @@ char *grid_view_string_cells(struct grid *, u_int, u_int, u_int); void screen_write_start( struct screen_write_ctx *, struct window_pane *, struct screen *); void screen_write_stop(struct screen_write_ctx *); +void screen_write_reset(struct screen_write_ctx *); size_t printflike2 screen_write_cstrlen(int, const char *, ...); void printflike5 screen_write_cnputs(struct screen_write_ctx *, ssize_t, struct grid_cell *, int, const char *, ...); From be7b56a6137847823bfb56f35d1d92f29f2650ad Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 21 Jan 2012 08:12:03 +0000 Subject: [PATCH 1004/1180] One day I will actually fix ALL the warnings before I commit... --- input.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/input.c b/input.c index f5ffe8f2..e6c63207 100644 --- a/input.c +++ b/input.c @@ -978,7 +978,7 @@ input_esc_dispatch(struct input_ctx *ictx) ictx->old_cx = 0; ictx->old_cy = 0; - screen_write_reset(sctx->s); + screen_write_reset(sctx); break; case INPUT_ESC_IND: screen_write_linefeed(sctx, 0); From 7f24020cbe477548795754f2f7f01aafc2cd3cb8 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 21 Jan 2012 08:23:12 +0000 Subject: [PATCH 1005/1180] Add strings to allow the aixterm bright colours to be used when configuring colours, requested by Elliott Cable a few months ago. --- colour.c | 40 ++++++++++++++++++++++++++++++++++++++++ input.c | 2 +- tmux.1 | 4 ++++ tty.c | 8 ++++---- 4 files changed, 49 insertions(+), 5 deletions(-) diff --git a/colour.c b/colour.c index ae69e88f..ff492687 100644 --- a/colour.c +++ b/colour.c @@ -170,6 +170,22 @@ colour_tostring(int c) return ("white"); case 8: return ("default"); + case 90: + return ("brightblack"); + case 91: + return ("brightred"); + case 92: + return ("brightgreen"); + case 93: + return ("brightyellow"); + case 94: + return ("brightblue"); + case 95: + return ("brightmagenta"); + case 96: + return ("brightcyan"); + case 97: + return ("brightwhite"); } return (NULL); } @@ -219,6 +235,30 @@ colour_fromstring(const char *s) return (7); if (strcasecmp(s, "default") == 0 || (s[0] == '8' && s[1] == '\0')) return (8); + if (strcasecmp(s, "brightblack") == 0 || + (s[0] == '9' && s[1] == '0' && s[1] == '\0')) + return (90); + if (strcasecmp(s, "brightred") == 0 || + (s[0] == '9' && s[1] == '1' && s[1] == '\0')) + return (91); + if (strcasecmp(s, "brightgreen") == 0 || + (s[0] == '9' && s[1] == '2' && s[1] == '\0')) + return (92); + if (strcasecmp(s, "brightyellow") == 0 || + (s[0] == '9' && s[1] == '3' && s[1] == '\0')) + return (93); + if (strcasecmp(s, "brightblue") == 0 || + (s[0] == '9' && s[1] == '4' && s[1] == '\0')) + return (94); + if (strcasecmp(s, "brightmagenta") == 0 || + (s[0] == '9' && s[1] == '5' && s[1] == '\0')) + return (95); + if (strcasecmp(s, "brightcyan") == 0 || + (s[0] == '9' && s[1] == '6' && s[1] == '\0')) + return (96); + if (strcasecmp(s, "brightwhite") == 0 || + (s[0] == '9' && s[1] == '7' && s[1] == '\0')) + return (97); return (-1); } diff --git a/input.c b/input.c index e6c63207..957053da 100644 --- a/input.c +++ b/input.c @@ -1436,7 +1436,7 @@ input_csi_dispatch_sgr(struct input_ctx *ictx) case 106: case 107: gc->flags &= ~GRID_FLAG_BG256; - gc->bg = n; + gc->bg = n - 10; break; } } diff --git a/tmux.1 b/tmux.1 index b72c636d..5403d6f8 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1976,6 +1976,10 @@ is one of: .Ic magenta , .Ic cyan , .Ic white , +aixterm bright variants (if supported: +.Ic brightred , +.Ic brightgreen , +and so on), .Ic colour0 to .Ic colour255 diff --git a/tty.c b/tty.c index d5fc106e..51718c3c 100644 --- a/tty.c +++ b/tty.c @@ -1440,7 +1440,7 @@ tty_check_bg(struct tty *tty, struct grid_cell *gc) /* Is this an aixterm colour? */ colours = tty_term_number(tty->term, TTYC_COLORS); - if (gc->bg >= 100 && gc->bg <= 107 && colours < 16) { + if (gc->bg >= 90 && gc->bg <= 97 && colours < 16) { gc->bg -= 90; gc->attr |= GRID_ATTR_BRIGHT; } @@ -1500,14 +1500,14 @@ tty_colours_bg(struct tty *tty, const struct grid_cell *gc) } /* Is this an aixterm bright colour? */ - if (bg >= 100 && bg <= 107) { + if (bg >= 90 && bg <= 97) { /* 16 colour terminals or above only. */ if (tty_term_number(tty->term, TTYC_COLORS) >= 16) { - xsnprintf(s, sizeof s, "\033[%dm", bg); + xsnprintf(s, sizeof s, "\033[%dm", bg + 10); tty_puts(tty, s); goto save_bg; } - bg -= 100; + bg -= 90; /* no such thing as a bold background */ } From 535286c05aee55c0127cdabada8e54582905ef8e Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 21 Jan 2012 08:40:09 +0000 Subject: [PATCH 1006/1180] Drop the ability to have a list of keys in the prefix in favour of two separate options, prefix and prefix2. This simplifies the code and gets rid the data options type which was only used for this one option. Also add a -2 flag to send-prefix to send the secondary prefix key, fixing a cause of minor irritation. People who want three prefix keys are out of luck :-). --- cmd-send-prefix.c | 13 ++++++++----- cmd-set-option.c | 32 ++++++++++---------------------- key-string.c | 4 ++++ options-table.c | 25 +++++++++++-------------- options.c | 41 ----------------------------------------- server-client.c | 16 ++++++---------- tmux.1 | 19 +++++++++++-------- tmux.c | 7 ------- tmux.h | 11 +---------- 9 files changed, 51 insertions(+), 117 deletions(-) diff --git a/cmd-send-prefix.c b/cmd-send-prefix.c index 398f440e..b541fddf 100644 --- a/cmd-send-prefix.c +++ b/cmd-send-prefix.c @@ -28,8 +28,8 @@ int cmd_send_prefix_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_send_prefix_entry = { "send-prefix", NULL, - "t:", 0, 0, - CMD_TARGET_PANE_USAGE, + "2t:", 0, 0, + "[-2] " CMD_TARGET_PANE_USAGE, 0, NULL, NULL, @@ -42,13 +42,16 @@ cmd_send_prefix_exec(struct cmd *self, struct cmd_ctx *ctx) struct args *args = self->args; struct session *s; struct window_pane *wp; - struct keylist *keylist; + int key; if (cmd_find_pane(ctx, args_get(args, 't'), &s, &wp) == NULL) return (-1); - keylist = options_get_data(&s->options, "prefix"); - window_pane_key(wp, s, ARRAY_FIRST(keylist)); + if (args_has(args, '2')) + key = options_get_number(&s->options, "prefix2"); + else + key = options_get_number(&s->options, "prefix"); + window_pane_key(wp, s, key); return (0); } diff --git a/cmd-set-option.c b/cmd-set-option.c index 9ddfba9c..88aa454a 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -45,7 +45,7 @@ struct options_entry *cmd_set_option_string(struct cmd *, struct cmd_ctx *, struct options_entry *cmd_set_option_number(struct cmd *, struct cmd_ctx *, const struct options_table_entry *, struct options *, const char *); -struct options_entry *cmd_set_option_keys(struct cmd *, struct cmd_ctx *, +struct options_entry *cmd_set_option_key(struct cmd *, struct cmd_ctx *, const struct options_table_entry *, struct options *, const char *); struct options_entry *cmd_set_option_colour(struct cmd *, struct cmd_ctx *, @@ -236,8 +236,8 @@ cmd_set_option_set(struct cmd *self, struct cmd_ctx *ctx, case OPTIONS_TABLE_NUMBER: o = cmd_set_option_number(self, ctx, oe, oo, value); break; - case OPTIONS_TABLE_KEYS: - o = cmd_set_option_keys(self, ctx, oe, oo, value); + case OPTIONS_TABLE_KEY: + o = cmd_set_option_key(self, ctx, oe, oo, value); break; case OPTIONS_TABLE_COLOUR: o = cmd_set_option_colour(self, ctx, oe, oo, value); @@ -298,31 +298,19 @@ cmd_set_option_number(unused struct cmd *self, struct cmd_ctx *ctx, return (options_set_number(oo, oe->name, ll)); } -/* Set a keys option. */ +/* Set a key option. */ struct options_entry * -cmd_set_option_keys(unused struct cmd *self, struct cmd_ctx *ctx, +cmd_set_option_key(unused struct cmd *self, struct cmd_ctx *ctx, const struct options_table_entry *oe, struct options *oo, const char *value) { - struct keylist *keylist; - char *copy, *ptr, *s; - int key; + int key; - keylist = xmalloc(sizeof *keylist); - ARRAY_INIT(keylist); - - ptr = copy = xstrdup(value); - while ((s = strsep(&ptr, ",")) != NULL) { - if ((key = key_string_lookup_string(s)) == KEYC_NONE) { - ctx->error(ctx, "unknown key: %s", s); - xfree(copy); - xfree(keylist); - return (NULL); - } - ARRAY_ADD(keylist, key); + if ((key = key_string_lookup_string(value)) == KEYC_NONE) { + ctx->error(ctx, "bad key: %s", value); + return (NULL); } - xfree(copy); - return (options_set_data(oo, oe->name, keylist, xfree)); + return (options_set_number(oo, oe->name, key)); } /* Set a colour option. */ diff --git a/key-string.c b/key-string.c index 29b6a844..08cf0b9c 100644 --- a/key-string.c +++ b/key-string.c @@ -188,6 +188,10 @@ key_string_lookup_key(int key) *out = '\0'; + /* Handle no key. */ + if (key == KEYC_NONE) + return ("none"); + /* * Special case: display C-@ as C-Space. Could do this below in * the (key >= 0 && key <= 32), but this way we let it be found diff --git a/options-table.c b/options-table.c index 8bc61149..918a9f51 100644 --- a/options-table.c +++ b/options-table.c @@ -262,8 +262,13 @@ const struct options_table_entry session_options_table[] = { }, { .name = "prefix", - .type = OPTIONS_TABLE_KEYS, - /* set in main() */ + .type = OPTIONS_TABLE_KEY, + .default_num = '\002', + }, + + { .name = "prefix2", + .type = OPTIONS_TABLE_KEY, + .default_num = KEYC_NONE, }, { .name = "repeat-time", @@ -683,10 +688,8 @@ const char * options_table_print_entry( const struct options_table_entry *oe, struct options_entry *o) { - static char out[BUFSIZ]; - const char *s; - struct keylist *keylist; - u_int i; + static char out[BUFSIZ]; + const char *s; *out = '\0'; switch (oe->type) { @@ -696,14 +699,8 @@ options_table_print_entry( case OPTIONS_TABLE_NUMBER: xsnprintf(out, sizeof out, "%lld", o->num); break; - case OPTIONS_TABLE_KEYS: - keylist = o->data; - for (i = 0; i < ARRAY_LENGTH(keylist); i++) { - s = key_string_lookup_key(ARRAY_ITEM(keylist, i)); - strlcat(out, s, sizeof out); - if (i != ARRAY_LENGTH(keylist) - 1) - strlcat(out, ",", sizeof out); - } + case OPTIONS_TABLE_KEY: + xsnprintf(out, sizeof out, "%s", key_string_lookup_key(o->num)); break; case OPTIONS_TABLE_COLOUR: s = colour_tostring(o->num); diff --git a/options.c b/options.c index f7efdc29..6ee4bf1d 100644 --- a/options.c +++ b/options.c @@ -54,8 +54,6 @@ options_free(struct options *oo) xfree(o->name); if (o->type == OPTIONS_STRING) xfree(o->str); - else if (o->type == OPTIONS_DATA) - o->freefn(o->data); xfree(o); } } @@ -97,8 +95,6 @@ options_remove(struct options *oo, const char *name) xfree(o->name); if (o->type == OPTIONS_STRING) xfree(o->str); - else if (o->type == OPTIONS_DATA) - o->freefn(o->data); xfree(o); } @@ -114,8 +110,6 @@ options_set_string(struct options *oo, const char *name, const char *fmt, ...) SPLAY_INSERT(options_tree, &oo->tree, o); } else if (o->type == OPTIONS_STRING) xfree(o->str); - else if (o->type == OPTIONS_DATA) - o->freefn(o->data); va_start(ap, fmt); o->type = OPTIONS_STRING; @@ -147,8 +141,6 @@ options_set_number(struct options *oo, const char *name, long long value) SPLAY_INSERT(options_tree, &oo->tree, o); } else if (o->type == OPTIONS_STRING) xfree(o->str); - else if (o->type == OPTIONS_DATA) - o->freefn(o->data); o->type = OPTIONS_NUMBER; o->num = value; @@ -166,36 +158,3 @@ options_get_number(struct options *oo, const char *name) fatalx("option not a number"); return (o->num); } - -struct options_entry * -options_set_data( - struct options *oo, const char *name, void *value, void (*freefn)(void *)) -{ - struct options_entry *o; - - if ((o = options_find1(oo, name)) == NULL) { - o = xmalloc(sizeof *o); - o->name = xstrdup(name); - SPLAY_INSERT(options_tree, &oo->tree, o); - } else if (o->type == OPTIONS_STRING) - xfree(o->str); - else if (o->type == OPTIONS_DATA) - o->freefn(o->data); - - o->type = OPTIONS_DATA; - o->data = value; - o->freefn = freefn; - return (o); -} - -void * -options_get_data(struct options *oo, const char *name) -{ - struct options_entry *o; - - if ((o = options_find(oo, name)) == NULL) - fatalx("missing option"); - if (o->type != OPTIONS_DATA) - fatalx("option not data"); - return (o->data); -} diff --git a/server-client.c b/server-client.c index 1ea1da91..138d9a80 100644 --- a/server-client.c +++ b/server-client.c @@ -273,9 +273,7 @@ server_client_handle_key(int key, struct mouse_event *mouse, void *data) struct options *oo; struct timeval tv; struct key_binding *bd; - struct keylist *keylist; int xtimeout, isprefix; - u_int i; /* Check the client is good to accept input. */ if ((c->flags & (CLIENT_DEAD|CLIENT_SUSPENDED)) != 0) @@ -360,14 +358,12 @@ server_client_handle_key(int key, struct mouse_event *mouse, void *data) } /* Is this a prefix key? */ - keylist = options_get_data(&c->session->options, "prefix"); - isprefix = 0; - for (i = 0; i < ARRAY_LENGTH(keylist); i++) { - if (key == ARRAY_ITEM(keylist, i)) { - isprefix = 1; - break; - } - } + if (key == options_get_number(&c->session->options, "prefix")) + isprefix = 1; + else if (key == options_get_number(&c->session->options, "prefix2")) + isprefix = 1; + else + isprefix = 0; /* No previous prefix key. */ if (!(c->flags & CLIENT_PREFIX)) { diff --git a/tmux.1 b/tmux.1 index 5403d6f8..0733ea4b 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1652,9 +1652,13 @@ All arguments are sent sequentially from first to last. The .Fl R flag causes the terminal state to be reset. -.It Ic send-prefix Op Fl t Ar target-pane -Send the prefix key to a window as if it was pressed. -If multiple prefix keys are configured, only the first is sent. +.It Xo Ic send-prefix +.Op Fl 2 +.Op Fl t Ar target-pane +.Xc +Send the prefix key, or with +.Fl 2 +the secondary prefix key, to a window as if it was pressed. .It Xo Ic unbind-key .Op Fl acn .Op Fl t Ar key-table @@ -2029,11 +2033,10 @@ 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 prefix Ar keys -Set the keys accepted as a prefix key. -.Ar keys -is a comma-separated list of key names, each of which individually behave as -the prefix key. +.It Ic prefix Ar key +Set the key accepted as a prefix key. +.It Ic prefix2 Ar key +Set a secondary key accepted as a prefix key. .It Ic repeat-time Ar time Allow multiple commands to be entered without pressing the prefix-key again in the specified diff --git a/tmux.c b/tmux.c index cab9d54e..35d43909 100644 --- a/tmux.c +++ b/tmux.c @@ -232,7 +232,6 @@ int main(int argc, char **argv) { struct passwd *pw; - struct keylist *keylist; char *s, *path, *label, *home, **var; int opt, flags, quiet, keys; @@ -329,12 +328,6 @@ main(int argc, char **argv) options_init(&global_w_options, NULL); options_table_populate_tree(window_options_table, &global_w_options); - /* Set the prefix option (its a list, so not in the table). */ - keylist = xmalloc(sizeof *keylist); - ARRAY_INIT(keylist); - ARRAY_ADD(keylist, '\002'); - options_set_data(&global_s_options, "prefix", keylist, xfree); - /* Enable UTF-8 if the first client is on UTF-8 terminal. */ if (flags & IDENTIFY_UTF8) { options_set_number(&global_s_options, "status-utf8", 1); diff --git a/tmux.h b/tmux.h index 617741d7..dba364fa 100644 --- a/tmux.h +++ b/tmux.h @@ -673,9 +673,6 @@ struct options_entry { char *str; long long num; - void *data; - - void (*freefn)(void *); SPLAY_ENTRY(options_entry) entry; }; @@ -685,9 +682,6 @@ struct options { struct options *parent; }; -/* Key list for prefix option. */ -ARRAY_DECL(keylist, int); - /* Scheduled job. */ struct job { char *cmd; @@ -1294,7 +1288,7 @@ SPLAY_HEAD(key_bindings, key_binding); enum options_table_type { OPTIONS_TABLE_STRING, OPTIONS_TABLE_NUMBER, - OPTIONS_TABLE_KEYS, + OPTIONS_TABLE_KEY, OPTIONS_TABLE_COLOUR, OPTIONS_TABLE_ATTRIBUTES, OPTIONS_TABLE_FLAG, @@ -1413,9 +1407,6 @@ char *options_get_string(struct options *, const char *); 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_data( - struct options *, const char *, void *, void (*)(void *)); -void *options_get_data(struct options *, const char *); /* options-table.c */ extern const struct options_table_entry server_options_table[]; From 8ed9124f3fd307a26b2b5032b02b05fe7ede023b Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 21 Jan 2012 11:12:13 +0000 Subject: [PATCH 1007/1180] Use RB trees not SPLAY. --- cmd-bind-key.c | 4 ++-- cmd-list-keys.c | 8 ++++---- cmd-unbind-key.c | 8 ++++---- key-bindings.c | 18 +++++++++--------- mode-key.c | 8 ++++---- options.c | 22 +++++++++++----------- tmux.h | 18 +++++++++--------- 7 files changed, 43 insertions(+), 43 deletions(-) diff --git a/cmd-bind-key.c b/cmd-bind-key.c index 30421115..4f1b9f18 100644 --- a/cmd-bind-key.c +++ b/cmd-bind-key.c @@ -107,7 +107,7 @@ cmd_bind_key_table(struct cmd *self, struct cmd_ctx *ctx, int key) mtmp.key = key; mtmp.mode = !!args_has(args, 'c'); - if ((mbind = SPLAY_FIND(mode_key_tree, mtab->tree, &mtmp)) != NULL) { + if ((mbind = RB_FIND(mode_key_tree, mtab->tree, &mtmp)) != NULL) { mbind->cmd = cmd; return (0); } @@ -115,6 +115,6 @@ cmd_bind_key_table(struct cmd *self, struct cmd_ctx *ctx, int key) mbind->key = mtmp.key; mbind->mode = mtmp.mode; mbind->cmd = cmd; - SPLAY_INSERT(mode_key_tree, mtab->tree, mbind); + RB_INSERT(mode_key_tree, mtab->tree, mbind); return (0); } diff --git a/cmd-list-keys.c b/cmd-list-keys.c index 73ecf458..95f33023 100644 --- a/cmd-list-keys.c +++ b/cmd-list-keys.c @@ -55,7 +55,7 @@ cmd_list_keys_exec(struct cmd *self, struct cmd_ctx *ctx) width = 0; - SPLAY_FOREACH(bd, key_bindings, &key_bindings) { + RB_FOREACH(bd, key_bindings, &key_bindings) { key = key_string_lookup_key(bd->key & ~KEYC_PREFIX); if (key == NULL) continue; @@ -72,7 +72,7 @@ cmd_list_keys_exec(struct cmd *self, struct cmd_ctx *ctx) width = keywidth; } - SPLAY_FOREACH(bd, key_bindings, &key_bindings) { + RB_FOREACH(bd, key_bindings, &key_bindings) { key = key_string_lookup_key(bd->key & ~KEYC_PREFIX); if (key == NULL) continue; @@ -116,7 +116,7 @@ cmd_list_keys_table(struct cmd *self, struct cmd_ctx *ctx) width = 0; any_mode = 0; - SPLAY_FOREACH(mbind, mode_key_tree, mtab->tree) { + RB_FOREACH(mbind, mode_key_tree, mtab->tree) { key = key_string_lookup_key(mbind->key); if (key == NULL) continue; @@ -129,7 +129,7 @@ cmd_list_keys_table(struct cmd *self, struct cmd_ctx *ctx) width = keywidth; } - SPLAY_FOREACH(mbind, mode_key_tree, mtab->tree) { + RB_FOREACH(mbind, mode_key_tree, mtab->tree) { key = key_string_lookup_key(mbind->key); if (key == NULL) continue; diff --git a/cmd-unbind-key.c b/cmd-unbind-key.c index 7e8c183c..22a35ed0 100644 --- a/cmd-unbind-key.c +++ b/cmd-unbind-key.c @@ -57,8 +57,8 @@ cmd_unbind_key_exec(struct cmd *self, unused struct cmd_ctx *ctx) int key; if (args_has(args, 'a')) { - while (!SPLAY_EMPTY(&key_bindings)) { - bd = SPLAY_ROOT(&key_bindings); + while (!RB_EMPTY(&key_bindings)) { + bd = RB_ROOT(&key_bindings); key_bindings_remove(bd->key); } return (0); @@ -95,8 +95,8 @@ cmd_unbind_key_table(struct cmd *self, struct cmd_ctx *ctx, int key) mtmp.key = key; mtmp.mode = !!args_has(args, 'c'); - if ((mbind = SPLAY_FIND(mode_key_tree, mtab->tree, &mtmp)) != NULL) { - SPLAY_REMOVE(mode_key_tree, mtab->tree, mbind); + if ((mbind = RB_FIND(mode_key_tree, mtab->tree, &mtmp)) != NULL) { + RB_REMOVE(mode_key_tree, mtab->tree, mbind); xfree(mbind); } return (0); diff --git a/key-bindings.c b/key-bindings.c index fe8a7576..fb1590a5 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -24,7 +24,7 @@ #include "tmux.h" -SPLAY_GENERATE(key_bindings, key_binding, entry, key_bindings_cmp); +RB_GENERATE(key_bindings, key_binding, entry, key_bindings_cmp); struct key_bindings key_bindings; struct key_bindings dead_key_bindings; @@ -52,7 +52,7 @@ key_bindings_lookup(int key) struct key_binding bd; bd.key = key; - return (SPLAY_FIND(key_bindings, &key_bindings, &bd)); + return (RB_FIND(key_bindings, &key_bindings, &bd)); } void @@ -64,7 +64,7 @@ key_bindings_add(int key, int can_repeat, struct cmd_list *cmdlist) bd = xmalloc(sizeof *bd); bd->key = key; - SPLAY_INSERT(key_bindings, &key_bindings, bd); + RB_INSERT(key_bindings, &key_bindings, bd); bd->can_repeat = can_repeat; bd->cmdlist = cmdlist; @@ -77,8 +77,8 @@ key_bindings_remove(int key) if ((bd = key_bindings_lookup(key)) == NULL) return; - SPLAY_REMOVE(key_bindings, &key_bindings, bd); - SPLAY_INSERT(key_bindings, &dead_key_bindings, bd); + RB_REMOVE(key_bindings, &key_bindings, bd); + RB_INSERT(key_bindings, &dead_key_bindings, bd); } void @@ -86,9 +86,9 @@ key_bindings_clean(void) { struct key_binding *bd; - while (!SPLAY_EMPTY(&dead_key_bindings)) { - bd = SPLAY_ROOT(&dead_key_bindings); - SPLAY_REMOVE(key_bindings, &dead_key_bindings, bd); + while (!RB_EMPTY(&dead_key_bindings)) { + bd = RB_ROOT(&dead_key_bindings); + RB_REMOVE(key_bindings, &dead_key_bindings, bd); cmd_list_free(bd->cmdlist); xfree(bd); } @@ -179,7 +179,7 @@ key_bindings_init(void) struct cmd *cmd; struct cmd_list *cmdlist; - SPLAY_INIT(&key_bindings); + RB_INIT(&key_bindings); for (i = 0; i < nitems(table); i++) { cmdlist = xmalloc(sizeof *cmdlist); diff --git a/mode-key.c b/mode-key.c index 6115d630..43d07c0f 100644 --- a/mode-key.c +++ b/mode-key.c @@ -412,7 +412,7 @@ const struct mode_key_table mode_key_tables[] = { { NULL, NULL, NULL, NULL } }; -SPLAY_GENERATE(mode_key_tree, mode_key_binding, entry, mode_key_cmp); +RB_GENERATE(mode_key_tree, mode_key_binding, entry, mode_key_cmp); int mode_key_cmp(struct mode_key_binding *mbind1, struct mode_key_binding *mbind2) @@ -462,13 +462,13 @@ mode_key_init_trees(void) struct mode_key_binding *mbind; for (mtab = mode_key_tables; mtab->name != NULL; mtab++) { - SPLAY_INIT(mtab->tree); + RB_INIT(mtab->tree); for (ment = mtab->table; ment->mode != -1; ment++) { mbind = xmalloc(sizeof *mbind); mbind->key = ment->key; mbind->mode = ment->mode; mbind->cmd = ment->cmd; - SPLAY_INSERT(mode_key_tree, mtab->tree, mbind); + RB_INSERT(mode_key_tree, mtab->tree, mbind); } } } @@ -487,7 +487,7 @@ mode_key_lookup(struct mode_key_data *mdata, int key) mtmp.key = key; mtmp.mode = mdata->mode; - if ((mbind = SPLAY_FIND(mode_key_tree, mdata->tree, &mtmp)) == NULL) { + if ((mbind = RB_FIND(mode_key_tree, mdata->tree, &mtmp)) == NULL) { if (mdata->mode != 0) return (MODEKEY_NONE); return (MODEKEY_OTHER); diff --git a/options.c b/options.c index 6ee4bf1d..9298ab11 100644 --- a/options.c +++ b/options.c @@ -28,7 +28,7 @@ * a splay tree. */ -SPLAY_GENERATE(options_tree, options_entry, entry, options_cmp); +RB_GENERATE(options_tree, options_entry, entry, options_cmp); int options_cmp(struct options_entry *o1, struct options_entry *o2) @@ -39,7 +39,7 @@ options_cmp(struct options_entry *o1, struct options_entry *o2) void options_init(struct options *oo, struct options *parent) { - SPLAY_INIT(&oo->tree); + RB_INIT(&oo->tree); oo->parent = parent; } @@ -48,9 +48,9 @@ options_free(struct options *oo) { struct options_entry *o; - while (!SPLAY_EMPTY(&oo->tree)) { - o = SPLAY_ROOT(&oo->tree); - SPLAY_REMOVE(options_tree, &oo->tree, o); + while (!RB_EMPTY(&oo->tree)) { + o = RB_ROOT(&oo->tree); + RB_REMOVE(options_tree, &oo->tree, o); xfree(o->name); if (o->type == OPTIONS_STRING) xfree(o->str); @@ -64,7 +64,7 @@ options_find1(struct options *oo, const char *name) struct options_entry p; p.name = (char *) name; - return (SPLAY_FIND(options_tree, &oo->tree, &p)); + return (RB_FIND(options_tree, &oo->tree, &p)); } struct options_entry * @@ -73,12 +73,12 @@ options_find(struct options *oo, const char *name) struct options_entry *o, p; p.name = (char *) name; - o = SPLAY_FIND(options_tree, &oo->tree, &p); + o = RB_FIND(options_tree, &oo->tree, &p); while (o == NULL) { oo = oo->parent; if (oo == NULL) break; - o = SPLAY_FIND(options_tree, &oo->tree, &p); + o = RB_FIND(options_tree, &oo->tree, &p); } return (o); } @@ -91,7 +91,7 @@ options_remove(struct options *oo, const char *name) if ((o = options_find1(oo, name)) == NULL) return; - SPLAY_REMOVE(options_tree, &oo->tree, o); + RB_REMOVE(options_tree, &oo->tree, o); xfree(o->name); if (o->type == OPTIONS_STRING) xfree(o->str); @@ -107,7 +107,7 @@ options_set_string(struct options *oo, const char *name, const char *fmt, ...) if ((o = options_find1(oo, name)) == NULL) { o = xmalloc(sizeof *o); o->name = xstrdup(name); - SPLAY_INSERT(options_tree, &oo->tree, o); + RB_INSERT(options_tree, &oo->tree, o); } else if (o->type == OPTIONS_STRING) xfree(o->str); @@ -138,7 +138,7 @@ options_set_number(struct options *oo, const char *name, long long value) if ((o = options_find1(oo, name)) == NULL) { o = xmalloc(sizeof *o); o->name = xstrdup(name); - SPLAY_INSERT(options_tree, &oo->tree, o); + RB_INSERT(options_tree, &oo->tree, o); } else if (o->type == OPTIONS_STRING) xfree(o->str); diff --git a/tmux.h b/tmux.h index dba364fa..40721133 100644 --- a/tmux.h +++ b/tmux.h @@ -545,9 +545,9 @@ struct mode_key_binding { int mode; enum mode_key_cmd cmd; - SPLAY_ENTRY(mode_key_binding) entry; + RB_ENTRY(mode_key_binding) entry; }; -SPLAY_HEAD(mode_key_tree, mode_key_binding); +RB_HEAD(mode_key_tree, mode_key_binding); /* Command to string mapping. */ struct mode_key_cmdstr { @@ -674,11 +674,11 @@ struct options_entry { char *str; long long num; - SPLAY_ENTRY(options_entry) entry; + RB_ENTRY(options_entry) entry; }; struct options { - SPLAY_HEAD(options_tree, options_entry) tree; + RB_HEAD(options_tree, options_entry) tree; struct options *parent; }; @@ -1276,9 +1276,9 @@ struct key_binding { struct cmd_list *cmdlist; int can_repeat; - SPLAY_ENTRY(key_binding) entry; + RB_ENTRY(key_binding) entry; }; -SPLAY_HEAD(key_bindings, key_binding); +RB_HEAD(key_bindings, key_binding); /* * Option table entries. The option table is the user-visible part of the @@ -1383,7 +1383,7 @@ extern struct mode_key_tree mode_key_tree_emacs_edit; extern struct mode_key_tree mode_key_tree_emacs_choice; extern struct mode_key_tree mode_key_tree_emacs_copy; int mode_key_cmp(struct mode_key_binding *, struct mode_key_binding *); -SPLAY_PROTOTYPE(mode_key_tree, mode_key_binding, entry, mode_key_cmp); +RB_PROTOTYPE(mode_key_tree, mode_key_binding, entry, mode_key_cmp); const char *mode_key_tostring(const struct mode_key_cmdstr *, enum mode_key_cmd); enum mode_key_cmd mode_key_fromstring(const struct mode_key_cmdstr *, @@ -1395,7 +1395,7 @@ enum mode_key_cmd mode_key_lookup(struct mode_key_data *, int); /* options.c */ int options_cmp(struct options_entry *, struct options_entry *); -SPLAY_PROTOTYPE(options_tree, options_entry, entry, options_cmp); +RB_PROTOTYPE(options_tree, options_entry, entry, options_cmp); void options_init(struct options *, struct options *); void options_free(struct options *); struct options_entry *options_find1(struct options *, const char *); @@ -1657,7 +1657,7 @@ int client_main(int, char **, int); /* key-bindings.c */ extern struct key_bindings key_bindings; int key_bindings_cmp(struct key_binding *, struct key_binding *); -SPLAY_PROTOTYPE(key_bindings, key_binding, entry, key_bindings_cmp); +RB_PROTOTYPE(key_bindings, key_binding, entry, key_bindings_cmp); struct key_binding *key_bindings_lookup(int); void key_bindings_add(int, int, struct cmd_list *); void key_bindings_remove(int); From e870a3f3ec0375813d6764b10d67e80d2a5d148f Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 21 Jan 2012 20:40:28 +0000 Subject: [PATCH 1008/1180] it's -> its. --- tmux.1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tmux.1 b/tmux.1 index 0733ea4b..2f447e31 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2719,7 +2719,7 @@ It is the same mechanism used to set for example the window title in an .Xr X 7 window manager. -Windows themselves do not have titles - a window's title is the title of it's +Windows themselves do not have titles - a window's title is the title of its active pane. .Nm itself may set the title of the terminal in which the client is running, see From b92e81a1aa9d1bfd50bcbe1983cc782f556c39d4 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 21 Jan 2012 23:45:44 +0000 Subject: [PATCH 1009/1180] Show pane size in top right of display panes mode. --- screen-redraw.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/screen-redraw.c b/screen-redraw.c index 0a546bf7..3a8faf46 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -286,15 +286,7 @@ screen_redraw_draw_number(struct client *c, struct window_pane *wp) if (wp->sx < len * 6 || wp->sy < 5) { tty_cursor(tty, xoff + px - len / 2, yoff + py); - memcpy(&gc, &grid_default_cell, sizeof gc); - gc.data = '_'; /* not space */ - if (w->active == wp) - colour_set_fg(&gc, active_colour); - else - colour_set_fg(&gc, colour); - tty_attributes(tty, &gc); - tty_puts(tty, buf); - return; + goto draw_text; } px -= len * 3; @@ -321,4 +313,21 @@ screen_redraw_draw_number(struct client *c, struct window_pane *wp) } px += 6; } + + len = xsnprintf(buf, sizeof buf, "%ux%u", wp->sx, wp->sy); + if (wp->sx < len || wp->sy < 6) + return; + tty_cursor(tty, xoff + wp->sx - len, yoff); + +draw_text: + memcpy(&gc, &grid_default_cell, sizeof gc); + gc.data = '_'; /* not space */ + if (w->active == wp) + colour_set_fg(&gc, active_colour); + else + colour_set_fg(&gc, colour); + tty_attributes(tty, &gc); + tty_puts(tty, buf); + + tty_cursor(tty, 0, 0); } From 678e67437f8549404a60809403d179d84c12a7da Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 21 Jan 2012 23:51:34 +0000 Subject: [PATCH 1010/1180] Remove unused backoff code that doesn't do any good. --- server-client.c | 44 -------------------------------------------- tmux.h | 3 +-- 2 files changed, 1 insertion(+), 46 deletions(-) diff --git a/server-client.c b/server-client.c index 138d9a80..45801eb9 100644 --- a/server-client.c +++ b/server-client.c @@ -561,50 +561,6 @@ server_client_check_exit(struct client *c) c->flags &= ~CLIENT_EXIT; } -/* - * Check if the client should backoff. During backoff, data from external - * programs is not written to the terminal. When the existing data drains, the - * client is redrawn. - * - * There are two backoff phases - both the tty and client have backoff flags - - * the first to allow existing data to drain and the latter to ensure backoff - * is disabled until the redraw has finished and prevent the redraw triggering - * another backoff. - */ -void -server_client_check_backoff(struct client *c) -{ - struct tty *tty = &c->tty; - size_t used; - - used = EVBUFFER_LENGTH(tty->event->output); - - /* - * If in the second backoff phase (redrawing), don't check backoff - * until the redraw has completed (or enough of it to drop below the - * backoff threshold). - */ - if (c->flags & CLIENT_BACKOFF) { - if (used > BACKOFF_THRESHOLD) - return; - c->flags &= ~CLIENT_BACKOFF; - return; - } - - /* Once drained, allow data through again and schedule redraw. */ - if (tty->flags & TTY_BACKOFF) { - if (used != 0) - return; - tty->flags &= ~TTY_BACKOFF; - c->flags |= (CLIENT_BACKOFF|CLIENT_REDRAWWINDOW|CLIENT_STATUS); - return; - } - - /* If too much data, start backoff. */ - if (used > BACKOFF_THRESHOLD) - tty->flags |= TTY_BACKOFF; -} - /* Check for client redraws. */ void server_client_check_redraw(struct client *c) diff --git a/tmux.h b/tmux.h index 40721133..7c245ff6 100644 --- a/tmux.h +++ b/tmux.h @@ -1168,8 +1168,7 @@ struct client { #define CLIENT_DEAD 0x200 #define CLIENT_BORDERS 0x400 #define CLIENT_READONLY 0x800 -#define CLIENT_BACKOFF 0x1000 -#define CLIENT_REDRAWWINDOW 0x2000 +#define CLIENT_REDRAWWINDOW 0x1000 int flags; struct event identify_timer; From d2d2df136502f95da8fa749f10a1e534fca7cde2 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 26 Jan 2012 09:03:09 +0000 Subject: [PATCH 1011/1180] Fix memory leak in error path, from Tiago Cunha. --- status.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/status.c b/status.c index 2fb89d1f..c111a238 100644 --- a/status.c +++ b/status.c @@ -462,12 +462,13 @@ do_replace: ptrlen = limit; if (*optr + ptrlen >= out + outsize - 1) - return; + goto out; while (ptrlen > 0 && *ptr != '\0') { *(*optr)++ = *ptr++; ptrlen--; } +out: if (freeptr != NULL) xfree(freeptr); return; From a7a44bfcd9f1eeec2b82b6490b35893dcb7c053f Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 26 Jan 2012 09:05:54 +0000 Subject: [PATCH 1012/1180] Terminate strftime buffer properly even if a really long format string is given, from Tiago Cunha. --- status.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/status.c b/status.c index c111a238..ae05853f 100644 --- a/status.c +++ b/status.c @@ -491,9 +491,10 @@ status_replace(struct client *c, struct session *s, struct winlink *wl, { static char out[BUFSIZ]; char in[BUFSIZ], ch, *iptr, *optr; + size_t len; - strftime(in, sizeof in, fmt, localtime(&t)); - in[(sizeof in) - 1] = '\0'; + len = strftime(in, sizeof in, fmt, localtime(&t)); + in[len] = '\0'; iptr = in; optr = out; From 9bbc63ed653e6ca73e4eaebd6f52466d53a4da73 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 29 Jan 2012 02:22:11 +0000 Subject: [PATCH 1013/1180] Call bufferevent_free before closing file descriptor associated with it or bugs in $EventMechanism on $OtherOS makes libevent get it's knickers in a twist. From Dylan Alex Simon. --- job.c | 4 ++-- server-client.c | 12 ++++++------ server-fn.c | 2 +- window.c | 6 +++--- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/job.c b/job.c index b167d456..e2e8ab48 100644 --- a/job.c +++ b/job.c @@ -124,10 +124,10 @@ job_free(struct job *job) if (job->pid != -1) kill(job->pid, SIGTERM); - if (job->fd != -1) - close(job->fd); if (job->event != NULL) bufferevent_free(job->event); + if (job->fd != -1) + close(job->fd); xfree(job); } diff --git a/server-client.c b/server-client.c index 45801eb9..9ee9e26f 100644 --- a/server-client.c +++ b/server-client.c @@ -124,24 +124,24 @@ server_client_lost(struct client *c) if (c->flags & CLIENT_TERMINAL) tty_free(&c->tty); + if (c->stdin_event != NULL) + bufferevent_free(c->stdin_event); if (c->stdin_fd != -1) { setblocking(c->stdin_fd, 1); close(c->stdin_fd); } - if (c->stdin_event != NULL) - bufferevent_free(c->stdin_event); + if (c->stdout_event != NULL) + bufferevent_free(c->stdout_event); if (c->stdout_fd != -1) { setblocking(c->stdout_fd, 1); close(c->stdout_fd); } - if (c->stdout_event != NULL) - bufferevent_free(c->stdout_event); + if (c->stderr_event != NULL) + bufferevent_free(c->stderr_event); if (c->stderr_fd != -1) { setblocking(c->stderr_fd, 1); close(c->stderr_fd); } - if (c->stderr_event != NULL) - bufferevent_free(c->stderr_event); status_free_jobs(&c->status_new); status_free_jobs(&c->status_old); diff --git a/server-fn.c b/server-fn.c index c8f85cd0..b9b7b714 100644 --- a/server-fn.c +++ b/server-fn.c @@ -337,8 +337,8 @@ server_destroy_pane(struct window_pane *wp) old_fd = wp->fd; if (wp->fd != -1) { - close(wp->fd); bufferevent_free(wp->event); + close(wp->fd); wp->fd = -1; } diff --git a/window.c b/window.c index f46e302f..9a735dd6 100644 --- a/window.c +++ b/window.c @@ -611,8 +611,8 @@ window_pane_destroy(struct window_pane *wp) window_pane_reset_mode(wp); if (wp->fd != -1) { - close(wp->fd); bufferevent_free(wp->event); + close(wp->fd); } input_free(wp); @@ -622,8 +622,8 @@ window_pane_destroy(struct window_pane *wp) grid_destroy(wp->saved_grid); if (wp->pipe_fd != -1) { - close(wp->pipe_fd); bufferevent_free(wp->pipe_event); + close(wp->pipe_fd); } RB_REMOVE(window_pane_tree, &all_window_panes, wp); @@ -647,8 +647,8 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell, struct termios tio2; if (wp->fd != -1) { - close(wp->fd); bufferevent_free(wp->event); + close(wp->fd); } if (cmd != NULL) { if (wp->cmd != NULL) From 230d0fbc9e273a171e811f58b540163fe871df5e Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 29 Jan 2012 09:37:02 +0000 Subject: [PATCH 1014/1180] Add an option to move the status line to the top of the screen, requested by many. --- layout.c | 4 +- options-table.c | 9 ++++ screen-redraw.c | 61 +++++++++++++++++++-------- server-client.c | 107 ++++++++++++++++++++++++++++++------------------ status.c | 14 +++++++ tmux.1 | 4 ++ tmux.h | 8 +++- tty.c | 65 +++++++++++++++-------------- 8 files changed, 180 insertions(+), 92 deletions(-) diff --git a/layout.c b/layout.c index a07ae2d5..429e103e 100644 --- a/layout.c +++ b/layout.c @@ -502,14 +502,14 @@ layout_resize_pane_mouse(struct client *c, struct mouse_event *mouse) wp->yoff <= 1 + c->last_mouse.y && wp->yoff + wp->sy >= c->last_mouse.y) { layout_resize_pane(wp, LAYOUT_LEFTRIGHT, - mouse->x - c->last_mouse.x); + mouse->x - c->last_mouse.x); pane_border = 1; } if (wp->yoff + wp->sy == c->last_mouse.y && wp->xoff <= 1 + c->last_mouse.x && wp->xoff + wp->sx >= c->last_mouse.x) { layout_resize_pane(wp, LAYOUT_TOPBOTTOM, - mouse->y - c->last_mouse.y); + mouse->y - c->last_mouse.y); pane_border = 1; } } diff --git a/options-table.c b/options-table.c index 918a9f51..e0a99f43 100644 --- a/options-table.c +++ b/options-table.c @@ -48,6 +48,9 @@ const char *options_table_status_keys_list[] = { const char *options_table_status_justify_list[] = { "left", "centre", "right", NULL }; +const char *options_table_status_position_list[] = { + "top", "bottom", NULL +}; const char *options_table_bell_action_list[] = { "none", "any", "current", NULL }; @@ -359,6 +362,12 @@ const struct options_table_entry session_options_table[] = { .default_num = 10 }, + { .name = "status-position", + .type = OPTIONS_TABLE_CHOICE, + .choices = options_table_status_position_list, + .default_num = 1 + }, + { .name = "status-right", .type = OPTIONS_TABLE_STRING, .default_str = "\"#22T\" %H:%M %d-%b-%y" diff --git a/screen-redraw.c b/screen-redraw.c index 3a8faf46..2eca1bdc 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -170,25 +170,33 @@ void screen_redraw_screen(struct client *c, int status_only, int borders_only) { 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; - int status, fg, bg; + u_int i, j, type, top; + int status, spos, fg, bg; /* Suspended clients should not be updated. */ if (c->flags & CLIENT_SUSPENDED) return; /* Get status line, er, status. */ + spos = options_get_number(oo, "status-position"); if (c->message_string != NULL || c->prompt_string != NULL) status = 1; else - status = options_get_number(&c->session->options, "status"); + status = options_get_number(oo, "status"); + top = 0; + if (status && spos == 0) + top = 1; /* If only drawing status and it is present, don't need the rest. */ if (status_only && status) { - tty_draw_line(tty, &c->status, 0, 0, tty->sy - 1); + 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; } @@ -198,19 +206,23 @@ screen_redraw_screen(struct client *c, int status_only, int borders_only) memcpy(&active_gc, &grid_default_cell, sizeof active_gc); active_gc.data = other_gc.data = 'x'; /* not space */ active_gc.attr = other_gc.attr = GRID_ATTR_CHARSET; - fg = options_get_number(&c->session->options, "pane-border-fg"); + fg = options_get_number(oo, "pane-border-fg"); colour_set_fg(&other_gc, fg); - bg = options_get_number(&c->session->options, "pane-border-bg"); + bg = options_get_number(oo, "pane-border-bg"); colour_set_bg(&other_gc, bg); - fg = options_get_number(&c->session->options, "pane-active-border-fg"); + fg = options_get_number(oo, "pane-active-border-fg"); colour_set_fg(&active_gc, fg); - bg = options_get_number(&c->session->options, "pane-active-border-bg"); + bg = options_get_number(oo, "pane-active-border-bg"); colour_set_bg(&active_gc, bg); /* Draw background and borders. */ for (j = 0; j < tty->sy - status; j++) { - if (status_only && j != tty->sy - 1) - continue; + 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); if (type == CELL_INSIDE) @@ -219,7 +231,7 @@ screen_redraw_screen(struct client *c, int status_only, int borders_only) tty_attributes(tty, &active_gc); else tty_attributes(tty, &other_gc); - tty_cursor(tty, i, j); + tty_cursor(tty, i, top + j); tty_putc(tty, CELL_BORDERS[type]); } } @@ -233,17 +245,26 @@ screen_redraw_screen(struct client *c, int status_only, int borders_only) if (!window_pane_visible(wp)) continue; for (i = 0; i < wp->sy; i++) { - if (status_only && wp->yoff + i != tty->sy - 1) - continue; - tty_draw_line(tty, wp->screen, i, wp->xoff, wp->yoff); + 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) - tty_draw_line(tty, &c->status, 0, 0, tty->sy - 1); + 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); + } tty_reset(tty); } @@ -251,10 +272,14 @@ screen_redraw_screen(struct client *c, int status_only, int borders_only) void screen_redraw_pane(struct client *c, struct window_pane *wp) { - u_int i; + u_int i, yoff; + + yoff = wp->yoff; + if (status_at_line(c) == 0) + yoff++; for (i = 0; i < wp->sy; i++) - tty_draw_line(&c->tty, wp->screen, i, wp->xoff, wp->yoff); + tty_draw_line(&c->tty, wp->screen, i, wp->xoff, yoff); tty_reset(&c->tty); } diff --git a/server-client.c b/server-client.c index 9ee9e26f..8efd9d7c 100644 --- a/server-client.c +++ b/server-client.c @@ -27,6 +27,8 @@ #include "tmux.h" +void server_client_check_mouse(struct client *c, + struct window_pane *wp, struct mouse_event *mouse); void server_client_handle_key(int, struct mouse_event *, void *); void server_client_repeat_timer(int, short, void *); void server_client_check_exit(struct client *); @@ -262,6 +264,65 @@ server_client_status_timer(void) } } +/* Check for mouse keys. */ +void +server_client_check_mouse( + struct client *c, struct window_pane *wp, struct mouse_event *mouse) +{ + struct session *s = c->session; + struct options *oo = &s->options; + int statusat; + + statusat = status_at_line(c); + + /* Is this a window selection click on the status line? */ + if (statusat != -1 && mouse->y == (u_int)statusat && + options_get_number(oo, "mouse-select-window")) { + if (mouse->b == MOUSE_UP && c->last_mouse.b != MOUSE_UP) { + status_set_window_at(c, mouse->x); + return; + } + if (mouse->b & MOUSE_45) { + if ((mouse->b & MOUSE_BUTTON) == MOUSE_1) { + session_previous(c->session, 0); + server_redraw_session(s); + } + if ((mouse->b & MOUSE_BUTTON) == MOUSE_2) { + session_next(c->session, 0); + server_redraw_session(s); + } + return; + } + } + + /* + * Not on status line - adjust mouse position if status line is at the + * top and limit if at the bottom. From here on a struct mouse + * represents the offset onto the window itself. + */ + if (statusat == 0 &&mouse->y > 0) + mouse->y--; + else if (statusat > 0 && mouse->y >= (u_int)statusat) + mouse->y = statusat - 1; + + /* Is this a pane selection? Allow down only in copy mode. */ + if (options_get_number(oo, "mouse-select-pane") && + ((!(mouse->b & MOUSE_DRAG) && mouse->b != MOUSE_UP) || + wp->mode != &window_copy_mode)) { + window_set_active_at(wp->window, mouse->x, mouse->y); + server_redraw_window_borders(wp->window); + wp = wp->window->active; /* may have changed */ + } + + /* Check if trying to resize pane. */ + if (options_get_number(oo, "mouse-resize-pane")) + layout_resize_pane_mouse(c, mouse); + + /* Update last and pass through to client. */ + memcpy(&c->last_mouse, mouse, sizeof c->last_mouse); + window_pane_mouse(wp, c->session, mouse); +} + /* Handle data key input from client. */ void server_client_handle_key(int key, struct mouse_event *mouse, void *data) @@ -317,43 +378,7 @@ server_client_handle_key(int key, struct mouse_event *mouse, void *data) if (key == KEYC_MOUSE) { if (c->flags & CLIENT_READONLY) return; - if (options_get_number(oo, "mouse-select-pane") && - (!(options_get_number(oo, "status") && - mouse->y + 1 == c->tty.sy)) && - ((!(mouse->b & MOUSE_DRAG) && mouse->b != MOUSE_UP) || - wp->mode != &window_copy_mode)) { - /* - * Allow pane switching in copy mode only by mouse down - * (click). - */ - window_set_active_at(w, mouse->x, mouse->y); - server_redraw_window_borders(w); - wp = w->active; - } - if (mouse->y + 1 == c->tty.sy && - options_get_number(oo, "mouse-select-window") && - options_get_number(oo, "status")) { - if (mouse->b == MOUSE_UP && - c->last_mouse.b != MOUSE_UP) { - status_set_window_at(c, mouse->x); - return; - } - if (mouse->b & MOUSE_45) { - if ((mouse->b & MOUSE_BUTTON) == MOUSE_1) { - session_previous(c->session, 0); - server_redraw_session(s); - } - if ((mouse->b & MOUSE_BUTTON) == MOUSE_2) { - session_next(c->session, 0); - server_redraw_session(s); - } - return; - } - } - if (options_get_number(oo, "mouse-resize-pane")) - layout_resize_pane_mouse(c, mouse); - memcpy(&c->last_mouse, mouse, sizeof c->last_mouse); - window_pane_mouse(wp, c->session, mouse); + server_client_check_mouse(c, wp, mouse); return; } @@ -472,7 +497,7 @@ server_client_reset_state(struct client *c) struct screen *s = wp->screen; struct options *oo = &c->session->options; struct options *wo = &w->options; - int status, mode; + int status, mode, o; if (c->flags & CLIENT_SUSPENDED) return; @@ -482,8 +507,10 @@ server_client_reset_state(struct client *c) status = options_get_number(oo, "status"); if (!window_pane_visible(wp) || wp->yoff + s->cy >= c->tty.sy - status) tty_cursor(&c->tty, 0, 0); - else - tty_cursor(&c->tty, wp->xoff + s->cx, wp->yoff + s->cy); + else { + o = status && options_get_number (oo, "status-position") == 0; + tty_cursor(&c->tty, wp->xoff + s->cx, o + wp->yoff + s->cy); + } /* * Resizing panes with the mouse requires at least button mode to give diff --git a/status.c b/status.c index ae05853f..fee9f2d6 100644 --- a/status.c +++ b/status.c @@ -60,6 +60,20 @@ status_out_cmp(struct status_out *so1, struct status_out *so2) return (strcmp(so1->cmd, so2->cmd)); } +/* Get screen line of status line. -1 means off. */ +int +status_at_line(struct client *c) +{ + struct session *s = c->session; + + if (!options_get_number(&s->options, "status")) + return (-1); + + if (options_get_number(&s->options, "status-position") == 0) + return (0); + return (c->tty.sy - 1); +} + /* Retrieve options for left string. */ char * status_redraw_get_left(struct client *c, diff --git a/tmux.1 b/tmux.1 index 2f447e31..36e4719b 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2199,6 +2199,10 @@ Set the maximum .Ar length of the left component of the status bar. The default is 10. +.It Xo Ic status-position +.Op Ic top | bottom +.Xc +Set the position of the status line. .It Ic status-right Ar string Display .Ar string diff --git a/tmux.h b/tmux.h index 7c245ff6..73353b65 100644 --- a/tmux.h +++ b/tmux.h @@ -1078,6 +1078,9 @@ struct tty_ctx { u_int orupper; u_int orlower; + u_int xoff; + u_int yoff; + /* Saved last cell on line. */ struct grid_cell last_cell; struct grid_utf8 last_utf8; @@ -1463,8 +1466,8 @@ void tty_draw_line(struct tty *, struct screen *, u_int, u_int, u_int); int tty_open(struct tty *, const char *, char **); void tty_close(struct tty *); void tty_free(struct tty *); -void tty_write(void (*)( - struct tty *, const struct tty_ctx *), const struct tty_ctx *); +void tty_write( + void (*)(struct tty *, const struct tty_ctx *), struct tty_ctx *); void tty_cmd_alignmenttest(struct tty *, const struct tty_ctx *); void tty_cmd_cell(struct tty *, const struct tty_ctx *); void tty_cmd_clearendofline(struct tty *, const struct tty_ctx *); @@ -1722,6 +1725,7 @@ void server_update_event(struct client *); /* status.c */ int status_out_cmp(struct status_out *, struct status_out *); RB_PROTOTYPE(status_out_tree, status_out, entry, status_out_cmp); +int status_at_line(struct client *); void status_free_jobs(struct status_out_tree *); void status_update_jobs(struct client *); void status_set_window_at(struct client *, u_int); diff --git a/tty.c b/tty.c index 51718c3c..6e3e2cf2 100644 --- a/tty.c +++ b/tty.c @@ -513,10 +513,10 @@ tty_redraw_region(struct tty *tty, const struct tty_ctx *ctx) if (ctx->ocy < ctx->orupper || ctx->ocy > ctx->orlower) { for (i = ctx->ocy; i < screen_size_y(s); i++) - tty_draw_line(tty, s, i, wp->xoff, wp->yoff); + tty_draw_line(tty, s, i, ctx->xoff, ctx->yoff); } else { for (i = ctx->orupper; i <= ctx->orlower; i++) - tty_draw_line(tty, s, i, wp->xoff, wp->yoff); + tty_draw_line(tty, s, i, ctx->xoff, ctx->yoff); } } @@ -585,11 +585,13 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int py, u_int ox, u_int oy) } void -tty_write(void (*cmdfn)( - struct tty *, const struct tty_ctx *), const struct tty_ctx *ctx) +tty_write( + void (*cmdfn)(struct tty *, const struct tty_ctx *), struct tty_ctx *ctx) { struct window_pane *wp = ctx->wp; struct client *c; + struct session *s; + struct options *oo; u_int i; /* wp can be NULL if updating the screen but not the terminal. */ @@ -607,12 +609,20 @@ tty_write(void (*cmdfn)( continue; if (c->flags & CLIENT_SUSPENDED) continue; + s = c->session; - if (c->session->curw->window == wp->window) { + if (s->curw->window == wp->window) { if (c->tty.term == NULL) continue; if (c->tty.flags & (TTY_FREEZE|TTY_BACKOFF)) continue; + oo = &s->options; + + ctx->xoff = wp->xoff; + ctx->yoff = wp->yoff; + if (status_at_line(c) == 0) + ctx->yoff++; + cmdfn(&c->tty, ctx); } } @@ -625,8 +635,8 @@ tty_cmd_insertcharacter(struct tty *tty, const struct tty_ctx *ctx) struct screen *s = wp->screen; u_int i; - if (wp->xoff != 0 || screen_size_x(s) < tty->sx) { - tty_draw_line(tty, wp->screen, ctx->ocy, wp->xoff, wp->yoff); + if (ctx->xoff != 0 || screen_size_x(s) < tty->sx) { + tty_draw_line(tty, wp->screen, ctx->ocy, ctx->xoff, ctx->yoff); return; } @@ -644,7 +654,7 @@ tty_cmd_insertcharacter(struct tty *tty, const struct tty_ctx *ctx) tty_putc(tty, ' '); tty_putcode(tty, TTYC_RMIR); } else - tty_draw_line(tty, wp->screen, ctx->ocy, wp->xoff, wp->yoff); + tty_draw_line(tty, wp->screen, ctx->ocy, ctx->xoff, ctx->yoff); } void @@ -653,10 +663,10 @@ tty_cmd_deletecharacter(struct tty *tty, const struct tty_ctx *ctx) struct window_pane *wp = ctx->wp; struct screen *s = wp->screen; - if (wp->xoff != 0 || screen_size_x(s) < tty->sx || + if (ctx->xoff != 0 || screen_size_x(s) < tty->sx || (!tty_term_has(tty->term, TTYC_DCH) && !tty_term_has(tty->term, TTYC_DCH1))) { - tty_draw_line(tty, wp->screen, ctx->ocy, wp->xoff, wp->yoff); + tty_draw_line(tty, wp->screen, ctx->ocy, ctx->xoff, ctx->yoff); return; } @@ -675,7 +685,7 @@ tty_cmd_insertline(struct tty *tty, const struct tty_ctx *ctx) struct window_pane *wp = ctx->wp; struct screen *s = wp->screen; - if (wp->xoff != 0 || screen_size_x(s) < tty->sx || + if (ctx->xoff != 0 || screen_size_x(s) < tty->sx || !tty_term_has(tty->term, TTYC_CSR) || !tty_term_has(tty->term, TTYC_IL1)) { tty_redraw_region(tty, ctx); @@ -696,7 +706,7 @@ tty_cmd_deleteline(struct tty *tty, const struct tty_ctx *ctx) struct window_pane *wp = ctx->wp; struct screen *s = wp->screen; - if (wp->xoff != 0 || screen_size_x(s) < tty->sx || + if (ctx->xoff != 0 || screen_size_x(s) < tty->sx || !tty_term_has(tty->term, TTYC_CSR) || !tty_term_has(tty->term, TTYC_DL1)) { tty_redraw_region(tty, ctx); @@ -722,7 +732,7 @@ tty_cmd_clearline(struct tty *tty, const struct tty_ctx *ctx) tty_cursor_pane(tty, ctx, 0, ctx->ocy); - if (wp->xoff == 0 && screen_size_x(s) >= tty->sx && + if (ctx->xoff == 0 && screen_size_x(s) >= tty->sx && tty_term_has(tty->term, TTYC_EL)) { tty_putcode(tty, TTYC_EL); } else { @@ -742,7 +752,7 @@ tty_cmd_clearendofline(struct tty *tty, const struct tty_ctx *ctx) tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); - if (wp->xoff == 0 && screen_size_x(s) >= tty->sx && + if (ctx->xoff == 0 && screen_size_x(s) >= tty->sx && tty_term_has(tty->term, TTYC_EL)) tty_putcode(tty, TTYC_EL); else { @@ -754,12 +764,11 @@ tty_cmd_clearendofline(struct tty *tty, const struct tty_ctx *ctx) void tty_cmd_clearstartofline(struct tty *tty, const struct tty_ctx *ctx) { - struct window_pane *wp = ctx->wp; - u_int i; + u_int i; tty_reset(tty); - if (wp->xoff == 0 && tty_term_has(tty->term, TTYC_EL1)) { + if (ctx->xoff == 0 && tty_term_has(tty->term, TTYC_EL1)) { tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); tty_putcode(tty, TTYC_EL1); } else { @@ -778,7 +787,7 @@ tty_cmd_reverseindex(struct tty *tty, const struct tty_ctx *ctx) if (ctx->ocy != ctx->orupper) return; - if (wp->xoff != 0 || screen_size_x(s) < tty->sx || + if (ctx->xoff != 0 || screen_size_x(s) < tty->sx || !tty_term_has(tty->term, TTYC_CSR) || !tty_term_has(tty->term, TTYC_RI)) { tty_redraw_region(tty, ctx); @@ -802,7 +811,7 @@ tty_cmd_linefeed(struct tty *tty, const struct tty_ctx *ctx) if (ctx->ocy != ctx->orlower) return; - if (wp->xoff != 0 || screen_size_x(s) < tty->sx || + if (ctx->xoff != 0 || screen_size_x(s) < tty->sx || !tty_term_has(tty->term, TTYC_CSR)) { tty_redraw_region(tty, ctx); return; @@ -836,7 +845,7 @@ tty_cmd_clearendofscreen(struct tty *tty, const struct tty_ctx *ctx) tty_region_pane(tty, ctx, 0, screen_size_y(s) - 1); tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); - if (wp->xoff == 0 && screen_size_x(s) >= tty->sx && + if (ctx->xoff == 0 && screen_size_x(s) >= tty->sx && tty_term_has(tty->term, TTYC_EL)) { tty_putcode(tty, TTYC_EL); if (ctx->ocy != screen_size_y(s) - 1) { @@ -872,7 +881,7 @@ tty_cmd_clearstartofscreen(struct tty *tty, const struct tty_ctx *ctx) tty_region_pane(tty, ctx, 0, screen_size_y(s) - 1); tty_cursor_pane(tty, ctx, 0, 0); - if (wp->xoff == 0 && screen_size_x(s) >= tty->sx && + if (ctx->xoff == 0 && screen_size_x(s) >= tty->sx && tty_term_has(tty->term, TTYC_EL)) { for (i = 0; i < ctx->ocy; i++) { tty_putcode(tty, TTYC_EL); @@ -902,7 +911,7 @@ tty_cmd_clearscreen(struct tty *tty, const struct tty_ctx *ctx) tty_region_pane(tty, ctx, 0, screen_size_y(s) - 1); tty_cursor_pane(tty, ctx, 0, 0); - if (wp->xoff == 0 && screen_size_x(s) >= tty->sx && + if (ctx->xoff == 0 && screen_size_x(s) >= tty->sx && tty_term_has(tty->term, TTYC_EL)) { for (i = 0; i < screen_size_y(s); i++) { tty_putcode(tty, TTYC_EL); @@ -957,7 +966,7 @@ tty_cmd_cell(struct tty *tty, const struct tty_ctx *ctx) /* Is the cursor in the very last position? */ if (ctx->ocx > wp->sx - width) { - if (wp->xoff != 0 || wp->sx != tty->sx) { + if (ctx->xoff != 0 || wp->sx != tty->sx) { /* * The pane doesn't fill the entire line, the linefeed * will already have happened, so just move the cursor. @@ -991,7 +1000,7 @@ tty_cmd_utf8character(struct tty *tty, const struct tty_ctx *ctx) * Cannot rely on not being a partial character, so just redraw the * whole line. */ - tty_draw_line(tty, wp->screen, ctx->ocy, wp->xoff, wp->yoff); + tty_draw_line(tty, wp->screen, ctx->ocy, ctx->xoff, ctx->yoff); } void @@ -1078,9 +1087,7 @@ void tty_region_pane( struct tty *tty, const struct tty_ctx *ctx, u_int rupper, u_int rlower) { - struct window_pane *wp = ctx->wp; - - tty_region(tty, wp->yoff + rupper, wp->yoff + rlower); + tty_region(tty, ctx->yoff + rupper, ctx->yoff + rlower); } /* Set region at absolute position. */ @@ -1112,9 +1119,7 @@ tty_region(struct tty *tty, u_int rupper, u_int rlower) void tty_cursor_pane(struct tty *tty, const struct tty_ctx *ctx, u_int cx, u_int cy) { - struct window_pane *wp = ctx->wp; - - tty_cursor(tty, wp->xoff + cx, wp->yoff + cy); + tty_cursor(tty, ctx->xoff + cx, ctx->yoff + cy); } /* Move cursor to absolute position. */ From 937173ff110601d7ff44254ec57b4389d5c24994 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 29 Jan 2012 21:31:11 +0000 Subject: [PATCH 1015/1180] Enforce history-limit option when clearing the screen, memory leak spotted by R I Pienaar. --- grid-view.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/grid-view.c b/grid-view.c index 075feb6b..e36144f0 100644 --- a/grid-view.c +++ b/grid-view.c @@ -94,8 +94,10 @@ grid_view_clear_history(struct grid *gd) return; /* Scroll the lines into the history. */ - for (yy = 0; yy < last; yy++) + for (yy = 0; yy < last; yy++) { + grid_collect_history(gd); grid_scroll_history(gd); + } } /* Clear area. */ From 0e59bc75fd90c09e3ea936fd58a5a13e69208253 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 30 Jan 2012 09:39:34 +0000 Subject: [PATCH 1016/1180] Give each window a unique id, like panes but prefixed with @. Based on work from George Nachman. --- cmd-list-windows.c | 4 +-- cmd.c | 73 ++++++++++++++++++++++++++++++++++------------ format.c | 1 + tmux.1 | 5 ++-- tmux.h | 3 ++ window.c | 32 ++++++++++++++++++-- 6 files changed, 94 insertions(+), 24 deletions(-) diff --git a/cmd-list-windows.c b/cmd-list-windows.c index 0c3a9e64..a012dce2 100644 --- a/cmd-list-windows.c +++ b/cmd-list-windows.c @@ -87,14 +87,14 @@ cmd_list_windows_session( template = "#{window_index}: " "#{window_name} " "[#{window_width}x#{window_height}] " - "[layout #{window_layout}]" + "[layout #{window_layout}] #{window_id} " "#{?window_active, (active),}"; break; case 1: template = "#{session_name}:#{window_index}: " "#{window_name} " "[#{window_width}x#{window_height}] " - "[layout #{window_layout}]" + "[layout #{window_layout}] #{window_id} " "#{?window_active, (active),}"; break; } diff --git a/cmd.c b/cmd.c index f5d863d7..9656ae4f 100644 --- a/cmd.c +++ b/cmd.c @@ -120,8 +120,10 @@ struct session *cmd_lookup_session(const char *, int *); struct winlink *cmd_lookup_window(struct session *, const char *, int *); int cmd_lookup_index(struct session *, const char *, int *); struct window_pane *cmd_lookup_paneid(const char *); -struct session *cmd_pane_session(struct cmd_ctx *, - struct window_pane *, struct winlink **); +struct winlink *cmd_lookup_winlink_windowid(struct session *, const char *); +struct window *cmd_lookup_windowid(const char *); +struct session *cmd_window_session(struct cmd_ctx *, + struct window *, struct winlink **); struct winlink *cmd_find_window_offset(const char *, struct session *, int *); int cmd_find_index_offset(const char *, struct session *, int *); struct window_pane *cmd_find_pane_offset(const char *, struct winlink *); @@ -587,6 +589,10 @@ cmd_lookup_window(struct session *s, const char *name, int *ambiguous) *ambiguous = 0; + /* Try as a window id. */ + if ((wl = cmd_lookup_winlink_windowid(s, name)) != NULL) + return (wl); + /* First see if this is a valid window index in this session. */ idx = strtonum(name, 0, INT_MAX, &errstr); if (errstr == NULL) { @@ -649,10 +655,7 @@ cmd_lookup_index(struct session *s, const char *name, int *ambiguous) return (-1); } -/* - * Lookup pane id. An initial % means a pane id. sp must already point to the - * current session. - */ +/* Lookup pane id. An initial % means a pane id. */ struct window_pane * cmd_lookup_paneid(const char *arg) { @@ -668,19 +671,50 @@ cmd_lookup_paneid(const char *arg) return (window_pane_find_by_id(paneid)); } -/* Find session and winlink for pane. */ +/* Lookup window id in a session. An initial @ means a window id. */ +struct winlink * +cmd_lookup_winlink_windowid(struct session *s, const char *arg) +{ + const char *errstr; + u_int windowid; + + if (*arg != '@') + return (NULL); + + windowid = strtonum(arg + 1, 0, UINT_MAX, &errstr); + if (errstr != NULL) + return (NULL); + return (winlink_find_by_window_id(&s->windows, windowid)); +} + +/* Lookup window id. An initial @ means a window id. */ +struct window * +cmd_lookup_windowid(const char *arg) +{ + const char *errstr; + u_int windowid; + + if (*arg != '@') + return (NULL); + + windowid = strtonum(arg + 1, 0, UINT_MAX, &errstr); + if (errstr != NULL) + return (NULL); + return (window_find_by_id(windowid)); +} + +/* Find session and winlink for window. */ struct session * -cmd_pane_session(struct cmd_ctx *ctx, struct window_pane *wp, - struct winlink **wlp) +cmd_window_session(struct cmd_ctx *ctx, struct window *w, struct winlink **wlp) { struct session *s; struct sessionslist ss; struct winlink *wl; - /* If this pane is in the current session, return that winlink. */ + /* If this window is in the current session, return that winlink. */ s = cmd_current_session(ctx, 0); if (s != NULL) { - wl = winlink_find_by_window(&s->windows, wp->window); + wl = winlink_find_by_window(&s->windows, w); if (wl != NULL) { if (wlp != NULL) *wlp = wl; @@ -688,16 +722,16 @@ cmd_pane_session(struct cmd_ctx *ctx, struct window_pane *wp, } } - /* Otherwise choose from all sessions with this pane. */ + /* Otherwise choose from all sessions with this window. */ ARRAY_INIT(&ss); RB_FOREACH(s, sessions, &sessions) { - if (winlink_find_by_window(&s->windows, wp->window) != NULL) + if (winlink_find_by_window(&s->windows, w) != NULL) ARRAY_ADD(&ss, s); } s = cmd_choose_session_list(&ss); ARRAY_FREE(&ss); if (wlp != NULL) - *wlp = winlink_find_by_window(&s->windows, wp->window); + *wlp = winlink_find_by_window(&s->windows, w); return (s); } @@ -707,6 +741,7 @@ cmd_find_session(struct cmd_ctx *ctx, const char *arg, int prefer_unattached) { struct session *s; struct window_pane *wp; + struct window *w; struct client *c; char *tmparg; size_t arglen; @@ -716,9 +751,11 @@ cmd_find_session(struct cmd_ctx *ctx, const char *arg, int prefer_unattached) if (arg == NULL) return (cmd_current_session(ctx, prefer_unattached)); - /* Lookup as pane id. */ + /* Lookup as pane id or window id. */ if ((wp = cmd_lookup_paneid(arg)) != NULL) - return (cmd_pane_session(ctx, wp, NULL)); + return (cmd_window_session(ctx, wp->window, NULL)); + if ((w = cmd_lookup_windowid(arg)) != NULL) + return (cmd_window_session(ctx, w, NULL)); /* Trim a single trailing colon if any. */ tmparg = xstrdup(arg); @@ -780,7 +817,7 @@ cmd_find_window(struct cmd_ctx *ctx, const char *arg, struct session **sp) /* Lookup as pane id. */ if ((wp = cmd_lookup_paneid(arg)) != NULL) { - s = cmd_pane_session(ctx, wp, &wl); + s = cmd_window_session(ctx, wp->window, &wl); if (sp != NULL) *sp = s; return (wl); @@ -1081,7 +1118,7 @@ cmd_find_pane(struct cmd_ctx *ctx, /* Lookup as pane id. */ if ((*wpp = cmd_lookup_paneid(arg)) != NULL) { - s = cmd_pane_session(ctx, *wpp, &wl); + s = cmd_window_session(ctx, (*wpp)->window, &wl); if (sp != NULL) *sp = s; return (wl); diff --git a/format.c b/format.c index 3c8aea6e..c8502bdd 100644 --- a/format.c +++ b/format.c @@ -341,6 +341,7 @@ format_winlink(struct format_tree *ft, struct session *s, struct winlink *wl) layout = layout_dump(w); flags = window_printable_flags(s, wl); + format_add(ft, "window_id", "@%u", w->id); format_add(ft, "window_index", "%d", wl->idx); format_add(ft, "window_name", "%s", w->name); format_add(ft, "window_width", "%u", w->sx); diff --git a/tmux.1 b/tmux.1 index 36e4719b..1d6d4c24 100644 --- a/tmux.1 +++ b/tmux.1 @@ -385,8 +385,9 @@ follows the same rules as for .Ar target-session , and .Em window -is looked for in order: as a window index, for example mysession:1; as an exact -window name, such as mysession:mywindow; then as an +is looked for in order: as a window index, for example mysession:1; +as a window id, such as @1; +as an exact window name, such as mysession:mywindow; then as an .Xr fnmatch 3 pattern or the start of a window name, such as mysession:mywin* or mysession:mywin. diff --git a/tmux.h b/tmux.h index 73353b65..a52edf6f 100644 --- a/tmux.h +++ b/tmux.h @@ -848,6 +848,7 @@ RB_HEAD(window_pane_tree, window_pane); /* Window structure. */ struct window { + u_int id; char *name; struct event name_timer; struct timeval silence_timer; @@ -1905,6 +1906,7 @@ int window_pane_cmp(struct window_pane *, struct window_pane *); RB_PROTOTYPE(window_pane_tree, window_pane, tree_entry, window_pane_cmp); struct winlink *winlink_find_by_index(struct winlinks *, int); struct winlink *winlink_find_by_window(struct winlinks *, struct window *); +struct winlink *winlink_find_by_window_id(struct winlinks *, u_int); int winlink_next_index(struct winlinks *, int); u_int winlink_count(struct winlinks *); struct winlink *winlink_add(struct winlinks *, int); @@ -1919,6 +1921,7 @@ struct winlink *winlink_previous_by_number(struct winlink *, struct session *, void winlink_stack_push(struct winlink_stack *, struct winlink *); void winlink_stack_remove(struct winlink_stack *, struct winlink *); int window_index(struct window *, u_int *); +struct window *window_find_by_id(u_int); struct window *window_create1(u_int, u_int); struct window *window_create(const char *, const char *, const char *, const char *, struct environ *, struct termios *, diff --git a/window.c b/window.c index 9a735dd6..1664999c 100644 --- a/window.c +++ b/window.c @@ -58,7 +58,8 @@ struct windows windows; /* Global panes tree. */ struct window_pane_tree all_window_panes; -u_int next_window_pane; +u_int next_window_pane_id; +u_int next_window_id; void window_pane_read_callback(struct bufferevent *, void *); void window_pane_error_callback(struct bufferevent *, short, void *); @@ -104,6 +105,18 @@ winlink_find_by_index(struct winlinks *wwl, int idx) return (RB_FIND(winlinks, wwl, &wl)); } +struct winlink * +winlink_find_by_window_id(struct winlinks *wwl, u_int id) +{ + struct winlink *wl; + + RB_FOREACH(wl, winlinks, wwl) { + if (wl->window->id == id) + return (wl); + } + return NULL; +} + int winlink_next_index(struct winlinks *wwl, int idx) { @@ -248,6 +261,20 @@ window_index(struct window *s, u_int *i) return (-1); } +struct window * +window_find_by_id(u_int id) +{ + struct window *w; + u_int i; + + for (i = 0; i < ARRAY_LENGTH(&windows); i++) { + w = ARRAY_ITEM(&windows, i); + if (w->id == id) + return (w); + } + return NULL; +} + struct window * window_create1(u_int sx, u_int sy) { @@ -255,6 +282,7 @@ window_create1(u_int sx, u_int sy) u_int i; w = xcalloc(1, sizeof *w); + w->id = next_window_id++; w->name = NULL; w->flags = 0; @@ -571,7 +599,7 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit) wp = xcalloc(1, sizeof *wp); wp->window = w; - wp->id = next_window_pane++; + wp->id = next_window_pane_id++; RB_INSERT(window_pane_tree, &all_window_panes, wp); wp->cmd = NULL; From f188345b33061d3bff7bb8a0fcae2948489b37c1 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 30 Jan 2012 20:39:56 +0000 Subject: [PATCH 1017/1180] Don't print double spaces in list output. --- cmd-list-windows.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd-list-windows.c b/cmd-list-windows.c index a012dce2..3919bfbe 100644 --- a/cmd-list-windows.c +++ b/cmd-list-windows.c @@ -87,14 +87,14 @@ cmd_list_windows_session( template = "#{window_index}: " "#{window_name} " "[#{window_width}x#{window_height}] " - "[layout #{window_layout}] #{window_id} " + "[layout #{window_layout}] #{window_id}" "#{?window_active, (active),}"; break; case 1: template = "#{session_name}:#{window_index}: " "#{window_name} " "[#{window_width}x#{window_height}] " - "[layout #{window_layout}] #{window_id} " + "[layout #{window_layout}] #{window_id}" "#{?window_active, (active),}"; break; } From 677ed3e5f0ed6296e421c974a3e4c90cefe2024c Mon Sep 17 00:00:00 2001 From: Jason McIntyre Date: Mon, 30 Jan 2012 20:48:28 +0000 Subject: [PATCH 1018/1180] id -> ID; ok nicm --- tmux.1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tmux.1 b/tmux.1 index 1d6d4c24..d282f1d9 100644 --- a/tmux.1 +++ b/tmux.1 @@ -386,7 +386,7 @@ follows the same rules as for and .Em window is looked for in order: as a window index, for example mysession:1; -as a window id, such as @1; +as a window ID, such as @1; as an exact window name, such as mysession:mywindow; then as an .Xr fnmatch 3 pattern or the start of a window name, such as mysession:mywin* or @@ -2684,7 +2684,7 @@ The following variables are available, where appropriate: .It Li "pane_active" Ta "1 if active pane" .It Li "pane_dead" Ta "1 if pane is dead" .It Li "pane_height" Ta "Height of pane" -.It Li "pane_id" Ta "Unique pane id" +.It Li "pane_id" Ta "Unique pane ID" .It Li "pane_pid" Ta "PID of first process in pane" .It Li "pane_start_command" Ta "Command pane started with" .It Li "pane_start_path" Ta "Path pane started with" From 49a5a587ec6c99e4030d51cb65f04d49c87e3c31 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 30 Jan 2012 20:57:02 +0000 Subject: [PATCH 1019/1180] Add pane id to each pane in layout description (while still accepting the old form). Based on diff from George Nachman. --- cmd-select-layout.c | 3 +++ layout-custom.c | 17 ++++++++++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/cmd-select-layout.c b/cmd-select-layout.c index b030c311..e1f20a4e 100644 --- a/cmd-select-layout.c +++ b/cmd-select-layout.c @@ -105,6 +105,7 @@ cmd_select_layout_exec(struct cmd *self, struct cmd_ctx *ctx) layout = layout_set_next(wl->window); else layout = layout_set_previous(wl->window); + server_redraw_window(wl->window); ctx->info(ctx, "arranging in: %s", layout_set_name(layout)); return (0); } @@ -115,6 +116,7 @@ cmd_select_layout_exec(struct cmd *self, struct cmd_ctx *ctx) layout = layout_set_lookup(args->argv[0]); if (layout != -1) { layout = layout_set_select(wl->window, layout); + server_redraw_window(wl->window); ctx->info(ctx, "arranging in: %s", layout_set_name(layout)); return (0); } @@ -125,6 +127,7 @@ cmd_select_layout_exec(struct cmd *self, struct cmd_ctx *ctx) ctx->error(ctx, "can't set layout: %s", layoutname); return (-1); } + server_redraw_window(wl->window); ctx->info(ctx, "arranging in: %s", layoutname); return (0); } diff --git a/layout-custom.c b/layout-custom.c index 9fb9cebd..88fcde1f 100644 --- a/layout-custom.c +++ b/layout-custom.c @@ -79,8 +79,13 @@ layout_append(struct layout_cell *lc, char *buf, size_t len) if (len == 0) return (-1); - tmplen = xsnprintf(tmp, sizeof tmp, - "%ux%u,%u,%u", lc->sx, lc->sy, lc->xoff, lc->yoff); + if (lc->wp != NULL) { + tmplen = xsnprintf(tmp, sizeof tmp, "%ux%u,%u,%u,%u", + lc->sx, lc->sy, lc->xoff, lc->yoff, lc->wp->id); + } else { + tmplen = xsnprintf(tmp, sizeof tmp, "%ux%u,%u,%u", + lc->sx, lc->sy, lc->xoff, lc->yoff); + } if (tmplen > (sizeof tmp) - 1) return (-1); if (strlcat(buf, tmp, len) >= len) @@ -202,7 +207,8 @@ layout_construct(struct layout_cell *lcparent, const char **layout) if (!isdigit((u_char) **layout)) return (NULL); - if (sscanf(*layout, "%ux%u,%u,%u", &sx, &sy, &xoff, &yoff) != 4) + if (sscanf(*layout, "%ux%u,%u,%u,%*u", &sx, &sy, &xoff, &yoff) != 5 && + sscanf(*layout, "%ux%u,%u,%u", &sx, &sy, &xoff, &yoff) != 4) return (NULL); while (isdigit((u_char) **layout)) @@ -222,6 +228,11 @@ layout_construct(struct layout_cell *lcparent, const char **layout) (*layout)++; while (isdigit((u_char) **layout)) (*layout)++; + if (**layout == ',') { + (*layout)++; + while (isdigit((u_char) **layout)) + (*layout)++; + } lc = layout_create_cell(lcparent); lc->sx = sx; From 908a22e41ce9b33156ee2fa7a68bd585033cf3a3 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 31 Jan 2012 15:52:21 +0000 Subject: [PATCH 1020/1180] Provide defined ways to set the various default-path possibilities: ~ for home directory, . for server start directory, - for session start directory and empty for the pane's working directory (the default). All can also be used as part of a relative path (eg -/foo). Also provide -c flags to neww and splitw to override default-path setting. Based on a diff from sthen. ok sthen --- cmd-new-window.c | 7 ++-- cmd-split-window.c | 7 ++-- cmd.c | 87 ++++++++++++++++++++++++++++++++++++---------- tmux.1 | 11 ++++++ tmux.h | 2 +- 5 files changed, 88 insertions(+), 26 deletions(-) diff --git a/cmd-new-window.c b/cmd-new-window.c index d858ee30..cf93567d 100644 --- a/cmd-new-window.c +++ b/cmd-new-window.c @@ -30,8 +30,9 @@ int cmd_new_window_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_new_window_entry = { "new-window", "neww", - "adkn:Pt:", 0, 1, - "[-adk] [-n window-name] [-t target-window] [command]", + "ac:dkn:Pt:", 0, 1, + "[-adk] [-c start-directory] [-n window-name] [-t target-window] " + "[command]", 0, NULL, NULL, @@ -99,7 +100,7 @@ cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx) cmd = options_get_string(&s->options, "default-command"); else cmd = args->argv[0]; - cwd = cmd_get_default_path(ctx); + cwd = cmd_get_default_path(ctx, args_get(args, 'c')); if (idx == -1) idx = -1 - options_get_number(&s->options, "base-index"); diff --git a/cmd-split-window.c b/cmd-split-window.c index 05de0955..5aa0af5f 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -33,8 +33,9 @@ int cmd_split_window_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_split_window_entry = { "split-window", "splitw", - "dl:hp:Pt:v", 0, 1, - "[-dhvP] [-p percentage|-l size] [-t target-pane] [command]", + "c:dl:hp:Pt:v", 0, 1, + "[-dhvP] [-c start-directory] [-p percentage|-l size] [-t target-pane] " + "[command]", 0, cmd_split_window_key_binding, NULL, @@ -78,7 +79,7 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) cmd = options_get_string(&s->options, "default-command"); else cmd = args->argv[0]; - cwd = cmd_get_default_path(ctx); + cwd = cmd_get_default_path(ctx, args_get(args, 'c')); type = LAYOUT_TOPBOTTOM; if (args_has(args, 'h')) diff --git a/cmd.c b/cmd.c index 9656ae4f..5e2abfec 100644 --- a/cmd.c +++ b/cmd.c @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -1251,34 +1252,82 @@ cmd_template_replace(char *template, const char *s, int idx) return (buf); } -/* Return the default path for a new pane. */ +/* + * Return the default path for a new pane, using the given path or the + * default-path option if it is NULL. Several special values are accepted: the + * empty string or relative path for the current pane's working directory, ~ + * for the user's home, - for the session working directory, . for the tmux + * server's working directory. The default on failure is the session's working + * directory. + */ const char * -cmd_get_default_path(struct cmd_ctx *ctx) +cmd_get_default_path(struct cmd_ctx *ctx, const char *cwd) { - const char *cwd; struct session *s; - struct window_pane *wp; struct environ_entry *envent; + const char *root; + char tmp[MAXPATHLEN]; + struct passwd *pw; + int n; + size_t skip; + static char path[MAXPATHLEN]; if ((s = cmd_current_session(ctx, 0)) == NULL) return (NULL); - cwd = options_get_string(&s->options, "default-path"); - if ((cwd[0] == '~' && cwd[1] == '\0') || !strcmp(cwd, "$HOME")) { - envent = environ_find(&global_environ, "HOME"); - if (envent != NULL && *envent->value != '\0') - return envent->value; - cwd = ""; - } - if (*cwd == '\0') { - if (ctx->cmdclient != NULL && ctx->cmdclient->cwd != NULL) - return (ctx->cmdclient->cwd); - if (ctx->curclient != NULL) { - wp = s->curw->window->active; - if ((cwd = get_proc_cwd(wp->pid)) != NULL) - return (cwd); + if (cwd == NULL) + cwd = options_get_string(&s->options, "default-path"); + + skip = 1; + if (strcmp(cwd, "$HOME") == 0 || strncmp(cwd, "$HOME/", 6) == 0) { + /* User's home directory - $HOME. */ + skip = 5; + goto find_home; + } else if (cwd[0] == '~' && (cwd[1] == '\0' || cwd[1] == '/')) { + /* User's home directory - ~. */ + goto find_home; + } else if (cwd[0] == '-' && (cwd[1] == '\0' || cwd[1] == '/')) { + /* Session working directory. */ + root = s->cwd; + goto complete_path; + } else if (cwd[0] == '.' && (cwd[1] == '\0' || cwd[1] == '/')){ + /* Server working directory. */ + if (getcwd(tmp, sizeof tmp) != NULL) { + root = tmp; + goto complete_path; } return (s->cwd); + } else if (*cwd == '/') { + /* Absolute path. */ + return (cwd); + } else { + /* Empty or relative path. */ + if (ctx->cmdclient != NULL && ctx->cmdclient->cwd != NULL) + root = ctx->cmdclient->cwd; + else if (ctx->curclient != NULL) + root = get_proc_cwd(s->curw->window->active->pid); + else + return (s->cwd); + skip = 0; + goto complete_path; } - return (cwd); + + return (s->cwd); + +find_home: + envent = environ_find(&global_environ, "HOME"); + if (envent != NULL && *envent->value != '\0') + root = envent->value; + else if ((pw = getpwuid(getuid())) != NULL) + root = pw->pw_dir; + else + return (s->cwd); + +complete_path: + if (root[skip] == '\0') + return (root); + n = snprintf(path, sizeof path, "%s/%s", root, cwd + skip); + if (n > 0 && (size_t)n < sizeof path) + return (path); + return (s->cwd); } diff --git a/tmux.1 b/tmux.1 index d282f1d9..e34eeb73 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1224,6 +1224,7 @@ is moved to .Ar dst-window . .It Xo Ic new-window .Op Fl adkP +.Op Fl c Ar start-directory .Op Fl n Ar window-name .Op Fl t Ar target-window .Op Ar shell-command @@ -1254,6 +1255,15 @@ If is not specified, the value of the .Ic default-command option is used. +.Fl c +specifies the working directory in which the new window is created. +It may have an absolute path or one of the following values (or a subdirectory): +.Bl -column "XXXXXXXXXXXX" "XXXXXXXXXXXXXXXXXXXXXXXX" -offset indent +.It Li "Empty string" Ta "Current pane's directory" +.It Li "~" Ta "User's home directory" +.It Li "-" Ta "Where session was started" +.It Li "." Ta "Where server was started" +.El .Pp When the shell command completes, the window closes. See the @@ -1453,6 +1463,7 @@ and commands. .It Xo Ic split-window .Op Fl dhvP +.Op Fl c Ar start-directory .Oo Fl l .Ar size | .Fl p Ar percentage Oc diff --git a/tmux.h b/tmux.h index a52edf6f..1e1639de 100644 --- a/tmux.h +++ b/tmux.h @@ -1559,7 +1559,7 @@ int cmd_find_index( struct winlink *cmd_find_pane(struct cmd_ctx *, const char *, struct session **, struct window_pane **); char *cmd_template_replace(char *, const char *, int); -const char *cmd_get_default_path(struct cmd_ctx *ctx); +const char *cmd_get_default_path(struct cmd_ctx *, 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 d1ae2d9757138bd778a06ae8841df0cbeac08567 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 2 Feb 2012 00:03:45 +0000 Subject: [PATCH 1021/1180] Get client_width and client_height the right way round, from Stephen Thirlwall. --- format.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/format.c b/format.c index c8502bdd..b7bcd71c 100644 --- a/format.c +++ b/format.c @@ -303,8 +303,8 @@ format_client(struct format_tree *ft, struct client *c) time_t t; format_add(ft, "client_cwd", "%s", c->cwd); - format_add(ft, "client_height", "%u", c->tty.sx); - format_add(ft, "client_width", "%u", c->tty.sy); + format_add(ft, "client_height", "%u", c->tty.sy); + format_add(ft, "client_width", "%u", c->tty.sx); format_add(ft, "client_tty", "%s", c->tty.path); format_add(ft, "client_termname", "%s", c->tty.termname); From fdeaa73342dc92bd8b0119461b6b38e38d495ffc Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 2 Feb 2012 00:04:54 +0000 Subject: [PATCH 1022/1180] Do not change pane when changing window with mouse on status line, pointed out by Romain Francoise. --- server-client.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/server-client.c b/server-client.c index 8efd9d7c..a748d363 100644 --- a/server-client.c +++ b/server-client.c @@ -293,6 +293,8 @@ server_client_check_mouse( } return; } + memcpy(&c->last_mouse, mouse, sizeof c->last_mouse); + return; } /* From 8363d19307c476f6434a91b79fd962814f6acc1a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 2 Feb 2012 00:10:11 +0000 Subject: [PATCH 1023/1180] Move window name changes into wrapper function window_set_name, from George Nachman. --- cmd-break-pane.c | 5 ++++- cmd-new-session.c | 3 +-- cmd-rename-window.c | 3 +-- input.c | 3 +-- tmux.h | 1 + window.c | 8 ++++++++ 6 files changed, 16 insertions(+), 7 deletions(-) diff --git a/cmd-break-pane.c b/cmd-break-pane.c index f6663149..6e455ab9 100644 --- a/cmd-break-pane.c +++ b/cmd-break-pane.c @@ -46,6 +46,7 @@ cmd_break_pane_exec(struct cmd *self, struct cmd_ctx *ctx) struct session *s; struct window_pane *wp; struct window *w; + char *name; char *cause; int base_idx; @@ -74,7 +75,9 @@ cmd_break_pane_exec(struct cmd *self, struct cmd_ctx *ctx) w = wp->window = window_create1(s->sx, s->sy); TAILQ_INSERT_HEAD(&w->panes, wp, entry); w->active = wp; - w->name = default_window_name(w); + name = default_window_name(w); + window_set_name(w, name); + xfree(name); layout_init(w); base_idx = options_get_number(&s->options, "base-index"); diff --git a/cmd-new-session.c b/cmd-new-session.c index d576dc61..5fb9e62c 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -217,8 +217,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) if (cmd != NULL && args_has(args, 'n')) { w = s->curw->window; - xfree(w->name); - w->name = xstrdup(args_get(args, 'n')); + window_set_name(w, args_get(args, 'n')); options_set_number(&w->options, "automatic-rename", 0); } diff --git a/cmd-rename-window.c b/cmd-rename-window.c index 5f4783dd..dc7fec5c 100644 --- a/cmd-rename-window.c +++ b/cmd-rename-window.c @@ -48,8 +48,7 @@ cmd_rename_window_exec(struct cmd *self, struct cmd_ctx *ctx) if ((wl = cmd_find_window(ctx, args_get(args, 't'), &s)) == NULL) return (-1); - xfree(wl->window->name); - wl->window->name = xstrdup(args->argv[0]); + window_set_name(wl->window, args->argv[0]); options_set_number(&wl->window->options, "automatic-rename", 0); server_status_window(wl->window); diff --git a/input.c b/input.c index 957053da..3bbb7ef2 100644 --- a/input.c +++ b/input.c @@ -1552,8 +1552,7 @@ input_exit_rename(struct input_ctx *ictx) return; log_debug("%s: \"%s\"", __func__, ictx->input_buf); - xfree(ictx->wp->window->name); - ictx->wp->window->name = xstrdup(ictx->input_buf); + window_set_name(ictx->wp->window, ictx->input_buf); options_set_number(&ictx->wp->window->options, "automatic-rename", 0); server_status_window(ictx->wp->window); diff --git a/tmux.h b/tmux.h index 1e1639de..0aa2b854 100644 --- a/tmux.h +++ b/tmux.h @@ -1968,6 +1968,7 @@ struct window_pane *window_pane_find_up(struct window_pane *); struct window_pane *window_pane_find_down(struct window_pane *); struct window_pane *window_pane_find_left(struct window_pane *); struct window_pane *window_pane_find_right(struct window_pane *); +void window_set_name(struct window *, const char *); /* layout.c */ u_int layout_count_cells(struct layout_cell *); diff --git a/window.c b/window.c index 1664999c..0489d105 100644 --- a/window.c +++ b/window.c @@ -361,6 +361,14 @@ window_destroy(struct window *w) xfree(w); } +void +window_set_name(struct window *w, const char *new_name) +{ + if (w->name != NULL) + xfree(w->name); + w->name = xstrdup(new_name); +} + void window_resize(struct window *w, u_int sx, u_int sy) { From efb639e1d20d2bd4948dfb2d7c4ede929c423b5f Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 2 Feb 2012 00:15:28 +0000 Subject: [PATCH 1024/1180] Add -l flag to send-keys to send input literally (without translating key names). From Frank Terbeck. --- cmd-send-keys.c | 7 ++++--- tmux.1 | 5 ++++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/cmd-send-keys.c b/cmd-send-keys.c index 2e4775aa..5c92f7dc 100644 --- a/cmd-send-keys.c +++ b/cmd-send-keys.c @@ -31,8 +31,8 @@ int cmd_send_keys_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_send_keys_entry = { "send-keys", "send", - "Rt:", 0, -1, - "[-R] [-t target-pane] key ...", + "lRt:", 0, -1, + "[-lR] [-t target-pane] key ...", 0, NULL, NULL, @@ -71,7 +71,8 @@ cmd_send_keys_exec(struct cmd *self, struct cmd_ctx *ctx) for (i = 0; i < args->argc; i++) { str = args->argv[i]; - if ((key = key_string_lookup_string(str)) != KEYC_NONE) { + if (!args_has(args, 'l') && + (key = key_string_lookup_string(str)) != KEYC_NONE) { window_pane_key(wp, s, key); } else { for (; *str != '\0'; str++) diff --git a/tmux.1 b/tmux.1 index e34eeb73..20837d9d 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1646,7 +1646,7 @@ are listed; this may be one of: or .Em emacs-copy . .It Xo Ic send-keys -.Fl R +.Op Fl lR .Op Fl t Ar target-pane .Ar key Ar ... .Xc @@ -1660,6 +1660,9 @@ or .Ql npage ) to send; if the string is not recognised as a key, it is sent as a series of characters. +The +.Fl l +flag disables key name lookup and sends the keys literally. All arguments are sent sequentially from first to last. The .Fl R From fe7cf0ba90dc99f03ecc778fc8941c3626085910 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 2 Feb 2012 22:33:05 +0000 Subject: [PATCH 1025/1180] Document option values, particularly that omitting on|off for a flag is a toggle. --- tmux.1 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tmux.1 b/tmux.1 index 20837d9d..f930d3e4 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1783,6 +1783,10 @@ It is not possible to unset a global option. Available window options are listed under .Ic set-window-option . .Pp +.Ar value +depends on the option and may be a number, a string, or a flag (on, off, or +omitted to toggle). +.Pp Available server options are: .Bl -tag -width Ds .It Ic buffer-limit Ar number From 3f49137f9027f0c2cf8b0318548a69505c4708ab Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 5 Feb 2012 22:23:13 +0000 Subject: [PATCH 1026/1180] Check for the right return value from sscanf. --- layout-custom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/layout-custom.c b/layout-custom.c index 88fcde1f..8a4f08dc 100644 --- a/layout-custom.c +++ b/layout-custom.c @@ -207,7 +207,7 @@ layout_construct(struct layout_cell *lcparent, const char **layout) if (!isdigit((u_char) **layout)) return (NULL); - if (sscanf(*layout, "%ux%u,%u,%u,%*u", &sx, &sy, &xoff, &yoff) != 5 && + if (sscanf(*layout, "%ux%u,%u,%u,%*u", &sx, &sy, &xoff, &yoff) != 4 && sscanf(*layout, "%ux%u,%u,%u", &sx, &sy, &xoff, &yoff) != 4) return (NULL); From 67949de0a173901fc741674c31bb971172442ec9 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 6 Feb 2012 17:29:29 +0000 Subject: [PATCH 1027/1180] Don't die if fail to get root directory, from Ben Boeckel. --- cmd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmd.c b/cmd.c index 5e2abfec..fbcde912 100644 --- a/cmd.c +++ b/cmd.c @@ -1309,7 +1309,8 @@ cmd_get_default_path(struct cmd_ctx *ctx, const char *cwd) else return (s->cwd); skip = 0; - goto complete_path; + if (root != NULL) + goto complete_path; } return (s->cwd); From fddbd44c185c44ad1fff37d5113519eda883e702 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 15 Feb 2012 17:25:02 +0000 Subject: [PATCH 1028/1180] Add a wrapper function tty_set_size from George Nachman. --- tmux.h | 1 + tty.c | 13 ++++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/tmux.h b/tmux.h index 0aa2b854..52180809 100644 --- a/tmux.h +++ b/tmux.h @@ -1458,6 +1458,7 @@ void tty_putc(struct tty *, u_char); void tty_pututf8(struct tty *, const struct grid_utf8 *); void tty_init(struct tty *, int, char *); int tty_resize(struct tty *); +int tty_set_size(struct tty *tty, u_int sx, u_int sy); void tty_start_tty(struct tty *); void tty_stop_tty(struct tty *); void tty_set_title(struct tty *, const char *); diff --git a/tty.c b/tty.c index 6e3e2cf2..6b0e503d 100644 --- a/tty.c +++ b/tty.c @@ -93,10 +93,8 @@ tty_resize(struct tty *tty) sx = 80; sy = 24; } - if (sx == tty->sx && sy == tty->sy) + if (!tty_set_size(tty, sx, sy)) return (0); - tty->sx = sx; - tty->sy = sy; tty->cx = UINT_MAX; tty->cy = UINT_MAX; @@ -116,6 +114,15 @@ tty_resize(struct tty *tty) return (1); } +int +tty_set_size(struct tty *tty, u_int sx, u_int sy) { + if (sx == tty->sx && sy == tty->sy) + return (0); + tty->sx = sx; + tty->sy = sy; + return (1); +} + int tty_open(struct tty *tty, const char *overrides, char **cause) { From fe055c89f524bf50439ec7bcbc29ae363bf6e6ae Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 15 Feb 2012 18:44:49 +0000 Subject: [PATCH 1029/1180] Sort some entries, from Ben Boeckel. --- options-table.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/options-table.c b/options-table.c index e0a99f43..b68e0b43 100644 --- a/options-table.c +++ b/options-table.c @@ -584,6 +584,21 @@ const struct options_table_entry window_options_table[] = { .default_num = 0 /* overridden in main() */ }, + { .name = "window-status-activity-attr", + .type = OPTIONS_TABLE_ATTRIBUTES, + .default_num = GRID_ATTR_REVERSE + }, + + { .name = "window-status-activity-bg", + .type = OPTIONS_TABLE_COLOUR, + .default_num = 8 + }, + + { .name = "window-status-activity-fg", + .type = OPTIONS_TABLE_COLOUR, + .default_num = 8 + }, + { .name = "window-status-bell-attr", .type = OPTIONS_TABLE_ATTRIBUTES, .default_num = GRID_ATTR_REVERSE @@ -614,21 +629,6 @@ const struct options_table_entry window_options_table[] = { .default_num = 8 }, - { .name = "window-status-activity-attr", - .type = OPTIONS_TABLE_ATTRIBUTES, - .default_num = GRID_ATTR_REVERSE - }, - - { .name = "window-status-activity-bg", - .type = OPTIONS_TABLE_COLOUR, - .default_num = 8 - }, - - { .name = "window-status-activity-fg", - .type = OPTIONS_TABLE_COLOUR, - .default_num = 8 - }, - { .name = "window-status-attr", .type = OPTIONS_TABLE_ATTRIBUTES, .default_num = 0 From aaf0bfccf45b2c2a606ef104b620939a5abcbddc Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 23 Feb 2012 22:40:58 +0000 Subject: [PATCH 1030/1180] Use format for display-message, based on a diff from George Nachman. --- cmd-display-message.c | 40 +++++++++++++++++++++++++++++----------- tmux.1 | 6 +++--- 2 files changed, 32 insertions(+), 14 deletions(-) diff --git a/cmd-display-message.c b/cmd-display-message.c index b2cf832b..fb650501 100644 --- a/cmd-display-message.c +++ b/cmd-display-message.c @@ -30,8 +30,8 @@ int cmd_display_message_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_display_message_entry = { "display-message", "display", - "c:pt:", 0, 1, - "[-p] [-c target-client] [-t target-pane] [message]", + "c:pt:F:", 0, 1, + "[-p] [-c target-client] [-t target-pane] [-F format] [message]", 0, NULL, NULL, @@ -48,26 +48,44 @@ cmd_display_message_exec(struct cmd *self, struct cmd_ctx *ctx) struct window_pane *wp; const char *template; char *msg; + struct format_tree *ft; + char out[BUFSIZ]; + time_t t; if ((c = cmd_find_client(ctx, args_get(args, 'c'))) == NULL) return (-1); - if (args_has(args, 't') != 0) { + if (args_has(args, 't')) { wl = cmd_find_pane(ctx, args_get(args, 't'), &s, &wp); if (wl == NULL) return (-1); } else { - s = NULL; - wl = NULL; - wp = NULL; + wl = cmd_find_pane(ctx, NULL, &s, &wp); + if (wl == NULL) + return (-1); } - if (args->argc == 0) - template = "[#S] #I:#W, current pane #P - (%H:%M %d-%b-%y)"; - else - template = args->argv[0]; + if (args_has(args, 'F') && args->argc != 0) { + ctx->error(ctx, "only one of -F or argument must be given"); + return (-1); + } - msg = status_replace(c, s, wl, wp, template, time(NULL), 0); + template = args_get(args, 'F'); + if (args->argc != 0) + template = args->argv[0]; + if (template == NULL) + template = "[#S] #I:#W, current pane #P - (%H:%M %d-%b-%y)"; + + ft = format_create(); + format_client(ft, c); + format_session(ft, s); + format_winlink(ft, s, wl); + format_window_pane(ft, wp); + + t = time(NULL); + strftime(out, sizeof out, template, localtime(&t)); + + msg = format_expand(ft, out); if (args_has(self->args, 'p')) ctx->print(ctx, "%s", msg); else diff --git a/tmux.1 b/tmux.1 index f930d3e4..73bc5115 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2990,9 +2990,9 @@ is given, the output is printed to stdout, otherwise it is displayed in the status line. The format of .Ar message -is as for -.Ic status-left , -with the exception that #() are not handled; information is taken from +is described in the +.Sx FORMATS +section; information is taken from .Ar target-pane if .Fl t From 4e7de210e4e260b6e29e2cde59d4d879faea5fa5 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 25 Feb 2012 12:57:42 +0000 Subject: [PATCH 1031/1180] Allow a single option to be specified to show-options to show just that option. --- cmd-set-option.c | 38 +------------------------------------- cmd-show-options.c | 28 ++++++++++++++++++++++------ options-table.c | 40 ++++++++++++++++++++++++++++++++++++++++ tmux.1 | 6 ++++-- tmux.h | 3 +++ 5 files changed, 70 insertions(+), 45 deletions(-) diff --git a/cmd-set-option.c b/cmd-set-option.c index 88aa454a..c020b578 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -29,9 +29,6 @@ int cmd_set_option_exec(struct cmd *, struct cmd_ctx *); -int cmd_set_option_find(const char *, const struct options_table_entry **, - const struct options_table_entry **); - int cmd_set_option_unset(struct cmd *, struct cmd_ctx *, const struct options_table_entry *, struct options *, const char *); @@ -81,39 +78,6 @@ const struct cmd_entry cmd_set_window_option_entry = { cmd_set_option_exec }; -/* Look for an option in all three tables. */ -int -cmd_set_option_find( - const char *optstr, const struct options_table_entry **table, - const struct options_table_entry **oe) -{ - static const struct options_table_entry *tables[] = { - server_options_table, - window_options_table, - session_options_table - }; - const struct options_table_entry *oe_loop; - u_int i; - - for (i = 0; i < nitems(tables); i++) { - for (oe_loop = tables[i]; oe_loop->name != NULL; oe_loop++) { - if (strncmp(oe_loop->name, optstr, strlen(optstr)) != 0) - continue; - - /* If already found, ambiguous. */ - if (*oe != NULL) - return (-1); - *oe = oe_loop; - *table = tables[i]; - - /* Bail now if an exact match. */ - if (strcmp((*oe)->name, optstr) == 0) - break; - } - } - return (0); -} - int cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) { @@ -139,7 +103,7 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) /* Find the option entry, try each table. */ table = oe = NULL; - if (cmd_set_option_find(optstr, &table, &oe) != 0) { + if (options_table_find(optstr, &table, &oe) != 0) { ctx->error(ctx, "ambiguous option: %s", optstr); return (-1); } diff --git a/cmd-show-options.c b/cmd-show-options.c index 2a4adb0f..7df62a04 100644 --- a/cmd-show-options.c +++ b/cmd-show-options.c @@ -31,8 +31,8 @@ int cmd_show_options_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_show_options_entry = { "show-options", "show", - "gst:w", 0, 0, - "[-gsw] [-t target-session|target-window]", + "gst:w", 0, 1, + "[-gsw] [-t target-session|target-window] [option]", 0, NULL, NULL, @@ -41,8 +41,8 @@ const struct cmd_entry cmd_show_options_entry = { const struct cmd_entry cmd_show_window_options_entry = { "show-window-options", "showw", - "gt:", 0, 0, - "[-g] " CMD_TARGET_WINDOW_USAGE, + "gt:", 0, 1, + "[-g] " CMD_TARGET_WINDOW_USAGE " [option]", 0, NULL, NULL, @@ -86,11 +86,27 @@ cmd_show_options_exec(struct cmd *self, struct cmd_ctx *ctx) } } - for (oe = table; oe->name != NULL; oe++) { + if (args->argc != 0) { + table = oe = NULL; + if (options_table_find(args->argv[0], &table, &oe) != 0) { + ctx->error(ctx, "ambiguous option: %s", args->argv[0]); + return (-1); + } + if (oe == NULL) { + ctx->error(ctx, "unknown option: %s", args->argv[0]); + return (-1); + } if ((o = options_find1(oo, oe->name)) == NULL) - continue; + return (0); optval = options_table_print_entry(oe, o); ctx->print(ctx, "%s %s", oe->name, optval); + } else { + for (oe = table; oe->name != NULL; oe++) { + if ((o = options_find1(oo, oe->name)) == NULL) + continue; + optval = options_table_print_entry(oe, o); + ctx->print(ctx, "%s %s", oe->name, optval); + } } return (0); diff --git a/options-table.c b/options-table.c index b68e0b43..dfb8650a 100644 --- a/options-table.c +++ b/options-table.c @@ -569,6 +569,13 @@ const struct options_table_entry window_options_table[] = { .default_num = 0 }, + { .name = "rate-limit", + .type = OPTIONS_TABLE_NUMBER, + .minimum = 0, + .maximum = UINT_MAX, + .default_num = 0 + }, + { .name = "remain-on-exit", .type = OPTIONS_TABLE_FLAG, .default_num = 0 @@ -732,3 +739,36 @@ options_table_print_entry( } return (out); } + +/* Find an option. */ +int +options_table_find( + const char *optstr, const struct options_table_entry **table, + const struct options_table_entry **oe) +{ + static const struct options_table_entry *tables[] = { + server_options_table, + window_options_table, + session_options_table + }; + const struct options_table_entry *oe_loop; + u_int i; + + for (i = 0; i < nitems(tables); i++) { + for (oe_loop = tables[i]; oe_loop->name != NULL; oe_loop++) { + if (strncmp(oe_loop->name, optstr, strlen(optstr)) != 0) + continue; + + /* If already found, ambiguous. */ + if (*oe != NULL) + return (-1); + *oe = oe_loop; + *table = tables[i]; + + /* Bail now if an exact match. */ + if (strcmp((*oe)->name, optstr) == 0) + break; + } + } + return (0); +} diff --git a/tmux.1 b/tmux.1 index 73bc5115..15306d5e 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2622,9 +2622,10 @@ The default is off. .It Xo Ic show-options .Op Fl gsw .Op Fl t Ar target-session | Ar target-window +.Op Ar option .Xc .D1 (alias: Ic show ) -Show the window options with +Show the window options (or a single window option if given) with .Fl w (equivalent to .Ic show-window-options ) , @@ -2638,9 +2639,10 @@ is used. .It Xo Ic show-window-options .Op Fl g .Op Fl t Ar target-window +.Op Ar option .Xc .D1 (alias: Ic showw ) -List the window options for +List the window options or a single option for .Ar target-window , or the global window options if .Fl g diff --git a/tmux.h b/tmux.h index 52180809..0a484187 100644 --- a/tmux.h +++ b/tmux.h @@ -1419,6 +1419,9 @@ void options_table_populate_tree( const struct options_table_entry *, struct options *); const char *options_table_print_entry( const struct options_table_entry *, struct options_entry *); +int options_table_find( + const char *, const struct options_table_entry **, + const struct options_table_entry **); /* job.c */ extern struct joblist all_jobs; From 952ffdd28826a611c3c3374f1d1629ecd5bc7195 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 29 Feb 2012 21:10:51 +0000 Subject: [PATCH 1032/1180] Remove accidentally committed option. --- options-table.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/options-table.c b/options-table.c index dfb8650a..305bada8 100644 --- a/options-table.c +++ b/options-table.c @@ -569,13 +569,6 @@ const struct options_table_entry window_options_table[] = { .default_num = 0 }, - { .name = "rate-limit", - .type = OPTIONS_TABLE_NUMBER, - .minimum = 0, - .maximum = UINT_MAX, - .default_num = 0 - }, - { .name = "remain-on-exit", .type = OPTIONS_TABLE_FLAG, .default_num = 0 From 4d9ccd322909334b896d6a0420ea747898799385 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 2 Mar 2012 11:16:44 +0000 Subject: [PATCH 1033/1180] Add printf attribute to a couple of functions, from Tim Ruehsen. --- tmux.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tmux.h b/tmux.h index 0a484187..9b1df265 100644 --- a/tmux.h +++ b/tmux.h @@ -1367,7 +1367,7 @@ int format_cmp(struct format_entry *, struct format_entry *); RB_PROTOTYPE(format_tree, format_entry, entry, format_cmp); struct format_tree *format_create(void); void format_free(struct format_tree *); -void format_add( +void printflike3 format_add( struct format_tree *, const char *, const char *, ...); const char *format_find(struct format_tree *, const char *); char *format_expand(struct format_tree *, const char *); @@ -2021,7 +2021,7 @@ extern const struct window_mode window_clock_mode; extern const struct window_mode window_copy_mode; void window_copy_init_from_pane(struct window_pane *); void window_copy_init_for_output(struct window_pane *); -void window_copy_add(struct window_pane *, const char *, ...); +void printflike2 window_copy_add(struct window_pane *, const char *, ...); void window_copy_vadd(struct window_pane *, const char *, va_list); void window_copy_pageup(struct window_pane *); From 07ac16807f85d7bd5e7c7570f2b11250c65b6228 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 3 Mar 2012 08:31:18 +0000 Subject: [PATCH 1034/1180] Add move-pane command (like join-pane but allows the same window). Also -b flag to join-pane and move-pane to place the pane to the left or above. From George Nachman. --- cmd-join-pane.c | 35 +++++++++++++++++++++++++++++------ cmd-split-window.c | 2 +- cmd.c | 1 + layout.c | 33 ++++++++++++++++++++++++--------- tmux.1 | 24 +++++++++++++++++++++++- tmux.h | 3 ++- 6 files changed, 80 insertions(+), 18 deletions(-) diff --git a/cmd-join-pane.c b/cmd-join-pane.c index 0bfefd2f..03fb4317 100644 --- a/cmd-join-pane.c +++ b/cmd-join-pane.c @@ -1,6 +1,7 @@ /* $OpenBSD$ */ /* + * Copyright (c) 2011 George Nachman * Copyright (c) 2009 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any @@ -25,22 +26,34 @@ #include "tmux.h" /* - * Join a pane into another (like split/swap/kill). + * Join or move a pane into another (like split/swap/kill). */ void cmd_join_pane_key_binding(struct cmd *, int); int cmd_join_pane_exec(struct cmd *, struct cmd_ctx *); +int join_pane(struct cmd *, struct cmd_ctx *, int); + const struct cmd_entry cmd_join_pane_entry = { "join-pane", "joinp", - "dhvp:l:s:t:", 0, 0, - "[-dhv] [-p percentage|-l size] [-s src-pane] [-t dst-pane]", + "bdhvp:l:s:t:", 0, 0, + "[-bdhv] [-p percentage|-l size] [-s src-pane] [-t dst-pane]", 0, cmd_join_pane_key_binding, NULL, cmd_join_pane_exec }; +const struct cmd_entry cmd_move_pane_entry = { + "move-pane", "movep", + "bdhvp:l:s:t:", 0, 0, + "[-bdhv] [-p percentage|-l size] [-s src-pane] [-t dst-pane]", + 0, + NULL, + NULL, + cmd_join_pane_exec +}; + void cmd_join_pane_key_binding(struct cmd *self, int key) { @@ -57,6 +70,12 @@ cmd_join_pane_key_binding(struct cmd *self, int key) int cmd_join_pane_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + return join_pane(self, ctx, self->entry == &cmd_join_pane_entry); +} + +int +join_pane(struct cmd *self, struct cmd_ctx *ctx, int not_same_window) { struct args *args = self->args; struct session *dst_s; @@ -79,10 +98,14 @@ cmd_join_pane_exec(struct cmd *self, struct cmd_ctx *ctx) return (-1); src_w = src_wl->window; - if (src_w == dst_w) { + if (not_same_window && src_w == dst_w) { ctx->error(ctx, "can't join a pane to its own window"); return (-1); } + if (!not_same_window && src_wp == dst_wp) { + ctx->error(ctx, "source and target panes must be different"); + return (-1); + } type = LAYOUT_TOPBOTTOM; if (args_has(args, 'h')) @@ -108,8 +131,8 @@ cmd_join_pane_exec(struct cmd *self, struct cmd_ctx *ctx) else size = (dst_wp->sx * percentage) / 100; } - - if ((lc = layout_split_pane(dst_wp, type, size)) == NULL) { + lc = layout_split_pane(dst_wp, type, size, args_has(args, 'b')); + if (lc == NULL) { ctx->error(ctx, "create pane failed: pane too small"); return (-1); } diff --git a/cmd-split-window.c b/cmd-split-window.c index 5aa0af5f..3c7878f0 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -113,7 +113,7 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) if (*shell == '\0' || areshell(shell)) shell = _PATH_BSHELL; - if ((lc = layout_split_pane(wp, type, size)) == NULL) { + if ((lc = layout_split_pane(wp, type, size, 0)) == NULL) { cause = xstrdup("pane too small"); goto error; } diff --git a/cmd.c b/cmd.c index fbcde912..1bc17e22 100644 --- a/cmd.c +++ b/cmd.c @@ -68,6 +68,7 @@ const struct cmd_entry *cmd_table[] = { &cmd_lock_client_entry, &cmd_lock_server_entry, &cmd_lock_session_entry, + &cmd_move_pane_entry, &cmd_move_window_entry, &cmd_new_session_entry, &cmd_new_window_entry, diff --git a/layout.c b/layout.c index 429e103e..1050efc4 100644 --- a/layout.c +++ b/layout.c @@ -616,9 +616,10 @@ layout_assign_pane(struct layout_cell *lc, struct window_pane *wp) * split. This must be followed by layout_assign_pane before much else happens! **/ struct layout_cell * -layout_split_pane(struct window_pane *wp, enum layout_type type, int size) +layout_split_pane( + struct window_pane *wp, enum layout_type type, int size, int insert_before) { - struct layout_cell *lc, *lcparent, *lcnew; + struct layout_cell *lc, *lcparent, *lcnew, *lc1, *lc2; u_int sx, sy, xoff, yoff, size1, size2; lc = wp->layout_cell; @@ -650,8 +651,12 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size) */ /* Create the new child cell. */ - lcnew = layout_create_cell(lc->parent); - TAILQ_INSERT_AFTER(&lc->parent->cells, lc, lcnew, entry); + lcparent = lc->parent; + lcnew = layout_create_cell(lcparent); + if (insert_before) + TAILQ_INSERT_BEFORE(lc, lcnew, entry); + else + TAILQ_INSERT_AFTER(&lcparent->cells, lc, lcnew, entry); } else { /* * Otherwise create a new parent and insert it. @@ -672,7 +677,17 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size) /* Create the new child cell. */ lcnew = layout_create_cell(lcparent); - TAILQ_INSERT_TAIL(&lcparent->cells, lcnew, entry); + if (insert_before) + TAILQ_INSERT_HEAD(&lcparent->cells, lcnew, entry); + else + TAILQ_INSERT_TAIL(&lcparent->cells, lcnew, entry); + } + if (insert_before) { + lc1 = lcnew; + lc2 = lc; + } else { + lc1 = lc; + lc2 = lcnew; } /* Set new cell sizes. size is the target size or -1 for middle split, @@ -689,8 +704,8 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size) else if (size2 > sx - 2) size2 = sx - 2; size1 = sx - 1 - size2; - layout_set_size(lc, size1, sy, xoff, yoff); - layout_set_size(lcnew, size2, sy, xoff + lc->sx + 1, yoff); + layout_set_size(lc1, size1, sy, xoff, yoff); + layout_set_size(lc2, size2, sy, xoff + lc1->sx + 1, yoff); break; case LAYOUT_TOPBOTTOM: if (size < 0) @@ -702,8 +717,8 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size) else if (size2 > sy - 2) size2 = sy - 2; size1 = sy - 1 - size2; - layout_set_size(lc, sx, size1, xoff, yoff); - layout_set_size(lcnew, sx, size2, xoff, yoff + lc->sy + 1); + layout_set_size(lc1, sx, size1, xoff, yoff); + layout_set_size(lc2, sx, size2, xoff, yoff + lc1->sy + 1); break; default: fatalx("bad layout type"); diff --git a/tmux.1 b/tmux.1 index 15306d5e..133af6ca 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1105,7 +1105,7 @@ choice list is shown. This command only works from inside .Nm . .It Xo Ic join-pane -.Op Fl dhv +.Op Fl bdhv .Oo Fl l .Ar size | .Fl p Ar percentage Oc @@ -1122,6 +1122,12 @@ and creating a new pane, split it and move into the space. This can be used to reverse .Ic break-pane . +The +.Fl b +option causes +.Ar src-pane +to be joined to left of or above +.Ar dst-pane . .It Xo Ic kill-pane .Op Fl a .Op Fl t Ar target-pane @@ -1210,6 +1216,22 @@ For the meaning of the flag, see the .Sx FORMATS section. +.It Xo Ic move-pane +.Op Fl bdhv +.Oo Fl l +.Ar size | +.Fl p Ar percentage Oc +.Op Fl s Ar src-pane +.Op Fl t Ar dst-pane +.Xc +.D1 (alias: Ic movep ) +Like +.Ic join-pane , +but +.Ar src-pane +and +.Ar dst-pane +may belong to the same window. .It Xo Ic move-window .Op Fl dk .Op Fl s Ar src-window diff --git a/tmux.h b/tmux.h index 9b1df265..51fe79a4 100644 --- a/tmux.h +++ b/tmux.h @@ -1605,6 +1605,7 @@ extern const struct cmd_entry cmd_load_buffer_entry; extern const struct cmd_entry cmd_lock_client_entry; extern const struct cmd_entry cmd_lock_server_entry; extern const struct cmd_entry cmd_lock_session_entry; +extern const struct cmd_entry cmd_move_pane_entry; extern const struct cmd_entry cmd_move_window_entry; extern const struct cmd_entry cmd_new_session_entry; extern const struct cmd_entry cmd_new_window_entry; @@ -1999,7 +2000,7 @@ void layout_resize_pane_mouse( struct client *c, struct mouse_event *mouse); void layout_assign_pane(struct layout_cell *, struct window_pane *); struct layout_cell *layout_split_pane( - struct window_pane *, enum layout_type, int); + struct window_pane *, enum layout_type, int, int); void layout_close_pane(struct window_pane *); /* layout-custom.c */ From 4b8bb7770fc06ae61942372ff7edc38b64efb58d Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 3 Mar 2012 08:55:56 +0000 Subject: [PATCH 1035/1180] The wlmouse offset should be part of the client, not the server. From Ailin Nemui. --- status.c | 4 ++-- tmux.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/status.c b/status.c index fee9f2d6..af35ff64 100644 --- a/status.c +++ b/status.c @@ -141,7 +141,7 @@ status_set_window_at(struct client *c, u_int x) struct session *s = c->session; struct winlink *wl; - x += s->wlmouse; + x += c->wlmouse; RB_FOREACH(wl, winlinks, &s->windows) { if (x < wl->status_width && session_select(s, wl->idx) == 0) { @@ -356,7 +356,7 @@ draw: wloffset++; /* Copy the window list. */ - s->wlmouse = -wloffset + wlstart; + c->wlmouse = -wloffset + wlstart; screen_write_cursormove(&ctx, wloffset, 0); screen_write_copy(&ctx, &window_list, wlstart, 0, wlwidth, 1); screen_free(&window_list); diff --git a/tmux.h b/tmux.h index 51fe79a4..a2c1d9fb 100644 --- a/tmux.h +++ b/tmux.h @@ -975,8 +975,6 @@ struct session { struct environ environ; - int wlmouse; - int references; TAILQ_ENTRY(session) gentry; @@ -1199,6 +1197,8 @@ struct client { struct mouse_event last_mouse; + int wlmouse; + int references; }; ARRAY_DECL(clients, struct client *); From f4fdddc9306886e3ab5257f40003f6db83ac926b Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 3 Mar 2012 09:43:22 +0000 Subject: [PATCH 1036/1180] Support "bracketed paste" mode. This adds a -p flag to paste-buffer - if this is used and the application has requested bracketed pastes, then tmux surrounds the pasted text by \033[200~ and \033[201~. Applications like vim can (apparently) use this to avoid, for example, indenting the text. From Ailin Nemui. --- cmd-paste-buffer.c | 23 ++++++++++++++++------- input.c | 6 ++++++ screen-write.c | 12 ++++++++++++ tmux.1 | 6 +++++- tmux.h | 2 ++ tty.c | 6 ++++++ 6 files changed, 47 insertions(+), 8 deletions(-) diff --git a/cmd-paste-buffer.c b/cmd-paste-buffer.c index 0d145c7d..db20643c 100644 --- a/cmd-paste-buffer.c +++ b/cmd-paste-buffer.c @@ -30,13 +30,13 @@ int cmd_paste_buffer_exec(struct cmd *, struct cmd_ctx *); -void cmd_paste_buffer_filter( - struct window_pane *, const char *, size_t, const char *); +void cmd_paste_buffer_filter(struct window_pane *, + const char *, size_t, const char *, int bracket); const struct cmd_entry cmd_paste_buffer_entry = { "paste-buffer", "pasteb", - "db:rs:t:", 0, 0, - "[-dr] [-s separator] [-b buffer-index] [-t target-pane]", + "db:prs:t:", 0, 0, + "[-dpr] [-s separator] [-b buffer-index] [-t target-pane]", 0, NULL, NULL, @@ -53,6 +53,7 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) const char *sepstr; char *cause; int buffer; + int pflag; if (cmd_find_pane(ctx, args_get(args, 't'), &s, &wp) == NULL) return (-1); @@ -86,7 +87,9 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) else sepstr = "\r"; } - cmd_paste_buffer_filter(wp, pb->data, pb->size, sepstr); + pflag = args_has(args, 'p') && + (wp->screen->mode & MODE_BRACKETPASTE); + cmd_paste_buffer_filter(wp, pb->data, pb->size, sepstr, pflag); } /* Delete the buffer if -d. */ @@ -102,13 +105,16 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) /* Add bytes to a buffer and filter '\n' according to separator. */ void -cmd_paste_buffer_filter( - struct window_pane *wp, const char *data, size_t size, const char *sep) +cmd_paste_buffer_filter(struct window_pane *wp, + const char *data, size_t size, const char *sep, int bracket) { const char *end = data + size; const char *lf; size_t seplen; + if (bracket) + bufferevent_write(wp->event, "\033[200~", 6); + seplen = strlen(sep); while ((lf = memchr(data, '\n', end - data)) != NULL) { if (lf != data) @@ -119,4 +125,7 @@ cmd_paste_buffer_filter( if (end != data) bufferevent_write(wp->event, data, end - data); + + if (bracket) + bufferevent_write(wp->event, "\033[201~", 6); } diff --git a/input.c b/input.c index 3bbb7ef2..c12e1b29 100644 --- a/input.c +++ b/input.c @@ -1212,6 +1212,9 @@ input_csi_dispatch(struct input_ctx *ictx) case 1049: window_pane_alternate_off(wp, &ictx->cell); break; + case 2004: + screen_write_bracketpaste(&ictx->ctx, 0); + break; default: log_debug("%s: unknown '%c'", __func__, ictx->ch); break; @@ -1264,6 +1267,9 @@ input_csi_dispatch(struct input_ctx *ictx) case 1049: window_pane_alternate_on(wp, &ictx->cell); break; + case 2004: + screen_write_bracketpaste(&ictx->ctx, 1); + break; default: log_debug("%s: unknown '%c'", __func__, ictx->ch); break; diff --git a/screen-write.c b/screen-write.c index 784f02e2..d8659593 100644 --- a/screen-write.c +++ b/screen-write.c @@ -878,6 +878,18 @@ screen_write_mousemode_on(struct screen_write_ctx *ctx, int mode) s->mode |= mode; } +/* Set bracketed paste mode. */ +void +screen_write_bracketpaste(struct screen_write_ctx *ctx, int state) +{ + struct screen *s = ctx->s; + + if (state) + s->mode |= MODE_BRACKETPASTE; + else + s->mode &= ~MODE_BRACKETPASTE; +} + /* Line feed. */ void screen_write_linefeed(struct screen_write_ctx *ctx, int wrapped) diff --git a/tmux.1 b/tmux.1 index 133af6ca..6bef3e67 100644 --- a/tmux.1 +++ b/tmux.1 @@ -3084,7 +3084,7 @@ List the global buffers. Load the contents of the specified paste buffer from .Ar path . .It Xo Ic paste-buffer -.Op Fl dr +.Op Fl dpr .Op Fl b Ar buffer-index .Op Fl s Ar separator .Op Fl t Ar target-pane @@ -3103,6 +3103,10 @@ flag. The .Fl r flag means to do no replacement (equivalent to a separator of LF). +If +.Fl p +is specified, paste bracket control codes are inserted around the +buffer if the application has requested bracketed paste mode. .It Xo Ic save-buffer .Op Fl a .Op Fl b Ar buffer-index diff --git a/tmux.h b/tmux.h index a2c1d9fb..33e82ac0 100644 --- a/tmux.h +++ b/tmux.h @@ -573,6 +573,7 @@ struct mode_key_table { #define MODE_MOUSE_BUTTON 0x40 #define MODE_MOUSE_ANY 0x80 #define MODE_MOUSE_UTF8 0x100 +#define MODE_BRACKETPASTE 0x200 #define ALL_MOUSE_MODES (MODE_MOUSE_STANDARD|MODE_MOUSE_BUTTON|MODE_MOUSE_ANY) @@ -1883,6 +1884,7 @@ void screen_write_cell(struct screen_write_ctx *, const struct grid_cell *, const struct utf8_data *); void screen_write_setselection(struct screen_write_ctx *, u_char *, u_int); void screen_write_rawstring(struct screen_write_ctx *, u_char *, u_int); +void screen_write_bracketpaste(struct screen_write_ctx *, int); /* screen-redraw.c */ void screen_redraw_screen(struct client *, int, int); diff --git a/tty.c b/tty.c index 6b0e503d..bbe2f1da 100644 --- a/tty.c +++ b/tty.c @@ -480,6 +480,12 @@ tty_update_mode(struct tty *tty, int mode, struct screen *s) else tty_putcode(tty, TTYC_RMKX); } + if (changed & MODE_BRACKETPASTE) { + if (mode & MODE_BRACKETPASTE) + tty_puts(tty, "\033[?2004h"); + else + tty_puts(tty, "\033[?2004l"); + } tty->mode = mode; } From 8b68ea146212cd56139ca9838e146ab018c2b8bc Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 3 Mar 2012 09:45:41 +0000 Subject: [PATCH 1037/1180] Terminate strftime buffer properly and free format string, whoops. From Tiago Cunha. --- cmd-display-message.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/cmd-display-message.c b/cmd-display-message.c index fb650501..d8b623b9 100644 --- a/cmd-display-message.c +++ b/cmd-display-message.c @@ -51,6 +51,7 @@ cmd_display_message_exec(struct cmd *self, struct cmd_ctx *ctx) struct format_tree *ft; char out[BUFSIZ]; time_t t; + size_t len; if ((c = cmd_find_client(ctx, args_get(args, 'c'))) == NULL) return (-1); @@ -83,14 +84,16 @@ cmd_display_message_exec(struct cmd *self, struct cmd_ctx *ctx) format_window_pane(ft, wp); t = time(NULL); - strftime(out, sizeof out, template, localtime(&t)); + len = strftime(out, sizeof out, template, localtime(&t)); + out[len] = '\0'; msg = format_expand(ft, out); if (args_has(self->args, 'p')) ctx->print(ctx, "%s", msg); else status_message_set(c, "%s", msg); - xfree(msg); + xfree(msg); + format_free(ft); return (0); } From 30f4c30ca3ff53684282c83384796d600eae7e74 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 4 Mar 2012 07:38:11 +0000 Subject: [PATCH 1038/1180] Add A and I keys for vi status line editing. --- mode-key.c | 11 +++++++++-- status.c | 6 ++++++ tmux.h | 2 ++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/mode-key.c b/mode-key.c index 43d07c0f..d6906d45 100644 --- a/mode-key.c +++ b/mode-key.c @@ -35,8 +35,9 @@ * * vi command mode is handled by having a mode flag in the struct which allows * two sets of bindings to be swapped between. A couple of editing commands - * (MODEKEYEDIT_SWITCHMODE and MODEKEYEDIT_SWITCHMODEAPPEND) are special-cased - * to do this. + * (MODEKEYEDIT_SWITCHMODE, MODEKEYEDIT_SWITCHMODEAPPEND, + * MODEKEYEDIT_SWITCHMODEAPPENDLINE, and MODEKEYEDIT_SWITCHMODEBEGINLINE) + * are special-cased to do this. */ /* Edit keys command strings. */ @@ -64,6 +65,8 @@ const struct mode_key_cmdstr mode_key_cmdstr_edit[] = { { MODEKEYEDIT_STARTOFLINE, "start-of-line" }, { MODEKEYEDIT_SWITCHMODE, "switch-mode" }, { MODEKEYEDIT_SWITCHMODEAPPEND, "switch-mode-append" }, + { MODEKEYEDIT_SWITCHMODEAPPENDLINE, "switch-mode-append-line" }, + { MODEKEYEDIT_SWITCHMODEBEGINLINE, "switch-mode-begin-line" }, { MODEKEYEDIT_TRANSPOSECHARS, "transpose-chars" }, { 0, NULL } @@ -151,9 +154,11 @@ const struct mode_key_entry mode_key_vi_edit[] = { { '$', 1, MODEKEYEDIT_ENDOFLINE }, { '0', 1, MODEKEYEDIT_STARTOFLINE }, + { 'A', 1, MODEKEYEDIT_SWITCHMODEAPPENDLINE }, { 'B', 1, MODEKEYEDIT_PREVIOUSSPACE }, { 'D', 1, MODEKEYEDIT_DELETETOENDOFLINE }, { 'E', 1, MODEKEYEDIT_NEXTSPACEEND }, + { 'I', 1, MODEKEYEDIT_SWITCHMODEBEGINLINE }, { 'W', 1, MODEKEYEDIT_NEXTSPACE }, { 'X', 1, MODEKEYEDIT_BACKSPACE }, { '\003' /* C-c */, 1, MODEKEYEDIT_CANCEL }, @@ -496,6 +501,8 @@ mode_key_lookup(struct mode_key_data *mdata, int key) switch (mbind->cmd) { case MODEKEYEDIT_SWITCHMODE: case MODEKEYEDIT_SWITCHMODEAPPEND: + case MODEKEYEDIT_SWITCHMODEAPPENDLINE: + case MODEKEYEDIT_SWITCHMODEBEGINLINE: mdata->mode = 1 - mdata->mode; /* FALLTHROUGH */ default: diff --git a/status.c b/status.c index af35ff64..0342b5f1 100644 --- a/status.c +++ b/status.c @@ -1038,12 +1038,18 @@ status_prompt_key(struct client *c, int key) c->flags |= CLIENT_STATUS; } break; + case MODEKEYEDIT_SWITCHMODEBEGINLINE: + c->flags |= CLIENT_STATUS; + /* FALLTHROUGH */ case MODEKEYEDIT_STARTOFLINE: if (c->prompt_index != 0) { c->prompt_index = 0; c->flags |= CLIENT_STATUS; } break; + case MODEKEYEDIT_SWITCHMODEAPPENDLINE: + c->flags |= CLIENT_STATUS; + /* FALLTHROUGH */ case MODEKEYEDIT_ENDOFLINE: if (c->prompt_index != size) { c->prompt_index = size; diff --git a/tmux.h b/tmux.h index 33e82ac0..6503d886 100644 --- a/tmux.h +++ b/tmux.h @@ -457,6 +457,8 @@ enum mode_key_cmd { MODEKEYEDIT_STARTOFLINE, MODEKEYEDIT_SWITCHMODE, MODEKEYEDIT_SWITCHMODEAPPEND, + MODEKEYEDIT_SWITCHMODEAPPENDLINE, + MODEKEYEDIT_SWITCHMODEBEGINLINE, MODEKEYEDIT_TRANSPOSECHARS, /* Menu (choice) keys. */ From 178a20718c007a254611d4f02c4c6f3ca7184d8d Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 4 Mar 2012 20:40:54 +0000 Subject: [PATCH 1039/1180] Accept hex values as keys, needed for send-keys, based on a diff from George Nachman. --- key-string.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/key-string.c b/key-string.c index 08cf0b9c..e06a71eb 100644 --- a/key-string.c +++ b/key-string.c @@ -137,6 +137,15 @@ int key_string_lookup_string(const char *string) { int key, modifiers; + u_short u; + int size; + + /* Is this a hexadecimal value? */ + if (string[0] == '0' && string[1] == 'x') { + if (sscanf(string + 2, "%hx%n", &u, &size) != 1 || size > 4) + return (KEYC_NONE); + return (u); + } /* Check for modifiers. */ modifiers = 0; From 03dca66ae207e5b2d98a9cd337d472ea26bb95c6 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 4 Mar 2012 20:50:53 +0000 Subject: [PATCH 1040/1180] Add -F format to new-window and split-window to use with the -P flag, from George Nachman. --- cmd-new-window.c | 42 +++++++++++++++++++++++++++++++----------- cmd-split-window.c | 33 +++++++++++++++++++++++++-------- tmux.1 | 8 +++++++- 3 files changed, 63 insertions(+), 20 deletions(-) diff --git a/cmd-new-window.c b/cmd-new-window.c index cf93567d..2d409399 100644 --- a/cmd-new-window.c +++ b/cmd-new-window.c @@ -30,9 +30,9 @@ int cmd_new_window_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_new_window_entry = { "new-window", "neww", - "ac:dkn:Pt:", 0, 1, - "[-adk] [-c start-directory] [-n window-name] [-t target-window] " - "[command]", + "ac:dF:kn:Pt:", 0, 1, + "[-adkP] [-c start-directory] [-F format] [-n window-name] " + "[-t target-window] [command]", 0, NULL, NULL, @@ -42,12 +42,16 @@ const struct cmd_entry cmd_new_window_entry = { int cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct args *args = self->args; - struct session *s; - struct winlink *wl; - const char *cmd, *cwd; - char *cause; - int idx, last, detached; + struct args *args = self->args; + struct session *s; + struct winlink *wl; + struct client *c; + const char *cmd, *cwd; + const char *template; + char *cause; + int idx, last, detached; + struct format_tree *ft; + char *cp; if (args_has(args, 'a')) { wl = cmd_find_window(ctx, args_get(args, 't'), &s); @@ -116,7 +120,23 @@ cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx) } else server_status_session_group(s); - if (args_has(args, 'P')) - ctx->print(ctx, "%s:%u", s->name, wl->idx); + if (args_has(args, 'P')) { + template = "#{session_name}:#{window_index}"; + if (args_has(args, 'F')) + template = args_get(args, 'F'); + + ft = format_create(); + if ((c = cmd_find_client(ctx, NULL)) != NULL) + format_client(ft, c); + format_session(ft, s); + format_winlink(ft, s, wl); + + cp = format_expand(ft, template); + ctx->print(ctx, "%s", cp); + free(cp); + + format_free(ft); + } + return (0); } diff --git a/cmd-split-window.c b/cmd-split-window.c index 3c7878f0..5addd107 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -33,9 +33,9 @@ int cmd_split_window_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_split_window_entry = { "split-window", "splitw", - "c:dl:hp:Pt:v", 0, 1, - "[-dhvP] [-c start-directory] [-p percentage|-l size] [-t target-pane] " - "[command]", + "c:dF:l:hp:Pt:v", 0, 1, + "[-dhvP] [-c start-directory] [-F format] [-p percentage|-l size] " + "[-t target-pane] [command]", 0, cmd_split_window_key_binding, NULL, @@ -59,12 +59,16 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) struct window *w; struct window_pane *wp, *new_wp = NULL; struct environ env; - const char *cmd, *cwd, *shell; + const char *cmd, *cwd, *shell; char *cause, *new_cause; - u_int hlimit, paneidx; + u_int hlimit; int size, percentage; enum layout_type type; struct layout_cell *lc; + const char *template; + struct client *c; + struct format_tree *ft; + char *cp; if ((wl = cmd_find_pane(ctx, args_get(args, 't'), &s, &wp)) == NULL) return (-1); @@ -135,9 +139,22 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) environ_free(&env); if (args_has(args, 'P')) { - if (window_pane_index(new_wp, &paneidx) != 0) - fatalx("index not found"); - ctx->print(ctx, "%s:%u.%u", s->name, wl->idx, paneidx); + template = "#{session_name}:#{window_index}.#{pane_index}"; + if (args_has(args, 'F')) + template = args_get(args, 'F'); + + ft = format_create(); + if ((c = cmd_find_client(ctx, NULL)) != NULL) + format_client(ft, c); + format_session(ft, s); + format_winlink(ft, s, wl); + format_window_pane(ft, new_wp); + + cp = format_expand(ft, template); + ctx->print(ctx, "%s", cp); + free(cp); + + format_free(ft); } return (0); diff --git a/tmux.1 b/tmux.1 index 6bef3e67..a7950d26 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1249,6 +1249,7 @@ is moved to .Op Fl c Ar start-directory .Op Fl n Ar window-name .Op Fl t Ar target-window +.Op Fl F Ar format .Op Ar shell-command .Xc .D1 (alias: Ic neww ) @@ -1306,7 +1307,11 @@ start-up files. .Pp The .Fl P -option prints the location of the new window after it has been created. +option prints information about the new window after it has been created. +By default, it uses the format +.Ql #{session_name}:#{window_index} +but a different format may be specified with +.Fl F . .It Ic next-layout Op Fl t Ar target-window .D1 (alias: Ic nextl ) Move a window to the next layout and rearrange the panes to fit. @@ -1491,6 +1496,7 @@ commands. .Fl p Ar percentage Oc .Op Fl t Ar target-pane .Op Ar shell-command +.Op Fl F Ar format .Xc .D1 (alias: Ic splitw ) Create a new pane by splitting From 18012f5b18e0ff8bdb95d70dd0fbc9c03a05f2f5 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 4 Mar 2012 20:52:05 +0000 Subject: [PATCH 1041/1180] free -> xfree. --- cmd-new-window.c | 2 +- cmd-split-window.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd-new-window.c b/cmd-new-window.c index 2d409399..c906d4d2 100644 --- a/cmd-new-window.c +++ b/cmd-new-window.c @@ -133,7 +133,7 @@ cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx) cp = format_expand(ft, template); ctx->print(ctx, "%s", cp); - free(cp); + xfree(cp); format_free(ft); } diff --git a/cmd-split-window.c b/cmd-split-window.c index 5addd107..08a371c9 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -152,7 +152,7 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) cp = format_expand(ft, template); ctx->print(ctx, "%s", cp); - free(cp); + xfree(cp); format_free(ft); } From ac9ebc29a26c1e7c19e1c9a58fef42bfc75d2100 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 9 Mar 2012 09:57:40 +0000 Subject: [PATCH 1042/1180] Use a lock file and flock() to serialize server start, avoids problems when running a bunch of tmux from cron at the same time. Based on a diff from Tim Ruehsen. --- client.c | 53 ++++++++++++++++++++++++++++++++++++++++------------- server.c | 6 +++++- tmux.h | 2 +- 3 files changed, 46 insertions(+), 15 deletions(-) diff --git a/client.c b/client.c index eea45177..d2e53b6d 100644 --- a/client.c +++ b/client.c @@ -39,6 +39,7 @@ int client_exitval; enum msgtype client_exittype; int client_attached; +int client_get_lock(char *); int client_connect(char *, int); void client_send_identify(int); void client_send_environ(void); @@ -49,13 +50,38 @@ void client_callback(int, short, void *); int client_dispatch_attached(void); int client_dispatch_wait(void *); +/* + * Get server create lock. If already held then server start is happening in + * another client, so block until the lock is released and return -1 to + * retry. Ignore other errors - just continue and start the server without the + * lock. + */ +int +client_get_lock(char *lockfile) +{ + int lockfd; + + if ((lockfd = open(lockfile, O_WRONLY|O_CREAT, 0600)) == -1) + fatal("open failed"); + + if (flock(lockfd, LOCK_EX|LOCK_NB) == -1 && errno == EWOULDBLOCK) { + while (flock(lockfd, LOCK_EX) == -1 && errno == EINTR) + /* nothing */; + close(lockfd); + return (-1); + } + + return (lockfd); +} + /* Connect client to server. */ int client_connect(char *path, int start_server) { struct sockaddr_un sa; size_t size; - int fd; + int fd, lockfd; + char *lockfile; memset(&sa, 0, sizeof sa); sa.sun_family = AF_UNIX; @@ -65,24 +91,25 @@ client_connect(char *path, int start_server) return (-1); } +retry: if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) fatal("socket failed"); if (connect(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1) { + if (errno != ECONNREFUSED && errno != ENOENT) + goto failed; if (!start_server) goto failed; - switch (errno) { - case ECONNREFUSED: - if (unlink(path) != 0) - goto failed; - /* FALLTHROUGH */ - case ENOENT: - if ((fd = server_start()) == -1) - goto failed; - break; - default: - goto failed; - } + close(fd); + + xasprintf(&lockfile, "%s.lock", path); + if ((lockfd = client_get_lock(lockfile)) == -1) + goto retry; + if (unlink(path) != 0 && errno != ENOENT) + return (-1); + fd = server_start(lockfd, lockfile); + xfree(lockfile); + close(lockfd); } setblocking(fd, 0); diff --git a/server.c b/server.c index a548a694..c269535d 100644 --- a/server.c +++ b/server.c @@ -104,7 +104,7 @@ server_create_socket(void) /* Fork new server. */ int -server_start(void) +server_start(int lockfd, char *lockfile) { struct window_pane *wp; int pair[2]; @@ -161,6 +161,10 @@ server_start(void) server_fd = server_create_socket(); server_client_create(pair[1]); + unlink(lockfile); + xfree(lockfile); + close(lockfd); + if (access(SYSTEM_CFG, R_OK) == 0) load_cfg(SYSTEM_CFG, NULL, &cfg_causes); else if (errno != ENOENT) { diff --git a/tmux.h b/tmux.h index 6503d886..3b60a983 100644 --- a/tmux.h +++ b/tmux.h @@ -1687,7 +1687,7 @@ const char *key_string_lookup_key(int); extern struct clients clients; extern struct clients dead_clients; extern struct paste_stack global_buffers; -int server_start(void); +int server_start(int, char *); void server_update_socket(void); /* server-client.c */ From be63fef8728a3948ae58eb89ed0873a2327de25c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 9 Mar 2012 21:11:28 +0000 Subject: [PATCH 1043/1180] Add a missing call to window_set_name, from George Nachman. --- names.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/names.c b/names.c index 0bdcbe3e..a1fc1ba3 100644 --- a/names.c +++ b/names.c @@ -78,13 +78,11 @@ window_name_callback(unused int fd, unused short events, void *data) wname = name; } - if (strcmp(wname, w->name) == 0) - xfree(wname); - else { - xfree(w->name); - w->name = wname; + if (strcmp(wname, w->name)) { + window_set_name(w, wname); server_status_window(w); } + xfree(wname); } char * From 799f437effd83d8aaf03c82919e5acfbfa79230f Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 9 Mar 2012 21:42:13 +0000 Subject: [PATCH 1044/1180] Remove some bits leftover from unused backoff code. --- server-client.c | 1 - tmux.h | 4 ---- tty.c | 2 +- 3 files changed, 1 insertion(+), 6 deletions(-) diff --git a/server-client.c b/server-client.c index a748d363..ba5077e5 100644 --- a/server-client.c +++ b/server-client.c @@ -32,7 +32,6 @@ void server_client_check_mouse(struct client *c, void server_client_handle_key(int, struct mouse_event *, void *); void server_client_repeat_timer(int, short, void *); void server_client_check_exit(struct client *); -void server_client_check_backoff(struct client *); void server_client_check_redraw(struct client *); void server_client_set_title(struct client *); void server_client_reset_state(struct client *); diff --git a/tmux.h b/tmux.h index 3b60a983..69b777d8 100644 --- a/tmux.h +++ b/tmux.h @@ -59,9 +59,6 @@ extern char **environ; /* Automatic name refresh interval, in milliseconds. */ #define NAME_INTERVAL 500 -/* Maximum data to buffer for output before suspending writing to a tty. */ -#define BACKOFF_THRESHOLD 16384 - /* * Maximum sizes of strings in message data. Don't forget to bump * PROTOCOL_VERSION if any of these change! @@ -1048,7 +1045,6 @@ struct tty { #define TTY_UTF8 0x8 #define TTY_STARTED 0x10 #define TTY_OPENED 0x20 -#define TTY_BACKOFF 0x40 int flags; int term_flags; diff --git a/tty.c b/tty.c index bbe2f1da..81c964b4 100644 --- a/tty.c +++ b/tty.c @@ -627,7 +627,7 @@ tty_write( if (s->curw->window == wp->window) { if (c->tty.term == NULL) continue; - if (c->tty.flags & (TTY_FREEZE|TTY_BACKOFF)) + if (c->tty.flags & TTY_FREEZE) continue; oo = &s->options; From 1bbb7932636799b99acbd95dbf845872606412ab Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 11 Mar 2012 23:01:19 +0000 Subject: [PATCH 1045/1180] Always remember last cursor position when moving up or down, not just for if crossing zero length lines. From Itay Perl. --- window-copy.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/window-copy.c b/window-copy.c index 3ba11f2a..3d491822 100644 --- a/window-copy.c +++ b/window-copy.c @@ -1629,7 +1629,7 @@ window_copy_cursor_up(struct window_pane *wp, int scroll_only) oy = screen_hsize(data->backing) + data->cy - data->oy; ox = window_copy_find_length(wp, oy); - if (ox != 0) { + if (data->cx != ox) { data->lastcx = data->cx; data->lastsx = ox; } @@ -1671,7 +1671,7 @@ window_copy_cursor_down(struct window_pane *wp, int scroll_only) oy = screen_hsize(data->backing) + data->cy - data->oy; ox = window_copy_find_length(wp, oy); - if (ox != 0) { + if (data->cx != ox) { data->lastcx = data->cx; data->lastsx = ox; } From 31ddae77358b620c9b1776a472711018916ba1cb Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 12 Mar 2012 12:38:42 +0000 Subject: [PATCH 1046/1180] Use EL to clear to end of line if possible. --- tty.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tty.c b/tty.c index 81c964b4..80d2c4c4 100644 --- a/tty.c +++ b/tty.c @@ -588,7 +588,8 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int py, u_int ox, u_int oy) tty_reset(tty); tty_cursor(tty, ox + sx, oy + py); - if (screen_size_x(s) >= tty->sx && tty_term_has(tty->term, TTYC_EL)) + if (ox + sx + screen_size_x(s) >= tty->sx && + tty_term_has(tty->term, TTYC_EL)) tty_putcode(tty, TTYC_EL); else { for (i = sx; i < screen_size_x(s); i++) From 575bfa4b4b6d6f702abf4a6abf6cf1c82bf10b53 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 12 Mar 2012 12:43:18 +0000 Subject: [PATCH 1047/1180] Erm, use EL in a way that actually works... --- tty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tty.c b/tty.c index 80d2c4c4..502f2b98 100644 --- a/tty.c +++ b/tty.c @@ -588,7 +588,7 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int py, u_int ox, u_int oy) tty_reset(tty); tty_cursor(tty, ox + sx, oy + py); - if (ox + sx + screen_size_x(s) >= tty->sx && + if (ox + screen_size_x(s) >= tty->sx && tty_term_has(tty->term, TTYC_EL)) tty_putcode(tty, TTYC_EL); else { From 4e05a2c0ae0017f8b1b501eb9cec0ea8d4ec2ca4 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 12 Mar 2012 13:31:09 +0000 Subject: [PATCH 1048/1180] Add -P/-F flags to break-pane too, from George Nachman. --- cmd-break-pane.c | 25 +++++++++++++++++++++++-- tmux.1 | 10 +++++++++- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/cmd-break-pane.c b/cmd-break-pane.c index 6e455ab9..6e6ab589 100644 --- a/cmd-break-pane.c +++ b/cmd-break-pane.c @@ -30,8 +30,8 @@ int cmd_break_pane_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_break_pane_entry = { "break-pane", "breakp", - "dt:", 0, 0, - "[-d] " CMD_TARGET_PANE_USAGE, + "dPF:t:", 0, 0, + "[-dP] [-F format] " CMD_TARGET_PANE_USAGE, 0, NULL, NULL, @@ -49,6 +49,10 @@ cmd_break_pane_exec(struct cmd *self, struct cmd_ctx *ctx) char *name; char *cause; int base_idx; + struct client *c; + struct format_tree *ft; + const char *template; + char *cp; if ((wl = cmd_find_pane(ctx, args_get(args, 't'), &s, &wp)) == NULL) return (-1); @@ -88,5 +92,22 @@ cmd_break_pane_exec(struct cmd *self, struct cmd_ctx *ctx) server_redraw_session(s); server_status_session_group(s); + if (args_has(args, 'P')) { + template = "#{session_name}:#{window_index}"; + if (args_has(args, 'F')) + template = args_get(args, 'F'); + ft = format_create(); + if ((c = cmd_find_client(ctx, NULL)) != NULL) + format_client(ft, c); + format_session(ft, s); + format_winlink(ft, s, wl); + format_window_pane(ft, wp); + + cp = format_expand(ft, template); + ctx->print(ctx, "%s", cp); + xfree(cp); + + format_free(ft); + } return (0); } diff --git a/tmux.1 b/tmux.1 index a7950d26..e5ea872f 100644 --- a/tmux.1 +++ b/tmux.1 @@ -996,7 +996,8 @@ from which the layout was originally defined. Commands related to windows and panes are as follows: .Bl -tag -width Ds .It Xo Ic break-pane -.Op Fl d +.Op Fl dP +.Op Fl F Ar format .Op Fl t Ar target-pane .Xc .D1 (alias: Ic breakp ) @@ -1006,6 +1007,13 @@ off from its containing window to make it the only pane in a new window. If .Fl d is given, the new window does not become the current window. +The +.Fl P +option prints information about the new window after it has been created. +By default, it uses the format +.Ql #{session_name}:#{window_index} +but a different format may be specified with +.Fl F . .It Xo Ic capture-pane .Op Fl b Ar buffer-index .Op Fl E Ar end-line From 71df37c247a3fcebfd24637410bd4ef41801147c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 14 Mar 2012 23:29:07 +0000 Subject: [PATCH 1049/1180] Store context off before moving the cursor when wrapping, to fix long standing bug drawing over the status line. --- screen-write.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/screen-write.c b/screen-write.c index d8659593..50abb174 100644 --- a/screen-write.c +++ b/screen-write.c @@ -1071,9 +1071,6 @@ screen_write_cell(struct screen_write_ctx *ctx, return; } - /* Initialise the redraw context, saving the last cell. */ - screen_write_initctx(ctx, &ttyctx, 1); - /* If in insert mode, make space for the cells. */ if (s->mode & MODE_INSERT && s->cx <= screen_size_x(s) - width) { xx = screen_size_x(s) - s->cx - width; @@ -1087,6 +1084,9 @@ screen_write_cell(struct screen_write_ctx *ctx, s->cx = 0; /* carriage return */ } + /* Initialise the redraw context, saving the last cell. */ + screen_write_initctx(ctx, &ttyctx, 1); + /* Sanity checks. */ if (((s->mode & MODE_WRAP) && s->cx > screen_size_x(s) - width) || s->cy > screen_size_y(s) - 1) From 698361ccde262b82ce91c81891b767f6752ebf67 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 15 Mar 2012 09:10:33 +0000 Subject: [PATCH 1050/1180] Add a helper function for enabling an optimization to make some code clearer. --- tty.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/tty.c b/tty.c index 502f2b98..7c54913d 100644 --- a/tty.c +++ b/tty.c @@ -501,6 +501,19 @@ tty_emulate_repeat( } } +/* + * Is the region large enough to be worth redrawing once later rather than + * probably several times now? Currently yes if it is more than 50% of the + * pane. + */ +int +tty_large_region(unused struct tty *tty, const struct tty_ctx *ctx) +{ + struct window_pane *wp = ctx->wp; + + return (ctx->orlower - ctx->orupper >= screen_size_y(wp->screen) / 2); +} + /* * Redraw scroll region using data from screen (already updated). Used when * CSR not supported, or window is a pane that doesn't take up the full @@ -514,12 +527,10 @@ tty_redraw_region(struct tty *tty, const struct tty_ctx *ctx) u_int i; /* - * If region is >= 50% of the screen, just schedule a window redraw. In - * most cases, this is likely to be followed by some more scrolling - - * without this, the entire pane ends up being redrawn many times which - * can be much more data. + * If region is large, schedule a window redraw. In most cases this is + * likely to be followed by some more scrolling. */ - if (ctx->orlower - ctx->orupper >= screen_size_y(s) / 2) { + if (tty_large_region(tty, ctx)) { wp->flags |= PANE_REDRAW; return; } From 005566f915030d269fdf7a42e619f8469099b0f0 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 15 Mar 2012 09:22:31 +0000 Subject: [PATCH 1051/1180] Fix a warning. Doh. --- tty.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tty.c b/tty.c index 7c54913d..5494ad4d 100644 --- a/tty.c +++ b/tty.c @@ -43,6 +43,7 @@ void tty_check_bg(struct tty *, struct grid_cell *); void tty_colours_fg(struct tty *, const struct grid_cell *); void tty_colours_bg(struct tty *, const struct grid_cell *); +int tty_large_region(struct tty *, const struct tty_ctx *); void tty_redraw_region(struct tty *, const struct tty_ctx *); void tty_emulate_repeat( struct tty *, enum tty_code_code, enum tty_code_code, u_int); From 523ed3873dfa15cf625ce3d013efd8770974f59d Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 15 Mar 2012 10:05:49 +0000 Subject: [PATCH 1052/1180] Respond to secondary DA requests. --- input.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/input.c b/input.c index c12e1b29..88e633fe 100644 --- a/input.c +++ b/input.c @@ -127,6 +127,7 @@ enum input_csi_type { INPUT_CSI_CUP, INPUT_CSI_CUU, INPUT_CSI_DA, + INPUT_CSI_DA_TWO, INPUT_CSI_DCH, INPUT_CSI_DECSCUSR, INPUT_CSI_DECSTBM, @@ -166,6 +167,7 @@ const struct input_table_entry input_csi_table[] = { { 'P', "", INPUT_CSI_DCH }, { 'Z', "", INPUT_CSI_CBT }, { 'c', "", INPUT_CSI_DA }, + { 'c', ">", INPUT_CSI_DA_TWO }, { 'd', "", INPUT_CSI_VPA }, { 'f', "", INPUT_CSI_CUP }, { 'g', "", INPUT_CSI_TBC }, @@ -1097,6 +1099,16 @@ input_csi_dispatch(struct input_ctx *ictx) break; } break; + case INPUT_CSI_DA_TWO: + switch (input_get(ictx, 0, 0, 0)) { + case 0: + input_reply(ictx, "\033[>0;95;0c"); + break; + default: + log_debug("%s: unknown '%c'", __func__, ictx->ch); + break; + } + break; case INPUT_CSI_DCH: screen_write_deletecharacter(sctx, input_get(ictx, 0, 1, 1)); break; From c8c0d681285938a0f8f6aaa34f85ca50c5494f1d Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 15 Mar 2012 10:36:00 +0000 Subject: [PATCH 1053/1180] Send secondary DA to terminals with XT in terminfo when starting up and parse it to work out the xterm version. --- cmd-server-info.c | 10 +++--- tmux.h | 1 + tty-keys.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++- tty.c | 3 ++ 4 files changed, 86 insertions(+), 6 deletions(-) diff --git a/cmd-server-info.c b/cmd-server-info.c index 776b137d..1a5a5cf8 100644 --- a/cmd-server-info.c +++ b/cmd-server-info.c @@ -88,12 +88,12 @@ cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx) if (c == NULL || c->session == NULL) continue; - ctx->print(ctx,"%2d: %s (%d, %d): %s [%ux%u %s bs=%hho] " - "[flags=0x%x/0x%x, references=%u]", i, c->tty.path, - c->ibuf.fd, c->tty.fd, c->session->name, + ctx->print(ctx,"%2d: %s (%d, %d): %s [%ux%u %s bs=%hho " + "xterm=%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->flags, - c->tty.flags, c->references); + c->tty.tio.c_cc[VERASE], c->tty.xterm_version, + c->flags, c->tty.flags, c->references); } ctx->print(ctx, "%s", ""); diff --git a/tmux.h b/tmux.h index 69b777d8..801d2406 100644 --- a/tmux.h +++ b/tmux.h @@ -1013,6 +1013,7 @@ LIST_HEAD(tty_terms, tty_term); struct tty { char *path; + u_int xterm_version; u_int sx; u_int sy; diff --git a/tty-keys.c b/tty-keys.c index 223d574e..91bf6503 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -19,6 +19,8 @@ #include #include +#include +#include #include #include #include @@ -40,6 +42,7 @@ struct tty_key *tty_keys_find(struct tty *, const char *, size_t, size_t *); void tty_keys_callback(int, short, void *); int tty_keys_mouse(struct tty *, const char *, size_t, size_t *, struct mouse_event *); +int tty_keys_device(struct tty *, const char *, size_t, size_t *); struct tty_key_ent { enum tty_code_code code; @@ -461,6 +464,19 @@ tty_keys_next(struct tty *tty) goto handle_key; } + /* Is this device attributes response? */ + switch (tty_keys_device(tty, buf, len, &size)) { + case 0: /* yes */ + evbuffer_drain(tty->event->input, size); + key = KEYC_NONE; + goto handle_key; + case -1: /* no, or not valid */ + break; + case 1: /* partial */ + goto partial_key; + } + + /* Is this a mouse key press? */ switch (tty_keys_mouse(tty, buf, len, &size, &mouse)) { case 0: /* yes */ @@ -559,7 +575,8 @@ found_key: handle_key: evtimer_del(&tty->key_timer); - tty->key_callback(key, &mouse, tty->key_data); + if (key != KEYC_NONE) + tty->key_callback(key, &mouse, tty->key_data); tty->flags &= ~TTY_ESCAPE; return (1); @@ -655,3 +672,62 @@ tty_keys_mouse(struct tty *tty, log_debug("mouse position: x=%u y=%u b=%u", m->x, m->y, m->b); return (0); } + +/* + * Handle device attributes input. Returns 0 for success, -1 for failure, 1 for + * partial. + */ +int +tty_keys_device(struct tty *tty, const char *buf, size_t len, size_t *size) +{ + u_int i, a, b; + char tmp[64], *endptr; + + /* + * Secondary device attributes are \033[>a;b;c. We only request + * attributes on xterm, so we only care about the middle values which + * is the xterm version. + */ + + *size = 0; + + /* First three bytes are always \033[>. */ + if (buf[0] != '\033') + return (-1); + if (len == 1) + return (1); + if (buf[1] != '[') + return (-1); + if (len == 2) + return (1); + if (buf[2] != '>') + return (-1); + if (len == 3) + return (1); + + /* Copy the rest up to a 'c'. */ + for (i = 0; i < (sizeof tmp) - 1 && buf[3 + i] != 'c'; i++) { + if (3 + i == len) + return (1); + tmp[i] = buf[3 + i]; + } + if (i == (sizeof tmp) - 1) + return (-1); + tmp[i] = '\0'; + *size = 4 + i; + + /* Convert version numbers. */ + a = strtoul(tmp, &endptr, 10); + if (*endptr == ';') { + b = strtoul(endptr + 1, &endptr, 10); + if (*endptr != '\0' && *endptr != ';') + b = 0; + } else + a = b = 0; + + log_debug("received xterm version %u", b); + if (tty->xterm_version == 0) + tty->xterm_version = b; + + return (0); +} diff --git a/tty.c b/tty.c index 5494ad4d..bf5eac09 100644 --- a/tty.c +++ b/tty.c @@ -211,6 +211,9 @@ tty_start_tty(struct tty *tty) if (tty_term_has(tty->term, TTYC_KMOUS)) tty_puts(tty, "\033[?1000l"); + if (tty_term_has(tty->term, TTYC_XT)) + tty_puts(tty, "\033[>c"); + tty->cx = UINT_MAX; tty->cy = UINT_MAX; From 0489213b1bf6a3fc7e158951ba993f4b88f48557 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 17 Mar 2012 17:36:03 +0000 Subject: [PATCH 1054/1180] Revert screen-write.c r1.54 and fix the bug properly. After wrapping a line in a pane, the cursor needs to move to the next line unless it scrolled. --- screen-write.c | 8 ++++---- tty.c | 5 ++++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/screen-write.c b/screen-write.c index 50abb174..90511e30 100644 --- a/screen-write.c +++ b/screen-write.c @@ -1071,8 +1071,11 @@ screen_write_cell(struct screen_write_ctx *ctx, return; } + /* Initialise the redraw context, saving the last cell. */ + screen_write_initctx(ctx, &ttyctx, 1); + /* If in insert mode, make space for the cells. */ - if (s->mode & MODE_INSERT && s->cx <= screen_size_x(s) - width) { + if ((s->mode & MODE_INSERT) && s->cx <= screen_size_x(s) - width) { xx = screen_size_x(s) - s->cx - width; grid_move_cells(s->grid, s->cx + width, s->cx, s->cy, xx); insert = 1; @@ -1084,9 +1087,6 @@ screen_write_cell(struct screen_write_ctx *ctx, s->cx = 0; /* carriage return */ } - /* Initialise the redraw context, saving the last cell. */ - screen_write_initctx(ctx, &ttyctx, 1); - /* Sanity checks. */ if (((s->mode & MODE_WRAP) && s->cx > screen_size_x(s) - width) || s->cy > screen_size_y(s) - 1) diff --git a/tty.c b/tty.c index bf5eac09..c7e603c1 100644 --- a/tty.c +++ b/tty.c @@ -1000,7 +1000,10 @@ tty_cmd_cell(struct tty *tty, const struct tty_ctx *ctx) * The pane doesn't fill the entire line, the linefeed * will already have happened, so just move the cursor. */ - tty_cursor_pane(tty, ctx, 0, ctx->ocy + 1); + if (ctx->ocy != wp->yoff + wp->sy) + tty_cursor_pane(tty, ctx, 0, ctx->ocy + 1); + else + tty_cursor_pane(tty, ctx, 0, ctx->ocy); } else if (tty->cx < tty->sx) { /* * The cursor isn't in the last position already, so From a597e3546cf667c2db91aea5545d2cb2125366f5 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 17 Mar 2012 18:23:03 +0000 Subject: [PATCH 1055/1180] Redirect libevent logging to tmux's log. --- log.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/log.c b/log.c index 35728855..0798ee91 100644 --- a/log.c +++ b/log.c @@ -42,6 +42,13 @@ int log_level; void log_vwrite(int, const char *, va_list); __dead void log_vfatal(const char *, va_list); +/* Log callback for libevent. */ +void +log_event_cb(unused int severity, const char *msg) +{ + log_warnx(msg); +} + /* Open logging to tty. */ void log_open_tty(int level) @@ -51,6 +58,7 @@ log_open_tty(int level) setlinebuf(stderr); setlinebuf(stdout); + event_set_log_callback(log_event_cb); tzset(); } @@ -67,6 +75,7 @@ log_open_file(int level, const char *path) log_level = level; setlinebuf(log_file); + event_set_log_callback(log_event_cb); tzset(); } @@ -78,6 +87,8 @@ log_close(void) if (log_type == LOG_TYPE_FILE) fclose(log_file); + event_set_log_callback(NULL); + log_type = LOG_TYPE_OFF; } From d3c842d3678e52275c944123f00a2a974eb5d965 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 17 Mar 2012 18:24:07 +0000 Subject: [PATCH 1056/1180] Check event_initialized before event_del if event may not have been set up; libevent2 complains about this. Reported by Moriyoshi Koizumi. --- names.c | 3 ++- server-client.c | 9 ++++++--- server-fn.c | 6 ++++-- status.c | 3 ++- tty-keys.c | 6 ++++-- tty.c | 3 ++- window.c | 3 ++- 7 files changed, 22 insertions(+), 11 deletions(-) diff --git a/names.c b/names.c index a1fc1ba3..5821d94a 100644 --- a/names.c +++ b/names.c @@ -36,7 +36,8 @@ queue_window_name(struct window *w) tv.tv_sec = 0; tv.tv_usec = NAME_INTERVAL * 1000L; - evtimer_del(&w->name_timer); + if (event_initialized(&w->name_timer)) + evtimer_del(&w->name_timer); evtimer_set(&w->name_timer, window_name_callback, w); evtimer_add(&w->name_timer, &tv); } diff --git a/server-client.c b/server-client.c index ba5077e5..2f84f011 100644 --- a/server-client.c +++ b/server-client.c @@ -153,11 +153,13 @@ server_client_lost(struct client *c) evtimer_del(&c->repeat_timer); - evtimer_del(&c->identify_timer); + if (event_initialized(&c->identify_timer)) + evtimer_del(&c->identify_timer); if (c->message_string != NULL) xfree(c->message_string); - evtimer_del(&c->message_timer); + if (event_initialized (&c->message_timer)) + evtimer_del(&c->message_timer); for (i = 0; i < ARRAY_LENGTH(&c->message_log); i++) { msg = &ARRAY_ITEM(&c->message_log, i); xfree(msg->msg); @@ -176,7 +178,8 @@ server_client_lost(struct client *c) close(c->ibuf.fd); imsg_clear(&c->ibuf); - event_del(&c->event); + if (event_initialized(&c->event)) + event_del(&c->event); for (i = 0; i < ARRAY_LENGTH(&dead_clients); i++) { if (ARRAY_ITEM(&dead_clients, i) == NULL) { diff --git a/server-fn.c b/server-fn.c index b9b7b714..66298571 100644 --- a/server-fn.c +++ b/server-fn.c @@ -453,7 +453,8 @@ server_set_identify(struct client *c) tv.tv_sec = delay / 1000; tv.tv_usec = (delay % 1000) * 1000L; - evtimer_del(&c->identify_timer); + if (event_initialized (&c->identify_timer)) + evtimer_del(&c->identify_timer); evtimer_set(&c->identify_timer, server_callback_identify, c); evtimer_add(&c->identify_timer, &tv); @@ -491,7 +492,8 @@ server_update_event(struct client *c) events |= EV_READ; if (c->ibuf.w.queued > 0) events |= EV_WRITE; - event_del(&c->event); + if (event_initialized(&c->event)) + event_del(&c->event); event_set(&c->event, c->ibuf.fd, events, server_client_callback, c); event_add(&c->event, NULL); } diff --git a/status.c b/status.c index 0342b5f1..8338fbe4 100644 --- a/status.c +++ b/status.c @@ -776,7 +776,8 @@ status_message_set(struct client *c, const char *fmt, ...) tv.tv_sec = delay / 1000; tv.tv_usec = (delay % 1000) * 1000L; - evtimer_del(&c->message_timer); + if (event_initialized (&c->message_timer)) + evtimer_del(&c->message_timer); evtimer_set(&c->message_timer, status_message_callback, c); evtimer_add(&c->message_timer, &tv); diff --git a/tty-keys.c b/tty-keys.c index 91bf6503..37265dce 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -549,7 +549,8 @@ start_timer: tv.tv_sec = delay / 1000; tv.tv_usec = (delay % 1000) * 1000L; - evtimer_del(&tty->key_timer); + if (event_initialized(&tty->key_timer)) + evtimer_del(&tty->key_timer); evtimer_set(&tty->key_timer, tty_keys_callback, tty); evtimer_add(&tty->key_timer, &tv); @@ -573,7 +574,8 @@ found_key: goto handle_key; handle_key: - evtimer_del(&tty->key_timer); + if (event_initialized(&tty->key_timer)) + evtimer_del(&tty->key_timer); if (key != KEYC_NONE) tty->key_callback(key, &mouse, tty->key_data); diff --git a/tty.c b/tty.c index c7e603c1..4ea999ba 100644 --- a/tty.c +++ b/tty.c @@ -279,7 +279,8 @@ tty_close(struct tty *tty) tty->log_fd = -1; } - evtimer_del(&tty->key_timer); + if (event_initialized(&tty->key_timer)) + evtimer_del(&tty->key_timer); tty_stop_tty(tty); if (tty->flags & TTY_OPENED) { diff --git a/window.c b/window.c index 0489d105..f0061293 100644 --- a/window.c +++ b/window.c @@ -350,7 +350,8 @@ window_destroy(struct window *w) if (w->layout_root != NULL) layout_free(w); - evtimer_del(&w->name_timer); + if (event_initialized(&w->name_timer)) + evtimer_del(&w->name_timer); options_free(&w->options); From 7ad052583a058efb1816d7d4cb634fbc5be1ccc6 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 17 Mar 2012 18:38:58 +0000 Subject: [PATCH 1057/1180] Fix warnings. Doh. --- log.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/log.c b/log.c index 0798ee91..184f9597 100644 --- a/log.c +++ b/log.c @@ -39,6 +39,7 @@ FILE *log_file; /* Debug level. */ int log_level; +void log_event_cb(int, const char *); void log_vwrite(int, const char *, va_list); __dead void log_vfatal(const char *, va_list); @@ -46,7 +47,7 @@ __dead void log_vfatal(const char *, va_list); void log_event_cb(unused int severity, const char *msg) { - log_warnx(msg); + log_warnx("%s", msg); } /* Open logging to tty. */ From 928f40615c7a000b87a8fc843b97955a7cfc4a9a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 17 Mar 2012 18:51:50 +0000 Subject: [PATCH 1058/1180] Tweak last fix to actually hit the right end of pane. --- tty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tty.c b/tty.c index 4ea999ba..96932647 100644 --- a/tty.c +++ b/tty.c @@ -1001,7 +1001,7 @@ tty_cmd_cell(struct tty *tty, const struct tty_ctx *ctx) * The pane doesn't fill the entire line, the linefeed * will already have happened, so just move the cursor. */ - if (ctx->ocy != wp->yoff + wp->sy) + if (ctx->ocy != wp->yoff + wp->sy - 1) tty_cursor_pane(tty, ctx, 0, ctx->ocy + 1); else tty_cursor_pane(tty, ctx, 0, ctx->ocy); From 0b34fefe6e007ca2eb68382d0b4042d7a1ab1dd4 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 17 Mar 2012 19:18:37 +0000 Subject: [PATCH 1059/1180] Use the region lower not the pane size to work out where the bottom line is. --- tty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tty.c b/tty.c index 96932647..1f83ca74 100644 --- a/tty.c +++ b/tty.c @@ -1001,7 +1001,7 @@ tty_cmd_cell(struct tty *tty, const struct tty_ctx *ctx) * The pane doesn't fill the entire line, the linefeed * will already have happened, so just move the cursor. */ - if (ctx->ocy != wp->yoff + wp->sy - 1) + if (ctx->ocy != wp->yoff + wp->screen->rlower) tty_cursor_pane(tty, ctx, 0, ctx->ocy + 1); else tty_cursor_pane(tty, ctx, 0, ctx->ocy); From 164e85cca75d5f7a6f36c286f597e03d08c90c2a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 17 Mar 2012 19:29:46 +0000 Subject: [PATCH 1060/1180] Do not clear to end of line if the line is full, fixes missing last character in rightmost pane. --- tty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tty.c b/tty.c index 1f83ca74..288d4bd1 100644 --- a/tty.c +++ b/tty.c @@ -604,7 +604,7 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int py, u_int ox, u_int oy) tty_reset(tty); tty_cursor(tty, ox + sx, oy + py); - if (ox + screen_size_x(s) >= tty->sx && + if (sx != screen_size_x(s) && ox + screen_size_x(s) >= tty->sx && tty_term_has(tty->term, TTYC_EL)) tty_putcode(tty, TTYC_EL); else { From 889fe42e1153ada95d73e5f9983d1a9d671837a1 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 17 Mar 2012 21:27:51 +0000 Subject: [PATCH 1061/1180] Break out termios initialization into a separate function, from George Nachman. --- tmux.h | 1 + tty.c | 21 ++++++++++++++------- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/tmux.h b/tmux.h index 801d2406..9257117a 100644 --- a/tmux.h +++ b/tmux.h @@ -1444,6 +1444,7 @@ void environ_update(const char *, struct environ *, struct environ *); void environ_push(struct environ *); /* tty.c */ +void tty_init_termios(int, struct termios *, struct bufferevent *); void tty_raw(struct tty *, const char *); void tty_attributes(struct tty *, const struct grid_cell *); void tty_reset(struct tty *); diff --git a/tty.c b/tty.c index 288d4bd1..a36bf787 100644 --- a/tty.c +++ b/tty.c @@ -175,18 +175,19 @@ tty_error_callback( } void -tty_start_tty(struct tty *tty) +tty_init_termios(int fd, struct termios *orig_tio, struct bufferevent *bufev) { struct termios tio; - if (tty->fd == -1 || tcgetattr(tty->fd, &tty->tio) != 0) + if (fd == -1 || tcgetattr(fd, orig_tio) != 0) return; - setblocking(tty->fd, 0); + setblocking(fd, 0); - bufferevent_enable(tty->event, EV_READ|EV_WRITE); + if (bufev != NULL) + bufferevent_enable(bufev, EV_READ|EV_WRITE); - memcpy(&tio, &tty->tio, sizeof tio); + memcpy(&tio, orig_tio, sizeof tio); tio.c_iflag &= ~(IXON|IXOFF|ICRNL|INLCR|IGNCR|IMAXBEL|ISTRIP); tio.c_iflag |= IGNBRK; tio.c_oflag &= ~(OPOST|ONLCR|OCRNL|ONLRET); @@ -194,8 +195,14 @@ tty_start_tty(struct tty *tty) ECHOPRT|ECHOKE|ECHOCTL|ISIG); tio.c_cc[VMIN] = 1; tio.c_cc[VTIME] = 0; - if (tcsetattr(tty->fd, TCSANOW, &tio) == 0) - tcflush(tty->fd, TCIOFLUSH); + if (tcsetattr(fd, TCSANOW, &tio) == 0) + tcflush(fd, TCIOFLUSH); +} + +void +tty_start_tty(struct tty *tty) +{ + tty_init_termios(tty->fd, &tty->tio, tty->event); tty_putcode(tty, TTYC_SMCUP); From f152379e5a21b2e0603c9fb9001c7a9e70e62bf4 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 17 Mar 2012 21:33:33 +0000 Subject: [PATCH 1062/1180] Add -q option to set-option to turn off info message, from marcel partap. --- cmd-set-option.c | 17 ++++++++++------- tmux.1 | 13 ++++++++++--- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/cmd-set-option.c b/cmd-set-option.c index c020b578..153d2d88 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -60,8 +60,8 @@ struct options_entry *cmd_set_option_choice(struct cmd *, struct cmd_ctx *, const struct cmd_entry cmd_set_option_entry = { "set-option", "set", - "agst:uw", 1, 2, - "[-agsuw] [-t target-session|target-window] option [value]", + "agqst:uw", 1, 2, + "[-agsquw] [-t target-session|target-window] option [value]", 0, NULL, NULL, @@ -70,8 +70,8 @@ const struct cmd_entry cmd_set_option_entry = { const struct cmd_entry cmd_set_window_option_entry = { "set-window-option", "setw", - "agt:u", 1, 2, - "[-agu] " CMD_TARGET_WINDOW_USAGE " option [value]", + "agqt:u", 1, 2, + "[-agqu] " CMD_TARGET_WINDOW_USAGE " option [value]", 0, NULL, NULL, @@ -175,7 +175,8 @@ cmd_set_option_unset(struct cmd *self, struct cmd_ctx *ctx, } options_remove(oo, oe->name); - ctx->info(ctx, "unset option: %s", oe->name); + if (!args_has(args, 'q')) + ctx->info(ctx, "unset option: %s", oe->name); return (0); } @@ -184,6 +185,7 @@ int cmd_set_option_set(struct cmd *self, struct cmd_ctx *ctx, const struct options_table_entry *oe, struct options *oo, const char *value) { + struct args *args = self->args; struct options_entry *o; const char *s; @@ -220,7 +222,8 @@ cmd_set_option_set(struct cmd *self, struct cmd_ctx *ctx, return (-1); s = options_table_print_entry(oe, o); - ctx->info(ctx, "set option: %s -> %s", oe->name, s); + if (!args_has(args, 'q')) + ctx->info(ctx, "set option: %s -> %s", oe->name, s); return (0); } @@ -229,7 +232,7 @@ struct options_entry * cmd_set_option_string(struct cmd *self, unused struct cmd_ctx *ctx, const struct options_table_entry *oe, struct options *oo, const char *value) { - struct args *args = self->args; + struct args *args = self->args; struct options_entry *o; char *oldval, *newval; diff --git a/tmux.1 b/tmux.1 index e5ea872f..0ab98afe 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1788,7 +1788,7 @@ command. Commands which set options are as follows: .Bl -tag -width Ds .It Xo Ic set-option -.Op Fl agsuw +.Op Fl agqsuw .Op Fl t Ar target-session | Ar target-window .Ar option Ar value .Xc @@ -1816,6 +1816,12 @@ flag unsets an option, so a session inherits the option from the global options. It is not possible to unset a global option. .Pp +The +.Fl q +flag suppresses the informational message (as if the +.Ic quiet +server option was set). +.Pp Available window options are listed under .Ic set-window-option . .Pp @@ -2381,7 +2387,7 @@ The default is .Ql \ -_@ . .El .It Xo Ic set-window-option -.Op Fl agu +.Op Fl agqu .Op Fl t Ar target-window .Ar option Ar value .Xc @@ -2389,7 +2395,8 @@ The default is Set a window option. The .Fl a , -.Fl g +.Fl g , +.Fl q and .Fl u flags work similarly to the From e87d4b43abdba32698ed44590f7fd84cf6891c8d Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 17 Mar 2012 21:34:34 +0000 Subject: [PATCH 1063/1180] Need to call recalculate_sizes() when changing window with the mouse, from marcel partap. --- server-client.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/server-client.c b/server-client.c index 2f84f011..443f9e38 100644 --- a/server-client.c +++ b/server-client.c @@ -282,16 +282,19 @@ server_client_check_mouse( options_get_number(oo, "mouse-select-window")) { if (mouse->b == MOUSE_UP && c->last_mouse.b != MOUSE_UP) { status_set_window_at(c, mouse->x); + recalculate_sizes(); return; } if (mouse->b & MOUSE_45) { if ((mouse->b & MOUSE_BUTTON) == MOUSE_1) { session_previous(c->session, 0); server_redraw_session(s); + recalculate_sizes(); } if ((mouse->b & MOUSE_BUTTON) == MOUSE_2) { session_next(c->session, 0); server_redraw_session(s); + recalculate_sizes(); } return; } From 87d092d2262031cfb714069525d9d7ec894b7fcc Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 17 Mar 2012 21:37:36 +0000 Subject: [PATCH 1064/1180] Michael Krysiak points out that some terminals (eg mintty) have cursor styles 5 and 6 too, so allow them to be set. --- screen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/screen.c b/screen.c index 3c8a5235..ed5fcfce 100644 --- a/screen.c +++ b/screen.c @@ -96,7 +96,7 @@ screen_reset_tabs(struct screen *s) void screen_set_cursor_style(struct screen *s, u_int style) { - if (style <= 4) + if (style <= 6) s->cstyle = style; } From 95f48a219a3b270e4e6b235745b094db4b7fe9f3 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 17 Mar 2012 21:40:53 +0000 Subject: [PATCH 1065/1180] Add a wrap-search option to turn off wrapping of searches in copy mode. From Jacobo de Vera. --- options-table.c | 5 +++++ tmux.1 | 6 ++++++ window-copy.c | 10 ++++++---- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/options-table.c b/options-table.c index 305bada8..fa71f399 100644 --- a/options-table.c +++ b/options-table.c @@ -669,6 +669,11 @@ const struct options_table_entry window_options_table[] = { .default_str = "#I:#W#F" }, + { .name = "wrap-search", + .type = OPTIONS_TABLE_FLAG, + .default_num = 1 + }, + { .name = "xterm-keys", .type = OPTIONS_TABLE_FLAG, .default_num = 0 diff --git a/tmux.1 b/tmux.1 index 0ab98afe..993a2af3 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2661,6 +2661,12 @@ will generate function key sequences; these have a number included to indicate modifiers such as Shift, Alt or Ctrl. The default is off. +.Pp +.It Xo Ic wrap-search +.Op Ic on | off +.Xc +If this option is set, searches will wrap around the end of the pane contents. +The default is on. .El .It Xo Ic show-options .Op Fl gsw diff --git a/window-copy.c b/window-copy.c index 3d491822..2f1c353c 100644 --- a/window-copy.c +++ b/window-copy.c @@ -984,11 +984,12 @@ window_copy_search_up(struct window_pane *wp, const char *searchstr) struct grid_cell gc; size_t searchlen; u_int i, last, fx, fy, px; - int utf8flag, n, wrapped; + int utf8flag, n, wrapped, wrapflag; if (*searchstr == '\0') return; utf8flag = options_get_number(&wp->window->options, "utf8"); + wrapflag = options_get_number(&wp->window->options, "wrap-search"); searchlen = screen_write_strlen(utf8flag, "%s", searchstr); screen_init(&ss, searchlen, 1, 0); @@ -1021,7 +1022,7 @@ retry: break; } } - if (!n && !wrapped) { + if (wrapflag && !n && !wrapped) { fx = gd->sx - 1; fy = gd->hsize + gd->sy - 1; wrapped = 1; @@ -1041,11 +1042,12 @@ window_copy_search_down(struct window_pane *wp, const char *searchstr) struct grid_cell gc; size_t searchlen; u_int i, first, fx, fy, px; - int utf8flag, n, wrapped; + int utf8flag, n, wrapped, wrapflag; if (*searchstr == '\0') return; utf8flag = options_get_number(&wp->window->options, "utf8"); + wrapflag = options_get_number(&wp->window->options, "wrap-search"); searchlen = screen_write_strlen(utf8flag, "%s", searchstr); screen_init(&ss, searchlen, 1, 0); @@ -1078,7 +1080,7 @@ retry: break; } } - if (!n && !wrapped) { + if (wrapflag && !n && !wrapped) { fx = 0; fy = 0; wrapped = 1; From 50f5d2a7ec9b3497a4d2c8ab4470ea2627edf5b9 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 17 Mar 2012 21:45:25 +0000 Subject: [PATCH 1066/1180] Use snprintf for constructing attribute string, from Tim Ruehsen. --- attributes.c | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/attributes.c b/attributes.c index 81f29452..84e4f9c6 100644 --- a/attributes.c +++ b/attributes.c @@ -26,27 +26,21 @@ const char * attributes_tostring(u_char attr) { static char buf[128]; + size_t len; if (attr == 0) return ("none"); - buf[0] = '\0'; - if (attr & GRID_ATTR_BRIGHT) - strlcat(buf, "bright,", sizeof (buf)); - if (attr & GRID_ATTR_DIM) - strlcat(buf, "dim,", sizeof (buf)); - if (attr & GRID_ATTR_UNDERSCORE) - strlcat(buf, "underscore,", sizeof (buf)); - if (attr & GRID_ATTR_BLINK) - strlcat(buf, "blink,", sizeof (buf)); - if (attr & GRID_ATTR_REVERSE) - strlcat(buf, "reverse,", sizeof (buf)); - if (attr & GRID_ATTR_HIDDEN) - strlcat(buf, "hidden,", sizeof (buf)); - if (attr & GRID_ATTR_ITALICS) - strlcat(buf, "italics,", sizeof (buf)); - if (*buf != '\0') - *(strrchr(buf, ',')) = '\0'; + len = xsnprintf(buf, sizeof buf, "%s%s%s%s%s%s%s", + attr & GRID_ATTR_BRIGHT ? "bright," : "", + attr & GRID_ATTR_DIM ? "dim," : "", + attr & GRID_ATTR_UNDERSCORE ? "underscore," : "", + attr & GRID_ATTR_BLINK ? "blink," : "", + attr & GRID_ATTR_REVERSE ? "reverse," : "", + attr & GRID_ATTR_HIDDEN ? "hidden," : "", + attr & GRID_ATTR_ITALICS ? "italics," : ""); + if (len > 0) + buf[len - 1] = '\0'; return (buf); } From 4f480c901de715a2fa0ec450c57d4881d662413f Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 17 Mar 2012 22:34:12 +0000 Subject: [PATCH 1067/1180] $Id$ -> $OpenBSD$. --- cmd-respawn-pane.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd-respawn-pane.c b/cmd-respawn-pane.c index d4d67d54..d1e52669 100644 --- a/cmd-respawn-pane.c +++ b/cmd-respawn-pane.c @@ -1,4 +1,4 @@ -/* $Id$ */ +/* $OpenBSD$ */ /* * Copyright (c) 2008 Nicholas Marriott From 46210344a62b079ff61435b978da41a0f92caf3a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 17 Mar 2012 22:35:09 +0000 Subject: [PATCH 1068/1180] Add notify hooks for various events, the functions are currently empty stubs but will be filled in for control mode later. From George Nachman. --- Makefile | 2 +- cmd-attach-session.c | 2 ++ cmd-join-pane.c | 3 +++ cmd-new-session.c | 2 ++ cmd-new-window.c | 1 + cmd-rename-session.c | 1 + cmd-split-window.c | 1 + layout-custom.c | 2 ++ layout.c | 2 ++ notify.c | 59 ++++++++++++++++++++++++++++++++++++++++++++ resize.c | 1 + server-fn.c | 2 ++ session.c | 16 ++++++++++-- tmux.h | 10 ++++++++ window.c | 1 + 15 files changed, 102 insertions(+), 3 deletions(-) create mode 100644 notify.c diff --git a/Makefile b/Makefile index dd2e4e98..2e23b71a 100644 --- a/Makefile +++ b/Makefile @@ -31,7 +31,7 @@ SRCS= arguments.c attributes.c cfg.c client.c clock.c \ cmd-pipe-pane.c cmd-capture-pane.c cmd.c \ colour.c environ.c grid-view.c grid-utf8.c grid.c input-keys.c \ input.c key-bindings.c key-string.c format.c \ - layout-custom.c layout-set.c layout.c log.c job.c \ + layout-custom.c layout-set.c layout.c log.c job.c notify.c \ mode-key.c names.c options.c options-table.c paste.c procname.c \ resize.c screen-redraw.c screen-write.c screen.c session.c status.c \ signal.c server-fn.c server.c server-client.c server-window.c \ diff --git a/cmd-attach-session.c b/cmd-attach-session.c index 18e06323..bdf3568e 100644 --- a/cmd-attach-session.c +++ b/cmd-attach-session.c @@ -74,6 +74,7 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx) } ctx->curclient->session = s; + notify_attached_session_changed(ctx->curclient); session_update_activity(s); server_redraw_client(ctx->curclient); s->curw->flags &= ~WINLINK_ALERTFLAGS; @@ -98,6 +99,7 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx) server_write_session(s, MSG_DETACH, NULL, 0); ctx->cmdclient->session = s; + notify_attached_session_changed(ctx->cmdclient); session_update_activity(s); server_write_client(ctx->cmdclient, MSG_READY, NULL, 0); diff --git a/cmd-join-pane.c b/cmd-join-pane.c index 03fb4317..dedda5ef 100644 --- a/cmd-join-pane.c +++ b/cmd-join-pane.c @@ -148,6 +148,8 @@ join_pane(struct cmd *self, struct cmd_ctx *ctx, int not_same_window) if (window_count_panes(src_w) == 0) server_kill_window(src_w); + else + notify_window_layout_changed(src_w); src_wp->window = dst_w; TAILQ_INSERT_AFTER(&dst_w->panes, dst_wp, src_wp, entry); @@ -165,5 +167,6 @@ join_pane(struct cmd *self, struct cmd_ctx *ctx, int not_same_window) } else server_status_session(dst_s); + notify_window_layout_changed(dst_w); return (0); } diff --git a/cmd-new-session.c b/cmd-new-session.c index 5fb9e62c..d40b5095 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -244,6 +244,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) if (old_s != NULL) ctx->cmdclient->last_session = old_s; ctx->cmdclient->session = s; + notify_attached_session_changed(ctx->cmdclient); session_update_activity(s); server_redraw_client(ctx->cmdclient); } else { @@ -251,6 +252,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) if (old_s != NULL) ctx->curclient->last_session = old_s; ctx->curclient->session = s; + notify_attached_session_changed(ctx->curclient); session_update_activity(s); server_redraw_client(ctx->curclient); } diff --git a/cmd-new-window.c b/cmd-new-window.c index c906d4d2..5051ab1a 100644 --- a/cmd-new-window.c +++ b/cmd-new-window.c @@ -89,6 +89,7 @@ cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx) * 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); diff --git a/cmd-rename-session.c b/cmd-rename-session.c index cbda700f..9f741d8d 100644 --- a/cmd-rename-session.c +++ b/cmd-rename-session.c @@ -64,6 +64,7 @@ cmd_rename_session_exec(struct cmd *self, struct cmd_ctx *ctx) RB_INSERT(sessions, &sessions, s); server_status_session(s); + notify_session_renamed(s); return (0); } diff --git a/cmd-split-window.c b/cmd-split-window.c index 08a371c9..5123942e 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -156,6 +156,7 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) format_free(ft); } + notify_window_layout_changed(w); return (0); error: diff --git a/layout-custom.c b/layout-custom.c index 8a4f08dc..dbbb8c14 100644 --- a/layout-custom.c +++ b/layout-custom.c @@ -172,6 +172,8 @@ layout_parse(struct window *w, const char *layout) layout_print_cell(lc, __func__, 0); + notify_window_layout_changed(w); + return (0); fail: diff --git a/layout.c b/layout.c index 1050efc4..4e51a594 100644 --- a/layout.c +++ b/layout.c @@ -483,6 +483,7 @@ layout_resize_pane(struct window_pane *wp, enum layout_type type, int change) /* Fix cell offsets. */ layout_fix_offsets(wp->window->layout_root); layout_fix_panes(wp->window, wp->window->sx, wp->window->sy); + notify_window_layout_changed(wp->window); } void @@ -742,4 +743,5 @@ layout_close_pane(struct window_pane *wp) layout_fix_offsets(wp->window->layout_root); layout_fix_panes(wp->window, wp->window->sx, wp->window->sy); } + notify_window_layout_changed(wp->window); } diff --git a/notify.c b/notify.c new file mode 100644 index 00000000..a9d89ee5 --- /dev/null +++ b/notify.c @@ -0,0 +1,59 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2012 George Nachman + * + * 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 "tmux.h" + +void +notify_window_layout_changed(unused struct window *w) +{ +} + +void +notify_window_unlinked(unused struct session *s, unused struct window *w) +{ +} + +void +notify_window_linked(unused struct session *s, unused struct window *w) +{ +} + +void +notify_window_renamed(unused struct window *w) +{ +} + +void +notify_attached_session_changed(unused struct client *c) +{ +} + +void +notify_session_renamed(unused struct session *s) +{ +} + +void +notify_session_created(unused struct session *s) +{ +} + +void +notify_session_closed(unused struct session *s) +{ +} diff --git a/resize.c b/resize.c index 517a7481..5553ce9a 100644 --- a/resize.c +++ b/resize.c @@ -141,5 +141,6 @@ recalculate_sizes(void) } server_redraw_window(w); + notify_window_layout_changed(w); } } diff --git a/server-fn.c b/server-fn.c index 66298571..f6b1cb7a 100644 --- a/server-fn.c +++ b/server-fn.c @@ -293,6 +293,7 @@ server_link_window(struct session *src, struct winlink *srcwl, * Can't use session_detach as it will destroy session * if this makes it empty. */ + notify_window_unlinked(dst, dstwl->window); dstwl->flags &= ~WINLINK_ALERTFLAGS; winlink_stack_remove(&dst->lastw, dstwl); winlink_remove(&dst->windows, dstwl); @@ -419,6 +420,7 @@ server_destroy_session(struct session *s) } else { c->last_session = NULL; c->session = s_new; + notify_attached_session_changed(c); session_update_activity(s_new); server_redraw_client(c); } diff --git a/session.c b/session.c index 2545d868..0109fd5d 100644 --- a/session.c +++ b/session.c @@ -142,6 +142,7 @@ session_create(const char *name, const char *cmd, const char *cwd, } log_debug("session %s created", s->name); + notify_session_created(s); return (s); } @@ -150,9 +151,11 @@ session_create(const char *name, const char *cmd, const char *cwd, void session_destroy(struct session *s) { + struct winlink *wl; log_debug("session %s destroyed", s->name); RB_REMOVE(sessions, &sessions, s); + notify_session_closed(s); if (s->tio != NULL) xfree(s->tio); @@ -163,8 +166,11 @@ session_destroy(struct session *s) while (!TAILQ_EMPTY(&s->lastw)) winlink_stack_remove(&s->lastw, TAILQ_FIRST(&s->lastw)); - while (!RB_EMPTY(&s->windows)) - winlink_remove(&s->windows, RB_ROOT(&s->windows)); + while (!RB_EMPTY(&s->windows)) { + wl = RB_ROOT(&s->windows); + notify_window_unlinked(s, wl->window); + winlink_remove(&s->windows, wl); + } xfree(s->cwd); @@ -254,6 +260,7 @@ session_new(struct session *s, return (NULL); } winlink_set_window(wl, w); + notify_window_linked(s, w); environ_free(&env); if (options_get_number(&s->options, "set-remain-on-exit")) @@ -274,6 +281,7 @@ session_attach(struct session *s, struct window *w, int idx, char **cause) return (NULL); } winlink_set_window(wl, w); + notify_window_linked(s, w); session_group_synchronize_from(s); return (wl); @@ -288,6 +296,7 @@ session_detach(struct session *s, struct winlink *wl) session_next(s, 0); wl->flags &= ~WINLINK_ALERTFLAGS; + notify_window_unlinked(s, wl->window); winlink_stack_remove(&s->lastw, wl); winlink_remove(&s->windows, wl); session_group_synchronize_from(s); @@ -555,6 +564,7 @@ session_group_synchronize1(struct session *target, struct session *s) RB_FOREACH(wl, winlinks, ww) { wl2 = winlink_add(&s->windows, wl->idx); winlink_set_window(wl2, wl->window); + notify_window_linked(s, wl2->window); wl2->flags |= wl->flags & WINLINK_ALERTFLAGS; } @@ -576,6 +586,8 @@ session_group_synchronize1(struct session *target, struct session *s) /* Then free the old winlinks list. */ while (!RB_EMPTY(&old_windows)) { wl = RB_ROOT(&old_windows); + if (winlink_find_by_window_id(&s->windows, wl->window->id) == NULL) + notify_window_unlinked(s, wl->window); winlink_remove(&old_windows, wl); } } diff --git a/tmux.h b/tmux.h index 9257117a..5f2f3a44 100644 --- a/tmux.h +++ b/tmux.h @@ -1396,6 +1396,16 @@ void mode_key_init_trees(void); void mode_key_init(struct mode_key_data *, struct mode_key_tree *); enum mode_key_cmd mode_key_lookup(struct mode_key_data *, int); +/* notify.c */ +void notify_window_layout_changed(struct window *); +void notify_window_unlinked(struct session *, struct window *); +void notify_window_linked(struct session *, struct window *); +void notify_window_renamed(struct window *); +void notify_attached_session_changed(struct client *); +void notify_session_renamed(struct session *); +void notify_session_created(struct session *); +void notify_session_closed(struct session *); + /* options.c */ int options_cmp(struct options_entry *, struct options_entry *); RB_PROTOTYPE(options_tree, options_entry, entry, options_cmp); diff --git a/window.c b/window.c index f0061293..51d43ac4 100644 --- a/window.c +++ b/window.c @@ -368,6 +368,7 @@ window_set_name(struct window *w, const char *new_name) if (w->name != NULL) xfree(w->name); w->name = xstrdup(new_name); + notify_window_renamed(w); } void From d8805af66bb876d762248d1695872eca3296f0e6 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 17 Mar 2012 22:56:04 +0000 Subject: [PATCH 1069/1180] On xterm 271 and later, put the terminal into SCL 5 and use DECCRA for scrolling the region in panes (if the large region check isn't hit). With help from Ailin Nemui. --- tmux.h | 3 ++- tty-keys.c | 3 +-- tty.c | 43 +++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 44 insertions(+), 5 deletions(-) diff --git a/tmux.h b/tmux.h index 5f2f3a44..8d0b680f 100644 --- a/tmux.h +++ b/tmux.h @@ -1472,8 +1472,9 @@ void tty_putc(struct tty *, u_char); void tty_pututf8(struct tty *, const struct grid_utf8 *); void tty_init(struct tty *, int, char *); int tty_resize(struct tty *); -int tty_set_size(struct tty *tty, u_int sx, u_int sy); +int tty_set_size(struct tty *, u_int, u_int); void tty_start_tty(struct tty *); +void tty_set_version(struct tty *, u_int); void tty_stop_tty(struct tty *); void tty_set_title(struct tty *, const char *); void tty_update_mode(struct tty *, int, struct screen *); diff --git a/tty-keys.c b/tty-keys.c index 37265dce..c5b85ce1 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -728,8 +728,7 @@ tty_keys_device(struct tty *tty, const char *buf, size_t len, size_t *size) a = b = 0; log_debug("received xterm version %u", b); - if (tty->xterm_version == 0) - tty->xterm_version = b; + tty_set_version(tty, b); return (0); } diff --git a/tty.c b/tty.c index a36bf787..c9191a6a 100644 --- a/tty.c +++ b/tty.c @@ -177,7 +177,7 @@ tty_error_callback( void tty_init_termios(int fd, struct termios *orig_tio, struct bufferevent *bufev) { - struct termios tio; + struct termios tio; if (fd == -1 || tcgetattr(fd, orig_tio) != 0) return; @@ -234,6 +234,27 @@ tty_start_tty(struct tty *tty) tty_force_cursor_colour(tty, ""); } +void +tty_set_version(struct tty *tty, u_int version) +{ + if (tty->xterm_version != 0) + return; + tty->xterm_version = version; + + if (tty->xterm_version > 270) { + tty_puts(tty, "\033[65;1\"p"); + + tty_putcode(tty, TTYC_RMACS); + memcpy(&tty->cell, &grid_default_cell, sizeof tty->cell); + + tty->cx = UINT_MAX; + tty->cy = UINT_MAX; + + tty->rupper = UINT_MAX; + tty->rlower = UINT_MAX; + } +} + void tty_stop_tty(struct tty *tty) { @@ -276,6 +297,9 @@ tty_stop_tty(struct tty *tty) tty_raw(tty, "\033[?1000l"); tty_raw(tty, tty_term_string(tty->term, TTYC_RMCUP)); + + if (tty->xterm_version > 270) + tty_raw(tty, "\033[61;1\"p"); } void @@ -844,13 +868,28 @@ tty_cmd_linefeed(struct tty *tty, const struct tty_ctx *ctx) { struct window_pane *wp = ctx->wp; struct screen *s = wp->screen; + char tmp[64]; if (ctx->ocy != ctx->orlower) return; if (ctx->xoff != 0 || screen_size_x(s) < tty->sx || !tty_term_has(tty->term, TTYC_CSR)) { - tty_redraw_region(tty, ctx); + if (tty_large_region(tty, ctx)) + wp->flags |= PANE_REDRAW; + else if (tty->xterm_version > 270) { + snprintf(tmp, sizeof tmp, + "\033[%u;%u;%u;%u;1;%u;%u;1$v", + ctx->yoff + ctx->orupper + 2, + ctx->xoff + 1, + ctx->yoff + ctx->orlower + 1, + ctx->xoff + screen_size_x(s), + ctx->yoff + ctx->orupper + 1, + ctx->xoff + 1); + tty_puts(tty, tmp); + tty_cmd_clearline(tty, ctx); + } else + tty_redraw_region(tty, ctx); return; } From bf9e7a1c688eaa48dc2c0900ccd12a06e35c3ae4 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 19 Mar 2012 08:42:06 +0000 Subject: [PATCH 1070/1180] Move MSG_IDENTIFY to the last sent by the client, this will be needed by control clients and irrelevant for others. --- client.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/client.c b/client.c index d2e53b6d..683aa54c 100644 --- a/client.c +++ b/client.c @@ -250,11 +250,6 @@ client_send_identify(int flags) strlcpy(data.term, term, sizeof data.term) >= sizeof data.term) *data.term = '\0'; - if ((fd = dup(STDIN_FILENO)) == -1) - fatal("dup failed"); - imsg_compose(&client_ibuf, - MSG_IDENTIFY, PROTOCOL_VERSION, -1, fd, &data, sizeof data); - if ((fd = dup(STDOUT_FILENO)) == -1) fatal("dup failed"); imsg_compose(&client_ibuf, @@ -264,6 +259,11 @@ client_send_identify(int flags) fatal("dup failed"); imsg_compose(&client_ibuf, MSG_STDERR, PROTOCOL_VERSION, -1, fd, NULL, 0); + + if ((fd = dup(STDIN_FILENO)) == -1) + fatal("dup failed"); + imsg_compose(&client_ibuf, + MSG_IDENTIFY, PROTOCOL_VERSION, -1, fd, &data, sizeof data); } /* Forward entire environment to server. */ From f59971276ac02d8b42ef222509673ff356800f56 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 20 Mar 2012 11:01:00 +0000 Subject: [PATCH 1071/1180] Add a simple form of output rate limiting by counting the number of certain C0 sequences (linefeeds, backspaces, carriage returns) and if it exceeds a threshold (current default 50/millisecond), start to redraw the pane every 100 milliseconds instead of making each change as it comes. Two configuration options - c0-change-trigger and c0-change-interval. This makes tmux much more responsive under very fast output (for example yes(1) or accidentally cat'ing a large file) but may not be perfect on all terminals and connections - feedback very welcome, particularly where this change has a negative rather than positive effect (making it off by default is a possibility). After much experimentation based originally on a request Robin Lee Powell (which ended with a completely different solution), this idea from discussion with Ailin Nemui. --- input.c | 16 +++++++++++++--- options-table.c | 15 +++++++++++++++ tmux.1 | 18 ++++++++++++++++++ tmux.h | 7 ++++++- tty.c | 2 +- window.c | 40 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 93 insertions(+), 5 deletions(-) diff --git a/input.c b/input.c index 88e633fe..1a38ba33 100644 --- a/input.c +++ b/input.c @@ -908,6 +908,7 @@ input_c0_dispatch(struct input_ctx *ictx) struct screen_write_ctx *sctx = &ictx->ctx; struct window_pane *wp = ictx->wp; struct screen *s = sctx->s; + u_int trigger; log_debug("%s: '%c", __func__, ictx->ch); @@ -919,7 +920,7 @@ input_c0_dispatch(struct input_ctx *ictx) break; case '\010': /* BS */ screen_write_backspace(sctx); - break; + goto count_c0; case '\011': /* HT */ /* Don't tab beyond the end of the line. */ if (s->cx >= screen_size_x(s) - 1) @@ -936,10 +937,10 @@ input_c0_dispatch(struct input_ctx *ictx) case '\013': /* VT */ case '\014': /* FF */ screen_write_linefeed(sctx, 0); - break; + goto count_c0; case '\015': /* CR */ screen_write_carriagereturn(sctx); - break; + goto count_c0; case '\016': /* SO */ ictx->cell.attr |= GRID_ATTR_CHARSET; break; @@ -951,6 +952,15 @@ input_c0_dispatch(struct input_ctx *ictx) break; } + return (0); + +count_c0: + trigger = options_get_number(&wp->window->options, "c0-change-trigger"); + if (++wp->changes == trigger) { + wp->flags |= PANE_DROP; + window_pane_timer_start(wp); + } + return (0); } diff --git a/options-table.c b/options-table.c index fa71f399..9bbcc5d7 100644 --- a/options-table.c +++ b/options-table.c @@ -465,6 +465,21 @@ const struct options_table_entry window_options_table[] = { .default_num = 1 }, + + { .name = "c0-change-trigger", + .type = OPTIONS_TABLE_NUMBER, + .default_num = 50, + .minimum = 0, + .maximum = USHRT_MAX + }, + + { .name = "c0-change-interval", + .type = OPTIONS_TABLE_NUMBER, + .default_num = 100, + .minimum = 1, + .maximum = USHRT_MAX + }, + { .name = "clock-mode-colour", .type = OPTIONS_TABLE_COLOUR, .default_num = 4 diff --git a/tmux.1 b/tmux.1 index 993a2af3..62bcd0f6 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2463,6 +2463,24 @@ It may be switched off globally with: set-window-option -g automatic-rename off .Ed .Pp +.It Ic c0-change-interval Ar interval +.It Ic c0-change-trigger Ar trigger +These two options configure a simple form of rate limiting for a pane. +If +.Nm +sees more than +.Ar trigger +C0 sequences that modify the screen (for example, carriage returns, linefeeds +or backspaces) in one millisecond, it will stop updating the pane immediately and +instead redraw it entirely every +.Ar interval +milliseconds. +This helps to prevent fast output (such as +.Xr yes 1 +overwhelming the terminal). +The default is a trigger of 50 and an interval of 100. +A trigger of zero disables the rate limiting. +.Pp .It Ic clock-mode-colour Ar colour Set clock colour. .Pp diff --git a/tmux.h b/tmux.h index 8d0b680f..87a15485 100644 --- a/tmux.h +++ b/tmux.h @@ -811,6 +811,7 @@ struct window_pane { int flags; #define PANE_REDRAW 0x1 +#define PANE_DROP 0x2 char *cmd; char *shell; @@ -819,6 +820,10 @@ struct window_pane { pid_t pid; char tty[TTY_NAME_MAX]; + u_int changes; + struct event changes_timer; + u_int changes_redraw; + int fd; struct bufferevent *event; @@ -1963,6 +1968,7 @@ void window_destroy_panes(struct window *); struct window_pane *window_pane_find_by_id(u_int); struct window_pane *window_pane_create(struct window *, u_int, u_int, u_int); void window_pane_destroy(struct window_pane *); +void window_pane_timer_start(struct window_pane *); int window_pane_spawn(struct window_pane *, const char *, const char *, const char *, struct environ *, struct termios *, char **); @@ -1981,7 +1987,6 @@ int window_pane_visible(struct window_pane *); char *window_pane_search( struct window_pane *, const char *, u_int *); char *window_printable_flags(struct session *, struct winlink *); - struct window_pane *window_pane_find_up(struct window_pane *); struct window_pane *window_pane_find_down(struct window_pane *); struct window_pane *window_pane_find_left(struct window_pane *); diff --git a/tty.c b/tty.c index c9191a6a..03a99341 100644 --- a/tty.c +++ b/tty.c @@ -661,7 +661,7 @@ tty_write( if (wp->window->flags & WINDOW_REDRAW || wp->flags & PANE_REDRAW) return; - if (!window_pane_visible(wp)) + if (!window_pane_visible(wp) || wp->flags & PANE_DROP) return; for (i = 0; i < ARRAY_LENGTH(&clients); i++) { diff --git a/window.c b/window.c index 51d43ac4..704c7a16 100644 --- a/window.c +++ b/window.c @@ -61,6 +61,7 @@ struct window_pane_tree all_window_panes; u_int next_window_pane_id; u_int next_window_id; +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 *); @@ -648,6 +649,8 @@ window_pane_destroy(struct window_pane *wp) { window_pane_reset_mode(wp); + event_del(&wp->changes_timer); + if (wp->fd != -1) { bufferevent_free(wp->event); close(wp->fd); @@ -764,6 +767,43 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell, return (0); } +void +window_pane_timer_start(struct window_pane *wp) +{ + struct timeval tv; + + tv.tv_sec = 0; + tv.tv_usec = 1000; + + evtimer_del(&wp->changes_timer); + evtimer_set(&wp->changes_timer, window_pane_timer_callback, wp); + evtimer_add(&wp->changes_timer, &tv); +} + +void +window_pane_timer_callback(unused int fd, unused short events, void *data) +{ + struct window_pane *wp = data; + struct window *w = wp->window; + u_int interval, trigger; + + interval = options_get_number(&w->options, "c0-change-interval"); + trigger = options_get_number(&w->options, "c0-change-trigger"); + + if (wp->changes_redraw++ == interval) { + wp->flags |= PANE_REDRAW; + wp->changes_redraw = 0; + + } + + if (trigger == 0 || wp->changes < trigger) { + wp->flags |= PANE_REDRAW; + wp->flags &= ~PANE_DROP; + } else + window_pane_timer_start(wp); + wp->changes = 0; +} + /* ARGSUSED */ void window_pane_read_callback(unused struct bufferevent *bufev, void *data) From 01f2b5d64b18a5da6d04e4ccc66c71b4debc044a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 20 Mar 2012 11:23:12 +0000 Subject: [PATCH 1072/1180] 50 is a too low trigger default on larger terminals, bump to 250. --- options-table.c | 2 +- tmux.1 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/options-table.c b/options-table.c index 9bbcc5d7..965e4ebd 100644 --- a/options-table.c +++ b/options-table.c @@ -468,7 +468,7 @@ const struct options_table_entry window_options_table[] = { { .name = "c0-change-trigger", .type = OPTIONS_TABLE_NUMBER, - .default_num = 50, + .default_num = 250, .minimum = 0, .maximum = USHRT_MAX }, diff --git a/tmux.1 b/tmux.1 index 62bcd0f6..a0074d1c 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2478,7 +2478,7 @@ milliseconds. This helps to prevent fast output (such as .Xr yes 1 overwhelming the terminal). -The default is a trigger of 50 and an interval of 100. +The default is a trigger of 250 and an interval of 100. A trigger of zero disables the rate limiting. .Pp .It Ic clock-mode-colour Ar colour From 5672f2ce6bc87dc5c5215576f8f9a2b6bdadc07a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 20 Mar 2012 14:06:44 +0000 Subject: [PATCH 1073/1180] Check changes_timer with event_initialized before event_del. --- window.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/window.c b/window.c index 704c7a16..34214e71 100644 --- a/window.c +++ b/window.c @@ -649,7 +649,8 @@ window_pane_destroy(struct window_pane *wp) { window_pane_reset_mode(wp); - event_del(&wp->changes_timer); + if (event_initialized(&wp->changes_timer)) + evtimer_del(&wp->changes_timer); if (wp->fd != -1) { bufferevent_free(wp->event); From 90bf560fe4e0fa60bdeaa5c6ecd62187a58f118d Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 20 Mar 2012 17:09:48 +0000 Subject: [PATCH 1074/1180] Add -C -N -T flags to find-window to find in content, name, title. From Jonathan Daugherty. --- cmd-find-window.c | 58 ++++++++++++++++++++++++++++++++++++++++++----- tmux.1 | 14 ++++++++++-- 2 files changed, 64 insertions(+), 8 deletions(-) diff --git a/cmd-find-window.c b/cmd-find-window.c index 6c3c48ce..bba1398f 100644 --- a/cmd-find-window.c +++ b/cmd-find-window.c @@ -29,13 +29,25 @@ int cmd_find_window_exec(struct cmd *, struct cmd_ctx *); +u_int cmd_find_window_match_flags(struct args *); void cmd_find_window_callback(void *, int); void cmd_find_window_free(void *); +/* Flags for determining matching behavior. */ +#define CMD_FIND_WINDOW_BY_TITLE 0x1 +#define CMD_FIND_WINDOW_BY_CONTENT 0x2 +#define CMD_FIND_WINDOW_BY_NAME 0x4 + +#define CMD_FIND_WINDOW_ALL \ + (CMD_FIND_WINDOW_BY_TITLE | \ + CMD_FIND_WINDOW_BY_CONTENT | \ + CMD_FIND_WINDOW_BY_NAME) + + const struct cmd_entry cmd_find_window_entry = { "find-window", "findw", - "t:", 1, 1, - CMD_TARGET_WINDOW_USAGE " match-string", + "CNt:T", 1, 4, + "[-CNT] " CMD_TARGET_WINDOW_USAGE " match-string", 0, NULL, NULL, @@ -46,6 +58,26 @@ struct cmd_find_window_data { struct session *session; }; +u_int +cmd_find_window_match_flags(struct args *args) +{ + u_int match_flags = 0; + + /* Turn on flags based on the options. */ + if (args_has(args, 'T')) + match_flags |= CMD_FIND_WINDOW_BY_TITLE; + if (args_has(args, 'C')) + match_flags |= CMD_FIND_WINDOW_BY_CONTENT; + if (args_has(args, 'N')) + match_flags |= CMD_FIND_WINDOW_BY_NAME; + + /* If none of the flags were set, default to matching anything. */ + if (match_flags == 0) + match_flags = CMD_FIND_WINDOW_ALL; + + return match_flags; +} + int cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx) { @@ -58,7 +90,7 @@ cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx) ARRAY_DECL(, u_int) list_idx; ARRAY_DECL(, char *) list_ctx; char *str, *sres, *sctx, *searchstr; - u_int i, line; + u_int i, line, match_flags; if (ctx->curclient == NULL) { ctx->error(ctx, "must be run interactively"); @@ -69,6 +101,7 @@ cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx) if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL) return (-1); + match_flags = cmd_find_window_match_flags(args); str = args->argv[0]; ARRAY_INIT(&list_idx); @@ -80,12 +113,25 @@ cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx) TAILQ_FOREACH(wp, &wm->window->panes, entry) { i++; - if (fnmatch(searchstr, wm->window->name, 0) == 0) + if ((match_flags & CMD_FIND_WINDOW_BY_NAME) && + fnmatch(searchstr, wm->window->name, 0) == 0) sctx = xstrdup(""); else { - sres = window_pane_search(wp, str, &line); + sres = NULL; + if (match_flags & CMD_FIND_WINDOW_BY_CONTENT) { + sres = window_pane_search( + wp, str, &line); + } + + /* + * If match_title isn't set we don't want to + * bother checking the title, but that also + * constitutes a failure to match so we still + * want to abort. + */ if (sres == NULL && - fnmatch(searchstr, wp->base.title, 0) != 0) + (!(match_flags & CMD_FIND_WINDOW_BY_TITLE) || + fnmatch(searchstr, wp->base.title, 0) != 0)) continue; if (sres == NULL) { diff --git a/tmux.1 b/tmux.1 index a0074d1c..479c2652 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1099,6 +1099,7 @@ to .Ql 9 keys. .It Xo Ic find-window +.Op Fl CNT .Op Fl t Ar target-window .Ar match-string .Xc @@ -1108,8 +1109,17 @@ Search for the pattern .Ar match-string in window names, titles, and visible content (but not history). -If only one window is matched, it'll be automatically selected, otherwise a -choice list is shown. +The flags control matching behavior: +.Fl C +matches only visible window contents, +.Fl N +matches only the window name and +.Fl T +matches only the window title. +The default is +.Fl CNT . +If only one window is matched, it'll be automatically selected, +otherwise a choice list is shown. This command only works from inside .Nm . .It Xo Ic join-pane From b1e4b8769b2edc414194ede0fde31f0175ae8a6b Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 20 Mar 2012 23:20:08 +0000 Subject: [PATCH 1075/1180] Remove a stale comment. --- cmd-find-window.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/cmd-find-window.c b/cmd-find-window.c index bba1398f..e1d5536f 100644 --- a/cmd-find-window.c +++ b/cmd-find-window.c @@ -123,12 +123,6 @@ cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx) wp, str, &line); } - /* - * If match_title isn't set we don't want to - * bother checking the title, but that also - * constitutes a failure to match so we still - * want to abort. - */ if (sres == NULL && (!(match_flags & CMD_FIND_WINDOW_BY_TITLE) || fnmatch(searchstr, wp->base.title, 0) != 0)) From 49ce38b09a68830d313e60dc78b9cf3fd4fbb8e1 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 21 Mar 2012 19:16:07 +0000 Subject: [PATCH 1076/1180] Fix save-buffer usage, from Kazuhiko Sakaguchi. --- cmd-save-buffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd-save-buffer.c b/cmd-save-buffer.c index f45902aa..93ec4b0b 100644 --- a/cmd-save-buffer.c +++ b/cmd-save-buffer.c @@ -33,7 +33,7 @@ int cmd_save_buffer_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_save_buffer_entry = { "save-buffer", "saveb", "ab:", 1, 1, - "[-a] " CMD_BUFFER_USAGE, + "[-a] " CMD_BUFFER_USAGE " path", 0, NULL, NULL, From 7c9d003e99eff8d9a935102e47662f681e7629bb Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 21 Mar 2012 21:28:03 +0000 Subject: [PATCH 1077/1180] Some terminals respond to secondary DA with primary (they ignore the intermediate character). So ignore the possible responses to primary DA. --- tty-keys.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/tty-keys.c b/tty-keys.c index c5b85ce1..a9bdaa1c 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -686,9 +686,9 @@ tty_keys_device(struct tty *tty, const char *buf, size_t len, size_t *size) char tmp[64], *endptr; /* - * Secondary device attributes are \033[>a;b;c. We only request - * attributes on xterm, so we only care about the middle values which - * is the xterm version. + * Primary device attributes are \033[?a;b and secondary are + * \033[>a;b;c. We only request attributes on xterm, so we only care + * about the middle values which is the xterm version. */ *size = 0; @@ -702,7 +702,7 @@ tty_keys_device(struct tty *tty, const char *buf, size_t len, size_t *size) return (-1); if (len == 2) return (1); - if (buf[2] != '>') + if (buf[2] != '>' && buf[2] != '?') return (-1); if (len == 3) return (1); @@ -718,6 +718,10 @@ tty_keys_device(struct tty *tty, const char *buf, size_t len, size_t *size) tmp[i] = '\0'; *size = 4 + i; + /* Only secondary is of interest. */ + if (buf[2] != '>') + return (0); + /* Convert version numbers. */ a = strtoul(tmp, &endptr, 10); if (*endptr == ';') { From c0cfbe12e4089431a2cbc69ba7c6b919cc7d4054 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 22 Mar 2012 11:11:57 +0000 Subject: [PATCH 1078/1180] Accept an argument to show-environment to show one variable, based on a diff from Kazuhiko Sakaguchi. --- cmd-show-environment.c | 17 +++++++++++++++-- tmux.1 | 4 ++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/cmd-show-environment.c b/cmd-show-environment.c index e84ff685..17960321 100644 --- a/cmd-show-environment.c +++ b/cmd-show-environment.c @@ -31,8 +31,8 @@ int cmd_show_environment_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_show_environment_entry = { "show-environment", "showenv", - "gt:", 0, 0, - "[-g] " CMD_TARGET_SESSION_USAGE, + "gt:", 0, 1, + "[-g] " CMD_TARGET_SESSION_USAGE " [name]", 0, NULL, NULL, @@ -55,6 +55,19 @@ cmd_show_environment_exec(struct cmd *self, struct cmd_ctx *ctx) env = &s->environ; } + if (args->argc != 0) { + envent = environ_find(env, args->argv[0]); + if (envent == NULL) { + ctx->error(ctx, "unknown variable: %s", args->argv[0]); + return (-1); + } + if (envent->value != NULL) + ctx->print(ctx, "%s=%s", envent->name, envent->value); + else + ctx->print(ctx, "-%s", envent->name); + return (0); + } + RB_FOREACH(envent, environ, env) { if (envent->value != NULL) ctx->print(ctx, "%s=%s", envent->name, envent->value); diff --git a/tmux.1 b/tmux.1 index 479c2652..971ba931 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2908,12 +2908,16 @@ new process. .It Xo Ic show-environment .Op Fl g .Op Fl t Ar target-session +.Op Ar variable .Xc .D1 (alias: Ic showenv ) Display the environment for .Ar target-session or the global environment with .Fl g . +If +.Ar variable +is omitted, all variables are shown. Variables removed from the environment are prefixed with .Ql - . .El From 0edaa34bfda4aa6ba509688fa32af9e1ee1bb7fc Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 24 Mar 2012 11:23:19 +0000 Subject: [PATCH 1079/1180] Add sys/file.h. --- client.c | 1 + 1 file changed, 1 insertion(+) diff --git a/client.c b/client.c index 683aa54c..030bc36d 100644 --- a/client.c +++ b/client.c @@ -17,6 +17,7 @@ */ #include +#include #include #include #include From cd8e536c430d8a605d5452f03674b7bdfd0b5fa7 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 1 Apr 2012 08:10:56 +0000 Subject: [PATCH 1080/1180] Only find each window once no matter how many panes, from Jonathan Daugherty. --- cmd-find-window.c | 1 + 1 file changed, 1 insertion(+) diff --git a/cmd-find-window.c b/cmd-find-window.c index e1d5536f..c1dde2e2 100644 --- a/cmd-find-window.c +++ b/cmd-find-window.c @@ -142,6 +142,7 @@ cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx) ARRAY_ADD(&list_idx, wm->idx); ARRAY_ADD(&list_ctx, sctx); + break; } } xfree(searchstr); From c11da7ca88b3553cd6e9ecf09843e815fab43d73 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 1 Apr 2012 09:23:31 +0000 Subject: [PATCH 1081/1180] Only exit mouse mode on scroll wheel when actually reaching the end of the history, from James Nylen. --- window-copy.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/window-copy.c b/window-copy.c index 2f1c353c..517f4d49 100644 --- a/window-copy.c +++ b/window-copy.c @@ -822,7 +822,7 @@ window_copy_mouse( { struct window_copy_mode_data *data = wp->modedata; struct screen *s = &data->screen; - u_int i, old_cy; + u_int i; if (m->x >= screen_size_x(s)) return; @@ -835,10 +835,9 @@ window_copy_mouse( for (i = 0; i < 5; i++) window_copy_cursor_up(wp, 0); } else if ((m->b & MOUSE_BUTTON) == MOUSE_2) { - old_cy = data->cy; for (i = 0; i < 5; i++) window_copy_cursor_down(wp, 0); - if (old_cy == data->cy) + if (data->oy == 0) goto reset_mode; } return; From b831f8635409883e2ad2b6feedf05821f8f2ea84 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 1 Apr 2012 10:42:39 +0000 Subject: [PATCH 1082/1180] Add pane_current_path format, suggested by Mikolaj Kucharski. --- format.c | 1 + tmux.1 | 1 + 2 files changed, 2 insertions(+) diff --git a/format.c b/format.c index b7bcd71c..5403f170 100644 --- a/format.c +++ b/format.c @@ -389,6 +389,7 @@ format_window_pane(struct format_tree *ft, struct window_pane *wp) format_add(ft, "pane_start_command", "%s", wp->cmd); if (wp->cwd != NULL) format_add(ft, "pane_start_path", "%s", wp->cwd); + format_add(ft, "pane_current_path", "%s", get_proc_cwd(wp->pid)); format_add(ft, "pane_pid", "%ld", (long) wp->pid); format_add(ft, "pane_tty", "%s", wp->tty); } diff --git a/tmux.1 b/tmux.1 index 971ba931..7b97cd81 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2779,6 +2779,7 @@ The following variables are available, where appropriate: .It Li "host" Ta "Hostname of local host" .It Li "line" Ta "Line number in the list" .It Li "pane_active" Ta "1 if active pane" +.It Li "pane_current_path" Ta "Current path if available" .It Li "pane_dead" Ta "1 if pane is dead" .It Li "pane_height" Ta "Height of pane" .It Li "pane_id" Ta "Unique pane ID" From 85f5485cb5e46d6d574b7a1b8c1357c85b528e2b Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 1 Apr 2012 13:18:38 +0000 Subject: [PATCH 1083/1180] Add a layout history which can be stepped through with select-layout -u and -U commands (bound to 'u' and 'U' by default). --- cmd-resize-pane.c | 1 + cmd-select-layout.c | 47 ++++++++++++++++++++++------- key-bindings.c | 2 ++ layout.c | 72 +++++++++++++++++++++++++++++++++++++++++++++ options-table.c | 7 +++++ tmux.1 | 16 +++++++++- tmux.h | 16 +++++++++- window.c | 1 + 8 files changed, 149 insertions(+), 13 deletions(-) diff --git a/cmd-resize-pane.c b/cmd-resize-pane.c index 1380b283..cabf1da4 100644 --- a/cmd-resize-pane.c +++ b/cmd-resize-pane.c @@ -103,6 +103,7 @@ cmd_resize_pane_exec(struct cmd *self, struct cmd_ctx *ctx) } } + layout_list_add(wp->window); if (args_has(self->args, 'L')) layout_resize_pane(wp, LAYOUT_LEFTRIGHT, -adjust); else if (args_has(self->args, 'R')) diff --git a/cmd-select-layout.c b/cmd-select-layout.c index e1f20a4e..d2352fb4 100644 --- a/cmd-select-layout.c +++ b/cmd-select-layout.c @@ -29,8 +29,8 @@ int cmd_select_layout_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_select_layout_entry = { "select-layout", "selectl", - "npt:", 0, 1, - "[-np] " CMD_TARGET_WINDOW_USAGE " [layout-name]", + "nprut:", 0, 1, + "[-npUu] " CMD_TARGET_WINDOW_USAGE " [layout-name]", 0, cmd_select_layout_key_binding, NULL, @@ -76,6 +76,14 @@ cmd_select_layout_key_binding(struct cmd *self, int key) case '5' | KEYC_ESCAPE: self->args = args_create(1, "tiled"); break; + case 'u': + self->args = args_create(0); + args_set(self->args, 'u', NULL); + break; + case 'U': + self->args = args_create(0); + args_set(self->args, 'U', NULL); + break; default: self->args = args_create(0); break; @@ -87,11 +95,13 @@ cmd_select_layout_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; struct winlink *wl; + struct window *w; const char *layoutname; int next, previous, layout; if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL) return (-1); + w = wl->window; next = self->entry == &cmd_next_layout_entry; if (args_has(self->args, 'n')) @@ -100,6 +110,21 @@ cmd_select_layout_exec(struct cmd *self, struct cmd_ctx *ctx) if (args_has(self->args, 'p')) previous = 1; + layout_list_add(w); + if (args_has(self->args, 'U')) { + if ((layoutname = layout_list_redo(w)) == NULL) { + ctx->error(ctx, "no more layout history"); + return (-1); + } + goto set_layout; + } else if (args_has(self->args, 'u')) { + if ((layoutname = layout_list_undo(w)) == NULL) { + ctx->error(ctx, "no more layout history"); + return (-1); + } + goto set_layout; + } + if (next || previous) { if (next) layout = layout_set_next(wl->window); @@ -121,16 +146,16 @@ cmd_select_layout_exec(struct cmd *self, struct cmd_ctx *ctx) return (0); } - if (args->argc != 0) { - layoutname = args->argv[0]; - if (layout_parse(wl->window, layoutname) == -1) { - ctx->error(ctx, "can't set layout: %s", layoutname); - return (-1); - } - server_redraw_window(wl->window); - ctx->info(ctx, "arranging in: %s", layoutname); + if (args->argc == 0) return (0); - } + layoutname = args->argv[0]; +set_layout: + if (layout_parse(wl->window, layoutname) == -1) { + ctx->error(ctx, "can't set layout: %s", layoutname); + return (-1); + } + server_redraw_window(wl->window); + ctx->info(ctx, "arranging in: %s", layoutname); return (0); } diff --git a/key-bindings.c b/key-bindings.c index fb1590a5..ea27848c 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -130,6 +130,7 @@ key_bindings_init(void) { '?', 0, &cmd_list_keys_entry }, { 'D', 0, &cmd_choose_client_entry }, { 'L', 0, &cmd_switch_client_entry }, + { 'U', 1, &cmd_select_layout_entry }, { '[', 0, &cmd_copy_mode_entry }, { '\'', 0, &cmd_command_prompt_entry }, { '\002', /* C-b */ 0, &cmd_send_prefix_entry }, @@ -148,6 +149,7 @@ key_bindings_init(void) { 'r', 0, &cmd_refresh_client_entry }, { 's', 0, &cmd_choose_session_entry }, { 't', 0, &cmd_clock_mode_entry }, + { 'u', 1, &cmd_select_layout_entry }, { 'w', 0, &cmd_choose_window_entry }, { 'x', 0, &cmd_confirm_before_entry }, { '{', 0, &cmd_swap_pane_entry }, diff --git a/layout.c b/layout.c index 4e51a594..bfe66119 100644 --- a/layout.c +++ b/layout.c @@ -19,6 +19,7 @@ #include #include +#include #include "tmux.h" @@ -745,3 +746,74 @@ layout_close_pane(struct window_pane *wp) } notify_window_layout_changed(wp->window); } + +/* Add layout to list. */ +void +layout_list_add(struct window *w) +{ + struct last_layout *ll, *ll_last; + char *layout; + u_int limit; + + layout = layout_dump(w); + + ll_last = w->layout_list_last; + if (ll_last != NULL && strcmp(ll_last->layout, layout) == 0) { + free(layout); + return; + } + + ll = xmalloc(sizeof *ll); + ll->layout = layout; + if (ll_last == NULL) + TAILQ_INSERT_TAIL(&w->layout_list, ll, entry); + else + TAILQ_INSERT_AFTER(&w->layout_list, ll_last, ll, entry); + w->layout_list_size++; + w->layout_list_last = ll; + + limit = options_get_number(&w->options, "layout-history"); + while (w->layout_list_size > limit) { + ll = TAILQ_LAST(&w->layout_list, last_layouts); + if (ll == w->layout_list_last) + ll = TAILQ_FIRST(&w->layout_list); + + TAILQ_REMOVE(&w->layout_list, ll, entry); + w->layout_list_size--; + + xfree(ll->layout); + xfree(ll); + } +} + +/* Apply next layout from list. */ +const char * +layout_list_redo(struct window *w) +{ + struct last_layout *ll, *ll_last; + + ll_last = w->layout_list_last; + if (ll_last == NULL) + return (NULL); + ll = TAILQ_NEXT(ll_last, entry); + if (ll == NULL) + return (NULL); + w->layout_list_last = ll; + return (ll->layout); +} + +/* Apply previous layout from list. */ +const char * +layout_list_undo(struct window *w) +{ + struct last_layout *ll, *ll_last; + + ll_last = w->layout_list_last; + if (ll_last == NULL) + return (NULL); + ll = TAILQ_PREV(ll_last, last_layouts, entry); + if (ll == NULL) + return (NULL); + w->layout_list_last = ll; + return (ll->layout); +} diff --git a/options-table.c b/options-table.c index 965e4ebd..90833114 100644 --- a/options-table.c +++ b/options-table.c @@ -505,6 +505,13 @@ const struct options_table_entry window_options_table[] = { .default_num = 0 }, + { .name = "layout-history-limit", + .type = OPTIONS_TABLE_NUMBER, + .minimum = 1, + .maximum = USHRT_MAX, + .default_num = 20 + }, + { .name = "main-pane-height", .type = OPTIONS_TABLE_NUMBER, .minimum = 1, diff --git a/tmux.1 b/tmux.1 index 7b97cd81..d6cc5a68 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1451,7 +1451,7 @@ lower) with .Fl U or downward (numerically higher). .It Xo Ic select-layout -.Op Fl np +.Op Fl npUu .Op Fl t Ar target-window .Op Ar layout-name .Xc @@ -1468,6 +1468,13 @@ are equivalent to the and .Ic previous-layout commands. +.Pp +.Fl U +and +.Fl u +step forward and back through previous layouts, up to the maximum set by the +.Ic layout-history-limit +option. .It Xo Ic select-pane .Op Fl lDLRU .Op Fl t Ar target-pane @@ -2509,6 +2516,13 @@ or .Ar height . A value of zero restores the default unlimited setting. .Pp +.It Ic layout-history-limit Ar limit +Set the number of previous layouts stored for recovery with +.Ic select-layout +.Fl U +and +.Fl u . +.Pp .It Ic main-pane-height Ar height .It Ic main-pane-width Ar width Set the width or height of the main (left or top) pane in the diff --git a/tmux.h b/tmux.h index 87a15485..9d8ca08a 100644 --- a/tmux.h +++ b/tmux.h @@ -851,6 +851,13 @@ struct window_pane { TAILQ_HEAD(window_panes, window_pane); RB_HEAD(window_pane_tree, window_pane); +/* Window last layout. */ +struct last_layout { + char *layout; + + TAILQ_ENTRY(last_layout) entry; +}; + /* Window structure. */ struct window { u_int id; @@ -864,6 +871,9 @@ struct window { int lastlayout; struct layout_cell *layout_root; + TAILQ_HEAD(last_layouts, last_layout) layout_list; + u_int layout_list_size; + struct last_layout *layout_list_last; u_int sx; u_int sy; @@ -1998,7 +2008,8 @@ u_int layout_count_cells(struct layout_cell *); struct layout_cell *layout_create_cell(struct layout_cell *); void layout_free_cell(struct layout_cell *); void layout_print_cell(struct layout_cell *, const char *, u_int); -void layout_destroy_cell(struct layout_cell *, struct layout_cell **); +void layout_destroy_cell( + struct layout_cell *, struct layout_cell **); void layout_set_size( struct layout_cell *, u_int, u_int, u_int, u_int); void layout_make_leaf( @@ -2020,6 +2031,9 @@ void layout_assign_pane(struct layout_cell *, struct window_pane *); struct layout_cell *layout_split_pane( struct window_pane *, enum layout_type, int, int); void layout_close_pane(struct window_pane *); +void layout_list_add(struct window *); +const char *layout_list_redo(struct window *); +const char *layout_list_undo(struct window *); /* layout-custom.c */ char *layout_dump(struct window *); diff --git a/window.c b/window.c index 34214e71..036bb941 100644 --- a/window.c +++ b/window.c @@ -292,6 +292,7 @@ window_create1(u_int sx, u_int sy) w->lastlayout = -1; w->layout_root = NULL; + TAILQ_INIT(&w->layout_list); w->sx = sx; w->sy = sy; From e1273fb6a16596cea81e0c105920b88c49722505 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 1 Apr 2012 13:21:38 +0000 Subject: [PATCH 1084/1180] Fix option name. --- layout.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/layout.c b/layout.c index bfe66119..995552fa 100644 --- a/layout.c +++ b/layout.c @@ -772,7 +772,7 @@ layout_list_add(struct window *w) w->layout_list_size++; w->layout_list_last = ll; - limit = options_get_number(&w->options, "layout-history"); + limit = options_get_number(&w->options, "layout-history-limit"); while (w->layout_list_size > limit) { ll = TAILQ_LAST(&w->layout_list, last_layouts); if (ll == w->layout_list_last) From 20d10c608d0f6f9e111677656e8d11680d3fc47b Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 1 Apr 2012 13:27:18 +0000 Subject: [PATCH 1085/1180] Turn some errors down to info. --- cmd-select-layout.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd-select-layout.c b/cmd-select-layout.c index d2352fb4..c79e8c7e 100644 --- a/cmd-select-layout.c +++ b/cmd-select-layout.c @@ -113,13 +113,13 @@ cmd_select_layout_exec(struct cmd *self, struct cmd_ctx *ctx) layout_list_add(w); if (args_has(self->args, 'U')) { if ((layoutname = layout_list_redo(w)) == NULL) { - ctx->error(ctx, "no more layout history"); + ctx->info(ctx, "no more layout history"); return (-1); } goto set_layout; } else if (args_has(self->args, 'u')) { if ((layoutname = layout_list_undo(w)) == NULL) { - ctx->error(ctx, "no more layout history"); + ctx->info(ctx, "no more layout history"); return (-1); } goto set_layout; From c829bdf5370e2f96f533beb627cbb5062a68ae80 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 1 Apr 2012 20:53:47 +0000 Subject: [PATCH 1086/1180] Minor style nits - return (). --- cmd-find-window.c | 2 +- cmd-join-pane.c | 2 +- window-copy.c | 6 +++--- window.c | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/cmd-find-window.c b/cmd-find-window.c index c1dde2e2..3ac3c68b 100644 --- a/cmd-find-window.c +++ b/cmd-find-window.c @@ -75,7 +75,7 @@ cmd_find_window_match_flags(struct args *args) if (match_flags == 0) match_flags = CMD_FIND_WINDOW_ALL; - return match_flags; + return (match_flags); } int diff --git a/cmd-join-pane.c b/cmd-join-pane.c index dedda5ef..708430ca 100644 --- a/cmd-join-pane.c +++ b/cmd-join-pane.c @@ -71,7 +71,7 @@ cmd_join_pane_key_binding(struct cmd *self, int key) int cmd_join_pane_exec(struct cmd *self, struct cmd_ctx *ctx) { - return join_pane(self, ctx, self->entry == &cmd_join_pane_entry); + return (join_pane(self, ctx, self->entry == &cmd_join_pane_entry)); } int diff --git a/window-copy.c b/window-copy.c index 517f4d49..cbd0bb6a 100644 --- a/window-copy.c +++ b/window-copy.c @@ -805,14 +805,14 @@ window_copy_key_numeric_prefix(struct window_pane *wp, int key) key &= KEYC_MASK_KEY; if (key < '0' || key > '9') - return 1; + return (1); if (data->numprefix >= 100) /* no more than three digits */ - return 0; + return (0); data->numprefix = data->numprefix * 10 + key - '0'; window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1); - return 0; + return (0); } /* ARGSUSED */ diff --git a/window.c b/window.c index 036bb941..4a013405 100644 --- a/window.c +++ b/window.c @@ -115,7 +115,7 @@ winlink_find_by_window_id(struct winlinks *wwl, u_int id) if (wl->window->id == id) return (wl); } - return NULL; + return (NULL); } int @@ -273,7 +273,7 @@ window_find_by_id(u_int id) if (w->id == id) return (w); } - return NULL; + return (NULL); } struct window * From 18d3498fb2ecd9dba82cdaa64842e0079015c7e6 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 1 Apr 2012 20:56:47 +0000 Subject: [PATCH 1087/1180] Simplify mouse input function. --- input-keys.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/input-keys.c b/input-keys.c index d875f523..485dd051 100644 --- a/input-keys.c +++ b/input-keys.c @@ -204,7 +204,6 @@ input_mouse(struct window_pane *wp, struct mouse_event *m) { char buf[10]; size_t len; - int value; if (wp->screen->mode & ALL_MOUSE_MODES) { if (wp->screen->mode & MODE_MOUSE_UTF8) { @@ -221,13 +220,15 @@ input_mouse(struct window_pane *wp, struct mouse_event *m) buf[len++] = m->y + 33; } bufferevent_write(wp->event, buf, len); - } else if ((m->b & MOUSE_BUTTON) != MOUSE_2) { - value = options_get_number(&wp->window->options, "mode-mouse"); - if (value == 1 && - window_pane_set_mode(wp, &window_copy_mode) == 0) { + return; + } + + if (options_get_number(&wp->window->options, "mode-mouse") == 1) { + if (window_pane_set_mode(wp, &window_copy_mode) == 0) { window_copy_init_from_pane(wp); if (wp->mode->mouse != NULL) wp->mode->mouse(wp, NULL, m); } + return; } } From 711d2205ddc4a81c26ab8eb7d647c52492540b03 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 1 Apr 2012 21:07:35 +0000 Subject: [PATCH 1088/1180] Fix some indentation. --- layout.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/layout.c b/layout.c index 995552fa..c803aef6 100644 --- a/layout.c +++ b/layout.c @@ -498,18 +498,18 @@ layout_resize_pane_mouse(struct client *c, struct mouse_event *mouse) pane_border = 0; if ((c->last_mouse.b & MOUSE_BUTTON) != MOUSE_UP && - (c->last_mouse.b & MOUSE_RESIZE_PANE)) { + (c->last_mouse.b & MOUSE_RESIZE_PANE)) { TAILQ_FOREACH(wp, &w->panes, entry) { if (wp->xoff + wp->sx == c->last_mouse.x && - wp->yoff <= 1 + c->last_mouse.y && - wp->yoff + wp->sy >= c->last_mouse.y) { + wp->yoff <= 1 + c->last_mouse.y && + wp->yoff + wp->sy >= c->last_mouse.y) { layout_resize_pane(wp, LAYOUT_LEFTRIGHT, mouse->x - c->last_mouse.x); pane_border = 1; } if (wp->yoff + wp->sy == c->last_mouse.y && - wp->xoff <= 1 + c->last_mouse.x && - wp->xoff + wp->sx >= c->last_mouse.x) { + wp->xoff <= 1 + c->last_mouse.x && + wp->xoff + wp->sx >= c->last_mouse.x) { layout_resize_pane(wp, LAYOUT_TOPBOTTOM, mouse->y - c->last_mouse.y); pane_border = 1; @@ -518,14 +518,14 @@ layout_resize_pane_mouse(struct client *c, struct mouse_event *mouse) if (pane_border) server_redraw_window(w); } else if (mouse->b != MOUSE_UP && - mouse->b == (mouse->b & MOUSE_BUTTON)) { + mouse->b == (mouse->b & MOUSE_BUTTON)) { TAILQ_FOREACH(wp, &w->panes, entry) { if ((wp->xoff + wp->sx == mouse->x && - wp->yoff <= 1 + mouse->y && - wp->yoff + wp->sy >= mouse->y) || - (wp->yoff + wp->sy == mouse->y && - wp->xoff <= 1 + mouse->x && - wp->xoff + wp->sx >= mouse->x)) { + wp->yoff <= 1 + mouse->y && + wp->yoff + wp->sy >= mouse->y) || + (wp->yoff + wp->sy == mouse->y && + wp->xoff <= 1 + mouse->x && + wp->xoff + wp->sx >= mouse->x)) { pane_border = 1; } } From ed54f01d2f830935e443b3c009a6ef6085c9ae20 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 1 Apr 2012 21:45:48 +0000 Subject: [PATCH 1089/1180] Fix comment for mouse bits. --- tmux.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tmux.h b/tmux.h index 9d8ca08a..cc37cbaf 100644 --- a/tmux.h +++ b/tmux.h @@ -1102,14 +1102,11 @@ struct tty_ctx { }; /* - * xterm mouse mode is fairly silly. Buttons are in the bottom two - * bits: 0 button 1; 1 button 2; 2 button 3; 3 buttons released. - * - * Bit 3 is shift; bit 4 is meta; bit 5 control. - * - * Bit 6 is added for mouse buttons 4 and 5. + * Mouse input. xterm mouse mode is fairly silly. Buttons are in the bottom two + * bits: 0 = button 1; 1 = button 2; 2 = button 3; 3 = buttons released. Bits + * 3, 4 and 5 are for keys. Bit 6 is set for dragging and 7 for mouse buttons 4 + * and 5. */ -/* Mouse input. */ struct mouse_event { u_int b; #define MOUSE_1 0 @@ -1117,6 +1114,9 @@ struct mouse_event { #define MOUSE_3 2 #define MOUSE_UP 3 #define MOUSE_BUTTON 3 +#define MOUSE_SHIFT 4 +#define MOUSE_ESCAPE 8 +#define MOUSE_CTRL 16 #define MOUSE_DRAG 32 #define MOUSE_45 64 #define MOUSE_RESIZE_PANE 128 /* marker for resizing */ From 631d6b59fdb193cc29d845d1baf30b729a4cb75a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 8 Apr 2012 06:47:26 +0000 Subject: [PATCH 1090/1180] Do not fire name timer when automatic-rename is off, from Tim Ruehsen a while ago. --- cmd-set-option.c | 13 +++++++++++++ names.c | 4 +--- window.c | 4 ++-- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/cmd-set-option.c b/cmd-set-option.c index 153d2d88..ff138873 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -87,6 +87,7 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) struct winlink *wl; struct client *c; struct options *oo; + struct window *w; const char *optstr, *valstr; u_int i; @@ -147,6 +148,18 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) return (-1); } + /* Start or stop timers when automatic-rename changed. */ + if (strcmp (oe->name, "automatic-rename") == 0) { + for (i = 0; i < ARRAY_LENGTH(&windows); i++) { + if ((w = ARRAY_ITEM(&windows, i)) == NULL) + continue; + if (options_get_number(&w->options, "automatic-rename")) + queue_window_name(w); + else if (event_initialized(&w->name_timer)) + evtimer_del(&w->name_timer); + } + } + /* Update sizes and redraw. May not need it but meh. */ recalculate_sizes(); for (i = 0; i < ARRAY_LENGTH(&clients); i++) { diff --git a/names.c b/names.c index 5821d94a..469f9123 100644 --- a/names.c +++ b/names.c @@ -49,9 +49,7 @@ window_name_callback(unused int fd, unused short events, void *data) struct window *w = data; char *name, *wname; - queue_window_name(w); /* XXX even if the option is off? */ - if (!options_get_number(&w->options, "automatic-rename")) - return; + queue_window_name(w); /* stopped when option turned off */ if (w->active->screen != &w->active->base) name = NULL; diff --git a/window.c b/window.c index 4a013405..9071972d 100644 --- a/window.c +++ b/window.c @@ -297,9 +297,9 @@ window_create1(u_int sx, u_int sy) w->sx = sx; w->sy = sy; - queue_window_name(w); - options_init(&w->options, &global_w_options); + if (options_get_number(&w->options, "automatic-rename")) + queue_window_name(w); for (i = 0; i < ARRAY_LENGTH(&windows); i++) { if (ARRAY_ITEM(&windows, i) == NULL) { From 6703ca8d26a57acc0314f58d6899f383d4235acb Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 11 Apr 2012 06:16:14 +0000 Subject: [PATCH 1091/1180] Stop accepting new clients for 1 second on EMFILE/ENFILE. Based on ongoing fixes to other daemons by Theo. --- server-client.c | 2 ++ server.c | 37 +++++++++++++++++++++++++++++++------ tmux.h | 1 + 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/server-client.c b/server-client.c index 443f9e38..b7212379 100644 --- a/server-client.c +++ b/server-client.c @@ -191,6 +191,8 @@ server_client_lost(struct client *c) ARRAY_ADD(&dead_clients, c); c->flags |= CLIENT_DEAD; + server_add_accept(0); /* may be more file descriptors now */ + recalculate_sizes(); server_check_unattached(); server_update_socket(); diff --git a/server.c b/server.c index c269535d..bc0e4ab9 100644 --- a/server.c +++ b/server.c @@ -191,9 +191,7 @@ server_start(int lockfd, char *lockfile) } cfg_finished = 1; - event_set(&server_ev_accept, - server_fd, EV_READ|EV_PERSIST, server_accept_callback, NULL); - event_add(&server_ev_accept, NULL); + server_add_accept(0); memset(&tv, 0, sizeof tv); tv.tv_sec = 1; @@ -337,6 +335,7 @@ server_accept_callback(int fd, short events, unused void *data) socklen_t slen = sizeof sa; int newfd; + server_add_accept(0); if (!(events & EV_READ)) return; @@ -344,6 +343,11 @@ server_accept_callback(int fd, short events, unused void *data) if (newfd == -1) { if (errno == EAGAIN || errno == EINTR || errno == ECONNABORTED) return; + if (errno == ENFILE || errno == EMFILE) { + /* Delete and don't try again for 1 second. */ + server_add_accept(1); + return; + } fatal("accept failed"); } if (server_shutdown) { @@ -353,6 +357,29 @@ server_accept_callback(int fd, short events, unused void *data) server_client_create(newfd); } +/* + * Add accept event. If timeout is nonzero, add as a timeout instead of a read + * event - used to backoff when running out of file descriptors. + */ +void +server_add_accept(int timeout) +{ + struct timeval tv = { timeout, 0 }; + + if (event_initialized(&server_ev_accept)) + event_del(&server_ev_accept); + + if (timeout == 0) { + event_set(&server_ev_accept, + server_fd, EV_READ, server_accept_callback, NULL); + event_add(&server_ev_accept, NULL); + } else { + event_set(&server_ev_accept, + server_fd, EV_TIMEOUT, server_accept_callback, NULL); + event_add(&server_ev_accept, &tv); + } +} + /* Signal handler. */ /* ARGSUSED */ void @@ -370,9 +397,7 @@ server_signal_callback(int sig, unused short events, unused void *data) event_del(&server_ev_accept); close(server_fd); server_fd = server_create_socket(); - event_set(&server_ev_accept, server_fd, - EV_READ|EV_PERSIST, server_accept_callback, NULL); - event_add(&server_ev_accept, NULL); + server_add_accept(0); break; } } diff --git a/tmux.h b/tmux.h index cc37cbaf..160831a3 100644 --- a/tmux.h +++ b/tmux.h @@ -1713,6 +1713,7 @@ extern struct clients dead_clients; extern struct paste_stack global_buffers; int server_start(int, char *); void server_update_socket(void); +void server_add_accept(int); /* server-client.c */ void server_client_create(int); From c6e0af9bdb11e2a1d95859725ecedbba31eb3380 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 11 Apr 2012 07:45:30 +0000 Subject: [PATCH 1092/1180] Turn automatic-rename off properly if turned off by renaming a window. Reported by Romain Francoise. --- names.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/names.c b/names.c index 469f9123..a20d8cfc 100644 --- a/names.c +++ b/names.c @@ -49,7 +49,12 @@ window_name_callback(unused int fd, unused short events, void *data) struct window *w = data; char *name, *wname; - queue_window_name(w); /* stopped when option turned off */ + if (!options_get_number(&w->options, "automatic-rename")) { + if (event_initialized(&w->name_timer)) + event_del(&w->name_timer); + return; + } + queue_window_name(w); if (w->active->screen != &w->active->base) name = NULL; From e8dff6858815eef50b5ed41c6346cf8d8bb113ee Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 22 Apr 2012 05:21:40 +0000 Subject: [PATCH 1093/1180] Handle partial keys properly by making sure the timer has actually expired, fixes problems with mintty reported by Michael Simpson. --- tty-keys.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/tty-keys.c b/tty-keys.c index a9bdaa1c..ddd113e2 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -476,7 +476,6 @@ tty_keys_next(struct tty *tty) goto partial_key; } - /* Is this a mouse key press? */ switch (tty_keys_mouse(tty, buf, len, &size, &mouse)) { case 0: /* yes */ @@ -532,10 +531,11 @@ tty_keys_next(struct tty *tty) partial_key: /* - * Escape but no key string. If have already seen an escape, then the - * timer must have expired, so give up waiting and send the escape. + * Escape but no key string. If have already seen an escape and the + * timer has expired, give up waiting and send the escape. */ - if (tty->flags & TTY_ESCAPE) { + if ((tty->flags & TTY_ESCAPE) && + !evtimer_pending(&tty->key_timer, NULL)) { evbuffer_drain(tty->event->input, 1); key = '\033'; goto handle_key; @@ -544,6 +544,10 @@ partial_key: /* Fall through to start the timer. */ start_timer: + /* If already waiting for timer, do nothing. */ + if (evtimer_pending(&tty->key_timer, NULL)) + return (0); + /* Start the timer and wait for expiry or more data. */ delay = options_get_number(&global_options, "escape-time"); tv.tv_sec = delay / 1000; From 5cbca2e70f146ea90748fcec6056babcf671ad3f Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 22 Apr 2012 05:24:05 +0000 Subject: [PATCH 1094/1180] Fix printing commands with no arguments, from Benjamin Poirier. --- cmd.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/cmd.c b/cmd.c index 1bc17e22..5d8e7209 100644 --- a/cmd.c +++ b/cmd.c @@ -304,11 +304,10 @@ cmd_print(struct cmd *cmd, char *buf, size_t len) if (off < len) { used = args_print(cmd->args, buf + off, len - off); if (used == 0) - buf[off - 1] = '\0'; - else { + off--; + else off += used; - buf[off] = '\0'; - } + buf[off] = '\0'; } return (off); } From ed58b2d3534dfa6c2f8203710d2fbd3c76d46532 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 23 Apr 2012 22:10:45 +0000 Subject: [PATCH 1095/1180] Add -a flag to kill-window, from Thomas Adam. --- cmd-kill-window.c | 16 +++++++++++----- tmux.1 | 9 ++++++++- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/cmd-kill-window.c b/cmd-kill-window.c index 30f4c40e..f734eeaf 100644 --- a/cmd-kill-window.c +++ b/cmd-kill-window.c @@ -28,8 +28,8 @@ int cmd_kill_window_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_kill_window_entry = { "kill-window", "killw", - "t:", 0, 0, - CMD_TARGET_WINDOW_USAGE, + "at:", 0, 0, + "[-a] " CMD_TARGET_WINDOW_USAGE, 0, NULL, NULL, @@ -40,13 +40,19 @@ int cmd_kill_window_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; - struct winlink *wl; + struct winlink *wl, *wl2; if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL) return (-1); - server_kill_window(wl->window); - recalculate_sizes(); + if (args_has(args, 'a')) { + RB_FOREACH(wl2, winlinks, &ctx->curclient->session->windows) { + if (wl != wl2) + server_kill_window(wl2->window); + } + } else + server_kill_window(wl->window); + recalculate_sizes(); return (0); } diff --git a/tmux.1 b/tmux.1 index d6cc5a68..cd28e7da 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1157,11 +1157,18 @@ The .Fl a option kills all but the pane given with .Fl t . -.It Ic kill-window Op Fl t Ar target-window +.It Xo Ic kill-window +.Op Fl a +.Op Fl t Ar target-window +.Xc .D1 (alias: Ic killw ) Kill the current window or the window at .Ar target-window , removing it from any sessions to which it is linked. +The +.Fl a +option kills all but the window given with +.Fl t . .It Ic last-pane Op Fl t Ar target-window .D1 (alias: Ic lastp ) Select the last (previously selected) pane. From e02d1bce98e35b5eeb3073ec9d891363493ed72a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 23 Apr 2012 22:23:14 +0000 Subject: [PATCH 1096/1180] Add window-status-separator option, from Thomas Adam. --- options-table.c | 5 +++++ status.c | 16 ++++++++++++---- tmux.1 | 4 ++++ 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/options-table.c b/options-table.c index 90833114..28e4af7e 100644 --- a/options-table.c +++ b/options-table.c @@ -691,6 +691,11 @@ const struct options_table_entry window_options_table[] = { .default_str = "#I:#W#F" }, + { .name = "window-status-separator", + .type = OPTIONS_TABLE_STRING, + .default_str = " " + }, + { .name = "wrap-search", .type = OPTIONS_TABLE_FLAG, .default_num = 1 diff --git a/status.c b/status.c index 8338fbe4..33ac81ff 100644 --- a/status.c +++ b/status.c @@ -160,11 +160,12 @@ status_redraw(struct client *c) struct winlink *wl; struct screen old_status, window_list; struct grid_cell stdgc, lgc, rgc, gc; + struct options *oo; time_t t; - char *left, *right; + char *left, *right, *sep; u_int offset, needed; u_int wlstart, wlwidth, wlavailable, wloffset, wlsize; - size_t llen, rlen; + size_t llen, rlen, seplen; int larrow, rarrow, utf8flag; /* No status line? */ @@ -230,7 +231,11 @@ status_redraw(struct client *c) if (wl == s->curw) wloffset = wlwidth; - wlwidth += wl->status_width + 1; + + oo = &wl->window->options; + sep = options_get_string(oo, "window-status-separator"); + seplen = screen_write_strlen(utf8flag, "%s", sep); + wlwidth += wl->status_width + seplen; } /* Create a new screen for the window list. */ @@ -241,7 +246,10 @@ status_redraw(struct client *c) RB_FOREACH(wl, winlinks, &s->windows) { screen_write_cnputs(&ctx, -1, &wl->status_cell, utf8flag, "%s", wl->status_text); - screen_write_putc(&ctx, &stdgc, ' '); + + oo = &wl->window->options; + sep = options_get_string(oo, "window-status-separator"); + screen_write_nputs(&ctx, -1, &stdgc, utf8flag, "%s", sep); } screen_write_stop(&ctx); diff --git a/tmux.1 b/tmux.1 index cd28e7da..e5aa3602 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2700,6 +2700,10 @@ option for details of special character sequences available. The default is .Ql #I:#W#F . .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 Xo Ic xterm-keys .Op Ic on | off .Xc From 48e6ebbe1ec8bb2631bbe5afe7c67ea0198d43d4 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 23 Apr 2012 22:40:47 +0000 Subject: [PATCH 1097/1180] Use a helper function to fire choose callback. --- window-choose.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/window-choose.c b/window-choose.c index ccd09afc..70eb651f 100644 --- a/window-choose.c +++ b/window-choose.c @@ -29,6 +29,7 @@ void window_choose_key(struct window_pane *, struct session *, int); void window_choose_mouse( struct window_pane *, struct session *, struct mouse_event *); +void window_choose_fire_callback(struct window_pane *, int); void window_choose_redraw_screen(struct window_pane *); void window_choose_write_line( struct window_pane *, struct screen_write_ctx *, u_int); @@ -169,6 +170,20 @@ window_choose_resize(struct window_pane *wp, u_int sx, u_int sy) window_choose_redraw_screen(wp); } +void +window_choose_fire_callback(struct window_pane *wp, int idx) +{ + struct window_choose_mode_data *data = wp->modedata; + const struct window_mode *oldmode; + + oldmode = wp->mode; + wp->mode = NULL; + + data->callbackfn(data->data, idx); + + wp->mode = oldmode; +} + /* ARGSUSED */ void window_choose_key(struct window_pane *wp, unused struct session *sess, int key) @@ -184,12 +199,12 @@ window_choose_key(struct window_pane *wp, unused struct session *sess, int key) switch (mode_key_lookup(&data->mdata, key)) { case MODEKEYCHOICE_CANCEL: - data->callbackfn(data->data, -1); + window_choose_fire_callback(wp, -1); window_pane_reset_mode(wp); break; case MODEKEYCHOICE_CHOOSE: item = &ARRAY_ITEM(&data->list, data->selected); - data->callbackfn(data->data, item->idx); + window_choose_fire_callback(wp, item->idx); window_pane_reset_mode(wp); break; case MODEKEYCHOICE_UP: @@ -295,7 +310,7 @@ window_choose_key(struct window_pane *wp, unused struct session *sess, int key) data->selected = idx; item = &ARRAY_ITEM(&data->list, data->selected); - data->callbackfn(data->data, item->idx); + window_choose_fire_callback(wp, item->idx); window_pane_reset_mode(wp); break; } @@ -324,7 +339,7 @@ window_choose_mouse( data->selected = idx; item = &ARRAY_ITEM(&data->list, data->selected); - data->callbackfn(data->data, item->idx); + window_choose_fire_callback(wp, item->idx); window_pane_reset_mode(wp); } From 0f9e0d1cfe645f276ef471131b55e9bfe2276758 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 23 Apr 2012 22:43:09 +0000 Subject: [PATCH 1098/1180] Do not return a buffer on the stack, mentioned by jsg a while ago. --- cmd.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cmd.c b/cmd.c index 5d8e7209..a3a70284 100644 --- a/cmd.c +++ b/cmd.c @@ -1325,8 +1325,10 @@ find_home: return (s->cwd); complete_path: - if (root[skip] == '\0') - return (root); + if (root[skip] == '\0') { + strlcpy(path, root, sizeof path); + return (path); + } n = snprintf(path, sizeof path, "%s/%s", root, cwd + skip); if (n > 0 && (size_t)n < sizeof path) return (path); From d3e432069bd86b696fa65cccade5a82732a1f310 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 23 Apr 2012 23:18:43 +0000 Subject: [PATCH 1099/1180] Use an enum for client exit reasons, from George Nachman. --- client.c | 57 +++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 46 insertions(+), 11 deletions(-) diff --git a/client.c b/client.c index 030bc36d..84edf128 100644 --- a/client.c +++ b/client.c @@ -35,7 +35,16 @@ struct imsgbuf client_ibuf; struct event client_event; -const char *client_exitmsg; +enum { + CLIENT_EXIT_NONE, + CLIENT_EXIT_DETACHED, + CLIENT_EXIT_DETACHED_HUP, + CLIENT_EXIT_LOST_TTY, + CLIENT_EXIT_TERMINATED, + CLIENT_EXIT_LOST_SERVER, + CLIENT_EXIT_EXITED, + CLIENT_EXIT_SERVER_EXITED, +} client_exitreason = CLIENT_EXIT_NONE; int client_exitval; enum msgtype client_exittype; int client_attached; @@ -121,6 +130,31 @@ failed: return (-1); } +/* Get exit string from reason number. */ +const char * +client_exit_message(void) +{ + switch (client_exitreason) { + case CLIENT_EXIT_NONE: + break; + case CLIENT_EXIT_DETACHED: + return ("detached"); + case CLIENT_EXIT_DETACHED_HUP: + return ("detached and SIGHUP"); + case CLIENT_EXIT_LOST_TTY: + return ("lost tty"); + case CLIENT_EXIT_TERMINATED: + return ("terminated"); + case CLIENT_EXIT_LOST_SERVER: + return ("lost server"); + case CLIENT_EXIT_EXITED: + return ("exited"); + case CLIENT_EXIT_SERVER_EXITED: + return ("server exited"); + } + return ("unknown reason"); +} + /* Client main loop. */ int client_main(int argc, char **argv, int flags) @@ -170,7 +204,8 @@ client_main(int argc, char **argv, int flags) * if the socket path matches $TMUX, this is probably the same server. */ if (shell_cmd == NULL && environ_path != NULL && - cmdflags & CMD_CANTNEST && strcmp(socket_path, environ_path) == 0) { + (cmdflags & CMD_CANTNEST) && + strcmp(socket_path, environ_path) == 0) { log_warnx("sessions should be nested with care. " "unset $TMUX to force."); return (1); @@ -223,8 +258,8 @@ client_main(int argc, char **argv, int flags) /* Print the exit message, if any, and exit. */ if (client_attached) { - if (client_exitmsg != NULL && !login_shell) - printf("[%s]\n", client_exitmsg); + if (client_exitreason != CLIENT_EXIT_NONE && !login_shell) + printf("[%s]\n", client_exit_message()); ppid = getppid(); if (client_exittype == MSG_DETACHKILL && ppid > 1) @@ -323,12 +358,12 @@ client_signal(int sig, unused short events, unused void *data) } else { switch (sig) { case SIGHUP: - client_exitmsg = "lost tty"; + client_exitreason = CLIENT_EXIT_LOST_TTY; client_exitval = 1; client_write_server(MSG_EXITING, NULL, 0); break; case SIGTERM: - client_exitmsg = "terminated"; + client_exitreason = CLIENT_EXIT_TERMINATED; client_exitval = 1; client_write_server(MSG_EXITING, NULL, 0); break; @@ -380,7 +415,7 @@ client_callback(unused int fd, short events, void *data) return; lost_server: - client_exitmsg = "lost server"; + client_exitreason = CLIENT_EXIT_LOST_SERVER; client_exitval = 1; event_loopexit(NULL); } @@ -477,9 +512,9 @@ client_dispatch_attached(void) client_exittype = imsg.hdr.type; if (imsg.hdr.type == MSG_DETACHKILL) - client_exitmsg = "detached and SIGHUP"; + client_exitreason = CLIENT_EXIT_DETACHED_HUP; else - client_exitmsg = "detached"; + client_exitreason = CLIENT_EXIT_DETACHED; client_write_server(MSG_EXITING, NULL, 0); break; case MSG_EXIT: @@ -488,7 +523,7 @@ client_dispatch_attached(void) fatalx("bad MSG_EXIT size"); client_write_server(MSG_EXITING, NULL, 0); - client_exitmsg = "exited"; + client_exitreason = CLIENT_EXIT_EXITED; break; case MSG_EXITED: if (datalen != 0) @@ -501,7 +536,7 @@ client_dispatch_attached(void) fatalx("bad MSG_SHUTDOWN size"); client_write_server(MSG_EXITING, NULL, 0); - client_exitmsg = "server exited"; + client_exitreason = CLIENT_EXIT_SERVER_EXITED; client_exitval = 1; break; case MSG_SUSPEND: From 94795eb48e50ee247ebe5be2efc790268fa80f1a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 23 Apr 2012 23:25:02 +0000 Subject: [PATCH 1100/1180] Add missing prototype. --- client.c | 1 + 1 file changed, 1 insertion(+) diff --git a/client.c b/client.c index 84edf128..113083fd 100644 --- a/client.c +++ b/client.c @@ -59,6 +59,7 @@ void client_signal(int, short, void *); void client_callback(int, short, void *); int client_dispatch_attached(void); int client_dispatch_wait(void *); +const char *client_exit_message(void); /* * Get server create lock. If already held then server start is happening in From ff5155f71923b078a35509260f01be46222dafb7 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 25 Apr 2012 21:12:49 +0000 Subject: [PATCH 1101/1180] Add a buffer with all input from last ground state, will be used for control mode. From George Nachman. --- input.c | 39 +++++++++++++++++++++++++++++++-------- tmux.h | 6 ++++++ 2 files changed, 37 insertions(+), 8 deletions(-) diff --git a/input.c b/input.c index 1a38ba33..eee0f78d 100644 --- a/input.c +++ b/input.c @@ -47,9 +47,11 @@ */ /* Helper functions. */ +struct input_transition; int input_split(struct input_ctx *); int input_get(struct input_ctx *, u_int, int, int); void input_reply(struct input_ctx *, const char *, ...); +void input_set_state(struct window_pane *, const struct input_transition *); /* Transition entry/exit handlers. */ void input_clear(struct input_ctx *); @@ -692,12 +694,34 @@ input_init(struct window_pane *wp) ictx->state = &input_state_ground; ictx->flags = 0; + + ictx->since_ground = evbuffer_new(); } /* Destroy input parser. */ void -input_free(unused struct window_pane *wp) +input_free(struct window_pane *wp) { + if (wp != NULL) + evbuffer_free(wp->ictx.since_ground); +} + +/* Change input state. */ +void +input_set_state(struct window_pane *wp, const struct input_transition *itr) +{ + struct input_ctx *ictx = &wp->ictx; + struct evbuffer *ground_evb = ictx->since_ground; + + if (ictx->state->exit != NULL) + ictx->state->exit(ictx); + + if (itr->state == &input_state_ground) + evbuffer_drain(ground_evb, EVBUFFER_LENGTH(ground_evb)); + + ictx->state = itr->state; + if (ictx->state->enter != NULL) + ictx->state->enter(ictx); } /* Parse input. */ @@ -755,13 +779,12 @@ input_parse(struct window_pane *wp) continue; /* And switch state, if necessary. */ - if (itr->state != NULL) { - if (ictx->state->exit != NULL) - ictx->state->exit(ictx); - ictx->state = itr->state; - if (ictx->state->enter != NULL) - ictx->state->enter(ictx); - } + if (itr->state != NULL) + input_set_state(wp, itr); + + /* If not in ground state, save input. */ + if (ictx->state != &input_state_ground) + evbuffer_add(ictx->since_ground, &ictx->ch, 1); } /* Close the screen. */ diff --git a/tmux.h b/tmux.h index 160831a3..b095e3c7 100644 --- a/tmux.h +++ b/tmux.h @@ -777,6 +777,12 @@ struct input_ctx { #define INPUT_DISCARD 0x1 const struct input_state *state; + + /* + * All input received since we were last in the ground state. Sent to + * control clients on connection. + */ + struct evbuffer *since_ground; }; /* From e60f48ab09f75c622f45718797f83964a28769c0 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 29 Apr 2012 07:33:41 +0000 Subject: [PATCH 1102/1180] Use int not u_char for colours from options since they may have bit 8 set to mark them as 256-colour. Reported by Chris Johnson. --- status.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/status.c b/status.c index 33ac81ff..b90d1885 100644 --- a/status.c +++ b/status.c @@ -81,7 +81,7 @@ status_redraw_get_left(struct client *c, { struct session *s = c->session; char *left; - u_char fg, bg, attr; + int fg, bg, attr; size_t leftlen; fg = options_get_number(&s->options, "status-left-fg"); @@ -111,7 +111,7 @@ status_redraw_get_right(struct client *c, { struct session *s = c->session; char *right; - u_char fg, bg, attr; + int fg, bg, attr; size_t rightlen; fg = options_get_number(&s->options, "status-right-fg"); @@ -683,7 +683,7 @@ status_print( struct session *s = c->session; const char *fmt; char *text; - u_char fg, bg, attr; + int fg, bg, attr; fg = options_get_number(oo, "window-status-fg"); if (fg != 8) From a6c22d650b2d9fba8eb069b488555ab71e5096d6 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 29 Apr 2012 17:20:01 +0000 Subject: [PATCH 1103/1180] Add a flag to move-window to renumber the windows in a session (closing any gaps) and add an option to do this automatically each time a window is killed. From Thomas Adam. --- cmd-move-window.c | 17 ++++++++++++++--- options-table.c | 5 +++++ server-fn.c | 3 +++ session.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ tmux.1 | 17 ++++++++++++++++- tmux.h | 1 + 6 files changed, 85 insertions(+), 4 deletions(-) diff --git a/cmd-move-window.c b/cmd-move-window.c index ee3ba59c..5e30d6b5 100644 --- a/cmd-move-window.c +++ b/cmd-move-window.c @@ -30,8 +30,8 @@ int cmd_move_window_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_move_window_entry = { "move-window", "movew", - "dks:t:", 0, 0, - "[-dk] " CMD_SRCDST_WINDOW_USAGE, + "dkrs:t:", 0, 0, + "[-dkr] " CMD_SRCDST_WINDOW_USAGE, 0, NULL, NULL, @@ -42,11 +42,22 @@ int cmd_move_window_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; - struct session *src, *dst; + struct session *src, *dst, *s; struct winlink *wl; char *cause; int idx, kflag, dflag; + if ((s = ctx->curclient->session) == NULL) + return (-1); + + if (args_has(args, 'r')) + { + session_renumber_windows(s); + recalculate_sizes(); + + return (0); + } + if ((wl = cmd_find_window(ctx, args_get(args, 's'), &src)) == NULL) return (-1); if ((idx = cmd_find_index(ctx, args_get(args, 't'), &dst)) == -2) diff --git a/options-table.c b/options-table.c index 28e4af7e..3e471908 100644 --- a/options-table.c +++ b/options-table.c @@ -274,6 +274,11 @@ const struct options_table_entry session_options_table[] = { .default_num = KEYC_NONE, }, + { .name = "renumber-windows", + .type = OPTIONS_TABLE_FLAG, + .default_num = 0 + }, + { .name = "repeat-time", .type = OPTIONS_TABLE_NUMBER, .minimum = 0, diff --git a/server-fn.c b/server-fn.c index f6b1cb7a..600955af 100644 --- a/server-fn.c +++ b/server-fn.c @@ -263,6 +263,9 @@ server_kill_window(struct window *w) } else server_redraw_session_group(s); } + + if (options_get_number(&s->options, "renumber-windows")) + session_renumber_windows(s); } } diff --git a/session.c b/session.c index 0109fd5d..b3f03541 100644 --- a/session.c +++ b/session.c @@ -591,3 +591,49 @@ session_group_synchronize1(struct session *target, struct session *s) winlink_remove(&old_windows, wl); } } + +/* Renumber the windows across winlinks attached to a specific session. */ +void +session_renumber_windows(struct session *s) +{ + struct winlink *wl, *wl1, *wl_new; + struct winlinks old_wins; + struct winlink_stack old_lastw; + int new_idx, new_curw_idx; + + /* Save and replace old window list. */ + memcpy(&old_wins, &s->windows, sizeof old_wins); + RB_INIT(&s->windows); + + /* Start renumbering from the base-index if it's set. */ + new_idx = options_get_number(&s->options, "base-index"); + new_curw_idx = 0; + + /* Go through the winlinks and assign new indexes. */ + RB_FOREACH(wl, winlinks, &old_wins) { + wl_new = winlink_add(&s->windows, new_idx); + winlink_set_window(wl_new, wl->window); + wl_new->flags |= wl->flags & WINLINK_ALERTFLAGS; + + if (wl == s->curw) + new_curw_idx = wl_new->idx; + + new_idx++; + } + + /* Fix the stack of last windows now. */ + memcpy(&old_lastw, &s->lastw, sizeof old_lastw); + TAILQ_INIT(&s->lastw); + TAILQ_FOREACH(wl, &old_lastw, sentry) { + wl_new = winlink_find_by_index(&s->windows, wl->idx); + if (wl_new != NULL) + TAILQ_INSERT_TAIL(&s->lastw, wl_new, sentry); + } + + /* Set the current window. */ + s->curw = winlink_find_by_index(&s->windows, new_curw_idx); + + /* Free the old winlinks (reducing window references too). */ + RB_FOREACH_SAFE(wl, winlinks, &old_wins, wl1) + winlink_remove(&old_wins, wl); +} diff --git a/tmux.1 b/tmux.1 index e5aa3602..c0531775 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1258,7 +1258,7 @@ and .Ar dst-pane may belong to the same window. .It Xo Ic move-window -.Op Fl dk +.Op Fl rdk .Op Fl s Ar src-window .Op Fl t Ar dst-window .Xc @@ -1269,6 +1269,12 @@ except the window at .Ar src-window is moved to .Ar dst-window . +With +.Fl r , +all windows in the session are renumbered in sequential order, respecting +the +.Ic base-index +option. .It Xo Ic new-window .Op Fl adkP .Op Fl c Ar start-directory @@ -2122,6 +2128,15 @@ Set the pane border colour for panes aside from the active pane. Set the key accepted as a prefix key. .It Ic prefix2 Ar key Set a secondary key accepted as a prefix key. +.It Xo Ic renumber-windows +.Op Ic on | off +.Xc +If on, when a window is closed in a session, automatically renumber the other +windows in numerical order. +This respects the +.Ic base-index +option if it has been set. +If off, do not renumber the windows. .It Ic repeat-time Ar time Allow multiple commands to be entered without pressing the prefix-key again in the specified diff --git a/tmux.h b/tmux.h index b095e3c7..fdbe2724 100644 --- a/tmux.h +++ b/tmux.h @@ -2116,6 +2116,7 @@ void session_group_remove(struct session *); void session_group_synchronize_to(struct session *); void session_group_synchronize_from(struct session *); void session_group_synchronize1(struct session *, struct session *); +void session_renumber_windows(struct session *); /* utf8.c */ void utf8_build(void); From cc979bda0f2e4203d02038805c7c62cbae243f1d Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 2 May 2012 19:29:13 +0000 Subject: [PATCH 1104/1180] default-path has the same possibilities as new-window -c now. --- tmux.1 | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/tmux.1 b/tmux.1 index c0531775..989bb0ea 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1944,16 +1944,10 @@ Set the default working directory for new panes. If empty (the default), the working directory is determined from the process running in the active pane, from the command line environment or from the working directory where the session was created. -If -.Ar path -is "$HOME" or "~", the value of the -.Ev HOME -environment variable is used. -If -.Ar path -is ".", the working directory when -.Nm -was started is used. +Otherwise the same options are available as for the +.Fl c +flag to +.Ic new-window . .It Ic default-shell Ar path Specify the default shell. This is used as the login shell for new windows when the From f66b105c2100c63e591f6d7bf4db817ffdb00f63 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 5 May 2012 17:40:47 +0000 Subject: [PATCH 1105/1180] Make unbind-key -a work with -t, based on a diff from Kazuhiko Sakaguchi. --- cmd-unbind-key.c | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/cmd-unbind-key.c b/cmd-unbind-key.c index 22a35ed0..4a061061 100644 --- a/cmd-unbind-key.c +++ b/cmd-unbind-key.c @@ -42,8 +42,8 @@ const struct cmd_entry cmd_unbind_key_entry = { int cmd_unbind_key_check(struct args *args) { - if (args_has(args, 'a') && (args->argc != 0 || args_has(args, 't'))) - return (-1); + if (args_has(args, 'a') && args->argc != 0) + return (-1); if (!args_has(args, 'a') && args->argc != 1) return (-1); return (0); @@ -56,7 +56,19 @@ cmd_unbind_key_exec(struct cmd *self, unused struct cmd_ctx *ctx) struct key_binding *bd; int key; - if (args_has(args, 'a')) { + if (!args_has(args, 'a')) { + key = key_string_lookup_string(args->argv[0]); + if (key == KEYC_NONE) { + ctx->error(ctx, "unknown key: %s", args->argv[0]); + return (-1); + } + } else + key = KEYC_NONE; + + if (args_has(args, 't')) + return (cmd_unbind_key_table(self, ctx, key)); + + if (key == KEYC_NONE) { while (!RB_EMPTY(&key_bindings)) { bd = RB_ROOT(&key_bindings); key_bindings_remove(bd->key); @@ -64,15 +76,6 @@ cmd_unbind_key_exec(struct cmd *self, unused struct cmd_ctx *ctx) return (0); } - key = key_string_lookup_string(args->argv[0]); - if (key == KEYC_NONE) { - ctx->error(ctx, "unknown key: %s", args->argv[0]); - return (-1); - } - - if (args_has(args, 't')) - return (cmd_unbind_key_table(self, ctx, key)); - if (!args_has(args, 'n')) key |= KEYC_PREFIX; key_bindings_remove(key); @@ -93,6 +96,15 @@ cmd_unbind_key_table(struct cmd *self, struct cmd_ctx *ctx, int key) return (-1); } + if (key == KEYC_NONE) { + while (!RB_EMPTY(mtab->tree)) { + mbind = RB_ROOT(mtab->tree); + RB_REMOVE(mode_key_tree, mtab->tree, mbind); + xfree(mbind); + } + return (0); + } + mtmp.key = key; mtmp.mode = !!args_has(args, 'c'); if ((mbind = RB_FIND(mode_key_tree, mtab->tree, &mtmp)) != NULL) { From 3e6454f2d6a87cf173617b8232fca77934bc6a6c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 5 May 2012 18:17:59 +0000 Subject: [PATCH 1106/1180] Pull CRA out into a separate function and add ERA, from Ailin Nemui. --- tty.c | 53 ++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 11 deletions(-) diff --git a/tty.c b/tty.c index 03a99341..6b22c851 100644 --- a/tty.c +++ b/tty.c @@ -44,6 +44,10 @@ void tty_colours_fg(struct tty *, const struct grid_cell *); void tty_colours_bg(struct tty *, const struct grid_cell *); int tty_large_region(struct tty *, const struct tty_ctx *); +void tty_cra_pane(struct tty *, + const struct tty_ctx *, u_int, u_int, u_int, u_int, u_int, u_int); +void tty_era_pane(struct tty *, + const struct tty_ctx *, u_int, u_int, u_int, u_int); void tty_redraw_region(struct tty *, const struct tty_ctx *); void tty_emulate_repeat( struct tty *, enum tty_code_code, enum tty_code_code, u_int); @@ -52,6 +56,8 @@ void tty_cell(struct tty *, #define tty_use_acs(tty) \ (tty_term_has(tty->term, TTYC_ACSC) && !((tty)->flags & TTY_UTF8)) +#define tty_use_rect(tty) \ + (tty->xterm_version > 270) void tty_init(struct tty *tty, int fd, char *term) @@ -689,6 +695,38 @@ tty_write( } } +void +tty_cra_pane(struct tty *tty, const struct tty_ctx *ctx, + u_int t, u_int l, u_int b, u_int r, u_int tt, u_int tl) +{ + char tmp[64]; + + snprintf(tmp, sizeof tmp, + "\033[%u;%u;%u;%u;1;%u;%u;1$v", + ctx->yoff + t + 1, + ctx->xoff + l + 1, + ctx->yoff + b + 1, + ctx->xoff + r + 1, + ctx->yoff + tt + 1, + ctx->xoff + tl + 1); + tty_puts(tty, tmp); +} + +void +tty_era_pane(struct tty *tty, const struct tty_ctx *ctx, + u_int t, u_int l, u_int b, u_int r) +{ + char tmp[64]; + + snprintf(tmp, sizeof tmp, + "\033[%u;%u;%u;%u$z", + ctx->yoff + t + 1, + ctx->xoff + l + 1, + ctx->yoff + b + 1, + ctx->xoff + r + 1); + tty_puts(tty, tmp); +} + void tty_cmd_insertcharacter(struct tty *tty, const struct tty_ctx *ctx) { @@ -868,7 +906,6 @@ tty_cmd_linefeed(struct tty *tty, const struct tty_ctx *ctx) { struct window_pane *wp = ctx->wp; struct screen *s = wp->screen; - char tmp[64]; if (ctx->ocy != ctx->orlower) return; @@ -877,16 +914,10 @@ tty_cmd_linefeed(struct tty *tty, const struct tty_ctx *ctx) !tty_term_has(tty->term, TTYC_CSR)) { if (tty_large_region(tty, ctx)) wp->flags |= PANE_REDRAW; - else if (tty->xterm_version > 270) { - snprintf(tmp, sizeof tmp, - "\033[%u;%u;%u;%u;1;%u;%u;1$v", - ctx->yoff + ctx->orupper + 2, - ctx->xoff + 1, - ctx->yoff + ctx->orlower + 1, - ctx->xoff + screen_size_x(s), - ctx->yoff + ctx->orupper + 1, - ctx->xoff + 1); - tty_puts(tty, tmp); + else if (tty_use_rect(tty)) { + tty_cra_pane (tty, ctx, ctx->orupper + 1, 0, + ctx->orlower, screen_size_x(s) - 1, + ctx->orupper, 0); tty_cmd_clearline(tty, ctx); } else tty_redraw_region(tty, ctx); From 132403b6bec15eaf02e4e9742f1f67a9ce271737 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 5 May 2012 18:31:09 +0000 Subject: [PATCH 1107/1180] Missing ()s in macros. --- tty.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tty.c b/tty.c index 6b22c851..1c6f7d5b 100644 --- a/tty.c +++ b/tty.c @@ -55,9 +55,9 @@ void tty_cell(struct tty *, const struct grid_cell *, const struct grid_utf8 *); #define tty_use_acs(tty) \ - (tty_term_has(tty->term, TTYC_ACSC) && !((tty)->flags & TTY_UTF8)) + (tty_term_has((tty)->term, TTYC_ACSC) && !((tty)->flags & TTY_UTF8)) #define tty_use_rect(tty) \ - (tty->xterm_version > 270) + ((tty)->xterm_version > 270) void tty_init(struct tty *tty, int fd, char *term) From 96a34a0c0a6e42dc3cccc386f0d4809dc1facc68 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 5 May 2012 18:45:55 +0000 Subject: [PATCH 1108/1180] Tidy up by adding a macro for the pane being the full screen width, from Ailin Nemui. --- tty.c | 35 ++++++++++++----------------------- 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/tty.c b/tty.c index 1c6f7d5b..de153382 100644 --- a/tty.c +++ b/tty.c @@ -59,6 +59,9 @@ void tty_cell(struct tty *, #define tty_use_rect(tty) \ ((tty)->xterm_version > 270) +#define tty_pane_full_width(tty, ctx) \ + ((ctx)->xoff == 0 && screen_size_x((ctx)->wp->screen) >= (tty)->sx) + void tty_init(struct tty *tty, int fd, char *term) { @@ -781,10 +784,7 @@ tty_cmd_deletecharacter(struct tty *tty, const struct tty_ctx *ctx) void tty_cmd_insertline(struct tty *tty, const struct tty_ctx *ctx) { - struct window_pane *wp = ctx->wp; - struct screen *s = wp->screen; - - if (ctx->xoff != 0 || screen_size_x(s) < tty->sx || + if (!tty_pane_full_width(tty, ctx) || !tty_term_has(tty->term, TTYC_CSR) || !tty_term_has(tty->term, TTYC_IL1)) { tty_redraw_region(tty, ctx); @@ -802,10 +802,7 @@ tty_cmd_insertline(struct tty *tty, const struct tty_ctx *ctx) void tty_cmd_deleteline(struct tty *tty, const struct tty_ctx *ctx) { - struct window_pane *wp = ctx->wp; - struct screen *s = wp->screen; - - if (ctx->xoff != 0 || screen_size_x(s) < tty->sx || + if (!tty_pane_full_width(tty, ctx) || !tty_term_has(tty->term, TTYC_CSR) || !tty_term_has(tty->term, TTYC_DL1)) { tty_redraw_region(tty, ctx); @@ -831,8 +828,7 @@ tty_cmd_clearline(struct tty *tty, const struct tty_ctx *ctx) tty_cursor_pane(tty, ctx, 0, ctx->ocy); - if (ctx->xoff == 0 && screen_size_x(s) >= tty->sx && - tty_term_has(tty->term, TTYC_EL)) { + if (tty_pane_full_width(tty, ctx) && tty_term_has(tty->term, TTYC_EL)) { tty_putcode(tty, TTYC_EL); } else { for (i = 0; i < screen_size_x(s); i++) @@ -851,8 +847,7 @@ tty_cmd_clearendofline(struct tty *tty, const struct tty_ctx *ctx) tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); - if (ctx->xoff == 0 && screen_size_x(s) >= tty->sx && - tty_term_has(tty->term, TTYC_EL)) + if (tty_pane_full_width(tty, ctx) && tty_term_has(tty->term, TTYC_EL)) tty_putcode(tty, TTYC_EL); else { for (i = ctx->ocx; i < screen_size_x(s); i++) @@ -880,13 +875,10 @@ tty_cmd_clearstartofline(struct tty *tty, const struct tty_ctx *ctx) void tty_cmd_reverseindex(struct tty *tty, const struct tty_ctx *ctx) { - struct window_pane *wp = ctx->wp; - struct screen *s = wp->screen; - if (ctx->ocy != ctx->orupper) return; - if (ctx->xoff != 0 || screen_size_x(s) < tty->sx || + if (!tty_pane_full_width(tty, ctx) || !tty_term_has(tty->term, TTYC_CSR) || !tty_term_has(tty->term, TTYC_RI)) { tty_redraw_region(tty, ctx); @@ -910,7 +902,7 @@ tty_cmd_linefeed(struct tty *tty, const struct tty_ctx *ctx) if (ctx->ocy != ctx->orlower) return; - if (ctx->xoff != 0 || screen_size_x(s) < tty->sx || + if (!tty_pane_full_width(tty, ctx) || !tty_term_has(tty->term, TTYC_CSR)) { if (tty_large_region(tty, ctx)) wp->flags |= PANE_REDRAW; @@ -952,8 +944,7 @@ tty_cmd_clearendofscreen(struct tty *tty, const struct tty_ctx *ctx) tty_region_pane(tty, ctx, 0, screen_size_y(s) - 1); tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); - if (ctx->xoff == 0 && screen_size_x(s) >= tty->sx && - tty_term_has(tty->term, TTYC_EL)) { + if (tty_pane_full_width(tty, ctx) && tty_term_has(tty->term, TTYC_EL)) { tty_putcode(tty, TTYC_EL); if (ctx->ocy != screen_size_y(s) - 1) { tty_cursor_pane(tty, ctx, 0, ctx->ocy + 1); @@ -988,8 +979,7 @@ tty_cmd_clearstartofscreen(struct tty *tty, const struct tty_ctx *ctx) tty_region_pane(tty, ctx, 0, screen_size_y(s) - 1); tty_cursor_pane(tty, ctx, 0, 0); - if (ctx->xoff == 0 && screen_size_x(s) >= tty->sx && - tty_term_has(tty->term, TTYC_EL)) { + if (tty_pane_full_width(tty, ctx) && tty_term_has(tty->term, TTYC_EL)) { for (i = 0; i < ctx->ocy; i++) { tty_putcode(tty, TTYC_EL); tty_emulate_repeat(tty, TTYC_CUD, TTYC_CUD1, 1); @@ -1018,8 +1008,7 @@ tty_cmd_clearscreen(struct tty *tty, const struct tty_ctx *ctx) tty_region_pane(tty, ctx, 0, screen_size_y(s) - 1); tty_cursor_pane(tty, ctx, 0, 0); - if (ctx->xoff == 0 && screen_size_x(s) >= tty->sx && - tty_term_has(tty->term, TTYC_EL)) { + if (tty_pane_full_width(tty, ctx) && tty_term_has(tty->term, TTYC_EL)) { for (i = 0; i < screen_size_y(s); i++) { tty_putcode(tty, TTYC_EL); if (i != screen_size_y(s) - 1) { From 218b692221b9dd675275ec353364910dfc072151 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 5 May 2012 18:48:31 +0000 Subject: [PATCH 1109/1180] Only enter copy mode on scroll up, from Ailin Nemui. --- input-keys.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/input-keys.c b/input-keys.c index 485dd051..11743b75 100644 --- a/input-keys.c +++ b/input-keys.c @@ -223,7 +223,8 @@ input_mouse(struct window_pane *wp, struct mouse_event *m) return; } - if (options_get_number(&wp->window->options, "mode-mouse") == 1) { + if ((m->b & 3) != 1 && + options_get_number(&wp->window->options, "mode-mouse") == 1) { if (window_pane_set_mode(wp, &window_copy_mode) == 0) { window_copy_init_from_pane(wp); if (wp->mode->mouse != NULL) From 37f9bb46d815e8ba6377c3435d72c052267831ed Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 6 May 2012 07:38:17 +0000 Subject: [PATCH 1110/1180] Add a helper function to open the terminal for attach-/new-session. --- cmd-attach-session.c | 13 +++---------- cmd-new-session.c | 11 ++--------- server-client.c | 19 +++++++++++++++++++ tmux.h | 1 + 4 files changed, 25 insertions(+), 19 deletions(-) diff --git a/cmd-attach-session.c b/cmd-attach-session.c index bdf3568e..c4ee2437 100644 --- a/cmd-attach-session.c +++ b/cmd-attach-session.c @@ -43,7 +43,7 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx) struct session *s; struct client *c; const char *update; - char *overrides, *cause; + char *cause; u_int i; if (RB_EMPTY(&sessions)) { @@ -79,15 +79,8 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx) server_redraw_client(ctx->curclient); s->curw->flags &= ~WINLINK_ALERTFLAGS; } else { - if (!(ctx->cmdclient->flags & CLIENT_TERMINAL)) { - ctx->error(ctx, "not a terminal"); - return (-1); - } - - overrides = - options_get_string(&s->options, "terminal-overrides"); - if (tty_open(&ctx->cmdclient->tty, overrides, &cause) != 0) { - ctx->error(ctx, "terminal open failed: %s", cause); + if (server_client_open(ctx->cmdclient, s, &cause) != 0) { + ctx->error(ctx, "open terminal failed: %s", cause); xfree(cause); return (-1); } diff --git a/cmd-new-session.c b/cmd-new-session.c index d40b5095..c078d1d2 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -63,7 +63,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) struct termios tio, *tiop; struct passwd *pw; const char *newname, *target, *update, *cwd, *errstr; - char *overrides, *cmd, *cause; + char *cmd, *cause; int detached, idx; u_int sx, sy, i; @@ -128,14 +128,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) /* Open the terminal if necessary. */ if (!detached && ctx->cmdclient != NULL) { - if (!(ctx->cmdclient->flags & CLIENT_TERMINAL)) { - ctx->error(ctx, "not a terminal"); - return (-1); - } - - overrides = - options_get_string(&global_s_options, "terminal-overrides"); - if (tty_open(&ctx->cmdclient->tty, overrides, &cause) != 0) { + if (server_client_open(ctx->cmdclient, NULL, &cause) != 0) { ctx->error(ctx, "open terminal failed: %s", cause); xfree(cause); return (-1); diff --git a/server-client.c b/server-client.c index b7212379..2cbb5bf3 100644 --- a/server-client.c +++ b/server-client.c @@ -105,6 +105,25 @@ server_client_create(int fd) log_debug("new client %d", fd); } +/* Open client terminal if needed. */ +int +server_client_open(struct client *c, struct session *s, char **cause) +{ + struct options *oo = s != NULL ? &s->options : &global_s_options; + char *overrides; + + if (!(c->flags & CLIENT_TERMINAL)) { + *cause = xstrdup ("not a terminal"); + return (-1); + } + + overrides = options_get_string(oo, "terminal-overrides"); + if (tty_open(&c->tty, overrides, cause) != 0) + return (-1); + + return (0); +} + /* Lost a client. */ void server_client_lost(struct client *c) diff --git a/tmux.h b/tmux.h index fdbe2724..8c66bca5 100644 --- a/tmux.h +++ b/tmux.h @@ -1723,6 +1723,7 @@ void server_add_accept(int); /* server-client.c */ void server_client_create(int); +int server_client_open(struct client *, struct session *, char **); void server_client_lost(struct client *); void server_client_callback(int, short, void *); void server_client_status_timer(void); From 50cefec497946f7e19213470880bb5fbe2b8d7f1 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 13 May 2012 07:33:31 +0000 Subject: [PATCH 1111/1180] Use -t for move-window with -r rather than dying. Reported by Ben Boeckel and Thomas Adam. --- cmd-move-window.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/cmd-move-window.c b/cmd-move-window.c index 5e30d6b5..6268226e 100644 --- a/cmd-move-window.c +++ b/cmd-move-window.c @@ -47,11 +47,10 @@ cmd_move_window_exec(struct cmd *self, struct cmd_ctx *ctx) char *cause; int idx, kflag, dflag; - if ((s = ctx->curclient->session) == NULL) - return (-1); + if (args_has(args, 'r')) { + if ((s = cmd_find_session(ctx, args_get(args, 't'), 0)) == NULL) + return (-1); - if (args_has(args, 'r')) - { session_renumber_windows(s); recalculate_sizes(); From ac7e2f13e999c1f24b58f7db868c7faeeb0a3c0e Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 17 May 2012 21:21:31 +0000 Subject: [PATCH 1112/1180] Ignore line continuation when escaped as \\, from Simon Nicolussi. --- cfg.c | 4 +++- tmux.1 | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/cfg.c b/cfg.c index d49bfa61..22a50d22 100644 --- a/cfg.c +++ b/cfg.c @@ -109,7 +109,9 @@ load_cfg(const char *path, struct cmd_ctx *ctxin, struct causelist *causes) len = strlen(line); if (len > 0 && line[len - 1] == '\\') { line[len - 1] = '\0'; - continue; + /* Ignore escaped backslash at EOL. */ + if (len > 1 && line[len - 2] != '\\') + continue; } buf = line; line = NULL; diff --git a/tmux.1 b/tmux.1 index 989bb0ea..96742378 100644 --- a/tmux.1 +++ b/tmux.1 @@ -493,7 +493,8 @@ Multiple commands may be specified together as part of a .Em command sequence . Each command should be separated by spaces and a semicolon; commands are executed sequentially from left to right and -lines ending with a backslash continue on to the next line. +lines ending with a backslash continue on to the next line, +except when escaped by another backslash. A literal semicolon may be included by escaping it with a backslash (for example, when specifying a command sequence to .Ic bind-key ) . From 7a4679a17f827efaebb5dac5059f4b8bba69c4cf Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 21 May 2012 18:27:42 +0000 Subject: [PATCH 1113/1180] Instead of passing stdin/stdout/stderr file descriptors over imsg and handling them in the server, handle them in the client and pass buffers over imsg. This is much tidier for some upcoming changes and the performance hit isn't critical. The tty fd is still passed to the server as before. This bumps the tmux protocol version so new clients and old servers are incompatible. --- client.c | 64 ++++++++++++++----- cmd-load-buffer.c | 51 ++++++--------- cmd-save-buffer.c | 3 +- server-client.c | 159 +++++++++++----------------------------------- server-fn.c | 80 +++++++++++++++++++++-- tmux.h | 41 ++++++++---- 6 files changed, 213 insertions(+), 185 deletions(-) diff --git a/client.c b/client.c index 113083fd..4ebcf2ad 100644 --- a/client.c +++ b/client.c @@ -35,6 +35,7 @@ struct imsgbuf client_ibuf; struct event client_event; +struct event client_stdin; enum { CLIENT_EXIT_NONE, CLIENT_EXIT_DETACHED, @@ -56,6 +57,7 @@ void client_send_environ(void); void client_write_server(enum msgtype, void *, size_t); void client_update_event(void); void client_signal(int, short, void *); +void client_stdin_callback(int, short, void *); void client_callback(int, short, void *); int client_dispatch_attached(void); int client_dispatch_wait(void *); @@ -227,6 +229,11 @@ client_main(int argc, char **argv, int flags) imsg_init(&client_ibuf, fd); event_set(&client_event, fd, EV_READ, client_callback, shell_cmd); + /* Create stdin handler. */ + setblocking(STDIN_FILENO, 0); + event_set(&client_stdin, STDIN_FILENO, EV_READ|EV_PERSIST, + client_stdin_callback, NULL); + /* Establish signal handlers. */ set_signals(client_signal); @@ -255,6 +262,7 @@ client_main(int argc, char **argv, int flags) /* Set the event and dispatch. */ client_update_event(); + event_add (&client_stdin, NULL); event_dispatch(); /* Print the exit message, if any, and exit. */ @@ -266,6 +274,7 @@ client_main(int argc, char **argv, int flags) if (client_exittype == MSG_DETACHKILL && ppid > 1) kill(ppid, SIGHUP); } + setblocking(STDIN_FILENO, 1); return (client_exitval); } @@ -287,20 +296,11 @@ client_send_identify(int flags) strlcpy(data.term, term, sizeof data.term) >= sizeof data.term) *data.term = '\0'; - if ((fd = dup(STDOUT_FILENO)) == -1) - fatal("dup failed"); - imsg_compose(&client_ibuf, - MSG_STDOUT, PROTOCOL_VERSION, -1, fd, NULL, 0); - - if ((fd = dup(STDERR_FILENO)) == -1) - fatal("dup failed"); - imsg_compose(&client_ibuf, - MSG_STDERR, PROTOCOL_VERSION, -1, fd, NULL, 0); - if ((fd = dup(STDIN_FILENO)) == -1) fatal("dup failed"); imsg_compose(&client_ibuf, MSG_IDENTIFY, PROTOCOL_VERSION, -1, fd, &data, sizeof data); + client_update_event(); } /* Forward entire environment to server. */ @@ -322,6 +322,7 @@ void client_write_server(enum msgtype type, void *buf, size_t len) { imsg_compose(&client_ibuf, type, PROTOCOL_VERSION, -1, -1, buf, len); + client_update_event(); } /* Update client event based on whether it needs to read or read and write. */ @@ -421,6 +422,23 @@ lost_server: event_loopexit(NULL); } +/* Callback for client stdin read events. */ +/* ARGSUSED */ +void +client_stdin_callback(unused int fd, unused short events, unused void *data1) +{ + struct msg_stdin_data data; + + data.size = read(STDIN_FILENO, data.data, sizeof data.data); + if (data.size < 0 && (errno == EINTR || errno == EAGAIN)) + return; + + client_write_server(MSG_STDIN, &data, sizeof data); + if (data.size <= 0) + event_del(&client_stdin); + client_update_event(); +} + /* Dispatch imsgs when in wait state (before MSG_READY). */ int client_dispatch_wait(void *data) @@ -429,11 +447,10 @@ client_dispatch_wait(void *data) ssize_t n, datalen; struct msg_shell_data shelldata; struct msg_exit_data exitdata; + struct msg_stdout_data stdoutdata; + struct msg_stderr_data stderrdata; const char *shellcmd = data; - if ((n = imsg_read(&client_ibuf)) == -1 || n == 0) - fatalx("imsg_read failed"); - for (;;) { if ((n = imsg_get(&client_ibuf, &imsg)) == -1) fatalx("imsg_get failed"); @@ -441,6 +458,7 @@ client_dispatch_wait(void *data) return (0); datalen = imsg.hdr.len - IMSG_HEADER_SIZE; + log_debug("got %d from server", imsg.hdr.type); switch (imsg.hdr.type) { case MSG_EXIT: case MSG_SHUTDOWN: @@ -457,14 +475,30 @@ client_dispatch_wait(void *data) if (datalen != 0) fatalx("bad MSG_READY size"); + event_del(&client_stdin); client_attached = 1; break; + case MSG_STDOUT: + if (datalen != sizeof stdoutdata) + fatalx("bad MSG_STDOUT"); + memcpy(&stdoutdata, imsg.data, sizeof stdoutdata); + + fwrite(stdoutdata.data, stdoutdata.size, 1, stdout); + break; + case MSG_STDERR: + if (datalen != sizeof stderrdata) + fatalx("bad MSG_STDERR"); + memcpy(&stderrdata, imsg.data, sizeof stderrdata); + + fwrite(stderrdata.data, stderrdata.size, 1, stderr); + break; case MSG_VERSION: if (datalen != 0) fatalx("bad MSG_VERSION size"); - log_warnx("protocol version mismatch (client %u, " - "server %u)", PROTOCOL_VERSION, imsg.hdr.peerid); + fprintf(stderr, "protocol version mismatch " + "(client %u, server %u)\n", PROTOCOL_VERSION, + imsg.hdr.peerid); client_exitval = 1; imsg_free(&imsg); diff --git a/cmd-load-buffer.c b/cmd-load-buffer.c index 09fddbf7..1e6b6024 100644 --- a/cmd-load-buffer.c +++ b/cmd-load-buffer.c @@ -31,7 +31,7 @@ */ int cmd_load_buffer_exec(struct cmd *, struct cmd_ctx *); -void cmd_load_buffer_callback(struct client *, void *); +void cmd_load_buffer_callback(struct client *, int, void *); const struct cmd_entry cmd_load_buffer_entry = { "load-buffer", "loadb", @@ -54,8 +54,7 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) char *pdata, *new_pdata, *cause; size_t psize; u_int limit; - int ch, buffer; - int *buffer_ptr; + int ch, error, buffer, *buffer_ptr; if (!args_has(args, 'b')) buffer = -1; @@ -70,27 +69,16 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) path = args->argv[0]; if (strcmp(path, "-") == 0) { - if (c == NULL) { - ctx->error(ctx, "%s: can't read from stdin", path); - return (-1); - } - if (c->flags & CLIENT_TERMINAL) { - ctx->error(ctx, "%s: stdin is a tty", path); - return (-1); - } - if (c->stdin_fd == -1) { - ctx->error(ctx, "%s: can't read from stdin", path); - return (-1); - } - buffer_ptr = xmalloc(sizeof *buffer_ptr); *buffer_ptr = buffer; - c->stdin_data = buffer_ptr; - c->stdin_callback = cmd_load_buffer_callback; - - c->references++; - bufferevent_enable(c->stdin_event, EV_READ); + error = server_set_stdin_callback (c, cmd_load_buffer_callback, + buffer_ptr, &cause); + if (error != 0) { + ctx->error(ctx, "%s: %s", path, cause); + xfree(cause); + return (-1); + } return (1); } @@ -154,35 +142,36 @@ error: } void -cmd_load_buffer_callback(struct client *c, void *data) +cmd_load_buffer_callback(struct client *c, int closed, void *data) { int *buffer = data; char *pdata; size_t psize; u_int limit; - /* - * Event callback has already checked client is not dead and reduced - * its reference count. But tell it to exit. - */ + if (!closed) + return; + c->stdin_callback = NULL; + + c->references--; c->flags |= CLIENT_EXIT; - psize = EVBUFFER_LENGTH(c->stdin_event->input); + psize = EVBUFFER_LENGTH(c->stdin_data); if (psize == 0 || (pdata = malloc(psize + 1)) == NULL) { xfree(data); return; } - bufferevent_read(c->stdin_event, pdata, psize); + memcpy(pdata, EVBUFFER_DATA(c->stdin_data), psize); pdata[psize] = '\0'; + evbuffer_drain(c->stdin_data, psize); limit = options_get_number(&global_options, "buffer-limit"); if (*buffer == -1) paste_add(&global_buffers, pdata, psize, limit); else if (paste_replace(&global_buffers, *buffer, pdata, psize) != 0) { /* No context so can't use server_client_msg_error. */ - evbuffer_add_printf( - c->stderr_event->output, "no buffer %d\n", *buffer); - bufferevent_enable(c->stderr_event, EV_WRITE); + evbuffer_add_printf(c->stderr_data, "no buffer %d\n", *buffer); + server_push_stderr(c); } xfree(data); diff --git a/cmd-save-buffer.c b/cmd-save-buffer.c index 93ec4b0b..80f9d572 100644 --- a/cmd-save-buffer.c +++ b/cmd-save-buffer.c @@ -79,7 +79,8 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) ctx->error(ctx, "%s: can't write to stdout", path); return (-1); } - bufferevent_write(c->stdout_event, pb->data, pb->size); + evbuffer_add(c->stdout_data, pb->data, pb->size); + server_push_stdout(c); } else { if (c != NULL) wd = c->cwd; diff --git a/server-client.c b/server-client.c index 2cbb5bf3..25f17f06 100644 --- a/server-client.c +++ b/server-client.c @@ -35,9 +35,6 @@ void server_client_check_exit(struct client *); void server_client_check_redraw(struct client *); void server_client_set_title(struct client *); void server_client_reset_state(struct client *); -void server_client_in_callback(struct bufferevent *, short, void *); -void server_client_out_callback(struct bufferevent *, short, void *); -void server_client_err_callback(struct bufferevent *, short, void *); int server_client_msg_dispatch(struct client *); void server_client_msg_command(struct client *, struct msg_command_data *); @@ -67,9 +64,9 @@ server_client_create(int fd) fatal("gettimeofday failed"); memcpy(&c->activity_time, &c->creation_time, sizeof c->activity_time); - c->stdin_event = NULL; - c->stdout_event = NULL; - c->stderr_event = NULL; + c->stdin_data = evbuffer_new (); + c->stdout_data = evbuffer_new (); + c->stderr_data = evbuffer_new (); c->tty.fd = -1; c->title = NULL; @@ -144,24 +141,9 @@ server_client_lost(struct client *c) if (c->flags & CLIENT_TERMINAL) tty_free(&c->tty); - if (c->stdin_event != NULL) - bufferevent_free(c->stdin_event); - if (c->stdin_fd != -1) { - setblocking(c->stdin_fd, 1); - close(c->stdin_fd); - } - if (c->stdout_event != NULL) - bufferevent_free(c->stdout_event); - if (c->stdout_fd != -1) { - setblocking(c->stdout_fd, 1); - close(c->stdout_fd); - } - if (c->stderr_event != NULL) - bufferevent_free(c->stderr_event); - if (c->stderr_fd != -1) { - setblocking(c->stderr_fd, 1); - close(c->stderr_fd); - } + evbuffer_free (c->stdin_data); + evbuffer_free (c->stdout_data); + evbuffer_free (c->stderr_data); status_free_jobs(&c->status_new); status_free_jobs(&c->status_old); @@ -240,6 +222,9 @@ server_client_callback(int fd, short events, void *data) goto client_lost; } + server_push_stdout(c); + server_push_stderr(c); + server_update_event(c); return; @@ -603,11 +588,11 @@ server_client_check_exit(struct client *c) if (!(c->flags & CLIENT_EXIT)) return; - if (c->stdout_fd != -1 && c->stdout_event != NULL && - EVBUFFER_LENGTH(c->stdout_event->output) != 0) + if (EVBUFFER_LENGTH(c->stdin_data) != 0) return; - if (c->stderr_fd != -1 && c->stderr_event != NULL && - EVBUFFER_LENGTH(c->stderr_event->output) != 0) + if (EVBUFFER_LENGTH(c->stdout_data) != 0) + return; + if (EVBUFFER_LENGTH(c->stderr_data) != 0) return; exitdata.retcode = c->retcode; @@ -686,55 +671,6 @@ server_client_set_title(struct client *c) xfree(title); } -/* - * Error callback for client stdin. Caller must increase reference count when - * enabling event! - */ -void -server_client_in_callback( - unused struct bufferevent *bufev, unused short what, void *data) -{ - struct client *c = data; - - c->references--; - if (c->flags & CLIENT_DEAD) - return; - - bufferevent_disable(c->stdin_event, EV_READ|EV_WRITE); - setblocking(c->stdin_fd, 1); - close(c->stdin_fd); - c->stdin_fd = -1; - - if (c->stdin_callback != NULL) - c->stdin_callback(c, c->stdin_data); -} - -/* Error callback for client stdout. */ -void -server_client_out_callback( - unused struct bufferevent *bufev, unused short what, unused void *data) -{ - struct client *c = data; - - bufferevent_disable(c->stdout_event, EV_READ|EV_WRITE); - setblocking(c->stdout_fd, 1); - close(c->stdout_fd); - c->stdout_fd = -1; -} - -/* Error callback for client stderr. */ -void -server_client_err_callback( - unused struct bufferevent *bufev, unused short what, unused void *data) -{ - struct client *c = data; - - bufferevent_disable(c->stderr_event, EV_READ|EV_WRITE); - setblocking(c->stderr_fd, 1); - close(c->stderr_fd); - c->stderr_fd = -1; -} - /* Dispatch message from client. */ int server_client_msg_dispatch(struct client *c) @@ -743,6 +679,7 @@ server_client_msg_dispatch(struct client *c) struct msg_command_data commanddata; struct msg_identify_data identifydata; struct msg_environ_data environdata; + struct msg_stdin_data stdindata; ssize_t n, datalen; if ((n = imsg_read(&c->ibuf)) == -1 || n == 0) @@ -778,42 +715,23 @@ server_client_msg_dispatch(struct client *c) fatalx("MSG_IDENTIFY missing fd"); memcpy(&identifydata, imsg.data, sizeof identifydata); - c->stdin_fd = imsg.fd; - c->stdin_event = bufferevent_new(c->stdin_fd, - NULL, NULL, server_client_in_callback, c); - if (c->stdin_event == NULL) - fatalx("failed to create stdin event"); - setblocking(c->stdin_fd, 0); - server_client_msg_identify(c, &identifydata, imsg.fd); break; - case MSG_STDOUT: - if (datalen != 0) - fatalx("bad MSG_STDOUT size"); - if (imsg.fd == -1) - fatalx("MSG_STDOUT missing fd"); - - c->stdout_fd = imsg.fd; - c->stdout_event = bufferevent_new(c->stdout_fd, - NULL, NULL, server_client_out_callback, c); - if (c->stdout_event == NULL) - fatalx("failed to create stdout event"); - setblocking(c->stdout_fd, 0); - - break; - case MSG_STDERR: - if (datalen != 0) - fatalx("bad MSG_STDERR size"); - if (imsg.fd == -1) - fatalx("MSG_STDERR missing fd"); - - c->stderr_fd = imsg.fd; - c->stderr_event = bufferevent_new(c->stderr_fd, - NULL, NULL, server_client_err_callback, c); - if (c->stderr_event == NULL) - fatalx("failed to create stderr event"); - setblocking(c->stderr_fd, 0); + case MSG_STDIN: + if (datalen != sizeof stdindata) + fatalx("bad MSG_STDIN size"); + memcpy(&stdindata, imsg.data, sizeof stdindata); + if (c->stdin_callback == NULL) + break; + if (stdindata.size <= 0) + c->stdin_closed = 1; + else { + evbuffer_add(c->stdin_data, stdindata.data, + stdindata.size); + } + c->stdin_callback(c, c->stdin_closed, + c->stdin_callback_data); break; case MSG_RESIZE: if (datalen != 0) @@ -880,10 +798,11 @@ server_client_msg_error(struct cmd_ctx *ctx, const char *fmt, ...) va_list ap; va_start(ap, fmt); - evbuffer_add_vprintf(ctx->cmdclient->stderr_event->output, fmt, ap); + evbuffer_add_vprintf(ctx->cmdclient->stderr_data, fmt, ap); va_end(ap); - bufferevent_write(ctx->cmdclient->stderr_event, "\n", 1); + evbuffer_add(ctx->cmdclient->stderr_data, "\n", 1); + server_push_stderr(ctx->cmdclient); ctx->cmdclient->retcode = 1; } @@ -894,10 +813,11 @@ server_client_msg_print(struct cmd_ctx *ctx, const char *fmt, ...) va_list ap; va_start(ap, fmt); - evbuffer_add_vprintf(ctx->cmdclient->stdout_event->output, fmt, ap); + evbuffer_add_vprintf(ctx->cmdclient->stdout_data, fmt, ap); va_end(ap); - bufferevent_write(ctx->cmdclient->stdout_event, "\n", 1); + evbuffer_add(ctx->cmdclient->stdout_data, "\n", 1); + server_push_stdout(ctx->cmdclient); } /* Callback to send print message to client, if not quiet. */ @@ -910,10 +830,11 @@ server_client_msg_info(struct cmd_ctx *ctx, const char *fmt, ...) return; va_start(ap, fmt); - evbuffer_add_vprintf(ctx->cmdclient->stdout_event->output, fmt, ap); + evbuffer_add_vprintf(ctx->cmdclient->stdout_data, fmt, ap); va_end(ap); - bufferevent_write(ctx->cmdclient->stdout_event, "\n", 1); + evbuffer_add(ctx->cmdclient->stdout_data, "\n", 1); + server_push_stdout(ctx->cmdclient); } /* Handle command message. */ @@ -970,8 +891,6 @@ void server_client_msg_identify( struct client *c, struct msg_identify_data *data, int fd) { - int tty_fd; - c->cwd = NULL; data->cwd[(sizeof data->cwd) - 1] = '\0'; if (*data->cwd != '\0') @@ -979,10 +898,8 @@ server_client_msg_identify( if (!isatty(fd)) return; - if ((tty_fd = dup(fd)) == -1) - fatal("dup failed"); data->term[(sizeof data->term) - 1] = '\0'; - tty_init(&c->tty, tty_fd, data->term); + tty_init(&c->tty, fd, data->term); if (data->flags & IDENTIFY_UTF8) c->tty.flags |= TTY_UTF8; if (data->flags & IDENTIFY_256COLOURS) diff --git a/server-fn.c b/server-fn.c index 600955af..791aab1c 100644 --- a/server-fn.c +++ b/server-fn.c @@ -46,17 +46,21 @@ server_fill_environ(struct session *s, struct environ *env) environ_set(env, "TMUX", var); } -void +int server_write_client( struct client *c, enum msgtype type, const void *buf, size_t len) { struct imsgbuf *ibuf = &c->ibuf; + int error; if (c->flags & CLIENT_BAD) - return; + return (-1); log_debug("writing %d to client %d", type, c->ibuf.fd); - imsg_compose(ibuf, type, PROTOCOL_VERSION, -1, -1, (void *) buf, len); - server_update_event(c); + error = imsg_compose(ibuf, type, PROTOCOL_VERSION, -1, -1, + (void *) buf, len); + if (error == 1) + server_update_event(c); + return (error == 1 ? 0 : -1); } void @@ -502,3 +506,71 @@ server_update_event(struct client *c) event_set(&c->event, c->ibuf.fd, events, server_client_callback, c); event_add(&c->event, NULL); } + +/* Push stdout to client if possible. */ +void +server_push_stdout(struct client *c) +{ + struct msg_stdout_data data; + size_t size; + + size = EVBUFFER_LENGTH(c->stdout_data); + if (size == 0) + return; + if (size > sizeof data.data) + size = sizeof data.data; + + memcpy(data.data, EVBUFFER_DATA(c->stdout_data), size); + data.size = size; + + if (server_write_client(c, MSG_STDOUT, &data, sizeof data) == 0) + evbuffer_drain(c->stdout_data, size); +} + +/* Push stderr to client if possible. */ +void +server_push_stderr(struct client *c) +{ + struct msg_stderr_data data; + size_t size; + + size = EVBUFFER_LENGTH(c->stderr_data); + if (size == 0) + return; + if (size > sizeof data.data) + size = sizeof data.data; + + memcpy(data.data, EVBUFFER_DATA(c->stderr_data), size); + data.size = size; + + if (server_write_client(c, MSG_STDERR, &data, sizeof data) == 0) + evbuffer_drain(c->stderr_data, size); +} + +/* Set stdin callback. */ +int +server_set_stdin_callback(struct client *c, void (*cb)(struct client *, int, + void *), void *cb_data, char **cause) +{ + if (c == NULL) { + *cause = xstrdup("no client with stdin"); + return (-1); + } + if (c->flags & CLIENT_TERMINAL) { + *cause = xstrdup("stdin is a tty"); + return (-1); + } + if (c->stdin_callback != NULL) { + *cause = xstrdup("stdin in use"); + return (-1); + } + + c->stdin_callback_data = cb_data; + c->stdin_callback = cb; + + c->references++; + + if (c->stdin_closed) + c->stdin_callback (c, 1, c->stdin_callback_data); + return (0); +} diff --git a/tmux.h b/tmux.h index 8c66bca5..96efb661 100644 --- a/tmux.h +++ b/tmux.h @@ -19,7 +19,7 @@ #ifndef TMUX_H #define TMUX_H -#define PROTOCOL_VERSION 6 +#define PROTOCOL_VERSION 7 #include #include @@ -369,7 +369,7 @@ enum msgtype { MSG_EXITED, MSG_EXITING, MSG_IDENTIFY, - MSG_PRINT, + MSG_STDIN, MSG_READY, MSG_RESIZE, MSG_SHUTDOWN, @@ -425,6 +425,21 @@ struct msg_exit_data { int retcode; }; +struct msg_stdin_data { + ssize_t size; + char data[BUFSIZ]; +}; + +struct msg_stdout_data { + ssize_t size; + char data[BUFSIZ]; +}; + +struct msg_stderr_data { + ssize_t size; + char data[BUFSIZ]; +}; + /* Mode key commands. */ enum mode_key_cmd { MODEKEY_NONE, @@ -1161,16 +1176,12 @@ struct client { struct tty tty; - int stdin_fd; - void *stdin_data; - void (*stdin_callback)(struct client *, void *); - struct bufferevent *stdin_event; - - int stdout_fd; - struct bufferevent *stdout_event; - - int stderr_fd; - struct bufferevent *stderr_event; + void (*stdin_callback)(struct client *, int, void *); + void *stdin_callback_data; + struct evbuffer *stdin_data; + int stdin_closed; + struct evbuffer *stdout_data; + struct evbuffer *stderr_data; struct event repeat_timer; @@ -1734,7 +1745,7 @@ void server_window_loop(void); /* server-fn.c */ void server_fill_environ(struct session *, struct environ *); -void server_write_client( +int server_write_client( struct client *, enum msgtype, const void *, size_t); void server_write_session( struct session *, enum msgtype, const void *, size_t); @@ -1762,6 +1773,10 @@ void server_check_unattached (void); void server_set_identify(struct client *); void server_clear_identify(struct client *); void server_update_event(struct client *); +void server_push_stdout(struct client *); +void server_push_stderr(struct client *); +int server_set_stdin_callback(struct client *, void (*)(struct client *, + int, void *), void *, char **); /* status.c */ int status_out_cmp(struct status_out *, struct status_out *); From 243d12752c4ccb4f2cfabeff8c8cb843550078ae Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 22 May 2012 09:09:16 +0000 Subject: [PATCH 1114/1180] Move some common code to repeat spaces into a function. --- tty.c | 54 ++++++++++++++++++++++-------------------------------- 1 file changed, 22 insertions(+), 32 deletions(-) diff --git a/tty.c b/tty.c index de153382..63a54f0a 100644 --- a/tty.c +++ b/tty.c @@ -51,6 +51,7 @@ void tty_era_pane(struct tty *, void tty_redraw_region(struct tty *, const struct tty_ctx *); void tty_emulate_repeat( struct tty *, enum tty_code_code, enum tty_code_code, u_int); +void tty_repeat_space(struct tty *, u_int); void tty_cell(struct tty *, const struct grid_cell *, const struct grid_utf8 *); @@ -546,6 +547,13 @@ tty_emulate_repeat( } } +void +tty_repeat_space(struct tty *tty, u_int n) +{ + while (n-- > 0) + tty_putc(tty, ' '); +} + /* * Is the region large enough to be worth redrawing once later rather than * probably several times now? Currently yes if it is more than 50% of the @@ -647,10 +655,8 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int py, u_int ox, u_int oy) if (sx != screen_size_x(s) && ox + screen_size_x(s) >= tty->sx && tty_term_has(tty->term, TTYC_EL)) tty_putcode(tty, TTYC_EL); - else { - for (i = sx; i < screen_size_x(s); i++) - tty_putc(tty, ' '); - } + else + tty_repeat_space(tty, screen_size_x(s) - sx); tty_update_mode(tty, tty->mode, s); } @@ -735,7 +741,6 @@ tty_cmd_insertcharacter(struct tty *tty, const struct tty_ctx *ctx) { struct window_pane *wp = ctx->wp; struct screen *s = wp->screen; - u_int i; if (ctx->xoff != 0 || screen_size_x(s) < tty->sx) { tty_draw_line(tty, wp->screen, ctx->ocy, ctx->xoff, ctx->yoff); @@ -752,8 +757,7 @@ tty_cmd_insertcharacter(struct tty *tty, const struct tty_ctx *ctx) else if (tty_term_has(tty->term, TTYC_SMIR) && tty_term_has(tty->term, TTYC_RMIR)) { tty_putcode(tty, TTYC_SMIR); - for (i = 0; i < ctx->num; i++) - tty_putc(tty, ' '); + tty_repeat_space(tty, ctx->num); tty_putcode(tty, TTYC_RMIR); } else tty_draw_line(tty, wp->screen, ctx->ocy, ctx->xoff, ctx->yoff); @@ -822,18 +826,15 @@ tty_cmd_clearline(struct tty *tty, const struct tty_ctx *ctx) { struct window_pane *wp = ctx->wp; struct screen *s = wp->screen; - u_int i; tty_reset(tty); tty_cursor_pane(tty, ctx, 0, ctx->ocy); - if (tty_pane_full_width(tty, ctx) && tty_term_has(tty->term, TTYC_EL)) { + if (tty_pane_full_width(tty, ctx) && tty_term_has(tty->term, TTYC_EL)) tty_putcode(tty, TTYC_EL); - } else { - for (i = 0; i < screen_size_x(s); i++) - tty_putc(tty, ' '); - } + else + tty_repeat_space(tty, screen_size_x(s)); } void @@ -841,7 +842,6 @@ tty_cmd_clearendofline(struct tty *tty, const struct tty_ctx *ctx) { struct window_pane *wp = ctx->wp; struct screen *s = wp->screen; - u_int i; tty_reset(tty); @@ -849,17 +849,13 @@ tty_cmd_clearendofline(struct tty *tty, const struct tty_ctx *ctx) if (tty_pane_full_width(tty, ctx) && tty_term_has(tty->term, TTYC_EL)) tty_putcode(tty, TTYC_EL); - else { - for (i = ctx->ocx; i < screen_size_x(s); i++) - tty_putc(tty, ' '); - } + else + tty_repeat_space(tty, screen_size_x(s) - ctx->ocx); } void tty_cmd_clearstartofline(struct tty *tty, const struct tty_ctx *ctx) { - u_int i; - tty_reset(tty); if (ctx->xoff == 0 && tty_term_has(tty->term, TTYC_EL1)) { @@ -867,8 +863,7 @@ tty_cmd_clearstartofline(struct tty *tty, const struct tty_ctx *ctx) tty_putcode(tty, TTYC_EL1); } else { tty_cursor_pane(tty, ctx, 0, ctx->ocy); - for (i = 0; i < ctx->ocx + 1; i++) - tty_putc(tty, ' '); + tty_repeat_space(tty, ctx->ocx + 1); } } @@ -957,12 +952,10 @@ tty_cmd_clearendofscreen(struct tty *tty, const struct tty_ctx *ctx) } } } else { - for (i = ctx->ocx; i < screen_size_x(s); i++) - tty_putc(tty, ' '); + tty_repeat_space(tty, screen_size_x(s) - ctx->ocx); for (j = ctx->ocy + 1; j < screen_size_y(s); j++) { tty_cursor_pane(tty, ctx, 0, j); - for (i = 0; i < screen_size_x(s); i++) - tty_putc(tty, ' '); + tty_repeat_space(tty, screen_size_x(s)); } } } @@ -988,12 +981,10 @@ tty_cmd_clearstartofscreen(struct tty *tty, const struct tty_ctx *ctx) } else { for (j = 0; j < ctx->ocy; j++) { tty_cursor_pane(tty, ctx, 0, j); - for (i = 0; i < screen_size_x(s); i++) - tty_putc(tty, ' '); + tty_repeat_space(tty, screen_size_x(s)); } } - for (i = 0; i <= ctx->ocx; i++) - tty_putc(tty, ' '); + tty_repeat_space(tty, ctx->ocx + 1); } void @@ -1019,8 +1010,7 @@ tty_cmd_clearscreen(struct tty *tty, const struct tty_ctx *ctx) } else { for (j = 0; j < screen_size_y(s); j++) { tty_cursor_pane(tty, ctx, 0, j); - for (i = 0; i < screen_size_x(s); i++) - tty_putc(tty, ' '); + tty_repeat_space(tty, screen_size_x(s)); } } } From 2f93affb988ecdae1cfd3fb73801ce5b943a6525 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 22 May 2012 09:36:12 +0000 Subject: [PATCH 1115/1180] If there are any terminals with insert mode but not ich1, they can go through the slow path. Tidies code slightly. --- tmux.h | 2 -- tty-term.c | 2 -- tty.c | 7 +------ 3 files changed, 1 insertion(+), 10 deletions(-) diff --git a/tmux.h b/tmux.h index 96efb661..b142c696 100644 --- a/tmux.h +++ b/tmux.h @@ -316,7 +316,6 @@ enum tty_code_code { TTYC_RI, /* scroll_reverse, sr */ TTYC_RMACS, /* exit_alt_charset_mode */ TTYC_RMCUP, /* exit_ca_mode, te */ - TTYC_RMIR, /* exit_insert_mode, ei */ TTYC_RMKX, /* keypad_local, ke */ TTYC_SETAB, /* set_a_background, AB */ TTYC_SETAF, /* set_a_foreground, AF */ @@ -324,7 +323,6 @@ enum tty_code_code { TTYC_SITM, /* enter_italics_mode, it */ TTYC_SMACS, /* enter_alt_charset_mode, as */ TTYC_SMCUP, /* enter_ca_mode, ti */ - TTYC_SMIR, /* enter_insert_mode, im */ TTYC_SMKX, /* keypad_xmit, ks */ TTYC_SMSO, /* enter_standout_mode, so */ TTYC_SMUL, /* enter_underline_mode, us */ diff --git a/tty-term.c b/tty-term.c index 5338d0d9..d79cbf2f 100644 --- a/tty-term.c +++ b/tty-term.c @@ -174,7 +174,6 @@ const struct tty_term_code_entry tty_term_codes[NTTYCODE] = { { TTYC_RI, TTYCODE_STRING, "ri" }, { TTYC_RMACS, TTYCODE_STRING, "rmacs" }, { TTYC_RMCUP, TTYCODE_STRING, "rmcup" }, - { TTYC_RMIR, TTYCODE_STRING, "rmir" }, { TTYC_RMKX, TTYCODE_STRING, "rmkx" }, { TTYC_SETAB, TTYCODE_STRING, "setab" }, { TTYC_SETAF, TTYCODE_STRING, "setaf" }, @@ -182,7 +181,6 @@ const struct tty_term_code_entry tty_term_codes[NTTYCODE] = { { TTYC_SITM, TTYCODE_STRING, "sitm" }, { TTYC_SMACS, TTYCODE_STRING, "smacs" }, { TTYC_SMCUP, TTYCODE_STRING, "smcup" }, - { TTYC_SMIR, TTYCODE_STRING, "smir" }, { TTYC_SMKX, TTYCODE_STRING, "smkx" }, { TTYC_SMSO, TTYCODE_STRING, "smso" }, { TTYC_SMUL, TTYCODE_STRING, "smul" }, diff --git a/tty.c b/tty.c index 63a54f0a..91ef75bd 100644 --- a/tty.c +++ b/tty.c @@ -754,12 +754,7 @@ tty_cmd_insertcharacter(struct tty *tty, const struct tty_ctx *ctx) if (tty_term_has(tty->term, TTYC_ICH) || tty_term_has(tty->term, TTYC_ICH1)) tty_emulate_repeat(tty, TTYC_ICH, TTYC_ICH1, ctx->num); - else if (tty_term_has(tty->term, TTYC_SMIR) && - tty_term_has(tty->term, TTYC_RMIR)) { - tty_putcode(tty, TTYC_SMIR); - tty_repeat_space(tty, ctx->num); - tty_putcode(tty, TTYC_RMIR); - } else + else tty_draw_line(tty, wp->screen, ctx->ocy, ctx->xoff, ctx->yoff); } From 82b053a81135c0873f9aa8824386e63abd48bbc4 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 22 May 2012 09:37:54 +0000 Subject: [PATCH 1116/1180] Use tty_pane_full_width macro in some more places. --- tty.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tty.c b/tty.c index 91ef75bd..5eb37ade 100644 --- a/tty.c +++ b/tty.c @@ -740,9 +740,8 @@ void tty_cmd_insertcharacter(struct tty *tty, const struct tty_ctx *ctx) { struct window_pane *wp = ctx->wp; - struct screen *s = wp->screen; - if (ctx->xoff != 0 || screen_size_x(s) < tty->sx) { + if (!tty_pane_full_width(tty, ctx)) { tty_draw_line(tty, wp->screen, ctx->ocy, ctx->xoff, ctx->yoff); return; } @@ -762,9 +761,8 @@ void tty_cmd_deletecharacter(struct tty *tty, const struct tty_ctx *ctx) { struct window_pane *wp = ctx->wp; - struct screen *s = wp->screen; - if (ctx->xoff != 0 || screen_size_x(s) < tty->sx || + if (!tty_pane_full_width(tty, ctx) || (!tty_term_has(tty->term, TTYC_DCH) && !tty_term_has(tty->term, TTYC_DCH1))) { tty_draw_line(tty, wp->screen, ctx->ocy, ctx->xoff, ctx->yoff); From 682884edc5ef0b6ded98b385fce3066e820317ff Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 22 May 2012 10:56:48 +0000 Subject: [PATCH 1117/1180] Add a helper function to send ready message. --- cmd-attach-session.c | 2 +- cmd-new-session.c | 2 +- server-fn.c | 6 ++++++ tmux.h | 1 + 4 files changed, 9 insertions(+), 2 deletions(-) diff --git a/cmd-attach-session.c b/cmd-attach-session.c index c4ee2437..d07b727d 100644 --- a/cmd-attach-session.c +++ b/cmd-attach-session.c @@ -94,7 +94,7 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx) ctx->cmdclient->session = s; notify_attached_session_changed(ctx->cmdclient); session_update_activity(s); - server_write_client(ctx->cmdclient, MSG_READY, NULL, 0); + server_write_ready(ctx->cmdclient); update = options_get_string(&s->options, "update-environment"); environ_update(update, &ctx->cmdclient->environ, &s->environ); diff --git a/cmd-new-session.c b/cmd-new-session.c index c078d1d2..09413796 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -231,7 +231,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) */ if (!detached) { if (ctx->cmdclient != NULL) { - server_write_client(ctx->cmdclient, MSG_READY, NULL, 0); + server_write_ready(ctx->cmdclient); old_s = ctx->cmdclient->session; if (old_s != NULL) diff --git a/server-fn.c b/server-fn.c index 791aab1c..794205d7 100644 --- a/server-fn.c +++ b/server-fn.c @@ -46,6 +46,12 @@ server_fill_environ(struct session *s, struct environ *env) environ_set(env, "TMUX", var); } +void +server_write_ready(struct client *c) +{ + server_write_client(c, MSG_READY, NULL, 0); +} + int server_write_client( struct client *c, enum msgtype type, const void *buf, size_t len) diff --git a/tmux.h b/tmux.h index b142c696..6c88fac1 100644 --- a/tmux.h +++ b/tmux.h @@ -1743,6 +1743,7 @@ void server_window_loop(void); /* server-fn.c */ void server_fill_environ(struct session *, struct environ *); +void server_write_ready(struct client *); int server_write_client( struct client *, enum msgtype, const void *, size_t); void server_write_session( From ebf94bc9cba6c41074fdfa1d1084ad5fff43fc24 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 22 May 2012 11:35:37 +0000 Subject: [PATCH 1118/1180] Switch all of the various choose- and list- commands over to the format infrastructure, from Thomas Adam. --- cmd-break-pane.c | 7 +++--- cmd-choose-buffer.c | 24 ++++++++++++++------ cmd-choose-client.c | 26 +++++++++++++++------- cmd-choose-session.c | 33 ++++++++++++++-------------- cmd-choose-window.c | 37 ++++++++++++++----------------- cmd-display-message.c | 2 +- cmd-find-window.c | 30 +++++++++++++++++-------- cmd-list-buffers.c | 25 +++++++++++++++------ cmd-list-clients.c | 9 ++------ cmd-list-sessions.c | 10 ++------- cmd-list-windows.c | 14 +++--------- cmd-new-window.c | 6 ++--- cmd-split-window.c | 5 ++--- format.c | 12 ++++++++++ tmux.1 | 51 ++++++++++++++++++++++++++++++++++++------- tmux.h | 32 +++++++++++++++++++++++++++ 16 files changed, 211 insertions(+), 112 deletions(-) diff --git a/cmd-break-pane.c b/cmd-break-pane.c index 6e6ab589..8e09774b 100644 --- a/cmd-break-pane.c +++ b/cmd-break-pane.c @@ -93,9 +93,10 @@ cmd_break_pane_exec(struct cmd *self, struct cmd_ctx *ctx) server_status_session_group(s); if (args_has(args, 'P')) { - template = "#{session_name}:#{window_index}"; - if (args_has(args, 'F')) - template = args_get(args, 'F'); + + if ((template = args_get(args, 'F')) == NULL) + template = DEFAULT_PANE_INFO_TEMPLATE; + ft = format_create(); if ((c = cmd_find_client(ctx, NULL)) != NULL) format_client(ft, c); diff --git a/cmd-choose-buffer.c b/cmd-choose-buffer.c index c1093f92..9045d9eb 100644 --- a/cmd-choose-buffer.c +++ b/cmd-choose-buffer.c @@ -33,8 +33,8 @@ void cmd_choose_buffer_free(void *); const struct cmd_entry cmd_choose_buffer_entry = { "choose-buffer", NULL, - "t:", 0, 1, - CMD_TARGET_WINDOW_USAGE " [template]", + "F:t:", 0, 1, + CMD_TARGET_WINDOW_USAGE " [-F format] [template]", 0, NULL, NULL, @@ -53,14 +53,19 @@ cmd_choose_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) struct cmd_choose_buffer_data *cdata; struct winlink *wl; struct paste_buffer *pb; + struct format_tree *ft; u_int idx; - char *tmp; + char *line; + const char *template; if (ctx->curclient == NULL) { ctx->error(ctx, "must be run interactively"); return (-1); } + if ((template = args_get(args, 'F')) == NULL) + template = DEFAULT_BUFFER_LIST_TEMPLATE; + if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL) return (-1); @@ -72,10 +77,15 @@ cmd_choose_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) idx = 0; while ((pb = paste_walk_stack(&global_buffers, &idx)) != NULL) { - tmp = paste_print(pb, 50); - window_choose_add(wl->window->active, idx - 1, - "%u: %zu bytes: \"%s\"", idx - 1, pb->size, tmp); - xfree(tmp); + ft = format_create(); + format_add(ft, "line", "%u", idx - 1); + format_paste_buffer(ft, pb); + + line = format_expand(ft, template); + window_choose_add(wl->window->active, idx - 1, "%s", line); + + xfree(line); + format_free(ft); } cdata = xmalloc(sizeof *cdata); diff --git a/cmd-choose-client.c b/cmd-choose-client.c index 6ad1b495..ba7508d7 100644 --- a/cmd-choose-client.c +++ b/cmd-choose-client.c @@ -33,8 +33,8 @@ void cmd_choose_client_free(void *); const struct cmd_entry cmd_choose_client_entry = { "choose-client", NULL, - "t:", 0, 1, - CMD_TARGET_WINDOW_USAGE " [template]", + "F:t:", 0, 1, + CMD_TARGET_WINDOW_USAGE " [-F format] [template]", 0, NULL, NULL, @@ -51,8 +51,11 @@ cmd_choose_client_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; struct cmd_choose_client_data *cdata; + struct format_tree *ft; struct winlink *wl; struct client *c; + char *line; + const char *template; u_int i, idx, cur; if (ctx->curclient == NULL) { @@ -66,6 +69,9 @@ cmd_choose_client_exec(struct cmd *self, struct cmd_ctx *ctx) if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0) return (0); + if ((template = args_get(args, 'F')) == NULL) + template = DEFAULT_CLIENT_TEMPLATE; + cur = idx = 0; for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); @@ -75,12 +81,16 @@ cmd_choose_client_exec(struct cmd *self, struct cmd_ctx *ctx) cur = idx; idx++; - window_choose_add(wl->window->active, i, - "%s: %s [%ux%u %s]%s%s", c->tty.path, - c->session->name, c->tty.sx, c->tty.sy, - c->tty.termname, - c->tty.flags & TTY_UTF8 ? " (utf8)" : "", - c->flags & CLIENT_READONLY ? " (ro)" : ""); + ft = format_create(); + format_add(ft, "line", "%u", i); + format_session(ft, c->session); + format_client(ft, c); + + line = format_expand(ft, template); + window_choose_add(wl->window->active, i, "%s", line); + xfree(line); + + format_free(ft); } cdata = xmalloc(sizeof *cdata); diff --git a/cmd-choose-session.c b/cmd-choose-session.c index 5aa0877b..ad13b151 100644 --- a/cmd-choose-session.c +++ b/cmd-choose-session.c @@ -33,8 +33,8 @@ void cmd_choose_session_free(void *); const struct cmd_entry cmd_choose_session_entry = { "choose-session", NULL, - "t:", 0, 1, - CMD_TARGET_WINDOW_USAGE " [template]", + "F:t:", 0, 1, + CMD_TARGET_WINDOW_USAGE " [-F format] [template]", 0, NULL, NULL, @@ -53,9 +53,10 @@ cmd_choose_session_exec(struct cmd *self, struct cmd_ctx *ctx) struct cmd_choose_session_data *cdata; struct winlink *wl; struct session *s; - struct session_group *sg; - u_int idx, sgidx, cur; - char tmp[64]; + struct format_tree *ft; + const char *template; + char *line; + u_int idx, cur; if (ctx->curclient == NULL) { ctx->error(ctx, "must be run interactively"); @@ -68,24 +69,24 @@ cmd_choose_session_exec(struct cmd *self, struct cmd_ctx *ctx) if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0) return (0); + if ((template = args_get(args, 'F')) == NULL) + template = DEFAULT_SESSION_TEMPLATE; + cur = idx = 0; RB_FOREACH(s, sessions, &sessions) { if (s == ctx->curclient->session) cur = idx; idx++; - sg = session_group_find(s); - if (sg == NULL) - *tmp = '\0'; - else { - sgidx = session_group_index(sg); - xsnprintf(tmp, sizeof tmp, " (group %u)", sgidx); - } + ft = format_create(); + format_add(ft, "line", "%u", idx); + format_session(ft, s); - window_choose_add(wl->window->active, s->idx, - "%s: %u windows [%ux%u]%s%s", s->name, - winlink_count(&s->windows), s->sx, s->sy, - tmp, s->flags & SESSION_UNATTACHED ? "" : " (attached)"); + line = format_expand(ft, template); + window_choose_add(wl->window->active, s->idx, "%s", line); + xfree(line); + + format_free(ft); } cdata = xmalloc(sizeof *cdata); diff --git a/cmd-choose-window.c b/cmd-choose-window.c index a1280927..ba70fcd1 100644 --- a/cmd-choose-window.c +++ b/cmd-choose-window.c @@ -33,8 +33,8 @@ void cmd_choose_window_free(void *); const struct cmd_entry cmd_choose_window_entry = { "choose-window", NULL, - "t:", 0, 1, - CMD_TARGET_WINDOW_USAGE " [template]", + "F:t:", 0, 1, + CMD_TARGET_WINDOW_USAGE " [-F format] [template]", 0, NULL, NULL, @@ -54,10 +54,10 @@ cmd_choose_window_exec(struct cmd *self, struct cmd_ctx *ctx) struct cmd_choose_window_data *cdata; struct session *s; struct winlink *wl, *wm; - struct window *w; + struct format_tree *ft; + const char *template; + char *line; u_int idx, cur; - char *flags, *title; - const char *left, *right; if (ctx->curclient == NULL) { ctx->error(ctx, "must be run interactively"); @@ -71,30 +71,25 @@ cmd_choose_window_exec(struct cmd *self, struct cmd_ctx *ctx) if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0) return (0); + if ((template = args_get(args, 'F')) == NULL) + template = DEFAULT_WINDOW_TEMPLATE; + cur = idx = 0; RB_FOREACH(wm, winlinks, &s->windows) { - w = wm->window; - if (wm == s->curw) cur = idx; idx++; - flags = window_printable_flags(s, wm); - title = w->active->screen->title; - if (wm == wl) - title = w->active->base.title; - left = " \""; - right = "\""; - if (*title == '\0') - left = right = ""; + ft = format_create(); + format_add(ft, "line", "%u", idx); + format_session(ft, s); + format_winlink(ft, s, wm); - window_choose_add(wl->window->active, - wm->idx, "%3d: %s%s [%ux%u] (%u panes%s)%s%s%s", - wm->idx, w->name, flags, w->sx, w->sy, window_count_panes(w), - w->active->fd == -1 ? ", dead" : "", - left, title, right); + line = format_expand(ft, template); + window_choose_add(wl->window->active, idx, "%s", line); - xfree(flags); + xfree(line); + format_free(ft); } cdata = xmalloc(sizeof *cdata); diff --git a/cmd-display-message.c b/cmd-display-message.c index d8b623b9..058de1fa 100644 --- a/cmd-display-message.c +++ b/cmd-display-message.c @@ -75,7 +75,7 @@ cmd_display_message_exec(struct cmd *self, struct cmd_ctx *ctx) if (args->argc != 0) template = args->argv[0]; if (template == NULL) - template = "[#S] #I:#W, current pane #P - (%H:%M %d-%b-%y)"; + template = DEFAULT_DISPLAY_MESSAGE_TEMPLATE; ft = format_create(); format_client(ft, c); diff --git a/cmd-find-window.c b/cmd-find-window.c index 3ac3c68b..2d6c942f 100644 --- a/cmd-find-window.c +++ b/cmd-find-window.c @@ -46,8 +46,8 @@ void cmd_find_window_free(void *); const struct cmd_entry cmd_find_window_entry = { "find-window", "findw", - "CNt:T", 1, 4, - "[-CNT] " CMD_TARGET_WINDOW_USAGE " match-string", + "F:CNt:T", 1, 4, + "[-CNT] [-F format] " CMD_TARGET_WINDOW_USAGE " match-string", 0, NULL, NULL, @@ -85,11 +85,13 @@ cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx) struct cmd_find_window_data *cdata; struct session *s; struct winlink *wl, *wm; - struct window *w; struct window_pane *wp; + struct format_tree *ft; ARRAY_DECL(, u_int) list_idx; ARRAY_DECL(, char *) list_ctx; char *str, *sres, *sctx, *searchstr; + char *find_line; + const char *template; u_int i, line, match_flags; if (ctx->curclient == NULL) { @@ -101,6 +103,9 @@ cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx) if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL) return (-1); + if ((template = args_get(args, 'F')) == NULL) + template = DEFAULT_FIND_WINDOW_TEMPLATE; + match_flags = cmd_find_window_match_flags(args); str = args->argv[0]; @@ -167,13 +172,20 @@ cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx) for (i = 0; i < ARRAY_LENGTH(&list_idx); i++) { wm = winlink_find_by_index( &s->windows, ARRAY_ITEM(&list_idx, i)); - w = wm->window; - sctx = ARRAY_ITEM(&list_ctx, i); - window_choose_add(wl->window->active, - wm->idx, "%3d: %s [%ux%u] (%u panes) %s", wm->idx, w->name, - w->sx, w->sy, window_count_panes(w), sctx); - xfree(sctx); + ft = format_create(); + format_add(ft, "line", "%u", i); + format_add(ft, "window_find_matches", "%s", + ARRAY_ITEM(&list_ctx, i)); + format_session(ft, s); + format_winlink(ft, s, wm); + + find_line = format_expand(ft, template); + + window_choose_add(wl->window->active, wm->idx, "%s", find_line); + + xfree(find_line); + format_free(ft); } cdata = xmalloc(sizeof *cdata); diff --git a/cmd-list-buffers.c b/cmd-list-buffers.c index d4ff9a22..777a6371 100644 --- a/cmd-list-buffers.c +++ b/cmd-list-buffers.c @@ -30,8 +30,8 @@ int cmd_list_buffers_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_list_buffers_entry = { "list-buffers", "lsb", - "", 0, 0, - "", + "F:", 0, 0, + "[-F format]", 0, NULL, NULL, @@ -42,16 +42,27 @@ const struct cmd_entry cmd_list_buffers_entry = { int cmd_list_buffers_exec(unused struct cmd *self, struct cmd_ctx *ctx) { + struct args *args = self->args; struct paste_buffer *pb; + struct format_tree *ft; u_int idx; - char *tmp; + char *line; + const char *template; + + if ((template = args_get(args, 'F')) == NULL) + template = DEFAULT_BUFFER_LIST_TEMPLATE; idx = 0; while ((pb = paste_walk_stack(&global_buffers, &idx)) != NULL) { - tmp = paste_print(pb, 50); - ctx->print(ctx, - "%u: %zu bytes: \"%s\"", idx - 1, pb->size, tmp); - xfree(tmp); + ft = format_create(); + format_add(ft, "line", "%u", idx - 1); + format_paste_buffer(ft, pb); + + line = format_expand(ft, template); + ctx->print(ctx, "%s", line); + xfree(line); + + format_free(ft); } return (0); diff --git a/cmd-list-clients.c b/cmd-list-clients.c index 04d756b5..c818fd6d 100644 --- a/cmd-list-clients.c +++ b/cmd-list-clients.c @@ -58,13 +58,8 @@ cmd_list_clients_exec(struct cmd *self, struct cmd_ctx *ctx) } else s = NULL; - template = args_get(args, 'F'); - if (template == NULL) { - template = "#{client_tty}: #{session_name} " - "[#{client_width}x#{client_height} #{client_termname}]" - "#{?client_utf8, (utf8),}" - "#{?client_readonly, (ro),}"; - } + if ((template = args_get(args, 'F')) == NULL) + template = DEFAULT_CLIENT_TEMPLATE; for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); diff --git a/cmd-list-sessions.c b/cmd-list-sessions.c index 10e6b16d..7dabfc08 100644 --- a/cmd-list-sessions.c +++ b/cmd-list-sessions.c @@ -49,14 +49,8 @@ cmd_list_sessions_exec(struct cmd *self, struct cmd_ctx *ctx) const char *template; char *line; - template = args_get(args, 'F'); - if (template == NULL) { - template = "#{session_name}: #{session_windows} windows " - "(created #{session_created_string}) [#{session_width}x" - "#{session_height}]#{?session_grouped, (group ,}" - "#{session_group}#{?session_grouped,),}" - "#{?session_attached, (attached),}"; - } + if ((template = args_get(args, 'F')) == NULL) + template = DEFAULT_SESSION_TEMPLATE; n = 0; RB_FOREACH(s, sessions, &sessions) { diff --git a/cmd-list-windows.c b/cmd-list-windows.c index 3919bfbe..103931d2 100644 --- a/cmd-list-windows.c +++ b/cmd-list-windows.c @@ -34,7 +34,7 @@ void cmd_list_windows_session( const struct cmd_entry cmd_list_windows_entry = { "list-windows", "lsw", - "aF:t:", 0, 0, + "F:at:", 0, 0, "[-a] [-F format] " CMD_TARGET_SESSION_USAGE, 0, NULL, @@ -84,18 +84,10 @@ cmd_list_windows_session( if (template == NULL) { switch (type) { case 0: - template = "#{window_index}: " - "#{window_name} " - "[#{window_width}x#{window_height}] " - "[layout #{window_layout}] #{window_id}" - "#{?window_active, (active),}"; + template = DEFAULT_WINDOW_TEMPLATE; break; case 1: - template = "#{session_name}:#{window_index}: " - "#{window_name} " - "[#{window_width}x#{window_height}] " - "[layout #{window_layout}] #{window_id}" - "#{?window_active, (active),}"; + template = "#{session_name}:" DEFAULT_WINDOW_TEMPLATE; break; } } diff --git a/cmd-new-window.c b/cmd-new-window.c index 5051ab1a..46bda8fc 100644 --- a/cmd-new-window.c +++ b/cmd-new-window.c @@ -122,15 +122,15 @@ cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx) server_status_session_group(s); if (args_has(args, 'P')) { - template = "#{session_name}:#{window_index}"; - if (args_has(args, 'F')) - template = args_get(args, 'F'); + if ((template = args_get(args, 'F')) == NULL) + template = DEFAULT_PANE_INFO_TEMPLATE; ft = format_create(); if ((c = cmd_find_client(ctx, NULL)) != NULL) format_client(ft, c); format_session(ft, s); format_winlink(ft, s, wl); + format_window_pane(ft, wl->window->active); cp = format_expand(ft, template); ctx->print(ctx, "%s", cp); diff --git a/cmd-split-window.c b/cmd-split-window.c index 5123942e..db00a67b 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -139,9 +139,8 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) environ_free(&env); if (args_has(args, 'P')) { - template = "#{session_name}:#{window_index}.#{pane_index}"; - if (args_has(args, 'F')) - template = args_get(args, 'F'); + if ((template = args_get(args, 'F')) == NULL) + template = DEFAULT_PANE_INFO_TEMPLATE; ft = format_create(); if ((c = cmd_find_client(ctx, NULL)) != NULL) diff --git a/format.c b/format.c index 5403f170..8fe4acf4 100644 --- a/format.c +++ b/format.c @@ -349,6 +349,7 @@ format_winlink(struct format_tree *ft, struct session *s, struct winlink *wl) format_add(ft, "window_flags", "%s", flags); format_add(ft, "window_layout", "%s", layout); format_add(ft, "window_active", "%d", wl == s->curw); + format_add(ft, "window_panes", "%u", window_count_panes(w)); xfree(flags); xfree(layout); @@ -393,3 +394,14 @@ format_window_pane(struct format_tree *ft, struct window_pane *wp) format_add(ft, "pane_pid", "%ld", (long) wp->pid); format_add(ft, "pane_tty", "%s", wp->tty); } + +void +format_paste_buffer(struct format_tree *ft, struct paste_buffer *pb) +{ + char *pb_print = paste_print(pb, 50); + + format_add(ft, "buffer_size", "%zu", pb->size); + format_add(ft, "buffer_sample", "%s", pb_print); + + xfree(pb_print); +} diff --git a/tmux.1 b/tmux.1 index 96742378..4fad6147 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1033,6 +1033,7 @@ visible pane and negative numbers are lines in the history. The default is to capture only the visible contents of the pane. .It Xo .Ic choose-client +.Op Fl F Ar format .Op Fl t Ar target-window .Op Ar template .Xc @@ -1048,10 +1049,16 @@ and the result executed as a command. If .Ar template is not given, "detach-client -t '%%'" is used. +For the meaning of the +.Fl F +flag, see the +.Sx FORMATS +section. This command works only from inside .Nm . .It Xo .Ic choose-session +.Op Fl F Ar format .Op Fl t Ar target-window .Op Ar template .Xc @@ -1065,10 +1072,16 @@ and the result executed as a command. If .Ar template is not given, "switch-client -t '%%'" is used. +For the meaning of the +.Fl F +flag, see the +.Sx FORMATS +section. This command works only from inside .Nm . .It Xo .Ic choose-window +.Op Fl F Ar format .Op Fl t Ar target-window .Op Ar template .Xc @@ -1082,6 +1095,11 @@ and the result executed as a command. If .Ar template is not given, "select-window -t '%%'" is used. +For the meaning of the +.Fl F +flag, see the +.Sx FORMATS +section. This command works only from inside .Nm . .It Ic display-panes Op Fl t Ar target-client @@ -1101,6 +1119,7 @@ to keys. .It Xo Ic find-window .Op Fl CNT +.Op Fl F Ar format .Op Fl t Ar target-window .Ar match-string .Xc @@ -1121,6 +1140,11 @@ The default is .Fl CNT . If only one window is matched, it'll be automatically selected, otherwise a choice list is shown. +For the meaning of the +.Fl F +flag, see the +.Sx FORMATS +section. This command only works from inside .Nm . .It Xo Ic join-pane @@ -2761,13 +2785,7 @@ or the global window options if is used. .El .Sh FORMATS -The -.Ic list-clients , -.Ic list-sessions , -.Ic list-windows -and -.Ic list-panes -commands accept the +Certain commands accept the .Fl F flag with a .Ar format @@ -2800,6 +2818,8 @@ if it is unattached. The following variables are available, where appropriate: .Bl -column "session_created_string" "Replaced with" -offset indent .It Sy "Variable name" Ta Sy "Replaced with" +.It Li "buffer_sample" Ta "First 50 characters from the specified buffer" +.It Li "buffer_size" Ta "Size of the specified buffer in bytes" .It Li "client_activity" Ta "Integer time client last had activity" .It Li "client_activity_string" Ta "String time client last had activity" .It Li "client_created" Ta "Integer time client created" @@ -2834,11 +2854,13 @@ The following variables are available, where appropriate: .It Li "session_width" Ta "Width of session" .It Li "session_windows" Ta "Number of windows in session" .It Li "window_active" Ta "1 if window active" +.It Li "window_find_matches" Ta "Matched data from the find-window command if available" .It Li "window_flags" Ta "Window flags" .It Li "window_height" Ta "Height of window" .It Li "window_index" Ta "Index of window" .It Li "window_layout" Ta "Window layout description" .It Li "window_name" Ta "Name of window" +.It Li "window_panes" Ta "Number of panes in window" .It Li "window_width" Ta "Width of window" .El .Sh NAMES AND TITLES @@ -3145,6 +3167,7 @@ The buffer commands are as follows: .Bl -tag -width Ds .It Xo .Ic choose-buffer +.Op Fl F Ar format .Op Fl t Ar target-window .Op Ar template .Xc @@ -3158,6 +3181,11 @@ and the result executed as a command. If .Ar template is not given, "paste-buffer -b '%%'" is used. +For the meaning of the +.Fl F +flag, see the +.Sx FORMATS +section. This command works only from inside .Nm . .It Ic clear-history Op Fl t Ar target-pane @@ -3168,9 +3196,16 @@ Remove and free the history for the specified pane. Delete the buffer at .Ar buffer-index , or the top buffer if not specified. -.It Ic list-buffers +.It Xo Ic list-buffers +.Op Fl F Ar format +.Xc .D1 (alias: Ic lsb ) List the global buffers. +For the meaning of the +.Fl F +flag, see the +.Sx FORMATS +section. .It Xo Ic load-buffer .Op Fl b Ar buffer-index .Ar path diff --git a/tmux.h b/tmux.h index 6c88fac1..721bef1b 100644 --- a/tmux.h +++ b/tmux.h @@ -92,6 +92,37 @@ extern char **environ; #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) #endif +/* Default format templates. */ +#define DEFAULT_BUFFER_LIST_TEMPLATE \ + "#{line}: #{buffer_size} bytes: \"#{buffer_sample}\"" +#define DEFAULT_CLIENT_TEMPLATE \ + "#{client_tty}: #{session_name} " \ + "[#client_width}x#{client_height} #{client_termname}]" \ + "{?client_utf8, (utf8),} #{?client_readonly, (ro),}" +#define DEFAULT_DISPLAY_MESSAGE_TEMPLATE \ + "[#{session_name}] #{window_index}:" \ + "#{window_name}, current pane #{pane_index} " \ + "- (%H:%M %d-%b-%y)" +#define DEFAULT_FIND_WINDOW_TEMPLATE \ + "#{window_index}: #{window_name} " \ + "[#{window_width}x#{window_height}] " \ + "(#{window_panes} panes) #{window_find_matches}" +#define DEFAULT_SESSION_TEMPLATE \ + "#{session_name}: #{session_windows} windows " \ + "(created #{session_created_string}) " \ + "[#{session_width}x#{session_height}]" \ + "#{?session_grouped, (group ,}" \ + "#{session_group}#{?session_grouped,),}" \ + "#{?session_attached, (attached),}" +#define DEFAULT_WINDOW_TEMPLATE \ + "#{window_index}: #{window_name}#{window_flags} " \ + "(#{window_panes} panes) " \ + "[#{window_width}x#{window_height}] " \ + "[layout #{window_layout}] #{window_id}" \ + "#{?window_active, (active),}" +#define DEFAULT_PANE_INFO_TEMPLATE \ + "#{session_name}:#{window_index}.#{pane_index}" + /* Bell option values. */ #define BELL_NONE 0 #define BELL_ANY 1 @@ -1406,6 +1437,7 @@ void format_client(struct format_tree *, struct client *); void format_winlink( struct format_tree *, struct session *, struct winlink *); void format_window_pane(struct format_tree *, struct window_pane *); +void format_paste_buffer(struct format_tree *, struct paste_buffer *); /* mode-key.c */ extern const struct mode_key_table mode_key_tables[]; From fe4f00834d9b28ac21b5ca641b2d190e93241a2e Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 22 May 2012 14:11:30 +0000 Subject: [PATCH 1119/1180] Store mouse data in tty structure not on the stack. --- tmux.h | 49 +++++++++++++++++++++++++------------------------ tty-keys.c | 28 +++++++++++++--------------- 2 files changed, 38 insertions(+), 39 deletions(-) diff --git a/tmux.h b/tmux.h index 721bef1b..48f415bf 100644 --- a/tmux.h +++ b/tmux.h @@ -1048,6 +1048,29 @@ struct session { RB_HEAD(sessions, session); ARRAY_DECL(sessionslist, struct session *); +/* + * Mouse input. xterm mouse mode is fairly silly. Buttons are in the bottom two + * bits: 0 = button 1; 1 = button 2; 2 = button 3; 3 = buttons released. Bits + * 3, 4 and 5 are for keys. Bit 6 is set for dragging and 7 for mouse buttons 4 + * and 5. + */ +struct mouse_event { + u_int b; +#define MOUSE_1 0 +#define MOUSE_2 1 +#define MOUSE_3 2 +#define MOUSE_UP 3 +#define MOUSE_BUTTON 3 +#define MOUSE_SHIFT 4 +#define MOUSE_ESCAPE 8 +#define MOUSE_CTRL 16 +#define MOUSE_DRAG 32 +#define MOUSE_45 64 +#define MOUSE_RESIZE_PANE 128 /* marker for resizing */ + u_int x; + u_int y; +}; + /* TTY information. */ struct tty_key { char ch; @@ -1115,6 +1138,7 @@ struct tty { int term_flags; + struct mouse_event mouse_event; void (*key_callback)(int, struct mouse_event *, void *); void *key_data; struct event key_timer; @@ -1151,29 +1175,6 @@ struct tty_ctx { u_int last_width; }; -/* - * Mouse input. xterm mouse mode is fairly silly. Buttons are in the bottom two - * bits: 0 = button 1; 1 = button 2; 2 = button 3; 3 = buttons released. Bits - * 3, 4 and 5 are for keys. Bit 6 is set for dragging and 7 for mouse buttons 4 - * and 5. - */ -struct mouse_event { - u_int b; -#define MOUSE_1 0 -#define MOUSE_2 1 -#define MOUSE_3 2 -#define MOUSE_UP 3 -#define MOUSE_BUTTON 3 -#define MOUSE_SHIFT 4 -#define MOUSE_ESCAPE 8 -#define MOUSE_CTRL 16 -#define MOUSE_DRAG 32 -#define MOUSE_45 64 -#define MOUSE_RESIZE_PANE 128 /* marker for resizing */ - u_int x; - u_int y; -}; - /* Saved message entry. */ struct message_entry { char *msg; @@ -1224,7 +1225,7 @@ struct client { #define CLIENT_EXIT 0x4 #define CLIENT_REDRAW 0x8 #define CLIENT_STATUS 0x10 -#define CLIENT_REPEAT 0x20 /* allow command to repeat within repeat time */ +#define CLIENT_REPEAT 0x20 /* allow command to repeat within repeat time */ #define CLIENT_SUSPENDED 0x40 #define CLIENT_BAD 0x80 #define CLIENT_IDENTIFY 0x100 diff --git a/tty-keys.c b/tty-keys.c index ddd113e2..d0bfb8ca 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -40,8 +40,7 @@ struct tty_key *tty_keys_find1( struct tty_key *, const char *, size_t, size_t *); struct tty_key *tty_keys_find(struct tty *, const char *, size_t, size_t *); void tty_keys_callback(int, short, void *); -int tty_keys_mouse(struct tty *, - const char *, size_t, size_t *, struct mouse_event *); +int tty_keys_mouse(struct tty *, const char *, size_t, size_t *); int tty_keys_device(struct tty *, const char *, size_t, size_t *); struct tty_key_ent { @@ -434,13 +433,12 @@ tty_keys_find1(struct tty_key *tk, const char *buf, size_t len, size_t *size) int tty_keys_next(struct tty *tty) { - struct tty_key *tk; - struct timeval tv; - struct mouse_event mouse; - const char *buf; - size_t len, size; - cc_t bspace; - int key, delay; + struct tty_key *tk; + struct timeval tv; + const char *buf; + size_t len, size; + cc_t bspace; + int key, delay; buf = EVBUFFER_DATA(tty->event->input); len = EVBUFFER_LENGTH(tty->event->input); @@ -477,7 +475,7 @@ tty_keys_next(struct tty *tty) } /* Is this a mouse key press? */ - switch (tty_keys_mouse(tty, buf, len, &size, &mouse)) { + switch (tty_keys_mouse(tty, buf, len, &size)) { case 0: /* yes */ evbuffer_drain(tty->event->input, size); key = KEYC_MOUSE; @@ -582,7 +580,7 @@ handle_key: evtimer_del(&tty->key_timer); if (key != KEYC_NONE) - tty->key_callback(key, &mouse, tty->key_data); + tty->key_callback(key, &tty->mouse_event, tty->key_data); tty->flags &= ~TTY_ESCAPE; return (1); @@ -607,11 +605,11 @@ tty_keys_callback(unused int fd, unused short events, void *data) * (probably a mouse sequence but need more data). */ int -tty_keys_mouse(struct tty *tty, - const char *buf, size_t len, size_t *size, struct mouse_event *m) +tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size) { - struct utf8_data utf8data; - u_int i, value; + struct mouse_event *m = &tty->mouse_event; + struct utf8_data utf8data; + u_int i, value; /* * Standard mouse sequences are \033[M followed by three characters From 84c708f3558d440be1a9e92ee8e6ead5c499fb0f Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 22 May 2012 14:32:28 +0000 Subject: [PATCH 1120/1180] Store client in tty struct directly instead of using a callback function pointer. --- server-client.c | 14 +++++--------- tmux.h | 10 ++++++---- tty-keys.c | 4 ++-- tty.c | 3 ++- 4 files changed, 15 insertions(+), 16 deletions(-) diff --git a/server-client.c b/server-client.c index 25f17f06..34217a61 100644 --- a/server-client.c +++ b/server-client.c @@ -27,9 +27,8 @@ #include "tmux.h" -void server_client_check_mouse(struct client *c, - struct window_pane *wp, struct mouse_event *mouse); -void server_client_handle_key(int, struct mouse_event *, void *); +void server_client_check_mouse(struct client *, struct window_pane *, + struct mouse_event *); void server_client_repeat_timer(int, short, void *); void server_client_check_exit(struct client *); void server_client_check_redraw(struct client *); @@ -338,9 +337,8 @@ server_client_check_mouse( /* Handle data key input from client. */ void -server_client_handle_key(int key, struct mouse_event *mouse, void *data) +server_client_handle_key(struct client *c, int key) { - struct client *c = data; struct session *s; struct window *w; struct window_pane *wp; @@ -391,7 +389,7 @@ server_client_handle_key(int key, struct mouse_event *mouse, void *data) if (key == KEYC_MOUSE) { if (c->flags & CLIENT_READONLY) return; - server_client_check_mouse(c, wp, mouse); + server_client_check_mouse(c, wp, &c->tty.mouse); return; } @@ -899,15 +897,13 @@ server_client_msg_identify( if (!isatty(fd)) return; data->term[(sizeof data->term) - 1] = '\0'; - tty_init(&c->tty, fd, data->term); + tty_init(&c->tty, c, fd, data->term); if (data->flags & IDENTIFY_UTF8) c->tty.flags |= TTY_UTF8; if (data->flags & IDENTIFY_256COLOURS) c->tty.term_flags |= TERM_256COLOURS; else if (data->flags & IDENTIFY_88COLOURS) c->tty.term_flags |= TERM_88COLOURS; - c->tty.key_callback = server_client_handle_key; - c->tty.key_data = c; tty_resize(&c->tty); diff --git a/tmux.h b/tmux.h index 48f415bf..ed722ab6 100644 --- a/tmux.h +++ b/tmux.h @@ -1100,6 +1100,8 @@ struct tty_term { LIST_HEAD(tty_terms, tty_term); struct tty { + struct client *client; + char *path; u_int xterm_version; @@ -1138,9 +1140,8 @@ struct tty { int term_flags; - struct mouse_event mouse_event; - void (*key_callback)(int, struct mouse_event *, void *); - void *key_data; + struct mouse_event mouse; + struct event key_timer; struct tty_key *key_tree; }; @@ -1533,7 +1534,7 @@ void tty_putcode_ptr2(struct tty *, enum tty_code_code, const void *, const void void tty_puts(struct tty *, const char *); void tty_putc(struct tty *, u_char); void tty_pututf8(struct tty *, const struct grid_utf8 *); -void tty_init(struct tty *, int, char *); +void tty_init(struct tty *, struct client *, int, char *); int tty_resize(struct tty *); int tty_set_size(struct tty *, u_int, u_int); void tty_start_tty(struct tty *); @@ -1764,6 +1765,7 @@ void server_update_socket(void); void server_add_accept(int); /* server-client.c */ +void server_client_handle_key(struct client *, int); void server_client_create(int); int server_client_open(struct client *, struct session *, char **); void server_client_lost(struct client *); diff --git a/tty-keys.c b/tty-keys.c index d0bfb8ca..9390981e 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -580,7 +580,7 @@ handle_key: evtimer_del(&tty->key_timer); if (key != KEYC_NONE) - tty->key_callback(key, &tty->mouse_event, tty->key_data); + server_client_handle_key(tty->client, key); tty->flags &= ~TTY_ESCAPE; return (1); @@ -607,7 +607,7 @@ tty_keys_callback(unused int fd, unused short events, void *data) int tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size) { - struct mouse_event *m = &tty->mouse_event; + struct mouse_event *m = &tty->mouse; struct utf8_data utf8data; u_int i, value; diff --git a/tty.c b/tty.c index 5eb37ade..6e895f5c 100644 --- a/tty.c +++ b/tty.c @@ -64,7 +64,7 @@ void tty_cell(struct tty *, ((ctx)->xoff == 0 && screen_size_x((ctx)->wp->screen) >= (tty)->sx) void -tty_init(struct tty *tty, int fd, char *term) +tty_init(struct tty *tty, struct client *c, int fd, char *term) { char *path; @@ -76,6 +76,7 @@ tty_init(struct tty *tty, int fd, char *term) else tty->termname = xstrdup(term); tty->fd = fd; + tty->client = c; if ((path = ttyname(fd)) == NULL) fatalx("ttyname failed"); From 1f23f6d68608716f93e9262cbb2abc335ef88401 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 23 May 2012 19:19:40 +0000 Subject: [PATCH 1121/1180] Use a predefined structure for not-space cells used to set attributes. --- grid.c | 1 + screen-redraw.c | 11 ++++------- tmux.h | 1 + 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/grid.c b/grid.c index b11e5a97..a92f43f4 100644 --- a/grid.c +++ b/grid.c @@ -36,6 +36,7 @@ /* Default grid cell data. */ const struct grid_cell grid_default_cell = { 0, 0, 8, 8, ' ' }; +const struct grid_cell grid_marker_cell = { 0, 0, 8, 8, '_' }; #define grid_put_cell(gd, px, py, gc) do { \ memcpy(&gd->linedata[py].celldata[px], \ diff --git a/screen-redraw.c b/screen-redraw.c index 2eca1bdc..8cc448a2 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -202,9 +202,8 @@ screen_redraw_screen(struct client *c, int status_only, int borders_only) } /* Set up pane border attributes. */ - memcpy(&other_gc, &grid_default_cell, sizeof other_gc); - memcpy(&active_gc, &grid_default_cell, sizeof active_gc); - active_gc.data = other_gc.data = 'x'; /* not space */ + 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); @@ -317,8 +316,7 @@ screen_redraw_draw_number(struct client *c, struct window_pane *wp) px -= len * 3; py -= 2; - memcpy(&gc, &grid_default_cell, sizeof gc); - gc.data = '_'; /* not space */ + memcpy(&gc, &grid_marker_cell, sizeof gc); if (w->active == wp) colour_set_bg(&gc, active_colour); else @@ -345,8 +343,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_default_cell, sizeof gc); - gc.data = '_'; /* not space */ + memcpy(&gc, &grid_marker_cell, sizeof gc); if (w->active == wp) colour_set_fg(&gc, active_colour); else diff --git a/tmux.h b/tmux.h index ed722ab6..011c28c7 100644 --- a/tmux.h +++ b/tmux.h @@ -1862,6 +1862,7 @@ int attributes_fromstring(const char *); /* grid.c */ extern const struct grid_cell grid_default_cell; +extern const struct grid_cell grid_marker_cell; struct grid *grid_create(u_int, u_int, u_int); void grid_destroy(struct grid *); int grid_compare(struct grid *, struct grid *); From 196710e2d3602832595626aa8ec5973247aaff17 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 25 May 2012 08:28:10 +0000 Subject: [PATCH 1122/1180] Simplify logging and just fprintf(stderr, ...) for early errors. --- client.c | 10 ++++---- log.c | 73 +++++++++++++++----------------------------------------- tmux.c | 6 ++--- tmux.h | 3 +-- 4 files changed, 27 insertions(+), 65 deletions(-) diff --git a/client.c b/client.c index 4ebcf2ad..1a318d3f 100644 --- a/client.c +++ b/client.c @@ -209,15 +209,15 @@ client_main(int argc, char **argv, int flags) if (shell_cmd == NULL && environ_path != NULL && (cmdflags & CMD_CANTNEST) && strcmp(socket_path, environ_path) == 0) { - log_warnx("sessions should be nested with care. " - "unset $TMUX to force."); + fprintf(stderr, "sessions should be nested with care, " + "unset $TMUX to force\n"); return (1); } /* Initialise the client socket and start the server. */ fd = client_connect(socket_path, cmdflags & CMD_STARTSERVER); if (fd == -1) { - log_warn("failed to connect to server"); + fprintf(stderr, "failed to connect to server\n"); return (1); } @@ -252,7 +252,7 @@ client_main(int argc, char **argv, int flags) cmddata.argc = argc; if (cmd_pack_argv( argc, argv, cmddata.argv, sizeof cmddata.argv) != 0) { - log_warnx("command too long"); + fprintf(stderr, "command too long\n"); return (1); } @@ -538,7 +538,7 @@ client_dispatch_attached(void) return (0); datalen = imsg.hdr.len - IMSG_HEADER_SIZE; - log_debug("client got %d", imsg.hdr.type); + log_debug("got %d from server", imsg.hdr.type); switch (imsg.hdr.type) { case MSG_DETACHKILL: case MSG_DETACH: diff --git a/log.c b/log.c index 184f9597..dbae1972 100644 --- a/log.c +++ b/log.c @@ -27,20 +27,14 @@ #include "tmux.h" -/* Logging type. */ -#define LOG_TYPE_OFF 0 -#define LOG_TYPE_TTY 1 -#define LOG_TYPE_FILE 2 -int log_type = LOG_TYPE_OFF; - /* Log file, if needed. */ -FILE *log_file; +FILE *log_file = stderr; /* Debug level. */ -int log_level; +int log_level = 0; void log_event_cb(int, const char *); -void log_vwrite(int, const char *, va_list); +void log_vwrite(const char *, va_list); __dead void log_vfatal(const char *, va_list); /* Log callback for libevent. */ @@ -50,29 +44,13 @@ log_event_cb(unused int severity, const char *msg) log_warnx("%s", msg); } -/* Open logging to tty. */ -void -log_open_tty(int level) -{ - log_type = LOG_TYPE_TTY; - log_level = level; - - setlinebuf(stderr); - setlinebuf(stdout); - event_set_log_callback(log_event_cb); - - tzset(); -} - /* Open logging to file. */ void -log_open_file(int level, const char *path) +log_open(int level, const char *path) { log_file = fopen(path, "w"); if (log_file == NULL) return; - - log_type = LOG_TYPE_FILE; log_level = level; setlinebuf(log_file); @@ -85,37 +63,24 @@ log_open_file(int level, const char *path) void log_close(void) { - if (log_type == LOG_TYPE_FILE) + if (log_file != stderr) fclose(log_file); event_set_log_callback(NULL); - - log_type = LOG_TYPE_OFF; } /* Write a log message. */ void -log_vwrite(int pri, const char *msg, va_list ap) +log_vwrite(const char *msg, va_list ap) { char *fmt; - FILE *f = log_file; - switch (log_type) { - case LOG_TYPE_TTY: - if (pri == LOG_INFO) - f = stdout; - else - f = stderr; - /* FALLTHROUGH */ - case LOG_TYPE_FILE: - if (asprintf(&fmt, "%s\n", msg) == -1) - exit(1); - if (vfprintf(f, fmt, ap) == -1) - exit(1); - fflush(f); - free(fmt); - break; - } + if (asprintf(&fmt, "%s\n", msg) == -1) + exit(1); + if (vfprintf(log_file, fmt, ap) == -1) + exit(1); + fflush(log_file); + free(fmt); } /* Log a warning with error string. */ @@ -128,7 +93,7 @@ log_warn(const char *msg, ...) va_start(ap, msg); if (asprintf(&fmt, "%s: %s", msg, strerror(errno)) == -1) exit(1); - log_vwrite(LOG_CRIT, fmt, ap); + log_vwrite(fmt, ap); free(fmt); va_end(ap); } @@ -140,7 +105,7 @@ log_warnx(const char *msg, ...) va_list ap; va_start(ap, msg); - log_vwrite(LOG_CRIT, msg, ap); + log_vwrite(msg, ap); va_end(ap); } @@ -152,7 +117,7 @@ log_info(const char *msg, ...) if (log_level > -1) { va_start(ap, msg); - log_vwrite(LOG_INFO, msg, ap); + log_vwrite(msg, ap); va_end(ap); } } @@ -165,7 +130,7 @@ log_debug(const char *msg, ...) if (log_level > 0) { va_start(ap, msg); - log_vwrite(LOG_DEBUG, msg, ap); + log_vwrite(msg, ap); va_end(ap); } } @@ -178,7 +143,7 @@ log_debug2(const char *msg, ...) if (log_level > 1) { va_start(ap, msg); - log_vwrite(LOG_DEBUG, msg, ap); + log_vwrite(msg, ap); va_end(ap); } } @@ -192,11 +157,11 @@ log_vfatal(const char *msg, va_list ap) if (errno != 0) { if (asprintf(&fmt, "fatal: %s: %s", msg, strerror(errno)) == -1) exit(1); - log_vwrite(LOG_CRIT, fmt, ap); + log_vwrite(fmt, ap); } else { if (asprintf(&fmt, "fatal: %s", msg) == -1) exit(1); - log_vwrite(LOG_CRIT, fmt, ap); + log_vwrite(fmt, ap); } free(fmt); diff --git a/tmux.c b/tmux.c index 35d43909..468d37f7 100644 --- a/tmux.c +++ b/tmux.c @@ -73,7 +73,7 @@ logfile(const char *name) log_close(); if (debug_level > 0) { xasprintf(&path, "tmux-%s-%ld.log", name, (long) getpid()); - log_open_file(debug_level, path); + log_open(debug_level, path); xfree(path); } } @@ -294,8 +294,6 @@ main(int argc, char **argv) if (shell_cmd != NULL && argc != 0) usage(); - log_open_tty(debug_level); - if (!(flags & IDENTIFY_UTF8)) { /* * If the user has set whichever of LC_ALL, LC_CTYPE or LANG @@ -379,7 +377,7 @@ main(int argc, char **argv) /* -L or default set. */ if (label != NULL) { if ((path = makesocketpath(label)) == NULL) { - log_warn("can't create socket"); + fprintf(stderr, "can't create socket\n"); exit(1); } } diff --git a/tmux.h b/tmux.h index 011c28c7..8da42144 100644 --- a/tmux.h +++ b/tmux.h @@ -2181,8 +2181,7 @@ char *get_proc_name(int, char *); char *get_proc_cwd(pid_t); /* log.c */ -void log_open_tty(int); -void log_open_file(int, const char *); +void log_open(int, const char *); void log_close(void); void printflike1 log_warn(const char *, ...); void printflike1 log_warnx(const char *, ...); From 993f1b96a3ced16479c5f3b91149087efab318bb Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 27 May 2012 21:43:57 +0000 Subject: [PATCH 1123/1180] Fix client templates, from Romain Francoise. --- tmux.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tmux.h b/tmux.h index 8da42144..27c84c5d 100644 --- a/tmux.h +++ b/tmux.h @@ -97,8 +97,8 @@ extern char **environ; "#{line}: #{buffer_size} bytes: \"#{buffer_sample}\"" #define DEFAULT_CLIENT_TEMPLATE \ "#{client_tty}: #{session_name} " \ - "[#client_width}x#{client_height} #{client_termname}]" \ - "{?client_utf8, (utf8),} #{?client_readonly, (ro),}" + "[#{client_width}x#{client_height} #{client_termname}]" \ + "#{?client_utf8, (utf8),} #{?client_readonly, (ro),}" #define DEFAULT_DISPLAY_MESSAGE_TEMPLATE \ "[#{session_name}] #{window_index}:" \ "#{window_name}, current pane #{pane_index} " \ From 184580065121aae77881b78e4df71f3d9cf335c3 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 28 May 2012 07:59:07 +0000 Subject: [PATCH 1124/1180] Strip layout from choose-windows again (leave in list-windows), suggested by Romain Francoise, diff from Thomas Adam. --- cmd-list-windows.c | 4 +++- tmux.h | 4 +--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cmd-list-windows.c b/cmd-list-windows.c index 103931d2..347237e9 100644 --- a/cmd-list-windows.c +++ b/cmd-list-windows.c @@ -84,7 +84,9 @@ cmd_list_windows_session( if (template == NULL) { switch (type) { case 0: - template = DEFAULT_WINDOW_TEMPLATE; + template = DEFAULT_WINDOW_TEMPLATE \ + " [layout #{window_layout}] #{window_id}" \ + " #{?window_active, (active),}"; break; case 1: template = "#{session_name}:" DEFAULT_WINDOW_TEMPLATE; diff --git a/tmux.h b/tmux.h index 27c84c5d..6971fd0f 100644 --- a/tmux.h +++ b/tmux.h @@ -117,9 +117,7 @@ extern char **environ; #define DEFAULT_WINDOW_TEMPLATE \ "#{window_index}: #{window_name}#{window_flags} " \ "(#{window_panes} panes) " \ - "[#{window_width}x#{window_height}] " \ - "[layout #{window_layout}] #{window_id}" \ - "#{?window_active, (active),}" + "[#{window_width}x#{window_height}]" #define DEFAULT_PANE_INFO_TEMPLATE \ "#{session_name}:#{window_index}.#{pane_index}" From fbf2bd865cb2ea19572a259f2011f37975e41647 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 28 May 2012 08:00:46 +0000 Subject: [PATCH 1125/1180] Trim a double space from template. --- cmd-list-windows.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd-list-windows.c b/cmd-list-windows.c index 347237e9..e0617335 100644 --- a/cmd-list-windows.c +++ b/cmd-list-windows.c @@ -86,7 +86,7 @@ cmd_list_windows_session( case 0: template = DEFAULT_WINDOW_TEMPLATE \ " [layout #{window_layout}] #{window_id}" \ - " #{?window_active, (active),}"; + "#{?window_active, (active),}"; break; case 1: template = "#{session_name}:" DEFAULT_WINDOW_TEMPLATE; From f51c55c3f032e4c525cc7aa7ac74c1ce4a9d29ab Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 28 May 2012 08:55:43 +0000 Subject: [PATCH 1126/1180] Use default-shell not _PATH_BSHELL to spawn commands, pointed out by Dennis G?nnewig and Thomas Adam. --- window.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/window.c b/window.c index 9071972d..0d2b74bf 100644 --- a/window.c +++ b/window.c @@ -739,23 +739,24 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell, clear_signals(1); log_close(); - if (*wp->cmd != '\0') { - /* Set SHELL but only if it is currently not useful. */ - shell = getenv("SHELL"); - if (checkshell(shell)) - setenv("SHELL", wp->shell, 1); + setenv("SHELL", wp->shell, 1); + ptr = strrchr(wp->shell, '/'); - execl(_PATH_BSHELL, "sh", "-c", wp->cmd, (char *) NULL); + if (*wp->cmd != '\0') { + /* Use the command. */ + if (ptr != NULL && *(ptr + 1) != '\0') + xasprintf(&argv0, "%s", ptr + 1); + else + xasprintf(&argv0, "%s", wp->shell); + execl(wp->shell, argv0, "-c", wp->cmd, (char *) NULL); fatal("execl failed"); } /* No command; fork a login shell. */ - ptr = strrchr(wp->shell, '/'); if (ptr != NULL && *(ptr + 1) != '\0') xasprintf(&argv0, "-%s", ptr + 1); else xasprintf(&argv0, "-%s", wp->shell); - setenv("SHELL", wp->shell, 1); execl(wp->shell, argv0, (char *) NULL); fatal("execl failed"); } From 226f9fa0126da91e7c335dcb94222c5c1a0c92b4 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 29 May 2012 08:11:34 +0000 Subject: [PATCH 1127/1180] Use session from -t for killw -a, from Chris Johnsen. --- cmd-kill-window.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cmd-kill-window.c b/cmd-kill-window.c index f734eeaf..b772705f 100644 --- a/cmd-kill-window.c +++ b/cmd-kill-window.c @@ -41,12 +41,13 @@ cmd_kill_window_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; struct winlink *wl, *wl2; + struct session *s; - if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL) + if ((wl = cmd_find_window(ctx, args_get(args, 't'), &s)) == NULL) return (-1); if (args_has(args, 'a')) { - RB_FOREACH(wl2, winlinks, &ctx->curclient->session->windows) { + RB_FOREACH(wl2, winlinks, &s->windows) { if (wl != wl2) server_kill_window(wl2->window); } From 63d109fb7fb4522bf4d21528e12a14d91a8bb556 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 29 May 2012 08:12:13 +0000 Subject: [PATCH 1128/1180] Use RB_FOREACH_SAFE as winlinks are being removed, from Chris Johnsen. --- cmd-kill-window.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd-kill-window.c b/cmd-kill-window.c index b772705f..255026cd 100644 --- a/cmd-kill-window.c +++ b/cmd-kill-window.c @@ -40,14 +40,14 @@ int cmd_kill_window_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; - struct winlink *wl, *wl2; + struct winlink *wl, *wl2, *wl3; struct session *s; if ((wl = cmd_find_window(ctx, args_get(args, 't'), &s)) == NULL) return (-1); if (args_has(args, 'a')) { - RB_FOREACH(wl2, winlinks, &s->windows) { + RB_FOREACH_SAFE(wl2, winlinks, &s->windows, wl3) { if (wl != wl2) server_kill_window(wl2->window); } From db20f2d907caaa44797ec2f062903ba060aa4374 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 29 May 2012 08:15:45 +0000 Subject: [PATCH 1129/1180] Add pane title to choose-window template and use the right index for the pane, from Romain Francoise. --- cmd-choose-window.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cmd-choose-window.c b/cmd-choose-window.c index ba70fcd1..fffdfbb4 100644 --- a/cmd-choose-window.c +++ b/cmd-choose-window.c @@ -72,7 +72,7 @@ cmd_choose_window_exec(struct cmd *self, struct cmd_ctx *ctx) return (0); if ((template = args_get(args, 'F')) == NULL) - template = DEFAULT_WINDOW_TEMPLATE; + template = DEFAULT_WINDOW_TEMPLATE " \"#{pane_title}\""; cur = idx = 0; RB_FOREACH(wm, winlinks, &s->windows) { @@ -84,9 +84,10 @@ cmd_choose_window_exec(struct cmd *self, struct cmd_ctx *ctx) format_add(ft, "line", "%u", idx); format_session(ft, s); format_winlink(ft, s, wm); + format_window_pane(ft, wm->window->active); line = format_expand(ft, template); - window_choose_add(wl->window->active, idx, "%s", line); + window_choose_add(wl->window->active, wm->idx, "%s", line); xfree(line); format_free(ft); From 021e95b09ff8f07749bc45d61f8d7ca24a623263 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 30 May 2012 15:01:21 +0000 Subject: [PATCH 1130/1180] Do not use stderr for log file and don't call log_close when not needed. --- log.c | 7 +++++-- tmux.c | 1 - 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/log.c b/log.c index dbae1972..2f1400cb 100644 --- a/log.c +++ b/log.c @@ -28,7 +28,7 @@ #include "tmux.h" /* Log file, if needed. */ -FILE *log_file = stderr; +FILE *log_file; /* Debug level. */ int log_level = 0; @@ -63,7 +63,7 @@ log_open(int level, const char *path) void log_close(void) { - if (log_file != stderr) + if (log_file != NULL) fclose(log_file); event_set_log_callback(NULL); @@ -75,6 +75,9 @@ log_vwrite(const char *msg, va_list ap) { char *fmt; + if (log_file == NULL) + return; + if (asprintf(&fmt, "%s\n", msg) == -1) exit(1); if (vfprintf(log_file, fmt, ap) == -1) diff --git a/tmux.c b/tmux.c index 468d37f7..ad632be0 100644 --- a/tmux.c +++ b/tmux.c @@ -70,7 +70,6 @@ logfile(const char *name) { char *path; - log_close(); if (debug_level > 0) { xasprintf(&path, "tmux-%s-%ld.log", name, (long) getpid()); log_open(debug_level, path); From 04ac61ecd7ae7fb2f36ee534e4999ea9e84db759 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 18 Jun 2012 09:13:12 +0000 Subject: [PATCH 1131/1180] Simplify references to alerts in the man page, from Thomas Adam. --- tmux.1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tmux.1 b/tmux.1 index 4fad6147..f190d7bf 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1379,7 +1379,7 @@ Move a window to the next layout and rearrange the panes to fit. Move to the next window in the session. If .Fl a -is used, move to the next window with a bell, activity or content alert. +is used, move to the next window with an alert. .It Xo Ic pipe-pane .Op Fl o .Op Fl t Ar target-pane @@ -1422,7 +1422,7 @@ Move to the previous layout in the session. Move to the previous window in the session. With .Fl a , -move to the previous window with a bell, activity or content alert. +move to the previous window with an alert. .It Xo Ic rename-window .Op Fl t Ar target-window .Ar new-name @@ -1950,7 +1950,7 @@ means only bell in windows other than the current window are ignored. .It Xo Ic bell-on-alert .Op Ic on | off .Xc -If on, ring the terminal bell when an activity, content or silence alert +If on, ring the terminal bell when an alert occurs. .It Ic default-command Ar shell-command Set the command used for new windows (if not specified when the window is From 038e8b770d3ae551e9547a22d595877d237c2891 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 18 Jun 2012 09:15:22 +0000 Subject: [PATCH 1132/1180] Add -a flag for detach-client, from Thomas Adam. --- cmd-detach-client.c | 16 ++++++++++++---- tmux.1 | 5 +++++ 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/cmd-detach-client.c b/cmd-detach-client.c index d8642757..6477e062 100644 --- a/cmd-detach-client.c +++ b/cmd-detach-client.c @@ -28,8 +28,8 @@ int cmd_detach_client_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_detach_client_entry = { "detach-client", "detach", - "s:t:P", 0, 0, - "[-P] [-s target-session] " CMD_TARGET_CLIENT_USAGE, + "as:t:P", 0, 0, + "[-P] [-a] [-s target-session] " CMD_TARGET_CLIENT_USAGE, CMD_READONLY, NULL, NULL, @@ -40,7 +40,7 @@ int cmd_detach_client_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; - struct client *c; + struct client *c, *c2; struct session *s; enum msgtype msgtype; u_int i; @@ -65,7 +65,15 @@ cmd_detach_client_exec(struct cmd *self, struct cmd_ctx *ctx) if (c == NULL) return (-1); - server_write_client(c, msgtype, NULL, 0); + if (args_has(args, 'a')) { + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c2 = ARRAY_ITEM(&clients, i); + if (c2 == NULL || c == c2) + continue; + server_write_client(c2, msgtype, NULL, 0); + } + } else + server_write_client(c, msgtype, NULL, 0); } return (0); diff --git a/tmux.1 b/tmux.1 index f190d7bf..826e1cac 100644 --- a/tmux.1 +++ b/tmux.1 @@ -585,6 +585,7 @@ recently used session. .It Xo Ic detach-client .Op Fl P +.Op Fl a .Op Fl s Ar target-session .Op Fl t Ar target-client .Xc @@ -593,6 +594,10 @@ Detach the current client if bound to a key, the client specified with .Fl t , or all clients currently attached to the session specified by .Fl s . +The +.Fl a +option kills all but the client given with +.Fl t . If .Fl P is given, send SIGHUP to the parent process of the client, typically causing it From 2113115cdd554065c760ee2de8bf2790c541edf3 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 18 Jun 2012 09:16:15 +0000 Subject: [PATCH 1133/1180] Add -a for kill-session, from Thomas Adam. --- cmd-kill-session.c | 20 ++++++++++++++------ tmux.1 | 7 ++++++- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/cmd-kill-session.c b/cmd-kill-session.c index 69caef9e..bdc4a71c 100644 --- a/cmd-kill-session.c +++ b/cmd-kill-session.c @@ -31,8 +31,8 @@ int cmd_kill_session_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_kill_session_entry = { "kill-session", NULL, - "t:", 0, 0, - CMD_TARGET_SESSION_USAGE, + "at:", 0, 0, + "[-a] " CMD_TARGET_SESSION_USAGE, 0, NULL, NULL, @@ -43,13 +43,21 @@ int cmd_kill_session_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; - struct session *s; + struct session *s, *s2, *s3; if ((s = cmd_find_session(ctx, args_get(args, 't'), 0)) == NULL) return (-1); - server_destroy_session(s); - session_destroy(s); - + if (args_has(args, 'a')) { + RB_FOREACH_SAFE(s2, sessions, &sessions, s3) { + if (s != s2) { + server_destroy_session(s2); + session_destroy(s2); + } + } + } else { + server_destroy_session(s); + session_destroy(s); + } return (0); } diff --git a/tmux.1 b/tmux.1 index 826e1cac..e91046ed 100644 --- a/tmux.1 +++ b/tmux.1 @@ -610,9 +610,14 @@ If it does exist, exit with 0. Kill the .Nm server and clients and destroy all sessions. -.It Ic kill-session Op Fl t Ar target-session +.It Ic kill-session +.Op Fl a +.Op Fl t Ar target-session Destroy the given session, closing any windows linked to it and no other sessions, and detaching all clients attached to it. +If +.Fl a +is given, all sessions but the specified one is killed. .It Xo Ic list-clients .Op Fl F Ar format .Op Fl t Ar target-session From a4a2c68fa9428cc3ceb9c9630f4d54b9b91bf043 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 18 Jun 2012 09:20:19 +0000 Subject: [PATCH 1134/1180] Do not crash when the current session has no window, fixes a bug reported by Giorgio Lando. Fix from Thomas Adam. --- cmd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd.c b/cmd.c index a3a70284..16758589 100644 --- a/cmd.c +++ b/cmd.c @@ -1290,7 +1290,7 @@ cmd_get_default_path(struct cmd_ctx *ctx, const char *cwd) /* Session working directory. */ root = s->cwd; goto complete_path; - } else if (cwd[0] == '.' && (cwd[1] == '\0' || cwd[1] == '/')){ + } else if (cwd[0] == '.' && (cwd[1] == '\0' || cwd[1] == '/')) { /* Server working directory. */ if (getcwd(tmp, sizeof tmp) != NULL) { root = tmp; @@ -1304,7 +1304,7 @@ cmd_get_default_path(struct cmd_ctx *ctx, const char *cwd) /* Empty or relative path. */ if (ctx->cmdclient != NULL && ctx->cmdclient->cwd != NULL) root = ctx->cmdclient->cwd; - else if (ctx->curclient != NULL) + else if (ctx->curclient != NULL && s->curw != NULL) root = get_proc_cwd(s->curw->window->active->pid); else return (s->cwd); From a13b4a819a0a6d7d5763d12335eb82417093202d Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 18 Jun 2012 09:58:02 +0000 Subject: [PATCH 1135/1180] Add a couple of NULL pointer checks to key binding functions, from jspenguin on SF bug 3535531. --- key-bindings.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/key-bindings.c b/key-bindings.c index ea27848c..f020c19d 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -207,6 +207,9 @@ key_bindings_error(struct cmd_ctx *ctx, const char *fmt, ...) va_list ap; char *msg; + if (ctx->curclient->session == NULL) + return; + va_start(ap, fmt); xvasprintf(&msg, fmt, ap); va_end(ap); @@ -219,9 +222,13 @@ key_bindings_error(struct cmd_ctx *ctx, const char *fmt, ...) void printflike2 key_bindings_print(struct cmd_ctx *ctx, const char *fmt, ...) { - struct winlink *wl = ctx->curclient->session->curw; + struct winlink *wl; va_list ap; + if (ctx->curclient->session == NULL) + return; + + wl = ctx->curclient->session->curw; if (wl->window->active->mode != &window_copy_mode) { window_pane_reset_mode(wl->window->active); window_pane_set_mode(wl->window->active, &window_copy_mode); @@ -239,6 +246,9 @@ key_bindings_info(struct cmd_ctx *ctx, const char *fmt, ...) va_list ap; char *msg; + if (ctx->curclient->session == NULL) + return; + if (options_get_number(&global_options, "quiet")) return; From 7c39850d1f55f101c42a2dd65664691927c459a1 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 18 Jun 2012 10:58:44 +0000 Subject: [PATCH 1136/1180] Tidy up bell code, from Thomas Adam. --- server-window.c | 49 ++++++++++++++----------------------------------- 1 file changed, 14 insertions(+), 35 deletions(-) diff --git a/server-window.c b/server-window.c index 47dec89a..f382de99 100644 --- a/server-window.c +++ b/server-window.c @@ -76,46 +76,25 @@ server_window_check_bell(struct session *s, struct winlink *wl) return (0); if (s->curw != wl || s->flags & SESSION_UNATTACHED) wl->flags |= WINLINK_BELL; + if (s->flags & SESSION_UNATTACHED) + return (1); + visual = options_get_number(&s->options, "visual-bell"); action = options_get_number(&s->options, "bell-action"); - switch (action) { - case BELL_ANY: - if (s->flags & SESSION_UNATTACHED) - break; - visual = options_get_number(&s->options, "visual-bell"); - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - c = ARRAY_ITEM(&clients, i); - if (c == NULL || c->session != s) - continue; - if (!visual) { - tty_bell(&c->tty); - continue; - } - if (c->session->curw->window == w) { - status_message_set(c, "Bell in current window"); - continue; - } - status_message_set(c, "Bell in window %u", - winlink_find_by_window(&s->windows, w)->idx); + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c == NULL || c->session != s) + continue; + if (!visual) { + tty_bell(&c->tty); + continue; } - break; - case BELL_CURRENT: - if (s->flags & SESSION_UNATTACHED) - break; - visual = options_get_number(&s->options, "visual-bell"); - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - c = ARRAY_ITEM(&clients, i); - if (c == NULL || c->session != s) - continue; - if (c->session->curw->window != w) - continue; - if (!visual) { - tty_bell(&c->tty); - continue; - } + if (c->session->curw->window == w) status_message_set(c, "Bell in current window"); + else if (action == BELL_ANY) { + status_message_set(c, "Bell in window %u", + winlink_find_by_window(&s->windows, w)->idx); } - break; } return (1); From 2942eca8953561cef0764c1775666697ee032c34 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 18 Jun 2012 13:16:42 +0000 Subject: [PATCH 1137/1180] Add a skeleton mode to tmux (called "control mode") that let's tmux commands be sent and output received on stdout. This can be used to integrate with other terminal emulators and should allow some other things to be made simpler later. More to come so doesn't do much yet and deliberately not documented. --- Makefile | 2 +- client.c | 27 ++++++++++- cmd-list.c | 16 ++++++- control.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++++ server-client.c | 14 ++++++ server-fn.c | 2 + tmux.c | 8 +++- tmux.h | 6 +++ 8 files changed, 191 insertions(+), 5 deletions(-) create mode 100644 control.c diff --git a/Makefile b/Makefile index 2e23b71a..2b9dde1f 100644 --- a/Makefile +++ b/Makefile @@ -30,7 +30,7 @@ SRCS= arguments.c attributes.c cfg.c client.c clock.c \ cmd-display-message.c cmd-display-panes.c cmd-if-shell.c \ cmd-pipe-pane.c cmd-capture-pane.c cmd.c \ colour.c environ.c grid-view.c grid-utf8.c grid.c input-keys.c \ - input.c key-bindings.c key-string.c format.c \ + input.c key-bindings.c key-string.c format.c control.c \ layout-custom.c layout-set.c layout.c log.c job.c notify.c \ mode-key.c names.c options.c options-table.c paste.c procname.c \ resize.c screen-redraw.c screen-write.c screen.c session.c status.c \ diff --git a/client.c b/client.c index 1a318d3f..911a639f 100644 --- a/client.c +++ b/client.c @@ -169,6 +169,7 @@ client_main(int argc, char **argv, int flags) pid_t ppid; enum msgtype msg; char *cause; + struct termios tio, saved_tio; /* Set up the initial command. */ cmdflags = 0; @@ -233,6 +234,23 @@ client_main(int argc, char **argv, int flags) setblocking(STDIN_FILENO, 0); event_set(&client_stdin, STDIN_FILENO, EV_READ|EV_PERSIST, client_stdin_callback, NULL); + if (flags & IDENTIFY_TERMIOS) { + if (tcgetattr(STDIN_FILENO, &saved_tio) != 0) { + fprintf(stderr, "tcgetattr failed: %s\n", + strerror(errno)); + return (1); + } + cfmakeraw(&tio); + tio.c_iflag = ICRNL|IXANY; + tio.c_oflag = OPOST|ONLCR; + tio.c_lflag = NOKERNINFO; + tio.c_cflag = CREAD|CS8|HUPCL; + tio.c_cc[VMIN] = 1; + tio.c_cc[VTIME] = 0; + cfsetispeed(&tio, cfgetispeed(&saved_tio)); + cfsetospeed(&tio, cfgetospeed(&saved_tio)); + tcsetattr(STDIN_FILENO, TCSANOW, &tio); + } /* Establish signal handlers. */ set_signals(client_signal); @@ -273,7 +291,8 @@ client_main(int argc, char **argv, int flags) ppid = getppid(); if (client_exittype == MSG_DETACHKILL && ppid > 1) kill(ppid, SIGHUP); - } + } else if (flags & IDENTIFY_TERMIOS) + tcsetattr(STDOUT_FILENO, TCSAFLUSH, &saved_tio); setblocking(STDIN_FILENO, 1); return (client_exitval); } @@ -513,6 +532,12 @@ client_dispatch_wait(void *data) shell_exec(shelldata.shell, shellcmd); /* NOTREACHED */ + case MSG_DETACH: + client_write_server(MSG_EXITING, NULL, 0); + break; + case MSG_EXITED: + imsg_free(&imsg); + return (-1); default: fatalx("unexpected message"); } diff --git a/cmd-list.c b/cmd-list.c index b8a8c115..dc102dcc 100644 --- a/cmd-list.c +++ b/cmd-list.c @@ -81,12 +81,24 @@ bad: int cmd_list_exec(struct cmd_list *cmdlist, struct cmd_ctx *ctx) { + struct client *c = ctx->curclient; struct cmd *cmd; - int n, retval; + int n, retval, guards; + + guards = 0; + if (c != NULL && c->session != NULL) + guards = c->flags & CLIENT_CONTROL; retval = 0; TAILQ_FOREACH(cmd, &cmdlist->list, qentry) { - if ((n = cmd_exec(cmd, ctx)) == -1) + if (guards) + ctx->print(ctx, "%%begin"); + n = cmd_exec(cmd, ctx); + if (guards) + ctx->print(ctx, "%%end"); + + /* Return of -1 is an error. */ + if (n == -1) return (-1); /* diff --git a/control.c b/control.c new file mode 100644 index 00000000..52ccb202 --- /dev/null +++ b/control.c @@ -0,0 +1,121 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2012 Nicholas Marriott + * Copyright (c) 2012 George Nachman + * + * 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 "tmux.h" + +void printflike2 control_msg_error(struct cmd_ctx *, const char *, ...); +void printflike2 control_msg_print(struct cmd_ctx *, const char *, ...); +void printflike2 control_msg_info(struct cmd_ctx *, const char *, ...); +void printflike2 control_write(struct client *, const char *, ...); + +/* Command error callback. */ +void printflike2 +control_msg_error(struct cmd_ctx *ctx, const char *fmt, ...) +{ + struct client *c = ctx->curclient; + va_list ap; + + 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); +} + +/* Command print callback. */ +void printflike2 +control_msg_print(struct cmd_ctx *ctx, const char *fmt, ...) +{ + struct client *c = ctx->curclient; + va_list ap; + + 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); +} + +/* Command info callback. */ +void printflike2 +control_msg_info(unused struct cmd_ctx *ctx, unused const char *fmt, ...) +{ +} + +/* Write a line. */ +void printflike2 +control_write(struct client *c, const char *fmt, ...) +{ + va_list ap; + + 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); +} + +/* Control input callback. Read lines and fire commands. */ +void +control_callback(struct client *c, int closed, unused void *data) +{ + char *line, *cause; + struct cmd_ctx ctx; + struct cmd_list *cmdlist; + + if (closed) + c->flags |= CLIENT_EXIT; + + for (;;) { + line = evbuffer_readln(c->stdin_data, NULL, EVBUFFER_EOL_LF); + if (line == NULL) + break; + if (*line == '\0') { /* empty line exit */ + c->flags |= CLIENT_EXIT; + break; + } + + ctx.msgdata = NULL; + ctx.cmdclient = NULL; + ctx.curclient = c; + + ctx.error = control_msg_error; + ctx.print = control_msg_print; + ctx.info = control_msg_info; + + if (cmd_string_parse(line, &cmdlist, &cause) != 0) { + control_write(c, "%%error in line \"%s\": %s", line, + cause); + xfree(cause); + } else { + cmd_list_exec(cmdlist, &ctx); + cmd_list_free(cmdlist); + } + + xfree(line); + } +} diff --git a/server-client.c b/server-client.c index 34217a61..8b972c90 100644 --- a/server-client.c +++ b/server-client.c @@ -108,6 +108,9 @@ server_client_open(struct client *c, struct session *s, char **cause) struct options *oo = s != NULL ? &s->options : &global_s_options; char *overrides; + if (c->flags & CLIENT_CONTROL) + return (0); + if (!(c->flags & CLIENT_TERMINAL)) { *cause = xstrdup ("not a terminal"); return (-1); @@ -894,6 +897,17 @@ server_client_msg_identify( if (*data->cwd != '\0') c->cwd = xstrdup(data->cwd); + if (data->flags & IDENTIFY_CONTROL) { + c->stdin_callback = control_callback; + c->flags |= (CLIENT_CONTROL|CLIENT_SUSPENDED); + + c->tty.fd = -1; + c->tty.log_fd = -1; + + close(fd); + return; + } + if (!isatty(fd)) return; data->term[(sizeof data->term) - 1] = '\0'; diff --git a/server-fn.c b/server-fn.c index 794205d7..1c55e16b 100644 --- a/server-fn.c +++ b/server-fn.c @@ -49,6 +49,8 @@ server_fill_environ(struct session *s, struct environ *env) void server_write_ready(struct client *c) { + if (c->flags & CLIENT_CONTROL) + return; server_write_client(c, MSG_READY, NULL, 0); } diff --git a/tmux.c b/tmux.c index ad632be0..9a305c02 100644 --- a/tmux.c +++ b/tmux.c @@ -241,7 +241,7 @@ main(int argc, char **argv) quiet = flags = 0; label = path = NULL; login_shell = (**argv == '-'); - while ((opt = getopt(argc, argv, "28c:df:lL:qS:uUv")) != -1) { + while ((opt = getopt(argc, argv, "28c:Cdf:lL:qS:uUv")) != -1) { switch (opt) { case '2': flags |= IDENTIFY_256COLOURS; @@ -256,6 +256,12 @@ main(int argc, char **argv) xfree(shell_cmd); shell_cmd = xstrdup(optarg); break; + case 'C': + if (flags & IDENTIFY_CONTROL) + flags |= IDENTIFY_TERMIOS; + else + flags |= IDENTIFY_CONTROL; + break; case 'f': if (cfg_file != NULL) xfree(cfg_file); diff --git a/tmux.h b/tmux.h index 6971fd0f..891b8e3c 100644 --- a/tmux.h +++ b/tmux.h @@ -433,6 +433,8 @@ struct msg_identify_data { #define IDENTIFY_UTF8 0x1 #define IDENTIFY_256COLOURS 0x2 #define IDENTIFY_88COLOURS 0x4 +#define IDENTIFY_CONTROL 0x8 +#define IDENTIFY_TERMIOS 0x10 int flags; }; @@ -1232,6 +1234,7 @@ struct client { #define CLIENT_BORDERS 0x400 #define CLIENT_READONLY 0x800 #define CLIENT_REDRAWWINDOW 0x1000 +#define CLIENT_CONTROL 0x2000 int flags; struct event identify_timer; @@ -2131,6 +2134,9 @@ char *default_window_name(struct window *); void set_signals(void(*)(int, short, void *)); void clear_signals(int); +/* control.c */ +void control_callback(struct client *, int, void*); + /* session.c */ extern struct sessions sessions; extern struct sessions dead_sessions; From 0f00c3b47a700834f8cfab2537a37292cd8e5796 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 18 Jun 2012 13:34:56 +0000 Subject: [PATCH 1138/1180] Actually write all the data to stdout/stderr. --- client.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/client.c b/client.c index 911a639f..16498577 100644 --- a/client.c +++ b/client.c @@ -58,6 +58,7 @@ void client_write_server(enum msgtype, void *, size_t); void client_update_event(void); void client_signal(int, short, void *); void client_stdin_callback(int, short, void *); +void client_write(int, const char *, size_t); void client_callback(int, short, void *); int client_dispatch_attached(void); int client_dispatch_wait(void *); @@ -458,6 +459,24 @@ client_stdin_callback(unused int fd, unused short events, unused void *data1) client_update_event(); } +/* Force write to file descriptor. */ +void +client_write(int fd, const char *data, size_t size) +{ + ssize_t used; + + while (size != 0) { + used = write(fd, data, size); + if (used == -1) { + if (errno == EINTR || errno == EAGAIN) + continue; + break; + } + data += used; + size -= used; + } +} + /* Dispatch imsgs when in wait state (before MSG_READY). */ int client_dispatch_wait(void *data) @@ -502,14 +521,14 @@ client_dispatch_wait(void *data) fatalx("bad MSG_STDOUT"); memcpy(&stdoutdata, imsg.data, sizeof stdoutdata); - fwrite(stdoutdata.data, stdoutdata.size, 1, stdout); + client_write(STDOUT_FILENO, stdoutdata.data, stdoutdata.size); break; case MSG_STDERR: if (datalen != sizeof stderrdata) fatalx("bad MSG_STDERR"); memcpy(&stderrdata, imsg.data, sizeof stderrdata); - fwrite(stderrdata.data, stderrdata.size, 1, stderr); + client_write(STDERR_FILENO, stderrdata.data, stderrdata.size); break; case MSG_VERSION: if (datalen != 0) From a7917430d8bb41792e1a8c1d6c6066763925a500 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 20 Jun 2012 12:55:55 +0000 Subject: [PATCH 1139/1180] Remove a couple of unused variables from redbrain at gcc dot gnu dot org. --- server-client.c | 2 -- tty.c | 2 -- 2 files changed, 4 deletions(-) diff --git a/server-client.c b/server-client.c index 8b972c90..0e095af0 100644 --- a/server-client.c +++ b/server-client.c @@ -345,7 +345,6 @@ server_client_handle_key(struct client *c, int key) struct session *s; struct window *w; struct window_pane *wp; - struct options *oo; struct timeval tv; struct key_binding *bd; int xtimeout, isprefix; @@ -364,7 +363,6 @@ server_client_handle_key(struct client *c, int key) w = c->session->curw->window; wp = w->active; - oo = &c->session->options; /* Special case: number keys jump to pane in identify mode. */ if (c->flags & CLIENT_IDENTIFY && key >= '0' && key <= '9') { diff --git a/tty.c b/tty.c index 6e895f5c..ca65bdb3 100644 --- a/tty.c +++ b/tty.c @@ -668,7 +668,6 @@ tty_write( struct window_pane *wp = ctx->wp; struct client *c; struct session *s; - struct options *oo; u_int i; /* wp can be NULL if updating the screen but not the terminal. */ @@ -693,7 +692,6 @@ tty_write( continue; if (c->tty.flags & TTY_FREEZE) continue; - oo = &s->options; ctx->xoff = wp->xoff; ctx->yoff = wp->yoff; From 39abca401af428b62bdaa0539dcdb6df6bfc2afd Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 25 Jun 2012 13:49:16 +0000 Subject: [PATCH 1140/1180] Trim a blank line. --- cmd-find-window.c | 1 - 1 file changed, 1 deletion(-) diff --git a/cmd-find-window.c b/cmd-find-window.c index 2d6c942f..1877f8fd 100644 --- a/cmd-find-window.c +++ b/cmd-find-window.c @@ -43,7 +43,6 @@ void cmd_find_window_free(void *); CMD_FIND_WINDOW_BY_CONTENT | \ CMD_FIND_WINDOW_BY_NAME) - const struct cmd_entry cmd_find_window_entry = { "find-window", "findw", "F:CNt:T", 1, 4, From 5b6f78186c63a19e213eb8597efe69277556e038 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 25 Jun 2012 14:08:55 +0000 Subject: [PATCH 1141/1180] Clean up and simplify the choose mode code, from Thomas Adam. --- cmd-choose-buffer.c | 90 ++++++++++++----------------------- cmd-choose-client.c | 88 ++++++++++++---------------------- cmd-choose-session.c | 91 ++++++++++++----------------------- cmd-choose-window.c | 101 +++++++++++++-------------------------- cmd-find-window.c | 59 +++++++++++------------ tmux.h | 26 ++++++++-- window-choose.c | 110 +++++++++++++++++++++++++++++-------------- 7 files changed, 249 insertions(+), 316 deletions(-) diff --git a/cmd-choose-buffer.c b/cmd-choose-buffer.c index 9045d9eb..edef4d46 100644 --- a/cmd-choose-buffer.c +++ b/cmd-choose-buffer.c @@ -28,8 +28,8 @@ int cmd_choose_buffer_exec(struct cmd *, struct cmd_ctx *); -void cmd_choose_buffer_callback(void *, int); -void cmd_choose_buffer_free(void *); +void cmd_choose_buffer_callback(struct window_choose_data *); +void cmd_choose_buffer_free(struct window_choose_data *); const struct cmd_entry cmd_choose_buffer_entry = { "choose-buffer", NULL, @@ -41,21 +41,14 @@ const struct cmd_entry cmd_choose_buffer_entry = { cmd_choose_buffer_exec }; -struct cmd_choose_buffer_data { - struct client *client; - char *template; -}; - int cmd_choose_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; - struct cmd_choose_buffer_data *cdata; + struct window_choose_data *cdata; struct winlink *wl; struct paste_buffer *pb; - struct format_tree *ft; u_int idx; - char *line; const char *template; if (ctx->curclient == NULL) { @@ -77,77 +70,52 @@ cmd_choose_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) idx = 0; while ((pb = paste_walk_stack(&global_buffers, &idx)) != NULL) { - ft = format_create(); - format_add(ft, "line", "%u", idx - 1); - format_paste_buffer(ft, pb); + cdata = window_choose_data_create(ctx); + if (args->argc != 0) + cdata->action = xstrdup(args->argv[0]); + else + cdata->action = xstrdup("paste-buffer -b '%%'"); - line = format_expand(ft, template); - window_choose_add(wl->window->active, idx - 1, "%s", line); + cdata->idx = idx - 1; + cdata->client->references++; - xfree(line); - format_free(ft); + cdata->ft_template = xstrdup(template); + format_add(cdata->ft, "line", "%u", idx - 1); + format_paste_buffer(cdata->ft, pb); + + window_choose_add(wl->window->active, cdata); } - cdata = xmalloc(sizeof *cdata); - if (args->argc != 0) - cdata->template = xstrdup(args->argv[0]); - else - cdata->template = xstrdup("paste-buffer -b '%%'"); - cdata->client = ctx->curclient; - cdata->client->references++; - window_choose_ready(wl->window->active, - 0, cmd_choose_buffer_callback, cmd_choose_buffer_free, cdata); + 0, cmd_choose_buffer_callback, cmd_choose_buffer_free); return (0); } void -cmd_choose_buffer_callback(void *data, int idx) +cmd_choose_buffer_callback(struct window_choose_data *cdata) { - struct cmd_choose_buffer_data *cdata = data; - struct cmd_list *cmdlist; - struct cmd_ctx ctx; - char *template, *cause, tmp[16]; - - if (idx == -1) + if (cdata == NULL) return; if (cdata->client->flags & CLIENT_DEAD) return; - xsnprintf(tmp, sizeof tmp, "%u", idx); - template = cmd_template_replace(cdata->template, tmp, 1); - - if (cmd_string_parse(template, &cmdlist, &cause) != 0) { - if (cause != NULL) { - *cause = toupper((u_char) *cause); - status_message_set(cdata->client, "%s", cause); - xfree(cause); - } - xfree(template); - return; - } - xfree(template); - - ctx.msgdata = NULL; - ctx.curclient = cdata->client; - - ctx.error = key_bindings_error; - ctx.print = key_bindings_print; - ctx.info = key_bindings_info; - - ctx.cmdclient = NULL; - - cmd_list_exec(cmdlist, &ctx); - cmd_list_free(cmdlist); + xasprintf(&cdata->raw_format, "%u", cdata->idx); + window_choose_ctx(cdata); } void -cmd_choose_buffer_free(void *data) +cmd_choose_buffer_free(struct window_choose_data *data) { - struct cmd_choose_buffer_data *cdata = data; + struct window_choose_data *cdata = data; + + if (cdata == NULL) + return; cdata->client->references--; - xfree(cdata->template); + + xfree(cdata->ft_template); + xfree(cdata->action); + xfree(cdata->raw_format); xfree(cdata); } diff --git a/cmd-choose-client.c b/cmd-choose-client.c index ba7508d7..d12fc241 100644 --- a/cmd-choose-client.c +++ b/cmd-choose-client.c @@ -28,8 +28,8 @@ int cmd_choose_client_exec(struct cmd *, struct cmd_ctx *); -void cmd_choose_client_callback(void *, int); -void cmd_choose_client_free(void *); +void cmd_choose_client_callback(struct window_choose_data *); +void cmd_choose_client_free(struct window_choose_data *); const struct cmd_entry cmd_choose_client_entry = { "choose-client", NULL, @@ -50,11 +50,9 @@ int cmd_choose_client_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; - struct cmd_choose_client_data *cdata; - struct format_tree *ft; + struct window_choose_data *cdata; struct winlink *wl; struct client *c; - char *line; const char *template; u_int i, idx, cur; @@ -81,83 +79,59 @@ cmd_choose_client_exec(struct cmd *self, struct cmd_ctx *ctx) cur = idx; idx++; - ft = format_create(); - format_add(ft, "line", "%u", i); - format_session(ft, c->session); - format_client(ft, c); + cdata = window_choose_data_create(ctx); + if (args->argc != 0) + cdata->action = xstrdup(args->argv[0]); + else + cdata->action = xstrdup("detach-client -t '%%'"); - line = format_expand(ft, template); - window_choose_add(wl->window->active, i, "%s", line); - xfree(line); + cdata->idx = i; + cdata->client->references++; - format_free(ft); + cdata->ft_template = xstrdup(template); + format_add(cdata->ft, "line", "%u", i); + format_session(cdata->ft, c->session); + format_client(cdata->ft, c); + + window_choose_add(wl->window->active, cdata); } - cdata = xmalloc(sizeof *cdata); - if (args->argc != 0) - cdata->template = xstrdup(args->argv[0]); - else - cdata->template = xstrdup("detach-client -t '%%'"); - cdata->client = ctx->curclient; - cdata->client->references++; - window_choose_ready(wl->window->active, - cur, cmd_choose_client_callback, cmd_choose_client_free, cdata); + cur, cmd_choose_client_callback, cmd_choose_client_free); return (0); } void -cmd_choose_client_callback(void *data, int idx) +cmd_choose_client_callback(struct window_choose_data *cdata) { - struct cmd_choose_client_data *cdata = data; - struct client *c; - struct cmd_list *cmdlist; - struct cmd_ctx ctx; - char *template, *cause; + struct client *c; - if (idx == -1) + if (cdata == NULL) return; if (cdata->client->flags & CLIENT_DEAD) return; - if ((u_int) idx > ARRAY_LENGTH(&clients) - 1) + if (cdata->idx > ARRAY_LENGTH(&clients) - 1) return; - c = ARRAY_ITEM(&clients, idx); + c = ARRAY_ITEM(&clients, cdata->idx); if (c == NULL || c->session == NULL) return; - template = cmd_template_replace(cdata->template, c->tty.path, 1); - if (cmd_string_parse(template, &cmdlist, &cause) != 0) { - if (cause != NULL) { - *cause = toupper((u_char) *cause); - status_message_set(c, "%s", cause); - xfree(cause); - } - xfree(template); - return; - } - xfree(template); - - ctx.msgdata = NULL; - ctx.curclient = cdata->client; - - ctx.error = key_bindings_error; - ctx.print = key_bindings_print; - ctx.info = key_bindings_info; - - ctx.cmdclient = NULL; - - cmd_list_exec(cmdlist, &ctx); - cmd_list_free(cmdlist); + xasprintf(&cdata->raw_format, "%s", c->tty.path); + window_choose_ctx(cdata); } void -cmd_choose_client_free(void *data) +cmd_choose_client_free(struct window_choose_data *cdata) { - struct cmd_choose_client_data *cdata = data; + if (cdata == NULL) + return; cdata->client->references--; - xfree(cdata->template); + + xfree(cdata->ft_template); + xfree(cdata->action); + format_free(cdata->ft); xfree(cdata); } diff --git a/cmd-choose-session.c b/cmd-choose-session.c index ad13b151..b26d9d8f 100644 --- a/cmd-choose-session.c +++ b/cmd-choose-session.c @@ -28,8 +28,8 @@ int cmd_choose_session_exec(struct cmd *, struct cmd_ctx *); -void cmd_choose_session_callback(void *, int); -void cmd_choose_session_free(void *); +void cmd_choose_session_callback(struct window_choose_data *); +void cmd_choose_session_free(struct window_choose_data *); const struct cmd_entry cmd_choose_session_entry = { "choose-session", NULL, @@ -41,21 +41,14 @@ const struct cmd_entry cmd_choose_session_entry = { cmd_choose_session_exec }; -struct cmd_choose_session_data { - struct client *client; - char *template; -}; - int cmd_choose_session_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; - struct cmd_choose_session_data *cdata; + struct window_choose_data *cdata; struct winlink *wl; struct session *s; - struct format_tree *ft; const char *template; - char *line; u_int idx, cur; if (ctx->curclient == NULL) { @@ -78,80 +71,58 @@ cmd_choose_session_exec(struct cmd *self, struct cmd_ctx *ctx) cur = idx; idx++; - ft = format_create(); - format_add(ft, "line", "%u", idx); - format_session(ft, s); + cdata = window_choose_data_create(ctx); + if (args->argc != 0) + cdata->action = xstrdup(args->argv[0]); + else + cdata->action = xstrdup("switch-client -t '%%'"); + cdata->idx = s->idx; - line = format_expand(ft, template); - window_choose_add(wl->window->active, s->idx, "%s", line); - xfree(line); + cdata->client->references++; + cdata->session->references++; - format_free(ft); + cdata->ft_template = xstrdup(template); + format_add(cdata->ft, "line", "%u", idx); + format_session(cdata->ft, s); + + window_choose_add(wl->window->active, cdata); } - cdata = xmalloc(sizeof *cdata); - if (args->argc != 0) - cdata->template = xstrdup(args->argv[0]); - else - cdata->template = xstrdup("switch-client -t '%%'"); - cdata->client = ctx->curclient; - cdata->client->references++; - window_choose_ready(wl->window->active, - cur, cmd_choose_session_callback, cmd_choose_session_free, cdata); + cur, cmd_choose_session_callback, cmd_choose_session_free); return (0); } void -cmd_choose_session_callback(void *data, int idx) +cmd_choose_session_callback(struct window_choose_data *cdata) { - struct cmd_choose_session_data *cdata = data; - struct session *s; - struct cmd_list *cmdlist; - struct cmd_ctx ctx; - char *template, *cause; + struct session *s; - if (idx == -1) + if (cdata == NULL) return; if (cdata->client->flags & CLIENT_DEAD) return; - s = session_find_by_index(idx); + s = session_find_by_index(cdata->idx); if (s == NULL) return; - template = cmd_template_replace(cdata->template, s->name, 1); - if (cmd_string_parse(template, &cmdlist, &cause) != 0) { - if (cause != NULL) { - *cause = toupper((u_char) *cause); - status_message_set(cdata->client, "%s", cause); - xfree(cause); - } - xfree(template); - return; - } - xfree(template); - - ctx.msgdata = NULL; - ctx.curclient = cdata->client; - - ctx.error = key_bindings_error; - ctx.print = key_bindings_print; - ctx.info = key_bindings_info; - - ctx.cmdclient = NULL; - - cmd_list_exec(cmdlist, &ctx); - cmd_list_free(cmdlist); + cdata->raw_format = xstrdup(s->name); + window_choose_ctx(cdata); } void -cmd_choose_session_free(void *data) +cmd_choose_session_free(struct window_choose_data *cdata) { - struct cmd_choose_session_data *cdata = data; + if (cdata == NULL) + return; cdata->client->references--; - xfree(cdata->template); + cdata->session->references--; + + xfree(cdata->ft_template); + xfree(cdata->action); + format_free(cdata->ft); xfree(cdata); } diff --git a/cmd-choose-window.c b/cmd-choose-window.c index fffdfbb4..4ccb7c02 100644 --- a/cmd-choose-window.c +++ b/cmd-choose-window.c @@ -28,8 +28,8 @@ int cmd_choose_window_exec(struct cmd *, struct cmd_ctx *); -void cmd_choose_window_callback(void *, int); -void cmd_choose_window_free(void *); +void cmd_choose_window_callback(struct window_choose_data *); +void cmd_choose_window_free(struct window_choose_data *); const struct cmd_entry cmd_choose_window_entry = { "choose-window", NULL, @@ -41,22 +41,14 @@ const struct cmd_entry cmd_choose_window_entry = { cmd_choose_window_exec }; -struct cmd_choose_window_data { - struct client *client; - struct session *session; - char *template; -}; - int cmd_choose_window_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; - struct cmd_choose_window_data *cdata; + struct window_choose_data *cdata; struct session *s; struct winlink *wl, *wm; - struct format_tree *ft; const char *template; - char *line; u_int idx, cur; if (ctx->curclient == NULL) { @@ -80,86 +72,59 @@ cmd_choose_window_exec(struct cmd *self, struct cmd_ctx *ctx) cur = idx; idx++; - ft = format_create(); - format_add(ft, "line", "%u", idx); - format_session(ft, s); - format_winlink(ft, s, wm); - format_window_pane(ft, wm->window->active); + cdata = window_choose_data_create(ctx); + if (args->argc != 0) + cdata->action = xstrdup(args->argv[0]); + else + cdata->action = xstrdup("select-window -t '%%'"); - line = format_expand(ft, template); - window_choose_add(wl->window->active, wm->idx, "%s", line); + cdata->idx = wm->idx; + cdata->client->references++; + cdata->session->references++; - xfree(line); - format_free(ft); + cdata->ft_template = xstrdup(template); + format_add(cdata->ft, "line", "%u", idx); + format_session(cdata->ft, s); + format_winlink(cdata->ft, s, wm); + format_window_pane(cdata->ft, wm->window->active); + + window_choose_add(wl->window->active, cdata); } - - cdata = xmalloc(sizeof *cdata); - if (args->argc != 0) - cdata->template = xstrdup(args->argv[0]); - else - cdata->template = xstrdup("select-window -t '%%'"); - cdata->session = s; - cdata->session->references++; - cdata->client = ctx->curclient; - cdata->client->references++; - window_choose_ready(wl->window->active, - cur, cmd_choose_window_callback, cmd_choose_window_free, cdata); + cur, cmd_choose_window_callback, cmd_choose_window_free); return (0); } void -cmd_choose_window_callback(void *data, int idx) +cmd_choose_window_callback(struct window_choose_data *cdata) { - struct cmd_choose_window_data *cdata = data; - struct session *s = cdata->session; - struct cmd_list *cmdlist; - struct cmd_ctx ctx; - char *target, *template, *cause; + struct session *s; - if (idx == -1) - return; - if (!session_alive(s)) + if (cdata == NULL) return; if (cdata->client->flags & CLIENT_DEAD) return; - xasprintf(&target, "%s:%d", s->name, idx); - template = cmd_template_replace(cdata->template, target, 1); - xfree(target); - - if (cmd_string_parse(template, &cmdlist, &cause) != 0) { - if (cause != NULL) { - *cause = toupper((u_char) *cause); - status_message_set(cdata->client, "%s", cause); - xfree(cause); - } - xfree(template); + s = cdata->session; + if (!session_alive(s)) return; - } - xfree(template); - ctx.msgdata = NULL; - ctx.curclient = cdata->client; - - ctx.error = key_bindings_error; - ctx.print = key_bindings_print; - ctx.info = key_bindings_info; - - ctx.cmdclient = NULL; - - cmd_list_exec(cmdlist, &ctx); - cmd_list_free(cmdlist); + xasprintf(&cdata->raw_format, "%s:%u", s->name, cdata->idx); + window_choose_ctx(cdata); } void -cmd_choose_window_free(void *data) +cmd_choose_window_free(struct window_choose_data *cdata) { - struct cmd_choose_window_data *cdata = data; + if (cdata == NULL) + return; cdata->session->references--; cdata->client->references--; - xfree(cdata->template); + + xfree(cdata->ft_template); + xfree(cdata->action); + format_free(cdata->ft); xfree(cdata); } diff --git a/cmd-find-window.c b/cmd-find-window.c index 1877f8fd..9bd535f4 100644 --- a/cmd-find-window.c +++ b/cmd-find-window.c @@ -30,8 +30,8 @@ int cmd_find_window_exec(struct cmd *, struct cmd_ctx *); u_int cmd_find_window_match_flags(struct args *); -void cmd_find_window_callback(void *, int); -void cmd_find_window_free(void *); +void cmd_find_window_callback(struct window_choose_data *); +void cmd_find_window_free(struct window_choose_data *); /* Flags for determining matching behavior. */ #define CMD_FIND_WINDOW_BY_TITLE 0x1 @@ -53,10 +53,6 @@ const struct cmd_entry cmd_find_window_entry = { cmd_find_window_exec }; -struct cmd_find_window_data { - struct session *session; -}; - u_int cmd_find_window_match_flags(struct args *args) { @@ -81,15 +77,13 @@ int cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; - struct cmd_find_window_data *cdata; + struct window_choose_data *cdata; struct session *s; struct winlink *wl, *wm; struct window_pane *wp; - struct format_tree *ft; ARRAY_DECL(, u_int) list_idx; ARRAY_DECL(, char *) list_ctx; char *str, *sres, *sctx, *searchstr; - char *find_line; const char *template; u_int i, line, match_flags; @@ -172,29 +166,25 @@ cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx) wm = winlink_find_by_index( &s->windows, ARRAY_ITEM(&list_idx, i)); - ft = format_create(); - format_add(ft, "line", "%u", i); - format_add(ft, "window_find_matches", "%s", + cdata = window_choose_data_create(ctx); + cdata->idx = wm->idx; + cdata->client->references++; + + cdata->ft_template = xstrdup(template); + format_add(cdata->ft, "line", "%u", i); + format_add(cdata->ft, "window_find_matches", "%s", ARRAY_ITEM(&list_ctx, i)); - format_session(ft, s); - format_winlink(ft, s, wm); + format_session(cdata->ft, s); + format_winlink(cdata->ft, s, wm); - find_line = format_expand(ft, template); - - window_choose_add(wl->window->active, wm->idx, "%s", find_line); - - xfree(find_line); - format_free(ft); + window_choose_add(wl->window->active, cdata); } - cdata = xmalloc(sizeof *cdata); - cdata->session = s; - cdata->session->references++; - window_choose_ready(wl->window->active, - 0, cmd_find_window_callback, cmd_find_window_free, cdata); + 0, cmd_find_window_callback, cmd_find_window_free); out: + ARRAY_FREE(&list_idx); ARRAY_FREE(&list_ctx); @@ -202,27 +192,32 @@ out: } void -cmd_find_window_callback(void *data, int idx) +cmd_find_window_callback(struct window_choose_data *cdata) { - struct cmd_find_window_data *cdata = data; - struct session *s = cdata->session; + struct session *s; - if (idx == -1) + if (cdata == NULL) return; + + s = cdata->session; if (!session_alive(s)) return; - if (session_select(s, idx) == 0) { + if (session_select(s, cdata->idx) == 0) { server_redraw_session(s); recalculate_sizes(); } } void -cmd_find_window_free(void *data) +cmd_find_window_free(struct window_choose_data *cdata) { - struct cmd_find_window_data *cdata = data; + if (cdata == NULL) + return; cdata->session->references--; + + xfree(cdata->ft_template); + format_free(cdata->ft); xfree(cdata); } diff --git a/tmux.h b/tmux.h index 891b8e3c..a27b56ad 100644 --- a/tmux.h +++ b/tmux.h @@ -846,6 +846,22 @@ struct window_mode { void (*timer)(struct window_pane *); }; +/* Structures for choose mode. */ +struct window_choose_data { + struct client *client; + struct session *session; + struct format_tree *ft; + char *ft_template; + char *raw_format; + char *action; + u_int idx; +}; + +struct window_choose_mode_item { + struct window_choose_data *wcd; + char *name; +}; + /* Child window structure. */ struct window_pane { u_int id; @@ -2121,10 +2137,14 @@ void window_copy_pageup(struct window_pane *); extern const struct window_mode window_choose_mode; void window_choose_vadd( struct window_pane *, int, const char *, va_list); -void printflike3 window_choose_add( - struct window_pane *, int, const char *, ...); +void window_choose_add(struct window_pane *, + struct window_choose_data *); void window_choose_ready(struct window_pane *, - u_int, void (*)(void *, int), void (*)(void *), void *); + u_int, void (*)(struct window_choose_data *), + void (*)(struct window_choose_data *)); +struct window_choose_data *window_choose_data_create( + struct cmd_ctx *); +void window_choose_ctx(struct window_choose_data *); /* names.c */ void queue_window_name(struct window *); diff --git a/window-choose.c b/window-choose.c index 70eb651f..a21db699 100644 --- a/window-choose.c +++ b/window-choose.c @@ -18,6 +18,7 @@ #include +#include #include #include "tmux.h" @@ -29,7 +30,8 @@ void window_choose_key(struct window_pane *, struct session *, int); void window_choose_mouse( struct window_pane *, struct session *, struct mouse_event *); -void window_choose_fire_callback(struct window_pane *, int); +void window_choose_fire_callback( + struct window_pane *, struct window_choose_data *); void window_choose_redraw_screen(struct window_pane *); void window_choose_write_line( struct window_pane *, struct screen_write_ctx *, u_int); @@ -46,11 +48,6 @@ const struct window_mode window_choose_mode = { NULL, }; -struct window_choose_mode_item { - char *name; - int idx; -}; - struct window_choose_mode_data { struct screen screen; @@ -60,39 +57,30 @@ struct window_choose_mode_data { u_int top; u_int selected; - void (*callbackfn)(void *, int); - void (*freefn)(void *); - void *data; + void (*callbackfn)(struct window_choose_data *); + void (*freefn)(struct window_choose_data *); }; int window_choose_key_index(struct window_choose_mode_data *, u_int); int window_choose_index_key(struct window_choose_mode_data *, int); void -window_choose_vadd(struct window_pane *wp, int idx, const char *fmt, va_list ap) +window_choose_add(struct window_pane *wp, struct window_choose_data *wcd) { struct window_choose_mode_data *data = wp->modedata; struct window_choose_mode_item *item; ARRAY_EXPAND(&data->list, 1); item = &ARRAY_LAST(&data->list); - xvasprintf(&item->name, fmt, ap); - item->idx = idx; -} -void printflike3 -window_choose_add(struct window_pane *wp, int idx, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - window_choose_vadd(wp, idx, fmt, ap); - va_end(ap); + item->name = format_expand(wcd->ft, wcd->ft_template); + item->wcd = wcd; } void window_choose_ready(struct window_pane *wp, u_int cur, - void (*callbackfn)(void *, int), void (*freefn)(void *), void *cdata) + void (*callbackfn)(struct window_choose_data *), + void (*freefn)(struct window_choose_data *)) { struct window_choose_mode_data *data = wp->modedata; struct screen *s = &data->screen; @@ -103,7 +91,6 @@ window_choose_ready(struct window_pane *wp, u_int cur, data->callbackfn = callbackfn; data->freefn = freefn; - data->data = cdata; window_choose_redraw_screen(wp); } @@ -119,7 +106,6 @@ window_choose_init(struct window_pane *wp) data->callbackfn = NULL; data->freefn = NULL; - data->data = NULL; ARRAY_INIT(&data->list); data->top = 0; @@ -139,17 +125,36 @@ window_choose_init(struct window_pane *wp) return (s); } +struct window_choose_data * +window_choose_data_create(struct cmd_ctx *ctx) +{ + struct window_choose_data *wcd; + + wcd = xmalloc(sizeof *wcd); + wcd->ft = format_create(); + wcd->ft_template = NULL; + wcd->action = NULL; + wcd->raw_format = NULL; + wcd->client = ctx->curclient; + wcd->session = ctx->curclient->session; + wcd->idx = -1; + + return (wcd); +} + void window_choose_free(struct window_pane *wp) { struct window_choose_mode_data *data = wp->modedata; + struct window_choose_mode_item *item; u_int i; - if (data->freefn != NULL && data->data != NULL) - data->freefn(data->data); - - for (i = 0; i < ARRAY_LENGTH(&data->list); i++) - xfree(ARRAY_ITEM(&data->list, i).name); + for (i = 0; i < ARRAY_LENGTH(&data->list); i++) { + item = &ARRAY_ITEM(&data->list, i); + if (data->freefn != NULL && item->wcd != NULL) + data->freefn(item->wcd); + xfree(item->name); + } ARRAY_FREE(&data->list); screen_free(&data->screen); @@ -171,7 +176,8 @@ window_choose_resize(struct window_pane *wp, u_int sx, u_int sy) } void -window_choose_fire_callback(struct window_pane *wp, int idx) +window_choose_fire_callback( + struct window_pane *wp, struct window_choose_data *wcd) { struct window_choose_mode_data *data = wp->modedata; const struct window_mode *oldmode; @@ -179,7 +185,7 @@ window_choose_fire_callback(struct window_pane *wp, int idx) oldmode = wp->mode; wp->mode = NULL; - data->callbackfn(data->data, idx); + data->callbackfn(wcd); wp->mode = oldmode; } @@ -199,12 +205,12 @@ window_choose_key(struct window_pane *wp, unused struct session *sess, int key) switch (mode_key_lookup(&data->mdata, key)) { case MODEKEYCHOICE_CANCEL: - window_choose_fire_callback(wp, -1); + window_choose_fire_callback(wp, NULL); window_pane_reset_mode(wp); break; case MODEKEYCHOICE_CHOOSE: item = &ARRAY_ITEM(&data->list, data->selected); - window_choose_fire_callback(wp, item->idx); + window_choose_fire_callback(wp, item->wcd); window_pane_reset_mode(wp); break; case MODEKEYCHOICE_UP: @@ -310,7 +316,7 @@ window_choose_key(struct window_pane *wp, unused struct session *sess, int key) data->selected = idx; item = &ARRAY_ITEM(&data->list, data->selected); - window_choose_fire_callback(wp, item->idx); + window_choose_fire_callback(wp, item->wcd); window_pane_reset_mode(wp); break; } @@ -339,7 +345,7 @@ window_choose_mouse( data->selected = idx; item = &ARRAY_ITEM(&data->list, data->selected); - window_choose_fire_callback(wp, item->idx); + window_choose_fire_callback(wp, item->wcd); window_pane_reset_mode(wp); } @@ -470,3 +476,37 @@ window_choose_scroll_down(struct window_pane *wp) window_choose_write_line(wp, &ctx, screen_size_y(s) - 2); screen_write_stop(&ctx); } + +void +window_choose_ctx(struct window_choose_data *cdata) +{ + struct cmd_ctx ctx; + struct cmd_list *cmdlist; + char *template, *cause; + + template = cmd_template_replace(cdata->action, + cdata->raw_format, 1); + + if (cmd_string_parse(template, &cmdlist, &cause) != 0) { + if (cause != NULL) { + *cause = toupper((u_char) *cause); + status_message_set(cdata->client, "%s", cause); + xfree(cause); + } + xfree(template); + return; + } + xfree(template); + + ctx.msgdata = NULL; + ctx.curclient = cdata->client; + + ctx.error = key_bindings_error; + ctx.print = key_bindings_print; + ctx.info = key_bindings_info; + + ctx.cmdclient = NULL; + + cmd_list_exec(cmdlist, &ctx); + cmd_list_free(cmdlist); +} From 67b926cf3c77737e3b40c9d70c38314ac19ba105 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 25 Jun 2012 14:27:25 +0000 Subject: [PATCH 1142/1180] Provide common helper function for adding windows and sessions to choose lists and expand %% in command before using it rather than at callback time. From Thomas Adam. --- cmd-choose-buffer.c | 22 +++++++++------ cmd-choose-client.c | 17 +++++++----- cmd-choose-session.c | 34 +++++++---------------- cmd-choose-window.c | 31 ++++++++------------- tmux.h | 14 ++++++---- window-choose.c | 66 ++++++++++++++++++++++++++++++++++++++------ 6 files changed, 110 insertions(+), 74 deletions(-) diff --git a/cmd-choose-buffer.c b/cmd-choose-buffer.c index edef4d46..0baa0a28 100644 --- a/cmd-choose-buffer.c +++ b/cmd-choose-buffer.c @@ -48,8 +48,9 @@ cmd_choose_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) struct window_choose_data *cdata; struct winlink *wl; struct paste_buffer *pb; - u_int idx; + char *action, *action_data; const char *template; + u_int idx; if (ctx->curclient == NULL) { ctx->error(ctx, "must be run interactively"); @@ -68,14 +69,14 @@ cmd_choose_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0) return (0); + if (args->argc != 0) + action = xstrdup(args->argv[0]); + else + action = xstrdup("paste-buffer -b '%%'"); + idx = 0; while ((pb = paste_walk_stack(&global_buffers, &idx)) != NULL) { cdata = window_choose_data_create(ctx); - if (args->argc != 0) - cdata->action = xstrdup(args->argv[0]); - else - cdata->action = xstrdup("paste-buffer -b '%%'"); - cdata->idx = idx - 1; cdata->client->references++; @@ -83,8 +84,13 @@ cmd_choose_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) format_add(cdata->ft, "line", "%u", idx - 1); format_paste_buffer(cdata->ft, pb); + xasprintf(&action_data, "%u", idx - 1); + cdata->command = cmd_template_replace(action, action_data, 1); + xfree(action_data); + window_choose_add(wl->window->active, cdata); } + xfree(action); window_choose_ready(wl->window->active, 0, cmd_choose_buffer_callback, cmd_choose_buffer_free); @@ -100,7 +106,6 @@ cmd_choose_buffer_callback(struct window_choose_data *cdata) if (cdata->client->flags & CLIENT_DEAD) return; - xasprintf(&cdata->raw_format, "%u", cdata->idx); window_choose_ctx(cdata); } @@ -114,8 +119,7 @@ cmd_choose_buffer_free(struct window_choose_data *data) cdata->client->references--; + xfree(cdata->command); xfree(cdata->ft_template); - xfree(cdata->action); - xfree(cdata->raw_format); xfree(cdata); } diff --git a/cmd-choose-client.c b/cmd-choose-client.c index d12fc241..fd6b2128 100644 --- a/cmd-choose-client.c +++ b/cmd-choose-client.c @@ -54,6 +54,7 @@ cmd_choose_client_exec(struct cmd *self, struct cmd_ctx *ctx) struct winlink *wl; struct client *c; const char *template; + char *action; u_int i, idx, cur; if (ctx->curclient == NULL) { @@ -70,6 +71,11 @@ cmd_choose_client_exec(struct cmd *self, struct cmd_ctx *ctx) if ((template = args_get(args, 'F')) == NULL) template = DEFAULT_CLIENT_TEMPLATE; + if (args->argc != 0) + action = xstrdup(args->argv[0]); + else + action = xstrdup("detach-client -t '%%'"); + cur = idx = 0; for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); @@ -80,11 +86,6 @@ cmd_choose_client_exec(struct cmd *self, struct cmd_ctx *ctx) idx++; cdata = window_choose_data_create(ctx); - if (args->argc != 0) - cdata->action = xstrdup(args->argv[0]); - else - cdata->action = xstrdup("detach-client -t '%%'"); - cdata->idx = i; cdata->client->references++; @@ -93,8 +94,11 @@ cmd_choose_client_exec(struct cmd *self, struct cmd_ctx *ctx) format_session(cdata->ft, c->session); format_client(cdata->ft, c); + cdata->command = cmd_template_replace(action, c->tty.path, 1); + window_choose_add(wl->window->active, cdata); } + xfree(action); window_choose_ready(wl->window->active, cur, cmd_choose_client_callback, cmd_choose_client_free); @@ -118,7 +122,6 @@ cmd_choose_client_callback(struct window_choose_data *cdata) if (c == NULL || c->session == NULL) return; - xasprintf(&cdata->raw_format, "%s", c->tty.path); window_choose_ctx(cdata); } @@ -131,7 +134,7 @@ cmd_choose_client_free(struct window_choose_data *cdata) cdata->client->references--; xfree(cdata->ft_template); - xfree(cdata->action); + xfree(cdata->command); format_free(cdata->ft); xfree(cdata); } diff --git a/cmd-choose-session.c b/cmd-choose-session.c index b26d9d8f..2f30c309 100644 --- a/cmd-choose-session.c +++ b/cmd-choose-session.c @@ -45,9 +45,9 @@ int cmd_choose_session_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; - struct window_choose_data *cdata; struct winlink *wl; struct session *s; + char *action; const char *template; u_int idx, cur; @@ -65,28 +65,21 @@ cmd_choose_session_exec(struct cmd *self, struct cmd_ctx *ctx) if ((template = args_get(args, 'F')) == NULL) template = DEFAULT_SESSION_TEMPLATE; + if (args->argc != 0) + action = xstrdup(args->argv[0]); + else + action = xstrdup("switch-client -t '%%'"); + cur = idx = 0; RB_FOREACH(s, sessions, &sessions) { if (s == ctx->curclient->session) cur = idx; idx++; - cdata = window_choose_data_create(ctx); - if (args->argc != 0) - cdata->action = xstrdup(args->argv[0]); - else - cdata->action = xstrdup("switch-client -t '%%'"); - cdata->idx = s->idx; - - cdata->client->references++; - cdata->session->references++; - - cdata->ft_template = xstrdup(template); - format_add(cdata->ft, "line", "%u", idx); - format_session(cdata->ft, s); - - window_choose_add(wl->window->active, cdata); + window_choose_add_session(wl->window->active, + ctx, s, template, action, idx); } + xfree(action); window_choose_ready(wl->window->active, cur, cmd_choose_session_callback, cmd_choose_session_free); @@ -97,18 +90,11 @@ cmd_choose_session_exec(struct cmd *self, struct cmd_ctx *ctx) void cmd_choose_session_callback(struct window_choose_data *cdata) { - struct session *s; - if (cdata == NULL) return; if (cdata->client->flags & CLIENT_DEAD) return; - s = session_find_by_index(cdata->idx); - if (s == NULL) - return; - - cdata->raw_format = xstrdup(s->name); window_choose_ctx(cdata); } @@ -121,8 +107,8 @@ cmd_choose_session_free(struct window_choose_data *cdata) cdata->client->references--; cdata->session->references--; + xfree(cdata->command); xfree(cdata->ft_template); - xfree(cdata->action); format_free(cdata->ft); xfree(cdata); } diff --git a/cmd-choose-window.c b/cmd-choose-window.c index 4ccb7c02..3c8831eb 100644 --- a/cmd-choose-window.c +++ b/cmd-choose-window.c @@ -45,10 +45,10 @@ int cmd_choose_window_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; - struct window_choose_data *cdata; struct session *s; struct winlink *wl, *wm; const char *template; + char *action; u_int idx, cur; if (ctx->curclient == NULL) { @@ -66,30 +66,22 @@ cmd_choose_window_exec(struct cmd *self, struct cmd_ctx *ctx) if ((template = args_get(args, 'F')) == NULL) template = DEFAULT_WINDOW_TEMPLATE " \"#{pane_title}\""; + if (args->argc != 0) + action = xstrdup(args->argv[0]); + else + action = xstrdup("select-window -t '%%'"); + cur = idx = 0; RB_FOREACH(wm, winlinks, &s->windows) { if (wm == s->curw) cur = idx; idx++; - cdata = window_choose_data_create(ctx); - if (args->argc != 0) - cdata->action = xstrdup(args->argv[0]); - else - cdata->action = xstrdup("select-window -t '%%'"); - - cdata->idx = wm->idx; - cdata->client->references++; - cdata->session->references++; - - cdata->ft_template = xstrdup(template); - format_add(cdata->ft, "line", "%u", idx); - format_session(cdata->ft, s); - format_winlink(cdata->ft, s, wm); - format_window_pane(cdata->ft, wm->window->active); - - window_choose_add(wl->window->active, cdata); + window_choose_add_window(wl->window->active, ctx, s, wm, + template, action, idx); } + xfree(action); + window_choose_ready(wl->window->active, cur, cmd_choose_window_callback, cmd_choose_window_free); @@ -110,7 +102,6 @@ cmd_choose_window_callback(struct window_choose_data *cdata) if (!session_alive(s)) return; - xasprintf(&cdata->raw_format, "%s:%u", s->name, cdata->idx); window_choose_ctx(cdata); } @@ -124,7 +115,7 @@ cmd_choose_window_free(struct window_choose_data *cdata) cdata->client->references--; xfree(cdata->ft_template); - xfree(cdata->action); + xfree(cdata->command); format_free(cdata->ft); xfree(cdata); } diff --git a/tmux.h b/tmux.h index a27b56ad..f4e953c3 100644 --- a/tmux.h +++ b/tmux.h @@ -852,8 +852,7 @@ struct window_choose_data { struct session *session; struct format_tree *ft; char *ft_template; - char *raw_format; - char *action; + char *command; u_int idx; }; @@ -2135,16 +2134,19 @@ void window_copy_pageup(struct window_pane *); /* window-choose.c */ extern const struct window_mode window_choose_mode; -void window_choose_vadd( - struct window_pane *, int, const char *, va_list); void window_choose_add(struct window_pane *, struct window_choose_data *); void window_choose_ready(struct window_pane *, u_int, void (*)(struct window_choose_data *), void (*)(struct window_choose_data *)); -struct window_choose_data *window_choose_data_create( - struct cmd_ctx *); +struct window_choose_data *window_choose_data_create(struct cmd_ctx *); void window_choose_ctx(struct window_choose_data *); +struct window_choose_data *window_choose_add_window(struct window_pane *, + struct cmd_ctx *, struct session *, struct winlink *, + const char *, char *, u_int); +struct window_choose_data *window_choose_add_session(struct window_pane *, + struct cmd_ctx *, struct session *, const char *, + char *, u_int); /* names.c */ void queue_window_name(struct window *); diff --git a/window-choose.c b/window-choose.c index a21db699..ed951661 100644 --- a/window-choose.c +++ b/window-choose.c @@ -133,8 +133,7 @@ window_choose_data_create(struct cmd_ctx *ctx) wcd = xmalloc(sizeof *wcd); wcd->ft = format_create(); wcd->ft_template = NULL; - wcd->action = NULL; - wcd->raw_format = NULL; + wcd->command = NULL; wcd->client = ctx->curclient; wcd->session = ctx->curclient->session; wcd->idx = -1; @@ -482,21 +481,22 @@ window_choose_ctx(struct window_choose_data *cdata) { struct cmd_ctx ctx; struct cmd_list *cmdlist; - char *template, *cause; + char *cause; - template = cmd_template_replace(cdata->action, - cdata->raw_format, 1); + /* The command template will have already been replaced. But if it's + * NULL, bail here. + */ + if (cdata->command == NULL) + return; - if (cmd_string_parse(template, &cmdlist, &cause) != 0) { + if (cmd_string_parse(cdata->command, &cmdlist, &cause) != 0) { if (cause != NULL) { *cause = toupper((u_char) *cause); status_message_set(cdata->client, "%s", cause); xfree(cause); } - xfree(template); return; } - xfree(template); ctx.msgdata = NULL; ctx.curclient = cdata->client; @@ -510,3 +510,53 @@ window_choose_ctx(struct window_choose_data *cdata) cmd_list_exec(cmdlist, &ctx); cmd_list_free(cmdlist); } + +struct window_choose_data * +window_choose_add_session(struct window_pane *wp, struct cmd_ctx *ctx, + struct session *s, const char *template, char *action, u_int idx) +{ + struct window_choose_data *wcd; + + wcd = window_choose_data_create(ctx); + wcd->idx = s->idx; + wcd->command = cmd_template_replace(action, s->name, 1); + wcd->ft_template = xstrdup(template); + format_add(wcd->ft, "line", "%u", idx); + format_session(wcd->ft, s); + + wcd->client->references++; + wcd->session->references++; + + window_choose_add(wp, wcd); + + return (wcd); +} + +struct window_choose_data * +window_choose_add_window(struct window_pane *wp, struct cmd_ctx *ctx, + struct session *s, struct winlink *wl, const char *template, + char *action, u_int idx) +{ + struct window_choose_data *wcd; + char *action_data; + + wcd = window_choose_data_create(ctx); + + xasprintf(&action_data, "%s:%d", s->name, wl->idx); + wcd->command = cmd_template_replace(action, action_data, 1); + xfree(action_data); + + wcd->idx = wl->idx; + wcd->ft_template = xstrdup(template); + format_add(wcd->ft, "line", "%u", idx); + format_session(wcd->ft, s); + format_winlink(wcd->ft, s, wl); + format_window_pane(wcd->ft, wl->window->active); + + wcd->client->references++; + wcd->session->references++; + + window_choose_add(wp, wcd); + + return (wcd); +} From 63f5c38023439e23365b18581eb32f530c66a2d9 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 8 Jul 2012 07:27:32 +0000 Subject: [PATCH 1143/1180] Clear flags across all sessions, from Thomas Adam. --- server-window.c | 11 ++++++++--- session.c | 8 ++++---- tmux.h | 1 + window.c | 28 ++++++++++++++++++++++++++++ 4 files changed, 41 insertions(+), 7 deletions(-) diff --git a/server-window.c b/server-window.c index f382de99..c852acf1 100644 --- a/server-window.c +++ b/server-window.c @@ -56,9 +56,6 @@ server_window_loop(void) server_status_session(s); TAILQ_FOREACH(wp, &w->panes, entry) server_window_check_content(s, wl, wp); - - if (!(s->flags & SESSION_UNATTACHED)) - w->flags &= ~(WINDOW_BELL|WINDOW_ACTIVITY); } } } @@ -78,6 +75,8 @@ server_window_check_bell(struct session *s, struct winlink *wl) wl->flags |= WINLINK_BELL; if (s->flags & SESSION_UNATTACHED) return (1); + if (s->curw->window == wl->window) + w->flags &= ~WINDOW_BELL; visual = options_get_number(&s->options, "visual-bell"); action = options_get_number(&s->options, "bell-action"); @@ -108,6 +107,9 @@ server_window_check_activity(struct session *s, struct winlink *wl) struct window *w = wl->window; u_int i; + if (s->curw->window == wl->window) + w->flags &= ~WINDOW_ACTIVITY; + if (!(w->flags & WINDOW_ACTIVITY) || wl->flags & WINLINK_ACTIVITY) return (0); if (s->curw == wl && !(s->flags & SESSION_UNATTACHED)) @@ -196,6 +198,9 @@ server_window_check_content( char *found, *ptr; /* Activity flag must be set for new content. */ + if (s->curw->window == w) + w->flags &= ~WINDOW_ACTIVITY; + if (!(w->flags & WINDOW_ACTIVITY) || wl->flags & WINLINK_CONTENT) return (0); if (s->curw == wl && !(s->flags & SESSION_UNATTACHED)) diff --git a/session.c b/session.c index b3f03541..75ea8b0c 100644 --- a/session.c +++ b/session.c @@ -353,7 +353,7 @@ session_next(struct session *s, int alert) winlink_stack_remove(&s->lastw, wl); winlink_stack_push(&s->lastw, s->curw); s->curw = wl; - wl->flags &= ~WINLINK_ALERTFLAGS; + winlink_clear_flags(wl); return (0); } @@ -390,7 +390,7 @@ session_previous(struct session *s, int alert) winlink_stack_remove(&s->lastw, wl); winlink_stack_push(&s->lastw, s->curw); s->curw = wl; - wl->flags &= ~WINLINK_ALERTFLAGS; + winlink_clear_flags(wl); return (0); } @@ -408,7 +408,7 @@ session_select(struct session *s, int idx) winlink_stack_remove(&s->lastw, wl); winlink_stack_push(&s->lastw, s->curw); s->curw = wl; - wl->flags &= ~WINLINK_ALERTFLAGS; + winlink_clear_flags(wl); return (0); } @@ -427,7 +427,7 @@ session_last(struct session *s) winlink_stack_remove(&s->lastw, wl); winlink_stack_push(&s->lastw, s->curw); s->curw = wl; - wl->flags &= ~WINLINK_ALERTFLAGS; + winlink_clear_flags(wl); return (0); } diff --git a/tmux.h b/tmux.h index f4e953c3..e04bd2f4 100644 --- a/tmux.h +++ b/tmux.h @@ -2076,6 +2076,7 @@ struct window_pane *window_pane_find_down(struct window_pane *); struct window_pane *window_pane_find_left(struct window_pane *); struct window_pane *window_pane_find_right(struct window_pane *); void window_set_name(struct window *, const char *); +void winlink_clear_flags(struct winlink *); /* layout.c */ u_int layout_count_cells(struct layout_cell *); diff --git a/window.c b/window.c index 0d2b74bf..cf13c906 100644 --- a/window.c +++ b/window.c @@ -1164,3 +1164,31 @@ window_pane_find_right(struct window_pane *wp) } return (NULL); } + +/* Clear alert flags for a winlink */ +void +winlink_clear_flags(struct winlink *wl) +{ + struct winlink *wm; + struct session *s; + struct window *w; + u_int i; + + for (i = 0; i < ARRAY_LENGTH(&windows); i++) { + if ((w = ARRAY_ITEM(&windows, i)) == NULL) + continue; + + RB_FOREACH(s, sessions, &sessions) { + if ((wm = session_has(s, w)) == NULL) + continue; + + if (wm->window != wl->window) + continue; + if ((wm->flags & WINLINK_ALERTFLAGS) == 0) + continue; + + wm->flags &= ~WINLINK_ALERTFLAGS; + server_status_session(s); + } + } +} From 191a92c0c63d5a18d7afe19851ae7aadf3081552 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 8 Jul 2012 15:24:08 +0000 Subject: [PATCH 1144/1180] Sort SRCS list. --- Makefile | 158 +++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 123 insertions(+), 35 deletions(-) diff --git a/Makefile b/Makefile index 2b9dde1f..5e7b94c1 100644 --- a/Makefile +++ b/Makefile @@ -1,43 +1,131 @@ # $OpenBSD$ PROG= tmux -SRCS= arguments.c attributes.c cfg.c client.c clock.c \ - cmd-attach-session.c cmd-bind-key.c \ - cmd-break-pane.c cmd-choose-session.c cmd-choose-window.c \ - cmd-clear-history.c cmd-clock-mode.c cmd-command-prompt.c \ - cmd-confirm-before.c cmd-copy-mode.c \ - cmd-choose-buffer.c cmd-delete-buffer.c cmd-detach-client.c \ - cmd-find-window.c cmd-has-session.c cmd-kill-pane.c \ - cmd-kill-server.c cmd-kill-session.c cmd-kill-window.c \ - cmd-link-window.c cmd-list-buffers.c \ - cmd-list-clients.c cmd-list-commands.c cmd-list-keys.c \ - cmd-list-sessions.c cmd-list-windows.c cmd-list-panes.c \ - cmd-list.c cmd-load-buffer.c cmd-join-pane.c \ +SRCS= arguments.c \ + attributes.c \ + cfg.c \ + client.c \ + clock.c \ + cmd-attach-session.c \ + cmd-bind-key.c \ + cmd-break-pane.c \ + cmd-capture-pane.c \ + cmd-choose-buffer.c \ + cmd-choose-client.c \ + cmd-choose-session.c \ + cmd-choose-window.c \ + cmd-clear-history.c \ + cmd-clock-mode.c \ + cmd-command-prompt.c \ + cmd-confirm-before.c \ + cmd-copy-mode.c \ + cmd-delete-buffer.c \ + cmd-detach-client.c \ + cmd-display-message.c \ + cmd-display-panes.c \ + cmd-find-window.c \ + cmd-has-session.c \ + cmd-if-shell.c \ + cmd-join-pane.c \ + cmd-kill-pane.c \ + cmd-kill-server.c \ + cmd-kill-session.c \ + cmd-kill-window.c \ + cmd-link-window.c \ + cmd-list-buffers.c \ + cmd-list-clients.c \ + cmd-list-commands.c \ + cmd-list-keys.c \ + cmd-list-panes.c \ + cmd-list-sessions.c \ + cmd-list-windows.c \ + cmd-list.c \ + cmd-load-buffer.c \ cmd-lock-server.c \ - cmd-move-window.c cmd-new-session.c cmd-new-window.c \ + cmd-move-window.c \ + cmd-new-session.c \ + cmd-new-window.c \ cmd-paste-buffer.c \ - cmd-refresh-client.c cmd-respawn-pane.c \ - cmd-rename-session.c cmd-rename-window.c cmd-resize-pane.c \ - cmd-respawn-window.c cmd-rotate-window.c cmd-save-buffer.c \ - cmd-select-layout.c cmd-select-pane.c cmd-select-window.c \ - cmd-send-keys.c cmd-send-prefix.c cmd-server-info.c cmd-set-buffer.c \ - cmd-set-option.c cmd-show-buffer.c \ - cmd-show-messages.c cmd-show-options.c \ - cmd-source-file.c cmd-split-window.c cmd-start-server.c cmd-string.c \ - cmd-run-shell.c cmd-suspend-client.c cmd-swap-pane.c cmd-swap-window.c \ - cmd-switch-client.c cmd-unbind-key.c cmd-unlink-window.c \ - cmd-set-environment.c cmd-show-environment.c cmd-choose-client.c \ - cmd-display-message.c cmd-display-panes.c cmd-if-shell.c \ - cmd-pipe-pane.c cmd-capture-pane.c cmd.c \ - colour.c environ.c grid-view.c grid-utf8.c grid.c input-keys.c \ - input.c key-bindings.c key-string.c format.c control.c \ - layout-custom.c layout-set.c layout.c log.c job.c notify.c \ - mode-key.c names.c options.c options-table.c paste.c procname.c \ - resize.c screen-redraw.c screen-write.c screen.c session.c status.c \ - signal.c server-fn.c server.c server-client.c server-window.c \ - tmux.c tty-acs.c tty-keys.c tty-term.c tty.c utf8.c \ - window-choose.c window-clock.c window-copy.c window.c \ - xterm-keys.c xmalloc.c + cmd-pipe-pane.c \ + cmd-refresh-client.c \ + cmd-rename-session.c \ + cmd-rename-window.c \ + cmd-resize-pane.c \ + cmd-respawn-pane.c \ + cmd-respawn-window.c \ + cmd-rotate-window.c \ + cmd-run-shell.c \ + cmd-save-buffer.c \ + cmd-select-layout.c \ + cmd-select-pane.c \ + cmd-select-window.c \ + cmd-send-keys.c \ + cmd-send-prefix.c \ + cmd-server-info.c \ + cmd-set-buffer.c \ + cmd-set-environment.c \ + cmd-set-option.c \ + cmd-show-buffer.c \ + cmd-show-environment.c \ + cmd-show-messages.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 \ + cmd-swap-window.c \ + cmd-switch-client.c \ + cmd-unbind-key.c \ + cmd-unlink-window.c \ + cmd.c \ + colour.c \ + control.c \ + environ.c \ + format.c \ + grid-utf8.c \ + grid-view.c \ + grid.c \ + input-keys.c \ + input.c \ + job.c \ + key-bindings.c \ + key-string.c \ + layout-custom.c \ + layout-set.c \ + layout.c \ + log.c \ + mode-key.c \ + names.c \ + notify.c \ + options-table.c \ + options.c \ + paste.c \ + procname.c \ + resize.c \ + screen-redraw.c \ + screen-write.c \ + screen.c \ + server-client.c \ + server-fn.c \ + server-window.c \ + server.c \ + session.c \ + signal.c \ + status.c \ + tmux.c \ + tty-acs.c \ + tty-keys.c \ + tty-term.c \ + tty.c \ + utf8.c \ + window-choose.c \ + window-clock.c \ + window-copy.c \ + window.c \ + xmalloc.c \ + xterm-keys.c CDIAGFLAGS+= -Wno-long-long -Wall -W -Wnested-externs -Wformat=2 CDIAGFLAGS+= -Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations From f20c6fe0099a15002c6c2a7693ca9061aa6367ba Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 8 Jul 2012 16:04:38 +0000 Subject: [PATCH 1145/1180] Add choose-tree command to show windows and sessions in the same list. Change choose-window and -session to use the same code. From Thomas Adam. --- Makefile | 3 +- cmd-choose-session.c | 114 -------------------- cmd-choose-tree.c | 251 +++++++++++++++++++++++++++++++++++++++++++ cmd-choose-window.c | 121 --------------------- cmd.c | 1 + key-bindings.c | 2 +- tmux.1 | 62 +++++++++++ tmux.h | 1 + 8 files changed, 317 insertions(+), 238 deletions(-) delete mode 100644 cmd-choose-session.c create mode 100644 cmd-choose-tree.c delete mode 100644 cmd-choose-window.c diff --git a/Makefile b/Makefile index 5e7b94c1..efad64a0 100644 --- a/Makefile +++ b/Makefile @@ -12,8 +12,7 @@ SRCS= arguments.c \ cmd-capture-pane.c \ cmd-choose-buffer.c \ cmd-choose-client.c \ - cmd-choose-session.c \ - cmd-choose-window.c \ + cmd-choose-tree.c \ cmd-clear-history.c \ cmd-clock-mode.c \ cmd-command-prompt.c \ diff --git a/cmd-choose-session.c b/cmd-choose-session.c deleted file mode 100644 index 2f30c309..00000000 --- a/cmd-choose-session.c +++ /dev/null @@ -1,114 +0,0 @@ -/* $OpenBSD$ */ - -/* - * Copyright (c) 2009 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 "tmux.h" - -/* - * Enter choice mode to choose a session. - */ - -int cmd_choose_session_exec(struct cmd *, struct cmd_ctx *); - -void cmd_choose_session_callback(struct window_choose_data *); -void cmd_choose_session_free(struct window_choose_data *); - -const struct cmd_entry cmd_choose_session_entry = { - "choose-session", NULL, - "F:t:", 0, 1, - CMD_TARGET_WINDOW_USAGE " [-F format] [template]", - 0, - NULL, - NULL, - cmd_choose_session_exec -}; - -int -cmd_choose_session_exec(struct cmd *self, struct cmd_ctx *ctx) -{ - struct args *args = self->args; - struct winlink *wl; - struct session *s; - char *action; - const char *template; - u_int idx, cur; - - if (ctx->curclient == NULL) { - ctx->error(ctx, "must be run interactively"); - return (-1); - } - - if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL) - return (-1); - - if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0) - return (0); - - if ((template = args_get(args, 'F')) == NULL) - template = DEFAULT_SESSION_TEMPLATE; - - if (args->argc != 0) - action = xstrdup(args->argv[0]); - else - action = xstrdup("switch-client -t '%%'"); - - cur = idx = 0; - RB_FOREACH(s, sessions, &sessions) { - if (s == ctx->curclient->session) - cur = idx; - idx++; - - window_choose_add_session(wl->window->active, - ctx, s, template, action, idx); - } - xfree(action); - - window_choose_ready(wl->window->active, - cur, cmd_choose_session_callback, cmd_choose_session_free); - - return (0); -} - -void -cmd_choose_session_callback(struct window_choose_data *cdata) -{ - if (cdata == NULL) - return; - if (cdata->client->flags & CLIENT_DEAD) - return; - - window_choose_ctx(cdata); -} - -void -cmd_choose_session_free(struct window_choose_data *cdata) -{ - if (cdata == NULL) - return; - - cdata->client->references--; - cdata->session->references--; - - xfree(cdata->command); - xfree(cdata->ft_template); - format_free(cdata->ft); - xfree(cdata); -} diff --git a/cmd-choose-tree.c b/cmd-choose-tree.c new file mode 100644 index 00000000..385621cf --- /dev/null +++ b/cmd-choose-tree.c @@ -0,0 +1,251 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2012 Thomas Adam + * + * 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 "tmux.h" + +#define CMD_CHOOSE_TREE_WINDOW_ACTION "select-window -t '%%'" +#define CMD_CHOOSE_TREE_SESSION_ACTION "switch-client -t '%%'" +#define CMD_CHOOSE_TREE_WINDOW_TEMPLATE \ + DEFAULT_WINDOW_TEMPLATE " \"#{pane_title}\"" + +/* + * Enter choice mode to choose a session and/or window. + */ + +int cmd_choose_tree_exec(struct cmd *, struct cmd_ctx *); + +void cmd_choose_tree_callback(struct window_choose_data *); +void cmd_choose_tree_free(struct window_choose_data *); + +const struct cmd_entry cmd_choose_tree_entry = { + "choose-tree", NULL, + "S:W:swb:c:t:", 0, 1, + "[-SW] [-s format] [-w format ] [-b session template] " \ + "[-c window template] " CMD_TARGET_WINDOW_USAGE, + 0, + NULL, + NULL, + cmd_choose_tree_exec +}; + +const struct cmd_entry cmd_choose_session_entry = { + "choose-session", NULL, + "F:t:", 0, 1, + CMD_TARGET_WINDOW_USAGE " [-F format] [template]", + 0, + NULL, + NULL, + cmd_choose_tree_exec +}; + +const struct cmd_entry cmd_choose_window_entry = { + "choose-window", NULL, + "F:t:", 0, 1, + CMD_TARGET_WINDOW_USAGE "[-F format] [template]", + 0, + NULL, + NULL, + cmd_choose_tree_exec +}; + +int +cmd_choose_tree_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct args *args = self->args; + struct winlink *wl, *wm; + struct session *s, *s2; + struct tty *tty; + struct window_choose_data *wcd = NULL; + const char *ses_template, *win_template; + char *final_win_action, *final_win_template; + const char *ses_action, *win_action; + u_int cur_win, idx_ses, win_ses; + u_int wflag, sflag; + + ses_template = win_template = NULL; + ses_action = win_action = NULL; + + if (ctx->curclient == NULL) { + ctx->error(ctx, "must be run interactively"); + return (-1); + } + + s = ctx->curclient->session; + tty = &ctx->curclient->tty; + + if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL) + return (-1); + + if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0) + return (0); + + /* Sort out which command this is. */ + wflag = sflag = 0; + if (self->entry == &cmd_choose_session_entry) { + sflag = 1; + if ((ses_template = args_get(args, 'F')) == NULL) + ses_template = DEFAULT_SESSION_TEMPLATE; + + if (args->argc != 0) + ses_action = args->argv[0]; + else + ses_action = CMD_CHOOSE_TREE_SESSION_ACTION; + } else if (self->entry == &cmd_choose_window_entry) { + wflag = 1; + if ((win_template = args_get(args, 'F')) == NULL) + win_template = CMD_CHOOSE_TREE_WINDOW_TEMPLATE; + + if (args->argc != 0) + win_action = args->argv[0]; + else + win_action = CMD_CHOOSE_TREE_WINDOW_ACTION; + } else { + wflag = args_has(args, 'w'); + sflag = args_has(args, 's'); + + if ((ses_action = args_get(args, 'b')) == NULL) + ses_action = CMD_CHOOSE_TREE_SESSION_ACTION; + + if ((win_action = args_get(args, 'c')) == NULL) + win_action = CMD_CHOOSE_TREE_WINDOW_ACTION; + + if ((ses_template = args_get(args, 'S')) == NULL) + ses_template = DEFAULT_SESSION_TEMPLATE; + + if ((win_template = args_get(args, 'W')) == NULL) + win_template = CMD_CHOOSE_TREE_WINDOW_TEMPLATE; + } + + /* + * If not asking for windows and sessions, assume no "-ws" given and + * hence display the entire tree outright. + */ + if (!wflag && !sflag) + wflag = sflag = 1; + + /* + * If we're drawing in tree mode, including sessions, then pad the + * window template, otherwise just render the windows as a flat list + * without any padding. + */ + if (wflag && sflag) + xasprintf(&final_win_template, " --> %s", win_template); + else if (wflag) + final_win_template = xstrdup(win_template); + else + final_win_template = NULL; + + idx_ses = cur_win = -1; + RB_FOREACH(s2, sessions, &sessions) { + idx_ses++; + + /* + * If we're just choosing windows, jump straight there. Note + * that this implies the current session, so only choose + * windows when the session matches this one. + */ + if (wflag && !sflag) { + if (s != s2) + continue; + goto windows_only; + } + + wcd = window_choose_add_session(wl->window->active, + ctx, s2, ses_template, (char *)ses_action, idx_ses); + + /* If we're just choosing sessions, skip choosing windows. */ + if (sflag && !wflag) { + if (s == s2) + cur_win = idx_ses; + continue; + } +windows_only: + win_ses = -1; + RB_FOREACH(wm, winlinks, &s2->windows) { + win_ses++; + if (sflag && wflag) + idx_ses++; + + if (wm == s2->curw && s == s2) { + if (wflag && !sflag) { + /* + * Then we're only counting windows. + * So remember which is the current + * window in the list. + */ + cur_win = win_ses; + } else + cur_win = idx_ses; + } + + xasprintf(&final_win_action, "%s ; %s", win_action, + wcd ? wcd->command : ""); + + window_choose_add_window(wl->window->active, + ctx, s2, wm, final_win_template, + final_win_action, idx_ses); + + xfree(final_win_action); + } + /* + * If we're just drawing windows, don't consider moving on to + * other sessions as we only list windows in this session. + */ + if (wflag && !sflag) + break; + } + if (final_win_template != NULL) + xfree(final_win_template); + + window_choose_ready(wl->window->active, cur_win, + cmd_choose_tree_callback, cmd_choose_tree_free); + + return (0); +} + +void +cmd_choose_tree_callback(struct window_choose_data *cdata) +{ + if (cdata == NULL) + return; + + if (cdata->client->flags & CLIENT_DEAD) + return; + + window_choose_ctx(cdata); +} + +void +cmd_choose_tree_free(struct window_choose_data *cdata) +{ + cdata->session->references--; + cdata->client->references--; + + xfree(cdata->ft_template); + xfree(cdata->command); + format_free(cdata->ft); + xfree(cdata); + +} + diff --git a/cmd-choose-window.c b/cmd-choose-window.c deleted file mode 100644 index 3c8831eb..00000000 --- a/cmd-choose-window.c +++ /dev/null @@ -1,121 +0,0 @@ -/* $OpenBSD$ */ - -/* - * Copyright (c) 2009 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 "tmux.h" - -/* - * Enter choice mode to choose a window. - */ - -int cmd_choose_window_exec(struct cmd *, struct cmd_ctx *); - -void cmd_choose_window_callback(struct window_choose_data *); -void cmd_choose_window_free(struct window_choose_data *); - -const struct cmd_entry cmd_choose_window_entry = { - "choose-window", NULL, - "F:t:", 0, 1, - CMD_TARGET_WINDOW_USAGE " [-F format] [template]", - 0, - NULL, - NULL, - cmd_choose_window_exec -}; - -int -cmd_choose_window_exec(struct cmd *self, struct cmd_ctx *ctx) -{ - struct args *args = self->args; - struct session *s; - struct winlink *wl, *wm; - const char *template; - char *action; - u_int idx, cur; - - if (ctx->curclient == NULL) { - ctx->error(ctx, "must be run interactively"); - return (-1); - } - s = ctx->curclient->session; - - if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL) - return (-1); - - if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0) - return (0); - - if ((template = args_get(args, 'F')) == NULL) - template = DEFAULT_WINDOW_TEMPLATE " \"#{pane_title}\""; - - if (args->argc != 0) - action = xstrdup(args->argv[0]); - else - action = xstrdup("select-window -t '%%'"); - - cur = idx = 0; - RB_FOREACH(wm, winlinks, &s->windows) { - if (wm == s->curw) - cur = idx; - idx++; - - window_choose_add_window(wl->window->active, ctx, s, wm, - template, action, idx); - } - xfree(action); - - window_choose_ready(wl->window->active, - cur, cmd_choose_window_callback, cmd_choose_window_free); - - return (0); -} - -void -cmd_choose_window_callback(struct window_choose_data *cdata) -{ - struct session *s; - - if (cdata == NULL) - return; - if (cdata->client->flags & CLIENT_DEAD) - return; - - s = cdata->session; - if (!session_alive(s)) - return; - - window_choose_ctx(cdata); -} - -void -cmd_choose_window_free(struct window_choose_data *cdata) -{ - if (cdata == NULL) - return; - - cdata->session->references--; - cdata->client->references--; - - xfree(cdata->ft_template); - xfree(cdata->command); - format_free(cdata->ft); - xfree(cdata); -} diff --git a/cmd.c b/cmd.c index 16758589..5f97a854 100644 --- a/cmd.c +++ b/cmd.c @@ -36,6 +36,7 @@ const struct cmd_entry *cmd_table[] = { &cmd_choose_buffer_entry, &cmd_choose_client_entry, &cmd_choose_session_entry, + &cmd_choose_tree_entry, &cmd_choose_window_entry, &cmd_clear_history_entry, &cmd_clock_mode_entry, diff --git a/key-bindings.c b/key-bindings.c index f020c19d..8511ea7c 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -147,7 +147,7 @@ key_bindings_init(void) { 'p', 0, &cmd_previous_window_entry }, { 'q', 0, &cmd_display_panes_entry }, { 'r', 0, &cmd_refresh_client_entry }, - { 's', 0, &cmd_choose_session_entry }, + { 's', 0, &cmd_choose_tree_entry }, { 't', 0, &cmd_clock_mode_entry }, { 'u', 1, &cmd_select_layout_entry }, { 'w', 0, &cmd_choose_window_entry }, diff --git a/tmux.1 b/tmux.1 index e91046ed..96762511 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1090,6 +1090,68 @@ section. This command works only from inside .Nm . .It Xo +.Ic choose-tree +.Op Fl s +.Op Fl w +.Op Fl b Ar session-template +.Op Fl c Ar window-template +.Op Fl S Ar format +.Op Fl W Ar format +.Op Fl t Ar target-window +.Xc +Put a window into tree choice mode, where either sessions or windows may be +selected interactively from a list. +By default, windows belonging to a session are indented to show their +relationship to a session. +.Pp +Note that the +.Ic choose-window +and +.Ic choose-session +commands are wrappers around +.Ic choose-tree . +. +.Pp +If +.Fl s +is given, will show sessions. +If +.Fl w +is given, will show windows. +If +.Fl b +is given, will override the default session command. +Note that +.Ql %% +can be used, and will be replaced with the session name. +The default option if not specified is "switch-client -t '%%'". +If +.Fl c +is given, will override the default window command. +Note that +.Ql %% +can be used, and will be replaced with the session name and window index. +This command will run +.Ar session-template +before it. +If +.Fl S +is given will display the specified format instead of the default session +format. +If +.Fl W +is given will display the specified format instead of the default window +format. +For the meaning of the +.Fl s +and +.Fl w +options, see the +.Sx FORMATS +section. +This command only works from inside +.Nm . +.It Xo .Ic choose-window .Op Fl F Ar format .Op Fl t Ar target-window diff --git a/tmux.h b/tmux.h index e04bd2f4..02237f8a 100644 --- a/tmux.h +++ b/tmux.h @@ -1664,6 +1664,7 @@ extern const struct cmd_entry cmd_capture_pane_entry; extern const struct cmd_entry cmd_choose_buffer_entry; extern const struct cmd_entry cmd_choose_client_entry; extern const struct cmd_entry cmd_choose_session_entry; +extern const struct cmd_entry cmd_choose_tree_entry; extern const struct cmd_entry cmd_choose_window_entry; extern const struct cmd_entry cmd_clear_history_entry; extern const struct cmd_entry cmd_clock_mode_entry; From b0f4f94b5b61b106c33a6fc1f2bcbbbfcf076b94 Mon Sep 17 00:00:00 2001 From: Jason McIntyre Date: Sun, 8 Jul 2012 17:24:29 +0000 Subject: [PATCH 1146/1180] remove extraneous line; --- tmux.1 | 1 - 1 file changed, 1 deletion(-) diff --git a/tmux.1 b/tmux.1 index 96762511..a88dcb36 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1110,7 +1110,6 @@ and .Ic choose-session commands are wrappers around .Ic choose-tree . -. .Pp If .Fl s From 91f54b59acc8b21dd5c42d5fd95bebc256dc1e1b Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 9 Jul 2012 07:08:03 +0000 Subject: [PATCH 1147/1180] Fix choose-tree usage string. --- cmd-choose-tree.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd-choose-tree.c b/cmd-choose-tree.c index 385621cf..c29b2eab 100644 --- a/cmd-choose-tree.c +++ b/cmd-choose-tree.c @@ -41,8 +41,8 @@ void cmd_choose_tree_free(struct window_choose_data *); const struct cmd_entry cmd_choose_tree_entry = { "choose-tree", NULL, "S:W:swb:c:t:", 0, 1, - "[-SW] [-s format] [-w format ] [-b session template] " \ - "[-c window template] " CMD_TARGET_WINDOW_USAGE, + "[-sw] [-b session-template] [-c window template] [-S format] " \ + "[-W format] " CMD_TARGET_WINDOW_USAGE, 0, NULL, NULL, From a3391692ad5800ca034bbbdcd803924fc4e392ee Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 9 Jul 2012 09:55:57 +0000 Subject: [PATCH 1148/1180] Move a NULL check inside a function, from Tiago Cunha. --- status.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/status.c b/status.c index b90d1885..a1c23286 100644 --- a/status.c +++ b/status.c @@ -515,6 +515,9 @@ status_replace(struct client *c, struct session *s, struct winlink *wl, char in[BUFSIZ], ch, *iptr, *optr; size_t len; + if (fmt == NULL) + return (xstrdup("")); + len = strftime(in, sizeof in, fmt, localtime(&t)); in[len] = '\0'; @@ -877,8 +880,6 @@ status_prompt_set(struct client *c, const char *msg, const char *input, c->prompt_string = status_replace(c, NULL, NULL, NULL, msg, time(NULL), 0); - if (input == NULL) - input = ""; c->prompt_buffer = status_replace(c, NULL, NULL, NULL, input, time(NULL), 0); c->prompt_index = strlen(c->prompt_buffer); @@ -932,8 +933,6 @@ status_prompt_update(struct client *c, const char *msg, const char *input) time(NULL), 0); xfree(c->prompt_buffer); - if (input == NULL) - input = ""; c->prompt_buffer = status_replace(c, NULL, NULL, NULL, input, time(NULL), 0); c->prompt_index = strlen(c->prompt_buffer); From df912e3540968a2a0b266e523ecc08bb2dc0ca20 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 10 Jul 2012 11:53:01 +0000 Subject: [PATCH 1149/1180] xfree is not particularly helpful, remove it. From Thomas Adam. --- arguments.c | 20 ++++++++----------- array.h | 5 ++--- cfg.c | 11 ++++++----- client.c | 2 +- cmd-attach-session.c | 4 +++- cmd-bind-key.c | 3 ++- cmd-break-pane.c | 4 ++-- cmd-capture-pane.c | 12 ++++++------ cmd-choose-buffer.c | 11 ++++++----- cmd-choose-client.c | 9 +++++---- cmd-choose-tree.c | 12 ++++++------ cmd-command-prompt.c | 20 +++++++++---------- cmd-confirm-before.c | 12 ++++++------ cmd-delete-buffer.c | 2 +- cmd-display-message.c | 3 ++- cmd-find-window.c | 9 +++++---- cmd-if-shell.c | 10 +++++----- cmd-join-pane.c | 4 ++-- cmd-link-window.c | 2 +- cmd-list-buffers.c | 3 ++- cmd-list-clients.c | 3 ++- cmd-list-panes.c | 3 ++- cmd-list-sessions.c | 3 ++- cmd-list-windows.c | 3 ++- cmd-list.c | 3 ++- cmd-load-buffer.c | 13 ++++++------- cmd-move-window.c | 2 +- cmd-new-session.c | 6 +++--- cmd-new-window.c | 4 ++-- cmd-paste-buffer.c | 2 +- cmd-rename-session.c | 2 +- cmd-respawn-pane.c | 3 ++- cmd-respawn-window.c | 3 ++- cmd-run-shell.c | 9 +++++---- cmd-save-buffer.c | 3 ++- cmd-set-buffer.c | 7 ++++--- cmd-set-option.c | 2 +- cmd-show-buffer.c | 7 ++++--- cmd-source-file.c | 6 ++++-- cmd-split-window.c | 8 ++++---- cmd-string.c | 27 ++++++++++++-------------- cmd-unbind-key.c | 6 ++++-- cmd.c | 45 +++++++++++++++++-------------------------- control.c | 5 +++-- environ.c | 21 +++++++++----------- format.c | 19 +++++++++--------- grid.c | 17 +++++++--------- input-keys.c | 2 +- input.c | 2 +- job.c | 5 +++-- key-bindings.c | 6 +++--- layout.c | 6 +++--- names.c | 9 +++++---- options.c | 17 ++++++++-------- paste.c | 15 ++++++++------- screen-write.c | 11 ++++++----- screen.c | 14 ++++++-------- server-client.c | 24 +++++++++-------------- server-fn.c | 3 ++- server-window.c | 3 ++- server.c | 10 +++++----- session.c | 10 ++++------ status.c | 45 +++++++++++++++++++------------------------ tmux.c | 21 ++++++++------------ tmux.h | 1 - tty-keys.c | 2 +- tty-term.c | 15 +++++++-------- tty.c | 10 +++++----- window-choose.c | 9 +++++---- window-clock.c | 3 ++- window-copy.c | 11 +++++------ window.c | 37 ++++++++++++++--------------------- xmalloc.c | 8 -------- 73 files changed, 329 insertions(+), 360 deletions(-) diff --git a/arguments.c b/arguments.c index 72a8577f..c15832a4 100644 --- a/arguments.c +++ b/arguments.c @@ -69,15 +69,14 @@ args_parse(const char *template, int argc, char **argv) if (opt < 0 || opt >= SCHAR_MAX) continue; if (opt == '?' || (ptr = strchr(template, opt)) == NULL) { - xfree(args->flags); - xfree(args); + free(args->flags); + free(args); return (NULL); } bit_set(args->flags, opt); if (ptr[1] == ':') { - if (args->values[opt] != NULL) - xfree(args->values[opt]); + free(args->values[opt]); args->values[opt] = xstrdup(optarg); } } @@ -98,13 +97,11 @@ args_free(struct args *args) cmd_free_argv(args->argc, args->argv); - for (i = 0; i < SCHAR_MAX; i++) { - if (args->values[i] != NULL) - xfree(args->values[i]); - } + for (i = 0; i < SCHAR_MAX; i++) + free(args->values[i]); - xfree(args->flags); - xfree(args); + free(args->flags); + free(args); } /* Print a set of arguments. */ @@ -183,8 +180,7 @@ args_has(struct args *args, u_char ch) void args_set(struct args *args, u_char ch, const char *value) { - if (args->values[ch] != NULL) - xfree(args->values[ch]); + free(args->values[ch]); if (value != NULL) args->values[ch] = xstrdup(value); else diff --git a/array.h b/array.h index 59ac356f..c811bf6d 100644 --- a/array.h +++ b/array.h @@ -109,13 +109,12 @@ } while (0) #define ARRAY_FREE(a) do { \ - if ((a)->list != NULL) \ - xfree((a)->list); \ + free((a)->list); \ ARRAY_INIT(a); \ } while (0) #define ARRAY_FREEALL(a) do { \ ARRAY_FREE(a); \ - xfree(a); \ + free(a); \ } while (0) #endif diff --git a/cfg.c b/cfg.c index 22a50d22..733238f3 100644 --- a/cfg.c +++ b/cfg.c @@ -21,6 +21,7 @@ #include #include +#include #include #include "tmux.h" @@ -117,14 +118,14 @@ load_cfg(const char *path, struct cmd_ctx *ctxin, struct causelist *causes) line = NULL; if (cmd_string_parse(buf, &cmdlist, &cause) != 0) { - xfree(buf); + free(buf); if (cause == NULL) continue; cfg_add_cause(causes, "%s: %u: %s", path, n, cause); - xfree(cause); + free(cause); continue; } else - xfree(buf); + free(buf); if (cmdlist == NULL) continue; cfg_cause = NULL; @@ -150,13 +151,13 @@ load_cfg(const char *path, struct cmd_ctx *ctxin, struct causelist *causes) if (cfg_cause != NULL) { cfg_add_cause( causes, "%s: %d: %s", path, n, cfg_cause); - xfree(cfg_cause); + free(cfg_cause); } } if (line != NULL) { cfg_add_cause(causes, "%s: %d: line continuation at end of file", path, n); - xfree(line); + free(line); } fclose(f); diff --git a/client.c b/client.c index 16498577..1326a97d 100644 --- a/client.c +++ b/client.c @@ -122,7 +122,7 @@ retry: if (unlink(path) != 0 && errno != ENOENT) return (-1); fd = server_start(lockfd, lockfile); - xfree(lockfile); + free(lockfile); close(lockfd); } diff --git a/cmd-attach-session.c b/cmd-attach-session.c index d07b727d..42ef89ce 100644 --- a/cmd-attach-session.c +++ b/cmd-attach-session.c @@ -18,6 +18,8 @@ #include +#include + #include "tmux.h" /* @@ -81,7 +83,7 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx) } else { if (server_client_open(ctx->cmdclient, s, &cause) != 0) { ctx->error(ctx, "open terminal failed: %s", cause); - xfree(cause); + free(cause); return (-1); } diff --git a/cmd-bind-key.c b/cmd-bind-key.c index 4f1b9f18..980e7ec9 100644 --- a/cmd-bind-key.c +++ b/cmd-bind-key.c @@ -18,6 +18,7 @@ #include +#include #include #include "tmux.h" @@ -74,7 +75,7 @@ cmd_bind_key_exec(struct cmd *self, struct cmd_ctx *ctx) cmdlist = cmd_list_parse(args->argc - 1, args->argv + 1, &cause); if (cmdlist == NULL) { ctx->error(ctx, "%s", cause); - xfree(cause); + free(cause); return (-1); } diff --git a/cmd-break-pane.c b/cmd-break-pane.c index 8e09774b..bcb6e6b9 100644 --- a/cmd-break-pane.c +++ b/cmd-break-pane.c @@ -81,7 +81,7 @@ cmd_break_pane_exec(struct cmd *self, struct cmd_ctx *ctx) w->active = wp; name = default_window_name(w); window_set_name(w, name); - xfree(name); + free(name); layout_init(w); base_idx = options_get_number(&s->options, "base-index"); @@ -106,7 +106,7 @@ cmd_break_pane_exec(struct cmd *self, struct cmd_ctx *ctx) cp = format_expand(ft, template); ctx->print(ctx, "%s", cp); - xfree(cp); + free(cp); format_free(ft); } diff --git a/cmd-capture-pane.c b/cmd-capture-pane.c index 7c974f1f..236a51ca 100644 --- a/cmd-capture-pane.c +++ b/cmd-capture-pane.c @@ -62,7 +62,7 @@ cmd_capture_pane_exec(struct cmd *self, struct cmd_ctx *ctx) n = args_strtonum(args, 'S', INT_MIN, SHRT_MAX, &cause); if (cause != NULL) { top = gd->hsize; - xfree(cause); + free(cause); } else if (n < 0 && (u_int) -n > gd->hsize) top = 0; else @@ -73,7 +73,7 @@ cmd_capture_pane_exec(struct cmd *self, struct cmd_ctx *ctx) n = args_strtonum(args, 'E', INT_MIN, SHRT_MAX, &cause); if (cause != NULL) { bottom = gd->hsize + gd->sy - 1; - xfree(cause); + free(cause); } else if (n < 0 && (u_int) -n > gd->hsize) bottom = 0; else @@ -96,7 +96,7 @@ cmd_capture_pane_exec(struct cmd *self, struct cmd_ctx *ctx) len += linelen; buf[len++] = '\n'; - xfree(line); + free(line); } limit = options_get_number(&global_options, "buffer-limit"); @@ -109,14 +109,14 @@ cmd_capture_pane_exec(struct cmd *self, struct cmd_ctx *ctx) buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause); if (cause != NULL) { ctx->error(ctx, "buffer %s", cause); - xfree(buf); - xfree(cause); + free(buf); + free(cause); return (-1); } if (paste_replace(&global_buffers, buffer, buf, len) != 0) { ctx->error(ctx, "no buffer %d", buffer); - xfree(buf); + free(buf); return (-1); } diff --git a/cmd-choose-buffer.c b/cmd-choose-buffer.c index 0baa0a28..6c62cfa3 100644 --- a/cmd-choose-buffer.c +++ b/cmd-choose-buffer.c @@ -19,6 +19,7 @@ #include #include +#include #include "tmux.h" @@ -86,11 +87,11 @@ cmd_choose_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) xasprintf(&action_data, "%u", idx - 1); cdata->command = cmd_template_replace(action, action_data, 1); - xfree(action_data); + free(action_data); window_choose_add(wl->window->active, cdata); } - xfree(action); + free(action); window_choose_ready(wl->window->active, 0, cmd_choose_buffer_callback, cmd_choose_buffer_free); @@ -119,7 +120,7 @@ cmd_choose_buffer_free(struct window_choose_data *data) cdata->client->references--; - xfree(cdata->command); - xfree(cdata->ft_template); - xfree(cdata); + free(cdata->command); + free(cdata->ft_template); + free(cdata); } diff --git a/cmd-choose-client.c b/cmd-choose-client.c index fd6b2128..a20fec42 100644 --- a/cmd-choose-client.c +++ b/cmd-choose-client.c @@ -19,6 +19,7 @@ #include #include +#include #include "tmux.h" @@ -98,7 +99,7 @@ cmd_choose_client_exec(struct cmd *self, struct cmd_ctx *ctx) window_choose_add(wl->window->active, cdata); } - xfree(action); + free(action); window_choose_ready(wl->window->active, cur, cmd_choose_client_callback, cmd_choose_client_free); @@ -133,8 +134,8 @@ cmd_choose_client_free(struct window_choose_data *cdata) cdata->client->references--; - xfree(cdata->ft_template); - xfree(cdata->command); + free(cdata->ft_template); + free(cdata->command); format_free(cdata->ft); - xfree(cdata); + free(cdata); } diff --git a/cmd-choose-tree.c b/cmd-choose-tree.c index c29b2eab..0389bea3 100644 --- a/cmd-choose-tree.c +++ b/cmd-choose-tree.c @@ -19,6 +19,7 @@ #include #include +#include #include @@ -206,7 +207,7 @@ windows_only: ctx, s2, wm, final_win_template, final_win_action, idx_ses); - xfree(final_win_action); + free(final_win_action); } /* * If we're just drawing windows, don't consider moving on to @@ -215,8 +216,7 @@ windows_only: if (wflag && !sflag) break; } - if (final_win_template != NULL) - xfree(final_win_template); + free(final_win_template); window_choose_ready(wl->window->active, cur_win, cmd_choose_tree_callback, cmd_choose_tree_free); @@ -242,10 +242,10 @@ cmd_choose_tree_free(struct window_choose_data *cdata) cdata->session->references--; cdata->client->references--; - xfree(cdata->ft_template); - xfree(cdata->command); + free(cdata->ft_template); + free(cdata->command); format_free(cdata->ft); - xfree(cdata); + free(cdata); } diff --git a/cmd-command-prompt.c b/cmd-command-prompt.c index cd4d07ed..3105744f 100644 --- a/cmd-command-prompt.c +++ b/cmd-command-prompt.c @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -138,7 +139,7 @@ cmd_command_prompt_exec(struct cmd *self, struct cmd_ctx *ctx) status_prompt_set(c, prompt, input, cmd_command_prompt_callback, cmd_command_prompt_free, cdata, 0); - xfree(prompt); + free(prompt); return (0); } @@ -157,7 +158,7 @@ cmd_command_prompt_callback(void *data, const char *s) return (0); new_template = cmd_template_replace(cdata->template, s, cdata->idx); - xfree(cdata->template); + free(cdata->template); cdata->template = new_template; /* @@ -169,7 +170,7 @@ cmd_command_prompt_callback(void *data, const char *s) input = strsep(&cdata->next_input, ","); status_prompt_update(c, prompt, input); - xfree(prompt); + free(prompt); cdata->idx++; return (1); } @@ -178,7 +179,7 @@ cmd_command_prompt_callback(void *data, const char *s) if (cause != NULL) { *cause = toupper((u_char) *cause); status_message_set(c, "%s", cause); - xfree(cause); + free(cause); } return (0); } @@ -205,11 +206,8 @@ cmd_command_prompt_free(void *data) { struct cmd_command_prompt_cdata *cdata = data; - if (cdata->inputs != NULL) - xfree(cdata->inputs); - if (cdata->prompts != NULL) - xfree(cdata->prompts); - if (cdata->template != NULL) - xfree(cdata->template); - xfree(cdata); + free(cdata->inputs); + free(cdata->prompts); + free(cdata->template); + free(cdata); } diff --git a/cmd-confirm-before.c b/cmd-confirm-before.c index 048465da..78c6bac4 100644 --- a/cmd-confirm-before.c +++ b/cmd-confirm-before.c @@ -17,6 +17,7 @@ */ #include +#include #include #include "tmux.h" @@ -87,7 +88,7 @@ cmd_confirm_before_exec(struct cmd *self, struct cmd_ctx *ctx) ptr = copy = xstrdup(args->argv[0]); cmd = strsep(&ptr, " \t"); xasprintf(&new_prompt, "Confirm '%s'? (y/n) ", cmd); - xfree(copy); + free(copy); } cdata = xmalloc(sizeof *cdata); @@ -97,7 +98,7 @@ cmd_confirm_before_exec(struct cmd *self, struct cmd_ctx *ctx) cmd_confirm_before_callback, cmd_confirm_before_free, cdata, PROMPT_SINGLE); - xfree(new_prompt); + free(new_prompt); return (1); } @@ -119,7 +120,7 @@ cmd_confirm_before_callback(void *data, const char *s) if (cause != NULL) { *cause = toupper((u_char) *cause); status_message_set(c, "%s", cause); - xfree(cause); + free(cause); } return (0); } @@ -144,7 +145,6 @@ cmd_confirm_before_free(void *data) { struct cmd_confirm_before_data *cdata = data; - if (cdata->cmd != NULL) - xfree(cdata->cmd); - xfree(cdata); + free(cdata->cmd); + free(cdata); } diff --git a/cmd-delete-buffer.c b/cmd-delete-buffer.c index 3f0578ed..f087b9a7 100644 --- a/cmd-delete-buffer.c +++ b/cmd-delete-buffer.c @@ -53,7 +53,7 @@ cmd_delete_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause); if (cause != NULL) { ctx->error(ctx, "buffer %s", cause); - xfree(cause); + free(cause); return (-1); } diff --git a/cmd-display-message.c b/cmd-display-message.c index 058de1fa..3bc3a38c 100644 --- a/cmd-display-message.c +++ b/cmd-display-message.c @@ -18,6 +18,7 @@ #include +#include #include #include "tmux.h" @@ -93,7 +94,7 @@ cmd_display_message_exec(struct cmd *self, struct cmd_ctx *ctx) else status_message_set(c, "%s", msg); - xfree(msg); + free(msg); format_free(ft); return (0); } diff --git a/cmd-find-window.c b/cmd-find-window.c index 9bd535f4..864f1821 100644 --- a/cmd-find-window.c +++ b/cmd-find-window.c @@ -19,6 +19,7 @@ #include #include +#include #include #include "tmux.h" @@ -134,7 +135,7 @@ cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx) xasprintf(&sctx, "pane %u line %u: \"%s\"", i - 1, line + 1, sres); - xfree(sres); + free(sres); } } @@ -143,7 +144,7 @@ cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx) break; } } - xfree(searchstr); + free(searchstr); if (ARRAY_LENGTH(&list_idx) == 0) { ctx->error(ctx, "no windows matching: %s", str); @@ -217,7 +218,7 @@ cmd_find_window_free(struct window_choose_data *cdata) cdata->session->references--; - xfree(cdata->ft_template); + free(cdata->ft_template); format_free(cdata->ft); - xfree(cdata); + free(cdata); } diff --git a/cmd-if-shell.c b/cmd-if-shell.c index 6692a99c..bdd26e70 100644 --- a/cmd-if-shell.c +++ b/cmd-if-shell.c @@ -20,6 +20,7 @@ #include #include +#include #include #include "tmux.h" @@ -91,7 +92,7 @@ cmd_if_shell_callback(struct job *job) if (cmd_string_parse(cmd, &cmdlist, &cause) != 0) { if (cause != NULL) { ctx->error(ctx, "%s", cause); - xfree(cause); + free(cause); } return; } @@ -115,8 +116,7 @@ cmd_if_shell_free(void *data) if (ctx->curclient != NULL) ctx->curclient->references--; - if (cdata->cmd_else != NULL) - xfree(cdata->cmd_else); - xfree(cdata->cmd_if); - xfree(cdata); + free(cdata->cmd_else); + free(cdata->cmd_if); + free(cdata); } diff --git a/cmd-join-pane.c b/cmd-join-pane.c index 708430ca..602dcf66 100644 --- a/cmd-join-pane.c +++ b/cmd-join-pane.c @@ -116,14 +116,14 @@ join_pane(struct cmd *self, struct cmd_ctx *ctx, int not_same_window) size = args_strtonum(args, 'l', 0, INT_MAX, &cause); if (cause != NULL) { ctx->error(ctx, "size %s", cause); - xfree(cause); + free(cause); return (-1); } } else if (args_has(args, 'p')) { percentage = args_strtonum(args, 'p', 0, 100, &cause); if (cause != NULL) { ctx->error(ctx, "percentage %s", cause); - xfree(cause); + free(cause); return (-1); } if (type == LAYOUT_TOPBOTTOM) diff --git a/cmd-link-window.c b/cmd-link-window.c index a278fe34..a9dcf621 100644 --- a/cmd-link-window.c +++ b/cmd-link-window.c @@ -56,7 +56,7 @@ cmd_link_window_exec(struct cmd *self, struct cmd_ctx *ctx) dflag = args_has(self->args, 'd'); if (server_link_window(src, wl, dst, idx, kflag, !dflag, &cause) != 0) { ctx->error(ctx, "can't link window: %s", cause); - xfree(cause); + free(cause); return (-1); } recalculate_sizes(); diff --git a/cmd-list-buffers.c b/cmd-list-buffers.c index 777a6371..64fbd3f2 100644 --- a/cmd-list-buffers.c +++ b/cmd-list-buffers.c @@ -18,6 +18,7 @@ #include +#include #include #include "tmux.h" @@ -60,7 +61,7 @@ cmd_list_buffers_exec(unused struct cmd *self, struct cmd_ctx *ctx) line = format_expand(ft, template); ctx->print(ctx, "%s", line); - xfree(line); + free(line); format_free(ft); } diff --git a/cmd-list-clients.c b/cmd-list-clients.c index c818fd6d..2286ff98 100644 --- a/cmd-list-clients.c +++ b/cmd-list-clients.c @@ -18,6 +18,7 @@ #include +#include #include #include @@ -76,7 +77,7 @@ cmd_list_clients_exec(struct cmd *self, struct cmd_ctx *ctx) line = format_expand(ft, template); ctx->print(ctx, "%s", line); - xfree(line); + free(line); format_free(ft); } diff --git a/cmd-list-panes.c b/cmd-list-panes.c index 55559db7..3f9e672c 100644 --- a/cmd-list-panes.c +++ b/cmd-list-panes.c @@ -18,6 +18,7 @@ #include +#include #include #include "tmux.h" @@ -135,7 +136,7 @@ cmd_list_panes_window(struct cmd *self, line = format_expand(ft, template); ctx->print(ctx, "%s", line); - xfree(line); + free(line); format_free(ft); n++; diff --git a/cmd-list-sessions.c b/cmd-list-sessions.c index 7dabfc08..1aa6dbaa 100644 --- a/cmd-list-sessions.c +++ b/cmd-list-sessions.c @@ -18,6 +18,7 @@ #include +#include #include #include @@ -60,7 +61,7 @@ cmd_list_sessions_exec(struct cmd *self, struct cmd_ctx *ctx) line = format_expand(ft, template); ctx->print(ctx, "%s", line); - xfree(line); + free(line); format_free(ft); n++; diff --git a/cmd-list-windows.c b/cmd-list-windows.c index e0617335..241e64de 100644 --- a/cmd-list-windows.c +++ b/cmd-list-windows.c @@ -18,6 +18,7 @@ #include +#include #include #include "tmux.h" @@ -103,7 +104,7 @@ cmd_list_windows_session( line = format_expand(ft, template); ctx->print(ctx, "%s", line); - xfree(line); + free(line); format_free(ft); n++; diff --git a/cmd-list.c b/cmd-list.c index dc102dcc..08d5716f 100644 --- a/cmd-list.c +++ b/cmd-list.c @@ -18,6 +18,7 @@ #include +#include #include #include "tmux.h" @@ -139,7 +140,7 @@ cmd_list_free(struct cmd_list *cmdlist) TAILQ_REMOVE(&cmdlist->list, cmd, qentry); cmd_free(cmd); } - xfree(cmdlist); + free(cmdlist); } size_t diff --git a/cmd-load-buffer.c b/cmd-load-buffer.c index 1e6b6024..83ab6078 100644 --- a/cmd-load-buffer.c +++ b/cmd-load-buffer.c @@ -62,7 +62,7 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause); if (cause != NULL) { ctx->error(ctx, "buffer %s", cause); - xfree(cause); + free(cause); return (-1); } } @@ -76,7 +76,7 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) buffer_ptr, &cause); if (error != 0) { ctx->error(ctx, "%s: %s", path, cause); - xfree(cause); + free(cause); return (-1); } return (1); @@ -127,15 +127,14 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) } if (paste_replace(&global_buffers, buffer, pdata, psize) != 0) { ctx->error(ctx, "no buffer %d", buffer); - xfree(pdata); + free(pdata); return (-1); } return (0); error: - if (pdata != NULL) - xfree(pdata); + free(pdata); if (f != NULL) fclose(f); return (-1); @@ -158,7 +157,7 @@ cmd_load_buffer_callback(struct client *c, int closed, void *data) psize = EVBUFFER_LENGTH(c->stdin_data); if (psize == 0 || (pdata = malloc(psize + 1)) == NULL) { - xfree(data); + free(data); return; } memcpy(pdata, EVBUFFER_DATA(c->stdin_data), psize); @@ -174,5 +173,5 @@ cmd_load_buffer_callback(struct client *c, int closed, void *data) server_push_stderr(c); } - xfree(data); + free(data); } diff --git a/cmd-move-window.c b/cmd-move-window.c index 6268226e..4adad410 100644 --- a/cmd-move-window.c +++ b/cmd-move-window.c @@ -66,7 +66,7 @@ cmd_move_window_exec(struct cmd *self, struct cmd_ctx *ctx) dflag = args_has(self->args, 'd'); if (server_link_window(src, wl, dst, idx, kflag, !dflag, &cause) != 0) { ctx->error(ctx, "can't move window: %s", cause); - xfree(cause); + free(cause); return (-1); } server_unlink_window(src, wl); diff --git a/cmd-new-session.c b/cmd-new-session.c index 09413796..22ec16fb 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -130,7 +130,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) if (!detached && ctx->cmdclient != NULL) { if (server_client_open(ctx->cmdclient, NULL, &cause) != 0) { ctx->error(ctx, "open terminal failed: %s", cause); - xfree(cause); + free(cause); return (-1); } } @@ -201,7 +201,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) s = session_create(newname, cmd, cwd, &env, tiop, idx, sx, sy, &cause); if (s == NULL) { ctx->error(ctx, "create session failed: %s", cause); - xfree(cause); + free(cause); return (-1); } environ_free(&env); @@ -264,7 +264,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) for (i = 0; i < ARRAY_LENGTH(&cfg_causes); i++) { cause = ARRAY_ITEM(&cfg_causes, i); window_copy_add(wp, "%s", cause); - xfree(cause); + free(cause); } ARRAY_FREE(&cfg_causes); } diff --git a/cmd-new-window.c b/cmd-new-window.c index 46bda8fc..3d9e9320 100644 --- a/cmd-new-window.c +++ b/cmd-new-window.c @@ -112,7 +112,7 @@ cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx) wl = session_new(s, args_get(args, 'n'), cmd, cwd, idx, &cause); if (wl == NULL) { ctx->error(ctx, "create window failed: %s", cause); - xfree(cause); + free(cause); return (-1); } if (!detached) { @@ -134,7 +134,7 @@ cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx) cp = format_expand(ft, template); ctx->print(ctx, "%s", cp); - xfree(cp); + free(cp); format_free(ft); } diff --git a/cmd-paste-buffer.c b/cmd-paste-buffer.c index db20643c..2c367259 100644 --- a/cmd-paste-buffer.c +++ b/cmd-paste-buffer.c @@ -64,7 +64,7 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause); if (cause != NULL) { ctx->error(ctx, "buffer %s", cause); - xfree(cause); + free(cause); return (-1); } } diff --git a/cmd-rename-session.c b/cmd-rename-session.c index 9f741d8d..bbae1872 100644 --- a/cmd-rename-session.c +++ b/cmd-rename-session.c @@ -59,7 +59,7 @@ cmd_rename_session_exec(struct cmd *self, struct cmd_ctx *ctx) return (-1); RB_REMOVE(sessions, &sessions, s); - xfree(s->name); + free(s->name); s->name = xstrdup(newname); RB_INSERT(sessions, &sessions, s); diff --git a/cmd-respawn-pane.c b/cmd-respawn-pane.c index d1e52669..71e07831 100644 --- a/cmd-respawn-pane.c +++ b/cmd-respawn-pane.c @@ -19,6 +19,7 @@ #include +#include #include #include "tmux.h" @@ -79,7 +80,7 @@ cmd_respawn_pane_exec(struct cmd *self, struct cmd_ctx *ctx) cmd = NULL; if (window_pane_spawn(wp, cmd, NULL, NULL, &env, s->tio, &cause) != 0) { ctx->error(ctx, "respawn pane failed: %s", cause); - xfree(cause); + free(cause); environ_free(&env); return (-1); } diff --git a/cmd-respawn-window.c b/cmd-respawn-window.c index 319262e5..c15ca376 100644 --- a/cmd-respawn-window.c +++ b/cmd-respawn-window.c @@ -18,6 +18,7 @@ #include +#include #include #include "tmux.h" @@ -81,7 +82,7 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_ctx *ctx) cmd = NULL; if (window_pane_spawn(wp, cmd, NULL, NULL, &env, s->tio, &cause) != 0) { ctx->error(ctx, "respawn window failed: %s", cause); - xfree(cause); + free(cause); environ_free(&env); server_destroy_pane(wp); return (-1); diff --git a/cmd-run-shell.c b/cmd-run-shell.c index 85cd1e29..6a80d4ef 100644 --- a/cmd-run-shell.c +++ b/cmd-run-shell.c @@ -20,6 +20,7 @@ #include #include +#include #include #include "tmux.h" @@ -101,7 +102,7 @@ cmd_run_shell_callback(struct job *job) ctx->print(ctx, "%s", line); lines++; - xfree(line); + free(line); } cmd = cdata->cmd; @@ -119,7 +120,7 @@ cmd_run_shell_callback(struct job *job) ctx->print(ctx, "%s", msg); else ctx->info(ctx, "%s", msg); - xfree(msg); + free(msg); } } @@ -136,6 +137,6 @@ cmd_run_shell_free(void *data) if (ctx->curclient != NULL) ctx->curclient->references--; - xfree(cdata->cmd); - xfree(cdata); + free(cdata->cmd); + free(cdata); } diff --git a/cmd-save-buffer.c b/cmd-save-buffer.c index 80f9d572..875cbbbb 100644 --- a/cmd-save-buffer.c +++ b/cmd-save-buffer.c @@ -20,6 +20,7 @@ #include #include +#include #include #include "tmux.h" @@ -62,7 +63,7 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause); if (cause != NULL) { ctx->error(ctx, "buffer %s", cause); - xfree(cause); + free(cause); return (-1); } diff --git a/cmd-set-buffer.c b/cmd-set-buffer.c index 4f3d87a7..73e8b316 100644 --- a/cmd-set-buffer.c +++ b/cmd-set-buffer.c @@ -18,6 +18,7 @@ #include +#include #include #include "tmux.h" @@ -60,14 +61,14 @@ cmd_set_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause); if (cause != NULL) { ctx->error(ctx, "buffer %s", cause); - xfree(cause); - xfree(pdata); + free(cause); + free(pdata); return (-1); } if (paste_replace(&global_buffers, buffer, pdata, psize) != 0) { ctx->error(ctx, "no buffer %d", buffer); - xfree(pdata); + free(pdata); return (-1); } diff --git a/cmd-set-option.c b/cmd-set-option.c index ff138873..8e55a4fc 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -257,7 +257,7 @@ cmd_set_option_string(struct cmd *self, unused struct cmd_ctx *ctx, o = options_set_string(oo, oe->name, "%s", newval); - xfree(newval); + free(newval); return (o); } diff --git a/cmd-show-buffer.c b/cmd-show-buffer.c index 17d4509d..6dbc0c37 100644 --- a/cmd-show-buffer.c +++ b/cmd-show-buffer.c @@ -18,6 +18,7 @@ #include +#include #include #include "tmux.h" @@ -61,7 +62,7 @@ cmd_show_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause); if (cause != NULL) { ctx->error(ctx, "buffer %s", cause); - xfree(cause); + free(cause); return (-1); } @@ -103,9 +104,9 @@ cmd_show_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) buf[len] = '\0'; ctx->print(ctx, "%s", buf); } - xfree(buf); + free(buf); - xfree(in); + free(in); return (0); } diff --git a/cmd-source-file.c b/cmd-source-file.c index aa05d362..3804f0ec 100644 --- a/cmd-source-file.c +++ b/cmd-source-file.c @@ -18,6 +18,8 @@ #include +#include + #include "tmux.h" /* @@ -59,13 +61,13 @@ cmd_source_file_exec(struct cmd *self, struct cmd_ctx *ctx) for (i = 0; i < ARRAY_LENGTH(&causes); i++) { cause = ARRAY_ITEM(&causes, i); window_copy_add(wp, "%s", cause); - xfree(cause); + free(cause); } } else { for (i = 0; i < ARRAY_LENGTH(&causes); i++) { cause = ARRAY_ITEM(&causes, i); ctx->print(ctx, "%s", cause); - xfree(cause); + free(cause); } } ARRAY_FREE(&causes); diff --git a/cmd-split-window.c b/cmd-split-window.c index db00a67b..c8afdaba 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -94,7 +94,7 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) size = args_strtonum(args, 'l', 0, INT_MAX, &cause); if (cause != NULL) { xasprintf(&new_cause, "size %s", cause); - xfree(cause); + free(cause); cause = new_cause; goto error; } @@ -102,7 +102,7 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) percentage = args_strtonum(args, 'p', 0, INT_MAX, &cause); if (cause != NULL) { xasprintf(&new_cause, "percentage %s", cause); - xfree(cause); + free(cause); cause = new_cause; goto error; } @@ -151,7 +151,7 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) cp = format_expand(ft, template); ctx->print(ctx, "%s", cp); - xfree(cp); + free(cp); format_free(ft); } @@ -163,6 +163,6 @@ error: if (new_wp != NULL) window_remove_pane(w, new_wp); ctx->error(ctx, "create pane failed: %s", cause); - xfree(cause); + free(cause); return (-1); } diff --git a/cmd-string.c b/cmd-string.c index 9384f9e2..93beb3ca 100644 --- a/cmd-string.c +++ b/cmd-string.c @@ -87,7 +87,7 @@ cmd_string_parse(const char *s, struct cmd_list **cmdlist, char **cause) buf = xrealloc(buf, 1, len + strlen(t) + 1); strlcpy(buf + len, t, strlen(t) + 1); len += strlen(t); - xfree(t); + free(t); break; case '"': if ((t = cmd_string_string(s, &p, '"', 1)) == NULL) @@ -95,7 +95,7 @@ cmd_string_parse(const char *s, struct cmd_list **cmdlist, char **cause) buf = xrealloc(buf, 1, len + strlen(t) + 1); strlcpy(buf + len, t, strlen(t) + 1); len += strlen(t); - xfree(t); + free(t); break; case '$': if ((t = cmd_string_variable(s, &p)) == NULL) @@ -103,7 +103,7 @@ cmd_string_parse(const char *s, struct cmd_list **cmdlist, char **cause) buf = xrealloc(buf, 1, len + strlen(t) + 1); strlcpy(buf + len, t, strlen(t) + 1); len += strlen(t); - xfree(t); + free(t); break; case '#': /* Comment: discard rest of line. */ @@ -152,7 +152,7 @@ cmd_string_parse(const char *s, struct cmd_list **cmdlist, char **cause) buf = xrealloc(buf, 1, len + strlen(t) + 1); strlcpy(buf + len, t, strlen(t) + 1); len += strlen(t); - xfree(t); + free(t); break; } /* FALLTHROUGH */ @@ -170,13 +170,12 @@ error: xasprintf(cause, "invalid or unknown command: %s", s); out: - if (buf != NULL) - xfree(buf); + free(buf); if (argv != NULL) { for (i = 0; i < argc; i++) - xfree(argv[i]); - xfree(argv); + free(argv[i]); + free(argv); } return (rval); @@ -224,7 +223,7 @@ cmd_string_string(const char *s, size_t *p, char endch, int esc) buf = xrealloc(buf, 1, len + strlen(t) + 1); strlcpy(buf + len, t, strlen(t) + 1); len += strlen(t); - xfree(t); + free(t); continue; } @@ -239,8 +238,7 @@ cmd_string_string(const char *s, size_t *p, char endch, int esc) return (buf); error: - if (buf != NULL) - xfree(buf); + free(buf); return (NULL); } @@ -303,14 +301,13 @@ cmd_string_variable(const char *s, size_t *p) buf[len] = '\0'; envent = environ_find(&global_environ, buf); - xfree(buf); + free(buf); if (envent == NULL) return (xstrdup("")); return (xstrdup(envent->value)); error: - if (buf != NULL) - xfree(buf); + free(buf); return (NULL); } @@ -334,7 +331,7 @@ cmd_string_expand_tilde(const char *s, size_t *p) return (NULL); if ((pw = getpwnam(username)) != NULL) home = pw->pw_dir; - xfree(username); + free(username); } if (home == NULL) return (NULL); diff --git a/cmd-unbind-key.c b/cmd-unbind-key.c index 4a061061..ac6c0c0f 100644 --- a/cmd-unbind-key.c +++ b/cmd-unbind-key.c @@ -18,6 +18,8 @@ #include +#include + #include "tmux.h" /* @@ -100,7 +102,7 @@ cmd_unbind_key_table(struct cmd *self, struct cmd_ctx *ctx, int key) while (!RB_EMPTY(mtab->tree)) { mbind = RB_ROOT(mtab->tree); RB_REMOVE(mode_key_tree, mtab->tree, mbind); - xfree(mbind); + free(mbind); } return (0); } @@ -109,7 +111,7 @@ cmd_unbind_key_table(struct cmd *self, struct cmd_ctx *ctx, int key) mtmp.mode = !!args_has(args, 'c'); if ((mbind = RB_FIND(mode_key_tree, mtab->tree, &mtmp)) != NULL) { RB_REMOVE(mode_key_tree, mtab->tree, mbind); - xfree(mbind); + free(mbind); } return (0); } diff --git a/cmd.c b/cmd.c index 5f97a854..eb2fd75c 100644 --- a/cmd.c +++ b/cmd.c @@ -198,11 +198,9 @@ cmd_free_argv(int argc, char **argv) if (argc == 0) return; - for (i = 0; i < argc; i++) { - if (argv[i] != NULL) - xfree(argv[i]); - } - xfree(argv); + for (i = 0; i < argc; i++) + free(argv[i]); + free(argv); } struct cmd * @@ -291,9 +289,8 @@ cmd_exec(struct cmd *cmd, struct cmd_ctx *ctx) void cmd_free(struct cmd *cmd) { - if (cmd->args != NULL) - args_free(cmd->args); - xfree(cmd); + args_free(cmd->args); + free(cmd); } size_t @@ -507,7 +504,7 @@ cmd_find_client(struct cmd_ctx *ctx, const char *arg) if (c == NULL) ctx->error(ctx, "client not found: %s", tmparg); - xfree(tmparg); + free(tmparg); return (c); } @@ -767,7 +764,7 @@ cmd_find_session(struct cmd_ctx *ctx, const char *arg, int prefer_unattached) /* An empty session name is the current session. */ if (*tmparg == '\0') { - xfree(tmparg); + free(tmparg); return (cmd_current_session(ctx, prefer_unattached)); } @@ -786,7 +783,7 @@ cmd_find_session(struct cmd_ctx *ctx, const char *arg, int prefer_unattached) ctx->error(ctx, "session not found: %s", tmparg); } - xfree(tmparg); + free(tmparg); return (s); } @@ -861,7 +858,7 @@ cmd_find_window(struct cmd_ctx *ctx, const char *arg, struct session **sp) goto not_found; if (sessptr != NULL) - xfree(sessptr); + free(sessptr); return (wl); no_colon: @@ -899,8 +896,7 @@ no_session: ctx->error(ctx, "multiple sessions: %s", arg); else ctx->error(ctx, "session not found: %s", arg); - if (sessptr != NULL) - xfree(sessptr); + free(sessptr); return (NULL); not_found: @@ -908,8 +904,7 @@ not_found: ctx->error(ctx, "multiple windows: %s", arg); else ctx->error(ctx, "window not found: %s", arg); - if (sessptr != NULL) - xfree(sessptr); + free(sessptr); return (NULL); } @@ -1000,8 +995,7 @@ cmd_find_index(struct cmd_ctx *ctx, const char *arg, struct session **sp) } else if ((idx = cmd_lookup_index(s, winptr, &ambiguous)) == -1) goto invalid_index; - if (sessptr != NULL) - xfree(sessptr); + free(sessptr); return (idx); no_colon: @@ -1040,8 +1034,7 @@ no_session: ctx->error(ctx, "multiple sessions: %s", arg); else ctx->error(ctx, "session not found: %s", arg); - if (sessptr != NULL) - xfree(sessptr); + free(sessptr); return (-2); invalid_index: @@ -1049,8 +1042,7 @@ invalid_index: goto not_found; ctx->error(ctx, "invalid index: %s", arg); - if (sessptr != NULL) - xfree(sessptr); + free(sessptr); return (-2); not_found: @@ -1058,8 +1050,7 @@ not_found: ctx->error(ctx, "multiple windows: %s", arg); else ctx->error(ctx, "window not found: %s", arg); - if (sessptr != NULL) - xfree(sessptr); + free(sessptr); return (-2); } @@ -1153,7 +1144,7 @@ cmd_find_pane(struct cmd_ctx *ctx, goto lookup_string; } - xfree(winptr); + free(winptr); return (wl); lookup_string: @@ -1163,7 +1154,7 @@ lookup_string: goto error; } - xfree(winptr); + free(winptr); return (wl); no_period: @@ -1189,7 +1180,7 @@ lookup_window: return (wl); error: - xfree(winptr); + free(winptr); return (NULL); } diff --git a/control.c b/control.c index 52ccb202..3dc7bc2a 100644 --- a/control.c +++ b/control.c @@ -20,6 +20,7 @@ #include #include +#include #include #include "tmux.h" @@ -110,12 +111,12 @@ control_callback(struct client *c, int closed, unused void *data) if (cmd_string_parse(line, &cmdlist, &cause) != 0) { control_write(c, "%%error in line \"%s\": %s", line, cause); - xfree(cause); + free(cause); } else { cmd_list_exec(cmdlist, &ctx); cmd_list_free(cmdlist); } - xfree(line); + free(line); } } diff --git a/environ.c b/environ.c index 4c4af98f..2374d764 100644 --- a/environ.c +++ b/environ.c @@ -51,10 +51,9 @@ environ_free(struct environ *env) while (!RB_EMPTY(env)) { envent = RB_ROOT(env); RB_REMOVE(environ, env, envent); - xfree(envent->name); - if (envent->value != NULL) - xfree(envent->value); - xfree(envent); + free(envent->name); + free(envent->value); + free(envent); } } @@ -85,8 +84,7 @@ environ_set(struct environ *env, const char *name, const char *value) struct environ_entry *envent; if ((envent = environ_find(env, name)) != NULL) { - if (envent->value != NULL) - xfree(envent->value); + free(envent->value); if (value != NULL) envent->value = xstrdup(value); else @@ -117,7 +115,7 @@ environ_put(struct environ *env, const char *var) name[strcspn(name, "=")] = '\0'; environ_set(env, name, value); - xfree(name); + free(name); } /* Unset an environment variable. */ @@ -129,10 +127,9 @@ environ_unset(struct environ *env, const char *name) if ((envent = environ_find(env, name)) == NULL) return; RB_REMOVE(environ, env, envent); - xfree(envent->name); - if (envent->value != NULL) - xfree(envent->value); - xfree(envent); + free(envent->name); + free(envent->value); + free(envent); } /* @@ -152,7 +149,7 @@ environ_update(const char *vars, struct environ *srcenv, struct environ *dstenv) else environ_set(dstenv, envent->name, envent->value); } - xfree(copyvars); + free(copyvars); } /* Push environment into the real environment - use after fork(). */ diff --git a/format.c b/format.c index 8fe4acf4..bc638448 100644 --- a/format.c +++ b/format.c @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -102,12 +103,12 @@ format_free(struct format_tree *ft) fe_next = RB_NEXT(format_tree, ft, fe); RB_REMOVE(format_tree, ft, fe); - xfree(fe->value); - xfree(fe->key); - xfree(fe); + free(fe->value); + free(fe->key); + free(fe); } - xfree (ft); + free (ft); } /* Add a key-value pair. */ @@ -195,11 +196,11 @@ format_replace(struct format_tree *ft, memcpy(*buf + *off, value, valuelen); *off += valuelen; - xfree(copy); + free(copy); return (0); fail: - xfree(copy); + free(copy); return (-1); } @@ -351,8 +352,8 @@ format_winlink(struct format_tree *ft, struct session *s, struct winlink *wl) format_add(ft, "window_active", "%d", wl == s->curw); format_add(ft, "window_panes", "%u", window_count_panes(w)); - xfree(flags); - xfree(layout); + free(flags); + free(layout); } /* Set default format keys for a window pane. */ @@ -403,5 +404,5 @@ format_paste_buffer(struct format_tree *ft, struct paste_buffer *pb) format_add(ft, "buffer_size", "%zu", pb->size); format_add(ft, "buffer_sample", "%s", pb_print); - xfree(pb_print); + free(pb_print); } diff --git a/grid.c b/grid.c index a92f43f4..91ec7856 100644 --- a/grid.c +++ b/grid.c @@ -18,6 +18,7 @@ #include +#include #include #include "tmux.h" @@ -98,15 +99,13 @@ grid_destroy(struct grid *gd) for (yy = 0; yy < gd->hsize + gd->sy; yy++) { gl = &gd->linedata[yy]; - if (gl->celldata != NULL) - xfree(gl->celldata); - if (gl->utf8data != NULL) - xfree(gl->utf8data); + free(gl->celldata); + free(gl->utf8data); } - xfree(gd->linedata); + free(gd->linedata); - xfree(gd); + free(gd); } /* Compare grids. */ @@ -373,10 +372,8 @@ grid_clear_lines(struct grid *gd, u_int py, u_int ny) for (yy = py; yy < py + ny; yy++) { gl = &gd->linedata[yy]; - if (gl->celldata != NULL) - xfree(gl->celldata); - if (gl->utf8data != NULL) - xfree(gl->utf8data); + free(gl->celldata); + free(gl->utf8data); memset(gl, 0, sizeof *gl); } } diff --git a/input-keys.c b/input-keys.c index 11743b75..bd1c6157 100644 --- a/input-keys.c +++ b/input-keys.c @@ -164,7 +164,7 @@ input_key(struct window_pane *wp, int key) if (options_get_number(&wp->window->options, "xterm-keys")) { if ((out = xterm_keys_lookup(key)) != NULL) { bufferevent_write(wp->event, out, strlen(out)); - xfree(out); + free(out); return; } } diff --git a/input.c b/input.c index eee0f78d..7a9f0e48 100644 --- a/input.c +++ b/input.c @@ -853,7 +853,7 @@ input_reply(struct input_ctx *ictx, const char *fmt, ...) va_end(ap); bufferevent_write(ictx->wp->event, reply, strlen(reply)); - xfree(reply); + free(reply); } /* Clear saved state. */ diff --git a/job.c b/job.c index e2e8ab48..bc630128 100644 --- a/job.c +++ b/job.c @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -117,7 +118,7 @@ job_free(struct job *job) log_debug("free job %p: %s", job, job->cmd); LIST_REMOVE(job, lentry); - xfree(job->cmd); + free(job->cmd); if (job->freefn != NULL && job->data != NULL) job->freefn(job->data); @@ -129,7 +130,7 @@ job_free(struct job *job) if (job->fd != -1) close(job->fd); - xfree(job); + free(job); } /* Job buffer error callback. */ diff --git a/key-bindings.c b/key-bindings.c index 8511ea7c..8434cc03 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -90,7 +90,7 @@ key_bindings_clean(void) bd = RB_ROOT(&dead_key_bindings); RB_REMOVE(key_bindings, &dead_key_bindings, bd); cmd_list_free(bd->cmdlist); - xfree(bd); + free(bd); } } @@ -216,7 +216,7 @@ key_bindings_error(struct cmd_ctx *ctx, const char *fmt, ...) *msg = toupper((u_char) *msg); status_message_set(ctx->curclient, "%s", msg); - xfree(msg); + free(msg); } void printflike2 @@ -258,7 +258,7 @@ key_bindings_info(struct cmd_ctx *ctx, const char *fmt, ...) *msg = toupper((u_char) *msg); status_message_set(ctx->curclient, "%s", msg); - xfree(msg); + free(msg); } void diff --git a/layout.c b/layout.c index c803aef6..a0e624fb 100644 --- a/layout.c +++ b/layout.c @@ -78,7 +78,7 @@ layout_free_cell(struct layout_cell *lc) break; } - xfree(lc); + free(lc); } void @@ -781,8 +781,8 @@ layout_list_add(struct window *w) TAILQ_REMOVE(&w->layout_list, ll, entry); w->layout_list_size--; - xfree(ll->layout); - xfree(ll); + free(ll->layout); + free(ll); } } diff --git a/names.c b/names.c index a20d8cfc..de4b30cc 100644 --- a/names.c +++ b/names.c @@ -20,6 +20,7 @@ #include #include +#include #include #include @@ -73,12 +74,12 @@ window_name_callback(unused int fd, unused short events, void *data) wname = parse_window_name(name + 1); else wname = parse_window_name(name); - xfree(name); + free(name); } if (w->active->fd == -1) { xasprintf(&name, "%s[dead]", wname); - xfree(wname); + free(wname); wname = name; } @@ -86,7 +87,7 @@ window_name_callback(unused int fd, unused short events, void *data) window_set_name(w, wname); server_status_window(w); } - xfree(wname); + free(wname); } char * @@ -122,6 +123,6 @@ parse_window_name(const char *in) if (*name == '/') name = basename(name); name = xstrdup(name); - xfree(copy); + free(copy); return (name); } diff --git a/options.c b/options.c index 9298ab11..ec036741 100644 --- a/options.c +++ b/options.c @@ -19,6 +19,7 @@ #include #include +#include #include #include "tmux.h" @@ -51,10 +52,10 @@ options_free(struct options *oo) while (!RB_EMPTY(&oo->tree)) { o = RB_ROOT(&oo->tree); RB_REMOVE(options_tree, &oo->tree, o); - xfree(o->name); + free(o->name); if (o->type == OPTIONS_STRING) - xfree(o->str); - xfree(o); + free(o->str); + free(o); } } @@ -92,10 +93,10 @@ options_remove(struct options *oo, const char *name) return; RB_REMOVE(options_tree, &oo->tree, o); - xfree(o->name); + free(o->name); if (o->type == OPTIONS_STRING) - xfree(o->str); - xfree(o); + free(o->str); + free(o); } struct options_entry *printflike3 @@ -109,7 +110,7 @@ options_set_string(struct options *oo, const char *name, const char *fmt, ...) o->name = xstrdup(name); RB_INSERT(options_tree, &oo->tree, o); } else if (o->type == OPTIONS_STRING) - xfree(o->str); + free(o->str); va_start(ap, fmt); o->type = OPTIONS_STRING; @@ -140,7 +141,7 @@ options_set_number(struct options *oo, const char *name, long long value) o->name = xstrdup(name); RB_INSERT(options_tree, &oo->tree, o); } else if (o->type == OPTIONS_STRING) - xfree(o->str); + free(o->str); o->type = OPTIONS_NUMBER; o->num = value; diff --git a/paste.c b/paste.c index cc43d6e9..3dcd6008 100644 --- a/paste.c +++ b/paste.c @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -70,8 +71,8 @@ paste_free_top(struct paste_stack *ps) pb = ARRAY_FIRST(ps); ARRAY_REMOVE(ps, 0); - xfree(pb->data); - xfree(pb); + free(pb->data); + free(pb); return (0); } @@ -88,8 +89,8 @@ paste_free_index(struct paste_stack *ps, u_int idx) pb = ARRAY_ITEM(ps, idx); ARRAY_REMOVE(ps, idx); - xfree(pb->data); - xfree(pb); + free(pb->data); + free(pb); return (0); } @@ -108,8 +109,8 @@ paste_add(struct paste_stack *ps, char *data, size_t size, u_int limit) while (ARRAY_LENGTH(ps) >= limit) { pb = ARRAY_LAST(ps); - xfree(pb->data); - xfree(pb); + free(pb->data); + free(pb); ARRAY_TRUNC(ps, 1); } @@ -137,7 +138,7 @@ paste_replace(struct paste_stack *ps, u_int idx, char *data, size_t size) return (-1); pb = ARRAY_ITEM(ps, idx); - xfree(pb->data); + free(pb->data); pb->data = data; pb->size = size; diff --git a/screen-write.c b/screen-write.c index 90511e30..ee038e7d 100644 --- a/screen-write.c +++ b/screen-write.c @@ -18,6 +18,7 @@ #include +#include #include #include "tmux.h" @@ -102,8 +103,8 @@ screen_write_cstrlen(int utf8flag, const char *fmt, ...) size = screen_write_strlen(utf8flag, "%s", msg2); - xfree(msg); - xfree(msg2); + free(msg); + free(msg2); return (size); } @@ -141,7 +142,7 @@ screen_write_strlen(int utf8flag, const char *fmt, ...) } } - xfree(msg); + free(msg); return (size); } @@ -215,7 +216,7 @@ screen_write_vnputs(struct screen_write_ctx *ctx, ssize_t maxlen, } } - xfree(msg); + free(msg); } /* Write string, similar to nputs, but with embedded formatting (#[]). */ @@ -285,7 +286,7 @@ screen_write_cnputs(struct screen_write_ctx *ctx, } } - xfree(msg); + free(msg); } /* Parse an embedded style of the form "fg=colour,bg=colour,bright,...". */ diff --git a/screen.c b/screen.c index ed5fcfce..7ffe2a24 100644 --- a/screen.c +++ b/screen.c @@ -70,10 +70,9 @@ screen_reinit(struct screen *s) void screen_free(struct screen *s) { - if (s->tabs != NULL) - xfree(s->tabs); - xfree(s->title); - xfree(s->ccolour); + free(s->tabs); + free(s->title); + free(s->ccolour); grid_destroy(s->grid); } @@ -83,8 +82,7 @@ screen_reset_tabs(struct screen *s) { u_int i; - if (s->tabs != NULL) - xfree(s->tabs); + free(s->tabs); if ((s->tabs = bit_alloc(screen_size_x(s))) == NULL) fatal("bit_alloc failed"); @@ -104,7 +102,7 @@ screen_set_cursor_style(struct screen *s, u_int style) void screen_set_cursor_colour(struct screen *s, const char *colour_string) { - xfree(s->ccolour); + free(s->ccolour); s->ccolour = xstrdup(colour_string); } @@ -116,7 +114,7 @@ screen_set_title(struct screen *s, const char *title) strlcpy(tmp, title, sizeof tmp); - xfree(s->title); + free(s->title); s->title = xstrdup(tmp); } diff --git a/server-client.c b/server-client.c index 0e095af0..20f539ae 100644 --- a/server-client.c +++ b/server-client.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include "tmux.h" @@ -151,31 +152,25 @@ server_client_lost(struct client *c) status_free_jobs(&c->status_old); screen_free(&c->status); - if (c->title != NULL) - xfree(c->title); + free(c->title); evtimer_del(&c->repeat_timer); if (event_initialized(&c->identify_timer)) evtimer_del(&c->identify_timer); - if (c->message_string != NULL) - xfree(c->message_string); + free(c->message_string); if (event_initialized (&c->message_timer)) evtimer_del(&c->message_timer); for (i = 0; i < ARRAY_LENGTH(&c->message_log); i++) { msg = &ARRAY_ITEM(&c->message_log, i); - xfree(msg->msg); + free(msg->msg); } ARRAY_FREE(&c->message_log); - if (c->prompt_string != NULL) - xfree(c->prompt_string); - if (c->prompt_buffer != NULL) - xfree(c->prompt_buffer); - - if (c->cwd != NULL) - xfree(c->cwd); + free(c->prompt_string); + free(c->prompt_buffer); + free(c->cwd); environ_free(&c->environ); @@ -662,12 +657,11 @@ server_client_set_title(struct client *c) title = status_replace(c, NULL, NULL, NULL, template, time(NULL), 1); if (c->title == NULL || strcmp(title, c->title) != 0) { - if (c->title != NULL) - xfree(c->title); + free(c->title); c->title = xstrdup(title); tty_set_title(&c->tty, c->title); } - xfree(title); + free(title); } /* Dispatch message from client. */ diff --git a/server-fn.c b/server-fn.c index 1c55e16b..bea64178 100644 --- a/server-fn.c +++ b/server-fn.c @@ -18,6 +18,7 @@ #include +#include #include #include #include @@ -393,7 +394,7 @@ server_destroy_session_group(struct session *s) TAILQ_FOREACH(s, &sg->sessions, gentry) server_destroy_session(s); TAILQ_REMOVE(&session_groups, sg, entry); - xfree(sg); + free(sg); } } diff --git a/server-window.c b/server-window.c index c852acf1..8f3e2b63 100644 --- a/server-window.c +++ b/server-window.c @@ -19,6 +19,7 @@ #include #include +#include #include #include "tmux.h" @@ -211,7 +212,7 @@ server_window_check_content( return (0); if ((found = window_pane_search(wp, ptr, NULL)) == NULL) return (0); - xfree(found); + free(found); if (options_get_number(&s->options, "bell-on-alert")) ring_bell(s); diff --git a/server.c b/server.c index bc0e4ab9..740f71d9 100644 --- a/server.c +++ b/server.c @@ -162,7 +162,7 @@ server_start(int lockfd, char *lockfile) server_client_create(pair[1]); unlink(lockfile); - xfree(lockfile); + free(lockfile); close(lockfd); if (access(SYSTEM_CFG, R_OK) == 0) @@ -185,7 +185,7 @@ server_start(int lockfd, char *lockfile) for (i = 0; i < ARRAY_LENGTH(&cfg_causes); i++) { cause = ARRAY_ITEM(&cfg_causes, i); window_copy_add(wp, "%s", cause); - xfree(cause); + free(cause); } ARRAY_FREE(&cfg_causes); } @@ -275,8 +275,8 @@ server_clean_dead(void) next_s = RB_NEXT(sessions, &dead_sessions, s); if (s->references == 0) { RB_REMOVE(sessions, &dead_sessions, s); - xfree(s->name); - xfree(s); + free(s->name); + free(s); } s = next_s; } @@ -286,7 +286,7 @@ server_clean_dead(void) if (c == NULL || c->references != 0) continue; ARRAY_SET(&dead_clients, i, NULL); - xfree(c); + free(c); } } diff --git a/session.c b/session.c index 75ea8b0c..21929d8b 100644 --- a/session.c +++ b/session.c @@ -126,8 +126,7 @@ session_create(const char *name, const char *cmd, const char *cwd, s->name = NULL; do { s->idx = next_session++; - if (s->name != NULL) - xfree (s->name); + free (s->name); xasprintf(&s->name, "%u", s->idx); } while (RB_FIND(sessions, &sessions, s) != NULL); } @@ -157,8 +156,7 @@ session_destroy(struct session *s) RB_REMOVE(sessions, &sessions, s); notify_session_closed(s); - if (s->tio != NULL) - xfree(s->tio); + free(s->tio); session_group_remove(s); environ_free(&s->environ); @@ -172,7 +170,7 @@ session_destroy(struct session *s) winlink_remove(&s->windows, wl); } - xfree(s->cwd); + free(s->cwd); RB_INSERT(sessions, &dead_sessions, s); } @@ -495,7 +493,7 @@ session_group_remove(struct session *s) TAILQ_REMOVE(&sg->sessions, TAILQ_FIRST(&sg->sessions), gentry); if (TAILQ_EMPTY(&sg->sessions)) { TAILQ_REMOVE(&session_groups, sg, entry); - xfree(sg); + free(sg); } } diff --git a/status.c b/status.c index a1c23286..6cbdc6c4 100644 --- a/status.c +++ b/status.c @@ -222,8 +222,7 @@ status_redraw(struct client *c) /* Calculate the total size needed for the window list. */ wlstart = wloffset = wlwidth = 0; RB_FOREACH(wl, winlinks, &s->windows) { - if (wl->status_text != NULL) - xfree(wl->status_text); + free(wl->status_text); memcpy(&wl->status_cell, &stdgc, sizeof wl->status_cell); wl->status_text = status_print(c, wl, t, &wl->status_cell); wl->status_width = @@ -372,10 +371,8 @@ draw: screen_write_stop(&ctx); out: - if (left != NULL) - xfree(left); - if (right != NULL) - xfree(right); + free(left); + free(right); if (grid_compare(c->status.grid, old_status.grid) == 0) { screen_free(&old_status); @@ -491,8 +488,7 @@ do_replace: } out: - if (freeptr != NULL) - xfree(freeptr); + free(freeptr); return; skip_to: @@ -572,7 +568,7 @@ status_find_job(struct client *c, char **iptr) cmd[len++] = **iptr; } if (**iptr == '\0') /* no terminating ) */ { - xfree(cmd); + free(cmd); return (NULL); } (*iptr)++; /* skip final ) */ @@ -582,7 +578,7 @@ status_find_job(struct client *c, char **iptr) so_find.cmd = cmd; so = RB_FIND(status_out_tree, &c->status_new, &so_find); if (so != NULL && so->out != NULL) { - xfree(cmd); + free(cmd); return (so->out); } @@ -600,7 +596,7 @@ status_find_job(struct client *c, char **iptr) /* Lookup in the old tree. */ so_find.cmd = cmd; so = RB_FIND(status_out_tree, &c->status_old, &so_find); - xfree(cmd); + free(cmd); if (so != NULL) return (so->out); return (NULL); @@ -618,10 +614,9 @@ status_free_jobs(struct status_out_tree *sotree) so_next = RB_NEXT(status_out_tree, sotree, so); RB_REMOVE(status_out_tree, sotree, so); - if (so->out != NULL) - xfree(so->out); - xfree(so->cmd); - xfree(so); + free(so->out); + free(so->cmd); + free(so); } } @@ -778,7 +773,7 @@ status_message_set(struct client *c, const char *fmt, ...) limit = ARRAY_LENGTH(&c->message_log) - limit; for (i = 0; i < limit; i++) { msg = &ARRAY_FIRST(&c->message_log); - xfree(msg->msg); + free(msg->msg); ARRAY_REMOVE(&c->message_log, 0); } } @@ -803,7 +798,7 @@ status_message_clear(struct client *c) if (c->message_string == NULL) return; - xfree(c->message_string); + free(c->message_string); c->message_string = NULL; c->tty.flags &= ~(TTY_NOCURSOR|TTY_FREEZE); @@ -912,10 +907,10 @@ status_prompt_clear(struct client *c) if (c->prompt_freefn != NULL && c->prompt_data != NULL) c->prompt_freefn(c->prompt_data); - xfree(c->prompt_string); + free(c->prompt_string); c->prompt_string = NULL; - xfree(c->prompt_buffer); + free(c->prompt_buffer); c->prompt_buffer = NULL; c->tty.flags &= ~(TTY_NOCURSOR|TTY_FREEZE); @@ -928,11 +923,11 @@ status_prompt_clear(struct client *c) void status_prompt_update(struct client *c, const char *msg, const char *input) { - xfree(c->prompt_string); + free(c->prompt_string); c->prompt_string = status_replace(c, NULL, NULL, NULL, msg, time(NULL), 0); - xfree(c->prompt_buffer); + free(c->prompt_buffer); c->prompt_buffer = status_replace(c, NULL, NULL, NULL, input, time(NULL), 0); c->prompt_index = strlen(c->prompt_buffer); @@ -1109,7 +1104,7 @@ status_prompt_key(struct client *c, int key) memcpy(first, s, strlen(s)); c->prompt_index = (first - c->prompt_buffer) + strlen(s); - xfree(s); + free(s); c->flags |= CLIENT_STATUS; break; @@ -1250,7 +1245,7 @@ status_prompt_key(struct client *c, int key) histstr = status_prompt_up_history(&c->prompt_hindex); if (histstr == NULL) break; - xfree(c->prompt_buffer); + free(c->prompt_buffer); c->prompt_buffer = xstrdup(histstr); c->prompt_index = strlen(c->prompt_buffer); c->flags |= CLIENT_STATUS; @@ -1259,7 +1254,7 @@ status_prompt_key(struct client *c, int key) histstr = status_prompt_down_history(&c->prompt_hindex); if (histstr == NULL) break; - xfree(c->prompt_buffer); + free(c->prompt_buffer); c->prompt_buffer = xstrdup(histstr); c->prompt_index = strlen(c->prompt_buffer); c->flags |= CLIENT_STATUS; @@ -1383,7 +1378,7 @@ status_prompt_add_history(const char *line) return; if (size == PROMPT_HISTORY) { - xfree(ARRAY_FIRST(&status_prompt_history)); + free(ARRAY_FIRST(&status_prompt_history)); ARRAY_REMOVE(&status_prompt_history, 0); } diff --git a/tmux.c b/tmux.c index 9a305c02..e01017c9 100644 --- a/tmux.c +++ b/tmux.c @@ -73,7 +73,7 @@ logfile(const char *name) if (debug_level > 0) { xasprintf(&path, "tmux-%s-%ld.log", name, (long) getpid()); log_open(debug_level, path); - xfree(path); + free(path); } } @@ -252,8 +252,7 @@ main(int argc, char **argv) flags &= ~IDENTIFY_256COLOURS; break; case 'c': - if (shell_cmd != NULL) - xfree(shell_cmd); + free(shell_cmd); shell_cmd = xstrdup(optarg); break; case 'C': @@ -263,24 +262,21 @@ main(int argc, char **argv) flags |= IDENTIFY_CONTROL; break; case 'f': - if (cfg_file != NULL) - xfree(cfg_file); + free(cfg_file); cfg_file = xstrdup(optarg); break; case 'l': login_shell = 1; break; case 'L': - if (label != NULL) - xfree(label); + free(label); label = xstrdup(optarg); break; case 'q': quiet = 1; break; case 'S': - if (path != NULL) - xfree(path); + free(path); path = xstrdup(optarg); break; case 'u': @@ -360,7 +356,7 @@ main(int argc, char **argv) } xasprintf(&cfg_file, "%s/%s", home, DEFAULT_CFG); if (access(cfg_file, R_OK) != 0 && errno == ENOENT) { - xfree(cfg_file); + free(cfg_file); cfg_file = NULL; } } @@ -387,11 +383,10 @@ main(int argc, char **argv) } } } - if (label != NULL) - xfree(label); + free(label); if (realpath(path, socket_path) == NULL) strlcpy(socket_path, path, sizeof socket_path); - xfree(path); + free(path); /* Set process title. */ setproctitle("%s (%s)", __progname, socket_path); diff --git a/tmux.h b/tmux.h index 02237f8a..2538a97f 100644 --- a/tmux.h +++ b/tmux.h @@ -2224,7 +2224,6 @@ char *xstrdup(const char *); void *xcalloc(size_t, size_t); void *xmalloc(size_t); void *xrealloc(void *, size_t, size_t); -void xfree(void *); int printflike2 xasprintf(char **, const char *, ...); int xvasprintf(char **, const char *, va_list); int printflike3 xsnprintf(char *, size_t, const char *, ...); diff --git a/tty-keys.c b/tty-keys.c index 9390981e..c90eb71e 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -384,7 +384,7 @@ tty_keys_free1(struct tty_key *tk) tty_keys_free1(tk->left); if (tk->right != NULL) tty_keys_free1(tk->right); - xfree(tk); + free(tk); } /* Lookup a key in the tree. */ diff --git a/tty-term.c b/tty-term.c index d79cbf2f..f088d251 100644 --- a/tty-term.c +++ b/tty-term.c @@ -252,7 +252,7 @@ tty_term_override(struct tty_term *term, const char *overrides) *ptr++ = '\0'; val = xstrdup(ptr); if (strunvis(val, ptr) == -1) { - xfree(val); + free(val); val = xstrdup(ptr); } } else if (entstr[strlen(entstr) - 1] == '@') { @@ -278,7 +278,7 @@ tty_term_override(struct tty_term *term, const char *overrides) break; case TTYCODE_STRING: if (code->type == TTYCODE_STRING) - xfree(code->value.string); + free(code->value.string); code->value.string = xstrdup(val); code->type = ent->type; break; @@ -296,12 +296,11 @@ tty_term_override(struct tty_term *term, const char *overrides) } } - if (val != NULL) - xfree(val); + free(val); } } - xfree(s); + free(s); } struct tty_term * @@ -463,10 +462,10 @@ tty_term_free(struct tty_term *term) for (i = 0; i < NTTYCODE; i++) { if (term->codes[i].type == TTYCODE_STRING) - xfree(term->codes[i].value.string); + free(term->codes[i].value.string); } - xfree(term->name); - xfree(term); + free(term->name); + free(term); } int diff --git a/tty.c b/tty.c index ca65bdb3..d40e95d7 100644 --- a/tty.c +++ b/tty.c @@ -345,11 +345,11 @@ tty_free(struct tty *tty) { tty_close(tty); - xfree(tty->ccolour); + free(tty->ccolour); if (tty->path != NULL) - xfree(tty->path); + free(tty->path); if (tty->termname != NULL) - xfree(tty->termname); + free(tty->termname); } void @@ -468,7 +468,7 @@ tty_force_cursor_colour(struct tty *tty, const char *ccolour) tty_putcode(tty, TTYC_CR); else tty_putcode_ptr1(tty, TTYC_CC, ccolour); - xfree(tty->ccolour); + free(tty->ccolour); tty->ccolour = xstrdup(ccolour); } @@ -1099,7 +1099,7 @@ tty_cmd_setselection(struct tty *tty, const struct tty_ctx *ctx) b64_ntop(ctx->ptr, ctx->num, buf, off); tty_putcode_ptr2(tty, TTYC_MS, "", buf); - xfree(buf); + free(buf); } void diff --git a/window-choose.c b/window-choose.c index ed951661..58ac80ee 100644 --- a/window-choose.c +++ b/window-choose.c @@ -19,6 +19,7 @@ #include #include +#include #include #include "tmux.h" @@ -152,12 +153,12 @@ window_choose_free(struct window_pane *wp) item = &ARRAY_ITEM(&data->list, i); if (data->freefn != NULL && item->wcd != NULL) data->freefn(item->wcd); - xfree(item->name); + free(item->name); } ARRAY_FREE(&data->list); screen_free(&data->screen); - xfree(data); + free(data); } void @@ -493,7 +494,7 @@ window_choose_ctx(struct window_choose_data *cdata) if (cause != NULL) { *cause = toupper((u_char) *cause); status_message_set(cdata->client, "%s", cause); - xfree(cause); + free(cause); } return; } @@ -544,7 +545,7 @@ window_choose_add_window(struct window_pane *wp, struct cmd_ctx *ctx, xasprintf(&action_data, "%s:%d", s->name, wl->idx); wcd->command = cmd_template_replace(action, action_data, 1); - xfree(action_data); + free(action_data); wcd->idx = wl->idx; wcd->ft_template = xstrdup(template); diff --git a/window-clock.c b/window-clock.c index 64980df0..b6dc87e9 100644 --- a/window-clock.c +++ b/window-clock.c @@ -18,6 +18,7 @@ #include +#include #include #include @@ -69,7 +70,7 @@ window_clock_free(struct window_pane *wp) struct window_clock_mode_data *data = wp->modedata; screen_free(&data->screen); - xfree(data); + free(data); } void diff --git a/window-copy.c b/window-copy.c index cbd0bb6a..089974f1 100644 --- a/window-copy.c +++ b/window-copy.c @@ -240,17 +240,16 @@ window_copy_free(struct window_pane *wp) if (wp->fd != -1) bufferevent_enable(wp->event, EV_READ|EV_WRITE); - if (data->searchstr != NULL) - xfree(data->searchstr); - xfree(data->inputstr); + free(data->searchstr); + free(data->inputstr); if (data->backing != &wp->base) { screen_free(data->backing); - xfree(data->backing); + free(data->backing); } screen_free(&data->screen); - xfree(data); + free(data); } void @@ -1379,7 +1378,7 @@ window_copy_copy_selection(struct window_pane *wp, int idx) /* Don't bother if no data. */ if (off == 0) { - xfree(buf); + free(buf); return; } off--; /* remove final \n */ diff --git a/window.c b/window.c index cf13c906..cf738a1d 100644 --- a/window.c +++ b/window.c @@ -179,9 +179,8 @@ winlink_remove(struct winlinks *wwl, struct winlink *wl) struct window *w = wl->window; RB_REMOVE(winlinks, wwl, wl); - if (wl->status_text != NULL) - xfree(wl->status_text); - xfree(wl); + free(wl->status_text); + free(wl); if (w != NULL) { if (w->references == 0) @@ -359,16 +358,14 @@ window_destroy(struct window *w) window_destroy_panes(w); - if (w->name != NULL) - xfree(w->name); - xfree(w); + free(w->name); + free(w); } void window_set_name(struct window *w, const char *new_name) { - if (w->name != NULL) - xfree(w->name); + free(w->name); w->name = xstrdup(new_name); notify_window_renamed(w); } @@ -671,13 +668,10 @@ window_pane_destroy(struct window_pane *wp) RB_REMOVE(window_pane_tree, &all_window_panes, wp); - if (wp->cwd != NULL) - xfree(wp->cwd); - if (wp->shell != NULL) - xfree(wp->shell); - if (wp->cmd != NULL) - xfree(wp->cmd); - xfree(wp); + free(wp->cwd); + free(wp->shell); + free(wp->cmd); + free(wp); } int @@ -694,18 +688,15 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell, close(wp->fd); } if (cmd != NULL) { - if (wp->cmd != NULL) - xfree(wp->cmd); + free(wp->cmd); wp->cmd = xstrdup(cmd); } if (shell != NULL) { - if (wp->shell != NULL) - xfree(wp->shell); + free(wp->shell); wp->shell = xstrdup(shell); } if (cwd != NULL) { - if (wp->cwd != NULL) - xfree(wp->cwd); + free(wp->cwd); wp->cwd = xstrdup(cwd); } @@ -1048,10 +1039,10 @@ window_pane_search(struct window_pane *wp, const char *searchstr, u_int *lineno) *lineno = i; break; } - xfree(line); + free(line); } - xfree(newsearchstr); + free(newsearchstr); return (msg); } diff --git a/xmalloc.c b/xmalloc.c index 43b0080d..cb734edc 100644 --- a/xmalloc.c +++ b/xmalloc.c @@ -83,14 +83,6 @@ xrealloc(void *oldptr, size_t nmemb, size_t size) return (newptr); } -void -xfree(void *ptr) -{ - if (ptr == NULL) - fatalx("null pointer"); - free(ptr); -} - int printflike2 xasprintf(char **ret, const char *fmt, ...) { From ede8312d59c5d08990f83f38682c26434823525b Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 11 Jul 2012 07:10:15 +0000 Subject: [PATCH 1150/1180] Make command exec functions return an enum rather than -1/0/1 values and add a new value to mean "leave client running but don't attach" to fix problems with using some commands in a command sequence. Most of the work by Thomas Adam, problem reported by "jspenguin" on SF bug 3535531. --- cfg.c | 18 ++++++++++++++---- cmd-attach-session.c | 14 +++++++------- cmd-bind-key.c | 32 ++++++++++++++++---------------- cmd-break-pane.c | 10 +++++----- cmd-capture-pane.c | 14 +++++++------- cmd-choose-buffer.c | 14 +++++++------- cmd-choose-client.c | 12 ++++++------ cmd-choose-tree.c | 11 +++++------ cmd-clear-history.c | 8 ++++---- cmd-clock-mode.c | 8 ++++---- cmd-command-prompt.c | 10 +++++----- cmd-confirm-before.c | 16 ++++++++-------- cmd-copy-mode.c | 12 ++++++------ cmd-delete-buffer.c | 12 ++++++------ cmd-detach-client.c | 10 +++++----- cmd-display-message.c | 14 +++++++------- cmd-display-panes.c | 8 ++++---- cmd-find-window.c | 12 ++++++------ cmd-has-session.c | 8 ++++---- cmd-if-shell.c | 6 +++--- cmd-join-pane.c | 26 +++++++++++++------------- cmd-kill-pane.c | 10 +++++----- cmd-kill-server.c | 6 +++--- cmd-kill-session.c | 8 ++++---- cmd-kill-window.c | 8 ++++---- cmd-link-window.c | 12 ++++++------ cmd-list-buffers.c | 6 +++--- cmd-list-clients.c | 6 +++--- cmd-list-commands.c | 6 +++--- cmd-list-keys.c | 13 ++++++------- cmd-list-panes.c | 10 +++++----- cmd-list-sessions.c | 6 +++--- cmd-list-windows.c | 8 ++++---- cmd-list.c | 34 +++++++++++++++++++--------------- cmd-load-buffer.c | 22 +++++++++++----------- cmd-lock-server.c | 10 +++++----- cmd-move-window.c | 16 ++++++++-------- cmd-new-session.c | 28 ++++++++++++++-------------- cmd-new-window.c | 12 ++++++------ cmd-paste-buffer.c | 12 ++++++------ cmd-pipe-pane.c | 16 ++++++++-------- cmd-refresh-client.c | 8 ++++---- cmd-rename-session.c | 12 ++++++------ cmd-rename-window.c | 8 ++++---- cmd-resize-pane.c | 12 ++++++------ cmd-respawn-pane.c | 12 ++++++------ cmd-respawn-window.c | 12 ++++++------ cmd-rotate-window.c | 10 +++++----- cmd-run-shell.c | 11 +++++------ cmd-save-buffer.c | 18 +++++++++--------- cmd-select-layout.c | 22 +++++++++++----------- cmd-select-pane.c | 20 ++++++++++---------- cmd-select-window.c | 18 +++++++++--------- cmd-send-keys.c | 8 ++++---- cmd-send-prefix.c | 8 ++++---- cmd-server-info.c | 6 +++--- cmd-set-buffer.c | 12 ++++++------ cmd-set-environment.c | 18 +++++++++--------- cmd-set-option.c | 22 +++++++++++----------- cmd-show-buffer.c | 14 +++++++------- cmd-show-environment.c | 12 ++++++------ cmd-show-messages.c | 8 ++++---- cmd-show-options.c | 16 ++++++++-------- cmd-source-file.c | 4 ++-- cmd-split-window.c | 12 ++++++------ cmd-start-server.c | 6 +++--- cmd-suspend-client.c | 8 ++++---- cmd-swap-pane.c | 16 ++++++++-------- cmd-swap-window.c | 12 ++++++------ cmd-switch-client.c | 18 +++++++++--------- cmd-unbind-key.c | 31 +++++++++++++++---------------- cmd-unlink-window.c | 10 +++++----- cmd.c | 2 +- server-client.c | 10 +++++++++- tmux.h | 13 ++++++++++--- 75 files changed, 489 insertions(+), 464 deletions(-) diff --git a/cfg.c b/cfg.c index 733238f3..ead99818 100644 --- a/cfg.c +++ b/cfg.c @@ -81,7 +81,7 @@ load_cfg(const char *path, struct cmd_ctx *ctxin, struct causelist *causes) size_t len; struct cmd_list *cmdlist; struct cmd_ctx ctx; - int retval; + enum cmd_retval retval; if ((f = fopen(path, "rb")) == NULL) { cfg_add_cause(causes, "%s: %s", path, strerror(errno)); @@ -90,7 +90,7 @@ load_cfg(const char *path, struct cmd_ctx *ctxin, struct causelist *causes) n = 0; line = NULL; - retval = 0; + retval = CMD_RETURN_NORMAL; while ((buf = fgetln(f, &len))) { if (buf[len - 1] == '\n') len--; @@ -145,8 +145,18 @@ load_cfg(const char *path, struct cmd_ctx *ctxin, struct causelist *causes) ctx.info = cfg_print; cfg_cause = NULL; - if (cmd_list_exec(cmdlist, &ctx) == 1) - retval = 1; + switch (cmd_list_exec(cmdlist, &ctx)) { + case CMD_RETURN_YIELD: + if (retval != CMD_RETURN_ATTACH) + retval = CMD_RETURN_YIELD; + break; + case CMD_RETURN_ATTACH: + retval = CMD_RETURN_ATTACH; + break; + case CMD_RETURN_ERROR: + case CMD_RETURN_NORMAL: + break; + } cmd_list_free(cmdlist); if (cfg_cause != NULL) { cfg_add_cause( diff --git a/cmd-attach-session.c b/cmd-attach-session.c index 42ef89ce..30451389 100644 --- a/cmd-attach-session.c +++ b/cmd-attach-session.c @@ -26,7 +26,7 @@ * Attach existing session to the current terminal. */ -int cmd_attach_session_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_attach_session_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_attach_session_entry = { "attach-session", "attach", @@ -38,7 +38,7 @@ const struct cmd_entry cmd_attach_session_entry = { cmd_attach_session_exec }; -int +enum cmd_retval cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; @@ -50,14 +50,14 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx) if (RB_EMPTY(&sessions)) { ctx->error(ctx, "no sessions"); - return (-1); + return (CMD_RETURN_ERROR); } if ((s = cmd_find_session(ctx, args_get(args, 't'), 1)) == NULL) - return (-1); + return (CMD_RETURN_ERROR); if (ctx->cmdclient == NULL && ctx->curclient == NULL) - return (0); + return (CMD_RETURN_NORMAL); if (ctx->cmdclient == NULL) { if (args_has(self->args, 'd')) { @@ -84,7 +84,7 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx) if (server_client_open(ctx->cmdclient, s, &cause) != 0) { ctx->error(ctx, "open terminal failed: %s", cause); free(cause); - return (-1); + return (CMD_RETURN_ERROR); } if (args_has(self->args, 'r')) @@ -107,5 +107,5 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx) recalculate_sizes(); server_update_socket(); - return (1); /* 1 means don't tell command client to exit */ + return (CMD_RETURN_ATTACH); } diff --git a/cmd-bind-key.c b/cmd-bind-key.c index 980e7ec9..909f4839 100644 --- a/cmd-bind-key.c +++ b/cmd-bind-key.c @@ -27,10 +27,10 @@ * Bind a key to a command, this recurses through cmd_*. */ -int cmd_bind_key_check(struct args *); -int cmd_bind_key_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_bind_key_check(struct args *); +enum cmd_retval cmd_bind_key_exec(struct cmd *, struct cmd_ctx *); -int cmd_bind_key_table(struct cmd *, struct cmd_ctx *, int); +enum cmd_retval cmd_bind_key_table(struct cmd *, struct cmd_ctx *, int); const struct cmd_entry cmd_bind_key_entry = { "bind-key", "bind", @@ -42,20 +42,20 @@ const struct cmd_entry cmd_bind_key_entry = { cmd_bind_key_exec }; -int +enum cmd_retval cmd_bind_key_check(struct args *args) { if (args_has(args, 't')) { if (args->argc != 2) - return (-1); + return (CMD_RETURN_ERROR); } else { if (args->argc < 2) - return (-1); + return (CMD_RETURN_ERROR); } - return (0); + return (CMD_RETURN_NORMAL); } -int +enum cmd_retval cmd_bind_key_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; @@ -66,7 +66,7 @@ cmd_bind_key_exec(struct cmd *self, struct cmd_ctx *ctx) key = key_string_lookup_string(args->argv[0]); if (key == KEYC_NONE) { ctx->error(ctx, "unknown key: %s", args->argv[0]); - return (-1); + return (CMD_RETURN_ERROR); } if (args_has(args, 't')) @@ -76,16 +76,16 @@ cmd_bind_key_exec(struct cmd *self, struct cmd_ctx *ctx) if (cmdlist == NULL) { ctx->error(ctx, "%s", cause); free(cause); - return (-1); + return (CMD_RETURN_ERROR); } if (!args_has(args, 'n')) key |= KEYC_PREFIX; key_bindings_add(key, args_has(args, 'r'), cmdlist); - return (0); + return (CMD_RETURN_NORMAL); } -int +enum cmd_retval cmd_bind_key_table(struct cmd *self, struct cmd_ctx *ctx, int key) { struct args *args = self->args; @@ -97,25 +97,25 @@ cmd_bind_key_table(struct cmd *self, struct cmd_ctx *ctx, int key) tablename = args_get(args, 't'); if ((mtab = mode_key_findtable(tablename)) == NULL) { ctx->error(ctx, "unknown key table: %s", tablename); - return (-1); + return (CMD_RETURN_ERROR); } cmd = mode_key_fromstring(mtab->cmdstr, args->argv[1]); if (cmd == MODEKEY_NONE) { ctx->error(ctx, "unknown command: %s", args->argv[1]); - return (-1); + return (CMD_RETURN_ERROR); } mtmp.key = key; mtmp.mode = !!args_has(args, 'c'); if ((mbind = RB_FIND(mode_key_tree, mtab->tree, &mtmp)) != NULL) { mbind->cmd = cmd; - return (0); + return (CMD_RETURN_NORMAL); } mbind = xmalloc(sizeof *mbind); mbind->key = mtmp.key; mbind->mode = mtmp.mode; mbind->cmd = cmd; RB_INSERT(mode_key_tree, mtab->tree, mbind); - return (0); + return (CMD_RETURN_NORMAL); } diff --git a/cmd-break-pane.c b/cmd-break-pane.c index bcb6e6b9..5ddb8362 100644 --- a/cmd-break-pane.c +++ b/cmd-break-pane.c @@ -26,7 +26,7 @@ * Break pane off into a window. */ -int cmd_break_pane_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_break_pane_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_break_pane_entry = { "break-pane", "breakp", @@ -38,7 +38,7 @@ const struct cmd_entry cmd_break_pane_entry = { cmd_break_pane_exec }; -int +enum cmd_retval cmd_break_pane_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; @@ -55,11 +55,11 @@ cmd_break_pane_exec(struct cmd *self, struct cmd_ctx *ctx) char *cp; if ((wl = cmd_find_pane(ctx, args_get(args, 't'), &s, &wp)) == NULL) - return (-1); + return (CMD_RETURN_ERROR); if (window_count_panes(wl->window) == 1) { ctx->error(ctx, "can't break with only one pane"); - return (-1); + return (CMD_RETURN_ERROR); } w = wl->window; @@ -110,5 +110,5 @@ cmd_break_pane_exec(struct cmd *self, struct cmd_ctx *ctx) format_free(ft); } - return (0); + return (CMD_RETURN_NORMAL); } diff --git a/cmd-capture-pane.c b/cmd-capture-pane.c index 236a51ca..f38fcb76 100644 --- a/cmd-capture-pane.c +++ b/cmd-capture-pane.c @@ -27,7 +27,7 @@ * Write the entire contents of a pane to a buffer. */ -int cmd_capture_pane_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_capture_pane_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_capture_pane_entry = { "capture-pane", "capturep", @@ -39,7 +39,7 @@ const struct cmd_entry cmd_capture_pane_entry = { cmd_capture_pane_exec }; -int +enum cmd_retval cmd_capture_pane_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; @@ -52,7 +52,7 @@ cmd_capture_pane_exec(struct cmd *self, struct cmd_ctx *ctx) size_t len, linelen; if (cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp) == NULL) - return (-1); + return (CMD_RETURN_ERROR); s = &wp->base; gd = s->grid; @@ -103,7 +103,7 @@ cmd_capture_pane_exec(struct cmd *self, struct cmd_ctx *ctx) if (!args_has(args, 'b')) { paste_add(&global_buffers, buf, len, limit); - return (0); + return (CMD_RETURN_NORMAL); } buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause); @@ -111,14 +111,14 @@ cmd_capture_pane_exec(struct cmd *self, struct cmd_ctx *ctx) ctx->error(ctx, "buffer %s", cause); free(buf); free(cause); - return (-1); + return (CMD_RETURN_ERROR); } if (paste_replace(&global_buffers, buffer, buf, len) != 0) { ctx->error(ctx, "no buffer %d", buffer); free(buf); - return (-1); + return (CMD_RETURN_ERROR); } - return (0); + return (CMD_RETURN_NORMAL); } diff --git a/cmd-choose-buffer.c b/cmd-choose-buffer.c index 6c62cfa3..3deedfa9 100644 --- a/cmd-choose-buffer.c +++ b/cmd-choose-buffer.c @@ -27,7 +27,7 @@ * Enter choice mode to choose a buffer. */ -int cmd_choose_buffer_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_choose_buffer_exec(struct cmd *, struct cmd_ctx *); void cmd_choose_buffer_callback(struct window_choose_data *); void cmd_choose_buffer_free(struct window_choose_data *); @@ -42,7 +42,7 @@ const struct cmd_entry cmd_choose_buffer_entry = { cmd_choose_buffer_exec }; -int +enum cmd_retval cmd_choose_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; @@ -55,20 +55,20 @@ cmd_choose_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) if (ctx->curclient == NULL) { ctx->error(ctx, "must be run interactively"); - return (-1); + return (CMD_RETURN_ERROR); } if ((template = args_get(args, 'F')) == NULL) template = DEFAULT_BUFFER_LIST_TEMPLATE; if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL) - return (-1); + return (CMD_RETURN_ERROR); if (paste_get_top(&global_buffers) == NULL) - return (0); + return (CMD_RETURN_NORMAL); if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0) - return (0); + return (CMD_RETURN_NORMAL); if (args->argc != 0) action = xstrdup(args->argv[0]); @@ -96,7 +96,7 @@ cmd_choose_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) window_choose_ready(wl->window->active, 0, cmd_choose_buffer_callback, cmd_choose_buffer_free); - return (0); + return (CMD_RETURN_NORMAL); } void diff --git a/cmd-choose-client.c b/cmd-choose-client.c index a20fec42..4059cbba 100644 --- a/cmd-choose-client.c +++ b/cmd-choose-client.c @@ -27,7 +27,7 @@ * Enter choice mode to choose a client. */ -int cmd_choose_client_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_choose_client_exec(struct cmd *, struct cmd_ctx *); void cmd_choose_client_callback(struct window_choose_data *); void cmd_choose_client_free(struct window_choose_data *); @@ -47,7 +47,7 @@ struct cmd_choose_client_data { char *template; }; -int +enum cmd_retval cmd_choose_client_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; @@ -60,14 +60,14 @@ cmd_choose_client_exec(struct cmd *self, struct cmd_ctx *ctx) if (ctx->curclient == NULL) { ctx->error(ctx, "must be run interactively"); - return (-1); + return (CMD_RETURN_ERROR); } if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL) - return (-1); + return (CMD_RETURN_ERROR); if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0) - return (0); + return (CMD_RETURN_NORMAL); if ((template = args_get(args, 'F')) == NULL) template = DEFAULT_CLIENT_TEMPLATE; @@ -104,7 +104,7 @@ cmd_choose_client_exec(struct cmd *self, struct cmd_ctx *ctx) window_choose_ready(wl->window->active, cur, cmd_choose_client_callback, cmd_choose_client_free); - return (0); + return (CMD_RETURN_NORMAL); } void diff --git a/cmd-choose-tree.c b/cmd-choose-tree.c index 0389bea3..166684f8 100644 --- a/cmd-choose-tree.c +++ b/cmd-choose-tree.c @@ -70,7 +70,7 @@ const struct cmd_entry cmd_choose_window_entry = { cmd_choose_tree_exec }; -int +enum cmd_retval cmd_choose_tree_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; @@ -89,17 +89,17 @@ cmd_choose_tree_exec(struct cmd *self, struct cmd_ctx *ctx) if (ctx->curclient == NULL) { ctx->error(ctx, "must be run interactively"); - return (-1); + return (CMD_RETURN_ERROR); } s = ctx->curclient->session; tty = &ctx->curclient->tty; if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL) - return (-1); + return (CMD_RETURN_ERROR); if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0) - return (0); + return (CMD_RETURN_NORMAL); /* Sort out which command this is. */ wflag = sflag = 0; @@ -221,7 +221,7 @@ windows_only: window_choose_ready(wl->window->active, cur_win, cmd_choose_tree_callback, cmd_choose_tree_free); - return (0); + return (CMD_RETURN_NORMAL); } void @@ -248,4 +248,3 @@ cmd_choose_tree_free(struct window_choose_data *cdata) free(cdata); } - diff --git a/cmd-clear-history.c b/cmd-clear-history.c index cf3da229..8a88e46c 100644 --- a/cmd-clear-history.c +++ b/cmd-clear-history.c @@ -24,7 +24,7 @@ * Clear pane history. */ -int cmd_clear_history_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_clear_history_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_clear_history_entry = { "clear-history", "clearhist", @@ -36,7 +36,7 @@ const struct cmd_entry cmd_clear_history_entry = { cmd_clear_history_exec }; -int +enum cmd_retval cmd_clear_history_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; @@ -44,11 +44,11 @@ cmd_clear_history_exec(struct cmd *self, struct cmd_ctx *ctx) struct grid *gd; if (cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp) == NULL) - return (-1); + return (CMD_RETURN_ERROR); gd = wp->base.grid; grid_move_lines(gd, 0, gd->hsize, gd->sy); gd->hsize = 0; - return (0); + return (CMD_RETURN_NORMAL); } diff --git a/cmd-clock-mode.c b/cmd-clock-mode.c index 0dc151d1..f1d9eceb 100644 --- a/cmd-clock-mode.c +++ b/cmd-clock-mode.c @@ -24,7 +24,7 @@ * Enter clock mode. */ -int cmd_clock_mode_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_clock_mode_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_clock_mode_entry = { "clock-mode", NULL, @@ -36,16 +36,16 @@ const struct cmd_entry cmd_clock_mode_entry = { cmd_clock_mode_exec }; -int +enum cmd_retval cmd_clock_mode_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; struct window_pane *wp; if (cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp) == NULL) - return (-1); + return (CMD_RETURN_ERROR); window_pane_set_mode(wp, &window_clock_mode); - return (0); + return (CMD_RETURN_NORMAL); } diff --git a/cmd-command-prompt.c b/cmd-command-prompt.c index 3105744f..6c3df4ef 100644 --- a/cmd-command-prompt.c +++ b/cmd-command-prompt.c @@ -31,7 +31,7 @@ void cmd_command_prompt_key_binding(struct cmd *, int); int cmd_command_prompt_check(struct args *); -int cmd_command_prompt_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_command_prompt_exec(struct cmd *, struct cmd_ctx *); int cmd_command_prompt_callback(void *, const char *); void cmd_command_prompt_free(void *); @@ -84,7 +84,7 @@ cmd_command_prompt_key_binding(struct cmd *self, int key) } } -int +enum cmd_retval cmd_command_prompt_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; @@ -95,10 +95,10 @@ cmd_command_prompt_exec(struct cmd *self, struct cmd_ctx *ctx) size_t n; if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL) - return (-1); + return (CMD_RETURN_ERROR); if (c->prompt_string != NULL) - return (0); + return (CMD_RETURN_NORMAL); cdata = xmalloc(sizeof *cdata); cdata->c = c; @@ -141,7 +141,7 @@ cmd_command_prompt_exec(struct cmd *self, struct cmd_ctx *ctx) cmd_command_prompt_free, cdata, 0); free(prompt); - return (0); + return (CMD_RETURN_NORMAL); } int diff --git a/cmd-confirm-before.c b/cmd-confirm-before.c index 78c6bac4..16607d0e 100644 --- a/cmd-confirm-before.c +++ b/cmd-confirm-before.c @@ -26,11 +26,11 @@ * Asks for confirmation before executing a command. */ -void cmd_confirm_before_key_binding(struct cmd *, int); -int cmd_confirm_before_exec(struct cmd *, struct cmd_ctx *); +void cmd_confirm_before_key_binding(struct cmd *, int); +enum cmd_retval cmd_confirm_before_exec(struct cmd *, struct cmd_ctx *); -int cmd_confirm_before_callback(void *, const char *); -void cmd_confirm_before_free(void *); +int cmd_confirm_before_callback(void *, const char *); +void cmd_confirm_before_free(void *); const struct cmd_entry cmd_confirm_before_entry = { "confirm-before", "confirm", @@ -65,7 +65,7 @@ cmd_confirm_before_key_binding(struct cmd *self, int key) } } -int +enum cmd_retval cmd_confirm_before_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; @@ -76,11 +76,11 @@ cmd_confirm_before_exec(struct cmd *self, struct cmd_ctx *ctx) if (ctx->curclient == NULL) { ctx->error(ctx, "must be run interactively"); - return (-1); + return (CMD_RETURN_ERROR); } if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL) - return (-1); + return (CMD_RETURN_ERROR); if ((prompt = args_get(args, 'p')) != NULL) xasprintf(&new_prompt, "%s ", prompt); @@ -99,7 +99,7 @@ cmd_confirm_before_exec(struct cmd *self, struct cmd_ctx *ctx) PROMPT_SINGLE); free(new_prompt); - return (1); + return (CMD_RETURN_YIELD); } int diff --git a/cmd-copy-mode.c b/cmd-copy-mode.c index b9290593..3f80cd8c 100644 --- a/cmd-copy-mode.c +++ b/cmd-copy-mode.c @@ -24,8 +24,8 @@ * Enter copy mode. */ -void cmd_copy_mode_key_binding(struct cmd *, int); -int cmd_copy_mode_exec(struct cmd *, struct cmd_ctx *); +void cmd_copy_mode_key_binding(struct cmd *, int); +enum cmd_retval cmd_copy_mode_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_copy_mode_entry = { "copy-mode", NULL, @@ -45,20 +45,20 @@ cmd_copy_mode_key_binding(struct cmd *self, int key) args_set(self->args, 'u', NULL); } -int +enum cmd_retval cmd_copy_mode_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; struct window_pane *wp; if (cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp) == NULL) - return (-1); + return (CMD_RETURN_ERROR); if (window_pane_set_mode(wp, &window_copy_mode) != 0) - return (0); + return (CMD_RETURN_NORMAL); window_copy_init_from_pane(wp); if (wp->mode == &window_copy_mode && args_has(self->args, 'u')) window_copy_pageup(wp); - return (0); + return (CMD_RETURN_NORMAL); } diff --git a/cmd-delete-buffer.c b/cmd-delete-buffer.c index f087b9a7..c3f8776a 100644 --- a/cmd-delete-buffer.c +++ b/cmd-delete-buffer.c @@ -26,7 +26,7 @@ * Delete a paste buffer. */ -int cmd_delete_buffer_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_delete_buffer_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_delete_buffer_entry = { "delete-buffer", "deleteb", @@ -38,7 +38,7 @@ const struct cmd_entry cmd_delete_buffer_entry = { cmd_delete_buffer_exec }; -int +enum cmd_retval cmd_delete_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; @@ -47,20 +47,20 @@ cmd_delete_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) if (!args_has(args, 'b')) { paste_free_top(&global_buffers); - return (0); + return (CMD_RETURN_NORMAL); } buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause); if (cause != NULL) { ctx->error(ctx, "buffer %s", cause); free(cause); - return (-1); + return (CMD_RETURN_ERROR); } if (paste_free_index(&global_buffers, buffer) != 0) { ctx->error(ctx, "no buffer %d", buffer); - return (-1); + return (CMD_RETURN_ERROR); } - return (0); + return (CMD_RETURN_NORMAL); } diff --git a/cmd-detach-client.c b/cmd-detach-client.c index 6477e062..b437ddd3 100644 --- a/cmd-detach-client.c +++ b/cmd-detach-client.c @@ -24,7 +24,7 @@ * Detach a client. */ -int cmd_detach_client_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_detach_client_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_detach_client_entry = { "detach-client", "detach", @@ -36,7 +36,7 @@ const struct cmd_entry cmd_detach_client_entry = { cmd_detach_client_exec }; -int +enum cmd_retval cmd_detach_client_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; @@ -53,7 +53,7 @@ cmd_detach_client_exec(struct cmd *self, struct cmd_ctx *ctx) if (args_has(args, 's')) { s = cmd_find_session(ctx, args_get(args, 's'), 0); if (s == NULL) - return (-1); + return (CMD_RETURN_ERROR); for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); @@ -63,7 +63,7 @@ cmd_detach_client_exec(struct cmd *self, struct cmd_ctx *ctx) } else { c = cmd_find_client(ctx, args_get(args, 't')); if (c == NULL) - return (-1); + return (CMD_RETURN_ERROR); if (args_has(args, 'a')) { for (i = 0; i < ARRAY_LENGTH(&clients); i++) { @@ -76,5 +76,5 @@ cmd_detach_client_exec(struct cmd *self, struct cmd_ctx *ctx) server_write_client(c, msgtype, NULL, 0); } - return (0); + return (CMD_RETURN_NORMAL); } diff --git a/cmd-display-message.c b/cmd-display-message.c index 3bc3a38c..1aed4f1d 100644 --- a/cmd-display-message.c +++ b/cmd-display-message.c @@ -27,7 +27,7 @@ * Displays a message in the status line. */ -int cmd_display_message_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_display_message_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_display_message_entry = { "display-message", "display", @@ -39,7 +39,7 @@ const struct cmd_entry cmd_display_message_entry = { cmd_display_message_exec }; -int +enum cmd_retval cmd_display_message_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; @@ -55,21 +55,21 @@ cmd_display_message_exec(struct cmd *self, struct cmd_ctx *ctx) size_t len; if ((c = cmd_find_client(ctx, args_get(args, 'c'))) == NULL) - return (-1); + return (CMD_RETURN_ERROR); if (args_has(args, 't')) { wl = cmd_find_pane(ctx, args_get(args, 't'), &s, &wp); if (wl == NULL) - return (-1); + return (CMD_RETURN_ERROR); } else { wl = cmd_find_pane(ctx, NULL, &s, &wp); if (wl == NULL) - return (-1); + return (CMD_RETURN_ERROR); } if (args_has(args, 'F') && args->argc != 0) { ctx->error(ctx, "only one of -F or argument must be given"); - return (-1); + return (CMD_RETURN_ERROR); } template = args_get(args, 'F'); @@ -96,5 +96,5 @@ cmd_display_message_exec(struct cmd *self, struct cmd_ctx *ctx) free(msg); format_free(ft); - return (0); + return (CMD_RETURN_NORMAL); } diff --git a/cmd-display-panes.c b/cmd-display-panes.c index bc64b4b5..5f0893d4 100644 --- a/cmd-display-panes.c +++ b/cmd-display-panes.c @@ -24,7 +24,7 @@ * Display panes on a client. */ -int cmd_display_panes_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_display_panes_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_display_panes_entry = { "display-panes", "displayp", @@ -36,16 +36,16 @@ const struct cmd_entry cmd_display_panes_entry = { cmd_display_panes_exec }; -int +enum cmd_retval cmd_display_panes_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; struct client *c; if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL) - return (-1); + return (CMD_RETURN_ERROR); server_set_identify(c); - return (0); + return (CMD_RETURN_NORMAL); } diff --git a/cmd-find-window.c b/cmd-find-window.c index 864f1821..e73effbf 100644 --- a/cmd-find-window.c +++ b/cmd-find-window.c @@ -28,7 +28,7 @@ * Find window containing text. */ -int cmd_find_window_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_find_window_exec(struct cmd *, struct cmd_ctx *); u_int cmd_find_window_match_flags(struct args *); void cmd_find_window_callback(struct window_choose_data *); @@ -74,7 +74,7 @@ cmd_find_window_match_flags(struct args *args) return (match_flags); } -int +enum cmd_retval cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; @@ -90,12 +90,12 @@ cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx) if (ctx->curclient == NULL) { ctx->error(ctx, "must be run interactively"); - return (-1); + return (CMD_RETURN_ERROR); } s = ctx->curclient->session; if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL) - return (-1); + return (CMD_RETURN_ERROR); if ((template = args_get(args, 'F')) == NULL) template = DEFAULT_FIND_WINDOW_TEMPLATE; @@ -150,7 +150,7 @@ cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx) ctx->error(ctx, "no windows matching: %s", str); ARRAY_FREE(&list_idx); ARRAY_FREE(&list_ctx); - return (-1); + return (CMD_RETURN_ERROR); } if (ARRAY_LENGTH(&list_idx) == 1) { @@ -189,7 +189,7 @@ out: ARRAY_FREE(&list_idx); ARRAY_FREE(&list_ctx); - return (0); + return (CMD_RETURN_NORMAL); } void diff --git a/cmd-has-session.c b/cmd-has-session.c index cfaf032b..8e77942a 100644 --- a/cmd-has-session.c +++ b/cmd-has-session.c @@ -24,7 +24,7 @@ * Cause client to report an error and exit with 1 if session doesn't exist. */ -int cmd_has_session_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_has_session_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_has_session_entry = { "has-session", "has", @@ -36,13 +36,13 @@ const struct cmd_entry cmd_has_session_entry = { cmd_has_session_exec }; -int +enum cmd_retval cmd_has_session_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; if (cmd_find_session(ctx, args_get(args, 't'), 0) == NULL) - return (-1); + return (CMD_RETURN_ERROR); - return (0); + return (CMD_RETURN_NORMAL); } diff --git a/cmd-if-shell.c b/cmd-if-shell.c index bdd26e70..5e23fb10 100644 --- a/cmd-if-shell.c +++ b/cmd-if-shell.c @@ -29,7 +29,7 @@ * Executes a tmux command if a shell command returns true or false. */ -int cmd_if_shell_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_if_shell_exec(struct cmd *, struct cmd_ctx *); void cmd_if_shell_callback(struct job *); void cmd_if_shell_free(void *); @@ -50,7 +50,7 @@ struct cmd_if_shell_data { struct cmd_ctx ctx; }; -int +enum cmd_retval cmd_if_shell_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; @@ -72,7 +72,7 @@ cmd_if_shell_exec(struct cmd *self, struct cmd_ctx *ctx) job_run(shellcmd, cmd_if_shell_callback, cmd_if_shell_free, cdata); - return (1); /* don't let client exit */ + return (CMD_RETURN_YIELD); /* don't let client exit */ } void diff --git a/cmd-join-pane.c b/cmd-join-pane.c index 602dcf66..c792948c 100644 --- a/cmd-join-pane.c +++ b/cmd-join-pane.c @@ -29,10 +29,10 @@ * Join or move a pane into another (like split/swap/kill). */ -void cmd_join_pane_key_binding(struct cmd *, int); -int cmd_join_pane_exec(struct cmd *, struct cmd_ctx *); +void cmd_join_pane_key_binding(struct cmd *, int); +enum cmd_retval cmd_join_pane_exec(struct cmd *, struct cmd_ctx *); -int join_pane(struct cmd *, struct cmd_ctx *, int); +enum cmd_retval join_pane(struct cmd *, struct cmd_ctx *, int); const struct cmd_entry cmd_join_pane_entry = { "join-pane", "joinp", @@ -68,13 +68,13 @@ cmd_join_pane_key_binding(struct cmd *self, int key) } } -int +enum cmd_retval cmd_join_pane_exec(struct cmd *self, struct cmd_ctx *ctx) { return (join_pane(self, ctx, self->entry == &cmd_join_pane_entry)); } -int +enum cmd_retval join_pane(struct cmd *self, struct cmd_ctx *ctx, int not_same_window) { struct args *args = self->args; @@ -89,22 +89,22 @@ join_pane(struct cmd *self, struct cmd_ctx *ctx, int not_same_window) dst_wl = cmd_find_pane(ctx, args_get(args, 't'), &dst_s, &dst_wp); if (dst_wl == NULL) - return (-1); + return (CMD_RETURN_ERROR); dst_w = dst_wl->window; dst_idx = dst_wl->idx; src_wl = cmd_find_pane(ctx, args_get(args, 's'), NULL, &src_wp); if (src_wl == NULL) - return (-1); + return (CMD_RETURN_ERROR); src_w = src_wl->window; if (not_same_window && src_w == dst_w) { ctx->error(ctx, "can't join a pane to its own window"); - return (-1); + return (CMD_RETURN_ERROR); } if (!not_same_window && src_wp == dst_wp) { ctx->error(ctx, "source and target panes must be different"); - return (-1); + return (CMD_RETURN_ERROR); } type = LAYOUT_TOPBOTTOM; @@ -117,14 +117,14 @@ join_pane(struct cmd *self, struct cmd_ctx *ctx, int not_same_window) if (cause != NULL) { ctx->error(ctx, "size %s", cause); free(cause); - return (-1); + return (CMD_RETURN_ERROR); } } else if (args_has(args, 'p')) { percentage = args_strtonum(args, 'p', 0, 100, &cause); if (cause != NULL) { ctx->error(ctx, "percentage %s", cause); free(cause); - return (-1); + return (CMD_RETURN_ERROR); } if (type == LAYOUT_TOPBOTTOM) size = (dst_wp->sy * percentage) / 100; @@ -134,7 +134,7 @@ join_pane(struct cmd *self, struct cmd_ctx *ctx, int not_same_window) lc = layout_split_pane(dst_wp, type, size, args_has(args, 'b')); if (lc == NULL) { ctx->error(ctx, "create pane failed: pane too small"); - return (-1); + return (CMD_RETURN_ERROR); } layout_close_pane(src_wp); @@ -168,5 +168,5 @@ join_pane(struct cmd *self, struct cmd_ctx *ctx, int not_same_window) server_status_session(dst_s); notify_window_layout_changed(dst_w); - return (0); + return (CMD_RETURN_NORMAL); } diff --git a/cmd-kill-pane.c b/cmd-kill-pane.c index 215c8ed7..ff8c425f 100644 --- a/cmd-kill-pane.c +++ b/cmd-kill-pane.c @@ -26,7 +26,7 @@ * Kill pane. */ -int cmd_kill_pane_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_kill_pane_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_kill_pane_entry = { "kill-pane", "killp", @@ -38,7 +38,7 @@ const struct cmd_entry cmd_kill_pane_entry = { cmd_kill_pane_exec }; -int +enum cmd_retval cmd_kill_pane_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; @@ -46,13 +46,13 @@ cmd_kill_pane_exec(struct cmd *self, struct cmd_ctx *ctx) struct window_pane *loopwp, *nextwp, *wp; if ((wl = cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp)) == NULL) - return (-1); + return (CMD_RETURN_ERROR); if (window_count_panes(wl->window) == 1) { /* Only one pane, kill the window. */ server_kill_window(wl->window); recalculate_sizes(); - return (0); + return (CMD_RETURN_NORMAL); } if (args_has(self->args, 'a')) { @@ -71,5 +71,5 @@ cmd_kill_pane_exec(struct cmd *self, struct cmd_ctx *ctx) } server_redraw_window(wl->window); - return (0); + return (CMD_RETURN_NORMAL); } diff --git a/cmd-kill-server.c b/cmd-kill-server.c index 800563a4..6761dac4 100644 --- a/cmd-kill-server.c +++ b/cmd-kill-server.c @@ -27,7 +27,7 @@ * Kill the server and do nothing else. */ -int cmd_kill_server_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_kill_server_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_kill_server_entry = { "kill-server", NULL, @@ -40,10 +40,10 @@ const struct cmd_entry cmd_kill_server_entry = { }; /* ARGSUSED */ -int +enum cmd_retval cmd_kill_server_exec(unused struct cmd *self, unused struct cmd_ctx *ctx) { kill(getpid(), SIGTERM); - return (0); + return (CMD_RETURN_NORMAL); } diff --git a/cmd-kill-session.c b/cmd-kill-session.c index bdc4a71c..9ee6a928 100644 --- a/cmd-kill-session.c +++ b/cmd-kill-session.c @@ -27,7 +27,7 @@ * Note this deliberately has no alias to make it hard to hit by accident. */ -int cmd_kill_session_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_kill_session_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_kill_session_entry = { "kill-session", NULL, @@ -39,14 +39,14 @@ const struct cmd_entry cmd_kill_session_entry = { cmd_kill_session_exec }; -int +enum cmd_retval cmd_kill_session_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; struct session *s, *s2, *s3; if ((s = cmd_find_session(ctx, args_get(args, 't'), 0)) == NULL) - return (-1); + return (CMD_RETURN_ERROR); if (args_has(args, 'a')) { RB_FOREACH_SAFE(s2, sessions, &sessions, s3) { @@ -59,5 +59,5 @@ cmd_kill_session_exec(struct cmd *self, struct cmd_ctx *ctx) server_destroy_session(s); session_destroy(s); } - return (0); + return (CMD_RETURN_NORMAL); } diff --git a/cmd-kill-window.c b/cmd-kill-window.c index 255026cd..01587fc8 100644 --- a/cmd-kill-window.c +++ b/cmd-kill-window.c @@ -24,7 +24,7 @@ * Destroy window. */ -int cmd_kill_window_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_kill_window_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_kill_window_entry = { "kill-window", "killw", @@ -36,7 +36,7 @@ const struct cmd_entry cmd_kill_window_entry = { cmd_kill_window_exec }; -int +enum cmd_retval cmd_kill_window_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; @@ -44,7 +44,7 @@ cmd_kill_window_exec(struct cmd *self, struct cmd_ctx *ctx) struct session *s; if ((wl = cmd_find_window(ctx, args_get(args, 't'), &s)) == NULL) - return (-1); + return (CMD_RETURN_ERROR); if (args_has(args, 'a')) { RB_FOREACH_SAFE(wl2, winlinks, &s->windows, wl3) { @@ -55,5 +55,5 @@ cmd_kill_window_exec(struct cmd *self, struct cmd_ctx *ctx) server_kill_window(wl->window); recalculate_sizes(); - return (0); + return (CMD_RETURN_NORMAL); } diff --git a/cmd-link-window.c b/cmd-link-window.c index a9dcf621..5c050904 100644 --- a/cmd-link-window.c +++ b/cmd-link-window.c @@ -26,7 +26,7 @@ * Link a window into another session. */ -int cmd_link_window_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_link_window_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_link_window_entry = { "link-window", "linkw", @@ -38,7 +38,7 @@ const struct cmd_entry cmd_link_window_entry = { cmd_link_window_exec }; -int +enum cmd_retval cmd_link_window_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; @@ -48,18 +48,18 @@ cmd_link_window_exec(struct cmd *self, struct cmd_ctx *ctx) int idx, kflag, dflag; if ((wl = cmd_find_window(ctx, args_get(args, 's'), &src)) == NULL) - return (-1); + return (CMD_RETURN_ERROR); if ((idx = cmd_find_index(ctx, args_get(args, 't'), &dst)) == -2) - return (-1); + return (CMD_RETURN_ERROR); kflag = args_has(self->args, 'k'); dflag = args_has(self->args, 'd'); if (server_link_window(src, wl, dst, idx, kflag, !dflag, &cause) != 0) { ctx->error(ctx, "can't link window: %s", cause); free(cause); - return (-1); + return (CMD_RETURN_ERROR); } recalculate_sizes(); - return (0); + return (CMD_RETURN_NORMAL); } diff --git a/cmd-list-buffers.c b/cmd-list-buffers.c index 64fbd3f2..f22a35bc 100644 --- a/cmd-list-buffers.c +++ b/cmd-list-buffers.c @@ -27,7 +27,7 @@ * List paste buffers. */ -int cmd_list_buffers_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_list_buffers_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_list_buffers_entry = { "list-buffers", "lsb", @@ -40,7 +40,7 @@ const struct cmd_entry cmd_list_buffers_entry = { }; /* ARGSUSED */ -int +enum cmd_retval cmd_list_buffers_exec(unused struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; @@ -66,5 +66,5 @@ cmd_list_buffers_exec(unused struct cmd *self, struct cmd_ctx *ctx) format_free(ft); } - return (0); + return (CMD_RETURN_NORMAL); } diff --git a/cmd-list-clients.c b/cmd-list-clients.c index 2286ff98..af6ebde2 100644 --- a/cmd-list-clients.c +++ b/cmd-list-clients.c @@ -41,7 +41,7 @@ const struct cmd_entry cmd_list_clients_entry = { }; /* ARGSUSED */ -int +enum cmd_retval cmd_list_clients_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; @@ -55,7 +55,7 @@ cmd_list_clients_exec(struct cmd *self, struct cmd_ctx *ctx) if (args_has(args, 't')) { s = cmd_find_session(ctx, args_get(args, 't'), 0); if (s == NULL) - return (-1); + return (CMD_RETURN_ERROR); } else s = NULL; @@ -82,5 +82,5 @@ cmd_list_clients_exec(struct cmd *self, struct cmd_ctx *ctx) format_free(ft); } - return (0); + return (CMD_RETURN_NORMAL); } diff --git a/cmd-list-commands.c b/cmd-list-commands.c index 87901210..2ebc206e 100644 --- a/cmd-list-commands.c +++ b/cmd-list-commands.c @@ -24,7 +24,7 @@ * List all commands with usages. */ -int cmd_list_commands_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_list_commands_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_list_commands_entry = { "list-commands", "lscm", @@ -37,7 +37,7 @@ const struct cmd_entry cmd_list_commands_entry = { }; /* ARGSUSED */ -int +enum cmd_retval cmd_list_commands_exec(unused struct cmd *self, struct cmd_ctx *ctx) { const struct cmd_entry **entryp; @@ -45,5 +45,5 @@ cmd_list_commands_exec(unused struct cmd *self, struct cmd_ctx *ctx) for (entryp = cmd_table; *entryp != NULL; entryp++) ctx->print(ctx, "%s %s", (*entryp)->name, (*entryp)->usage); - return (0); + return (CMD_RETURN_NORMAL); } diff --git a/cmd-list-keys.c b/cmd-list-keys.c index 95f33023..d93f368b 100644 --- a/cmd-list-keys.c +++ b/cmd-list-keys.c @@ -26,9 +26,8 @@ * List key bindings. */ -int cmd_list_keys_exec(struct cmd *, struct cmd_ctx *); - -int cmd_list_keys_table(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_list_keys_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_list_keys_table(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_list_keys_entry = { "list-keys", "lsk", @@ -40,7 +39,7 @@ const struct cmd_entry cmd_list_keys_entry = { cmd_list_keys_exec }; -int +enum cmd_retval cmd_list_keys_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; @@ -95,7 +94,7 @@ cmd_list_keys_exec(struct cmd *self, struct cmd_ctx *ctx) ctx->print(ctx, "bind-key %s", tmp); } - return (0); + return (CMD_RETURN_NORMAL); } int @@ -111,7 +110,7 @@ cmd_list_keys_table(struct cmd *self, struct cmd_ctx *ctx) tablename = args_get(args, 't'); if ((mtab = mode_key_findtable(tablename)) == NULL) { ctx->error(ctx, "unknown key table: %s", tablename); - return (-1); + return (CMD_RETURN_ERROR); } width = 0; @@ -145,5 +144,5 @@ cmd_list_keys_table(struct cmd *self, struct cmd_ctx *ctx) } } - return (0); + return (CMD_RETURN_NORMAL); } diff --git a/cmd-list-panes.c b/cmd-list-panes.c index 3f9e672c..7a8d81d2 100644 --- a/cmd-list-panes.c +++ b/cmd-list-panes.c @@ -27,7 +27,7 @@ * List panes on given window. */ -int cmd_list_panes_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_list_panes_exec(struct cmd *, struct cmd_ctx *); void cmd_list_panes_server(struct cmd *, struct cmd_ctx *); void cmd_list_panes_session( @@ -45,7 +45,7 @@ const struct cmd_entry cmd_list_panes_entry = { cmd_list_panes_exec }; -int +enum cmd_retval cmd_list_panes_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; @@ -57,16 +57,16 @@ cmd_list_panes_exec(struct cmd *self, struct cmd_ctx *ctx) else if (args_has(args, 's')) { s = cmd_find_session(ctx, args_get(args, 't'), 0); if (s == NULL) - return (-1); + return (CMD_RETURN_ERROR); cmd_list_panes_session(self, s, ctx, 1); } else { wl = cmd_find_window(ctx, args_get(args, 't'), &s); if (wl == NULL) - return (-1); + return (CMD_RETURN_ERROR); cmd_list_panes_window(self, s, wl, ctx, 0); } - return (0); + return (CMD_RETURN_NORMAL); } void diff --git a/cmd-list-sessions.c b/cmd-list-sessions.c index 1aa6dbaa..6db1e11c 100644 --- a/cmd-list-sessions.c +++ b/cmd-list-sessions.c @@ -28,7 +28,7 @@ * List all sessions. */ -int cmd_list_sessions_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_list_sessions_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_list_sessions_entry = { "list-sessions", "ls", @@ -40,7 +40,7 @@ const struct cmd_entry cmd_list_sessions_entry = { cmd_list_sessions_exec }; -int +enum cmd_retval cmd_list_sessions_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; @@ -67,5 +67,5 @@ cmd_list_sessions_exec(struct cmd *self, struct cmd_ctx *ctx) n++; } - return (0); + return (CMD_RETURN_NORMAL); } diff --git a/cmd-list-windows.c b/cmd-list-windows.c index 241e64de..62ae6b11 100644 --- a/cmd-list-windows.c +++ b/cmd-list-windows.c @@ -27,7 +27,7 @@ * List windows on given session. */ -int cmd_list_windows_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_list_windows_exec(struct cmd *, struct cmd_ctx *); void cmd_list_windows_server(struct cmd *, struct cmd_ctx *); void cmd_list_windows_session( @@ -43,7 +43,7 @@ const struct cmd_entry cmd_list_windows_entry = { cmd_list_windows_exec }; -int +enum cmd_retval cmd_list_windows_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; @@ -54,11 +54,11 @@ cmd_list_windows_exec(struct cmd *self, struct cmd_ctx *ctx) else { s = cmd_find_session(ctx, args_get(args, 't'), 0); if (s == NULL) - return (-1); + return (CMD_RETURN_ERROR); cmd_list_windows_session(self, s, ctx, 0); } - return (0); + return (CMD_RETURN_NORMAL); } void diff --git a/cmd-list.c b/cmd-list.c index 08d5716f..80d1ade3 100644 --- a/cmd-list.c +++ b/cmd-list.c @@ -79,12 +79,13 @@ bad: return (NULL); } -int +enum cmd_retval cmd_list_exec(struct cmd_list *cmdlist, struct cmd_ctx *ctx) { struct client *c = ctx->curclient; struct cmd *cmd; - int n, retval, guards; + enum cmd_retval retval; + int guards, n; guards = 0; if (c != NULL && c->session != NULL) @@ -98,21 +99,17 @@ cmd_list_exec(struct cmd_list *cmdlist, struct cmd_ctx *ctx) if (guards) ctx->print(ctx, "%%end"); - /* Return of -1 is an error. */ - if (n == -1) - return (-1); - - /* - * A 1 return value means the command client is being attached - * (sent MSG_READY). - */ - if (n == 1) { - retval = 1; + switch (n) + { + case CMD_RETURN_ERROR: + return (CMD_RETURN_ERROR); + case CMD_RETURN_ATTACH: + /* Client is being attached (send MSG_READY). */ + retval = CMD_RETURN_ATTACH; /* - * The command client has been attached, so mangle the - * context to treat any following commands as if they - * were called from inside. + * Mangle the context to treat any following commands + * as if they were called from inside. */ if (ctx->curclient == NULL) { ctx->curclient = ctx->cmdclient; @@ -122,6 +119,13 @@ cmd_list_exec(struct cmd_list *cmdlist, struct cmd_ctx *ctx) ctx->print = key_bindings_print; ctx->info = key_bindings_info; } + break; + case CMD_RETURN_YIELD: + if (retval == CMD_RETURN_NORMAL) + retval = CMD_RETURN_YIELD; + break; + case CMD_RETURN_NORMAL: + break; } } return (retval); diff --git a/cmd-load-buffer.c b/cmd-load-buffer.c index 83ab6078..bfb06842 100644 --- a/cmd-load-buffer.c +++ b/cmd-load-buffer.c @@ -30,8 +30,8 @@ * Loads a paste buffer from a file. */ -int cmd_load_buffer_exec(struct cmd *, struct cmd_ctx *); -void cmd_load_buffer_callback(struct client *, int, void *); +enum cmd_retval cmd_load_buffer_exec(struct cmd *, struct cmd_ctx *); +void cmd_load_buffer_callback(struct client *, int, void *); const struct cmd_entry cmd_load_buffer_entry = { "load-buffer", "loadb", @@ -43,7 +43,7 @@ const struct cmd_entry cmd_load_buffer_entry = { cmd_load_buffer_exec }; -int +enum cmd_retval cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; @@ -63,7 +63,7 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) if (cause != NULL) { ctx->error(ctx, "buffer %s", cause); free(cause); - return (-1); + return (CMD_RETURN_ERROR); } } @@ -77,9 +77,9 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) if (error != 0) { ctx->error(ctx, "%s: %s", path, cause); free(cause); - return (-1); + return (CMD_RETURN_ERROR); } - return (1); + return (CMD_RETURN_YIELD); } if (c != NULL) @@ -97,7 +97,7 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) } if ((f = fopen(path, "rb")) == NULL) { ctx->error(ctx, "%s: %s", path, strerror(errno)); - return (-1); + return (CMD_RETURN_ERROR); } pdata = NULL; @@ -123,21 +123,21 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) limit = options_get_number(&global_options, "buffer-limit"); if (buffer == -1) { paste_add(&global_buffers, pdata, psize, limit); - return (0); + return (CMD_RETURN_NORMAL); } if (paste_replace(&global_buffers, buffer, pdata, psize) != 0) { ctx->error(ctx, "no buffer %d", buffer); free(pdata); - return (-1); + return (CMD_RETURN_ERROR); } - return (0); + return (CMD_RETURN_NORMAL); error: free(pdata); if (f != NULL) fclose(f); - return (-1); + return (CMD_RETURN_ERROR); } void diff --git a/cmd-lock-server.c b/cmd-lock-server.c index ecbcee9b..7a9ced33 100644 --- a/cmd-lock-server.c +++ b/cmd-lock-server.c @@ -28,7 +28,7 @@ * Lock commands. */ -int cmd_lock_server_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_lock_server_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_lock_server_entry = { "lock-server", "lock", @@ -61,7 +61,7 @@ const struct cmd_entry cmd_lock_client_entry = { }; /* ARGSUSED */ -int +enum cmd_retval cmd_lock_server_exec(struct cmd *self, unused struct cmd_ctx *ctx) { struct args *args = self->args; @@ -72,14 +72,14 @@ cmd_lock_server_exec(struct cmd *self, unused struct cmd_ctx *ctx) server_lock(); else if (self->entry == &cmd_lock_session_entry) { if ((s = cmd_find_session(ctx, args_get(args, 't'), 0)) == NULL) - return (-1); + return (CMD_RETURN_ERROR); server_lock_session(s); } else { if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL) - return (-1); + return (CMD_RETURN_ERROR); server_lock_client(c); } recalculate_sizes(); - return (0); + return (CMD_RETURN_NORMAL); } diff --git a/cmd-move-window.c b/cmd-move-window.c index 4adad410..03d42a8d 100644 --- a/cmd-move-window.c +++ b/cmd-move-window.c @@ -26,7 +26,7 @@ * Move a window. */ -int cmd_move_window_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_move_window_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_move_window_entry = { "move-window", "movew", @@ -38,7 +38,7 @@ const struct cmd_entry cmd_move_window_entry = { cmd_move_window_exec }; -int +enum cmd_retval cmd_move_window_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; @@ -49,28 +49,28 @@ cmd_move_window_exec(struct cmd *self, struct cmd_ctx *ctx) if (args_has(args, 'r')) { if ((s = cmd_find_session(ctx, args_get(args, 't'), 0)) == NULL) - return (-1); + return (CMD_RETURN_ERROR); session_renumber_windows(s); recalculate_sizes(); - return (0); + return (CMD_RETURN_NORMAL); } if ((wl = cmd_find_window(ctx, args_get(args, 's'), &src)) == NULL) - return (-1); + return (CMD_RETURN_ERROR); if ((idx = cmd_find_index(ctx, args_get(args, 't'), &dst)) == -2) - return (-1); + return (CMD_RETURN_ERROR); kflag = args_has(self->args, 'k'); dflag = args_has(self->args, 'd'); if (server_link_window(src, wl, dst, idx, kflag, !dflag, &cause) != 0) { ctx->error(ctx, "can't move window: %s", cause); free(cause); - return (-1); + return (CMD_RETURN_ERROR); } server_unlink_window(src, wl); recalculate_sizes(); - return (0); + return (CMD_RETURN_NORMAL); } diff --git a/cmd-new-session.c b/cmd-new-session.c index 22ec16fb..cd1bc2b1 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -30,8 +30,8 @@ * Create a new session and attach to the current terminal unless -d is given. */ -int cmd_new_session_check(struct args *); -int cmd_new_session_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_new_session_check(struct args *); +enum cmd_retval cmd_new_session_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_new_session_entry = { "new-session", "new", @@ -44,15 +44,15 @@ const struct cmd_entry cmd_new_session_entry = { cmd_new_session_exec }; -int +enum cmd_retval cmd_new_session_check(struct args *args) { if (args_has(args, 't') && (args->argc != 0 || args_has(args, 'n'))) - return (-1); - return (0); + return (CMD_RETURN_ERROR); + return (CMD_RETURN_NORMAL); } -int +enum cmd_retval cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; @@ -71,11 +71,11 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) if (newname != NULL) { if (!session_check_name(newname)) { ctx->error(ctx, "bad session name: %s", newname); - return (-1); + return (CMD_RETURN_ERROR); } if (session_find(newname) != NULL) { ctx->error(ctx, "duplicate session: %s", newname); - return (-1); + return (CMD_RETURN_ERROR); } } @@ -83,7 +83,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) if (target != NULL) { groupwith = cmd_find_session(ctx, target, 0); if (groupwith == NULL) - return (-1); + return (CMD_RETURN_ERROR); } else groupwith = NULL; @@ -131,7 +131,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) if (server_client_open(ctx->cmdclient, NULL, &cause) != 0) { ctx->error(ctx, "open terminal failed: %s", cause); free(cause); - return (-1); + return (CMD_RETURN_ERROR); } } @@ -163,7 +163,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) args_get(args, 'x'), 1, USHRT_MAX, &errstr); if (errstr != NULL) { ctx->error(ctx, "width %s", errstr); - return (-1); + return (CMD_RETURN_ERROR); } } if (args_has(args, 'y')) { @@ -171,7 +171,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) args_get(args, 'y'), 1, USHRT_MAX, &errstr); if (errstr != NULL) { ctx->error(ctx, "height %s", errstr); - return (-1); + return (CMD_RETURN_ERROR); } } } @@ -202,7 +202,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) if (s == NULL) { ctx->error(ctx, "create session failed: %s", cause); free(cause); - return (-1); + return (CMD_RETURN_ERROR); } environ_free(&env); @@ -269,5 +269,5 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) ARRAY_FREE(&cfg_causes); } - return (!detached); /* 1 means don't tell command client to exit */ + return (detached ? CMD_RETURN_NORMAL : CMD_RETURN_ATTACH); } diff --git a/cmd-new-window.c b/cmd-new-window.c index 3d9e9320..28dd2358 100644 --- a/cmd-new-window.c +++ b/cmd-new-window.c @@ -39,7 +39,7 @@ const struct cmd_entry cmd_new_window_entry = { cmd_new_window_exec }; -int +enum cmd_retval cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; @@ -56,7 +56,7 @@ cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx) if (args_has(args, 'a')) { wl = cmd_find_window(ctx, args_get(args, 't'), &s); if (wl == NULL) - return (-1); + return (CMD_RETURN_ERROR); idx = wl->idx + 1; /* Find the next free index. */ @@ -66,7 +66,7 @@ cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx) } if (last == INT_MAX) { ctx->error(ctx, "no free window indexes"); - return (-1); + return (CMD_RETURN_ERROR); } /* Move everything from last - 1 to idx up a bit. */ @@ -77,7 +77,7 @@ cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx) } } else { if ((idx = cmd_find_index(ctx, args_get(args, 't'), &s)) == -2) - return (-1); + return (CMD_RETURN_ERROR); } detached = args_has(args, 'd'); @@ -113,7 +113,7 @@ cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx) if (wl == NULL) { ctx->error(ctx, "create window failed: %s", cause); free(cause); - return (-1); + return (CMD_RETURN_ERROR); } if (!detached) { session_select(s, wl->idx); @@ -139,5 +139,5 @@ cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx) format_free(ft); } - return (0); + return (CMD_RETURN_NORMAL); } diff --git a/cmd-paste-buffer.c b/cmd-paste-buffer.c index 2c367259..9bf27fcd 100644 --- a/cmd-paste-buffer.c +++ b/cmd-paste-buffer.c @@ -28,7 +28,7 @@ * Paste paste buffer if present. */ -int cmd_paste_buffer_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_paste_buffer_exec(struct cmd *, struct cmd_ctx *); void cmd_paste_buffer_filter(struct window_pane *, const char *, size_t, const char *, int bracket); @@ -43,7 +43,7 @@ const struct cmd_entry cmd_paste_buffer_entry = { cmd_paste_buffer_exec }; -int +enum cmd_retval cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; @@ -56,7 +56,7 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) int pflag; if (cmd_find_pane(ctx, args_get(args, 't'), &s, &wp) == NULL) - return (-1); + return (CMD_RETURN_ERROR); if (!args_has(args, 'b')) buffer = -1; @@ -65,7 +65,7 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) if (cause != NULL) { ctx->error(ctx, "buffer %s", cause); free(cause); - return (-1); + return (CMD_RETURN_ERROR); } } @@ -75,7 +75,7 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) pb = paste_get_index(&global_buffers, buffer); if (pb == NULL) { ctx->error(ctx, "no buffer %d", buffer); - return (-1); + return (CMD_RETURN_ERROR); } } @@ -100,7 +100,7 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) paste_free_index(&global_buffers, buffer); } - return (0); + return (CMD_RETURN_NORMAL); } /* Add bytes to a buffer and filter '\n' according to separator. */ diff --git a/cmd-pipe-pane.c b/cmd-pipe-pane.c index 0a52ae5d..bf89e51a 100644 --- a/cmd-pipe-pane.c +++ b/cmd-pipe-pane.c @@ -32,7 +32,7 @@ * Open pipe to redirect pane output. If already open, close first. */ -int cmd_pipe_pane_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_pipe_pane_exec(struct cmd *, struct cmd_ctx *); void cmd_pipe_pane_error_callback(struct bufferevent *, short, void *); @@ -46,7 +46,7 @@ const struct cmd_entry cmd_pipe_pane_entry = { cmd_pipe_pane_exec }; -int +enum cmd_retval cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; @@ -56,7 +56,7 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx) int old_fd, pipe_fd[2], null_fd; if (cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp) == NULL) - return (-1); + return (CMD_RETURN_ERROR); c = cmd_find_client(ctx, NULL); /* Destroy the old pipe. */ @@ -69,7 +69,7 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx) /* If no pipe command, that is enough. */ if (args->argc == 0 || *args->argv[0] == '\0') - return (0); + return (CMD_RETURN_NORMAL); /* * With -o, only open the new pipe if there was no previous one. This @@ -78,19 +78,19 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx) * bind ^p pipep -o 'cat >>~/output' */ if (args_has(self->args, 'o') && old_fd != -1) - return (0); + return (CMD_RETURN_NORMAL); /* Open the new pipe. */ if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_fd) != 0) { ctx->error(ctx, "socketpair error: %s", strerror(errno)); - return (-1); + return (CMD_RETURN_ERROR); } /* Fork the child. */ switch (fork()) { case -1: ctx->error(ctx, "fork error: %s", strerror(errno)); - return (-1); + return (CMD_RETURN_ERROR); case 0: /* Child process. */ close(pipe_fd[0]); @@ -127,7 +127,7 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx) bufferevent_enable(wp->pipe_event, EV_WRITE); setblocking(wp->pipe_fd, 0); - return (0); + return (CMD_RETURN_NORMAL); } } diff --git a/cmd-refresh-client.c b/cmd-refresh-client.c index e7e10696..0ce7be9d 100644 --- a/cmd-refresh-client.c +++ b/cmd-refresh-client.c @@ -24,7 +24,7 @@ * Refresh client. */ -int cmd_refresh_client_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_refresh_client_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_refresh_client_entry = { "refresh-client", "refresh", @@ -36,14 +36,14 @@ const struct cmd_entry cmd_refresh_client_entry = { cmd_refresh_client_exec }; -int +enum cmd_retval cmd_refresh_client_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; struct client *c; if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL) - return (-1); + return (CMD_RETURN_ERROR); if (args_has(args, 'S')) { status_update_jobs(c); @@ -51,5 +51,5 @@ cmd_refresh_client_exec(struct cmd *self, struct cmd_ctx *ctx) } else server_redraw_client(c); - return (0); + return (CMD_RETURN_NORMAL); } diff --git a/cmd-rename-session.c b/cmd-rename-session.c index bbae1872..fb8dd4ed 100644 --- a/cmd-rename-session.c +++ b/cmd-rename-session.c @@ -26,7 +26,7 @@ * Change session name. */ -int cmd_rename_session_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_rename_session_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_rename_session_entry = { "rename-session", "rename", @@ -38,7 +38,7 @@ const struct cmd_entry cmd_rename_session_entry = { cmd_rename_session_exec }; -int +enum cmd_retval cmd_rename_session_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; @@ -48,15 +48,15 @@ cmd_rename_session_exec(struct cmd *self, struct cmd_ctx *ctx) newname = args->argv[0]; if (!session_check_name(newname)) { ctx->error(ctx, "bad session name: %s", newname); - return (-1); + return (CMD_RETURN_ERROR); } if (session_find(newname) != NULL) { ctx->error(ctx, "duplicate session: %s", newname); - return (-1); + return (CMD_RETURN_ERROR); } if ((s = cmd_find_session(ctx, args_get(args, 't'), 0)) == NULL) - return (-1); + return (CMD_RETURN_ERROR); RB_REMOVE(sessions, &sessions, s); free(s->name); @@ -66,5 +66,5 @@ cmd_rename_session_exec(struct cmd *self, struct cmd_ctx *ctx) server_status_session(s); notify_session_renamed(s); - return (0); + return (CMD_RETURN_NORMAL); } diff --git a/cmd-rename-window.c b/cmd-rename-window.c index dc7fec5c..099ab3b7 100644 --- a/cmd-rename-window.c +++ b/cmd-rename-window.c @@ -26,7 +26,7 @@ * Rename a window. */ -int cmd_rename_window_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_rename_window_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_rename_window_entry = { "rename-window", "renamew", @@ -38,7 +38,7 @@ const struct cmd_entry cmd_rename_window_entry = { cmd_rename_window_exec }; -int +enum cmd_retval cmd_rename_window_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; @@ -46,12 +46,12 @@ cmd_rename_window_exec(struct cmd *self, struct cmd_ctx *ctx) struct winlink *wl; if ((wl = cmd_find_window(ctx, args_get(args, 't'), &s)) == NULL) - return (-1); + return (CMD_RETURN_ERROR); window_set_name(wl->window, args->argv[0]); options_set_number(&wl->window->options, "automatic-rename", 0); server_status_window(wl->window); - return (0); + return (CMD_RETURN_NORMAL); } diff --git a/cmd-resize-pane.c b/cmd-resize-pane.c index cabf1da4..4842d411 100644 --- a/cmd-resize-pane.c +++ b/cmd-resize-pane.c @@ -26,8 +26,8 @@ * Increase or decrease pane size. */ -void cmd_resize_pane_key_binding(struct cmd *, int); -int cmd_resize_pane_exec(struct cmd *, struct cmd_ctx *); +void cmd_resize_pane_key_binding(struct cmd *, int); +enum cmd_retval cmd_resize_pane_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_resize_pane_entry = { "resize-pane", "resizep", @@ -81,7 +81,7 @@ cmd_resize_pane_key_binding(struct cmd *self, int key) } } -int +enum cmd_retval cmd_resize_pane_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; @@ -91,7 +91,7 @@ cmd_resize_pane_exec(struct cmd *self, struct cmd_ctx *ctx) u_int adjust; if ((wl = cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp)) == NULL) - return (-1); + return (CMD_RETURN_ERROR); if (args->argc == 0) adjust = 1; @@ -99,7 +99,7 @@ cmd_resize_pane_exec(struct cmd *self, struct cmd_ctx *ctx) adjust = strtonum(args->argv[0], 1, INT_MAX, &errstr); if (errstr != NULL) { ctx->error(ctx, "adjustment %s", errstr); - return (-1); + return (CMD_RETURN_ERROR); } } @@ -114,5 +114,5 @@ cmd_resize_pane_exec(struct cmd *self, struct cmd_ctx *ctx) layout_resize_pane(wp, LAYOUT_TOPBOTTOM, adjust); server_redraw_window(wl->window); - return (0); + return (CMD_RETURN_NORMAL); } diff --git a/cmd-respawn-pane.c b/cmd-respawn-pane.c index 71e07831..3860dc93 100644 --- a/cmd-respawn-pane.c +++ b/cmd-respawn-pane.c @@ -28,7 +28,7 @@ * Respawn a pane (restart the command). Kill existing if -k given. */ -int cmd_respawn_pane_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_respawn_pane_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_respawn_pane_entry = { "respawn-pane", "respawnp", @@ -40,7 +40,7 @@ const struct cmd_entry cmd_respawn_pane_entry = { cmd_respawn_pane_exec }; -int +enum cmd_retval cmd_respawn_pane_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; @@ -54,7 +54,7 @@ cmd_respawn_pane_exec(struct cmd *self, struct cmd_ctx *ctx) u_int idx; if ((wl = cmd_find_pane(ctx, args_get(args, 't'), &s, &wp)) == NULL) - return (-1); + return (CMD_RETURN_ERROR); w = wl->window; if (!args_has(self->args, 'k') && wp->fd != -1) { @@ -62,7 +62,7 @@ cmd_respawn_pane_exec(struct cmd *self, struct cmd_ctx *ctx) fatalx("index not found"); ctx->error(ctx, "pane still active: %s:%u.%u", s->name, wl->idx, idx); - return (-1); + return (CMD_RETURN_ERROR); } environ_init(&env); @@ -82,11 +82,11 @@ cmd_respawn_pane_exec(struct cmd *self, struct cmd_ctx *ctx) ctx->error(ctx, "respawn pane failed: %s", cause); free(cause); environ_free(&env); - return (-1); + return (CMD_RETURN_ERROR); } wp->flags |= PANE_REDRAW; server_status_window(w); environ_free(&env); - return (0); + return (CMD_RETURN_NORMAL); } diff --git a/cmd-respawn-window.c b/cmd-respawn-window.c index c15ca376..a178a2ba 100644 --- a/cmd-respawn-window.c +++ b/cmd-respawn-window.c @@ -27,7 +27,7 @@ * Respawn a window (restart the command). Kill existing if -k given. */ -int cmd_respawn_window_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_respawn_window_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_respawn_window_entry = { "respawn-window", "respawnw", @@ -39,7 +39,7 @@ const struct cmd_entry cmd_respawn_window_entry = { cmd_respawn_window_exec }; -int +enum cmd_retval cmd_respawn_window_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; @@ -52,7 +52,7 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_ctx *ctx) char *cause; if ((wl = cmd_find_window(ctx, args_get(args, 't'), &s)) == NULL) - return (-1); + return (CMD_RETURN_ERROR); w = wl->window; if (!args_has(self->args, 'k')) { @@ -61,7 +61,7 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_ctx *ctx) continue; ctx->error(ctx, "window still active: %s:%d", s->name, wl->idx); - return (-1); + return (CMD_RETURN_ERROR); } } @@ -85,7 +85,7 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_ctx *ctx) free(cause); environ_free(&env); server_destroy_pane(wp); - return (-1); + return (CMD_RETURN_ERROR); } layout_init(w); window_pane_reset_mode(wp); @@ -97,5 +97,5 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_ctx *ctx) server_redraw_window(w); environ_free(&env); - return (0); + return (CMD_RETURN_NORMAL); } diff --git a/cmd-rotate-window.c b/cmd-rotate-window.c index 1d752e74..7a6c60b3 100644 --- a/cmd-rotate-window.c +++ b/cmd-rotate-window.c @@ -24,8 +24,8 @@ * Rotate the panes in a window. */ -void cmd_rotate_window_key_binding(struct cmd *, int); -int cmd_rotate_window_exec(struct cmd *, struct cmd_ctx *); +void cmd_rotate_window_key_binding(struct cmd *, int); +enum cmd_retval cmd_rotate_window_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_rotate_window_entry = { "rotate-window", "rotatew", @@ -45,7 +45,7 @@ cmd_rotate_window_key_binding(struct cmd *self, int key) args_set(self->args, 'D', NULL); } -int +enum cmd_retval cmd_rotate_window_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; @@ -56,7 +56,7 @@ cmd_rotate_window_exec(struct cmd *self, struct cmd_ctx *ctx) u_int sx, sy, xoff, yoff; if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL) - return (-1); + return (CMD_RETURN_ERROR); w = wl->window; if (args_has(self->args, 'D')) { @@ -115,5 +115,5 @@ cmd_rotate_window_exec(struct cmd *self, struct cmd_ctx *ctx) server_redraw_window(w); } - return (0); + return (CMD_RETURN_NORMAL); } diff --git a/cmd-run-shell.c b/cmd-run-shell.c index 6a80d4ef..dcbcb375 100644 --- a/cmd-run-shell.c +++ b/cmd-run-shell.c @@ -29,10 +29,9 @@ * Runs a command without a window. */ -int cmd_run_shell_exec(struct cmd *, struct cmd_ctx *); - -void cmd_run_shell_callback(struct job *); -void cmd_run_shell_free(void *); +enum cmd_retval cmd_run_shell_exec(struct cmd *, struct cmd_ctx *); +void cmd_run_shell_callback(struct job *); +void cmd_run_shell_free(void *); const struct cmd_entry cmd_run_shell_entry = { "run-shell", "run", @@ -49,7 +48,7 @@ struct cmd_run_shell_data { struct cmd_ctx ctx; }; -int +enum cmd_retval cmd_run_shell_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; @@ -67,7 +66,7 @@ cmd_run_shell_exec(struct cmd *self, struct cmd_ctx *ctx) job_run(shellcmd, cmd_run_shell_callback, cmd_run_shell_free, cdata); - return (1); /* don't let client exit */ + return (CMD_RETURN_YIELD); /* don't let client exit */ } void diff --git a/cmd-save-buffer.c b/cmd-save-buffer.c index 875cbbbb..b8f9968b 100644 --- a/cmd-save-buffer.c +++ b/cmd-save-buffer.c @@ -29,7 +29,7 @@ * Saves a paste buffer to a file. */ -int cmd_save_buffer_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_save_buffer_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_save_buffer_entry = { "save-buffer", "saveb", @@ -41,7 +41,7 @@ const struct cmd_entry cmd_save_buffer_entry = { cmd_save_buffer_exec }; -int +enum cmd_retval cmd_save_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; @@ -57,20 +57,20 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) if (!args_has(args, 'b')) { if ((pb = paste_get_top(&global_buffers)) == NULL) { ctx->error(ctx, "no buffers"); - return (-1); + return (CMD_RETURN_ERROR); } } else { buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause); if (cause != NULL) { ctx->error(ctx, "buffer %s", cause); free(cause); - return (-1); + return (CMD_RETURN_ERROR); } pb = paste_get_index(&global_buffers, buffer); if (pb == NULL) { ctx->error(ctx, "no buffer %d", buffer); - return (-1); + return (CMD_RETURN_ERROR); } } @@ -78,7 +78,7 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) if (strcmp(path, "-") == 0) { if (c == NULL) { ctx->error(ctx, "%s: can't write to stdout", path); - return (-1); + return (CMD_RETURN_ERROR); } evbuffer_add(c->stdout_data, pb->data, pb->size); server_push_stdout(c); @@ -105,15 +105,15 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) umask(mask); if (f == NULL) { ctx->error(ctx, "%s: %s", path, strerror(errno)); - return (-1); + return (CMD_RETURN_ERROR); } if (fwrite(pb->data, 1, pb->size, f) != pb->size) { ctx->error(ctx, "%s: fwrite error", path); fclose(f); - return (-1); + return (CMD_RETURN_ERROR); } fclose(f); } - return (0); + return (CMD_RETURN_NORMAL); } diff --git a/cmd-select-layout.c b/cmd-select-layout.c index c79e8c7e..982c0b27 100644 --- a/cmd-select-layout.c +++ b/cmd-select-layout.c @@ -24,8 +24,8 @@ * Switch window to selected layout. */ -void cmd_select_layout_key_binding(struct cmd *, int); -int cmd_select_layout_exec(struct cmd *, struct cmd_ctx *); +void cmd_select_layout_key_binding(struct cmd *, int); +enum cmd_retval cmd_select_layout_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_select_layout_entry = { "select-layout", "selectl", @@ -90,7 +90,7 @@ cmd_select_layout_key_binding(struct cmd *self, int key) } } -int +enum cmd_retval cmd_select_layout_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; @@ -100,7 +100,7 @@ cmd_select_layout_exec(struct cmd *self, struct cmd_ctx *ctx) int next, previous, layout; if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL) - return (-1); + return (CMD_RETURN_ERROR); w = wl->window; next = self->entry == &cmd_next_layout_entry; @@ -114,13 +114,13 @@ cmd_select_layout_exec(struct cmd *self, struct cmd_ctx *ctx) if (args_has(self->args, 'U')) { if ((layoutname = layout_list_redo(w)) == NULL) { ctx->info(ctx, "no more layout history"); - return (-1); + return (CMD_RETURN_ERROR); } goto set_layout; } else if (args_has(self->args, 'u')) { if ((layoutname = layout_list_undo(w)) == NULL) { ctx->info(ctx, "no more layout history"); - return (-1); + return (CMD_RETURN_ERROR); } goto set_layout; } @@ -132,7 +132,7 @@ cmd_select_layout_exec(struct cmd *self, struct cmd_ctx *ctx) layout = layout_set_previous(wl->window); server_redraw_window(wl->window); ctx->info(ctx, "arranging in: %s", layout_set_name(layout)); - return (0); + return (CMD_RETURN_NORMAL); } if (args->argc == 0) @@ -143,19 +143,19 @@ cmd_select_layout_exec(struct cmd *self, struct cmd_ctx *ctx) layout = layout_set_select(wl->window, layout); server_redraw_window(wl->window); ctx->info(ctx, "arranging in: %s", layout_set_name(layout)); - return (0); + return (CMD_RETURN_NORMAL); } if (args->argc == 0) - return (0); + return (CMD_RETURN_NORMAL); layoutname = args->argv[0]; set_layout: if (layout_parse(wl->window, layoutname) == -1) { ctx->error(ctx, "can't set layout: %s", layoutname); - return (-1); + return (CMD_RETURN_ERROR); } server_redraw_window(wl->window); ctx->info(ctx, "arranging in: %s", layoutname); - return (0); + return (CMD_RETURN_NORMAL); } diff --git a/cmd-select-pane.c b/cmd-select-pane.c index 0dd847d6..fce34784 100644 --- a/cmd-select-pane.c +++ b/cmd-select-pane.c @@ -24,8 +24,8 @@ * Select pane. */ -void cmd_select_pane_key_binding(struct cmd *, int); -int cmd_select_pane_exec(struct cmd *, struct cmd_ctx *); +void cmd_select_pane_key_binding(struct cmd *, int); +enum cmd_retval cmd_select_pane_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_select_pane_entry = { "select-pane", "selectp", @@ -63,7 +63,7 @@ cmd_select_pane_key_binding(struct cmd *self, int key) args_set(self->args, 't', ":.+"); } -int +enum cmd_retval cmd_select_pane_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; @@ -73,26 +73,26 @@ cmd_select_pane_exec(struct cmd *self, struct cmd_ctx *ctx) if (self->entry == &cmd_last_pane_entry || args_has(args, 'l')) { wl = cmd_find_window(ctx, args_get(args, 't'), NULL); if (wl == NULL) - return (-1); + return (CMD_RETURN_ERROR); if (wl->window->last == NULL) { ctx->error(ctx, "no last pane"); - return (-1); + return (CMD_RETURN_ERROR); } window_set_active_pane(wl->window, wl->window->last); server_status_window(wl->window); server_redraw_window_borders(wl->window); - return (0); + return (CMD_RETURN_NORMAL); } if ((wl = cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp)) == NULL) - return (-1); + return (CMD_RETURN_ERROR); if (!window_pane_visible(wp)) { ctx->error(ctx, "pane not visible"); - return (-1); + return (CMD_RETURN_ERROR); } if (args_has(self->args, 'L')) @@ -105,12 +105,12 @@ cmd_select_pane_exec(struct cmd *self, struct cmd_ctx *ctx) wp = window_pane_find_down(wp); if (wp == NULL) { ctx->error(ctx, "pane not found"); - return (-1); + return (CMD_RETURN_ERROR); } window_set_active_pane(wl->window, wp); server_status_window(wl->window); server_redraw_window_borders(wl->window); - return (0); + return (CMD_RETURN_NORMAL); } diff --git a/cmd-select-window.c b/cmd-select-window.c index 2e076ae9..eaa3e889 100644 --- a/cmd-select-window.c +++ b/cmd-select-window.c @@ -26,8 +26,8 @@ * Select window by index. */ -void cmd_select_window_key_binding(struct cmd *, int); -int cmd_select_window_exec(struct cmd *, struct cmd_ctx *); +void cmd_select_window_key_binding(struct cmd *, int); +enum cmd_retval cmd_select_window_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_select_window_entry = { "select-window", "selectw", @@ -83,7 +83,7 @@ cmd_select_window_key_binding(struct cmd *self, int key) args_set(self->args, 'a', NULL); } -int +enum cmd_retval cmd_select_window_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; @@ -104,23 +104,23 @@ cmd_select_window_exec(struct cmd *self, struct cmd_ctx *ctx) if (next || previous || last) { s = cmd_find_session(ctx, args_get(args, 't'), 0); if (s == NULL) - return (-1); + return (CMD_RETURN_ERROR); activity = args_has(self->args, 'a'); if (next) { if (session_next(s, activity) != 0) { ctx->error(ctx, "no next window"); - return (-1); + return (CMD_RETURN_ERROR); } } else if (previous) { if (session_previous(s, activity) != 0) { ctx->error(ctx, "no previous window"); - return (-1); + return (CMD_RETURN_ERROR); } } else { if (session_last(s) != 0) { ctx->error(ctx, "no last window"); - return (-1); + return (CMD_RETURN_ERROR); } } @@ -128,12 +128,12 @@ cmd_select_window_exec(struct cmd *self, struct cmd_ctx *ctx) } else { wl = cmd_find_window(ctx, args_get(args, 't'), &s); if (wl == NULL) - return (-1); + return (CMD_RETURN_ERROR); if (session_select(s, wl->idx) == 0) server_redraw_session(s); } recalculate_sizes(); - return (0); + return (CMD_RETURN_NORMAL); } diff --git a/cmd-send-keys.c b/cmd-send-keys.c index 5c92f7dc..4a5c3656 100644 --- a/cmd-send-keys.c +++ b/cmd-send-keys.c @@ -27,7 +27,7 @@ * Send keys to client. */ -int cmd_send_keys_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_send_keys_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_send_keys_entry = { "send-keys", "send", @@ -39,7 +39,7 @@ const struct cmd_entry cmd_send_keys_entry = { cmd_send_keys_exec }; -int +enum cmd_retval cmd_send_keys_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; @@ -50,7 +50,7 @@ cmd_send_keys_exec(struct cmd *self, struct cmd_ctx *ctx) int i, key; if (cmd_find_pane(ctx, args_get(args, 't'), &s, &wp) == NULL) - return (-1); + return (CMD_RETURN_ERROR); if (args_has(args, 'R')) { ictx = &wp->ictx; @@ -80,5 +80,5 @@ cmd_send_keys_exec(struct cmd *self, struct cmd_ctx *ctx) } } - return (0); + return (CMD_RETURN_NORMAL); } diff --git a/cmd-send-prefix.c b/cmd-send-prefix.c index b541fddf..04556507 100644 --- a/cmd-send-prefix.c +++ b/cmd-send-prefix.c @@ -24,7 +24,7 @@ * Send prefix key as a key. */ -int cmd_send_prefix_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_send_prefix_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_send_prefix_entry = { "send-prefix", NULL, @@ -36,7 +36,7 @@ const struct cmd_entry cmd_send_prefix_entry = { cmd_send_prefix_exec }; -int +enum cmd_retval cmd_send_prefix_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; @@ -45,7 +45,7 @@ cmd_send_prefix_exec(struct cmd *self, struct cmd_ctx *ctx) int key; if (cmd_find_pane(ctx, args_get(args, 't'), &s, &wp) == NULL) - return (-1); + return (CMD_RETURN_ERROR); if (args_has(args, '2')) key = options_get_number(&s->options, "prefix2"); @@ -53,5 +53,5 @@ cmd_send_prefix_exec(struct cmd *self, struct cmd_ctx *ctx) key = options_get_number(&s->options, "prefix"); window_pane_key(wp, s, key); - return (0); + return (CMD_RETURN_NORMAL); } diff --git a/cmd-server-info.c b/cmd-server-info.c index 1a5a5cf8..ffd7efca 100644 --- a/cmd-server-info.c +++ b/cmd-server-info.c @@ -31,7 +31,7 @@ * Show various information about server. */ -int cmd_server_info_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_server_info_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_server_info_entry = { "server-info", "info", @@ -44,7 +44,7 @@ const struct cmd_entry cmd_server_info_entry = { }; /* ARGSUSED */ -int +enum cmd_retval cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx) { struct tty_term *term; @@ -179,5 +179,5 @@ cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx) job->cmd, job->fd, job->pid, job->status); } - return (0); + return (CMD_RETURN_NORMAL); } diff --git a/cmd-set-buffer.c b/cmd-set-buffer.c index 73e8b316..e3b1656b 100644 --- a/cmd-set-buffer.c +++ b/cmd-set-buffer.c @@ -27,7 +27,7 @@ * Add or set a paste buffer. */ -int cmd_set_buffer_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_set_buffer_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_set_buffer_entry = { "set-buffer", "setb", @@ -39,7 +39,7 @@ const struct cmd_entry cmd_set_buffer_entry = { cmd_set_buffer_exec }; -int +enum cmd_retval cmd_set_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; @@ -55,7 +55,7 @@ cmd_set_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) if (!args_has(args, 'b')) { paste_add(&global_buffers, pdata, psize, limit); - return (0); + return (CMD_RETURN_NORMAL); } buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause); @@ -63,14 +63,14 @@ cmd_set_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) ctx->error(ctx, "buffer %s", cause); free(cause); free(pdata); - return (-1); + return (CMD_RETURN_ERROR); } if (paste_replace(&global_buffers, buffer, pdata, psize) != 0) { ctx->error(ctx, "no buffer %d", buffer); free(pdata); - return (-1); + return (CMD_RETURN_ERROR); } - return (0); + return (CMD_RETURN_NORMAL); } diff --git a/cmd-set-environment.c b/cmd-set-environment.c index b43de458..67f28af5 100644 --- a/cmd-set-environment.c +++ b/cmd-set-environment.c @@ -27,7 +27,7 @@ * Set an environment variable. */ -int cmd_set_environment_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_set_environment_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_set_environment_entry = { "set-environment", "setenv", @@ -39,7 +39,7 @@ const struct cmd_entry cmd_set_environment_entry = { cmd_set_environment_exec }; -int +enum cmd_retval cmd_set_environment_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; @@ -50,11 +50,11 @@ cmd_set_environment_exec(struct cmd *self, struct cmd_ctx *ctx) name = args->argv[0]; if (*name == '\0') { ctx->error(ctx, "empty variable name"); - return (-1); + return (CMD_RETURN_ERROR); } if (strchr(name, '=') != NULL) { ctx->error(ctx, "variable name contains ="); - return (-1); + return (CMD_RETURN_ERROR); } if (args->argc < 1) @@ -66,29 +66,29 @@ cmd_set_environment_exec(struct cmd *self, struct cmd_ctx *ctx) env = &global_environ; else { if ((s = cmd_find_session(ctx, args_get(args, 't'), 0)) == NULL) - return (-1); + return (CMD_RETURN_ERROR); env = &s->environ; } if (args_has(self->args, 'u')) { if (value != NULL) { ctx->error(ctx, "can't specify a value with -u"); - return (-1); + return (CMD_RETURN_ERROR); } environ_unset(env, name); } else if (args_has(self->args, 'r')) { if (value != NULL) { ctx->error(ctx, "can't specify a value with -r"); - return (-1); + return (CMD_RETURN_ERROR); } environ_set(env, name, NULL); } else { if (value == NULL) { ctx->error(ctx, "no value specified"); - return (-1); + return (CMD_RETURN_ERROR); } environ_set(env, name, value); } - return (0); + return (CMD_RETURN_NORMAL); } diff --git a/cmd-set-option.c b/cmd-set-option.c index 8e55a4fc..d8d9edad 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -27,7 +27,7 @@ * Set an option. */ -int cmd_set_option_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_set_option_exec(struct cmd *, struct cmd_ctx *); int cmd_set_option_unset(struct cmd *, struct cmd_ctx *, const struct options_table_entry *, struct options *, @@ -78,7 +78,7 @@ const struct cmd_entry cmd_set_window_option_entry = { cmd_set_option_exec }; -int +enum cmd_retval cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; @@ -95,7 +95,7 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) optstr = args->argv[0]; if (*optstr == '\0') { ctx->error(ctx, "invalid option"); - return (-1); + return (CMD_RETURN_ERROR); } if (args->argc < 2) valstr = NULL; @@ -106,11 +106,11 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) table = oe = NULL; if (options_table_find(optstr, &table, &oe) != 0) { ctx->error(ctx, "ambiguous option: %s", optstr); - return (-1); + return (CMD_RETURN_ERROR); } if (oe == NULL) { ctx->error(ctx, "unknown option: %s", optstr); - return (-1); + return (CMD_RETURN_ERROR); } /* Work out the tree from the table. */ @@ -122,7 +122,7 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) else { wl = cmd_find_window(ctx, args_get(args, 't'), NULL); if (wl == NULL) - return (-1); + return (CMD_RETURN_ERROR); oo = &wl->window->options; } } else if (table == session_options_table) { @@ -131,21 +131,21 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) else { s = cmd_find_session(ctx, args_get(args, 't'), 0); if (s == NULL) - return (-1); + return (CMD_RETURN_ERROR); oo = &s->options; } } else { ctx->error(ctx, "unknown table"); - return (-1); + return (CMD_RETURN_ERROR); } /* Unset or set the option. */ if (args_has(args, 'u')) { if (cmd_set_option_unset(self, ctx, oe, oo, valstr) != 0) - return (-1); + return (CMD_RETURN_ERROR); } else { if (cmd_set_option_set(self, ctx, oe, oo, valstr) != 0) - return (-1); + return (CMD_RETURN_ERROR); } /* Start or stop timers when automatic-rename changed. */ @@ -168,7 +168,7 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) server_redraw_client(c); } - return (0); + return (CMD_RETURN_NORMAL); } /* Unset an option. */ diff --git a/cmd-show-buffer.c b/cmd-show-buffer.c index 6dbc0c37..0af82972 100644 --- a/cmd-show-buffer.c +++ b/cmd-show-buffer.c @@ -27,7 +27,7 @@ * Show a paste buffer. */ -int cmd_show_buffer_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_show_buffer_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_show_buffer_entry = { "show-buffer", "showb", @@ -39,7 +39,7 @@ const struct cmd_entry cmd_show_buffer_entry = { cmd_show_buffer_exec }; -int +enum cmd_retval cmd_show_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; @@ -51,25 +51,25 @@ cmd_show_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) u_int width; if ((s = cmd_find_session(ctx, NULL, 0)) == NULL) - return (-1); + return (CMD_RETURN_ERROR); if (!args_has(args, 'b')) { if ((pb = paste_get_top(&global_buffers)) == NULL) { ctx->error(ctx, "no buffers"); - return (-1); + return (CMD_RETURN_ERROR); } } else { buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause); if (cause != NULL) { ctx->error(ctx, "buffer %s", cause); free(cause); - return (-1); + return (CMD_RETURN_ERROR); } pb = paste_get_index(&global_buffers, buffer); if (pb == NULL) { ctx->error(ctx, "no buffer %d", buffer); - return (-1); + return (CMD_RETURN_ERROR); } } @@ -108,5 +108,5 @@ cmd_show_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) free(in); - return (0); + return (CMD_RETURN_NORMAL); } diff --git a/cmd-show-environment.c b/cmd-show-environment.c index 17960321..e7b9f7c9 100644 --- a/cmd-show-environment.c +++ b/cmd-show-environment.c @@ -27,7 +27,7 @@ * Show environment. */ -int cmd_show_environment_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_show_environment_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_show_environment_entry = { "show-environment", "showenv", @@ -39,7 +39,7 @@ const struct cmd_entry cmd_show_environment_entry = { cmd_show_environment_exec }; -int +enum cmd_retval cmd_show_environment_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; @@ -51,7 +51,7 @@ cmd_show_environment_exec(struct cmd *self, struct cmd_ctx *ctx) env = &global_environ; else { if ((s = cmd_find_session(ctx, args_get(args, 't'), 0)) == NULL) - return (-1); + return (CMD_RETURN_ERROR); env = &s->environ; } @@ -59,13 +59,13 @@ cmd_show_environment_exec(struct cmd *self, struct cmd_ctx *ctx) envent = environ_find(env, args->argv[0]); if (envent == NULL) { ctx->error(ctx, "unknown variable: %s", args->argv[0]); - return (-1); + return (CMD_RETURN_ERROR); } if (envent->value != NULL) ctx->print(ctx, "%s=%s", envent->name, envent->value); else ctx->print(ctx, "-%s", envent->name); - return (0); + return (CMD_RETURN_NORMAL); } RB_FOREACH(envent, environ, env) { @@ -75,5 +75,5 @@ cmd_show_environment_exec(struct cmd *self, struct cmd_ctx *ctx) ctx->print(ctx, "-%s", envent->name); } - return (0); + return (CMD_RETURN_NORMAL); } diff --git a/cmd-show-messages.c b/cmd-show-messages.c index 5979e8c3..038b673c 100644 --- a/cmd-show-messages.c +++ b/cmd-show-messages.c @@ -27,7 +27,7 @@ * Show client message log. */ -int cmd_show_messages_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_show_messages_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_show_messages_entry = { "show-messages", "showmsgs", @@ -39,7 +39,7 @@ const struct cmd_entry cmd_show_messages_entry = { cmd_show_messages_exec }; -int +enum cmd_retval cmd_show_messages_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; @@ -49,7 +49,7 @@ cmd_show_messages_exec(struct cmd *self, struct cmd_ctx *ctx) u_int i; if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL) - return (-1); + return (CMD_RETURN_ERROR); for (i = 0; i < ARRAY_LENGTH(&c->message_log); i++) { msg = &ARRAY_ITEM(&c->message_log, i); @@ -60,5 +60,5 @@ cmd_show_messages_exec(struct cmd *self, struct cmd_ctx *ctx) ctx->print(ctx, "%s %s", tim, msg->msg); } - return (0); + return (CMD_RETURN_NORMAL); } diff --git a/cmd-show-options.c b/cmd-show-options.c index 7df62a04..85b481a1 100644 --- a/cmd-show-options.c +++ b/cmd-show-options.c @@ -27,7 +27,7 @@ * Show options. */ -int cmd_show_options_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_show_options_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_show_options_entry = { "show-options", "show", @@ -49,7 +49,7 @@ const struct cmd_entry cmd_show_window_options_entry = { cmd_show_options_exec }; -int +enum cmd_retval cmd_show_options_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; @@ -71,7 +71,7 @@ cmd_show_options_exec(struct cmd *self, struct cmd_ctx *ctx) else { wl = cmd_find_window(ctx, args_get(args, 't'), NULL); if (wl == NULL) - return (-1); + return (CMD_RETURN_ERROR); oo = &wl->window->options; } } else { @@ -81,7 +81,7 @@ cmd_show_options_exec(struct cmd *self, struct cmd_ctx *ctx) else { s = cmd_find_session(ctx, args_get(args, 't'), 0); if (s == NULL) - return (-1); + return (CMD_RETURN_ERROR); oo = &s->options; } } @@ -90,14 +90,14 @@ cmd_show_options_exec(struct cmd *self, struct cmd_ctx *ctx) table = oe = NULL; if (options_table_find(args->argv[0], &table, &oe) != 0) { ctx->error(ctx, "ambiguous option: %s", args->argv[0]); - return (-1); + return (CMD_RETURN_ERROR); } if (oe == NULL) { ctx->error(ctx, "unknown option: %s", args->argv[0]); - return (-1); + return (CMD_RETURN_ERROR); } if ((o = options_find1(oo, oe->name)) == NULL) - return (0); + return (CMD_RETURN_NORMAL); optval = options_table_print_entry(oe, o); ctx->print(ctx, "%s %s", oe->name, optval); } else { @@ -109,5 +109,5 @@ cmd_show_options_exec(struct cmd *self, struct cmd_ctx *ctx) } } - return (0); + return (CMD_RETURN_NORMAL); } diff --git a/cmd-source-file.c b/cmd-source-file.c index 3804f0ec..758f959a 100644 --- a/cmd-source-file.c +++ b/cmd-source-file.c @@ -26,7 +26,7 @@ * Sources a configuration file. */ -int cmd_source_file_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_source_file_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_source_file_entry = { "source-file", "source", @@ -38,7 +38,7 @@ const struct cmd_entry cmd_source_file_entry = { cmd_source_file_exec }; -int +enum cmd_retval cmd_source_file_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; diff --git a/cmd-split-window.c b/cmd-split-window.c index c8afdaba..88d451c8 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -28,8 +28,8 @@ * Split a window (add a new pane). */ -void cmd_split_window_key_binding(struct cmd *, int); -int cmd_split_window_exec(struct cmd *, struct cmd_ctx *); +void cmd_split_window_key_binding(struct cmd *, int); +enum cmd_retval cmd_split_window_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_split_window_entry = { "split-window", "splitw", @@ -50,7 +50,7 @@ cmd_split_window_key_binding(struct cmd *self, int key) args_set(self->args, 'h', NULL); } -int +enum cmd_retval cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; @@ -71,7 +71,7 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) char *cp; if ((wl = cmd_find_pane(ctx, args_get(args, 't'), &s, &wp)) == NULL) - return (-1); + return (CMD_RETURN_ERROR); w = wl->window; environ_init(&env); @@ -156,7 +156,7 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) format_free(ft); } notify_window_layout_changed(w); - return (0); + return (CMD_RETURN_NORMAL); error: environ_free(&env); @@ -164,5 +164,5 @@ error: window_remove_pane(w, new_wp); ctx->error(ctx, "create pane failed: %s", cause); free(cause); - return (-1); + return (CMD_RETURN_ERROR); } diff --git a/cmd-start-server.c b/cmd-start-server.c index a69e77ea..eb6143c1 100644 --- a/cmd-start-server.c +++ b/cmd-start-server.c @@ -24,7 +24,7 @@ * Start the server and do nothing else. */ -int cmd_start_server_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_start_server_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_start_server_entry = { "start-server", "start", @@ -37,8 +37,8 @@ const struct cmd_entry cmd_start_server_entry = { }; /* ARGSUSED */ -int +enum cmd_retval cmd_start_server_exec(unused struct cmd *self, unused struct cmd_ctx *ctx) { - return (0); + return (CMD_RETURN_NORMAL); } diff --git a/cmd-suspend-client.c b/cmd-suspend-client.c index 2a4dac1b..24077d7f 100644 --- a/cmd-suspend-client.c +++ b/cmd-suspend-client.c @@ -27,7 +27,7 @@ * Suspend client with SIGTSTP. */ -int cmd_suspend_client_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_suspend_client_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_suspend_client_entry = { "suspend-client", "suspendc", @@ -39,18 +39,18 @@ const struct cmd_entry cmd_suspend_client_entry = { cmd_suspend_client_exec }; -int +enum cmd_retval cmd_suspend_client_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; struct client *c; if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL) - return (-1); + return (CMD_RETURN_ERROR); tty_stop_tty(&c->tty); c->flags |= CLIENT_SUSPENDED; server_write_client(c, MSG_SUSPEND, NULL, 0); - return (0); + return (CMD_RETURN_NORMAL); } diff --git a/cmd-swap-pane.c b/cmd-swap-pane.c index aa133faf..6d9fcfeb 100644 --- a/cmd-swap-pane.c +++ b/cmd-swap-pane.c @@ -26,8 +26,8 @@ * Swap two panes. */ -void cmd_swap_pane_key_binding(struct cmd *, int); -int cmd_swap_pane_exec(struct cmd *, struct cmd_ctx *); +void cmd_swap_pane_key_binding(struct cmd *, int); +enum cmd_retval cmd_swap_pane_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_swap_pane_entry = { "swap-pane", "swapp", @@ -49,7 +49,7 @@ cmd_swap_pane_key_binding(struct cmd *self, int key) args_set(self->args, 'D', NULL); } -int +enum cmd_retval cmd_swap_pane_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; @@ -61,7 +61,7 @@ cmd_swap_pane_exec(struct cmd *self, struct cmd_ctx *ctx) dst_wl = cmd_find_pane(ctx, args_get(args, 't'), NULL, &dst_wp); if (dst_wl == NULL) - return (-1); + return (CMD_RETURN_ERROR); dst_w = dst_wl->window; if (!args_has(args, 's')) { @@ -75,16 +75,16 @@ cmd_swap_pane_exec(struct cmd *self, struct cmd_ctx *ctx) if (src_wp == NULL) src_wp = TAILQ_LAST(&dst_w->panes, window_panes); } else - return (0); + return (CMD_RETURN_NORMAL); } else { src_wl = cmd_find_pane(ctx, args_get(args, 's'), NULL, &src_wp); if (src_wl == NULL) - return (-1); + return (CMD_RETURN_ERROR); src_w = src_wl->window; } if (src_wp == dst_wp) - return (0); + return (CMD_RETURN_NORMAL); tmp_wp = TAILQ_PREV(dst_wp, window_panes, entry); TAILQ_REMOVE(&dst_w->panes, dst_wp, entry); @@ -138,5 +138,5 @@ cmd_swap_pane_exec(struct cmd *self, struct cmd_ctx *ctx) server_redraw_window(src_w); server_redraw_window(dst_w); - return (0); + return (CMD_RETURN_NORMAL); } diff --git a/cmd-swap-window.c b/cmd-swap-window.c index 7583bdff..afd55e0b 100644 --- a/cmd-swap-window.c +++ b/cmd-swap-window.c @@ -38,7 +38,7 @@ const struct cmd_entry cmd_swap_window_entry = { cmd_swap_window_exec }; -int +enum cmd_retval cmd_swap_window_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; @@ -50,21 +50,21 @@ cmd_swap_window_exec(struct cmd *self, struct cmd_ctx *ctx) target_src = args_get(args, 's'); if ((wl_src = cmd_find_window(ctx, target_src, &src)) == NULL) - return (-1); + return (CMD_RETURN_ERROR); target_dst = args_get(args, 't'); if ((wl_dst = cmd_find_window(ctx, target_dst, &dst)) == NULL) - return (-1); + return (CMD_RETURN_ERROR); sg_src = session_group_find(src); sg_dst = session_group_find(dst); if (src != dst && sg_src != NULL && sg_dst != NULL && sg_src == sg_dst) { ctx->error(ctx, "can't move window, sessions are grouped"); - return (-1); + return (CMD_RETURN_ERROR); } if (wl_dst->window == wl_src->window) - return (0); + return (CMD_RETURN_NORMAL); w = wl_dst->window; wl_dst->window = wl_src->window; @@ -83,5 +83,5 @@ cmd_swap_window_exec(struct cmd *self, struct cmd_ctx *ctx) } recalculate_sizes(); - return (0); + return (CMD_RETURN_NORMAL); } diff --git a/cmd-switch-client.c b/cmd-switch-client.c index 7e9516bc..991974fd 100644 --- a/cmd-switch-client.c +++ b/cmd-switch-client.c @@ -27,8 +27,8 @@ * Switch client to a different session. */ -void cmd_switch_client_key_binding(struct cmd *, int); -int cmd_switch_client_exec(struct cmd *, struct cmd_ctx *); +void cmd_switch_client_key_binding(struct cmd *, int); +enum cmd_retval cmd_switch_client_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_switch_client_entry = { "switch-client", "switchc", @@ -57,7 +57,7 @@ cmd_switch_client_key_binding(struct cmd *self, int key) } } -int +enum cmd_retval cmd_switch_client_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; @@ -65,7 +65,7 @@ cmd_switch_client_exec(struct cmd *self, struct cmd_ctx *ctx) struct session *s; if ((c = cmd_find_client(ctx, args_get(args, 'c'))) == NULL) - return (-1); + return (CMD_RETURN_ERROR); if (args_has(args, 'r')) { if (c->flags & CLIENT_READONLY) { @@ -81,24 +81,24 @@ cmd_switch_client_exec(struct cmd *self, struct cmd_ctx *ctx) if (args_has(args, 'n')) { if ((s = session_next_session(c->session)) == NULL) { ctx->error(ctx, "can't find next session"); - return (-1); + return (CMD_RETURN_ERROR); } } else if (args_has(args, 'p')) { if ((s = session_previous_session(c->session)) == NULL) { ctx->error(ctx, "can't find previous session"); - return (-1); + return (CMD_RETURN_ERROR); } } else if (args_has(args, 'l')) { if (c->last_session != NULL && session_alive(c->last_session)) s = c->last_session; if (s == NULL) { ctx->error(ctx, "can't find last session"); - return (-1); + return (CMD_RETURN_ERROR); } } else s = cmd_find_session(ctx, args_get(args, 't'), 0); if (s == NULL) - return (-1); + return (CMD_RETURN_ERROR); if (c->session != NULL) c->last_session = c->session; @@ -110,5 +110,5 @@ cmd_switch_client_exec(struct cmd *self, struct cmd_ctx *ctx) server_redraw_client(c); s->curw->flags &= ~WINLINK_ALERTFLAGS; - return (0); + return (CMD_RETURN_NORMAL); } diff --git a/cmd-unbind-key.c b/cmd-unbind-key.c index ac6c0c0f..4a39f51b 100644 --- a/cmd-unbind-key.c +++ b/cmd-unbind-key.c @@ -26,10 +26,9 @@ * Unbind key from command. */ -int cmd_unbind_key_check(struct args *); -int cmd_unbind_key_exec(struct cmd *, struct cmd_ctx *); - -int cmd_unbind_key_table(struct cmd *, struct cmd_ctx *, int); +enum cmd_retval cmd_unbind_key_check(struct args *); +enum cmd_retval cmd_unbind_key_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_unbind_key_table(struct cmd *, struct cmd_ctx *, int); const struct cmd_entry cmd_unbind_key_entry = { "unbind-key", "unbind", @@ -41,17 +40,17 @@ const struct cmd_entry cmd_unbind_key_entry = { cmd_unbind_key_exec }; -int +enum cmd_retval cmd_unbind_key_check(struct args *args) { if (args_has(args, 'a') && args->argc != 0) - return (-1); + return (CMD_RETURN_ERROR); if (!args_has(args, 'a') && args->argc != 1) - return (-1); - return (0); + return (CMD_RETURN_ERROR); + return (CMD_RETURN_NORMAL); } -int +enum cmd_retval cmd_unbind_key_exec(struct cmd *self, unused struct cmd_ctx *ctx) { struct args *args = self->args; @@ -62,7 +61,7 @@ cmd_unbind_key_exec(struct cmd *self, unused struct cmd_ctx *ctx) key = key_string_lookup_string(args->argv[0]); if (key == KEYC_NONE) { ctx->error(ctx, "unknown key: %s", args->argv[0]); - return (-1); + return (CMD_RETURN_ERROR); } } else key = KEYC_NONE; @@ -75,16 +74,16 @@ cmd_unbind_key_exec(struct cmd *self, unused struct cmd_ctx *ctx) bd = RB_ROOT(&key_bindings); key_bindings_remove(bd->key); } - return (0); + return (CMD_RETURN_NORMAL); } if (!args_has(args, 'n')) key |= KEYC_PREFIX; key_bindings_remove(key); - return (0); + return (CMD_RETURN_NORMAL); } -int +enum cmd_retval cmd_unbind_key_table(struct cmd *self, struct cmd_ctx *ctx, int key) { struct args *args = self->args; @@ -95,7 +94,7 @@ cmd_unbind_key_table(struct cmd *self, struct cmd_ctx *ctx, int key) tablename = args_get(args, 't'); if ((mtab = mode_key_findtable(tablename)) == NULL) { ctx->error(ctx, "unknown key table: %s", tablename); - return (-1); + return (CMD_RETURN_ERROR); } if (key == KEYC_NONE) { @@ -104,7 +103,7 @@ cmd_unbind_key_table(struct cmd *self, struct cmd_ctx *ctx, int key) RB_REMOVE(mode_key_tree, mtab->tree, mbind); free(mbind); } - return (0); + return (CMD_RETURN_NORMAL); } mtmp.key = key; @@ -113,5 +112,5 @@ cmd_unbind_key_table(struct cmd *self, struct cmd_ctx *ctx, int key) RB_REMOVE(mode_key_tree, mtab->tree, mbind); free(mbind); } - return (0); + return (CMD_RETURN_NORMAL); } diff --git a/cmd-unlink-window.c b/cmd-unlink-window.c index 2b44ea8a..c3d3c2ee 100644 --- a/cmd-unlink-window.c +++ b/cmd-unlink-window.c @@ -24,7 +24,7 @@ * Unlink a window, unless it would be destroyed by doing so (only one link). */ -int cmd_unlink_window_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_unlink_window_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_unlink_window_entry = { "unlink-window", "unlinkw", @@ -36,7 +36,7 @@ const struct cmd_entry cmd_unlink_window_entry = { cmd_unlink_window_exec }; -int +enum cmd_retval cmd_unlink_window_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; @@ -47,7 +47,7 @@ cmd_unlink_window_exec(struct cmd *self, struct cmd_ctx *ctx) u_int references; if ((wl = cmd_find_window(ctx, args_get(args, 't'), &s)) == NULL) - return (-1); + return (CMD_RETURN_ERROR); w = wl->window; sg = session_group_find(s); @@ -60,11 +60,11 @@ cmd_unlink_window_exec(struct cmd *self, struct cmd_ctx *ctx) if (!args_has(self->args, 'k') && w->references == references) { ctx->error(ctx, "window is only linked to one session"); - return (-1); + return (CMD_RETURN_ERROR); } server_unlink_window(s, wl); recalculate_sizes(); - return (0); + return (CMD_RETURN_NORMAL); } diff --git a/cmd.c b/cmd.c index eb2fd75c..1db85eba 100644 --- a/cmd.c +++ b/cmd.c @@ -280,7 +280,7 @@ usage: return (NULL); } -int +enum cmd_retval cmd_exec(struct cmd *cmd, struct cmd_ctx *ctx) { return (cmd->entry->exec(cmd, ctx)); diff --git a/server-client.c b/server-client.c index 20f539ae..8ad996b0 100644 --- a/server-client.c +++ b/server-client.c @@ -868,8 +868,16 @@ server_client_msg_command(struct client *c, struct msg_command_data *data) } cmd_free_argv(argc, argv); - if (cmd_list_exec(cmdlist, &ctx) != 1) + switch (cmd_list_exec(cmdlist, &ctx)) + { + case CMD_RETURN_ERROR: + case CMD_RETURN_NORMAL: c->flags |= CLIENT_EXIT; + break; + case CMD_RETURN_ATTACH: + case CMD_RETURN_YIELD: + break; + } cmd_list_free(cmdlist); return; diff --git a/tmux.h b/tmux.h index 2538a97f..d189385f 100644 --- a/tmux.h +++ b/tmux.h @@ -1331,6 +1331,13 @@ struct cmd_list { TAILQ_HEAD(, cmd) list; }; +enum cmd_retval { + CMD_RETURN_ERROR = -1, + CMD_RETURN_NORMAL = 0, + CMD_RETURN_YIELD, + CMD_RETURN_ATTACH +}; + struct cmd_entry { const char *name; const char *alias; @@ -1349,7 +1356,7 @@ struct cmd_entry { void (*key_binding)(struct cmd *, int); int (*check)(struct args *); - int (*exec)(struct cmd *, struct cmd_ctx *); + enum cmd_retval (*exec)(struct cmd *, struct cmd_ctx *); }; /* Key binding. */ @@ -1641,7 +1648,7 @@ int cmd_unpack_argv(char *, size_t, int, char ***); char **cmd_copy_argv(int, char *const *); void cmd_free_argv(int, char **); struct cmd *cmd_parse(int, char **, char **); -int cmd_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_exec(struct cmd *, struct cmd_ctx *); void cmd_free(struct cmd *); size_t cmd_print(struct cmd *, char *, size_t); struct session *cmd_current_session(struct cmd_ctx *, int); @@ -1745,7 +1752,7 @@ extern const struct cmd_entry cmd_up_pane_entry; /* cmd-list.c */ struct cmd_list *cmd_list_parse(int, char **, char **); -int cmd_list_exec(struct cmd_list *, struct cmd_ctx *); +enum cmd_retval cmd_list_exec(struct cmd_list *, struct cmd_ctx *); void cmd_list_free(struct cmd_list *); size_t cmd_list_print(struct cmd_list *, char *, size_t); From 35a8a61254a190d2c4ec52f0525993ab1594bc44 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 12 Jul 2012 13:03:42 +0000 Subject: [PATCH 1151/1180] Nuke unused variable from Thomas Adam. --- cmd-choose-tree.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/cmd-choose-tree.c b/cmd-choose-tree.c index 166684f8..1fa40c96 100644 --- a/cmd-choose-tree.c +++ b/cmd-choose-tree.c @@ -76,7 +76,6 @@ cmd_choose_tree_exec(struct cmd *self, struct cmd_ctx *ctx) struct args *args = self->args; struct winlink *wl, *wm; struct session *s, *s2; - struct tty *tty; struct window_choose_data *wcd = NULL; const char *ses_template, *win_template; char *final_win_action, *final_win_template; @@ -93,7 +92,6 @@ cmd_choose_tree_exec(struct cmd *self, struct cmd_ctx *ctx) } s = ctx->curclient->session; - tty = &ctx->curclient->tty; if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL) return (CMD_RETURN_ERROR); From 5385a9bb347ae703fdc44eb59c71d70e61fbf95e Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 13 Jul 2012 06:27:41 +0000 Subject: [PATCH 1152/1180] Add a queue of notifys and a way to turn them off and on (we do not want notifys to happen during some commands). Based on code from George Nachman. --- cmd-list.c | 4 ++ notify.c | 145 ++++++++++++++++++++++++++++++++++++++++++++++++++--- tmux.h | 8 +-- 3 files changed, 146 insertions(+), 11 deletions(-) diff --git a/cmd-list.c b/cmd-list.c index 80d1ade3..2cf66a80 100644 --- a/cmd-list.c +++ b/cmd-list.c @@ -91,6 +91,8 @@ cmd_list_exec(struct cmd_list *cmdlist, struct cmd_ctx *ctx) if (c != NULL && c->session != NULL) guards = c->flags & CLIENT_CONTROL; + notify_disable(); + retval = 0; TAILQ_FOREACH(cmd, &cmdlist->list, qentry) { if (guards) @@ -128,6 +130,8 @@ cmd_list_exec(struct cmd_list *cmdlist, struct cmd_ctx *ctx) break; } } + + notify_enable(); return (retval); } diff --git a/notify.c b/notify.c index a9d89ee5..dad50b94 100644 --- a/notify.c +++ b/notify.c @@ -16,44 +16,173 @@ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include +#include + +#include + #include "tmux.h" +enum notify_type { + NOTIFY_WINDOW_LAYOUT_CHANGED, + NOTIFY_WINDOW_UNLINKED, + NOTIFY_WINDOW_LINKED, + NOTIFY_WINDOW_RENAMED, + NOTIFY_ATTACHED_SESSION_CHANGED, + NOTIFY_SESSION_RENAMED, + NOTIFY_SESSION_CREATED, + NOTIFY_SESSION_CLOSED +}; + +struct notify_entry { + enum notify_type type; + + struct client *client; + struct session *session; + struct window *window; + + TAILQ_ENTRY(notify_entry) entry; +}; +TAILQ_HEAD(, notify_entry) notify_queue = TAILQ_HEAD_INITIALIZER(notify_queue); +int notify_enabled = 1; + +void notify_drain(void); +void notify_add(enum notify_type, struct client *, struct session *, + struct window *); + void -notify_window_layout_changed(unused struct window *w) +notify_enable(void) { + notify_enabled = 1; + notify_drain(); } void -notify_window_unlinked(unused struct session *s, unused struct window *w) +notify_disable(void) { + notify_enabled = 0; } void -notify_window_linked(unused struct session *s, unused struct window *w) +notify_add(enum notify_type type, struct client *c, struct session *s, + struct window *w) { + struct notify_entry *ne; + + ne = xcalloc(1, sizeof *ne); + ne->type = type; + ne->client = c; + ne->session = s; + ne->window = w; + TAILQ_INSERT_TAIL(¬ify_queue, ne, entry); + + if (c != NULL) + c->references++; + if (s != NULL) + s->references++; + if (w != NULL) + w->references++; } void -notify_window_renamed(unused struct window *w) +notify_drain(void) { + struct notify_entry *ne, *ne1; + + if (!notify_enabled) + return; + + TAILQ_FOREACH_SAFE(ne, ¬ify_queue, entry, ne1) { + switch (ne->type) { + case NOTIFY_WINDOW_LAYOUT_CHANGED: + /* control_notify_window_layout_changed(ne->window); */ + break; + case NOTIFY_WINDOW_UNLINKED: + /* control_notify_window_unlinked(ne->session, ne->window); */ + break; + case NOTIFY_WINDOW_LINKED: + /* control_notify_window_linked(ne->session, ne->window); */ + break; + case NOTIFY_WINDOW_RENAMED: + /* control_notify_window_renamed(ne->window); */ + break; + case NOTIFY_ATTACHED_SESSION_CHANGED: + /* control_notify_attached_session_changed(ne->client, ne->session); */ + break; + case NOTIFY_SESSION_RENAMED: + /* control_notify_session_renamed(ne->session); */ + break; + case NOTIFY_SESSION_CREATED: + /* control_notify_session_created(ne->session); */ + break; + case NOTIFY_SESSION_CLOSED: + /* control_notify_session_close(ne->session); */ + break; + } + + if (ne->client != NULL) + ne->client->references--; + if (ne->session != NULL) + ne->session->references--; + if (ne->window != NULL) + ne->window->references--; + TAILQ_REMOVE(¬ify_queue, ne, entry); + free(ne); + } } void -notify_attached_session_changed(unused struct client *c) +notify_window_layout_changed(struct window *w) { + notify_add(NOTIFY_WINDOW_LAYOUT_CHANGED, NULL, NULL, w); + notify_drain(); } void -notify_session_renamed(unused struct session *s) +notify_window_unlinked(struct session *s, struct window *w) { + notify_add(NOTIFY_WINDOW_UNLINKED, NULL, s, w); + notify_drain(); } void -notify_session_created(unused struct session *s) +notify_window_linked(struct session *s, struct window *w) { + notify_add(NOTIFY_WINDOW_LINKED, NULL, s, w); + notify_drain(); } void -notify_session_closed(unused struct session *s) +notify_window_renamed(struct window *w) { + notify_add(NOTIFY_WINDOW_RENAMED, NULL, NULL, w); + notify_drain(); +} + +void +notify_attached_session_changed(struct client *c) +{ + notify_add(NOTIFY_ATTACHED_SESSION_CHANGED, c, NULL, NULL); + notify_drain(); +} + +void +notify_session_renamed(struct session *s) +{ + notify_add(NOTIFY_SESSION_RENAMED, NULL, s, NULL); + notify_drain(); +} + +void +notify_session_created(struct session *s) +{ + notify_add(NOTIFY_SESSION_CREATED, NULL, s, NULL); + notify_drain(); +} + +void +notify_session_closed(struct session *s) +{ + notify_add(NOTIFY_SESSION_CLOSED, NULL, s, NULL); + notify_drain(); } diff --git a/tmux.h b/tmux.h index d189385f..6c03cdc3 100644 --- a/tmux.h +++ b/tmux.h @@ -1484,6 +1484,8 @@ void mode_key_init(struct mode_key_data *, struct mode_key_tree *); enum mode_key_cmd mode_key_lookup(struct mode_key_data *, int); /* notify.c */ +void notify_enable(void); +void notify_disable(void); void notify_window_layout_changed(struct window *); void notify_window_unlinked(struct session *, struct window *); void notify_window_linked(struct session *, struct window *); @@ -2162,11 +2164,11 @@ void queue_window_name(struct window *); char *default_window_name(struct window *); /* signal.c */ -void set_signals(void(*)(int, short, void *)); -void clear_signals(int); +void set_signals(void(*)(int, short, void *)); +void clear_signals(int); /* control.c */ -void control_callback(struct client *, int, void*); +void control_callback(struct client *, int, void*); /* session.c */ extern struct sessions sessions; From 89a96b05fa9473e19b62c03e835731430ff5d04e Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 15 Jul 2012 06:51:57 +0000 Subject: [PATCH 1153/1180] Document pane_index variable, from sam at sltosis dot org. --- tmux.1 | 1 + 1 file changed, 1 insertion(+) diff --git a/tmux.1 b/tmux.1 index a88dcb36..bddc0473 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2909,6 +2909,7 @@ The following variables are available, where appropriate: .It Li "pane_dead" Ta "1 if pane is dead" .It Li "pane_height" Ta "Height of pane" .It Li "pane_id" Ta "Unique pane ID" +.It Li "pane_index" Ta "Index of pane" .It Li "pane_pid" Ta "PID of first process in pane" .It Li "pane_start_command" Ta "Command pane started with" .It Li "pane_start_path" Ta "Path pane started with" From ff4097e02cf35709e4b34aa62d227a54c5d7ddb5 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 11 Aug 2012 05:55:12 +0000 Subject: [PATCH 1154/1180] Add some missing formats from Samuel Le Thiec. --- tmux.1 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tmux.1 b/tmux.1 index bddc0473..b9110287 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2326,6 +2326,7 @@ may contain any of the following special character sequences: .It Li "#h" Ta "Hostname of local host without the domain name" .It Li "#F" Ta "Current window flag" .It Li "#I" Ta "Current window index" +.It Li "#D" Ta "Current pane unique identifier" .It Li "#P" Ta "Current pane index" .It Li "#S" Ta "Session name" .It Li "#T" Ta "Current pane title" @@ -2903,6 +2904,8 @@ The following variables are available, where appropriate: .It Li "client_utf8" Ta "1 if client supports utf8" .It Li "client_width" Ta "Width of client" .It Li "host" Ta "Hostname of local host" +.It Li "history_bytes" Ta "Number of bytes in window history" +.It Li "history_limit" Ta "Maximum window history lines" .It Li "line" Ta "Line number in the list" .It Li "pane_active" Ta "1 if active pane" .It Li "pane_current_path" Ta "Current path if available" @@ -2929,6 +2932,7 @@ The following variables are available, where appropriate: .It Li "window_find_matches" Ta "Matched data from the find-window command if available" .It Li "window_flags" Ta "Window flags" .It Li "window_height" Ta "Height of window" +.It Li "window_id" Ta "Unique window ID" .It Li "window_index" Ta "Index of window" .It Li "window_layout" Ta "Window layout description" .It Li "window_name" Ta "Name of window" From a3dec6becef3295e8bd376d5e5b017c538fb10fc Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 11 Aug 2012 06:45:33 +0000 Subject: [PATCH 1155/1180] Instead of numbering choose mode items 0-9a-z and then nothing, number them all and if there are more than 10 use a prompt when 0-9 is pressed. From Thomas Adam. --- mode-key.c | 24 ++++++++ tmux.h | 9 ++- window-choose.c | 159 +++++++++++++++++++++++++++++++++--------------- window-copy.c | 10 +-- window.c | 10 +++ 5 files changed, 152 insertions(+), 60 deletions(-) diff --git a/mode-key.c b/mode-key.c index d6906d45..bae6650c 100644 --- a/mode-key.c +++ b/mode-key.c @@ -74,6 +74,7 @@ const struct mode_key_cmdstr mode_key_cmdstr_edit[] = { /* Choice keys command strings. */ const struct mode_key_cmdstr mode_key_cmdstr_choice[] = { + { MODEKEYCHOICE_BACKSPACE, "backspace" }, { MODEKEYCHOICE_CANCEL, "cancel" }, { MODEKEYCHOICE_CHOOSE, "choose" }, { MODEKEYCHOICE_DOWN, "down" }, @@ -81,6 +82,7 @@ const struct mode_key_cmdstr mode_key_cmdstr_choice[] = { { MODEKEYCHOICE_PAGEUP, "page-up" }, { MODEKEYCHOICE_SCROLLDOWN, "scroll-down" }, { MODEKEYCHOICE_SCROLLUP, "scroll-up" }, + { MODEKEYCHOICE_STARTNUMBERPREFIX, "start-number-prefix" }, { MODEKEYCHOICE_UP, "up" }, { 0, NULL } @@ -190,6 +192,16 @@ struct mode_key_tree mode_key_tree_vi_edit; /* vi choice selection keys. */ const struct mode_key_entry mode_key_vi_choice[] = { + { '0', 0, MODEKEYCHOICE_STARTNUMBERPREFIX }, + { '1', 0, MODEKEYCHOICE_STARTNUMBERPREFIX }, + { '2', 0, MODEKEYCHOICE_STARTNUMBERPREFIX }, + { '3', 0, MODEKEYCHOICE_STARTNUMBERPREFIX }, + { '4', 0, MODEKEYCHOICE_STARTNUMBERPREFIX }, + { '5', 0, MODEKEYCHOICE_STARTNUMBERPREFIX }, + { '6', 0, MODEKEYCHOICE_STARTNUMBERPREFIX }, + { '7', 0, MODEKEYCHOICE_STARTNUMBERPREFIX }, + { '8', 0, MODEKEYCHOICE_STARTNUMBERPREFIX }, + { '9', 0, MODEKEYCHOICE_STARTNUMBERPREFIX }, { '\002' /* C-b */, 0, MODEKEYCHOICE_PAGEUP }, { '\003' /* C-c */, 0, MODEKEYCHOICE_CANCEL }, { '\005' /* C-e */, 0, MODEKEYCHOICE_SCROLLDOWN }, @@ -199,6 +211,7 @@ const struct mode_key_entry mode_key_vi_choice[] = { { 'j', 0, MODEKEYCHOICE_DOWN }, { 'k', 0, MODEKEYCHOICE_UP }, { 'q', 0, MODEKEYCHOICE_CANCEL }, + { KEYC_BSPACE, 0, MODEKEYCHOICE_BACKSPACE }, { KEYC_DOWN | KEYC_CTRL,0, MODEKEYCHOICE_SCROLLDOWN }, { KEYC_DOWN, 0, MODEKEYCHOICE_DOWN }, { KEYC_NPAGE, 0, MODEKEYCHOICE_PAGEDOWN }, @@ -317,6 +330,16 @@ struct mode_key_tree mode_key_tree_emacs_edit; /* emacs choice selection keys. */ const struct mode_key_entry mode_key_emacs_choice[] = { + { '0', 0, MODEKEYCHOICE_STARTNUMBERPREFIX }, + { '1', 0, MODEKEYCHOICE_STARTNUMBERPREFIX }, + { '2', 0, MODEKEYCHOICE_STARTNUMBERPREFIX }, + { '3', 0, MODEKEYCHOICE_STARTNUMBERPREFIX }, + { '4', 0, MODEKEYCHOICE_STARTNUMBERPREFIX }, + { '5', 0, MODEKEYCHOICE_STARTNUMBERPREFIX }, + { '6', 0, MODEKEYCHOICE_STARTNUMBERPREFIX }, + { '7', 0, MODEKEYCHOICE_STARTNUMBERPREFIX }, + { '8', 0, MODEKEYCHOICE_STARTNUMBERPREFIX }, + { '9', 0, MODEKEYCHOICE_STARTNUMBERPREFIX }, { '\003' /* C-c */, 0, MODEKEYCHOICE_CANCEL }, { '\016' /* C-n */, 0, MODEKEYCHOICE_DOWN }, { '\020' /* C-p */, 0, MODEKEYCHOICE_UP }, @@ -325,6 +348,7 @@ const struct mode_key_entry mode_key_emacs_choice[] = { { '\r', 0, MODEKEYCHOICE_CHOOSE }, { 'q', 0, MODEKEYCHOICE_CANCEL }, { 'v' | KEYC_ESCAPE, 0, MODEKEYCHOICE_PAGEUP }, + { KEYC_BSPACE, 0, MODEKEYCHOICE_BACKSPACE }, { KEYC_DOWN | KEYC_CTRL,0, MODEKEYCHOICE_SCROLLDOWN }, { KEYC_DOWN, 0, MODEKEYCHOICE_DOWN }, { KEYC_NPAGE, 0, MODEKEYCHOICE_PAGEDOWN }, diff --git a/tmux.h b/tmux.h index 6c03cdc3..0b20eb56 100644 --- a/tmux.h +++ b/tmux.h @@ -503,6 +503,7 @@ enum mode_key_cmd { MODEKEYEDIT_TRANSPOSECHARS, /* Menu (choice) keys. */ + MODEKEYCHOICE_BACKSPACE, MODEKEYCHOICE_CANCEL, MODEKEYCHOICE_CHOOSE, MODEKEYCHOICE_DOWN, @@ -510,6 +511,7 @@ enum mode_key_cmd { MODEKEYCHOICE_PAGEUP, MODEKEYCHOICE_SCROLLDOWN, MODEKEYCHOICE_SCROLLUP, + MODEKEYCHOICE_STARTNUMBERPREFIX, MODEKEYCHOICE_UP, /* Copy keys. */ @@ -851,14 +853,16 @@ struct window_choose_data { struct client *client; struct session *session; struct format_tree *ft; + struct winlink *wl; char *ft_template; char *command; u_int idx; }; struct window_choose_mode_item { - struct window_choose_data *wcd; - char *name; + struct window_choose_data *wcd; + char *name; + int pos; }; /* Child window structure. */ @@ -2087,6 +2091,7 @@ struct window_pane *window_pane_find_left(struct window_pane *); struct window_pane *window_pane_find_right(struct window_pane *); void window_set_name(struct window *, const char *); 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 *); diff --git a/window-choose.c b/window-choose.c index 58ac80ee..592d9f7f 100644 --- a/window-choose.c +++ b/window-choose.c @@ -40,6 +40,11 @@ void window_choose_write_line( void window_choose_scroll_up(struct window_pane *); void window_choose_scroll_down(struct window_pane *); +enum window_choose_input_type { + WINDOW_CHOOSE_NORMAL = -1, + WINDOW_CHOOSE_GOTO_ITEM, +}; + const struct window_mode window_choose_mode = { window_choose_init, window_choose_free, @@ -55,27 +60,39 @@ struct window_choose_mode_data { struct mode_key_data mdata; ARRAY_DECL(, struct window_choose_mode_item) list; + int width; u_int top; u_int selected; + enum window_choose_input_type input_type; + const char *input_prompt; + char *input_str; void (*callbackfn)(struct window_choose_data *); void (*freefn)(struct window_choose_data *); }; -int window_choose_key_index(struct window_choose_mode_data *, u_int); -int window_choose_index_key(struct window_choose_mode_data *, int); +int window_choose_index_key(int); +void window_choose_prompt_input(enum window_choose_input_type, + const char *, struct window_pane *, int); void window_choose_add(struct window_pane *wp, struct window_choose_data *wcd) { struct window_choose_mode_data *data = wp->modedata; struct window_choose_mode_item *item; + int width; + char tmp[10]; ARRAY_EXPAND(&data->list, 1); item = &ARRAY_LAST(&data->list); item->name = format_expand(wcd->ft, wcd->ft_template); item->wcd = wcd; + item->pos = ARRAY_LENGTH(&data->list) - 1; + + width = snprintf (tmp, sizeof tmp, "%u", item->pos); + if (width > data->width) + data->width = width; } void @@ -107,6 +124,9 @@ window_choose_init(struct window_pane *wp) data->callbackfn = NULL; data->freefn = NULL; + data->input_type = WINDOW_CHOOSE_NORMAL; + data->input_str = xstrdup(""); + data->input_prompt = NULL; ARRAY_INIT(&data->list); data->top = 0; @@ -156,6 +176,7 @@ window_choose_free(struct window_pane *wp) free(item->name); } ARRAY_FREE(&data->list); + free(data->input_str); screen_free(&data->screen); free(data); @@ -190,6 +211,24 @@ window_choose_fire_callback( wp->mode = oldmode; } +void +window_choose_prompt_input(enum window_choose_input_type input_type, + const char *prompt, struct window_pane *wp, int key) +{ + struct window_choose_mode_data *data = wp->modedata; + size_t input_len; + + data->input_type = input_type; + data->input_prompt = prompt; + input_len = strlen(data->input_str) + 2; + + data->input_str = xrealloc(data->input_str, 1, input_len); + data->input_str[input_len - 2] = key; + data->input_str[input_len - 1] = '\0'; + + window_choose_redraw_screen(wp); +} + /* ARGSUSED */ void window_choose_key(struct window_pane *wp, unused struct session *sess, int key) @@ -198,7 +237,8 @@ window_choose_key(struct window_pane *wp, unused struct session *sess, int key) struct screen *s = &data->screen; struct screen_write_ctx ctx; struct window_choose_mode_item *item; - u_int items; + size_t input_len; + u_int items, n; int idx; items = ARRAY_LENGTH(&data->list); @@ -209,9 +249,21 @@ window_choose_key(struct window_pane *wp, unused struct session *sess, int key) window_pane_reset_mode(wp); break; case MODEKEYCHOICE_CHOOSE: - item = &ARRAY_ITEM(&data->list, data->selected); - window_choose_fire_callback(wp, item->wcd); - window_pane_reset_mode(wp); + switch (data->input_type) { + case WINDOW_CHOOSE_NORMAL: + item = &ARRAY_ITEM(&data->list, data->selected); + window_choose_fire_callback(wp, item->wcd); + window_pane_reset_mode(wp); + break; + case WINDOW_CHOOSE_GOTO_ITEM: + n = strtonum(data->input_str, 0, INT_MAX, NULL); + if (n > items - 1) + break; + item = &ARRAY_ITEM(&data->list, n); + window_choose_fire_callback(wp, item->wcd); + window_pane_reset_mode(wp); + break; + } break; case MODEKEYCHOICE_UP: if (items == 0) @@ -309,15 +361,36 @@ window_choose_key(struct window_pane *wp, unused struct session *sess, int key) data->top = data->selected; window_choose_redraw_screen(wp); break; - default: - idx = window_choose_index_key(data, key); - if (idx < 0 || (u_int) idx >= ARRAY_LENGTH(&data->list)) + case MODEKEYCHOICE_BACKSPACE: + input_len = strlen(data->input_str); + if (input_len > 0) + data->input_str[input_len - 1] = '\0'; + window_choose_redraw_screen(wp); + break; + case MODEKEYCHOICE_STARTNUMBERPREFIX: + if (key < '0' && key > '9') break; - data->selected = idx; - item = &ARRAY_ITEM(&data->list, data->selected); - window_choose_fire_callback(wp, item->wcd); - window_pane_reset_mode(wp); + /* + * If there's less than ten items (0-9) then pressing a number + * will automatically select that item; otherwise, prompt for + * the item to go to. + */ + if (ARRAY_LENGTH(&data->list) - 1 <= 9) { + idx = window_choose_index_key(key); + if (idx < 0 || (u_int) idx >= ARRAY_LENGTH(&data->list)) + break; + data->selected = idx; + + item = &ARRAY_ITEM(&data->list, data->selected); + window_choose_fire_callback(wp, item->wcd); + window_pane_reset_mode(wp); + } else { + window_choose_prompt_input( + WINDOW_CHOOSE_GOTO_ITEM, "Goto item", wp, key); + } + break; + default: break; } } @@ -358,65 +431,51 @@ window_choose_write_line( struct options *oo = &wp->window->options; struct screen *s = &data->screen; struct grid_cell gc; - int utf8flag, key; + size_t last, xoff = 0; + char hdr[32]; + int utf8flag; if (data->callbackfn == NULL) fatalx("called before callback assigned"); + last = screen_size_y(s) - 1; utf8flag = options_get_number(&wp->window->options, "utf8"); memcpy(&gc, &grid_default_cell, sizeof gc); - if (data->selected == data->top + py) { - 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"); - } + if (data->selected == data->top + py) + window_mode_attrs(&gc, oo); screen_write_cursormove(ctx, 0, py); if (data->top + py < ARRAY_LENGTH(&data->list)) { item = &ARRAY_ITEM(&data->list, data->top + py); - key = window_choose_key_index(data, data->top + py); - if (key != -1) { - screen_write_nputs(ctx, screen_size_x(s) - 1, - &gc, utf8flag, "(%c) %s", key, item->name); - } else { - screen_write_nputs(ctx, screen_size_x(s) - 1, - &gc, utf8flag, " %s", item->name); - } + screen_write_nputs(ctx, screen_size_x(s) - 1, + &gc, utf8flag, "(%*d) %s", data->width, + item->pos, item->name); } while (s->cx < screen_size_x(s)) screen_write_putc(ctx, &gc, ' '); -} -int -window_choose_key_index(struct window_choose_mode_data *data, u_int idx) -{ - static const char keys[] = "0123456789abcdefghijklmnopqrstuvwxyz"; - const char *ptr; - int mkey; + if (data->input_type != WINDOW_CHOOSE_NORMAL) { + window_mode_attrs(&gc, oo); - for (ptr = keys; *ptr != '\0'; ptr++) { - mkey = mode_key_lookup(&data->mdata, *ptr); - if (mkey != MODEKEY_NONE && mkey != MODEKEY_OTHER) - continue; - if (idx-- == 0) - return (*ptr); + xoff = xsnprintf(hdr, sizeof hdr, + "%s: %s", data->input_prompt, data->input_str); + screen_write_cursormove(ctx, 0, last); + screen_write_puts(ctx, &gc, "%s", hdr); + screen_write_cursormove(ctx, xoff, py); + memcpy(&gc, &grid_default_cell, sizeof gc); } - return (-1); + } int -window_choose_index_key(struct window_choose_mode_data *data, int key) +window_choose_index_key(int key) { - static const char keys[] = "0123456789abcdefghijklmnopqrstuvwxyz"; + static const char keys[] = "0123456789"; const char *ptr; - int mkey; u_int idx = 0; for (ptr = keys; *ptr != '\0'; ptr++) { - mkey = mode_key_lookup(&data->mdata, *ptr); - if (mkey != MODEKEY_NONE && mkey != MODEKEY_OTHER) - continue; if (key == *ptr) return (idx); idx++; @@ -514,7 +573,7 @@ window_choose_ctx(struct window_choose_data *cdata) struct window_choose_data * window_choose_add_session(struct window_pane *wp, struct cmd_ctx *ctx, - struct session *s, const char *template, char *action, u_int idx) + struct session *s, const char *template, char *action, u_int idx) { struct window_choose_data *wcd; @@ -535,8 +594,8 @@ window_choose_add_session(struct window_pane *wp, struct cmd_ctx *ctx, struct window_choose_data * window_choose_add_window(struct window_pane *wp, struct cmd_ctx *ctx, - struct session *s, struct winlink *wl, const char *template, - char *action, u_int idx) + struct session *s, struct winlink *wl, const char *template, + char *action, u_int idx) { struct window_choose_data *wcd; char *action_data; diff --git a/window-copy.c b/window-copy.c index 089974f1..2c10861a 100644 --- a/window-copy.c +++ b/window-copy.c @@ -1115,10 +1115,7 @@ window_copy_write_line( char hdr[32]; size_t last, xoff = 0, size = 0; - 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"); + window_mode_attrs(&gc, oo); last = screen_size_y(s) - 1; if (py == 0) { @@ -1232,10 +1229,7 @@ window_copy_update_selection(struct window_pane *wp) return (0); /* Set colours. */ - 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"); + window_mode_attrs(&gc, oo); /* Find top of screen. */ ty = screen_hsize(data->backing) - data->oy; diff --git a/window.c b/window.c index cf738a1d..dcf1dd04 100644 --- a/window.c +++ b/window.c @@ -1183,3 +1183,13 @@ 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 8889a48f9baa6e05e387750930da84fd391600f9 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 11 Aug 2012 06:46:47 +0000 Subject: [PATCH 1156/1180] Fix a return type. --- cmd-choose-tree.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd-choose-tree.c b/cmd-choose-tree.c index 1fa40c96..102fdc3c 100644 --- a/cmd-choose-tree.c +++ b/cmd-choose-tree.c @@ -34,7 +34,7 @@ * Enter choice mode to choose a session and/or window. */ -int cmd_choose_tree_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_choose_tree_exec(struct cmd *, struct cmd_ctx *); void cmd_choose_tree_callback(struct window_choose_data *); void cmd_choose_tree_free(struct window_choose_data *); From cf2e65c0e2776ca14d5a70f52afa10da0d8d2bc7 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 11 Aug 2012 07:10:01 +0000 Subject: [PATCH 1157/1180] Another missing format from sam at sltosis.org. --- tmux.1 | 1 + 1 file changed, 1 insertion(+) diff --git a/tmux.1 b/tmux.1 index b9110287..9d206dfb 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2906,6 +2906,7 @@ The following variables are available, where appropriate: .It Li "host" Ta "Hostname of local host" .It Li "history_bytes" Ta "Number of bytes in window history" .It Li "history_limit" Ta "Maximum window history lines" +.It Li "history_size" Ta "Size of history in bytes" .It Li "line" Ta "Line number in the list" .It Li "pane_active" Ta "1 if active pane" .It Li "pane_current_path" Ta "Current path if available" From a194430e5de1f798913034099f4df72af3d9bd4b Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 11 Aug 2012 07:32:16 +0000 Subject: [PATCH 1158/1180] Remove dead code, from Sean Estabrooks. --- cmd-if-shell.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/cmd-if-shell.c b/cmd-if-shell.c index 5e23fb10..4cb9de82 100644 --- a/cmd-if-shell.c +++ b/cmd-if-shell.c @@ -106,11 +106,9 @@ cmd_if_shell_free(void *data) { struct cmd_if_shell_data *cdata = data; struct cmd_ctx *ctx = &cdata->ctx; - struct msg_exit_data exitdata; if (ctx->cmdclient != NULL) { ctx->cmdclient->references--; - exitdata.retcode = ctx->cmdclient->retcode; ctx->cmdclient->flags |= CLIENT_EXIT; } if (ctx->curclient != NULL) From 20129b7bf91d17e69f818b7cea00255e044354c3 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 12 Aug 2012 06:22:26 +0000 Subject: [PATCH 1159/1180] Simplify width calculation (all numbers always sequential) and don't rely on uninitialized data, from Thomas Adam. --- window-choose.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/window-choose.c b/window-choose.c index 592d9f7f..da4ab35a 100644 --- a/window-choose.c +++ b/window-choose.c @@ -80,7 +80,6 @@ window_choose_add(struct window_pane *wp, struct window_choose_data *wcd) { struct window_choose_mode_data *data = wp->modedata; struct window_choose_mode_item *item; - int width; char tmp[10]; ARRAY_EXPAND(&data->list, 1); @@ -90,9 +89,7 @@ window_choose_add(struct window_pane *wp, struct window_choose_data *wcd) item->wcd = wcd; item->pos = ARRAY_LENGTH(&data->list) - 1; - width = snprintf (tmp, sizeof tmp, "%u", item->pos); - if (width > data->width) - data->width = width; + data->width = snprintf (tmp, sizeof tmp , "%u", item->pos); } void From 6804d5841e53a38e2d4a8d574bcece384efa9499 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 14 Aug 2012 08:15:00 +0000 Subject: [PATCH 1160/1180] Add a patch missed during a merge sometime to use TAILQ_FOREACH_SAFE. From Tiago Cunha. --- cmd-kill-pane.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/cmd-kill-pane.c b/cmd-kill-pane.c index ff8c425f..51989768 100644 --- a/cmd-kill-pane.c +++ b/cmd-kill-pane.c @@ -43,7 +43,7 @@ cmd_kill_pane_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; struct winlink *wl; - struct window_pane *loopwp, *nextwp, *wp; + struct window_pane *loopwp, *tmpwp, *wp; if ((wl = cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp)) == NULL) return (CMD_RETURN_ERROR); @@ -56,14 +56,11 @@ cmd_kill_pane_exec(struct cmd *self, struct cmd_ctx *ctx) } if (args_has(self->args, 'a')) { - loopwp = TAILQ_FIRST(&wl->window->panes); - while (loopwp != NULL) { - nextwp = TAILQ_NEXT(loopwp, entry); - if (loopwp != wp) { - layout_close_pane(loopwp); - window_remove_pane(wl->window, loopwp); - } - loopwp = nextwp; + TAILQ_FOREACH_SAFE(loopwp, &wl->window->panes, entry, tmpwp) { + if (loopwp == wp) + continue; + layout_close_pane(loopwp); + window_remove_pane(wl->window, loopwp); } } else { layout_close_pane(wp); From 73c678553809956f428fec9db3210a5576d5883f Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 14 Aug 2012 08:51:53 +0000 Subject: [PATCH 1161/1180] Use a separate define for each default format template and strip clutter from the choose-tree defaults. --- cmd-break-pane.c | 2 +- cmd-choose-buffer.c | 2 +- cmd-choose-client.c | 2 +- cmd-choose-tree.c | 10 +++----- cmd-display-message.c | 2 +- cmd-find-window.c | 2 +- cmd-list-buffers.c | 2 +- cmd-list-clients.c | 2 +- cmd-list-sessions.c | 2 +- cmd-list-windows.c | 6 ++--- cmd-new-window.c | 2 +- cmd-split-window.c | 2 +- tmux.h | 60 +++++++++++++++++++++++++++++++++++-------- 13 files changed, 66 insertions(+), 30 deletions(-) diff --git a/cmd-break-pane.c b/cmd-break-pane.c index 5ddb8362..038ec85c 100644 --- a/cmd-break-pane.c +++ b/cmd-break-pane.c @@ -95,7 +95,7 @@ cmd_break_pane_exec(struct cmd *self, struct cmd_ctx *ctx) if (args_has(args, 'P')) { if ((template = args_get(args, 'F')) == NULL) - template = DEFAULT_PANE_INFO_TEMPLATE; + template = BREAK_PANE_TEMPLATE; ft = format_create(); if ((c = cmd_find_client(ctx, NULL)) != NULL) diff --git a/cmd-choose-buffer.c b/cmd-choose-buffer.c index 3deedfa9..b811a042 100644 --- a/cmd-choose-buffer.c +++ b/cmd-choose-buffer.c @@ -59,7 +59,7 @@ cmd_choose_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) } if ((template = args_get(args, 'F')) == NULL) - template = DEFAULT_BUFFER_LIST_TEMPLATE; + template = CHOOSE_BUFFER_TEMPLATE; if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL) return (CMD_RETURN_ERROR); diff --git a/cmd-choose-client.c b/cmd-choose-client.c index 4059cbba..299fa3af 100644 --- a/cmd-choose-client.c +++ b/cmd-choose-client.c @@ -70,7 +70,7 @@ cmd_choose_client_exec(struct cmd *self, struct cmd_ctx *ctx) return (CMD_RETURN_NORMAL); if ((template = args_get(args, 'F')) == NULL) - template = DEFAULT_CLIENT_TEMPLATE; + template = CHOOSE_CLIENT_TEMPLATE; if (args->argc != 0) action = xstrdup(args->argv[0]); diff --git a/cmd-choose-tree.c b/cmd-choose-tree.c index 102fdc3c..e4fd267e 100644 --- a/cmd-choose-tree.c +++ b/cmd-choose-tree.c @@ -27,8 +27,6 @@ #define CMD_CHOOSE_TREE_WINDOW_ACTION "select-window -t '%%'" #define CMD_CHOOSE_TREE_SESSION_ACTION "switch-client -t '%%'" -#define CMD_CHOOSE_TREE_WINDOW_TEMPLATE \ - DEFAULT_WINDOW_TEMPLATE " \"#{pane_title}\"" /* * Enter choice mode to choose a session and/or window. @@ -104,7 +102,7 @@ cmd_choose_tree_exec(struct cmd *self, struct cmd_ctx *ctx) if (self->entry == &cmd_choose_session_entry) { sflag = 1; if ((ses_template = args_get(args, 'F')) == NULL) - ses_template = DEFAULT_SESSION_TEMPLATE; + ses_template = CHOOSE_TREE_SESSION_TEMPLATE; if (args->argc != 0) ses_action = args->argv[0]; @@ -113,7 +111,7 @@ cmd_choose_tree_exec(struct cmd *self, struct cmd_ctx *ctx) } else if (self->entry == &cmd_choose_window_entry) { wflag = 1; if ((win_template = args_get(args, 'F')) == NULL) - win_template = CMD_CHOOSE_TREE_WINDOW_TEMPLATE; + win_template = CHOOSE_TREE_WINDOW_TEMPLATE; if (args->argc != 0) win_action = args->argv[0]; @@ -130,10 +128,10 @@ cmd_choose_tree_exec(struct cmd *self, struct cmd_ctx *ctx) win_action = CMD_CHOOSE_TREE_WINDOW_ACTION; if ((ses_template = args_get(args, 'S')) == NULL) - ses_template = DEFAULT_SESSION_TEMPLATE; + ses_template = CHOOSE_TREE_SESSION_TEMPLATE; if ((win_template = args_get(args, 'W')) == NULL) - win_template = CMD_CHOOSE_TREE_WINDOW_TEMPLATE; + win_template = CHOOSE_TREE_WINDOW_TEMPLATE; } /* diff --git a/cmd-display-message.c b/cmd-display-message.c index 1aed4f1d..a520e3db 100644 --- a/cmd-display-message.c +++ b/cmd-display-message.c @@ -76,7 +76,7 @@ cmd_display_message_exec(struct cmd *self, struct cmd_ctx *ctx) if (args->argc != 0) template = args->argv[0]; if (template == NULL) - template = DEFAULT_DISPLAY_MESSAGE_TEMPLATE; + template = DISPLAY_MESSAGE_TEMPLATE; ft = format_create(); format_client(ft, c); diff --git a/cmd-find-window.c b/cmd-find-window.c index e73effbf..44bf1770 100644 --- a/cmd-find-window.c +++ b/cmd-find-window.c @@ -98,7 +98,7 @@ cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx) return (CMD_RETURN_ERROR); if ((template = args_get(args, 'F')) == NULL) - template = DEFAULT_FIND_WINDOW_TEMPLATE; + template = FIND_WINDOW_TEMPLATE; match_flags = cmd_find_window_match_flags(args); str = args->argv[0]; diff --git a/cmd-list-buffers.c b/cmd-list-buffers.c index f22a35bc..e7f4b735 100644 --- a/cmd-list-buffers.c +++ b/cmd-list-buffers.c @@ -51,7 +51,7 @@ cmd_list_buffers_exec(unused struct cmd *self, struct cmd_ctx *ctx) const char *template; if ((template = args_get(args, 'F')) == NULL) - template = DEFAULT_BUFFER_LIST_TEMPLATE; + template = LIST_BUFFERS_TEMPLATE; idx = 0; while ((pb = paste_walk_stack(&global_buffers, &idx)) != NULL) { diff --git a/cmd-list-clients.c b/cmd-list-clients.c index af6ebde2..ba479689 100644 --- a/cmd-list-clients.c +++ b/cmd-list-clients.c @@ -60,7 +60,7 @@ cmd_list_clients_exec(struct cmd *self, struct cmd_ctx *ctx) s = NULL; if ((template = args_get(args, 'F')) == NULL) - template = DEFAULT_CLIENT_TEMPLATE; + template = LIST_CLIENTS_TEMPLATE; for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); diff --git a/cmd-list-sessions.c b/cmd-list-sessions.c index 6db1e11c..81cc51cc 100644 --- a/cmd-list-sessions.c +++ b/cmd-list-sessions.c @@ -51,7 +51,7 @@ cmd_list_sessions_exec(struct cmd *self, struct cmd_ctx *ctx) char *line; if ((template = args_get(args, 'F')) == NULL) - template = DEFAULT_SESSION_TEMPLATE; + template = LIST_SESSIONS_TEMPLATE; n = 0; RB_FOREACH(s, sessions, &sessions) { diff --git a/cmd-list-windows.c b/cmd-list-windows.c index 62ae6b11..146d29aa 100644 --- a/cmd-list-windows.c +++ b/cmd-list-windows.c @@ -85,12 +85,10 @@ cmd_list_windows_session( if (template == NULL) { switch (type) { case 0: - template = DEFAULT_WINDOW_TEMPLATE \ - " [layout #{window_layout}] #{window_id}" \ - "#{?window_active, (active),}"; + template = LIST_WINDOWS_TEMPLATE; break; case 1: - template = "#{session_name}:" DEFAULT_WINDOW_TEMPLATE; + template = LIST_WINDOWS_WITH_SESSION_TEMPLATE; break; } } diff --git a/cmd-new-window.c b/cmd-new-window.c index 28dd2358..1d9a1e66 100644 --- a/cmd-new-window.c +++ b/cmd-new-window.c @@ -123,7 +123,7 @@ cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx) if (args_has(args, 'P')) { if ((template = args_get(args, 'F')) == NULL) - template = DEFAULT_PANE_INFO_TEMPLATE; + template = NEW_WINDOW_TEMPLATE; ft = format_create(); if ((c = cmd_find_client(ctx, NULL)) != NULL) diff --git a/cmd-split-window.c b/cmd-split-window.c index 88d451c8..2d51d357 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -140,7 +140,7 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) if (args_has(args, 'P')) { if ((template = args_get(args, 'F')) == NULL) - template = DEFAULT_PANE_INFO_TEMPLATE; + template = SPLIT_WINDOW_TEMPLATE; ft = format_create(); if ((c = cmd_find_client(ctx, NULL)) != NULL) diff --git a/tmux.h b/tmux.h index 0b20eb56..10d4f03d 100644 --- a/tmux.h +++ b/tmux.h @@ -92,34 +92,74 @@ extern char **environ; #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) #endif -/* Default format templates. */ -#define DEFAULT_BUFFER_LIST_TEMPLATE \ +/* Default template for choose-buffer. */ +#define CHOOSE_BUFFER_TEMPLATE \ "#{line}: #{buffer_size} bytes: \"#{buffer_sample}\"" -#define DEFAULT_CLIENT_TEMPLATE \ + +/* Default template for choose-client. */ +#define CHOOSE_CLIENT_TEMPLATE \ "#{client_tty}: #{session_name} " \ "[#{client_width}x#{client_height} #{client_termname}]" \ "#{?client_utf8, (utf8),} #{?client_readonly, (ro),}" -#define DEFAULT_DISPLAY_MESSAGE_TEMPLATE \ + +/* Default templates for choose-tree. */ +#define CHOOSE_TREE_SESSION_TEMPLATE \ + "#{session_name}: #{session_windows} windows " \ + "#{?session_grouped, (group ,}" \ + "#{session_group}#{?session_grouped,),}" \ + "#{?session_attached, (attached),}" +#define CHOOSE_TREE_WINDOW_TEMPLATE \ + "#{window_index}: #{window_name}#{window_flags} " \ + "\"#{pane_title}\"" + +/* Default template for display-message. */ +#define DISPLAY_MESSAGE_TEMPLATE \ "[#{session_name}] #{window_index}:" \ "#{window_name}, current pane #{pane_index} " \ "- (%H:%M %d-%b-%y)" -#define DEFAULT_FIND_WINDOW_TEMPLATE \ + +/* Default template for find-window. */ +#define FIND_WINDOW_TEMPLATE \ "#{window_index}: #{window_name} " \ "[#{window_width}x#{window_height}] " \ "(#{window_panes} panes) #{window_find_matches}" -#define DEFAULT_SESSION_TEMPLATE \ + +/* Default template for list-buffers. */ +#define LIST_BUFFERS_TEMPLATE \ + "#{line}: #{buffer_size} bytes: \"#{buffer_sample}\"" + +/* Default template for list-clients. */ +#define LIST_CLIENTS_TEMPLATE \ + "#{client_tty}: #{session_name} " \ + "[#{client_width}x#{client_height} #{client_termname}]" \ + "#{?client_utf8, (utf8),} #{?client_readonly, (ro),}" + +/* Default template for list-sessions. */ +#define LIST_SESSIONS_TEMPLATE \ "#{session_name}: #{session_windows} windows " \ "(created #{session_created_string}) " \ "[#{session_width}x#{session_height}]" \ "#{?session_grouped, (group ,}" \ "#{session_group}#{?session_grouped,),}" \ "#{?session_attached, (attached),}" -#define DEFAULT_WINDOW_TEMPLATE \ + +/* Default templates for list-windows. */ +#define LIST_WINDOWS_TEMPLATE \ "#{window_index}: #{window_name}#{window_flags} " \ "(#{window_panes} panes) " \ - "[#{window_width}x#{window_height}]" -#define DEFAULT_PANE_INFO_TEMPLATE \ - "#{session_name}:#{window_index}.#{pane_index}" + "[#{window_width}x#{window_height}] " \ + "[layout #{window_layout}] #{window_id}" \ + "#{?window_active, (active),}"; +#define LIST_WINDOWS_WITH_SESSION_TEMPLATE \ + "#{session_name}: " \ + "#{window_index}: #{window_name}#{window_flags} " \ + "(#{window_panes} panes) " \ + "[#{window_width}x#{window_height}] " + +/* Default templates for break-pane, new-window and split-window. */ +#define BREAK_PANE_TEMPLATE "#{session_name}:#{window_index}.#{pane_index}" +#define NEW_WINDOW_TEMPLATE BREAK_PANE_TEMPLATE +#define SPLIT_WINDOW_TEMPLATE BREAK_PANE_TEMPLATE /* Bell option values. */ #define BELL_NONE 0 From f61fc576d922b4eb3780933a7808d35bd3725917 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 14 Aug 2012 08:58:25 +0000 Subject: [PATCH 1162/1180] Tidy up tty_write, from Sean Estabrooks. --- tty.c | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/tty.c b/tty.c index d40e95d7..68d23fc2 100644 --- a/tty.c +++ b/tty.c @@ -667,7 +667,6 @@ tty_write( { struct window_pane *wp = ctx->wp; struct client *c; - struct session *s; u_int i; /* wp can be NULL if updating the screen but not the terminal. */ @@ -681,25 +680,19 @@ tty_write( for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); - if (c == NULL || c->session == NULL) + if (c == NULL || c->session == NULL || c->tty.term == NULL) continue; - if (c->flags & CLIENT_SUSPENDED) + if (c->flags & (CLIENT_SUSPENDED|TTY_FREEZE)) + continue; + if (c->session->curw->window != wp->window) continue; - s = c->session; - if (s->curw->window == wp->window) { - if (c->tty.term == NULL) - continue; - if (c->tty.flags & TTY_FREEZE) - continue; + ctx->xoff = wp->xoff; + ctx->yoff = wp->yoff; + if (status_at_line(c) == 0) + ctx->yoff++; - ctx->xoff = wp->xoff; - ctx->yoff = wp->yoff; - if (status_at_line(c) == 0) - ctx->yoff++; - - cmdfn(&c->tty, ctx); - } + cmdfn(&c->tty, ctx); } } From a1e4908ed7d14c5b406541144017d57db4750c56 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 14 Aug 2012 09:17:14 +0000 Subject: [PATCH 1163/1180] Boldify windows with alerts in choose-* list. --- window-choose.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/window-choose.c b/window-choose.c index da4ab35a..99c09d52 100644 --- a/window-choose.c +++ b/window-choose.c @@ -152,6 +152,7 @@ window_choose_data_create(struct cmd_ctx *ctx) wcd->ft = format_create(); wcd->ft_template = NULL; wcd->command = NULL; + wcd->wl = NULL; wcd->client = ctx->curclient; wcd->session = ctx->curclient->session; wcd->idx = -1; @@ -444,6 +445,9 @@ window_choose_write_line( screen_write_cursormove(ctx, 0, py); if (data->top + py < ARRAY_LENGTH(&data->list)) { item = &ARRAY_ITEM(&data->list, data->top + py); + if (item->wcd->wl != NULL && + item->wcd->wl->flags & WINLINK_ALERTFLAGS) + gc.attr |= GRID_ATTR_BRIGHT; screen_write_nputs(ctx, screen_size_x(s) - 1, &gc, utf8flag, "(%*d) %s", data->width, item->pos, item->name); @@ -604,6 +608,7 @@ window_choose_add_window(struct window_pane *wp, struct cmd_ctx *ctx, free(action_data); wcd->idx = wl->idx; + wcd->wl = wl; wcd->ft_template = xstrdup(template); format_add(wcd->ft, "line", "%u", idx); format_session(wcd->ft, s); From 58e8e0eac841d6d337de3da4e2f81665c3cd3faa Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 21 Aug 2012 10:00:33 +0000 Subject: [PATCH 1164/1180] Fix up window reference counting and don't crash if the rename timer fires while the window is dead but still referenced. Fixes problem reported by Michael Scholz. --- names.c | 3 +++ notify.c | 3 ++- tmux.h | 1 + window.c | 19 ++++++++++++------- 4 files changed, 18 insertions(+), 8 deletions(-) diff --git a/names.c b/names.c index de4b30cc..46708bce 100644 --- a/names.c +++ b/names.c @@ -50,6 +50,9 @@ window_name_callback(unused int fd, unused short events, void *data) struct window *w = data; char *name, *wname; + if (w->active == NULL) + return; + if (!options_get_number(&w->options, "automatic-rename")) { if (event_initialized(&w->name_timer)) event_del(&w->name_timer); diff --git a/notify.c b/notify.c index dad50b94..33fea56c 100644 --- a/notify.c +++ b/notify.c @@ -125,7 +125,8 @@ notify_drain(void) if (ne->session != NULL) ne->session->references--; if (ne->window != NULL) - ne->window->references--; + window_remove_ref(ne->window); + TAILQ_REMOVE(¬ify_queue, ne, entry); free(ne); } diff --git a/tmux.h b/tmux.h index 10d4f03d..449f0676 100644 --- a/tmux.h +++ b/tmux.h @@ -2130,6 +2130,7 @@ struct window_pane *window_pane_find_down(struct window_pane *); struct window_pane *window_pane_find_left(struct window_pane *); 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 *); diff --git a/window.c b/window.c index dcf1dd04..71225a9b 100644 --- a/window.c +++ b/window.c @@ -182,13 +182,8 @@ winlink_remove(struct winlinks *wwl, struct winlink *wl) free(wl->status_text); free(wl); - if (w != NULL) { - if (w->references == 0) - fatal("bad reference count"); - w->references--; - if (w->references == 0) - window_destroy(w); - } + if (w != NULL) + window_remove_ref(w); } struct winlink * @@ -362,6 +357,16 @@ window_destroy(struct window *w) free(w); } +void +window_remove_ref(struct window *w) +{ + if (w->references == 0) + fatal("bad reference count"); + w->references--; + if (w->references == 0) + window_destroy(w); +} + void window_set_name(struct window *w, const char *new_name) { From d39c58c01c7d8fce29ee00632bf12a6b47ce942a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 21 Aug 2012 10:08:11 +0000 Subject: [PATCH 1165/1180] xterm won't reach version 500 for a while so set that as the upper limit. --- tty-keys.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tty-keys.c b/tty-keys.c index c90eb71e..cb3b4e03 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -734,7 +734,8 @@ tty_keys_device(struct tty *tty, const char *buf, size_t len, size_t *size) a = b = 0; log_debug("received xterm version %u", b); - tty_set_version(tty, b); + if (b < 500) + tty_set_version(tty, b); return (0); } From 753775033a9e2ff754a3cfb6017e4815669b356b Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 27 Aug 2012 21:29:23 +0000 Subject: [PATCH 1166/1180] Instead of requiring a prompt to enter all numbers >10, go back to 0-9a-z and add A-Z and enter the prompt when M-0 to M-9 are pressed (like in copy mode). Prompted by request from mcbride@, help from Thomas Adam. --- mode-key.c | 40 +++++++-------- window-choose.c | 131 ++++++++++++++++++++++++++++++++---------------- 2 files changed, 107 insertions(+), 64 deletions(-) diff --git a/mode-key.c b/mode-key.c index bae6650c..ea43962b 100644 --- a/mode-key.c +++ b/mode-key.c @@ -192,16 +192,16 @@ struct mode_key_tree mode_key_tree_vi_edit; /* vi choice selection keys. */ const struct mode_key_entry mode_key_vi_choice[] = { - { '0', 0, MODEKEYCHOICE_STARTNUMBERPREFIX }, - { '1', 0, MODEKEYCHOICE_STARTNUMBERPREFIX }, - { '2', 0, MODEKEYCHOICE_STARTNUMBERPREFIX }, - { '3', 0, MODEKEYCHOICE_STARTNUMBERPREFIX }, - { '4', 0, MODEKEYCHOICE_STARTNUMBERPREFIX }, - { '5', 0, MODEKEYCHOICE_STARTNUMBERPREFIX }, - { '6', 0, MODEKEYCHOICE_STARTNUMBERPREFIX }, - { '7', 0, MODEKEYCHOICE_STARTNUMBERPREFIX }, - { '8', 0, MODEKEYCHOICE_STARTNUMBERPREFIX }, - { '9', 0, MODEKEYCHOICE_STARTNUMBERPREFIX }, + { '0' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTNUMBERPREFIX }, + { '1' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTNUMBERPREFIX }, + { '2' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTNUMBERPREFIX }, + { '3' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTNUMBERPREFIX }, + { '4' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTNUMBERPREFIX }, + { '5' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTNUMBERPREFIX }, + { '6' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTNUMBERPREFIX }, + { '7' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTNUMBERPREFIX }, + { '8' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTNUMBERPREFIX }, + { '9' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTNUMBERPREFIX }, { '\002' /* C-b */, 0, MODEKEYCHOICE_PAGEUP }, { '\003' /* C-c */, 0, MODEKEYCHOICE_CANCEL }, { '\005' /* C-e */, 0, MODEKEYCHOICE_SCROLLDOWN }, @@ -330,16 +330,16 @@ struct mode_key_tree mode_key_tree_emacs_edit; /* emacs choice selection keys. */ const struct mode_key_entry mode_key_emacs_choice[] = { - { '0', 0, MODEKEYCHOICE_STARTNUMBERPREFIX }, - { '1', 0, MODEKEYCHOICE_STARTNUMBERPREFIX }, - { '2', 0, MODEKEYCHOICE_STARTNUMBERPREFIX }, - { '3', 0, MODEKEYCHOICE_STARTNUMBERPREFIX }, - { '4', 0, MODEKEYCHOICE_STARTNUMBERPREFIX }, - { '5', 0, MODEKEYCHOICE_STARTNUMBERPREFIX }, - { '6', 0, MODEKEYCHOICE_STARTNUMBERPREFIX }, - { '7', 0, MODEKEYCHOICE_STARTNUMBERPREFIX }, - { '8', 0, MODEKEYCHOICE_STARTNUMBERPREFIX }, - { '9', 0, MODEKEYCHOICE_STARTNUMBERPREFIX }, + { '0' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTNUMBERPREFIX }, + { '1' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTNUMBERPREFIX }, + { '2' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTNUMBERPREFIX }, + { '3' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTNUMBERPREFIX }, + { '4' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTNUMBERPREFIX }, + { '5' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTNUMBERPREFIX }, + { '6' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTNUMBERPREFIX }, + { '7' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTNUMBERPREFIX }, + { '8' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTNUMBERPREFIX }, + { '9' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTNUMBERPREFIX }, { '\003' /* C-c */, 0, MODEKEYCHOICE_CANCEL }, { '\016' /* C-n */, 0, MODEKEYCHOICE_DOWN }, { '\020' /* C-p */, 0, MODEKEYCHOICE_UP }, diff --git a/window-choose.c b/window-choose.c index 99c09d52..9d08376e 100644 --- a/window-choose.c +++ b/window-choose.c @@ -71,7 +71,8 @@ struct window_choose_mode_data { void (*freefn)(struct window_choose_data *); }; -int window_choose_index_key(int); +int window_choose_key_index(struct window_choose_mode_data *, u_int); +int window_choose_index_key(struct window_choose_mode_data *, int); void window_choose_prompt_input(enum window_choose_input_type, const char *, struct window_pane *, int); @@ -89,7 +90,7 @@ window_choose_add(struct window_pane *wp, struct window_choose_data *wcd) item->wcd = wcd; item->pos = ARRAY_LENGTH(&data->list) - 1; - data->width = snprintf (tmp, sizeof tmp , "%u", item->pos); + data->width = xsnprintf (tmp, sizeof tmp , "%u", item->pos); } void @@ -241,27 +242,48 @@ window_choose_key(struct window_pane *wp, unused struct session *sess, int key) items = ARRAY_LENGTH(&data->list); + if (data->input_type == WINDOW_CHOOSE_GOTO_ITEM) { + switch (mode_key_lookup(&data->mdata, key)) { + case MODEKEYCHOICE_CANCEL: + data->input_type = WINDOW_CHOOSE_NORMAL; + window_choose_redraw_screen(wp); + break; + case MODEKEYCHOICE_CHOOSE: + n = strtonum(data->input_str, 0, INT_MAX, NULL); + if (n > items - 1) { + data->input_type = WINDOW_CHOOSE_NORMAL; + window_choose_redraw_screen(wp); + break; + } + item = &ARRAY_ITEM(&data->list, n); + window_choose_fire_callback(wp, item->wcd); + window_pane_reset_mode(wp); + break; + case MODEKEYCHOICE_BACKSPACE: + input_len = strlen(data->input_str); + if (input_len > 0) + data->input_str[input_len - 1] = '\0'; + window_choose_redraw_screen(wp); + break; + default: + if (key < '0' || key > '9') + break; + window_choose_prompt_input(WINDOW_CHOOSE_GOTO_ITEM, + "Goto Item", wp, key); + break; + } + return; + } + switch (mode_key_lookup(&data->mdata, key)) { case MODEKEYCHOICE_CANCEL: window_choose_fire_callback(wp, NULL); window_pane_reset_mode(wp); break; case MODEKEYCHOICE_CHOOSE: - switch (data->input_type) { - case WINDOW_CHOOSE_NORMAL: - item = &ARRAY_ITEM(&data->list, data->selected); - window_choose_fire_callback(wp, item->wcd); - window_pane_reset_mode(wp); - break; - case WINDOW_CHOOSE_GOTO_ITEM: - n = strtonum(data->input_str, 0, INT_MAX, NULL); - if (n > items - 1) - break; - item = &ARRAY_ITEM(&data->list, n); - window_choose_fire_callback(wp, item->wcd); - window_pane_reset_mode(wp); - break; - } + item = &ARRAY_ITEM(&data->list, data->selected); + window_choose_fire_callback(wp, item->wcd); + window_pane_reset_mode(wp); break; case MODEKEYCHOICE_UP: if (items == 0) @@ -366,29 +388,21 @@ window_choose_key(struct window_pane *wp, unused struct session *sess, int key) window_choose_redraw_screen(wp); break; case MODEKEYCHOICE_STARTNUMBERPREFIX: - if (key < '0' && key > '9') + key &= KEYC_MASK_KEY; + if (key < '0' || key > '9') break; - - /* - * If there's less than ten items (0-9) then pressing a number - * will automatically select that item; otherwise, prompt for - * the item to go to. - */ - if (ARRAY_LENGTH(&data->list) - 1 <= 9) { - idx = window_choose_index_key(key); - if (idx < 0 || (u_int) idx >= ARRAY_LENGTH(&data->list)) - break; - data->selected = idx; - - item = &ARRAY_ITEM(&data->list, data->selected); - window_choose_fire_callback(wp, item->wcd); - window_pane_reset_mode(wp); - } else { - window_choose_prompt_input( - WINDOW_CHOOSE_GOTO_ITEM, "Goto item", wp, key); - } + window_choose_prompt_input(WINDOW_CHOOSE_GOTO_ITEM, + "Goto Item", wp, key); break; default: + idx = window_choose_index_key(data, key); + if (idx < 0 || (u_int) idx >= ARRAY_LENGTH(&data->list)) + break; + data->selected = idx; + + item = &ARRAY_ITEM(&data->list, data->selected); + window_choose_fire_callback(wp, item->wcd); + window_pane_reset_mode(wp); break; } } @@ -430,8 +444,8 @@ window_choose_write_line( struct screen *s = &data->screen; struct grid_cell gc; size_t last, xoff = 0; - char hdr[32]; - int utf8flag; + char hdr[32], label[32]; + int utf8flag, key; if (data->callbackfn == NULL) fatalx("called before callback assigned"); @@ -448,10 +462,14 @@ window_choose_write_line( if (item->wcd->wl != NULL && item->wcd->wl->flags & WINLINK_ALERTFLAGS) gc.attr |= GRID_ATTR_BRIGHT; - screen_write_nputs(ctx, screen_size_x(s) - 1, - &gc, utf8flag, "(%*d) %s", data->width, - item->pos, item->name); + key = window_choose_key_index(data, data->top + py); + if (key != -1) + xsnprintf (label, sizeof label, "(%c)", key); + else + xsnprintf (label, sizeof label, "(%d)", item->pos); + screen_write_nputs(ctx, screen_size_x(s) - 1, &gc, utf8flag, + "%*s %s", data->width + 2, label, item->name); } while (s->cx < screen_size_x(s)) screen_write_putc(ctx, &gc, ' '); @@ -470,13 +488,38 @@ window_choose_write_line( } int -window_choose_index_key(int key) +window_choose_key_index(struct window_choose_mode_data *data, u_int idx) { - static const char keys[] = "0123456789"; + static const char keys[] = "0123456789" + "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; const char *ptr; + int mkey; + + for (ptr = keys; *ptr != '\0'; ptr++) { + mkey = mode_key_lookup(&data->mdata, *ptr); + if (mkey != MODEKEY_NONE && mkey != MODEKEY_OTHER) + continue; + if (idx-- == 0) + return (*ptr); + } + return (-1); +} + +int +window_choose_index_key(struct window_choose_mode_data *data, int key) +{ + static const char keys[] = "0123456789" + "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + const char *ptr; + int mkey; u_int idx = 0; for (ptr = keys; *ptr != '\0'; ptr++) { + mkey = mode_key_lookup(&data->mdata, *ptr); + if (mkey != MODEKEY_NONE && mkey != MODEKEY_OTHER) + continue; if (key == *ptr) return (idx); idx++; From 84a4007b06adf2df5aa5e115b5a24a155819eb37 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 27 Aug 2012 21:35:11 +0000 Subject: [PATCH 1167/1180] Change a log to fprintf that was missed last time around, from Tiago Cunha. --- client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client.c b/client.c index 1326a97d..cb546c40 100644 --- a/client.c +++ b/client.c @@ -189,7 +189,7 @@ client_main(int argc, char **argv, int flags) * flag. */ if ((cmdlist = cmd_list_parse(argc, argv, &cause)) == NULL) { - log_warnx("%s", cause); + fprintf(stderr, "%s\n", cause); return (1); } cmdflags &= ~CMD_STARTSERVER; From 473911fb731eb740d1c468350eda334638902d94 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 3 Sep 2012 06:26:48 +0000 Subject: [PATCH 1168/1180] Can't call evtimer_pending on uninitialized events, call evtimer_initialized first. Reported by Vladimir Lomov, fix from Thomas Adam slightly modified by me. --- tty-keys.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tty-keys.c b/tty-keys.c index cb3b4e03..f375a07b 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -533,6 +533,7 @@ partial_key: * timer has expired, give up waiting and send the escape. */ if ((tty->flags & TTY_ESCAPE) && + evtimer_initialized(&tty->key_timer) && !evtimer_pending(&tty->key_timer, NULL)) { evbuffer_drain(tty->event->input, 1); key = '\033'; @@ -543,7 +544,8 @@ partial_key: start_timer: /* If already waiting for timer, do nothing. */ - if (evtimer_pending(&tty->key_timer, NULL)) + if (evtimer_initialized(&tty->key_timer) && + evtimer_pending(&tty->key_timer, NULL)) return (0); /* Start the timer and wait for expiry or more data. */ From 2e43372d0b2932f7abf5b16544faec3ecf214433 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 3 Sep 2012 08:48:57 +0000 Subject: [PATCH 1169/1180] If stdin in the client is enable immediately, tmux will eat anything sent to stdin before it is needed, which can be inconvenient (eg pasting commands). Instead, start with stdin disabled and reuse MSG_STDIN from server->client to mean that stdin should be enabled. Based on a diff from Chris Johnsen. --- client.c | 7 ++++++- server-fn.c | 3 +++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/client.c b/client.c index cb546c40..90993057 100644 --- a/client.c +++ b/client.c @@ -281,7 +281,6 @@ client_main(int argc, char **argv, int flags) /* Set the event and dispatch. */ client_update_event(); - event_add (&client_stdin, NULL); event_dispatch(); /* Print the exit message, if any, and exit. */ @@ -516,6 +515,12 @@ client_dispatch_wait(void *data) event_del(&client_stdin); client_attached = 1; break; + case MSG_STDIN: + if (datalen != 0) + fatalx("bad MSG_STDIN size"); + + event_add(&client_stdin, NULL); + break; case MSG_STDOUT: if (datalen != sizeof stdoutdata) fatalx("bad MSG_STDOUT"); diff --git a/server-fn.c b/server-fn.c index bea64178..c22095dc 100644 --- a/server-fn.c +++ b/server-fn.c @@ -581,5 +581,8 @@ server_set_stdin_callback(struct client *c, void (*cb)(struct client *, int, if (c->stdin_closed) c->stdin_callback (c, 1, c->stdin_callback_data); + + server_write_client(c, MSG_STDIN, NULL, 0); + return (0); } From a679a4a7081b8efdf90445ad14e87f9c6b1fe964 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 3 Sep 2012 09:01:16 +0000 Subject: [PATCH 1170/1180] Change format of choose-tree arrows slightly, from Romain Francoise. --- cmd-choose-tree.c | 42 ++++++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/cmd-choose-tree.c b/cmd-choose-tree.c index e4fd267e..269b8adb 100644 --- a/cmd-choose-tree.c +++ b/cmd-choose-tree.c @@ -74,11 +74,14 @@ cmd_choose_tree_exec(struct cmd *self, struct cmd_ctx *ctx) struct args *args = self->args; struct winlink *wl, *wm; struct session *s, *s2; + struct tty *tty; struct window_choose_data *wcd = NULL; const char *ses_template, *win_template; - char *final_win_action, *final_win_template; + char *final_win_action, *cur_win_template; + char *final_win_template_middle; + char *final_win_template_last; const char *ses_action, *win_action; - u_int cur_win, idx_ses, win_ses; + u_int cur_win, idx_ses, win_ses, win_max; u_int wflag, sflag; ses_template = win_template = NULL; @@ -90,6 +93,7 @@ cmd_choose_tree_exec(struct cmd *self, struct cmd_ctx *ctx) } s = ctx->curclient->session; + tty = &ctx->curclient->tty; if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL) return (CMD_RETURN_ERROR); @@ -146,12 +150,14 @@ cmd_choose_tree_exec(struct cmd *self, struct cmd_ctx *ctx) * window template, otherwise just render the windows as a flat list * without any padding. */ - if (wflag && sflag) - xasprintf(&final_win_template, " --> %s", win_template); - else if (wflag) - final_win_template = xstrdup(win_template); - else - final_win_template = NULL; + if (wflag && sflag) { + xasprintf(&final_win_template_middle, " |-> %s", win_template); + xasprintf(&final_win_template_last, " \\-> %s", win_template); + } else if (wflag) { + final_win_template_middle = xstrdup(win_template); + final_win_template_last = xstrdup(win_template); + } else + final_win_template_middle = final_win_template_last = NULL; idx_ses = cur_win = -1; RB_FOREACH(s2, sessions, &sessions) { @@ -169,7 +175,7 @@ cmd_choose_tree_exec(struct cmd *self, struct cmd_ctx *ctx) } wcd = window_choose_add_session(wl->window->active, - ctx, s2, ses_template, (char *)ses_action, idx_ses); + ctx, s2, ses_template, (char *)ses_action, idx_ses); /* If we're just choosing sessions, skip choosing windows. */ if (sflag && !wflag) { @@ -178,7 +184,9 @@ cmd_choose_tree_exec(struct cmd *self, struct cmd_ctx *ctx) continue; } windows_only: - win_ses = -1; + win_ses = win_max = -1; + RB_FOREACH(wm, winlinks, &s2->windows) + win_max++; RB_FOREACH(wm, winlinks, &s2->windows) { win_ses++; if (sflag && wflag) @@ -197,11 +205,16 @@ windows_only: } xasprintf(&final_win_action, "%s ; %s", win_action, - wcd ? wcd->command : ""); + wcd ? wcd->command : ""); + + if (win_ses != win_max) + cur_win_template = final_win_template_middle; + else + cur_win_template = final_win_template_last; window_choose_add_window(wl->window->active, - ctx, s2, wm, final_win_template, - final_win_action, idx_ses); + ctx, s2, wm, cur_win_template, + final_win_action, idx_ses); free(final_win_action); } @@ -212,7 +225,8 @@ windows_only: if (wflag && !sflag) break; } - free(final_win_template); + free(final_win_template_middle); + free(final_win_template_last); window_choose_ready(wl->window->active, cur_win, cmd_choose_tree_callback, cmd_choose_tree_free); From 9247c90d69c3efeeda7c7baa5c1ff82fb09da836 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 3 Sep 2012 09:32:38 +0000 Subject: [PATCH 1171/1180] Send notifications to control clients. Also don't redraw client when suspended. --- Makefile | 1 + control-notify.c | 183 +++++++++++++++++++++++++++++++++++++++++++++++ control.c | 1 - notify.c | 16 ++--- server-client.c | 4 ++ tmux.h | 11 +++ 6 files changed, 207 insertions(+), 9 deletions(-) create mode 100644 control-notify.c diff --git a/Makefile b/Makefile index efad64a0..bfd5d7e3 100644 --- a/Makefile +++ b/Makefile @@ -81,6 +81,7 @@ SRCS= arguments.c \ cmd.c \ colour.c \ control.c \ + control-notify.c \ environ.c \ format.c \ grid-utf8.c \ diff --git a/control-notify.c b/control-notify.c new file mode 100644 index 00000000..254f1f58 --- /dev/null +++ b/control-notify.c @@ -0,0 +1,183 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2012 Nicholas Marriott + * Copyright (c) 2012 George Nachman + * + * 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" + +#define CONTROL_SHOULD_NOTIFY_CLIENT(c) \ + ((c) != NULL && ((c)->flags & CLIENT_CONTROL)) + +void +control_notify_window_layout_changed(struct window *w) +{ + struct client *c; + struct session *s; + struct format_tree *ft; + struct winlink *wl; + u_int i; + const char *template; + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL) + continue; + s = c->session; + + if (winlink_find_by_window_id(&s->windows, w->id) == NULL) + continue; + + /* + * When the last pane in a window is closed it won't have a + * layout root and we don't need to inform the client about the + * layout change because the whole window will go away soon. + */ + if (w->layout_root == NULL) + continue; + template = "%layout-change #{window_id} #{window_layout}"; + + ft = format_create(); + wl = winlink_find_by_window(&s->windows, w); + if (wl != NULL) { + format_winlink(ft, c->session, wl); + control_write(c, "%s", format_expand(ft, template)); + } + format_free(ft); + } +} + +void +control_notify_window_unlinked(unused struct session *s, struct window *w) +{ + struct client *c; + struct session *cs; + u_int i; + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL) + continue; + cs = c->session; + + if (winlink_find_by_window_id(&cs->windows, w->id) != NULL) + control_write(c, "%%window-close %u", w->id); + else + control_write(c, "%%unlinked-window-close %u", w->id); + } +} + +void +control_notify_window_linked(unused struct session *s, struct window *w) +{ + struct client *c; + struct session *cs; + u_int i; + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL) + continue; + cs = c->session; + + if (winlink_find_by_window_id(&cs->windows, w->id) != NULL) + control_write(c, "%%window-add %u", w->id); + else + control_write(c, "%%unlinked-window-add %u", w->id); + } +} + +void +control_notify_window_renamed(struct window *w) +{ + struct client *c; + struct session *s; + u_int i; + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL) + continue; + s = c->session; + + if (winlink_find_by_window_id(&s->windows, w->id) != NULL) { + control_write(c, "%%window-renamed %u %s", + w->id, w->name); + } else { + control_write(c, "%%unlinked-window-renamed %u %s", + w->id, w->name); + } + } +} + +void +control_notify_attached_session_changed(struct client *c) +{ + struct session *s; + + if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL) + return; + s = c->session; + + control_write(c, "%%session-changed %d %s", s->idx, s->name); +} + +void +control_notify_session_renamed(struct session *s) +{ + struct client *c; + u_int i; + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session != s) + continue; + + control_write(c, "%%session-renamed %s", s->name); + } +} + +void +control_notify_session_created(unused struct session *s) +{ + struct client *c; + u_int i; + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL) + continue; + + control_write(c, "%%sessions-changed"); + } +} + +void +control_notify_session_close(unused struct session *s) +{ + struct client *c; + u_int i; + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL) + continue; + + control_write(c, "%%sessions-changed"); + } +} diff --git a/control.c b/control.c index 3dc7bc2a..c0d9e812 100644 --- a/control.c +++ b/control.c @@ -28,7 +28,6 @@ void printflike2 control_msg_error(struct cmd_ctx *, const char *, ...); void printflike2 control_msg_print(struct cmd_ctx *, const char *, ...); void printflike2 control_msg_info(struct cmd_ctx *, const char *, ...); -void printflike2 control_write(struct client *, const char *, ...); /* Command error callback. */ void printflike2 diff --git a/notify.c b/notify.c index 33fea56c..8fe792c1 100644 --- a/notify.c +++ b/notify.c @@ -95,28 +95,28 @@ notify_drain(void) TAILQ_FOREACH_SAFE(ne, ¬ify_queue, entry, ne1) { switch (ne->type) { case NOTIFY_WINDOW_LAYOUT_CHANGED: - /* control_notify_window_layout_changed(ne->window); */ + control_notify_window_layout_changed(ne->window); break; case NOTIFY_WINDOW_UNLINKED: - /* control_notify_window_unlinked(ne->session, ne->window); */ + control_notify_window_unlinked(ne->session, ne->window); break; case NOTIFY_WINDOW_LINKED: - /* control_notify_window_linked(ne->session, ne->window); */ + control_notify_window_linked(ne->session, ne->window); break; case NOTIFY_WINDOW_RENAMED: - /* control_notify_window_renamed(ne->window); */ + control_notify_window_renamed(ne->window); break; case NOTIFY_ATTACHED_SESSION_CHANGED: - /* control_notify_attached_session_changed(ne->client, ne->session); */ + control_notify_attached_session_changed(ne->client); break; case NOTIFY_SESSION_RENAMED: - /* control_notify_session_renamed(ne->session); */ + control_notify_session_renamed(ne->session); break; case NOTIFY_SESSION_CREATED: - /* control_notify_session_created(ne->session); */ + control_notify_session_created(ne->session); break; case NOTIFY_SESSION_CLOSED: - /* control_notify_session_close(ne->session); */ + control_notify_session_close(ne->session); break; } diff --git a/server-client.c b/server-client.c index 8ad996b0..7b7a3e4a 100644 --- a/server-client.c +++ b/server-client.c @@ -603,6 +603,9 @@ server_client_check_redraw(struct client *c) struct window_pane *wp; int flags, redraw; + if (c->flags & CLIENT_SUSPENDED) + return; + flags = c->tty.flags & TTY_FREEZE; c->tty.flags &= ~TTY_FREEZE; @@ -900,6 +903,7 @@ server_client_msg_identify( if (data->flags & IDENTIFY_CONTROL) { c->stdin_callback = control_callback; c->flags |= (CLIENT_CONTROL|CLIENT_SUSPENDED); + server_write_client(c, MSG_STDIN, NULL, 0); c->tty.fd = -1; c->tty.log_fd = -1; diff --git a/tmux.h b/tmux.h index 449f0676..85f5fb68 100644 --- a/tmux.h +++ b/tmux.h @@ -2215,6 +2215,17 @@ void clear_signals(int); /* control.c */ void control_callback(struct client *, int, void*); +void printflike2 control_write(struct client *, const char *, ...); + +/* control-notify.c */ +void control_notify_window_layout_changed(struct window *); +void control_notify_window_unlinked(struct session *, struct window *); +void control_notify_window_linked(struct session *, struct window *); +void control_notify_window_renamed(struct window *); +void control_notify_attached_session_changed(struct client *); +void control_notify_session_renamed(struct session *); +void control_notify_session_created(struct session *); +void control_notify_session_close(struct session *); /* session.c */ extern struct sessions sessions; From adc9fad4acc2f7e045b23b3672bca7f24ba10566 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 3 Sep 2012 09:36:07 +0000 Subject: [PATCH 1172/1180] Remove an unused variable. --- cmd-choose-tree.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/cmd-choose-tree.c b/cmd-choose-tree.c index 269b8adb..45cb6dad 100644 --- a/cmd-choose-tree.c +++ b/cmd-choose-tree.c @@ -74,7 +74,6 @@ cmd_choose_tree_exec(struct cmd *self, struct cmd_ctx *ctx) struct args *args = self->args; struct winlink *wl, *wm; struct session *s, *s2; - struct tty *tty; struct window_choose_data *wcd = NULL; const char *ses_template, *win_template; char *final_win_action, *cur_win_template; @@ -93,7 +92,6 @@ cmd_choose_tree_exec(struct cmd *self, struct cmd_ctx *ctx) } s = ctx->curclient->session; - tty = &ctx->curclient->tty; if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL) return (CMD_RETURN_ERROR); From 7263fa36eb3d4488b89d01837dc4bd533e6f061a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 3 Sep 2012 09:57:57 +0000 Subject: [PATCH 1173/1180] add cmd-choose-list to allow arbitrary options to be selected. From Thomas Adam. --- Makefile | 1 + cmd-choose-list.c | 117 ++++++++++++++++++++++++++++++++++++++++++++++ cmd.c | 1 + tmux.1 | 27 +++++++++++ tmux.h | 4 ++ window-choose.c | 32 +++++++++++++ 6 files changed, 182 insertions(+) create mode 100644 cmd-choose-list.c diff --git a/Makefile b/Makefile index bfd5d7e3..7333f0f1 100644 --- a/Makefile +++ b/Makefile @@ -12,6 +12,7 @@ SRCS= arguments.c \ cmd-capture-pane.c \ cmd-choose-buffer.c \ cmd-choose-client.c \ + cmd-choose-list.c \ cmd-choose-tree.c \ cmd-clear-history.c \ cmd-clock-mode.c \ diff --git a/cmd-choose-list.c b/cmd-choose-list.c new file mode 100644 index 00000000..8b605d08 --- /dev/null +++ b/cmd-choose-list.c @@ -0,0 +1,117 @@ +/* $Id$ */ + +/* + * Copyright (c) 2012 Thomas Adam + * + * 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 "tmux.h" + +#define CMD_CHOOSE_LIST_DEFAULT_TEMPLATE "run-shell '%%'" + +/* + * Enter choose mode to choose a custom list. + */ + +enum cmd_retval cmd_choose_list_exec(struct cmd *, struct cmd_ctx *); + +void cmd_choose_list_callback(struct window_choose_data *); +void cmd_choose_list_free(struct window_choose_data *); + +const struct cmd_entry cmd_choose_list_entry = { + "choose-list", NULL, + "l:t:", 0, 1, + "[-l items] " CMD_TARGET_WINDOW_USAGE "[template]", + 0, + NULL, + NULL, + cmd_choose_list_exec +}; + +enum cmd_retval +cmd_choose_list_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct args *args = self->args; + struct winlink *wl; + const char *lists; + char *template, *list, *copy, *lists1; + u_int idx; + + if (ctx->curclient == NULL) { + ctx->error(ctx, "must be run interactively"); + return (CMD_RETURN_ERROR); + } + + if ((lists = args_get(args, 'l')) == NULL) + return (CMD_RETURN_ERROR); + + if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL) + return (CMD_RETURN_ERROR); + + if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0) + return (CMD_RETURN_NORMAL); + + if (args->argc != 0) + template = xstrdup(args->argv[0]); + else + template = xstrdup(CMD_CHOOSE_LIST_DEFAULT_TEMPLATE); + + copy = lists1 = xstrdup(lists); + idx = 0; + while ((list = strsep(&lists1, ",")) != NULL) + { + if (*list == '\0') /* no empty entries */ + continue; + window_choose_add_item(wl->window->active, ctx, wl, list, + template, idx); + idx++; + } + free(copy); + + window_choose_ready(wl->window->active, 0, cmd_choose_list_callback, + cmd_choose_list_free); + + free(template); + + return (CMD_RETURN_NORMAL); +} + +void +cmd_choose_list_callback(struct window_choose_data *cdata) +{ + if (cdata == NULL || (cdata->client->flags & CLIENT_DEAD)) + return; + + window_choose_ctx(cdata); +} + +void +cmd_choose_list_free(struct window_choose_data *cdata) +{ + cdata->session->references--; + cdata->client->references--; + + free(cdata->ft_template); + free(cdata->command); + format_free(cdata->ft); + free(cdata); + +} diff --git a/cmd.c b/cmd.c index 1db85eba..021c0332 100644 --- a/cmd.c +++ b/cmd.c @@ -35,6 +35,7 @@ const struct cmd_entry *cmd_table[] = { &cmd_capture_pane_entry, &cmd_choose_buffer_entry, &cmd_choose_client_entry, + &cmd_choose_list_entry, &cmd_choose_session_entry, &cmd_choose_tree_entry, &cmd_choose_window_entry, diff --git a/tmux.1 b/tmux.1 index 9d206dfb..874938ed 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1067,6 +1067,33 @@ section. This command works only from inside .Nm . .It Xo +.Ic choose-list +.Op Fl l Ar items +.Op Fl t Ar target-window +.Op Ar template +.Xc +Put a window into list choice mode, allowing +.Ar items +to be selected. +.Ar items +can be a comma-separated list to display more than one item. +If an item has spaces, that entry must be quoted. +After an item is chosen, +.Ql %% +is replaced by the chosen item in the +.Ar template +and the result is executed as a command. +If +.Ar template +is not given, "run-shell '%%'" is used. +.Ar items +also accepts format specifiers. +For the meaning of this see the +.Sx FORMATS +section. +This command works only from inside +.Nm . +.It Xo .Ic choose-session .Op Fl F Ar format .Op Fl t Ar target-window diff --git a/tmux.h b/tmux.h index 85f5fb68..c1095681 100644 --- a/tmux.h +++ b/tmux.h @@ -1716,6 +1716,7 @@ extern const struct cmd_entry cmd_break_pane_entry; extern const struct cmd_entry cmd_capture_pane_entry; extern const struct cmd_entry cmd_choose_buffer_entry; extern const struct cmd_entry cmd_choose_client_entry; +extern const struct cmd_entry cmd_choose_list_entry; extern const struct cmd_entry cmd_choose_session_entry; extern const struct cmd_entry cmd_choose_tree_entry; extern const struct cmd_entry cmd_choose_window_entry; @@ -2204,6 +2205,9 @@ struct window_choose_data *window_choose_add_window(struct window_pane *, struct window_choose_data *window_choose_add_session(struct window_pane *, struct cmd_ctx *, struct session *, const char *, char *, u_int); +struct window_choose_data *window_choose_add_item(struct window_pane *, + struct cmd_ctx *, struct winlink *, const char *, + char *, u_int); /* names.c */ void queue_window_name(struct window *); diff --git a/window-choose.c b/window-choose.c index 9d08376e..7bab2ffe 100644 --- a/window-choose.c +++ b/window-choose.c @@ -636,6 +636,38 @@ window_choose_add_session(struct window_pane *wp, struct cmd_ctx *ctx, return (wcd); } +struct window_choose_data * +window_choose_add_item(struct window_pane *wp, struct cmd_ctx *ctx, + struct winlink *wl, const char *template, char *action, u_int idx) +{ + struct window_choose_data *wcd; + char *action_data; + + wcd = window_choose_data_create(ctx); + wcd->idx = wl->idx; + wcd->ft_template = xstrdup(template); + format_add(wcd->ft, "line", "%u", idx); + format_session(wcd->ft, wcd->session); + format_winlink(wcd->ft, wcd->session, wl); + format_window_pane(wcd->ft, wl->window->active); + + wcd->client->references++; + wcd->session->references++; + + window_choose_add(wp, wcd); + + /* + * Interpolate action_data here, since the data we pass back is the + * expanded template itself. + */ + xasprintf(&action_data, "%s", format_expand(wcd->ft, wcd->ft_template)); + wcd->command = cmd_template_replace(action, action_data, 1); + free(action_data); + + return (wcd); + +} + struct window_choose_data * window_choose_add_window(struct window_pane *wp, struct cmd_ctx *ctx, struct session *s, struct winlink *wl, const char *template, From c96a2a3c9e7a0c460c668f65712a7beac07953bf Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 3 Sep 2012 10:02:39 +0000 Subject: [PATCH 1174/1180] Rename variables to something a but more understandable. --- cmd-choose-list.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/cmd-choose-list.c b/cmd-choose-list.c index 8b605d08..15c644ec 100644 --- a/cmd-choose-list.c +++ b/cmd-choose-list.c @@ -51,8 +51,8 @@ cmd_choose_list_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; struct winlink *wl; - const char *lists; - char *template, *list, *copy, *lists1; + const char *list1; + char *template, *item, *copy, *list; u_int idx; if (ctx->curclient == NULL) { @@ -60,7 +60,7 @@ cmd_choose_list_exec(struct cmd *self, struct cmd_ctx *ctx) return (CMD_RETURN_ERROR); } - if ((lists = args_get(args, 'l')) == NULL) + if ((list1 = args_get(args, 'l')) == NULL) return (CMD_RETURN_ERROR); if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL) @@ -74,13 +74,13 @@ cmd_choose_list_exec(struct cmd *self, struct cmd_ctx *ctx) else template = xstrdup(CMD_CHOOSE_LIST_DEFAULT_TEMPLATE); - copy = lists1 = xstrdup(lists); + copy = list = xstrdup(list1); idx = 0; - while ((list = strsep(&lists1, ",")) != NULL) + while ((item = strsep(&list, ",")) != NULL) { - if (*list == '\0') /* no empty entries */ + if (*item == '\0') /* no empty entries */ continue; - window_choose_add_item(wl->window->active, ctx, wl, list, + window_choose_add_item(wl->window->active, ctx, wl, item, template, idx); idx++; } From 9e7bbc7281a3b0be63a0c6fa777fc413b668629c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 3 Sep 2012 12:20:17 +0000 Subject: [PATCH 1175/1180] When choosing a pane found by find-window, switch to that pane rather than just the window. Also use a helper function for the inner loop. --- cmd-find-window.c | 136 ++++++++++++++++++++++++++-------------------- tmux.h | 1 + 2 files changed, 78 insertions(+), 59 deletions(-) diff --git a/cmd-find-window.c b/cmd-find-window.c index 44bf1770..340f6e1a 100644 --- a/cmd-find-window.c +++ b/cmd-find-window.c @@ -30,7 +30,6 @@ enum cmd_retval cmd_find_window_exec(struct cmd *, struct cmd_ctx *); -u_int cmd_find_window_match_flags(struct args *); void cmd_find_window_callback(struct window_choose_data *); void cmd_find_window_free(struct window_choose_data *); @@ -54,6 +53,17 @@ const struct cmd_entry cmd_find_window_entry = { cmd_find_window_exec }; +struct cmd_find_window_data { + struct winlink *wl; + char *list_ctx; + u_int pane_id; +}; +ARRAY_DECL(cmd_find_window_data_list, struct cmd_find_window_data); + +u_int cmd_find_window_match_flags(struct args *); +void cmd_find_window_match(struct cmd_find_window_data_list *, int, + struct winlink *, const char *, const char *); + u_int cmd_find_window_match_flags(struct args *args) { @@ -74,6 +84,49 @@ cmd_find_window_match_flags(struct args *args) return (match_flags); } +void +cmd_find_window_match(struct cmd_find_window_data_list *find_list, + int match_flags, struct winlink *wl, const char *str, const char *searchstr) +{ + struct cmd_find_window_data find_data; + struct window_pane *wp; + u_int i, line; + char *sres; + + memset(&find_data, 0, sizeof find_data); + + i = 0; + TAILQ_FOREACH(wp, &wl->window->panes, entry) { + i++; + + if ((match_flags & CMD_FIND_WINDOW_BY_NAME) && + fnmatch(searchstr, wl->window->name, 0) == 0) { + find_data.list_ctx = xstrdup(""); + break; + } + + if ((match_flags & CMD_FIND_WINDOW_BY_TITLE) && + fnmatch(searchstr, wp->base.title, 0) == 0) { + xasprintf(&find_data.list_ctx, + "pane %u title: \"%s\"", i - 1, wp->base.title); + break; + } + + if (match_flags & CMD_FIND_WINDOW_BY_CONTENT && + (sres = window_pane_search(wp, str, &line)) != NULL) { + xasprintf(&find_data.list_ctx, + "pane %u line %u: \"%s\"", i - 1, line + 1, sres); + free(sres); + break; + } + } + if (find_data.list_ctx != NULL) { + find_data.wl = wl; + find_data.pane_id = i - 1; + ARRAY_ADD(find_list, find_data); + } +} + enum cmd_retval cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx) { @@ -81,12 +134,10 @@ cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx) struct window_choose_data *cdata; struct session *s; struct winlink *wl, *wm; - struct window_pane *wp; - ARRAY_DECL(, u_int) list_idx; - ARRAY_DECL(, char *) list_ctx; - char *str, *sres, *sctx, *searchstr; + struct cmd_find_window_data_list find_list; + char *str, *searchstr; const char *template; - u_int i, line, match_flags; + u_int i, match_flags; if (ctx->curclient == NULL) { ctx->error(ctx, "must be run interactively"); @@ -103,58 +154,21 @@ cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx) match_flags = cmd_find_window_match_flags(args); str = args->argv[0]; - ARRAY_INIT(&list_idx); - ARRAY_INIT(&list_ctx); + ARRAY_INIT(&find_list); xasprintf(&searchstr, "*%s*", str); - RB_FOREACH(wm, winlinks, &s->windows) { - i = 0; - TAILQ_FOREACH(wp, &wm->window->panes, entry) { - i++; - - if ((match_flags & CMD_FIND_WINDOW_BY_NAME) && - fnmatch(searchstr, wm->window->name, 0) == 0) - sctx = xstrdup(""); - else { - sres = NULL; - if (match_flags & CMD_FIND_WINDOW_BY_CONTENT) { - sres = window_pane_search( - wp, str, &line); - } - - if (sres == NULL && - (!(match_flags & CMD_FIND_WINDOW_BY_TITLE) || - fnmatch(searchstr, wp->base.title, 0) != 0)) - continue; - - if (sres == NULL) { - xasprintf(&sctx, - "pane %u title: \"%s\"", i - 1, - wp->base.title); - } else { - xasprintf(&sctx, - "pane %u line %u: \"%s\"", i - 1, - line + 1, sres); - free(sres); - } - } - - ARRAY_ADD(&list_idx, wm->idx); - ARRAY_ADD(&list_ctx, sctx); - break; - } - } + RB_FOREACH(wm, winlinks, &s->windows) + cmd_find_window_match (&find_list, match_flags, wm, str, searchstr); free(searchstr); - if (ARRAY_LENGTH(&list_idx) == 0) { + if (ARRAY_LENGTH(&find_list) == 0) { ctx->error(ctx, "no windows matching: %s", str); - ARRAY_FREE(&list_idx); - ARRAY_FREE(&list_ctx); + ARRAY_FREE(&find_list); return (CMD_RETURN_ERROR); } - if (ARRAY_LENGTH(&list_idx) == 1) { - if (session_select(s, ARRAY_FIRST(&list_idx)) == 0) + if (ARRAY_LENGTH(&find_list) == 1) { + if (session_select(s, ARRAY_FIRST(&find_list).wl->idx) == 0) server_redraw_session(s); recalculate_sizes(); goto out; @@ -163,18 +177,20 @@ cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx) if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0) goto out; - for (i = 0; i < ARRAY_LENGTH(&list_idx); i++) { - wm = winlink_find_by_index( - &s->windows, ARRAY_ITEM(&list_idx, i)); + for (i = 0; i < ARRAY_LENGTH(&find_list); i++) { + wm = ARRAY_ITEM(&find_list, i).wl; cdata = window_choose_data_create(ctx); cdata->idx = wm->idx; cdata->client->references++; + cdata->wl = wm; cdata->ft_template = xstrdup(template); + cdata->pane_id = ARRAY_ITEM(&find_list, i).pane_id; + format_add(cdata->ft, "line", "%u", i); format_add(cdata->ft, "window_find_matches", "%s", - ARRAY_ITEM(&list_ctx, i)); + ARRAY_ITEM(&find_list, i).list_ctx); format_session(cdata->ft, s); format_winlink(cdata->ft, s, wm); @@ -185,17 +201,15 @@ cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx) 0, cmd_find_window_callback, cmd_find_window_free); out: - - ARRAY_FREE(&list_idx); - ARRAY_FREE(&list_ctx); - + ARRAY_FREE(&find_list); return (CMD_RETURN_NORMAL); } void cmd_find_window_callback(struct window_choose_data *cdata) { - struct session *s; + struct session *s; + struct window_pane *wp; if (cdata == NULL) return; @@ -204,6 +218,10 @@ cmd_find_window_callback(struct window_choose_data *cdata) if (!session_alive(s)) return; + wp = window_pane_at_index(cdata->wl->window, cdata->pane_id); + if (wp != NULL && window_pane_visible(wp)) + window_set_active_pane(cdata->wl->window, wp); + if (session_select(s, cdata->idx) == 0) { server_redraw_session(s); recalculate_sizes(); diff --git a/tmux.h b/tmux.h index c1095681..c208361b 100644 --- a/tmux.h +++ b/tmux.h @@ -897,6 +897,7 @@ struct window_choose_data { char *ft_template; char *command; u_int idx; + int pane_id; }; struct window_choose_mode_item { From 4f8a6867faa24dfc381a79384c22c0ec7280ccab Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 3 Sep 2012 12:24:25 +0000 Subject: [PATCH 1176/1180] Use the right index when adding item in choose-tree, from Thomas Adam. --- cmd-choose-tree.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmd-choose-tree.c b/cmd-choose-tree.c index 45cb6dad..f1533ac0 100644 --- a/cmd-choose-tree.c +++ b/cmd-choose-tree.c @@ -212,7 +212,8 @@ windows_only: window_choose_add_window(wl->window->active, ctx, s2, wm, cur_win_template, - final_win_action, idx_ses); + final_win_action, + (wflag && !sflag) ? win_ses : idx_ses); free(final_win_action); } From 6307d63715b7509b56384214d7a605e022c678bb Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 3 Sep 2012 15:47:40 +0000 Subject: [PATCH 1177/1180] Remove xterm CRA support - support is patchy and it will be done better using margins. --- tty.c | 59 +---------------------------------------------------------- 1 file changed, 1 insertion(+), 58 deletions(-) diff --git a/tty.c b/tty.c index 68d23fc2..01b3a93d 100644 --- a/tty.c +++ b/tty.c @@ -44,10 +44,6 @@ void tty_colours_fg(struct tty *, const struct grid_cell *); void tty_colours_bg(struct tty *, const struct grid_cell *); int tty_large_region(struct tty *, const struct tty_ctx *); -void tty_cra_pane(struct tty *, - const struct tty_ctx *, u_int, u_int, u_int, u_int, u_int, u_int); -void tty_era_pane(struct tty *, - const struct tty_ctx *, u_int, u_int, u_int, u_int); void tty_redraw_region(struct tty *, const struct tty_ctx *); void tty_emulate_repeat( struct tty *, enum tty_code_code, enum tty_code_code, u_int); @@ -57,8 +53,6 @@ void tty_cell(struct tty *, #define tty_use_acs(tty) \ (tty_term_has((tty)->term, TTYC_ACSC) && !((tty)->flags & TTY_UTF8)) -#define tty_use_rect(tty) \ - ((tty)->xterm_version > 270) #define tty_pane_full_width(tty, ctx) \ ((ctx)->xoff == 0 && screen_size_x((ctx)->wp->screen) >= (tty)->sx) @@ -251,19 +245,6 @@ tty_set_version(struct tty *tty, u_int version) if (tty->xterm_version != 0) return; tty->xterm_version = version; - - if (tty->xterm_version > 270) { - tty_puts(tty, "\033[65;1\"p"); - - tty_putcode(tty, TTYC_RMACS); - memcpy(&tty->cell, &grid_default_cell, sizeof tty->cell); - - tty->cx = UINT_MAX; - tty->cy = UINT_MAX; - - tty->rupper = UINT_MAX; - tty->rlower = UINT_MAX; - } } void @@ -696,38 +677,6 @@ tty_write( } } -void -tty_cra_pane(struct tty *tty, const struct tty_ctx *ctx, - u_int t, u_int l, u_int b, u_int r, u_int tt, u_int tl) -{ - char tmp[64]; - - snprintf(tmp, sizeof tmp, - "\033[%u;%u;%u;%u;1;%u;%u;1$v", - ctx->yoff + t + 1, - ctx->xoff + l + 1, - ctx->yoff + b + 1, - ctx->xoff + r + 1, - ctx->yoff + tt + 1, - ctx->xoff + tl + 1); - tty_puts(tty, tmp); -} - -void -tty_era_pane(struct tty *tty, const struct tty_ctx *ctx, - u_int t, u_int l, u_int b, u_int r) -{ - char tmp[64]; - - snprintf(tmp, sizeof tmp, - "\033[%u;%u;%u;%u$z", - ctx->yoff + t + 1, - ctx->xoff + l + 1, - ctx->yoff + b + 1, - ctx->xoff + r + 1); - tty_puts(tty, tmp); -} - void tty_cmd_insertcharacter(struct tty *tty, const struct tty_ctx *ctx) { @@ -877,7 +826,6 @@ void tty_cmd_linefeed(struct tty *tty, const struct tty_ctx *ctx) { struct window_pane *wp = ctx->wp; - struct screen *s = wp->screen; if (ctx->ocy != ctx->orlower) return; @@ -886,12 +834,7 @@ tty_cmd_linefeed(struct tty *tty, const struct tty_ctx *ctx) !tty_term_has(tty->term, TTYC_CSR)) { if (tty_large_region(tty, ctx)) wp->flags |= PANE_REDRAW; - else if (tty_use_rect(tty)) { - tty_cra_pane (tty, ctx, ctx->orupper + 1, 0, - ctx->orlower, screen_size_x(s) - 1, - ctx->orupper, 0); - tty_cmd_clearline(tty, ctx); - } else + else tty_redraw_region(tty, ctx); return; } From 59c760dfcd9da4ce2a4e5b68e66416f77b4d5e5f Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 4 Sep 2012 13:24:50 +0000 Subject: [PATCH 1178/1180] Trivial code simplification from Tim Ruehsen. --- paste.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/paste.c b/paste.c index 3dcd6008..886231a2 100644 --- a/paste.c +++ b/paste.c @@ -162,10 +162,8 @@ paste_print(struct paste_buffer *pb, size_t width) len = width; used = strvisx(buf, pb->data, len, VIS_OCTAL|VIS_TAB|VIS_NL); - if (pb->size > width || used > width) { - buf[width - 3] = '\0'; - strlcat(buf, "...", width); - } + if (pb->size > width || used > width) + strlcpy(buf + width - 3, "...", 4); return (buf); } From b433886840ec4dba4b8b921b741b6a448a226d30 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 5 Sep 2012 09:59:41 +0000 Subject: [PATCH 1179/1180] We can't tell what the terminal has done with a DCS string, so reset the cursor and attributes afterwards. --- tty.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tty.c b/tty.c index 01b3a93d..0270af93 100644 --- a/tty.c +++ b/tty.c @@ -1046,6 +1046,12 @@ tty_cmd_rawstring(struct tty *tty, const struct tty_ctx *ctx) for (i = 0; i < ctx->num; i++) tty_putc(tty, str[i]); + + tty->cx = tty->cy = UINT_MAX; + tty->rupper = tty->rlower = UINT_MAX; + + tty_reset(tty); + tty_cursor(tty, 0, 0); } void From b2a9f4115f99f88a8b69a36a1f9ab12f6de4a986 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 5 Sep 2012 10:14:21 +0000 Subject: [PATCH 1180/1180] Handle empty list properly in choose-list, based on fix from Thomas Adam. --- cmd-choose-list.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cmd-choose-list.c b/cmd-choose-list.c index 15c644ec..4c32e694 100644 --- a/cmd-choose-list.c +++ b/cmd-choose-list.c @@ -86,6 +86,12 @@ cmd_choose_list_exec(struct cmd *self, struct cmd_ctx *ctx) } free(copy); + if (idx == 0) { + free(template); + window_pane_reset_mode(wl->window->active); + return (CMD_RETURN_ERROR); + } + window_choose_ready(wl->window->active, 0, cmd_choose_list_callback, cmd_choose_list_free);