aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/lock.yml2
-rw-r--r--.github/travis/before-install.sh17
-rw-r--r--.github/travis/build-all.sh38
-rw-r--r--.github/travis/build.sh25
-rw-r--r--.travis.yml72
-rw-r--r--CHANGES161
-rw-r--r--Makefile.am6
-rw-r--r--arguments.c63
-rw-r--r--attributes.c4
-rw-r--r--cfg.c61
-rw-r--r--client.c39
-rw-r--r--cmd-attach-session.c17
-rw-r--r--cmd-bind-key.c2
-rw-r--r--cmd-break-pane.c52
-rw-r--r--cmd-capture-pane.c12
-rw-r--r--cmd-choose-tree.c11
-rw-r--r--cmd-command-prompt.c45
-rw-r--r--cmd-confirm-before.c37
-rw-r--r--cmd-copy-mode.c31
-rw-r--r--cmd-detach-client.c46
-rw-r--r--cmd-display-menu.c305
-rw-r--r--cmd-display-message.c32
-rw-r--r--cmd-display-panes.c48
-rw-r--r--cmd-find-window.c7
-rw-r--r--cmd-find.c31
-rw-r--r--cmd-if-shell.c79
-rw-r--r--cmd-join-pane.c82
-rw-r--r--cmd-kill-pane.c8
-rw-r--r--cmd-kill-server.c2
-rw-r--r--cmd-kill-session.c9
-rw-r--r--cmd-kill-window.c11
-rw-r--r--cmd-list-buffers.c28
-rw-r--r--cmd-list-clients.c7
-rw-r--r--cmd-list-keys.c18
-rw-r--r--cmd-list-panes.c35
-rw-r--r--cmd-list-sessions.c28
-rw-r--r--cmd-list-windows.c33
-rw-r--r--cmd-load-buffer.c10
-rw-r--r--cmd-lock-server.c19
-rw-r--r--cmd-move-window.c57
-rw-r--r--cmd-new-session.c89
-rw-r--r--cmd-new-window.c19
-rw-r--r--cmd-parse.y96
-rw-r--r--cmd-paste-buffer.c5
-rw-r--r--cmd-pipe-pane.c21
-rw-r--r--cmd-queue.c428
-rw-r--r--cmd-refresh-client.c73
-rw-r--r--cmd-rename-session.c20
-rw-r--r--cmd-rename-window.c12
-rw-r--r--cmd-resize-pane.c103
-rw-r--r--cmd-resize-window.c7
-rw-r--r--cmd-respawn-pane.c12
-rw-r--r--cmd-respawn-window.c12
-rw-r--r--cmd-rotate-window.c10
-rw-r--r--cmd-run-shell.c83
-rw-r--r--cmd-save-buffer.c14
-rw-r--r--cmd-select-layout.c11
-rw-r--r--cmd-select-pane.c76
-rw-r--r--cmd-select-window.c24
-rw-r--r--cmd-send-keys.c73
-rw-r--r--cmd-set-buffer.c4
-rw-r--r--cmd-set-environment.c32
-rw-r--r--cmd-set-option.c79
-rw-r--r--cmd-show-environment.c37
-rw-r--r--cmd-show-messages.c26
-rw-r--r--cmd-show-options.c43
-rw-r--r--cmd-source-file.c4
-rw-r--r--cmd-split-window.c17
-rw-r--r--cmd-swap-pane.c12
-rw-r--r--cmd-swap-window.c18
-rw-r--r--cmd-switch-client.c65
-rw-r--r--cmd-unbind-key.c2
-rw-r--r--cmd-wait-for.c6
-rw-r--r--cmd.c151
-rw-r--r--compat.h4
-rw-r--r--configure.ac8
-rw-r--r--control.c32
-rw-r--r--environ.c29
-rw-r--r--format-draw.c12
-rw-r--r--format.c335
-rw-r--r--grid.c71
-rw-r--r--input-keys.c115
-rw-r--r--input.c246
-rw-r--r--job.c107
-rw-r--r--key-bindings.c120
-rw-r--r--key-string.c7
-rw-r--r--layout-set.c43
-rw-r--r--menu.c131
-rw-r--r--mode-tree.c83
-rw-r--r--names.c1
-rw-r--r--notify.c63
-rw-r--r--options-table.c201
-rw-r--r--options.c98
-rw-r--r--osdep-darwin.c2
-rw-r--r--paste.c11
-rw-r--r--popup.c519
-rw-r--r--regress/capture-pane-sgr0.sh15
-rw-r--r--regsub.c3
-rw-r--r--screen-redraw.c338
-rw-r--r--screen-write.c631
-rw-r--r--screen.c186
-rw-r--r--server-client.c318
-rw-r--r--server-fn.c6
-rw-r--r--server.c18
-rw-r--r--session.c18
-rw-r--r--spawn.c39
-rw-r--r--status.c600
-rw-r--r--style.c67
-rw-r--r--tmux.1483
-rw-r--r--tmux.c166
-rw-r--r--tmux.h485
-rw-r--r--tty-acs.c2
-rw-r--r--tty-features.c348
-rw-r--r--tty-keys.c112
-rw-r--r--tty-term.c149
-rw-r--r--tty.c828
-rw-r--r--window-buffer.c140
-rw-r--r--window-client.c3
-rw-r--r--window-clock.c2
-rw-r--r--window-copy.c464
-rw-r--r--window-tree.c34
-rw-r--r--window.c174
122 files changed, 7620 insertions, 3521 deletions
diff --git a/.github/lock.yml b/.github/lock.yml
index 89126482..08cf2fc0 100644
--- a/.github/lock.yml
+++ b/.github/lock.yml
@@ -1,4 +1,4 @@
-daysUntilLock: 180
+daysUntilLock: 30
skipCreatedBefore: false
exemptLabels: []
lockLabel: false
diff --git a/.github/travis/before-install.sh b/.github/travis/before-install.sh
new file mode 100644
index 00000000..9954e583
--- /dev/null
+++ b/.github/travis/before-install.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+if [ "$TRAVIS_OS_NAME" = "linux" ]; then
+ sudo apt-get update -qq
+ sudo apt-get -y install bison \
+ autotools-dev \
+ libncurses5-dev \
+ libevent-dev \
+ pkg-config \
+ libutempter-dev \
+ build-essential
+
+ if [ "$BUILD" = "musl" -o "$BUILD" = "musl-static" ]; then
+ sudo apt-get -y install musl-dev \
+ musl-tools
+ fi
+fi
diff --git a/.github/travis/build-all.sh b/.github/travis/build-all.sh
new file mode 100644
index 00000000..00f8f522
--- /dev/null
+++ b/.github/travis/build-all.sh
@@ -0,0 +1,38 @@
+#!/bin/sh
+
+BUILD=$PWD/build
+
+LIBEVENT=https://github.com/libevent/libevent/releases/download/release-2.1.11-stable/libevent-2.1.11-stab\
+le.tar.gz
+NCURSES=https://ftp.gnu.org/gnu/ncurses/ncurses-6.2.tar.gz
+
+wget -4q $LIBEVENT || exit 1
+tar -zxf libevent-*.tar.gz || exit 1
+(cd libevent-*/ &&
+ ./configure --prefix=$BUILD \
+ --enable-shared \
+ --disable-libevent-regress \
+ --disable-samples &&
+ make && make install) || exit 1
+
+wget -4q $NCURSES || exit 1
+tar -zxf ncurses-*.tar.gz || exit 1
+(cd ncurses-*/ &&
+ CPPFLAGS=-P ./configure --prefix=$BUILD \
+ --with-shared \
+ --with-termlib \
+ --without-ada \
+ --without-cxx \
+ --without-manpages \
+ --without-progs \
+ --without-tests \
+ --without-tack \
+ --disable-database \
+ --enable-termcap \
+ --enable-pc-files \
+ --with-pkg-config-libdir=$BUILD/lib/pkgconfig &&
+ make && make install) || exit 1
+
+sh autogen.sh || exit 1
+PKG_CONFIG_PATH=$BUILD/lib/pkgconfig ./configure --prefix=$BUILD "$@"
+make && make install || exit 1
diff --git a/.github/travis/build.sh b/.github/travis/build.sh
new file mode 100644
index 00000000..f863d8ad
--- /dev/null
+++ b/.github/travis/build.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+sh autogen.sh || exit 1
+case "$BUILD" in
+ static)
+ ./configure --enable-static || exit 1
+ exec make
+ ;;
+ all)
+ sh $(dirname $0)/build-all.sh
+ exec make
+ ;;
+ musl)
+ CC=musl-gcc sh $(dirname $0)/build-all.sh
+ exec make
+ ;;
+ musl-static)
+ CC=musl-gcc sh $(dirname $0)/build-all.sh --enable-static
+ exec make
+ ;;
+ *)
+ ./configure || exit 1
+ exec make
+ ;;
+esac
diff --git a/.travis.yml b/.travis.yml
index fd85bf61..16a04a16 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,16 +1,74 @@
language: c
os:
- - linux
- - osx
+ - linux
+ - osx
compiler:
- - gcc
- - clang
+ - gcc
+ - clang
+
+arch:
+ - amd64
+ - arm64
+
+env:
+ - BUILD=
+ - BUILD=static
+ - BUILD=all
+ - BUILD=musl
+ - BUILD=musl-static
+
+jobs:
+ exclude:
+ # Static builds are broken on OS X (by Apple)
+ - os: osx
+ compiler: gcc
+ env: BUILD=static
+ - os: osx
+ compiler: clang
+ env: BUILD=static
+ # No musl on OS X
+ - os: osx
+ compiler: gcc
+ env: BUILD=musl
+ - os: osx
+ compiler: clang
+ env: BUILD=musl
+ - os: osx
+ compiler: gcc
+ env: BUILD=musl-static
+ - os: osx
+ compiler: clang
+ env: BUILD=musl-static
+ # arm64 doesn't link ncurses
+ - os: linux
+ compiler: gcc
+ arch: arm64
+ env: BUILD=all
+ - os: linux
+ compiler: clang
+ arch: arm64
+ env: BUILD=all
+ - os: linux
+ compiler: gcc
+ arch: arm64
+ env: BUILD=musl
+ - os: linux
+ compiler: clang
+ arch: arm64
+ env: BUILD=musl
+ - os: linux
+ compiler: gcc
+ arch: arm64
+ env: BUILD=musl-static
+ - os: linux
+ compiler: clang
+ arch: arm64
+ env: BUILD=musl-static
before_install:
- - if [ "$TRAVIS_OS_NAME" = "linux" ]; then sudo apt-get update -qq; fi
- - if [ "$TRAVIS_OS_NAME" = "linux" ]; then sudo apt-get -y install bison autotools-dev libncurses5-dev libevent-dev pkg-config libutempter-dev build-essential; fi
+ - sh .github/travis/before-install.sh
script:
- - ./autogen.sh && ./configure && make
+ - sh .github/travis/build.sh
diff --git a/CHANGES b/CHANGES
index 01007a95..aeae71b1 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,164 @@
+CHANGES FROM 3.1b TO 3.2
+
+* Add a key (e) in buffer mode to open the buffer in an editor. The buffer
+ contents is updated when the editor exits.
+
+* Add -e flag for new-session to set environment variables, like the same flag
+ for new-window.
+
+* Improve search match marking in copy mode. Two new options
+ copy-mode-match-style and copy-mode-current-match-style to set the style for
+ matches and for the current match respectively. Also a change so that if a
+ copy key is pressed with no selection, the current match (if any) is copied.
+
+* Sanitize session names like window names instead of forbidding invalid ones.
+
+* Check if the clear terminfo(5) capability starts with CSI and if so then
+ assume the terminal is VT100-like, rather than relying on the XT capability.
+
+* Improve command prompt tab completion and add menus both for strings and for
+ -t and -s (when used without a trailing space).
+
+* Change all the style options to string options so they can support formats.
+ Change pane-border-active-style to use this to change the border colour when
+ in a mode or with synchronize-panes on. This also implies a few minor changes
+ to existing behaviour:
+
+ - set-option -a with a style option automatically inserts a comma between the
+ old value and appended text.
+
+ - OSC 10 and 11 no longer set the window-style option, instead they store the
+ colour internally in the pane data and it is used as the default when the
+ option is evaluated.
+
+ - status-fg and -bg now override status-style instead of the option values
+ being changed.
+
+* Add extension terminfo(5) capabilities for margins and focus reporting.
+
+* Try $XDG_CONFIG_HOME/tmux/tmux.conf as well as ~/.config/tmux/tmux.conf for
+ configuration file (the search paths are in TMUX_CONF in Makefile.am).
+
+* Remove the DSR 1337 iTerm2 extension and replace by the extended device
+ attributes sequence (CSI > q) supported by more terminals.
+
+* Add a -s flag to copy-mode to specify a different pane for the source
+ content. This means it is possible to view two places in a pane's history at
+ the same time in different panes, or view the history while still using the
+ pane. Pressing r refreshes the content from the source pane.
+
+* Add an argument to list-commands to show only a single command.
+
+* Change copy mode to make copy of the pane history so it does not need to
+ freeze the pane.
+
+* Restore pane_current_path format from portable tmux on OpenBSD.
+
+* Wait until the initial command sequence is done before sending a device
+ attributes request and other bits that prompt a reply from the terminal. This
+ means that stray relies are not left on the terminal if the command has
+ attached and then immediately detached and tmux will not be around to receive
+ them.
+
+* Add a -f filter argument to the list commands like choose-tree.
+
+* Move specific hooks for panes to pane options and windows for window options
+ rather than all hooks being session options. These hooks are now window options:
+
+ window-layout-changed
+ window-linked
+ window-pane-changed
+ window-renamed
+ window-unlinked
+
+ And these now pane options:
+
+ pane-died
+ pane-exited
+ pane-focus-in
+ pane-focus-out
+ pane-mode-changed
+ pane-set-clipboard
+
+ Any existing configurations using these hooks on a session rather than
+ globally (that is, set-hook or set-option without -g) may need to be changed.
+
+* Show signal names when a process exits with remain-on-exit on platforms which
+ have a way to get them.
+
+* Start menu with top item selected if no mouse and use mode-style for the
+ selected item.
+
+* Add a copy-command option and change copy-pipe and friends to pipe to it if
+ used without arguments, allows all the default copy key bindings to be
+ changed to pipe with one option rather than needing to change each key
+ binding individually.
+
+* Tidy up the terminal detection and feature code and add named sets of
+ terminal features, each of which are defined in one place and map to a
+ builtin set of terminfo(5) capabilities. Features can be specified based on
+ TERM with a new terminal-features option or with the -T flag when running
+ tmux. tmux will also detect a few common terminals from the DA and DSR
+ responses.
+
+ This is intended to make it easier to configure tmux's use of terminfo(5)
+ even in the presence of outdated ncurses(3) or terminfo(5) databases or for
+ features which do not yet have a terminfo(5) entry. Instead of having to grok
+ terminfo(5) capability names and what they should be set to in the
+ terminal-overrides option, the user can hopefully just give tmux a feature
+ name and let it do the right thing.
+
+ The terminal-overrides option remains both for backwards compatibility and to
+ allow tweaks of individual capabilities.
+
+* Support mintty's application escape sequence (means tmux doesn't have to
+ delay to wait for Escape, so no need to reduce escape-time when using
+ mintty).
+
+* Change so main-pane-width and height can be given as a percentage.
+
+* Support for the iTerm2 synchronized updates feature (allows the terminal to
+ avoid unnecessary drawing while output is still in progress).
+
+* Make the mouse_word and mouse_line formats work in copy mode and enable the
+ default pane menu in copy mode.
+
+* Add a -T flag to resize-pane to trim lines below the cursor, moving lines out
+ of the history.
+
+* Add a way to mark environment variables as "hidden" so they can be used by
+ tmux (for example in formats) but are not set in the environment for new
+ panes. set-environment and show-environment have a new -h flag and there is a
+ new %hidden statement for the configuration file.
+
+* Change default position for display-menu -x and -y to centre rather than top
+ left.
+
+* Add support for per-client transient popups, similar to menus. These are
+ created with new command display-popup. Popups may either show fixed text and
+ trigger a tmux command when a key is pressed, or run a program (-R flag).
+
+* Change double and triple click bindings so that only one is fired (previously
+ double click was fired on the way to triple click). Also add default double
+ and triple click bindings to copy the word or line under the cursor and
+ change the existing bindings in copy mode to do the same.
+
+* Add a default binding for button 2 to paste.
+
+* Add -d flag to run-shell to delay before running the command and allow it to
+ run without a command so it just delays.
+
+* Add C-g to cancel command prompt with vi keys as well as emacs, and q in
+ command mode.
+
+* When the server socket is given with -S, create it with umask 177 instead of
+ 117 (because it may not be in a safe directory like the default directory in
+ /tmp).
+
+* Add a copy-mode -H flag to hide the position marker in the top right.
+
+* Add number operators for formats (+, -, *, / and m),
+
CHANGES FROM 3.1a TO 3.1b
* Fix build on systems without sys/queue.h.
diff --git a/Makefile.am b/Makefile.am
index 082a467c..a395ecdb 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -12,8 +12,8 @@ dist_EXTRA_tmux_SOURCES = compat/*.[ch]
# Preprocessor flags.
AM_CPPFLAGS += @XOPEN_DEFINES@ \
- -DTMUX_VERSION="\"@VERSION@\"" \
- -DTMUX_CONF="\"$(sysconfdir)/tmux.conf:~/.tmux.conf:~/.config/tmux/tmux.conf\""
+ -DTMUX_VERSION='"@VERSION@"' \
+ -DTMUX_CONF='"$(sysconfdir)/tmux.conf:~/.tmux.conf:$$XDG_CONFIG_HOME/tmux/tmux.conf:~/.config/tmux/tmux.conf"'
# Additional object files.
LDADD = $(LIBOBJS)
@@ -154,6 +154,7 @@ dist_tmux_SOURCES = \
options-table.c \
options.c \
paste.c \
+ popup.c \
proc.c \
regsub.c \
resize.c \
@@ -170,6 +171,7 @@ dist_tmux_SOURCES = \
tmux.c \
tmux.h \
tty-acs.c \
+ tty-features.c \
tty-keys.c \
tty-term.c \
tty.c \
diff --git a/arguments.c b/arguments.c
index e2d18980..e1956ace 100644
--- a/arguments.c
+++ b/arguments.c
@@ -215,8 +215,10 @@ args_escape(const char *s)
char *escaped, *result;
int flags;
- if (*s == '\0')
- return (xstrdup(s));
+ if (*s == '\0') {
+ xasprintf(&result, "''");
+ return (result);
+ }
if (s[0] != ' ' &&
(strchr(quoted, s[0]) != NULL || s[0] == '~') &&
s[1] == '\0') {
@@ -343,3 +345,60 @@ args_strtonum(struct args *args, u_char ch, long long minval, long long maxval,
*cause = NULL;
return (ll);
}
+
+/* Convert an argument to a number which may be a percentage. */
+long long
+args_percentage(struct args *args, u_char ch, long long minval,
+ long long maxval, long long curval, char **cause)
+{
+ const char *value;
+ struct args_entry *entry;
+
+ if ((entry = args_find(args, ch)) == NULL) {
+ *cause = xstrdup("missing");
+ return (0);
+ }
+ value = TAILQ_LAST(&entry->values, args_values)->value;
+ return (args_string_percentage(value, minval, maxval, curval, cause));
+}
+
+/* Convert a string to a number which may be a percentage. */
+long long
+args_string_percentage(const char *value, long long minval, long long maxval,
+ long long curval, char **cause)
+{
+ const char *errstr;
+ long long ll;
+ size_t valuelen = strlen(value);
+ char *copy;
+
+ if (value[valuelen - 1] == '%') {
+ copy = xstrdup(value);
+ copy[valuelen - 1] = '\0';
+
+ ll = strtonum(copy, 0, 100, &errstr);
+ free(copy);
+ if (errstr != NULL) {
+ *cause = xstrdup(errstr);
+ return (0);
+ }
+ ll = (curval * ll) / 100;
+ if (ll < minval) {
+ *cause = xstrdup("too large");
+ return (0);
+ }
+ if (ll > maxval) {
+ *cause = xstrdup("too small");
+ return (0);
+ }
+ } else {
+ ll = strtonum(value, minval, maxval, &errstr);
+ if (errstr != NULL) {
+ *cause = xstrdup(errstr);
+ return (0);
+ }
+ }
+
+ *cause = NULL;
+ return (ll);
+}
diff --git a/attributes.c b/attributes.c
index ca88a056..b839f06d 100644
--- a/attributes.c
+++ b/attributes.c
@@ -31,7 +31,8 @@ attributes_tostring(int attr)
if (attr == 0)
return ("none");
- len = xsnprintf(buf, sizeof buf, "%s%s%s%s%s%s%s%s%s%s%s%s%s",
+ len = xsnprintf(buf, sizeof buf, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+ (attr & GRID_ATTR_CHARSET) ? "acs," : "",
(attr & GRID_ATTR_BRIGHT) ? "bright," : "",
(attr & GRID_ATTR_DIM) ? "dim," : "",
(attr & GRID_ATTR_UNDERSCORE) ? "underscore," : "",
@@ -62,6 +63,7 @@ attributes_fromstring(const char *str)
const char *name;
int attr;
} table[] = {
+ { "acs", GRID_ATTR_CHARSET },
{ "bright", GRID_ATTR_BRIGHT },
{ "bold", GRID_ATTR_BRIGHT },
{ "dim", GRID_ATTR_DIM },
diff --git a/cfg.c b/cfg.c
index 933eda4e..84be3967 100644
--- a/cfg.c
+++ b/cfg.c
@@ -66,45 +66,12 @@ set_cfg_file(const char *path)
cfg_file = xstrdup(path);
}
-static char *
-expand_cfg_file(const char *path, const char *home)
-{
- char *expanded, *name;
- const char *end;
- struct environ_entry *value;
-
- if (strncmp(path, "~/", 2) == 0) {
- if (home == NULL)
- return (NULL);
- xasprintf(&expanded, "%s%s", home, path + 1);
- return (expanded);
- }
-
- if (*path == '$') {
- end = strchr(path, '/');
- if (end == NULL)
- name = xstrdup(path + 1);
- else
- name = xstrndup(path + 1, end - path - 1);
- value = environ_find(global_environ, name);
- free(name);
- if (value == NULL)
- return (NULL);
- if (end == NULL)
- end = "";
- xasprintf(&expanded, "%s%s", value->value, end);
- return (expanded);
- }
-
- return (xstrdup(path));
-}
-
void
start_cfg(void)
{
- const char *home = find_home();
- struct client *c;
- char *path, *copy, *next, *expanded;
+ struct client *c;
+ char **paths;
+ u_int i, n;
/*
* Configuration files are loaded without a client, so commands are run
@@ -123,18 +90,12 @@ start_cfg(void)
}
if (cfg_file == NULL) {
- path = copy = xstrdup(TMUX_CONF);
- while ((next = strsep(&path, ":")) != NULL) {
- expanded = expand_cfg_file(next, home);
- if (expanded == NULL) {
- log_debug("couldn't expand %s", next);
- continue;
- }
- log_debug("expanded %s to %s", next, expanded);
- load_cfg(expanded, c, NULL, CMD_PARSE_QUIET, NULL);
- free(expanded);
+ expand_paths(TMUX_CONF, &paths, &n);
+ for (i = 0; i < n; i++) {
+ load_cfg(paths[i], c, NULL, CMD_PARSE_QUIET, NULL);
+ free(paths[i]);
}
- free(copy);
+ free(paths);
} else
load_cfg(cfg_file, c, NULL, 0, NULL);
@@ -182,7 +143,7 @@ load_cfg(const char *path, struct client *c, struct cmdq_item *item, int flags,
return (0);
}
- new_item0 = cmdq_get_command(pr->cmdlist, NULL, NULL, 0);
+ new_item0 = cmdq_get_command(pr->cmdlist, NULL);
if (item != NULL)
new_item0 = cmdq_insert_after(item, new_item0);
else
@@ -228,7 +189,7 @@ load_cfg_from_buffer(const void *buf, size_t len, const char *path,
return (0);
}
- new_item0 = cmdq_get_command(pr->cmdlist, NULL, NULL, 0);
+ new_item0 = cmdq_get_command(pr->cmdlist, NULL);
if (item != NULL)
new_item0 = cmdq_insert_after(item, new_item0);
else
@@ -283,7 +244,7 @@ cfg_show_causes(struct session *s)
wme = TAILQ_FIRST(&wp->modes);
if (wme == NULL || wme->mode != &window_view_mode)
- window_pane_set_mode(wp, &window_view_mode, NULL, NULL);
+ window_pane_set_mode(wp, NULL, &window_view_mode, NULL, NULL);
for (i = 0; i < cfg_ncauses; i++) {
window_copy_add(wp, "%s", cfg_causes[i]);
free(cfg_causes[i]);
diff --git a/client.c b/client.c
index f247d059..4e7f7dcc 100644
--- a/client.c
+++ b/client.c
@@ -57,7 +57,7 @@ static struct client_files client_files = RB_INITIALIZER(&client_files);
static __dead void client_exec(const char *,const char *);
static int client_get_lock(char *);
static int client_connect(struct event_base *, const char *, int);
-static void client_send_identify(const char *, const char *);
+static void client_send_identify(const char *, const char *, int);
static void client_signal(int);
static void client_dispatch(struct imsg *, void *);
static void client_dispatch_attached(struct imsg *);
@@ -97,7 +97,7 @@ client_get_lock(char *lockfile)
/* Connect client to server. */
static int
-client_connect(struct event_base *base, const char *path, int start_server)
+client_connect(struct event_base *base, const char *path, int flags)
{
struct sockaddr_un sa;
size_t size;
@@ -122,7 +122,7 @@ retry:
log_debug("connect failed: %s", strerror(errno));
if (errno != ECONNREFUSED && errno != ENOENT)
goto failed;
- if (!start_server)
+ if (~flags & CLIENT_STARTSERVER)
goto failed;
close(fd);
@@ -154,7 +154,7 @@ retry:
close(lockfd);
return (-1);
}
- fd = server_start(client_proc, base, lockfd, lockfile);
+ fd = server_start(client_proc, flags, base, lockfd, lockfile);
}
if (locked && lockfd >= 0) {
@@ -233,12 +233,11 @@ client_exit(void)
/* Client main loop. */
int
-client_main(struct event_base *base, int argc, char **argv, int flags)
+client_main(struct event_base *base, int argc, char **argv, int flags, int feat)
{
struct cmd_parse_result *pr;
- struct cmd *cmd;
struct msg_command *data;
- int cmdflags, fd, i;
+ int fd, i;
const char *ttynam, *cwd;
pid_t ppid;
enum msgtype msg;
@@ -248,17 +247,13 @@ client_main(struct event_base *base, int argc, char **argv, int flags)
/* Ignore SIGCHLD now or daemon() in the server will leave a zombie. */
signal(SIGCHLD, SIG_IGN);
- /* Save the flags. */
- client_flags = flags;
-
/* Set up the initial command. */
- cmdflags = 0;
if (shell_command != NULL) {
msg = MSG_SHELL;
- cmdflags = CMD_STARTSERVER;
+ flags |= CLIENT_STARTSERVER;
} else if (argc == 0) {
msg = MSG_COMMAND;
- cmdflags = CMD_STARTSERVER;
+ flags |= CLIENT_STARTSERVER;
} else {
msg = MSG_COMMAND;
@@ -269,21 +264,22 @@ client_main(struct event_base *base, int argc, char **argv, int flags)
*/
pr = cmd_parse_from_arguments(argc, argv, NULL);
if (pr->status == CMD_PARSE_SUCCESS) {
- TAILQ_FOREACH(cmd, &pr->cmdlist->list, qentry) {
- if (cmd->entry->flags & CMD_STARTSERVER)
- cmdflags |= CMD_STARTSERVER;
- }
+ if (cmd_list_any_have(pr->cmdlist, CMD_STARTSERVER))
+ flags |= CLIENT_STARTSERVER;
cmd_list_free(pr->cmdlist);
} else
free(pr->error);
}
+ /* Save the flags. */
+ client_flags = flags;
+
/* Create client process structure (starts logging). */
client_proc = proc_start("client");
proc_set_signals(client_proc, client_signal);
/* Initialize the client socket and start the server. */
- fd = client_connect(base, socket_path, cmdflags & CMD_STARTSERVER);
+ fd = client_connect(base, socket_path, client_flags);
if (fd == -1) {
if (errno == ECONNREFUSED) {
fprintf(stderr, "no server running on %s\n",
@@ -346,7 +342,7 @@ client_main(struct event_base *base, int argc, char **argv, int flags)
}
/* Send identify messages. */
- client_send_identify(ttynam, cwd);
+ client_send_identify(ttynam, cwd, feat);
/* Send first command. */
if (msg == MSG_COMMAND) {
@@ -412,7 +408,7 @@ client_main(struct event_base *base, int argc, char **argv, int flags)
/* Send identify messages to server. */
static void
-client_send_identify(const char *ttynam, const char *cwd)
+client_send_identify(const char *ttynam, const char *cwd, int feat)
{
const char *s;
char **ss;
@@ -425,6 +421,7 @@ client_send_identify(const char *ttynam, const char *cwd)
if ((s = getenv("TERM")) == NULL)
s = "";
proc_send(client_peer, MSG_IDENTIFY_TERM, -1, s, strlen(s) + 1);
+ proc_send(client_peer, MSG_IDENTIFY_FEATURES, -1, &feat, sizeof feat);
proc_send(client_peer, MSG_IDENTIFY_TTYNAME, -1, ttynam,
strlen(ttynam) + 1);
@@ -647,7 +644,7 @@ client_read_open(void *data, size_t datalen)
struct msg_read_done reply;
struct client_file find, *cf;
const int flags = O_NONBLOCK|O_RDONLY;
- int error = 0;
+ int error;
if (datalen < sizeof *msg)
fatalx("bad MSG_READ_OPEN size");
diff --git a/cmd-attach-session.c b/cmd-attach-session.c
index 477d3517..8c30c767 100644
--- a/cmd-attach-session.c
+++ b/cmd-attach-session.c
@@ -50,10 +50,11 @@ enum cmd_retval
cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
int xflag, int rflag, const char *cflag, int Eflag)
{
- struct cmd_find_state *current = &item->shared->current;
+ struct cmd_find_state *current = cmdq_get_current(item);
+ struct cmd_find_state target;
enum cmd_find_type type;
int flags;
- struct client *c = item->client, *c_loop;
+ struct client *c = cmdq_get_client(item), *c_loop;
struct session *s;
struct winlink *wl;
struct window_pane *wp;
@@ -80,11 +81,11 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
type = CMD_FIND_SESSION;
flags = CMD_FIND_PREFER_UNATTACHED;
}
- if (cmd_find_target(&item->target, item, tflag, type, flags) != 0)
+ if (cmd_find_target(&target, item, tflag, type, flags) != 0)
return (CMD_RETURN_ERROR);
- s = item->target.s;
- wl = item->target.wl;
- wp = item->target.wp;
+ s = target.s;
+ wl = target.wl;
+ wp = target.wp;
if (wl != NULL) {
if (wp != NULL)
@@ -118,7 +119,7 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
environ_update(s->options, c->environ, s->environ);
c->session = s;
- if (~item->shared->flags & CMDQ_SHARED_REPEAT)
+ if (~cmdq_get_flags(item) & CMDQ_STATE_REPEAT)
server_client_set_key_table(c, NULL);
tty_update_client_offset(c);
status_timer_start(c);
@@ -177,7 +178,7 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
static enum cmd_retval
cmd_attach_session_exec(struct cmd *self, struct cmdq_item *item)
{
- struct args *args = self->args;
+ struct args *args = cmd_get_args(self);
return (cmd_attach_session(item, args_get(args, 't'),
args_has(args, 'd'), args_has(args, 'x'), args_has(args, 'r'),
diff --git a/cmd-bind-key.c b/cmd-bind-key.c
index bc6a3d40..dcb56c06 100644
--- a/cmd-bind-key.c
+++ b/cmd-bind-key.c
@@ -44,7 +44,7 @@ const struct cmd_entry cmd_bind_key_entry = {
static enum cmd_retval
cmd_bind_key_exec(struct cmd *self, struct cmdq_item *item)
{
- struct args *args = self->args;
+ struct args *args = cmd_get_args(self);
key_code key;
const char *tablename, *note;
struct cmd_parse_result *pr;
diff --git a/cmd-break-pane.c b/cmd-break-pane.c
index 6c638103..87892d73 100644
--- a/cmd-break-pane.c
+++ b/cmd-break-pane.c
@@ -34,8 +34,8 @@ const struct cmd_entry cmd_break_pane_entry = {
.name = "break-pane",
.alias = "breakp",
- .args = { "dPF:n:s:t:", 0, 0 },
- .usage = "[-dP] [-F format] [-n window-name] [-s src-pane] "
+ .args = { "adPF:n:s:t:", 0, 0 },
+ .usage = "[-adP] [-F format] [-n window-name] [-s src-pane] "
"[-t dst-window]",
.source = { 's', CMD_FIND_PANE, 0 },
@@ -48,29 +48,45 @@ const struct cmd_entry cmd_break_pane_entry = {
static enum cmd_retval
cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
{
- struct args *args = self->args;
- struct cmd_find_state *current = &item->shared->current;
- struct client *c = cmd_find_client(item, NULL, 1);
- struct winlink *wl = item->source.wl;
- struct session *src_s = item->source.s;
- struct session *dst_s = item->target.s;
- struct window_pane *wp = item->source.wp;
+ struct args *args = cmd_get_args(self);
+ struct cmd_find_state *current = cmdq_get_current(item);
+ struct cmd_find_state *target = cmdq_get_target(item);
+ struct cmd_find_state *source = cmdq_get_source(item);
+ struct client *tc = cmdq_get_target_client(item);
+ struct winlink *wl = source->wl;
+ struct session *src_s = source->s;
+ struct session *dst_s = target->s;
+ struct window_pane *wp = source->wp;
struct window *w = wl->window;
char *name, *cause;
- int idx = item->target.idx;
+ int idx = target->idx;
const char *template;
char *cp;
- if (idx != -1 && winlink_find_by_index(&dst_s->windows, idx) != NULL) {
- cmdq_error(item, "index %d already in use", idx);
- return (CMD_RETURN_ERROR);
+ if (args_has(args, 'a')) {
+ if (target->wl != NULL)
+ idx = winlink_shuffle_up(dst_s, target->wl);
+ else
+ idx = winlink_shuffle_up(dst_s, dst_s->curw);
+ if (idx == -1)
+ return (CMD_RETURN_ERROR);
}
+ server_unzoom_window(w);
if (window_count_panes(w) == 1) {
- cmdq_error(item, "can't break with only one pane");
+ if (server_link_window(src_s, wl, dst_s, idx, 0,
+ !args_has(args, 'd'), &cause) != 0) {
+ cmdq_error(item, "%s", cause);
+ free(cause);
+ return (CMD_RETURN_ERROR);
+ }
+ server_unlink_window(src_s, wl);
+ return (CMD_RETURN_NORMAL);
+ }
+ if (idx != -1 && winlink_find_by_index(&dst_s->windows, idx) != NULL) {
+ cmdq_error(item, "index in use: %d", idx);
return (CMD_RETURN_ERROR);
}
- server_unzoom_window(w);
TAILQ_REMOVE(&w->panes, wp, entry);
window_lost_pane(w, wp);
@@ -81,7 +97,7 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
wp->flags |= PANE_STYLECHANGED;
TAILQ_INSERT_HEAD(&w->panes, wp, entry);
w->active = wp;
- w->latest = c;
+ w->latest = tc;
if (!args_has(args, 'n')) {
name = default_window_name(w);
@@ -98,7 +114,7 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
if (idx == -1)
idx = -1 - options_get_number(dst_s->options, "base-index");
wl = session_attach(dst_s, w, idx, &cause); /* can't fail */
- if (!args_has(self->args, 'd')) {
+ if (!args_has(args, 'd')) {
session_select(dst_s, wl->idx);
cmd_find_from_session(current, dst_s, 0);
}
@@ -113,7 +129,7 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
if (args_has(args, 'P')) {
if ((template = args_get(args, 'F')) == NULL)
template = BREAK_PANE_TEMPLATE;
- cp = format_single(item, template, c, dst_s, wl, wp);
+ cp = format_single(item, template, tc, dst_s, wl, wp);
cmdq_print(item, "%s", cp);
free(cp);
}
diff --git a/cmd-capture-pane.c b/cmd-capture-pane.c
index 18be3f77..588b0fd5 100644
--- a/cmd-capture-pane.c
+++ b/cmd-capture-pane.c
@@ -80,7 +80,7 @@ cmd_capture_pane_pending(struct args *args, struct window_pane *wp,
size_t linelen;
u_int i;
- pending = input_pending(wp);
+ pending = input_pending(wp->ictx);
if (pending == NULL)
return (xstrdup(""));
@@ -118,7 +118,7 @@ cmd_capture_pane_history(struct args *args, struct cmdq_item *item,
sx = screen_size_x(&wp->base);
if (args_has(args, 'a')) {
- gd = wp->saved_grid;
+ gd = wp->base.saved_grid;
if (gd == NULL) {
if (!args_has(args, 'q')) {
cmdq_error(item, "no alternate screen");
@@ -192,14 +192,14 @@ cmd_capture_pane_history(struct args *args, struct cmdq_item *item,
static enum cmd_retval
cmd_capture_pane_exec(struct cmd *self, struct cmdq_item *item)
{
- struct args *args = self->args;
- struct client *c = item->client;
- struct window_pane *wp = item->target.wp;
+ struct args *args = cmd_get_args(self);
+ struct client *c = cmdq_get_client(item);
+ struct window_pane *wp = cmdq_get_target(item)->wp;
char *buf, *cause;
const char *bufname;
size_t len;
- if (self->entry == &cmd_clear_history_entry) {
+ if (cmd_get_entry(self) == &cmd_clear_history_entry) {
window_pane_reset_mode_all(wp);
grid_clear_history(wp->base.grid);
return (CMD_RETURN_NORMAL);
diff --git a/cmd-choose-tree.c b/cmd-choose-tree.c
index 8178ec9f..0ada8fd4 100644
--- a/cmd-choose-tree.c
+++ b/cmd-choose-tree.c
@@ -71,21 +71,22 @@ const struct cmd_entry cmd_choose_buffer_entry = {
static enum cmd_retval
cmd_choose_tree_exec(struct cmd *self, struct cmdq_item *item)
{
- struct args *args = self->args;
- struct window_pane *wp = item->target.wp;
+ struct args *args = cmd_get_args(self);
+ struct cmd_find_state *target = cmdq_get_target(item);
+ struct window_pane *wp = target->wp;
const struct window_mode *mode;
- if (self->entry == &cmd_choose_buffer_entry) {
+ if (cmd_get_entry(self) == &cmd_choose_buffer_entry) {
if (paste_get_top(NULL) == NULL)
return (CMD_RETURN_NORMAL);
mode = &window_buffer_mode;
- } else if (self->entry == &cmd_choose_client_entry) {
+ } else if (cmd_get_entry(self) == &cmd_choose_client_entry) {
if (server_client_how_many() == 0)
return (CMD_RETURN_NORMAL);
mode = &window_client_mode;
} else
mode = &window_tree_mode;
- window_pane_set_mode(wp, mode, &item->target, args);
+ window_pane_set_mode(wp, NULL, mode, target, args);
return (CMD_RETURN_NORMAL);
}
diff --git a/cmd-command-prompt.c b/cmd-command-prompt.c
index 9f0ea19f..b8e3bd5c 100644
--- a/cmd-command-prompt.c
+++ b/cmd-command-prompt.c
@@ -40,11 +40,11 @@ const struct cmd_entry cmd_command_prompt_entry = {
.name = "command-prompt",
.alias = NULL,
- .args = { "1kiI:Np:t:", 0, 1 },
- .usage = "[-1kiN] [-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE " "
+ .args = { "1kiI:Np:Tt:W", 0, 1 },
+ .usage = "[-1kiNTW] [-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE " "
"[template]",
- .flags = 0,
+ .flags = CMD_CLIENT_TFLAG,
.exec = cmd_command_prompt_exec
};
@@ -64,17 +64,14 @@ struct cmd_command_prompt_cdata {
static enum cmd_retval
cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item)
{
- struct args *args = self->args;
+ struct args *args = cmd_get_args(self);
+ struct client *tc = cmdq_get_target_client(item);
const char *inputs, *prompts;
struct cmd_command_prompt_cdata *cdata;
- struct client *c;
char *prompt, *ptr, *input = NULL;
size_t n;
- if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
- return (CMD_RETURN_ERROR);
-
- if (c->prompt_string != NULL)
+ if (tc->prompt_string != NULL)
return (CMD_RETURN_NORMAL);
cdata = xcalloc(1, sizeof *cdata);
@@ -124,7 +121,11 @@ cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item)
cdata->flags |= PROMPT_INCREMENTAL;
else if (args_has(args, 'k'))
cdata->flags |= PROMPT_KEY;
- status_prompt_set(c, prompt, input, cmd_command_prompt_callback,
+ else if (args_has(args, 'W'))
+ cdata->flags |= PROMPT_WINDOW;
+ else if (args_has(args, 'T'))
+ cdata->flags |= PROMPT_TARGET;
+ status_prompt_set(tc, prompt, input, cmd_command_prompt_callback,
cmd_command_prompt_free, cdata, cdata->flags);
free(prompt);
@@ -136,10 +137,9 @@ cmd_command_prompt_callback(struct client *c, void *data, const char *s,
int done)
{
struct cmd_command_prompt_cdata *cdata = data;
- struct cmdq_item *new_item;
- char *new_template, *prompt, *ptr;
+ char *new_template, *prompt, *ptr, *error;
char *input = NULL;
- struct cmd_parse_result *pr;
+ enum cmd_parse_status status;
if (s == NULL)
return (0);
@@ -166,21 +166,10 @@ cmd_command_prompt_callback(struct client *c, void *data, const char *s,
return (1);
}
- pr = cmd_parse_from_string(new_template, NULL);
- switch (pr->status) {
- case CMD_PARSE_EMPTY:
- new_item = NULL;
- break;
- case CMD_PARSE_ERROR:
- new_item = cmdq_get_error(pr->error);
- free(pr->error);
- cmdq_append(c, new_item);
- break;
- case CMD_PARSE_SUCCESS:
- new_item = cmdq_get_command(pr->cmdlist, NULL, NULL, 0);
- cmd_list_free(pr->cmdlist);
- cmdq_append(c, new_item);
- break;
+ status = cmd_parse_and_append(new_template, NULL, c, NULL, &error);
+ if (status == CMD_PARSE_ERROR) {
+ cmdq_append(c, cmdq_get_error(error));
+ free(error);
}
if (!done)
diff --git a/cmd-confirm-before.c b/cmd-confirm-before.c
index be21a78b..0d881178 100644
--- a/cmd-confirm-before.c
+++ b/cmd-confirm-before.c
@@ -42,7 +42,7 @@ const struct cmd_entry cmd_confirm_before_entry = {
.args = { "p:t:", 1, 1 },
.usage = "[-p prompt] " CMD_TARGET_CLIENT_USAGE " command",
- .flags = 0,
+ .flags = CMD_CLIENT_TFLAG,
.exec = cmd_confirm_before_exec
};
@@ -53,15 +53,12 @@ struct cmd_confirm_before_data {
static enum cmd_retval
cmd_confirm_before_exec(struct cmd *self, struct cmdq_item *item)
{
- struct args *args = self->args;
+ struct args *args = cmd_get_args(self);
struct cmd_confirm_before_data *cdata;
- struct client *c;
+ struct client *tc = cmdq_get_target_client(item);
char *cmd, *copy, *new_prompt, *ptr;
const char *prompt;
- if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
- return (CMD_RETURN_ERROR);
-
if ((prompt = args_get(args, 'p')) != NULL)
xasprintf(&new_prompt, "%s ", prompt);
else {
@@ -74,9 +71,8 @@ cmd_confirm_before_exec(struct cmd *self, struct cmdq_item *item)
cdata = xmalloc(sizeof *cdata);
cdata->cmd = xstrdup(args->argv[0]);
- status_prompt_set(c, new_prompt, NULL,
- cmd_confirm_before_callback, cmd_confirm_before_free, cdata,
- PROMPT_SINGLE);
+ status_prompt_set(tc, new_prompt, NULL, cmd_confirm_before_callback,
+ cmd_confirm_before_free, cdata, PROMPT_SINGLE);
free(new_prompt);
return (CMD_RETURN_NORMAL);
@@ -87,8 +83,8 @@ cmd_confirm_before_callback(struct client *c, void *data, const char *s,
__unused int done)
{
struct cmd_confirm_before_data *cdata = data;
- struct cmdq_item *new_item;
- struct cmd_parse_result *pr;
+ char *error;
+ enum cmd_parse_status status;
if (c->flags & CLIENT_DEAD)
return (0);
@@ -98,21 +94,10 @@ cmd_confirm_before_callback(struct client *c, void *data, const char *s,
if (tolower((u_char)s[0]) != 'y' || s[1] != '\0')
return (0);
- pr = cmd_parse_from_string(cdata->cmd, NULL);
- switch (pr->status) {
- case CMD_PARSE_EMPTY:
- new_item = NULL;
- break;
- case CMD_PARSE_ERROR:
- new_item = cmdq_get_error(pr->error);
- free(pr->error);
- cmdq_append(c, new_item);
- break;
- case CMD_PARSE_SUCCESS:
- new_item = cmdq_get_command(pr->cmdlist, NULL, NULL, 0);
- cmd_list_free(pr->cmdlist);
- cmdq_append(c, new_item);
- break;
+ status = cmd_parse_and_append(cdata->cmd, NULL, c, NULL, &error);
+ if (status == CMD_PARSE_ERROR) {
+ cmdq_append(c, cmdq_get_error(error));
+ free(error);
}
return (0);
diff --git a/cmd-copy-mode.c b/cmd-copy-mode.c
index bdb8245e..d8b4fd3e 100644
--- a/cmd-copy-mode.c
+++ b/cmd-copy-mode.c
@@ -30,9 +30,10 @@ const struct cmd_entry cmd_copy_mode_entry = {
.name = "copy-mode",
.alias = NULL,
- .args = { "eHMt:uq", 0, 0 },
- .usage = "[-eHMuq] " CMD_TARGET_PANE_USAGE,
+ .args = { "eHMs:t:uq", 0, 0 },
+ .usage = "[-eHMuq] [-s src-pane] " CMD_TARGET_PANE_USAGE,
+ .source = { 's', CMD_FIND_PANE, 0 },
.target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK,
@@ -55,11 +56,13 @@ const struct cmd_entry cmd_clock_mode_entry = {
static enum cmd_retval
cmd_copy_mode_exec(struct cmd *self, struct cmdq_item *item)
{
- struct args *args = self->args;
- struct cmdq_shared *shared = item->shared;
- struct client *c = item->client;
+ struct args *args = cmd_get_args(self);
+ struct key_event *event = cmdq_get_event(item);
+ struct cmd_find_state *source = cmdq_get_source(item);
+ struct cmd_find_state *target = cmdq_get_target(item);
+ struct client *c = cmdq_get_client(item);
struct session *s;
- struct window_pane *wp = item->target.wp;
+ struct window_pane *wp = target->wp, *swp;
if (args_has(args, 'q')) {
window_pane_reset_mode_all(wp);
@@ -67,22 +70,26 @@ cmd_copy_mode_exec(struct cmd *self, struct cmdq_item *item)
}
if (args_has(args, 'M')) {
- if ((wp = cmd_mouse_pane(&shared->mouse, &s, NULL)) == NULL)
+ if ((wp = cmd_mouse_pane(&event->m, &s, NULL)) == NULL)
return (CMD_RETURN_NORMAL);
if (c == NULL || c->session != s)
return (CMD_RETURN_NORMAL);
}
- if (self->entry == &cmd_clock_mode_entry) {
- window_pane_set_mode(wp, &window_clock_mode, NULL, NULL);
+ if (cmd_get_entry(self) == &cmd_clock_mode_entry) {
+ window_pane_set_mode(wp, NULL, &window_clock_mode, NULL, NULL);
return (CMD_RETURN_NORMAL);
}
- if (!window_pane_set_mode(wp, &window_copy_mode, NULL, args)) {
+ if (args_has(args, 's'))
+ swp = source->wp;
+ else
+ swp = wp;
+ if (!window_pane_set_mode(wp, swp, &window_copy_mode, NULL, args)) {
if (args_has(args, 'M'))
- window_copy_start_drag(c, &shared->mouse);
+ window_copy_start_drag(c, &event->m);
}
- if (args_has(self->args, 'u'))
+ if (args_has(args, 'u'))
window_copy_pageup(wp, 0);
return (CMD_RETURN_NORMAL);
diff --git a/cmd-detach-client.c b/cmd-detach-client.c
index 85b9a4ed..02a43f4e 100644
--- a/cmd-detach-client.c
+++ b/cmd-detach-client.c
@@ -39,7 +39,7 @@ const struct cmd_entry cmd_detach_client_entry = {
.source = { 's', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
- .flags = CMD_READONLY,
+ .flags = CMD_READONLY|CMD_CLIENT_TFLAG,
.exec = cmd_detach_client_exec
};
@@ -50,24 +50,22 @@ const struct cmd_entry cmd_suspend_client_entry = {
.args = { "t:", 0, 0 },
.usage = CMD_TARGET_CLIENT_USAGE,
- .flags = 0,
+ .flags = CMD_CLIENT_TFLAG,
.exec = cmd_detach_client_exec
};
static enum cmd_retval
cmd_detach_client_exec(struct cmd *self, struct cmdq_item *item)
{
- struct args *args = self->args;
- struct client *c, *cloop;
- struct session *s;
- enum msgtype msgtype;
- const char *cmd = args_get(args, 'E');
-
- if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
- return (CMD_RETURN_ERROR);
-
- if (self->entry == &cmd_suspend_client_entry) {
- server_client_suspend(c);
+ struct args *args = cmd_get_args(self);
+ struct cmd_find_state *source = cmdq_get_source(item);
+ struct client *tc = cmdq_get_target_client(item), *loop;
+ struct session *s;
+ enum msgtype msgtype;
+ const char *cmd = args_get(args, 'E');
+
+ if (cmd_get_entry(self) == &cmd_suspend_client_entry) {
+ server_client_suspend(tc);
return (CMD_RETURN_NORMAL);
}
@@ -77,35 +75,35 @@ cmd_detach_client_exec(struct cmd *self, struct cmdq_item *item)
msgtype = MSG_DETACH;
if (args_has(args, 's')) {
- s = item->source.s;
+ s = source->s;
if (s == NULL)
return (CMD_RETURN_NORMAL);
- TAILQ_FOREACH(cloop, &clients, entry) {
- if (cloop->session == s) {
+ TAILQ_FOREACH(loop, &clients, entry) {
+ if (loop->session == s) {
if (cmd != NULL)
- server_client_exec(cloop, cmd);
+ server_client_exec(loop, cmd);
else
- server_client_detach(cloop, msgtype);
+ server_client_detach(loop, msgtype);
}
}
return (CMD_RETURN_STOP);
}
if (args_has(args, 'a')) {
- TAILQ_FOREACH(cloop, &clients, entry) {
- if (cloop->session != NULL && cloop != c) {
+ TAILQ_FOREACH(loop, &clients, entry) {
+ if (loop->session != NULL && loop != tc) {
if (cmd != NULL)
- server_client_exec(cloop, cmd);
+ server_client_exec(loop, cmd);
else
- server_client_detach(cloop, msgtype);
+ server_client_detach(loop, msgtype);
}
}
return (CMD_RETURN_NORMAL);
}
if (cmd != NULL)
- server_client_exec(c, cmd);
+ server_client_exec(tc, cmd);
else
- server_client_detach(c, msgtype);
+ server_client_detach(tc, msgtype);
return (CMD_RETURN_STOP);
}
diff --git a/cmd-display-menu.c b/cmd-display-menu.c
index ac7a4cfe..ae322444 100644
--- a/cmd-display-menu.c
+++ b/cmd-display-menu.c
@@ -29,6 +29,8 @@
static enum cmd_retval cmd_display_menu_exec(struct cmd *,
struct cmdq_item *);
+static enum cmd_retval cmd_display_popup_exec(struct cmd *,
+ struct cmdq_item *);
const struct cmd_entry cmd_display_menu_entry = {
.name = "display-menu",
@@ -40,44 +42,164 @@ const struct cmd_entry cmd_display_menu_entry = {
.target = { 't', CMD_FIND_PANE, 0 },
- .flags = CMD_AFTERHOOK,
+ .flags = CMD_AFTERHOOK|CMD_CLIENT_CFLAG,
.exec = cmd_display_menu_exec
};
+const struct cmd_entry cmd_display_popup_entry = {
+ .name = "display-popup",
+ .alias = "popup",
+
+ .args = { "CEKc:d:h:R:t:w:x:y:", 0, -1 },
+ .usage = "[-CEK] [-c target-client] [-d start-directory] [-h height] "
+ "[-R shell-command] " CMD_TARGET_PANE_USAGE " [-w width] "
+ "[-x position] [-y position] [command line ...]",
+
+ .target = { 't', CMD_FIND_PANE, 0 },
+
+ .flags = CMD_AFTERHOOK|CMD_CLIENT_CFLAG,
+ .exec = cmd_display_popup_exec
+};
+
+static void
+cmd_display_menu_get_position(struct client *tc, struct cmdq_item *item,
+ struct args *args, u_int *px, u_int *py, u_int w, u_int h)
+{
+ struct tty *tty = &tc->tty;
+ struct cmd_find_state *target = cmdq_get_target(item);
+ struct key_event *event = cmdq_get_event(item);
+ struct session *s = tc->session;
+ struct winlink *wl = target->wl;
+ struct window_pane *wp = target->wp;
+ struct style_ranges *ranges;
+ struct style_range *sr;
+ const char *xp, *yp;
+ u_int line, ox, oy, sx, sy, lines;
+
+ lines = status_line_size(tc);
+ for (line = 0; line < lines; line++) {
+ ranges = &tc->status.entries[line].ranges;
+ TAILQ_FOREACH(sr, ranges, entry) {
+ if (sr->type == STYLE_RANGE_WINDOW)
+ break;
+ }
+ if (sr != NULL)
+ break;
+ }
+ if (line == lines)
+ ranges = &tc->status.entries[0].ranges;
+
+ xp = args_get(args, 'x');
+ if (xp == NULL || strcmp(xp, "C") == 0)
+ *px = (tty->sx - 1) / 2 - w / 2;
+ else if (strcmp(xp, "R") == 0)
+ *px = tty->sx - 1;
+ else if (strcmp(xp, "P") == 0) {
+ tty_window_offset(&tc->tty, &ox, &oy, &sx, &sy);
+ if (wp->xoff >= ox)
+ *px = wp->xoff - ox;
+ else
+ *px = 0;
+ } else if (strcmp(xp, "M") == 0) {
+ if (event->m.valid && event->m.x > w / 2)
+ *px = event->m.x - w / 2;
+ else
+ *px = 0;
+ } else if (strcmp(xp, "W") == 0) {
+ if (status_at_line(tc) == -1)
+ *px = 0;
+ else {
+ TAILQ_FOREACH(sr, ranges, entry) {
+ if (sr->type != STYLE_RANGE_WINDOW)
+ continue;
+ if (sr->argument == (u_int)wl->idx)
+ break;
+ }
+ if (sr != NULL)
+ *px = sr->start;
+ else
+ *px = 0;
+ }
+ } else
+ *px = strtoul(xp, NULL, 10);
+ if ((*px) + w >= tty->sx)
+ *px = tty->sx - w;
+
+ yp = args_get(args, 'y');
+ if (yp == NULL || strcmp(yp, "C") == 0)
+ *py = (tty->sy - 1) / 2 + h / 2;
+ else if (strcmp(yp, "P") == 0) {
+ tty_window_offset(&tc->tty, &ox, &oy, &sx, &sy);
+ if (wp->yoff + wp->sy >= oy)
+ *py = wp->yoff + wp->sy - oy;
+ else
+ *py = 0;
+ } else if (strcmp(yp, "M") == 0) {
+ if (event->m.valid)
+ *py = event->m.y + h;
+ else
+ *py = 0;
+ } else if (strcmp(yp, "S") == 0) {
+ if (options_get_number(s->options, "status-position") == 0) {
+ if (lines != 0)
+ *py = lines + h;
+ else
+ *py = 0;
+ } else {
+ if (lines != 0)
+ *py = tty->sy - lines;
+ else
+ *py = tty->sy;
+ }
+ } else if (strcmp(yp, "W") == 0) {
+ if (options_get_number(s->options, "status-position") == 0) {
+ if (lines != 0)
+ *py = line + 1 + h;
+ else
+ *py = 0;
+ } else {
+ if (lines != 0)
+ *py = tty->sy - lines + line;
+ else
+ *py = tty->sy;
+ }
+ } else
+ *py = strtoul(yp, NULL, 10);
+ if (*py < h)
+ *py = 0;
+ else
+ *py -= h;
+ if ((*py) + h >= tty->sy)
+ *py = tty->sy - h;
+}
+
static enum cmd_retval
cmd_display_menu_exec(struct cmd *self, struct cmdq_item *item)
{
- struct args *args = self->args;
- struct client *c;
- struct session *s = item->target.s;
- struct winlink *wl = item->target.wl;
- struct window_pane *wp = item->target.wp;
- struct cmd_find_state *fs = &item->target;
+ struct args *args = cmd_get_args(self);
+ struct cmd_find_state *target = cmdq_get_target(item);
+ struct key_event *event = cmdq_get_event(item);
+ struct client *tc = cmdq_get_target_client(item);
struct menu *menu = NULL;
- struct style_range *sr;
struct menu_item menu_item;
- const char *xp, *yp, *key;
+ const char *key;
char *title, *name;
- int at, flags, i;
- u_int px, py, ox, oy, sx, sy;
+ int flags = 0, i;
+ u_int px, py;
- if ((c = cmd_find_client(item, args_get(args, 'c'), 0)) == NULL)
- return (CMD_RETURN_ERROR);
- if (c->overlay_draw != NULL)
+ if (tc->overlay_draw != NULL)
return (CMD_RETURN_NORMAL);
- at = status_at_line(c);
if (args_has(args, 'T'))
- title = format_single(NULL, args_get(args, 'T'), c, s, wl, wp);
+ title = format_single_from_target(item, args_get(args, 'T'));
else
title = xstrdup("");
-
menu = menu_create(title);
for (i = 0; i != args->argc; /* nothing */) {
name = args->argv[i++];
if (*name == '\0') {
- menu_add_item(menu, NULL, item, c, fs);
+ menu_add_item(menu, NULL, item, tc, target);
continue;
}
@@ -93,7 +215,7 @@ cmd_display_menu_exec(struct cmd *self, struct cmdq_item *item)
menu_item.key = key_string_lookup_string(key);
menu_item.command = args->argv[i++];
- menu_add_item(menu, &menu_item, item, c, fs);
+ menu_add_item(menu, &menu_item, item, tc, target);
}
free(title);
if (menu == NULL) {
@@ -104,75 +226,94 @@ cmd_display_menu_exec(struct cmd *self, struct cmdq_item *item)
menu_free(menu);
return (CMD_RETURN_NORMAL);
}
+ cmd_display_menu_get_position(tc, item, args, &px, &py, menu->width + 4,
+ menu->count + 2);
- xp = args_get(args, 'x');
- if (xp == NULL)
- px = 0;
- else if (strcmp(xp, "R") == 0)
- px = c->tty.sx - 1;
- else if (strcmp(xp, "P") == 0) {
- tty_window_offset(&c->tty, &ox, &oy, &sx, &sy);
- if (wp->xoff >= ox)
- px = wp->xoff - ox;
- else
- px = 0;
- } else if (strcmp(xp, "M") == 0 && item->shared->mouse.valid) {
- if (item->shared->mouse.x > (menu->width + 4) / 2)
- px = item->shared->mouse.x - (menu->width + 4) / 2;
- else
- px = 0;
+ if (!event->m.valid)
+ flags |= MENU_NOMOUSE;
+ if (menu_display(menu, flags, item, px, py, tc, target, NULL,
+ NULL) != 0)
+ return (CMD_RETURN_NORMAL);
+ return (CMD_RETURN_WAIT);
+}
+
+static enum cmd_retval
+cmd_display_popup_exec(struct cmd *self, struct cmdq_item *item)
+{
+ struct args *args = cmd_get_args(self);
+ struct cmd_find_state *target = cmdq_get_target(item);
+ struct client *tc = cmdq_get_target_client(item);
+ struct tty *tty = &tc->tty;
+ const char *value, *cmd = NULL, **lines = NULL;
+ const char *shellcmd = NULL;
+ char *cwd, *cause;
+ int flags = 0;
+ u_int px, py, w, h, nlines = 0;
+
+ if (args_has(args, 'C')) {
+ server_client_clear_overlay(tc);
+ return (CMD_RETURN_NORMAL);
}
- else if (strcmp(xp, "W") == 0) {
- if (at == -1)
- px = 0;
- else {
- TAILQ_FOREACH(sr, &c->status.entries[0].ranges, entry) {
- if (sr->type != STYLE_RANGE_WINDOW)
- continue;
- if (sr->argument == (u_int)wl->idx)
- break;
- }
- if (sr != NULL)
- px = sr->start;
- else
- px = 0;
+ if (tc->overlay_draw != NULL)
+ return (CMD_RETURN_NORMAL);
+
+ if (args->argc >= 1)
+ cmd = args->argv[0];
+ if (args->argc >= 2) {
+ lines = (const char **)args->argv + 1;
+ nlines = args->argc - 1;
+ }
+
+ if (nlines != 0)
+ h = popup_height(nlines, lines) + 2;
+ else
+ h = tty->sy / 2;
+ if (args_has(args, 'h')) {
+ h = args_percentage(args, 'h', 1, tty->sy, tty->sy, &cause);
+ if (cause != NULL) {
+ cmdq_error(item, "height %s", cause);
+ free(cause);
+ return (CMD_RETURN_ERROR);
}
- } else
- px = strtoul(xp, NULL, 10);
- if (px + menu->width + 4 >= c->tty.sx)
- px = c->tty.sx - menu->width - 4;
+ }
- yp = args_get(args, 'y');
- if (yp == NULL)
- py = 0;
- else if (strcmp(yp, "P") == 0) {
- tty_window_offset(&c->tty, &ox, &oy, &sx, &sy);
- if (wp->yoff + wp->sy >= oy)
- py = wp->yoff + wp->sy - oy;
- else
- py = 0;
- } else if (strcmp(yp, "M") == 0 && item->shared->mouse.valid)
- py = item->shared->mouse.y + menu->count + 2;
- else if (strcmp(yp, "S") == 0) {
- if (at == -1)
- py = c->tty.sy;
- else if (at == 0)
- py = status_line_size(c) + menu->count + 2;
- else
- py = at;
- } else
- py = strtoul(yp, NULL, 10);
- if (py < menu->count + 2)
- py = 0;
+ if (nlines != 0)
+ w = popup_width(item, nlines, lines, tc, target) + 2;
else
- py -= menu->count + 2;
- if (py + menu->count + 2 >= c->tty.sy)
- py = c->tty.sy - menu->count - 2;
+ w = tty->sx / 2;
+ if (args_has(args, 'w')) {
+ w = args_percentage(args, 'w', 1, tty->sx, tty->sx, &cause);
+ if (cause != NULL) {
+ cmdq_error(item, "width %s", cause);
+ free(cause);
+ return (CMD_RETURN_ERROR);
+ }
+ }
- flags = 0;
- if (!item->shared->mouse.valid)
- flags |= MENU_NOMOUSE;
- if (menu_display(menu, flags, item, px, py, c, fs, NULL, NULL) != 0)
+ if (w > tty->sx - 1)
+ w = tty->sx - 1;
+ if (h > tty->sy - 1)
+ h = tty->sy - 1;
+ cmd_display_menu_get_position(tc, item, args, &px, &py, w, h);
+
+ value = args_get(args, 'd');
+ if (value != NULL)
+ cwd = format_single_from_target(item, value);
+ else
+ cwd = xstrdup(server_client_get_cwd(tc, target->s));
+
+ value = args_get(args, 'R');
+ if (value != NULL)
+ shellcmd = format_single_from_target(item, value);
+
+ if (args_has(args, 'K'))
+ flags |= POPUP_WRITEKEYS;
+ if (args_has(args, 'E') > 1)
+ flags |= POPUP_CLOSEEXITZERO;
+ else if (args_has(args, 'E'))
+ flags |= POPUP_CLOSEEXIT;
+ if (popup_display(flags, item, px, py, w, h, nlines, lines, shellcmd,
+ cmd, cwd, tc, target, NULL, NULL) != 0)
return (CMD_RETURN_NORMAL);
return (CMD_RETURN_WAIT);
}
diff --git a/cmd-display-message.c b/cmd-display-message.c
index 4d9bccb6..4e69f03a 100644
--- a/cmd-display-message.c
+++ b/cmd-display-message.c
@@ -45,7 +45,7 @@ const struct cmd_entry cmd_display_message_entry = {
.target = { 't', CMD_FIND_PANE, 0 },
- .flags = CMD_AFTERHOOK,
+ .flags = CMD_AFTERHOOK|CMD_CLIENT_CFLAG|CMD_CLIENT_CANFAIL,
.exec = cmd_display_message_exec
};
@@ -60,11 +60,12 @@ cmd_display_message_each(const char *key, const char *value, void *arg)
static enum cmd_retval
cmd_display_message_exec(struct cmd *self, struct cmdq_item *item)
{
- struct args *args = self->args;
- struct client *c, *target_c;
- struct session *s = item->target.s;
- struct winlink *wl = item->target.wl;
- struct window_pane *wp = item->target.wp;
+ struct args *args = cmd_get_args(self);
+ struct cmd_find_state *target = cmdq_get_target(item);
+ struct client *tc = cmdq_get_target_client(item), *c;
+ struct session *s = target->s;
+ struct winlink *wl = target->wl;
+ struct window_pane *wp = target->wp;
const char *template;
char *msg, *cause;
struct format_tree *ft;
@@ -96,17 +97,16 @@ cmd_display_message_exec(struct cmd *self, struct cmdq_item *item)
* formats too, assuming it matches the session. If it doesn't, use the
* best client for the session.
*/
- c = cmd_find_client(item, args_get(args, 'c'), 1);
- if (c != NULL && c->session == s)
- target_c = c;
+ if (tc != NULL && tc->session == s)
+ c = tc;
else
- target_c = cmd_find_best_client(s);
- if (args_has(self->args, 'v'))
+ c = cmd_find_best_client(s);
+ if (args_has(args, 'v'))
flags = FORMAT_VERBOSE;
else
flags = 0;
- ft = format_create(item->client, item, FORMAT_NONE, flags);
- format_defaults(ft, target_c, s, wl, wp);
+ ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, flags);
+ format_defaults(ft, c, s, wl, wp);
if (args_has(args, 'a')) {
format_each(ft, cmd_display_message_each, item);
@@ -114,10 +114,10 @@ cmd_display_message_exec(struct cmd *self, struct cmdq_item *item)
}
msg = format_expand_time(ft, template);
- if (args_has(self->args, 'p'))
+ if (args_has(args, 'p'))
cmdq_print(item, "%s", msg);
- else if (c != NULL)
- status_message_set(c, "%s", msg);
+ else if (tc != NULL)
+ status_message_set(tc, "%s", msg);
free(msg);
format_free(ft);
diff --git a/cmd-display-panes.c b/cmd-display-panes.c
index df97819c..a13a06ae 100644
--- a/cmd-display-panes.c
+++ b/cmd-display-panes.c
@@ -37,7 +37,7 @@ const struct cmd_entry cmd_display_panes_entry = {
.args = { "bd:t:", 0, 1 },
.usage = "[-b] [-d duration] " CMD_TARGET_CLIENT_USAGE " [template]",
- .flags = CMD_AFTERHOOK,
+ .flags = CMD_AFTERHOOK|CMD_CLIENT_TFLAG,
.exec = cmd_display_panes_exec
};
@@ -131,9 +131,7 @@ cmd_display_panes_draw_pane(struct screen_redraw_ctx *ctx,
gc.bg = active_colour;
else
gc.bg = colour;
- gc.flags |= GRID_FLAG_NOPALETTE;
-
- tty_attributes(tty, &gc, wp);
+ tty_attributes(tty, &gc, &grid_default_cell, NULL);
for (ptr = buf; *ptr != '\0'; ptr++) {
if (*ptr < '0' || *ptr > '9')
continue;
@@ -160,9 +158,7 @@ draw_text:
gc.fg = active_colour;
else
gc.fg = colour;
- gc.flags |= GRID_FLAG_NOPALETTE;
-
- tty_attributes(tty, &gc, wp);
+ tty_attributes(tty, &gc, &grid_default_cell, NULL);
tty_puts(tty, buf);
tty_cursor(tty, 0, 0);
@@ -197,11 +193,10 @@ static int
cmd_display_panes_key(struct client *c, struct key_event *event)
{
struct cmd_display_panes_data *cdata = c->overlay_data;
- struct cmdq_item *new_item;
- char *cmd, *expanded;
+ char *cmd, *expanded, *error;
struct window *w = c->session->curw->window;
struct window_pane *wp;
- struct cmd_parse_result *pr;
+ enum cmd_parse_status status;
if (event->key < '0' || event->key > '9')
return (-1);
@@ -214,21 +209,10 @@ cmd_display_panes_key(struct client *c, struct key_event *event)
xasprintf(&expanded, "%%%u", wp->id);
cmd = cmd_template_replace(cdata->command, expanded, 1);
- pr = cmd_parse_from_string(cmd, NULL);
- switch (pr->status) {
- case CMD_PARSE_EMPTY:
- new_item = NULL;
- break;
- case CMD_PARSE_ERROR:
- new_item = cmdq_get_error(pr->error);
- free(pr->error);
- cmdq_append(c, new_item);
- break;
- case CMD_PARSE_SUCCESS:
- new_item = cmdq_get_command(pr->cmdlist, NULL, NULL, 0);
- cmd_list_free(pr->cmdlist);
- cmdq_append(c, new_item);
- break;
+ status = cmd_parse_and_append(cmd, NULL, c, NULL, &error);
+ if (status == CMD_PARSE_ERROR) {
+ cmdq_append(c, cmdq_get_error(error));
+ free(error);
}
free(cmd);
@@ -239,18 +223,14 @@ cmd_display_panes_key(struct client *c, struct key_event *event)
static enum cmd_retval
cmd_display_panes_exec(struct cmd *self, struct cmdq_item *item)
{
- struct args *args = self->args;
- struct client *c;
- struct session *s;
+ struct args *args = cmd_get_args(self);
+ struct client *tc = cmdq_get_target_client(item);
+ struct session *s = tc->session;
u_int delay;
char *cause;
struct cmd_display_panes_data *cdata;
- if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
- return (CMD_RETURN_ERROR);
- s = c->session;
-
- if (c->overlay_draw != NULL)
+ if (tc->overlay_draw != NULL)
return (CMD_RETURN_NORMAL);
if (args_has(args, 'd')) {
@@ -273,7 +253,7 @@ cmd_display_panes_exec(struct cmd *self, struct cmdq_item *item)
else
cdata->item = item;
- server_client_set_overlay(c, delay, cmd_display_panes_draw,
+ server_client_set_overlay(tc, delay, NULL, NULL, cmd_display_panes_draw,
cmd_display_panes_key, cmd_display_panes_free, cdata);
if (args_has(args, 'b'))
diff --git a/cmd-find-window.c b/cmd-find-window.c
index c29878b5..e1faeb2f 100644
--- a/cmd-find-window.c
+++ b/cmd-find-window.c
@@ -44,8 +44,9 @@ const struct cmd_entry cmd_find_window_entry = {
static enum cmd_retval
cmd_find_window_exec(struct cmd *self, struct cmdq_item *item)
{
- struct args *args = self->args, *new_args;
- struct window_pane *wp = item->target.wp;
+ struct args *args = cmd_get_args(self), *new_args;
+ struct cmd_find_state *target = cmdq_get_target(item);
+ struct window_pane *wp = target->wp;
const char *s = args->argv[0];
char *filter, *argv = { NULL };
int C, N, T;
@@ -116,7 +117,7 @@ cmd_find_window_exec(struct cmd *self, struct cmdq_item *item)
args_set(new_args, 'Z', NULL);
args_set(new_args, 'f', filter);
- window_pane_set_mode(wp, &window_tree_mode, &item->target, new_args);
+ window_pane_set_mode(wp, NULL, &window_tree_mode, target, new_args);
args_free(new_args);
free(filter);
diff --git a/cmd-find.c b/cmd-find.c
index 154842ab..e70eb606 100644
--- a/cmd-find.c
+++ b/cmd-find.c
@@ -960,10 +960,11 @@ cmd_find_target(struct cmd_find_state *fs, struct cmdq_item *item,
if (server_check_marked() && (flags & CMD_FIND_DEFAULT_MARKED)) {
fs->current = &marked_pane;
log_debug("%s: current is marked pane", __func__);
- } else if (cmd_find_valid_state(&item->shared->current)) {
- fs->current = &item->shared->current;
+ } else if (cmd_find_valid_state(cmdq_get_current(item))) {
+ fs->current = cmdq_get_current(item);
log_debug("%s: current is from queue", __func__);
- } else if (cmd_find_from_client(&current, item->client, flags) == 0) {
+ } else if (cmd_find_from_client(&current, cmdq_get_client(item),
+ flags) == 0) {
fs->current = &current;
log_debug("%s: current is from client", __func__);
} else {
@@ -980,7 +981,7 @@ cmd_find_target(struct cmd_find_state *fs, struct cmdq_item *item,
/* Mouse target is a plain = or {mouse}. */
if (strcmp(target, "=") == 0 || strcmp(target, "{mouse}") == 0) {
- m = &item->shared->mouse;
+ m = &cmdq_get_event(item)->m;
switch (type) {
case CMD_FIND_PANE:
fs->wp = cmd_mouse_pane(m, &fs->s, &fs->wl);
@@ -1230,29 +1231,31 @@ no_pane:
static struct client *
cmd_find_current_client(struct cmdq_item *item, int quiet)
{
- struct client *c;
+ struct client *c = NULL, *found;
struct session *s;
struct window_pane *wp;
struct cmd_find_state fs;
- if (item->client != NULL && item->client->session != NULL)
- return (item->client);
+ if (item != NULL)
+ c = cmdq_get_client(item);
+ if (c != NULL && c->session != NULL)
+ return (c);
- c = NULL;
- if ((wp = cmd_find_inside_pane(item->client)) != NULL) {
+ found = NULL;
+ if (c != NULL && (wp = cmd_find_inside_pane(c)) != NULL) {
cmd_find_clear_state(&fs, CMD_FIND_QUIET);
fs.w = wp->window;
if (cmd_find_best_session_with_window(&fs) == 0)
- c = cmd_find_best_client(fs.s);
+ found = cmd_find_best_client(fs.s);
} else {
s = cmd_find_best_session(NULL, 0, CMD_FIND_QUIET);
if (s != NULL)
- c = cmd_find_best_client(s);
+ found = cmd_find_best_client(s);
}
- if (c == NULL && !quiet)
+ if (found == NULL && item != NULL && !quiet)
cmdq_error(item, "no current client");
- log_debug("%s: no target, return %p", __func__, c);
- return (c);
+ log_debug("%s: no target, return %p", __func__, found);
+ return (found);
}
/* Find the target client or report an error and return NULL. */
diff --git a/cmd-if-shell.c b/cmd-if-shell.c
index 2befbc0c..d980472a 100644
--- a/cmd-if-shell.c
+++ b/cmd-if-shell.c
@@ -56,26 +56,23 @@ struct cmd_if_shell_data {
struct client *client;
struct cmdq_item *item;
- struct mouse_event mouse;
};
static enum cmd_retval
cmd_if_shell_exec(struct cmd *self, struct cmdq_item *item)
{
- struct args *args = self->args;
- struct mouse_event *m = &item->shared->mouse;
+ struct args *args = cmd_get_args(self);
+ struct cmd_find_state *target = cmdq_get_target(item);
+ struct cmdq_state *state = cmdq_get_state(item);
struct cmd_if_shell_data *cdata;
- char *shellcmd, *cmd;
- struct cmdq_item *new_item;
- struct cmd_find_state *fs = &item->target;
- struct client *c = cmd_find_client(item, NULL, 1);
- struct session *s = fs->s;
- struct winlink *wl = fs->wl;
- struct window_pane *wp = fs->wp;
+ char *shellcmd, *cmd, *error;
+ const char *file;
+ struct client *tc = cmdq_get_target_client(item);
+ struct session *s = target->s;
struct cmd_parse_input pi;
- struct cmd_parse_result *pr;
+ enum cmd_parse_status status;
- shellcmd = format_single(item, args->argv[0], c, s, wl, wp);
+ shellcmd = format_single_from_target(item, args->argv[0]);
if (args_has(args, 'F')) {
if (*shellcmd != '0' && *shellcmd != '\0')
cmd = args->argv[1];
@@ -88,26 +85,16 @@ cmd_if_shell_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_NORMAL);
memset(&pi, 0, sizeof pi);
- if (self->file != NULL)
- pi.file = self->file;
- pi.line = self->line;
+ cmd_get_source(self, &pi.file, &pi.line);
pi.item = item;
- pi.c = c;
- cmd_find_copy_state(&pi.fs, fs);
-
- pr = cmd_parse_from_string(cmd, &pi);
- switch (pr->status) {
- case CMD_PARSE_EMPTY:
- break;
- case CMD_PARSE_ERROR:
- cmdq_error(item, "%s", pr->error);
- free(pr->error);
+ pi.c = tc;
+ cmd_find_copy_state(&pi.fs, target);
+
+ status = cmd_parse_and_insert(cmd, &pi, item, state, &error);
+ if (status == CMD_PARSE_ERROR) {
+ cmdq_error(item, "%s", error);
+ free(error);
return (CMD_RETURN_ERROR);
- case CMD_PARSE_SUCCESS:
- new_item = cmdq_get_command(pr->cmdlist, fs, m, 0);
- cmdq_insert_after(item, new_item);
- cmd_list_free(pr->cmdlist);
- break;
}
return (CMD_RETURN_NORMAL);
}
@@ -119,12 +106,11 @@ cmd_if_shell_exec(struct cmd *self, struct cmdq_item *item)
cdata->cmd_else = xstrdup(args->argv[2]);
else
cdata->cmd_else = NULL;
- memcpy(&cdata->mouse, m, sizeof cdata->mouse);
if (!args_has(args, 'b'))
- cdata->client = item->client;
+ cdata->client = cmdq_get_client(item);
else
- cdata->client = c;
+ cdata->client = tc;
if (cdata->client != NULL)
cdata->client->references++;
@@ -134,17 +120,18 @@ cmd_if_shell_exec(struct cmd *self, struct cmdq_item *item)
cdata->item = NULL;
memset(&cdata->input, 0, sizeof cdata->input);
- if (self->file != NULL)
- cdata->input.file = xstrdup(self->file);
- cdata->input.line = self->line;
- cdata->input.item = cdata->item;
- cdata->input.c = c;
+ cmd_get_source(self, &file, &cdata->input.line);
+ if (file != NULL)
+ cdata->input.file = xstrdup(file);
+ cdata->input.c = tc;
if (cdata->input.c != NULL)
cdata->input.c->references++;
- cmd_find_copy_state(&cdata->input.fs, fs);
+ cmd_find_copy_state(&cdata->input.fs, target);
- if (job_run(shellcmd, s, server_client_get_cwd(item->client, s), NULL,
- cmd_if_shell_callback, cmd_if_shell_free, cdata, 0) == NULL) {
+ if (job_run(shellcmd, s,
+ server_client_get_cwd(cmdq_get_client(item), s), NULL,
+ cmd_if_shell_callback, cmd_if_shell_free, cdata, 0, -1,
+ -1) == NULL) {
cmdq_error(item, "failed to run command: %s", shellcmd);
free(shellcmd);
free(cdata);
@@ -162,8 +149,8 @@ cmd_if_shell_callback(struct job *job)
{
struct cmd_if_shell_data *cdata = job_get_data(job);
struct client *c = cdata->client;
- struct mouse_event *m = &cdata->mouse;
struct cmdq_item *new_item = NULL;
+ struct cmdq_state *new_state = NULL;
char *cmd;
int status;
struct cmd_parse_result *pr;
@@ -186,7 +173,13 @@ cmd_if_shell_callback(struct job *job)
free(pr->error);
break;
case CMD_PARSE_SUCCESS:
- new_item = cmdq_get_command(pr->cmdlist, NULL, m, 0);
+ if (cdata->item == NULL)
+ new_state = cmdq_new_state(NULL, NULL, 0);
+ else
+ new_state = cmdq_get_state(cdata->item);
+ new_item = cmdq_get_command(pr->cmdlist, new_state);
+ if (cdata->item == NULL)
+ cmdq_free_state(new_state);
cmd_list_free(pr->cmdlist);
break;
}
diff --git a/cmd-join-pane.c b/cmd-join-pane.c
index 4b767e3e..2e4bec50 100644
--- a/cmd-join-pane.c
+++ b/cmd-join-pane.c
@@ -49,8 +49,8 @@ const struct cmd_entry cmd_move_pane_entry = {
.name = "move-pane",
.alias = "movep",
- .args = { "bdhvp:l:s:t:", 0, 0 },
- .usage = "[-bdhv] [-p percentage|-l size] " CMD_SRCDST_PANE_USAGE,
+ .args = { "bdfhvp:l:s:t:", 0, 0 },
+ .usage = "[-bdfhv] [-l size] " CMD_SRCDST_PANE_USAGE,
.source = { 's', CMD_FIND_PANE, CMD_FIND_DEFAULT_MARKED },
.target = { 't', CMD_FIND_PANE, 0 },
@@ -62,42 +62,33 @@ const struct cmd_entry cmd_move_pane_entry = {
static enum cmd_retval
cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
{
- struct args *args = self->args;
- struct cmd_find_state *current = &item->shared->current;
+ struct args *args = cmd_get_args(self);
+ struct cmd_find_state *current = cmdq_get_current(item);
+ struct cmd_find_state *target = cmdq_get_target(item);
+ struct cmd_find_state *source = cmdq_get_source(item);
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, *copy;
- const char *errstr, *p;
- size_t plen;
- int size, percentage, dst_idx, not_same_window;
+ char *cause = NULL;
+ int size, percentage, dst_idx;
int flags;
enum layout_type type;
struct layout_cell *lc;
- if (self->entry == &cmd_join_pane_entry)
- not_same_window = 1;
- else
- not_same_window = 0;
-
- dst_s = item->target.s;
- dst_wl = item->target.wl;
- dst_wp = item->target.wp;
+ dst_s = target->s;
+ dst_wl = target->wl;
+ dst_wp = target->wp;
dst_w = dst_wl->window;
dst_idx = dst_wl->idx;
server_unzoom_window(dst_w);
- src_wl = item->source.wl;
- src_wp = item->source.wp;
+ src_wl = source->wl;
+ src_wp = source->wp;
src_w = src_wl->window;
server_unzoom_window(src_w);
- if (not_same_window && src_w == dst_w) {
- cmdq_error(item, "can't join a pane to its own window");
- return (CMD_RETURN_ERROR);
- }
- if (!not_same_window && src_wp == dst_wp) {
+ if (src_wp == dst_wp) {
cmdq_error(item, "source and target panes must be different");
return (CMD_RETURN_ERROR);
}
@@ -107,40 +98,27 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
type = LAYOUT_LEFTRIGHT;
size = -1;
- if ((p = args_get(args, 'l')) != NULL) {
- plen = strlen(p);
- if (p[plen - 1] == '%') {
- copy = xstrdup(p);
- copy[plen - 1] = '\0';
- percentage = strtonum(copy, 0, INT_MAX, &errstr);
- free(copy);
- if (errstr != NULL) {
- cmdq_error(item, "percentage %s", errstr);
- return (CMD_RETURN_ERROR);
- }
- if (type == LAYOUT_TOPBOTTOM)
- size = (dst_wp->sy * percentage) / 100;
- else
- size = (dst_wp->sx * percentage) / 100;
+ if (args_has(args, 'l')) {
+ if (type == LAYOUT_TOPBOTTOM) {
+ size = args_percentage(args, 'l', 0, INT_MAX,
+ dst_wp->sy, &cause);
} else {
- size = args_strtonum(args, 'l', 0, INT_MAX, &cause);
- if (cause != NULL) {
- cmdq_error(item, "size %s", cause);
- free(cause);
- return (CMD_RETURN_ERROR);
- }
+ size = args_percentage(args, 'l', 0, INT_MAX,
+ dst_wp->sx, &cause);
}
} else if (args_has(args, 'p')) {
percentage = args_strtonum(args, 'p', 0, 100, &cause);
- if (cause != NULL) {
- cmdq_error(item, "percentage %s", cause);
- free(cause);
- return (CMD_RETURN_ERROR);
+ if (cause == NULL) {
+ if (type == LAYOUT_TOPBOTTOM)
+ size = (dst_wp->sy * percentage) / 100;
+ else
+ size = (dst_wp->sx * percentage) / 100;
}
- if (type == LAYOUT_TOPBOTTOM)
- size = (dst_wp->sy * percentage) / 100;
- else
- size = (dst_wp->sx * percentage) / 100;
+ }
+ if (cause != NULL) {
+ cmdq_error(item, "size %s", cause);
+ free(cause);
+ return (CMD_RETURN_ERROR);
}
flags = 0;
diff --git a/cmd-kill-pane.c b/cmd-kill-pane.c
index f0aacb2a..2302d7bb 100644
--- a/cmd-kill-pane.c
+++ b/cmd-kill-pane.c
@@ -44,10 +44,12 @@ const struct cmd_entry cmd_kill_pane_entry = {
static enum cmd_retval
cmd_kill_pane_exec(struct cmd *self, struct cmdq_item *item)
{
- struct winlink *wl = item->target.wl;
- struct window_pane *loopwp, *tmpwp, *wp = item->target.wp;
+ struct args *args = cmd_get_args(self);
+ struct cmd_find_state *target = cmdq_get_target(item);
+ struct winlink *wl = target->wl;
+ struct window_pane *loopwp, *tmpwp, *wp = target->wp;
- if (args_has(self->args, 'a')) {
+ if (args_has(args, 'a')) {
server_unzoom_window(wl->window);
TAILQ_FOREACH_SAFE(loopwp, &wl->window->panes, entry, tmpwp) {
if (loopwp == wp)
diff --git a/cmd-kill-server.c b/cmd-kill-server.c
index d7eba692..76bcf267 100644
--- a/cmd-kill-server.c
+++ b/cmd-kill-server.c
@@ -54,7 +54,7 @@ const struct cmd_entry cmd_start_server_entry = {
static enum cmd_retval
cmd_kill_server_exec(struct cmd *self, __unused struct cmdq_item *item)
{
- if (self->entry == &cmd_kill_server_entry)
+ if (cmd_get_entry(self) == &cmd_kill_server_entry)
kill(getpid(), SIGTERM);
return (CMD_RETURN_NORMAL);
diff --git a/cmd-kill-session.c b/cmd-kill-session.c
index dcef8097..c10efba6 100644
--- a/cmd-kill-session.c
+++ b/cmd-kill-session.c
@@ -45,11 +45,10 @@ const struct cmd_entry cmd_kill_session_entry = {
static enum cmd_retval
cmd_kill_session_exec(struct cmd *self, struct cmdq_item *item)
{
- struct args *args = self->args;
- struct session *s, *sloop, *stmp;
- struct winlink *wl;
-
- s = item->target.s;
+ struct args *args = cmd_get_args(self);
+ struct cmd_find_state *target = cmdq_get_target(item);
+ struct session *s = target->s, *sloop, *stmp;
+ struct winlink *wl;
if (args_has(args, 'C')) {
RB_FOREACH(wl, winlinks, &s->windows) {
diff --git a/cmd-kill-window.c b/cmd-kill-window.c
index 50df83ee..68139faa 100644
--- a/cmd-kill-window.c
+++ b/cmd-kill-window.c
@@ -55,13 +55,14 @@ const struct cmd_entry cmd_unlink_window_entry = {
static enum cmd_retval
cmd_kill_window_exec(struct cmd *self, struct cmdq_item *item)
{
- struct args *args = self->args;
- struct winlink *wl = item->target.wl, *wl2, *wl3;
+ struct args *args = cmd_get_args(self);
+ struct cmd_find_state *target = cmdq_get_target(item);
+ struct winlink *wl = target->wl, *wl2, *wl3;
struct window *w = wl->window;
- struct session *s = item->target.s;
+ struct session *s = target->s;
- if (self->entry == &cmd_unlink_window_entry) {
- if (!args_has(self->args, 'k') && !session_is_linked(s, w)) {
+ if (cmd_get_entry(self) == &cmd_unlink_window_entry) {
+ if (!args_has(args, 'k') && !session_is_linked(s, w)) {
cmdq_error(item, "window only linked to one session");
return (CMD_RETURN_ERROR);
}
diff --git a/cmd-list-buffers.c b/cmd-list-buffers.c
index 0457a62d..45d5a4ee 100644
--- a/cmd-list-buffers.c
+++ b/cmd-list-buffers.c
@@ -36,8 +36,8 @@ const struct cmd_entry cmd_list_buffers_entry = {
.name = "list-buffers",
.alias = "lsb",
- .args = { "F:", 0, 0 },
- .usage = "[-F format]",
+ .args = { "F:f:", 0, 0 },
+ .usage = "[-F format] [-f filter]",
.flags = CMD_AFTERHOOK,
.exec = cmd_list_buffers_exec
@@ -46,23 +46,33 @@ const struct cmd_entry cmd_list_buffers_entry = {
static enum cmd_retval
cmd_list_buffers_exec(struct cmd *self, struct cmdq_item *item)
{
- struct args *args = self->args;
+ struct args *args = cmd_get_args(self);
struct paste_buffer *pb;
struct format_tree *ft;
- char *line;
- const char *template;
+ const char *template, *filter;
+ char *line, *expanded;
+ int flag;
if ((template = args_get(args, 'F')) == NULL)
template = LIST_BUFFERS_TEMPLATE;
+ filter = args_get(args, 'f');
pb = NULL;
while ((pb = paste_walk(pb)) != NULL) {
- ft = format_create(item->client, item, FORMAT_NONE, 0);
+ ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0);
format_defaults_paste_buffer(ft, pb);
- line = format_expand(ft, template);
- cmdq_print(item, "%s", line);
- free(line);
+ if (filter != NULL) {
+ expanded = format_expand(ft, filter);
+ flag = format_true(expanded);
+ free(expanded);
+ } else
+ flag = 1;
+ if (flag) {
+ line = format_expand(ft, template);
+ cmdq_print(item, "%s", line);
+ free(line);
+ }
format_free(ft);
}
diff --git a/cmd-list-clients.c b/cmd-list-clients.c
index 9fab8f84..75118c8e 100644
--- a/cmd-list-clients.c
+++ b/cmd-list-clients.c
@@ -51,7 +51,8 @@ const struct cmd_entry cmd_list_clients_entry = {
static enum cmd_retval
cmd_list_clients_exec(struct cmd *self, struct cmdq_item *item)
{
- struct args *args = self->args;
+ struct args *args = cmd_get_args(self);
+ struct cmd_find_state *target = cmdq_get_target(item);
struct client *c;
struct session *s;
struct format_tree *ft;
@@ -60,7 +61,7 @@ cmd_list_clients_exec(struct cmd *self, struct cmdq_item *item)
char *line;
if (args_has(args, 't'))
- s = item->target.s;
+ s = target->s;
else
s = NULL;
@@ -72,7 +73,7 @@ cmd_list_clients_exec(struct cmd *self, struct cmdq_item *item)
if (c->session == NULL || (s != NULL && s != c->session))
continue;
- ft = format_create(item->client, item, FORMAT_NONE, 0);
+ ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0);
format_add(ft, "line", "%u", idx);
format_defaults(ft, c, NULL, NULL, NULL);
diff --git a/cmd-list-keys.c b/cmd-list-keys.c
index 7e340516..1141bbb5 100644
--- a/cmd-list-keys.c
+++ b/cmd-list-keys.c
@@ -85,7 +85,7 @@ static int
cmd_list_keys_print_notes(struct cmdq_item *item, struct args *args,
const char *tablename, u_int keywidth, key_code only, const char *prefix)
{
- struct client *c = cmd_find_client(item, NULL, 1);
+ struct client *tc = cmdq_get_target_client(item);
struct key_table *table;
struct key_binding *bd;
const char *key;
@@ -111,8 +111,8 @@ cmd_list_keys_print_notes(struct cmdq_item *item, struct args *args,
else
note = xstrdup(bd->note);
tmp = utf8_padcstr(key, keywidth + 1);
- if (args_has(args, '1') && c != NULL)
- status_message_set(c, "%s%s%s", prefix, tmp, note);
+ if (args_has(args, '1') && tc != NULL)
+ status_message_set(tc, "%s%s%s", prefix, tmp, note);
else
cmdq_print(item, "%s%s%s", prefix, tmp, note);
free(tmp);
@@ -144,7 +144,7 @@ cmd_list_keys_get_prefix(struct args *args, key_code *prefix)
static enum cmd_retval
cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
{
- struct args *args = self->args;
+ struct args *args = cmd_get_args(self);
struct key_table *table;
struct key_binding *bd;
const char *tablename, *r;
@@ -153,7 +153,7 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
int repeat, width, tablewidth, keywidth, found = 0;
size_t tmpsize, tmpused, cplen;
- if (self->entry == &cmd_list_commands_entry)
+ if (cmd_get_entry(self) == &cmd_list_commands_entry)
return (cmd_list_keys_commands(self, item));
if (args->argc != 0) {
@@ -269,7 +269,7 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
tmpsize *= 2;
tmp = xrealloc(tmp, tmpsize);
}
- tmpused = strlcat(tmp, cp, tmpsize);
+ strlcat(tmp, cp, tmpsize);
tmpused = strlcat(tmp, " ", tmpsize);
free(cp);
@@ -279,7 +279,7 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
tmpsize *= 2;
tmp = xrealloc(tmp, tmpsize);
}
- tmpused = strlcat(tmp, cp, tmpsize);
+ strlcat(tmp, cp, tmpsize);
tmpused = strlcat(tmp, " ", tmpsize);
free(cp);
@@ -313,7 +313,7 @@ out:
static enum cmd_retval
cmd_list_keys_commands(struct cmd *self, struct cmdq_item *item)
{
- struct args *args = self->args;
+ struct args *args = cmd_get_args(self);
const struct cmd_entry **entryp;
const struct cmd_entry *entry;
struct format_tree *ft;
@@ -329,7 +329,7 @@ cmd_list_keys_commands(struct cmd *self, struct cmdq_item *item)
"#{command_list_usage}";
}
- ft = format_create(item->client, item, FORMAT_NONE, 0);
+ ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0);
format_defaults(ft, NULL, NULL, NULL, NULL);
for (entryp = cmd_table; *entryp != NULL; entryp++) {
diff --git a/cmd-list-panes.c b/cmd-list-panes.c
index 7f6994bd..c6dcff23 100644
--- a/cmd-list-panes.c
+++ b/cmd-list-panes.c
@@ -38,8 +38,8 @@ const struct cmd_entry cmd_list_panes_entry = {
.name = "list-panes",
.alias = "lsp",
- .args = { "asF:t:", 0, 0 },
- .usage = "[-as] [-F format] " CMD_TARGET_WINDOW_USAGE,
+ .args = { "asF:f:t:", 0, 0 },
+ .usage = "[-as] [-F format] [-f filter] " CMD_TARGET_WINDOW_USAGE,
.target = { 't', CMD_FIND_WINDOW, 0 },
@@ -50,9 +50,10 @@ const struct cmd_entry cmd_list_panes_entry = {
static enum cmd_retval
cmd_list_panes_exec(struct cmd *self, struct cmdq_item *item)
{
- struct args *args = self->args;
- struct session *s = item->target.s;
- struct winlink *wl = item->target.wl;
+ struct args *args = cmd_get_args(self);
+ struct cmd_find_state *target = cmdq_get_target(item);
+ struct session *s = target->s;
+ struct winlink *wl = target->wl;
if (args_has(args, 'a'))
cmd_list_panes_server(self, item);
@@ -87,12 +88,13 @@ static void
cmd_list_panes_window(struct cmd *self, struct session *s, struct winlink *wl,
struct cmdq_item *item, int type)
{
- struct args *args = self->args;
+ struct args *args = cmd_get_args(self);
struct window_pane *wp;
u_int n;
struct format_tree *ft;
- const char *template;
- char *line;
+ const char *template, *filter;
+ char *line, *expanded;
+ int flag;
template = args_get(args, 'F');
if (template == NULL) {
@@ -120,16 +122,25 @@ cmd_list_panes_window(struct cmd *self, struct session *s, struct winlink *wl,
break;
}
}
+ filter = args_get(args, 'f');
n = 0;
TAILQ_FOREACH(wp, &wl->window->panes, entry) {
- ft = format_create(item->client, item, FORMAT_NONE, 0);
+ ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0);
format_add(ft, "line", "%u", n);
format_defaults(ft, NULL, s, wl, wp);
- line = format_expand(ft, template);
- cmdq_print(item, "%s", line);
- free(line);
+ if (filter != NULL) {
+ expanded = format_expand(ft, filter);
+ flag = format_true(expanded);
+ free(expanded);
+ } else
+ flag = 1;
+ if (flag) {
+ line = format_expand(ft, template);
+ cmdq_print(item, "%s", line);
+ free(line);
+ }
format_free(ft);
n++;
diff --git a/cmd-list-sessions.c b/cmd-list-sessions.c
index 72ff47e8..fbc3db1d 100644
--- a/cmd-list-sessions.c
+++ b/cmd-list-sessions.c
@@ -42,8 +42,8 @@ const struct cmd_entry cmd_list_sessions_entry = {
.name = "list-sessions",
.alias = "ls",
- .args = { "F:", 0, 0 },
- .usage = "[-F format]",
+ .args = { "F:f:", 0, 0 },
+ .usage = "[-F format] [-f filter]",
.flags = CMD_AFTERHOOK,
.exec = cmd_list_sessions_exec
@@ -52,25 +52,35 @@ const struct cmd_entry cmd_list_sessions_entry = {
static enum cmd_retval
cmd_list_sessions_exec(struct cmd *self, struct cmdq_item *item)
{
- struct args *args = self->args;
+ struct args *args = cmd_get_args(self);
struct session *s;
u_int n;
struct format_tree *ft;
- const char *template;
- char *line;
+ const char *template, *filter;
+ char *line, *expanded;
+ int flag;
if ((template = args_get(args, 'F')) == NULL)
template = LIST_SESSIONS_TEMPLATE;
+ filter = args_get(args, 'f');
n = 0;
RB_FOREACH(s, sessions, &sessions) {
- ft = format_create(item->client, item, FORMAT_NONE, 0);
+ ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0);
format_add(ft, "line", "%u", n);
format_defaults(ft, NULL, s, NULL, NULL);
- line = format_expand(ft, template);
- cmdq_print(item, "%s", line);
- free(line);
+ if (filter != NULL) {
+ expanded = format_expand(ft, filter);
+ flag = format_true(expanded);
+ free(expanded);
+ } else
+ flag = 1;
+ if (flag) {
+ line = format_expand(ft, template);
+ cmdq_print(item, "%s", line);
+ free(line);
+ }
format_free(ft);
n++;
diff --git a/cmd-list-windows.c b/cmd-list-windows.c
index 46ee6f0c..9c33c2d0 100644
--- a/cmd-list-windows.c
+++ b/cmd-list-windows.c
@@ -49,8 +49,8 @@ const struct cmd_entry cmd_list_windows_entry = {
.name = "list-windows",
.alias = "lsw",
- .args = { "F:at:", 0, 0 },
- .usage = "[-a] [-F format] " CMD_TARGET_SESSION_USAGE,
+ .args = { "F:f:at:", 0, 0 },
+ .usage = "[-a] [-F format] [-f filter] " CMD_TARGET_SESSION_USAGE,
.target = { 't', CMD_FIND_SESSION, 0 },
@@ -61,12 +61,13 @@ const struct cmd_entry cmd_list_windows_entry = {
static enum cmd_retval
cmd_list_windows_exec(struct cmd *self, struct cmdq_item *item)
{
- struct args *args = self->args;
+ struct args *args = cmd_get_args(self);
+ struct cmd_find_state *target = cmdq_get_target(item);
if (args_has(args, 'a'))
cmd_list_windows_server(self, item);
else
- cmd_list_windows_session(self, item->target.s, item, 0);
+ cmd_list_windows_session(self, target->s, item, 0);
return (CMD_RETURN_NORMAL);
}
@@ -84,12 +85,13 @@ static void
cmd_list_windows_session(struct cmd *self, struct session *s,
struct cmdq_item *item, int type)
{
- struct args *args = self->args;
+ struct args *args = cmd_get_args(self);
struct winlink *wl;
u_int n;
struct format_tree *ft;
- const char *template;
- char *line;
+ const char *template, *filter;
+ char *line, *expanded;
+ int flag;
template = args_get(args, 'F');
if (template == NULL) {
@@ -102,16 +104,25 @@ cmd_list_windows_session(struct cmd *self, struct session *s,
break;
}
}
+ filter = args_get(args, 'f');
n = 0;
RB_FOREACH(wl, winlinks, &s->windows) {
- ft = format_create(item->client, item, FORMAT_NONE, 0);
+ ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0);
format_add(ft, "line", "%u", n);
format_defaults(ft, NULL, s, wl, NULL);
- line = format_expand(ft, template);
- cmdq_print(item, "%s", line);
- free(line);
+ if (filter != NULL) {
+ expanded = format_expand(ft, filter);
+ flag = format_true(expanded);
+ free(expanded);
+ } else
+ flag = 1;
+ if (flag) {
+ line = format_expand(ft, template);
+ cmdq_print(item, "%s", line);
+ free(line);
+ }
format_free(ft);
n++;
diff --git a/cmd-load-buffer.c b/cmd-load-buffer.c
index 5e930126..49e834d6 100644
--- a/cmd-load-buffer.c
+++ b/cmd-load-buffer.c
@@ -83,12 +83,8 @@ cmd_load_buffer_done(__unused struct client *c, const char *path, int error,
static enum cmd_retval
cmd_load_buffer_exec(struct cmd *self, struct cmdq_item *item)
{
- struct args *args = self->args;
+ struct args *args = cmd_get_args(self);
struct cmd_load_buffer_data *cdata;
- struct client *c = cmd_find_client(item, NULL, 1);
- struct session *s = item->target.s;
- struct winlink *wl = item->target.wl;
- struct window_pane *wp = item->target.wp;
const char *bufname = args_get(args, 'b');
char *path;
@@ -99,8 +95,8 @@ cmd_load_buffer_exec(struct cmd *self, struct cmdq_item *item)
else
cdata->name = NULL;
- path = format_single(item, args->argv[0], c, s, wl, wp);
- file_read(item->client, path, cmd_load_buffer_done, cdata);
+ path = format_single_from_target(item, args->argv[0]);
+ file_read(cmdq_get_client(item), path, cmd_load_buffer_done, cdata);
free(path);
return (CMD_RETURN_WAIT);
diff --git a/cmd-lock-server.c b/cmd-lock-server.c
index 524fa451..a0df95b0 100644
--- a/cmd-lock-server.c
+++ b/cmd-lock-server.c
@@ -57,25 +57,22 @@ const struct cmd_entry cmd_lock_client_entry = {
.args = { "t:", 0, 0 },
.usage = CMD_TARGET_CLIENT_USAGE,
- .flags = CMD_AFTERHOOK,
+ .flags = CMD_AFTERHOOK|CMD_CLIENT_TFLAG,
.exec = cmd_lock_server_exec
};
static enum cmd_retval
cmd_lock_server_exec(struct cmd *self, struct cmdq_item *item)
{
- struct args *args = self->args;
- struct client *c;
+ struct cmd_find_state *target = cmdq_get_target(item);
+ struct client *tc = cmdq_get_target_client(item);
- if (self->entry == &cmd_lock_server_entry)
+ if (cmd_get_entry(self) == &cmd_lock_server_entry)
server_lock();
- else if (self->entry == &cmd_lock_session_entry)
- server_lock_session(item->target.s);
- else {
- if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
- return (CMD_RETURN_ERROR);
- server_lock_client(c);
- }
+ else if (cmd_get_entry(self) == &cmd_lock_session_entry)
+ server_lock_session(target->s);
+ else
+ server_lock_client(tc);
recalculate_sizes();
return (CMD_RETURN_NORMAL);
diff --git a/cmd-move-window.c b/cmd-move-window.c
index cb64d1e0..94b6c950 100644
--- a/cmd-move-window.c
+++ b/cmd-move-window.c
@@ -59,49 +59,52 @@ const struct cmd_entry cmd_link_window_entry = {
static enum cmd_retval
cmd_move_window_exec(struct cmd *self, struct cmdq_item *item)
{
- struct args *args = self->args;
- const char *tflag = args_get(args, 't');
- struct session *src;
- struct session *dst;
- struct winlink *wl;
- char *cause;
- int idx, kflag, dflag, sflag;
+ struct args *args = cmd_get_args(self);
+ struct cmd_find_state *source = cmdq_get_source(item);
+ struct cmd_find_state target;
+ const char *tflag = args_get(args, 't');
+ struct session *src = source->s;
+ struct session *dst;
+ struct winlink *wl = source->wl;
+ char *cause;
+ int idx, kflag, dflag, sflag;
if (args_has(args, 'r')) {
- if (cmd_find_target(&item->target, item, tflag,
- CMD_FIND_SESSION, CMD_FIND_QUIET) != 0)
+ if (cmd_find_target(&target, item, tflag, CMD_FIND_SESSION,
+ CMD_FIND_QUIET) != 0)
return (CMD_RETURN_ERROR);
- session_renumber_windows(item->target.s);
+ session_renumber_windows(target.s);
recalculate_sizes();
- server_status_session(item->target.s);
+ server_status_session(target.s);
return (CMD_RETURN_NORMAL);
}
- if (cmd_find_target(&item->target, item, tflag, CMD_FIND_WINDOW,
+ if (cmd_find_target(&target, item, tflag, CMD_FIND_WINDOW,
CMD_FIND_WINDOW_INDEX) != 0)
return (CMD_RETURN_ERROR);
- src = item->source.s;
- dst = item->target.s;
- wl = item->source.wl;
- idx = item->target.idx;
-
- kflag = args_has(self->args, 'k');
- dflag = args_has(self->args, 'd');
- sflag = args_has(self->args, 's');
-
- if (args_has(self->args, 'a')) {
- if ((idx = winlink_shuffle_up(dst, dst->curw)) == -1)
+ dst = target.s;
+ idx = target.idx;
+
+ kflag = args_has(args, 'k');
+ dflag = args_has(args, 'd');
+ sflag = args_has(args, 's');
+
+ if (args_has(args, 'a')) {
+ if (target.wl != NULL)
+ idx = winlink_shuffle_up(dst, target.wl);
+ else
+ idx = winlink_shuffle_up(dst, dst->curw);
+ if (idx == -1)
return (CMD_RETURN_ERROR);
}
- if (server_link_window(src, wl, dst, idx, kflag, !dflag,
- &cause) != 0) {
- cmdq_error(item, "can't link window: %s", cause);
+ if (server_link_window(src, wl, dst, idx, kflag, !dflag, &cause) != 0) {
+ cmdq_error(item, "%s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
- if (self->entry == &cmd_move_window_entry)
+ if (cmd_get_entry(self) == &cmd_move_window_entry)
server_unlink_window(src, wl);
/*
diff --git a/cmd-new-session.c b/cmd-new-session.c
index a75fc972..9815e1e1 100644
--- a/cmd-new-session.c
+++ b/cmd-new-session.c
@@ -39,10 +39,10 @@ const struct cmd_entry cmd_new_session_entry = {
.name = "new-session",
.alias = "new",
- .args = { "Ac:dDEF:n:Ps:t:x:Xy:", 0, -1 },
- .usage = "[-AdDEPX] [-c start-directory] [-F format] [-n window-name] "
- "[-s session-name] " CMD_TARGET_SESSION_USAGE " [-x width] "
- "[-y height] [command]",
+ .args = { "Ac:dDe:EF:n:Ps:t:x:Xy:", 0, -1 },
+ .usage = "[-AdDEPX] [-c start-directory] [-e environment] [-F format] "
+ "[-n window-name] [-s session-name] "
+ CMD_TARGET_SESSION_USAGE " [-x width] [-y height] [command]",
.target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
@@ -66,22 +66,26 @@ const struct cmd_entry cmd_has_session_entry = {
static enum cmd_retval
cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
{
- struct args *args = self->args;
- struct client *c = item->client;
- struct session *s, *as, *groupwith;
+ struct args *args = cmd_get_args(self);
+ struct cmd_find_state *current = cmdq_get_current(item);
+ struct cmd_find_state *target = cmdq_get_target(item);
+ struct client *c = cmdq_get_client(item);
+ struct session *s, *as, *groupwith = NULL;
struct environ *env;
struct options *oo;
struct termios tio, *tiop;
- struct session_group *sg;
- const char *errstr, *template, *group, *prefix, *tmp;
+ struct session_group *sg = NULL;
+ const char *errstr, *template, *group, *tmp, *add;
char *cause, *cwd = NULL, *cp, *newname = NULL;
+ char *name, *prefix = NULL;
int detached, already_attached, is_control = 0;
u_int sx, sy, dsx, dsy;
struct spawn_context sc;
enum cmd_retval retval;
struct cmd_find_state fs;
+ struct args_value *value;
- if (self->entry == &cmd_has_session_entry) {
+ if (cmd_get_entry(self) == &cmd_has_session_entry) {
/*
* cmd_find_target() will fail if the session cannot be found,
* so always return success here.
@@ -96,17 +100,15 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
tmp = args_get(args, 's');
if (tmp != NULL) {
- newname = format_single(item, tmp, c, NULL, NULL, NULL);
- if (!session_check_name(newname)) {
- cmdq_error(item, "bad session name: %s", newname);
- goto fail;
- }
+ name = format_single(item, tmp, c, NULL, NULL, NULL);
+ newname = session_check_name(name);
+ free(name);
}
if (args_has(args, 'A')) {
if (newname != NULL)
as = session_find(newname);
else
- as = item->target.s;
+ as = target->s;
if (as != NULL) {
retval = cmd_attach_session(item, as->name,
args_has(args, 'D'), args_has(args, 'X'), 0, NULL,
@@ -123,25 +125,17 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
/* Is this going to be part of a session group? */
group = args_get(args, 't');
if (group != NULL) {
- groupwith = item->target.s;
- if (groupwith == NULL) {
- if (!session_check_name(group)) {
- cmdq_error(item, "bad group name: %s", group);
- goto fail;
- }
+ groupwith = target->s;
+ if (groupwith == NULL)
sg = session_group_find(group);
- } else
+ else
sg = session_group_contains(groupwith);
if (sg != NULL)
- prefix = sg->name;
+ prefix = xstrdup(sg->name);
else if (groupwith != NULL)
- prefix = groupwith->name;
+ prefix = xstrdup(groupwith->name);
else
- prefix = group;
- } else {
- groupwith = NULL;
- sg = NULL;
- prefix = NULL;
+ prefix = session_check_name(group);
}
/* Set -d if no client. */
@@ -172,7 +166,7 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
* over.
*/
if (!detached && !already_attached && c->tty.fd != -1) {
- if (server_client_check_nested(item->client)) {
+ if (server_client_check_nested(cmdq_get_client(item))) {
cmdq_error(item, "sessions should be nested with care, "
"unset $TMUX to force");
goto fail;
@@ -207,7 +201,8 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
goto fail;
}
}
- }
+ } else
+ dsx = 80;
if (args_has(args, 'y')) {
tmp = args_get(args, 'y');
if (strcmp(tmp, "-") == 0) {
@@ -222,7 +217,8 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
goto fail;
}
}
- }
+ } else
+ dsy = 24;
/* Find new session size. */
if (!detached && !is_control) {
@@ -233,13 +229,14 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
} else {
tmp = options_get_string(global_s_options, "default-size");
if (sscanf(tmp, "%ux%u", &sx, &sy) != 2) {
- sx = 80;
- sy = 24;
- }
- if (args_has(args, 'x'))
sx = dsx;
- if (args_has(args, 'y'))
sy = dsy;
+ } else {
+ if (args_has(args, 'x'))
+ sx = dsx;
+ if (args_has(args, 'y'))
+ sy = dsy;
+ }
}
if (sx == 0)
sx = 1;
@@ -258,13 +255,17 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
env = environ_create();
if (c != NULL && !args_has(args, 'E'))
environ_update(global_s_options, c->environ, env);
+ add = args_first_value(args, 'e', &value);
+ while (add != NULL) {
+ environ_put(env, add, 0);
+ add = args_next_value(&value);
+ }
s = session_create(prefix, newname, cwd, env, oo, tiop);
/* Spawn the initial window. */
memset(&sc, 0, sizeof sc);
sc.item = item;
sc.s = s;
- sc.c = c;
sc.name = args_get(args, 'n');
sc.argc = args->argc;
@@ -311,7 +312,7 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
} else if (c->session != NULL)
c->last_session = c->session;
c->session = s;
- if (~item->shared->flags & CMDQ_SHARED_REPEAT)
+ if (~cmdq_get_flags(item) & CMDQ_STATE_REPEAT)
server_client_set_key_table(c, NULL);
tty_update_client_offset(c);
status_timer_start(c);
@@ -339,20 +340,22 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
free(cp);
}
- if (!detached) {
+ if (!detached)
c->flags |= CLIENT_ATTACHED;
- cmd_find_from_session(&item->shared->current, s, 0);
- }
+ if (!args_has(args, 'd'))
+ cmd_find_from_session(current, s, 0);
cmd_find_from_session(&fs, s, 0);
cmdq_insert_hook(s, item, &fs, "after-new-session");
free(cwd);
free(newname);
+ free(prefix);
return (CMD_RETURN_NORMAL);
fail:
free(cwd);
free(newname);
+ free(prefix);
return (CMD_RETURN_ERROR);
}
diff --git a/cmd-new-window.c b/cmd-new-window.c
index 2fb92830..722f89b9 100644
--- a/cmd-new-window.c
+++ b/cmd-new-window.c
@@ -51,13 +51,14 @@ const struct cmd_entry cmd_new_window_entry = {
static enum cmd_retval
cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
{
- struct args *args = self->args;
- struct cmd_find_state *current = &item->shared->current;
+ struct args *args = cmd_get_args(self);
+ struct cmd_find_state *current = cmdq_get_current(item);
+ struct cmd_find_state *target = cmdq_get_target(item);
struct spawn_context sc;
- struct client *c = cmd_find_client(item, NULL, 1);
- struct session *s = item->target.s;
- struct winlink *wl = item->target.wl;
- int idx = item->target.idx;
+ struct client *tc = cmdq_get_target_client(item);
+ struct session *s = target->s;
+ struct winlink *wl = target->wl;
+ int idx = target->idx;
struct winlink *new_wl;
char *cause = NULL, *cp;
const char *template, *add;
@@ -72,7 +73,7 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
memset(&sc, 0, sizeof sc);
sc.item = item;
sc.s = s;
- sc.c = c;
+ sc.tc = tc;
sc.name = args_get(args, 'n');
sc.argc = args->argc;
@@ -81,7 +82,7 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
add = args_first_value(args, 'e', &value);
while (add != NULL) {
- environ_put(sc.environ, add);
+ environ_put(sc.environ, add, 0);
add = args_next_value(&value);
}
@@ -108,7 +109,7 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
if (args_has(args, 'P')) {
if ((template = args_get(args, 'F')) == NULL)
template = NEW_WINDOW_TEMPLATE;
- cp = format_single(item, template, c, s, new_wl,
+ cp = format_single(item, template, tc, s, new_wl,
new_wl->window->active);
cmdq_print(item, "%s", cp);
free(cp);
diff --git a/cmd-parse.y b/cmd-parse.y
index 2375370b..891f2289 100644
--- a/cmd-parse.y
+++ b/cmd-parse.y
@@ -99,6 +99,7 @@ static void cmd_parse_print_commands(struct cmd_parse_input *, u_int,
}
%token ERROR
+%token HIDDEN
%token IF
%token ELSE
%token ELIF
@@ -138,6 +139,11 @@ statement : /* empty */
$$ = xmalloc (sizeof *$$);
TAILQ_INIT($$);
}
+ | hidden_assignment
+ {
+ $$ = xmalloc (sizeof *$$);
+ TAILQ_INIT($$);
+ }
| condition
{
struct cmd_parse_state *ps = &parse_state;
@@ -204,10 +210,21 @@ assignment : EQUALS
if ((~flags & CMD_PARSE_PARSEONLY) &&
(ps->scope == NULL || ps->scope->flag))
- environ_put(global_environ, $1);
+ environ_put(global_environ, $1, 0);
free($1);
}
+hidden_assignment : HIDDEN EQUALS
+ {
+ struct cmd_parse_state *ps = &parse_state;
+ int flags = ps->input->flags;
+
+ if ((~flags & CMD_PARSE_PARSEONLY) &&
+ (ps->scope == NULL || ps->scope->flag))
+ environ_put(global_environ, $2, ENVIRON_HIDDEN);
+ free($2);
+ }
+
if_open : IF expanded
{
struct cmd_parse_state *ps = &parse_state;
@@ -683,15 +700,17 @@ cmd_parse_build_commands(struct cmd_parse_commands *cmds,
/*
* Parse each command into a command list. Create a new command list
- * for each line so they get a new group (so the queue knows which ones
- * to remove if a command fails when executed).
+ * for each line (unless the flag is set) so they get a new group (so
+ * the queue knows which ones to remove if a command fails when
+ * executed).
*/
result = cmd_list_new();
TAILQ_FOREACH(cmd, cmds, entry) {
log_debug("%s: %u %s", __func__, cmd->line, cmd->name);
cmd_log_argv(cmd->argc, cmd->argv, __func__);
- if (cmdlist == NULL || cmd->line != line) {
+ if (cmdlist == NULL ||
+ ((~pi->flags & CMD_PARSE_ONEGROUP) && cmd->line != line)) {
if (cmdlist != NULL) {
cmd_parse_print_commands(pi, line, cmdlist);
cmd_list_move(result, cmdlist);
@@ -758,9 +777,74 @@ cmd_parse_from_file(FILE *f, struct cmd_parse_input *pi)
struct cmd_parse_result *
cmd_parse_from_string(const char *s, struct cmd_parse_input *pi)
{
+ struct cmd_parse_input input;
+
+ if (pi == NULL) {
+ memset(&input, 0, sizeof input);
+ pi = &input;
+ }
+
+ /*
+ * When parsing a string, put commands in one group even if there are
+ * multiple lines. This means { a \n b } is identical to "a ; b" when
+ * given as an argument to another command.
+ */
+ pi->flags |= CMD_PARSE_ONEGROUP;
return (cmd_parse_from_buffer(s, strlen(s), pi));
}
+enum cmd_parse_status
+cmd_parse_and_insert(const char *s, struct cmd_parse_input *pi,
+ struct cmdq_item *after, struct cmdq_state *state, char **error)
+{
+ struct cmd_parse_result *pr;
+ struct cmdq_item *item;
+
+ pr = cmd_parse_from_string(s, pi);
+ switch (pr->status) {
+ case CMD_PARSE_EMPTY:
+ break;
+ case CMD_PARSE_ERROR:
+ if (error != NULL)
+ *error = pr->error;
+ else
+ free(pr->error);
+ break;
+ case CMD_PARSE_SUCCESS:
+ item = cmdq_get_command(pr->cmdlist, state);
+ cmdq_insert_after(after, item);
+ cmd_list_free(pr->cmdlist);
+ break;
+ }
+ return (pr->status);
+}
+
+enum cmd_parse_status
+cmd_parse_and_append(const char *s, struct cmd_parse_input *pi,
+ struct client *c, struct cmdq_state *state, char **error)
+{
+ struct cmd_parse_result *pr;
+ struct cmdq_item *item;
+
+ pr = cmd_parse_from_string(s, pi);
+ switch (pr->status) {
+ case CMD_PARSE_EMPTY:
+ break;
+ case CMD_PARSE_ERROR:
+ if (error != NULL)
+ *error = pr->error;
+ else
+ free(pr->error);
+ break;
+ case CMD_PARSE_SUCCESS:
+ item = cmdq_get_command(pr->cmdlist, state);
+ cmdq_append(c, item);
+ cmd_list_free(pr->cmdlist);
+ break;
+ }
+ return (pr->status);
+}
+
struct cmd_parse_result *
cmd_parse_from_buffer(const void *buf, size_t len, struct cmd_parse_input *pi)
{
@@ -1079,6 +1163,10 @@ yylex(void)
if (*cp == '\0')
return (TOKEN);
ps->condition = 1;
+ if (strcmp(yylval.token, "%hidden") == 0) {
+ free(yylval.token);
+ return (HIDDEN);
+ }
if (strcmp(yylval.token, "%if") == 0) {
free(yylval.token);
return (IF);
diff --git a/cmd-paste-buffer.c b/cmd-paste-buffer.c
index 2b5db825..c8447426 100644
--- a/cmd-paste-buffer.c
+++ b/cmd-paste-buffer.c
@@ -46,8 +46,9 @@ const struct cmd_entry cmd_paste_buffer_entry = {
static enum cmd_retval
cmd_paste_buffer_exec(struct cmd *self, struct cmdq_item *item)
{
- struct args *args = self->args;
- struct window_pane *wp = item->target.wp;
+ struct args *args = cmd_get_args(self);
+ struct cmd_find_state *target = cmdq_get_target(item);
+ struct window_pane *wp = target->wp;
struct paste_buffer *pb;
const char *sepstr, *bufname, *bufdata, *bufend, *line;
size_t seplen, bufsize;
diff --git a/cmd-pipe-pane.c b/cmd-pipe-pane.c
index ce1b3d37..b64229d8 100644
--- a/cmd-pipe-pane.c
+++ b/cmd-pipe-pane.c
@@ -55,11 +55,12 @@ const struct cmd_entry cmd_pipe_pane_entry = {
static enum cmd_retval
cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item)
{
- struct args *args = self->args;
- struct client *c = cmd_find_client(item, NULL, 1);
- struct window_pane *wp = item->target.wp;
- struct session *s = item->target.s;
- struct winlink *wl = item->target.wl;
+ struct args *args = cmd_get_args(self);
+ struct cmd_find_state *target = cmdq_get_target(item);
+ struct client *tc = cmdq_get_target_client(item);
+ struct window_pane *wp = target->wp;
+ struct session *s = target->s;
+ struct winlink *wl = target->wl;
char *cmd;
int old_fd, pipe_fd[2], null_fd, in, out;
struct format_tree *ft;
@@ -88,13 +89,13 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item)
*
* bind ^p pipep -o 'cat >>~/output'
*/
- if (args_has(self->args, 'o') && old_fd != -1)
+ if (args_has(args, 'o') && old_fd != -1)
return (CMD_RETURN_NORMAL);
/* What do we want to do? Neither -I or -O is -O. */
- if (args_has(self->args, 'I')) {
+ if (args_has(args, 'I')) {
in = 1;
- out = args_has(self->args, 'O');
+ out = args_has(args, 'O');
} else {
in = 0;
out = 1;
@@ -107,8 +108,8 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item)
}
/* Expand the command. */
- ft = format_create(item->client, item, FORMAT_NONE, 0);
- format_defaults(ft, c, s, wl, wp);
+ ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0);
+ format_defaults(ft, tc, s, wl, wp);
cmd = format_expand_time(ft, args->argv[0]);
format_free(ft);
diff --git a/cmd-queue.c b/cmd-queue.c
index a9e1dd3a..59f86c64 100644
--- a/cmd-queue.c
+++ b/cmd-queue.c
@@ -25,8 +25,69 @@
#include "tmux.h"
-/* Global command queue. */
-static struct cmdq_list global_queue = TAILQ_HEAD_INITIALIZER(global_queue);
+/* Command queue flags. */
+#define CMDQ_FIRED 0x1
+#define CMDQ_WAITING 0x2
+
+/* Command queue item type. */
+enum cmdq_type {
+ CMDQ_COMMAND,
+ CMDQ_CALLBACK,
+};
+
+/* Command queue item. */
+struct cmdq_item {
+ char *name;
+ struct cmdq_list *queue;
+ struct cmdq_item *next;
+
+ struct client *client;
+ struct client *target_client;
+
+ enum cmdq_type type;
+ u_int group;
+
+ u_int number;
+ time_t time;
+
+ int flags;
+
+ struct cmdq_state *state;
+ struct cmd_find_state source;
+ struct cmd_find_state target;
+
+ struct cmd_list *cmdlist;
+ struct cmd *cmd;
+
+ cmdq_cb cb;
+ void *data;
+
+ TAILQ_ENTRY(cmdq_item) entry;
+};
+TAILQ_HEAD(cmdq_item_list, cmdq_item);
+
+/*
+ * Command queue state. This is the context for commands on the command queue.
+ * It holds information about how the commands were fired (the key and flags),
+ * any additional formats for the commands, and the current default target.
+ * Multiple commands can share the same state and a command may update the
+ * default target.
+ */
+struct cmdq_state {
+ int references;
+ int flags;
+
+ struct format_tree *formats;
+
+ struct key_event event;
+ struct cmd_find_state current;
+};
+
+/* Command queue. */
+struct cmdq_list {
+ struct cmdq_item *item;
+ struct cmdq_item_list list;
+};
/* Get command queue name. */
static const char *
@@ -47,9 +108,179 @@ cmdq_name(struct client *c)
static struct cmdq_list *
cmdq_get(struct client *c)
{
- if (c == NULL)
- return (&global_queue);
- return (&c->queue);
+ static struct cmdq_list *global_queue;
+
+ if (c == NULL) {
+ if (global_queue == NULL)
+ global_queue = cmdq_new();
+ return (global_queue);
+ }
+ return (c->queue);
+}
+
+/* Create a queue. */
+struct cmdq_list *
+cmdq_new(void)
+{
+ struct cmdq_list *queue;
+
+ queue = xcalloc (1, sizeof *queue);
+ TAILQ_INIT (&queue->list);
+ return (queue);
+}
+
+/* Free a queue. */
+void
+cmdq_free(struct cmdq_list *queue)
+{
+ if (!TAILQ_EMPTY(&queue->list))
+ fatalx("queue not empty");
+ free(queue);
+}
+
+/* Get item name. */
+const char *
+cmdq_get_name(struct cmdq_item *item)
+{
+ return (item->name);
+}
+
+/* Get item client. */
+struct client *
+cmdq_get_client(struct cmdq_item *item)
+{
+ return (item->client);
+}
+
+/* Get item target client. */
+struct client *
+cmdq_get_target_client(struct cmdq_item *item)
+{
+ return (item->target_client);
+}
+
+/* Get item state. */
+struct cmdq_state *
+cmdq_get_state(struct cmdq_item *item)
+{
+ return (item->state);
+}
+
+/* Get item target. */
+struct cmd_find_state *
+cmdq_get_target(struct cmdq_item *item)
+{
+ return (&item->target);
+}
+
+/* Get item source. */
+struct cmd_find_state *
+cmdq_get_source(struct cmdq_item *item)
+{
+ return (&item->source);
+}
+
+/* Get state event. */
+struct key_event *
+cmdq_get_event(struct cmdq_item *item)
+{
+ return (&item->state->event);
+}
+
+/* Get state current target. */
+struct cmd_find_state *
+cmdq_get_current(struct cmdq_item *item)
+{
+ return (&item->state->current);
+}
+
+/* Get state flags. */
+int
+cmdq_get_flags(struct cmdq_item *item)
+{
+ return (item->state->flags);
+}
+
+/* Create a new state. */
+struct cmdq_state *
+cmdq_new_state(struct cmd_find_state *current, struct key_event *event,
+ int flags)
+{
+ struct cmdq_state *state;
+
+ state = xcalloc(1, sizeof *state);
+ state->references = 1;
+ state->flags = flags;
+
+ if (event != NULL)
+ memcpy(&state->event, event, sizeof state->event);
+ else
+ state->event.key = KEYC_NONE;
+ if (current != NULL && cmd_find_valid_state(current))
+ cmd_find_copy_state(&state->current, current);
+ else
+ cmd_find_clear_state(&state->current, 0);
+
+ return (state);
+}
+
+/* Add a reference to a state. */
+struct cmdq_state *
+cmdq_link_state(struct cmdq_state *state)
+{
+ state->references++;
+ return (state);
+}
+
+/* Make a copy of a state. */
+struct cmdq_state *
+cmdq_copy_state(struct cmdq_state *state)
+{
+ return (cmdq_new_state(&state->current, &state->event, state->flags));
+}
+
+/* Free a state. */
+void
+cmdq_free_state(struct cmdq_state *state)
+{
+ if (--state->references != 0)
+ return;
+
+ if (state->formats != NULL)
+ format_free(state->formats);
+ free(state);
+}
+
+/* Add a format to command queue. */
+void
+cmdq_add_format(struct cmdq_state *state, const char *key, const char *fmt, ...)
+{
+ va_list ap;
+ char *value;
+
+ va_start(ap, fmt);
+ xvasprintf(&value, fmt, ap);
+ va_end(ap);
+
+ if (state->formats == NULL)
+ state->formats = format_create(NULL, NULL, FORMAT_NONE, 0);
+ format_add(state->formats, key, "%s", value);
+
+ free(value);
+}
+
+/* Merge formats from item. */
+void
+cmdq_merge_formats(struct cmdq_item *item, struct format_tree *ft)
+{
+ const struct cmd_entry *entry;
+
+ if (item->cmd != NULL) {
+ entry = cmd_get_entry (item->cmd);
+ format_add(ft, "command", "%s", entry->name);
+ }
+ if (item->state->formats != NULL)
+ format_merge(ft, item->state->formats);
}
/* Append an item. */
@@ -68,12 +299,12 @@ cmdq_append(struct client *c, struct cmdq_item *item)
item->client = c;
item->queue = queue;
- TAILQ_INSERT_TAIL(queue, item, entry);
+ TAILQ_INSERT_TAIL(&queue->list, item, entry);
log_debug("%s %s: %s", __func__, cmdq_name(c), item->name);
item = next;
} while (item != NULL);
- return (TAILQ_LAST(queue, cmdq_list));
+ return (TAILQ_LAST(&queue->list, cmdq_item_list));
}
/* Insert an item. */
@@ -94,7 +325,7 @@ cmdq_insert_after(struct cmdq_item *after, struct cmdq_item *item)
item->client = c;
item->queue = queue;
- TAILQ_INSERT_AFTER(queue, after, item, entry);
+ TAILQ_INSERT_AFTER(&queue->list, after, item, entry);
log_debug("%s %s: %s after %s", __func__, cmdq_name(c),
item->name, after->name);
@@ -107,17 +338,19 @@ cmdq_insert_after(struct cmdq_item *after, struct cmdq_item *item)
/* Insert a hook. */
void
cmdq_insert_hook(struct session *s, struct cmdq_item *item,
- struct cmd_find_state *fs, const char *fmt, ...)
+ struct cmd_find_state *current, const char *fmt, ...)
{
+ struct cmdq_state *state = item->state;
struct options *oo;
va_list ap;
char *name;
struct cmdq_item *new_item;
+ struct cmdq_state *new_state;
struct options_entry *o;
struct options_array_item *a;
struct cmd_list *cmdlist;
- if (item->flags & CMDQ_NOHOOKS)
+ if (item->state->flags & CMDQ_STATE_NOHOOKS)
return;
if (s == NULL)
oo = global_s_options;
@@ -135,24 +368,27 @@ cmdq_insert_hook(struct session *s, struct cmdq_item *item,
}
log_debug("running hook %s (parent %p)", name, item);
+ /*
+ * The hooks get a new state because they should not update the current
+ * target or formats for any subsequent commands.
+ */
+ new_state = cmdq_new_state(current, &state->event, CMDQ_STATE_NOHOOKS);
+ cmdq_add_format(new_state, "hook", "%s", name);
+
a = options_array_first(o);
while (a != NULL) {
cmdlist = options_array_item_value(a)->cmdlist;
- if (cmdlist == NULL) {
- a = options_array_next(a);
- continue;
+ if (cmdlist != NULL) {
+ new_item = cmdq_get_command(cmdlist, new_state);
+ if (item != NULL)
+ item = cmdq_insert_after(item, new_item);
+ else
+ item = cmdq_append(NULL, new_item);
}
-
- new_item = cmdq_get_command(cmdlist, fs, NULL, CMDQ_NOHOOKS);
- cmdq_format(new_item, "hook", "%s", name);
- if (item != NULL)
- item = cmdq_insert_after(item, new_item);
- else
- item = cmdq_append(NULL, new_item);
-
a = options_array_next(a);
}
+ cmdq_free_state(new_state);
free(name);
}
@@ -167,19 +403,13 @@ cmdq_continue(struct cmdq_item *item)
static void
cmdq_remove(struct cmdq_item *item)
{
- if (item->shared != NULL && --item->shared->references == 0) {
- if (item->shared->formats != NULL)
- format_free(item->shared->formats);
- free(item->shared);
- }
-
if (item->client != NULL)
server_client_unref(item->client);
-
if (item->cmdlist != NULL)
cmd_list_free(item->cmdlist);
+ cmdq_free_state(item->state);
- TAILQ_REMOVE(item->queue, item, entry);
+ TAILQ_REMOVE(&item->queue->list, item, entry);
free(item->name);
free(item);
@@ -204,48 +434,46 @@ cmdq_remove_group(struct cmdq_item *item)
/* Get a command for the command queue. */
struct cmdq_item *
-cmdq_get_command(struct cmd_list *cmdlist, struct cmd_find_state *current,
- struct mouse_event *m, int flags)
+cmdq_get_command(struct cmd_list *cmdlist, struct cmdq_state *state)
{
struct cmdq_item *item, *first = NULL, *last = NULL;
struct cmd *cmd;
- struct cmdq_shared *shared = NULL;
- u_int group = 0;
-
- TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
- if (cmd->group != group) {
- shared = xcalloc(1, sizeof *shared);
- if (current != NULL)
- cmd_find_copy_state(&shared->current, current);
- else
- cmd_find_clear_state(&shared->current, 0);
- if (m != NULL)
- memcpy(&shared->mouse, m, sizeof shared->mouse);
- group = cmd->group;
- }
+ const struct cmd_entry *entry;
+ int created = 0;
+
+ if (state == NULL) {
+ state = cmdq_new_state(NULL, NULL, 0);
+ created = 1;
+ }
+
+ cmd = cmd_list_first(cmdlist);
+ while (cmd != NULL) {
+ entry = cmd_get_entry(cmd);
item = xcalloc(1, sizeof *item);
- xasprintf(&item->name, "[%s/%p]", cmd->entry->name, item);
+ xasprintf(&item->name, "[%s/%p]", entry->name, item);
item->type = CMDQ_COMMAND;
- item->group = cmd->group;
- item->flags = flags;
+ item->group = cmd_get_group(cmd);
+ item->state = cmdq_link_state(state);
- item->shared = shared;
item->cmdlist = cmdlist;
item->cmd = cmd;
- log_debug("%s: %s group %u", __func__, item->name, item->group);
-
- shared->references++;
cmdlist->references++;
+ log_debug("%s: %s group %u", __func__, item->name, item->group);
if (first == NULL)
first = item;
if (last != NULL)
last->next = item;
last = item;
+
+ cmd = cmd_list_next(cmd);
}
+
+ if (created)
+ cmdq_free_state(state);
return (first);
}
@@ -261,7 +489,7 @@ cmdq_find_flag(struct cmdq_item *item, struct cmd_find_state *fs,
return (CMD_RETURN_NORMAL);
}
- value = args_get(item->cmd->args, flag->flag);
+ value = args_get(cmd_get_args(item->cmd), flag->flag);
if (cmd_find_target(fs, item, value, flag->type, flag->flags) != 0) {
cmd_find_clear_state(fs, 0);
return (CMD_RETURN_ERROR);
@@ -273,14 +501,15 @@ cmdq_find_flag(struct cmdq_item *item, struct cmd_find_state *fs,
static enum cmd_retval
cmdq_fire_command(struct cmdq_item *item)
{
- struct client *c = item->client;
- const char *name = cmdq_name(c);
- struct cmdq_shared *shared = item->shared;
+ const char *name = cmdq_name(item->client);
+ struct cmdq_state *state = item->state;
struct cmd *cmd = item->cmd;
- const struct cmd_entry *entry = cmd->entry;
+ struct args *args = cmd_get_args(cmd);
+ const struct cmd_entry *entry = cmd_get_entry(cmd);
+ struct client *tc, *saved = item->client;
enum cmd_retval retval;
struct cmd_find_state *fsp, fs;
- int flags;
+ int flags, quiet = 0;
char *tmp;
if (log_get_level() > 1) {
@@ -289,11 +518,30 @@ cmdq_fire_command(struct cmdq_item *item)
free(tmp);
}
- flags = !!(shared->flags & CMDQ_SHARED_CONTROL);
+ flags = !!(state->flags & CMDQ_STATE_CONTROL);
cmdq_guard(item, "begin", flags);
if (item->client == NULL)
item->client = cmd_find_client(item, NULL, 1);
+
+ if (entry->flags & CMD_CLIENT_CANFAIL)
+ quiet = 1;
+ if (entry->flags & CMD_CLIENT_CFLAG) {
+ tc = cmd_find_client(item, args_get(args, 'c'), quiet);
+ if (tc == NULL && !quiet) {
+ retval = CMD_RETURN_ERROR;
+ goto out;
+ }
+ } else if (entry->flags & CMD_CLIENT_TFLAG) {
+ tc = cmd_find_client(item, args_get(args, 't'), quiet);
+ if (tc == NULL && !quiet) {
+ retval = CMD_RETURN_ERROR;
+ goto out;
+ }
+ } else
+ tc = cmd_find_client(item, NULL, 1);
+ item->target_client = tc;
+
retval = cmdq_find_flag(item, &item->source, &entry->source);
if (retval == CMD_RETURN_ERROR)
goto out;
@@ -301,6 +549,7 @@ cmdq_fire_command(struct cmdq_item *item)
if (retval == CMD_RETURN_ERROR)
goto out;
+
retval = entry->exec(cmd, item);
if (retval == CMD_RETURN_ERROR)
goto out;
@@ -308,8 +557,8 @@ cmdq_fire_command(struct cmdq_item *item)
if (entry->flags & CMD_AFTERHOOK) {
if (cmd_find_valid_state(&item->target))
fsp = &item->target;
- else if (cmd_find_valid_state(&item->shared->current))
- fsp = &item->shared->current;
+ else if (cmd_find_valid_state(&item->state->current))
+ fsp = &item->state->current;
else if (cmd_find_from_client(&fs, item->client, 0) == 0)
fsp = &fs;
else
@@ -318,7 +567,7 @@ cmdq_fire_command(struct cmdq_item *item)
}
out:
- item->client = c;
+ item->client = saved;
if (retval == CMD_RETURN_ERROR)
cmdq_guard(item, "error", flags);
else
@@ -337,7 +586,7 @@ cmdq_get_callback1(const char *name, cmdq_cb cb, void *data)
item->type = CMDQ_CALLBACK;
item->group = 0;
- item->flags = 0;
+ item->state = cmdq_new_state(NULL, NULL, 0);
item->cb = cb;
item->data = data;
@@ -371,25 +620,6 @@ cmdq_fire_callback(struct cmdq_item *item)
return (item->cb(item, item->data));
}
-/* Add a format to command queue. */
-void
-cmdq_format(struct cmdq_item *item, const char *key, const char *fmt, ...)
-{
- struct cmdq_shared *shared = item->shared;
- va_list ap;
- char *value;
-
- va_start(ap, fmt);
- xvasprintf(&value, fmt, ap);
- va_end(ap);
-
- if (shared->formats == NULL)
- shared->formats = format_create(NULL, NULL, FORMAT_NONE, 0);
- format_add(shared->formats, key, "%s", value);
-
- free(value);
-}
-
/* Process next item on command queue. */
u_int
cmdq_next(struct client *c)
@@ -401,18 +631,18 @@ cmdq_next(struct client *c)
u_int items = 0;
static u_int number;
- if (TAILQ_EMPTY(queue)) {
+ if (TAILQ_EMPTY(&queue->list)) {
log_debug("%s %s: empty", __func__, name);
return (0);
}
- if (TAILQ_FIRST(queue)->flags & CMDQ_WAITING) {
+ if (TAILQ_FIRST(&queue->list)->flags & CMDQ_WAITING) {
log_debug("%s %s: waiting", __func__, name);
return (0);
}
log_debug("%s %s: enter", __func__, name);
for (;;) {
- item = TAILQ_FIRST(queue);
+ item = queue->item = TAILQ_FIRST(&queue->list);
if (item == NULL)
break;
log_debug("%s %s: %s (%d), flags %x", __func__, name,
@@ -462,6 +692,7 @@ cmdq_next(struct client *c)
}
cmdq_remove(item);
}
+ queue->item = NULL;
log_debug("%s %s: exit (empty)", __func__, name);
return (items);
@@ -471,6 +702,15 @@ waiting:
return (items);
}
+/* Get running item if any. */
+struct cmdq_item *
+cmdq_running(struct client *c)
+{
+ struct cmdq_list *queue = cmdq_get(c);
+
+ return (queue->item);
+}
+
/* Print a guard line. */
void
cmdq_guard(struct cmdq_item *item, const char *guard, int flags)
@@ -511,8 +751,10 @@ cmdq_print(struct cmdq_item *item, const char *fmt, ...)
} else {
wp = c->session->curw->window->active;
wme = TAILQ_FIRST(&wp->modes);
- if (wme == NULL || wme->mode != &window_view_mode)
- window_pane_set_mode(wp, &window_view_mode, NULL, NULL);
+ if (wme == NULL || wme->mode != &window_view_mode) {
+ window_pane_set_mode(wp, NULL, &window_view_mode, NULL,
+ NULL);
+ }
window_copy_add(wp, "%s", msg);
}
@@ -526,8 +768,9 @@ cmdq_error(struct cmdq_item *item, const char *fmt, ...)
struct client *c = item->client;
struct cmd *cmd = item->cmd;
va_list ap;
- char *msg;
- char *tmp;
+ char *msg, *tmp;
+ const char *file;
+ u_int line;
va_start(ap, fmt);
xvasprintf(&msg, fmt, ap);
@@ -535,9 +778,10 @@ cmdq_error(struct cmdq_item *item, const char *fmt, ...)
log_debug("%s: %s", __func__, msg);
- if (c == NULL)
- cfg_add_cause("%s:%u: %s", cmd->file, cmd->line, msg);
- else if (c->session == NULL || (c->flags & CLIENT_CONTROL)) {
+ if (c == NULL) {
+ cmd_get_source(cmd, &file, &line);
+ cfg_add_cause("%s:%u: %s", file, line, msg);
+ } else if (c->session == NULL || (c->flags & CLIENT_CONTROL)) {
if (~c->flags & CLIENT_UTF8) {
tmp = msg;
msg = utf8_sanitize(tmp);
diff --git a/cmd-refresh-client.c b/cmd-refresh-client.c
index b4c5e844..5514ff73 100644
--- a/cmd-refresh-client.c
+++ b/cmd-refresh-client.c
@@ -38,25 +38,21 @@ const struct cmd_entry cmd_refresh_client_entry = {
.usage = "[-cDlLRSU] [-C XxY] [-F flags] " CMD_TARGET_CLIENT_USAGE
" [adjustment]",
- .flags = CMD_AFTERHOOK,
+ .flags = CMD_AFTERHOOK|CMD_CLIENT_TFLAG,
.exec = cmd_refresh_client_exec
};
static enum cmd_retval
cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item)
{
- struct args *args = self->args;
- struct client *c;
- struct tty *tty;
+ struct args *args = cmd_get_args(self);
+ struct client *tc = cmdq_get_target_client(item);
+ struct tty *tty = &tc->tty;
struct window *w;
const char *size, *errstr;
char *copy, *next, *s;
u_int x, y, adjust;
- if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
- return (CMD_RETURN_ERROR);
- tty = &c->tty;
-
if (args_has(args, 'c') ||
args_has(args, 'L') ||
args_has(args, 'R') ||
@@ -74,48 +70,47 @@ cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item)
}
if (args_has(args, 'c'))
- c->pan_window = NULL;
+ tc->pan_window = NULL;
else {
- w = c->session->curw->window;
- if (c->pan_window != w) {
- c->pan_window = w;
- c->pan_ox = tty->oox;
- c->pan_oy = tty->ooy;
+ w = tc->session->curw->window;
+ if (tc->pan_window != w) {
+ tc->pan_window = w;
+ tc->pan_ox = tty->oox;
+ tc->pan_oy = tty->ooy;
}
if (args_has(args, 'L')) {
- if (c->pan_ox > adjust)
- c->pan_ox -= adjust;
+ if (tc->pan_ox > adjust)
+ tc->pan_ox -= adjust;
else
- c->pan_ox = 0;
+ tc->pan_ox = 0;
} else if (args_has(args, 'R')) {
- c->pan_ox += adjust;
- if (c->pan_ox > w->sx - tty->osx)
- c->pan_ox = w->sx - tty->osx;
+ tc->pan_ox += adjust;
+ if (tc->pan_ox > w->sx - tty->osx)
+ tc->pan_ox = w->sx - tty->osx;
} else if (args_has(args, 'U')) {
- if (c->pan_oy > adjust)
- c->pan_oy -= adjust;
+ if (tc->pan_oy > adjust)
+ tc->pan_oy -= adjust;
else
- c->pan_oy = 0;
+ tc->pan_oy = 0;
} else if (args_has(args, 'D')) {
- c->pan_oy += adjust;
- if (c->pan_oy > w->sy - tty->osy)
- c->pan_oy = w->sy - tty->osy;
+ tc->pan_oy += adjust;
+ if (tc->pan_oy > w->sy - tty->osy)
+ tc->pan_oy = w->sy - tty->osy;
}
}
- tty_update_client_offset(c);
- server_redraw_client(c);
+ tty_update_client_offset(tc);
+ server_redraw_client(tc);
return (CMD_RETURN_NORMAL);
}
if (args_has(args, 'l')) {
- if (c->session != NULL)
- tty_putcode_ptr2(&c->tty, TTYC_MS, "", "?");
+ tty_putcode_ptr2(&tc->tty, TTYC_MS, "", "?");
return (CMD_RETURN_NORMAL);
}
if (args_has(args, 'C') || args_has(args, 'F')) {
if (args_has(args, 'C')) {
- if (!(c->flags & CLIENT_CONTROL)) {
+ if (!(tc->flags & CLIENT_CONTROL)) {
cmdq_error(item, "not a control client");
return (CMD_RETURN_ERROR);
}
@@ -130,12 +125,12 @@ cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item)
cmdq_error(item, "size too small or too big");
return (CMD_RETURN_ERROR);
}
- tty_set_size(&c->tty, x, y, 0, 0);
- c->flags |= CLIENT_SIZECHANGED;
+ tty_set_size(&tc->tty, x, y, 0, 0);
+ tc->flags |= CLIENT_SIZECHANGED;
recalculate_sizes();
}
if (args_has(args, 'F')) {
- if (!(c->flags & CLIENT_CONTROL)) {
+ if (!(tc->flags & CLIENT_CONTROL)) {
cmdq_error(item, "not a control client");
return (CMD_RETURN_ERROR);
}
@@ -143,7 +138,7 @@ cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item)
while ((next = strsep(&s, ",")) != NULL) {
/* Unknown flags are ignored. */
if (strcmp(next, "no-output") == 0)
- c->flags |= CLIENT_CONTROL_NOOUTPUT;
+ tc->flags |= CLIENT_CONTROL_NOOUTPUT;
}
free(copy);
}
@@ -151,11 +146,11 @@ cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item)
}
if (args_has(args, 'S')) {
- c->flags |= CLIENT_STATUSFORCE;
- server_status_client(c);
+ tc->flags |= CLIENT_STATUSFORCE;
+ server_status_client(tc);
} else {
- c->flags |= CLIENT_STATUSFORCE;
- server_redraw_client(c);
+ tc->flags |= CLIENT_STATUSFORCE;
+ server_redraw_client(tc);
}
return (CMD_RETURN_NORMAL);
}
diff --git a/cmd-rename-session.c b/cmd-rename-session.c
index 8385434a..51b8ffc8 100644
--- a/cmd-rename-session.c
+++ b/cmd-rename-session.c
@@ -46,22 +46,18 @@ const struct cmd_entry cmd_rename_session_entry = {
static enum cmd_retval
cmd_rename_session_exec(struct cmd *self, struct cmdq_item *item)
{
- struct args *args = self->args;
- struct client *c = cmd_find_client(item, NULL, 1);
- struct session *s = item->target.s;
- char *newname;
-
- newname = format_single(item, args->argv[0], c, s, NULL, NULL);
+ struct args *args = cmd_get_args(self);
+ struct cmd_find_state *target = cmdq_get_target(item);
+ struct session *s = target->s;
+ char *newname, *tmp;
+
+ tmp = format_single_from_target(item, args->argv[0]);
+ newname = session_check_name(tmp);
+ free(tmp);
if (strcmp(newname, s->name) == 0) {
free(newname);
return (CMD_RETURN_NORMAL);
}
-
- if (!session_check_name(newname)) {
- cmdq_error(item, "bad session name: %s", newname);
- free(newname);
- return (CMD_RETURN_ERROR);
- }
if (session_find(newname) != NULL) {
cmdq_error(item, "duplicate session: %s", newname);
free(newname);
diff --git a/cmd-rename-window.c b/cmd-rename-window.c
index 4d2ebb75..593e0b9e 100644
--- a/cmd-rename-window.c
+++ b/cmd-rename-window.c
@@ -45,16 +45,16 @@ const struct cmd_entry cmd_rename_window_entry = {
static enum cmd_retval
cmd_rename_window_exec(struct cmd *self, struct cmdq_item *item)
{
- struct args *args = self->args;
- struct client *c = cmd_find_client(item, NULL, 1);
- struct session *s = item->target.s;
- struct winlink *wl = item->target.wl;
- char *newname;
+ struct args *args = cmd_get_args(self);
+ struct cmd_find_state *target = cmdq_get_target(item);
+ struct winlink *wl = target->wl;
+ char *newname;
- newname = format_single(item, args->argv[0], c, s, wl, NULL);
+ newname = format_single_from_target(item, args->argv[0]);
window_set_name(wl->window, newname);
options_set_number(wl->window->options, "automatic-rename", 0);
+ server_redraw_window_borders(wl->window);
server_status_window(wl->window);
free(newname);
diff --git a/cmd-resize-pane.c b/cmd-resize-pane.c
index 3962546d..563c95fb 100644
--- a/cmd-resize-pane.c
+++ b/cmd-resize-pane.c
@@ -36,8 +36,8 @@ const struct cmd_entry cmd_resize_pane_entry = {
.name = "resize-pane",
.alias = "resizep",
- .args = { "DLMRt:Ux:y:Z", 0, 1 },
- .usage = "[-DLMRUZ] [-x width] [-y height] " CMD_TARGET_PANE_USAGE " "
+ .args = { "DLMRTt:Ux:y:Z", 0, 1 },
+ .usage = "[-DLMRTUZ] [-x width] [-y height] " CMD_TARGET_PANE_USAGE " "
"[adjustment]",
.target = { 't', CMD_FIND_PANE, 0 },
@@ -49,26 +49,39 @@ const struct cmd_entry cmd_resize_pane_entry = {
static enum cmd_retval
cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
{
- struct args *args = self->args;
- struct cmdq_shared *shared = item->shared;
- struct window_pane *wp = item->target.wp;
- struct winlink *wl = item->target.wl;
+ struct args *args = cmd_get_args(self);
+ struct cmd_find_state *target = cmdq_get_target(item);
+ struct key_event *event = cmdq_get_event(item);
+ struct window_pane *wp = target->wp;
+ struct winlink *wl = target->wl;
struct window *w = wl->window;
- struct client *c = item->client;
- struct session *s = item->target.s;
- const char *errstr, *p;
- char *cause, *copy;
+ struct client *c = cmdq_get_client(item);
+ struct session *s = target->s;
+ const char *errstr;
+ char *cause;
u_int adjust;
- int x, y, percentage;
- size_t plen;
+ int x, y;
+ struct grid *gd = wp->base.grid;
+
+ if (args_has(args, 'T')) {
+ if (!TAILQ_EMPTY(&wp->modes))
+ return (CMD_RETURN_NORMAL);
+ adjust = screen_size_y(&wp->base) - 1 - wp->base.cy;
+ if (adjust > gd->hsize)
+ adjust = gd->hsize;
+ grid_remove_history(gd, adjust);
+ wp->base.cy += adjust;
+ wp->flags |= PANE_REDRAW;
+ return (CMD_RETURN_NORMAL);
+ }
if (args_has(args, 'M')) {
- if (cmd_mouse_window(&shared->mouse, &s) == NULL)
+ if (!event->m.valid || cmd_mouse_window(&event->m, &s) == NULL)
return (CMD_RETURN_NORMAL);
if (c == NULL || c->session != s)
return (CMD_RETURN_NORMAL);
c->tty.mouse_drag_update = cmd_resize_pane_mouse_update;
- cmd_resize_pane_mouse_update(c, &shared->mouse);
+ cmd_resize_pane_mouse_update(c, &event->m);
return (CMD_RETURN_NORMAL);
}
@@ -78,7 +91,6 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
else
window_zoom(wp);
server_redraw_window(w);
- server_status_window(w);
return (CMD_RETURN_NORMAL);
}
server_unzoom_window(w);
@@ -93,58 +105,21 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
}
}
- if ((p = args_get(args, 'x')) != NULL) {
- plen = strlen(p);
- if (p[plen - 1] == '%') {
- copy = xstrdup(p);
- copy[plen - 1] = '\0';
- percentage = strtonum(copy, 0, INT_MAX, &errstr);
- free(copy);
- if (errstr != NULL) {
- cmdq_error(item, "width %s", errstr);
- return (CMD_RETURN_ERROR);
- }
- x = (w->sx * percentage) / 100;
- if (x < PANE_MINIMUM)
- x = PANE_MINIMUM;
- if (x > INT_MAX)
- x = INT_MAX;
- } else {
- x = args_strtonum(args, 'x', PANE_MINIMUM, INT_MAX,
- &cause);
- if (cause != NULL) {
- cmdq_error(item, "width %s", cause);
- free(cause);
- return (CMD_RETURN_ERROR);
- }
+ if (args_has(args, 'x')) {
+ x = args_percentage(args, 'x', 0, INT_MAX, w->sx, &cause);
+ if (cause != NULL) {
+ cmdq_error(item, "width %s", cause);
+ free(cause);
+ return (CMD_RETURN_ERROR);
}
layout_resize_pane_to(wp, LAYOUT_LEFTRIGHT, x);
}
- if ((p = args_get(args, 'y')) != NULL) {
- plen = strlen(p);
- if (p[plen - 1] == '%') {
- copy = xstrdup(p);
- copy[plen - 1] = '\0';
- percentage = strtonum(copy, 0, INT_MAX, &errstr);
- free(copy);
- if (errstr != NULL) {
- cmdq_error(item, "height %s", errstr);
- return (CMD_RETURN_ERROR);
- }
- y = (w->sy * percentage) / 100;
- if (y < PANE_MINIMUM)
- y = PANE_MINIMUM;
- if (y > INT_MAX)
- y = INT_MAX;
- }
- else {
- y = args_strtonum(args, 'y', PANE_MINIMUM, INT_MAX,
- &cause);
- if (cause != NULL) {
- cmdq_error(item, "height %s", cause);
- free(cause);
- return (CMD_RETURN_ERROR);
- }
+ if (args_has(args, 'y')) {
+ y = args_percentage(args, 'y', 0, INT_MAX, w->sy, &cause);
+ if (cause != NULL) {
+ cmdq_error(item, "width %s", cause);
+ free(cause);
+ return (CMD_RETURN_ERROR);
}
layout_resize_pane_to(wp, LAYOUT_TOPBOTTOM, y);
}
diff --git a/cmd-resize-window.c b/cmd-resize-window.c
index 9cc74e82..1ebb7aca 100644
--- a/cmd-resize-window.c
+++ b/cmd-resize-window.c
@@ -46,10 +46,11 @@ const struct cmd_entry cmd_resize_window_entry = {
static enum cmd_retval
cmd_resize_window_exec(struct cmd *self, struct cmdq_item *item)
{
- struct args *args = self->args;
- struct winlink *wl = item->target.wl;
+ struct args *args = cmd_get_args(self);
+ struct cmd_find_state *target = cmdq_get_target(item);
+ struct winlink *wl = target->wl;
struct window *w = wl->window;
- struct session *s = item->target.s;
+ struct session *s = target->s;
const char *errstr;
char *cause;
u_int adjust, sx, sy;
diff --git a/cmd-respawn-pane.c b/cmd-respawn-pane.c
index 5e23fa15..9db280b4 100644
--- a/cmd-respawn-pane.c
+++ b/cmd-respawn-pane.c
@@ -47,11 +47,12 @@ const struct cmd_entry cmd_respawn_pane_entry = {
static enum cmd_retval
cmd_respawn_pane_exec(struct cmd *self, struct cmdq_item *item)
{
- struct args *args = self->args;
+ struct args *args = cmd_get_args(self);
+ struct cmd_find_state *target = cmdq_get_target(item);
struct spawn_context sc;
- struct session *s = item->target.s;
- struct winlink *wl = item->target.wl;
- struct window_pane *wp = item->target.wp;
+ struct session *s = target->s;
+ struct winlink *wl = target->wl;
+ struct window_pane *wp = target->wp;
char *cause = NULL;
const char *add;
struct args_value *value;
@@ -71,7 +72,7 @@ cmd_respawn_pane_exec(struct cmd *self, struct cmdq_item *item)
add = args_first_value(args, 'e', &value);
while (add != NULL) {
- environ_put(sc.environ, add);
+ environ_put(sc.environ, add, 0);
add = args_next_value(&value);
}
@@ -89,6 +90,7 @@ cmd_respawn_pane_exec(struct cmd *self, struct cmdq_item *item)
}
wp->flags |= PANE_REDRAW;
+ server_redraw_window_borders(wp->window);
server_status_window(wp->window);
environ_free(sc.environ);
diff --git a/cmd-respawn-window.c b/cmd-respawn-window.c
index 497e401e..39d19ddb 100644
--- a/cmd-respawn-window.c
+++ b/cmd-respawn-window.c
@@ -47,10 +47,12 @@ const struct cmd_entry cmd_respawn_window_entry = {
static enum cmd_retval
cmd_respawn_window_exec(struct cmd *self, struct cmdq_item *item)
{
- struct args *args = self->args;
+ struct args *args = cmd_get_args(self);
+ struct cmd_find_state *target = cmdq_get_target(item);
struct spawn_context sc;
- struct session *s = item->target.s;
- struct winlink *wl = item->target.wl;
+ struct client *tc = cmdq_get_target_client(item);
+ struct session *s = target->s;
+ struct winlink *wl = target->wl;
char *cause = NULL;
const char *add;
struct args_value *value;
@@ -59,7 +61,7 @@ cmd_respawn_window_exec(struct cmd *self, struct cmdq_item *item)
sc.item = item;
sc.s = s;
sc.wl = wl;
- sc.c = cmd_find_client(item, NULL, 1);
+ sc.tc = tc;
sc.name = NULL;
sc.argc = args->argc;
@@ -68,7 +70,7 @@ cmd_respawn_window_exec(struct cmd *self, struct cmdq_item *item)
add = args_first_value(args, 'e', &value);
while (add != NULL) {
- environ_put(sc.environ, add);
+ environ_put(sc.environ, add, 0);
add = args_next_value(&value);
}
diff --git a/cmd-rotate-window.c b/cmd-rotate-window.c
index cc661163..55c1dde2 100644
--- a/cmd-rotate-window.c
+++ b/cmd-rotate-window.c
@@ -43,16 +43,18 @@ const struct cmd_entry cmd_rotate_window_entry = {
static enum cmd_retval
cmd_rotate_window_exec(struct cmd *self, struct cmdq_item *item)
{
- struct cmd_find_state *current = &item->shared->current;
- struct winlink *wl = item->target.wl;
+ struct args *args = cmd_get_args(self);
+ struct cmd_find_state *current = cmdq_get_current(item);
+ struct cmd_find_state *target = cmdq_get_target(item);
+ struct winlink *wl = target->wl;
struct window *w = wl->window;
struct window_pane *wp, *wp2;
struct layout_cell *lc;
u_int sx, sy, xoff, yoff;
- window_push_zoom(w, args_has(self->args, 'Z'));
+ window_push_zoom(w, args_has(args, 'Z'));
- if (args_has(self->args, 'D')) {
+ if (args_has(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 2f45f492..82d4a1a2 100644
--- a/cmd-run-shell.c
+++ b/cmd-run-shell.c
@@ -31,6 +31,7 @@
static enum cmd_retval cmd_run_shell_exec(struct cmd *, struct cmdq_item *);
+static void cmd_run_shell_timer(int, short, void *);
static void cmd_run_shell_callback(struct job *);
static void cmd_run_shell_free(void *);
static void cmd_run_shell_print(struct job *, const char *);
@@ -39,8 +40,8 @@ const struct cmd_entry cmd_run_shell_entry = {
.name = "run-shell",
.alias = "run",
- .args = { "bt:", 1, 1 },
- .usage = "[-b] " CMD_TARGET_PANE_USAGE " shell-command",
+ .args = { "bd:t:", 0, 1 },
+ .usage = "[-b] [-d delay] " CMD_TARGET_PANE_USAGE " [shell-command]",
.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
@@ -50,8 +51,11 @@ const struct cmd_entry cmd_run_shell_entry = {
struct cmd_run_shell_data {
char *cmd;
+ char *cwd;
struct cmdq_item *item;
+ struct session *s;
int wp_id;
+ struct event timer;
};
static void
@@ -78,22 +82,26 @@ cmd_run_shell_print(struct job *job, const char *msg)
wme = TAILQ_FIRST(&wp->modes);
if (wme == NULL || wme->mode != &window_view_mode)
- window_pane_set_mode(wp, &window_view_mode, NULL, NULL);
+ window_pane_set_mode(wp, NULL, &window_view_mode, NULL, NULL);
window_copy_add(wp, "%s", msg);
}
static enum cmd_retval
cmd_run_shell_exec(struct cmd *self, struct cmdq_item *item)
{
- struct args *args = self->args;
+ struct args *args = cmd_get_args(self);
+ struct cmd_find_state *target = cmdq_get_target(item);
struct cmd_run_shell_data *cdata;
- struct client *c = cmd_find_client(item, NULL, 1);
- struct session *s = item->target.s;
- struct winlink *wl = item->target.wl;
- struct window_pane *wp = item->target.wp;
+ struct session *s = target->s;
+ struct window_pane *wp = target->wp;
+ const char *delay;
+ double d;
+ struct timeval tv;
+ char *end;
cdata = xcalloc(1, sizeof *cdata);
- cdata->cmd = format_single(item, args->argv[0], c, s, wl, wp);
+ if (args->argc != 0)
+ cdata->cmd = format_single_from_target(item, args->argv[0]);
if (args_has(args, 't') && wp != NULL)
cdata->wp_id = wp->id;
@@ -103,12 +111,26 @@ cmd_run_shell_exec(struct cmd *self, struct cmdq_item *item)
if (!args_has(args, 'b'))
cdata->item = item;
- if (job_run(cdata->cmd, s, server_client_get_cwd(item->client, s), NULL,
- cmd_run_shell_callback, cmd_run_shell_free, cdata, 0) == NULL) {
- cmdq_error(item, "failed to run command: %s", cdata->cmd);
- free(cdata);
- return (CMD_RETURN_ERROR);
- }
+ cdata->cwd = xstrdup(server_client_get_cwd(cmdq_get_client(item), s));
+ cdata->s = s;
+ if (s != NULL)
+ session_add_ref(s, __func__);
+
+ evtimer_set(&cdata->timer, cmd_run_shell_timer, cdata);
+
+ if ((delay = args_get(args, 'd')) != NULL) {
+ d = strtod(delay, &end);
+ if (*end != '\0') {
+ cmdq_error(item, "invalid delay time: %s", delay);
+ cmd_run_shell_free(cdata);
+ return (CMD_RETURN_ERROR);
+ }
+ timerclear(&tv);
+ tv.tv_sec = (time_t)d;
+ tv.tv_usec = (d - (double)tv.tv_sec) * 1000000U;
+ evtimer_add(&cdata->timer, &tv);
+ } else
+ cmd_run_shell_timer(-1, 0, cdata);
if (args_has(args, 'b'))
return (CMD_RETURN_NORMAL);
@@ -116,10 +138,28 @@ cmd_run_shell_exec(struct cmd *self, struct cmdq_item *item)
}
static void
+cmd_run_shell_timer(__unused int fd, __unused short events, void* arg)
+{
+ struct cmd_run_shell_data *cdata = arg;
+
+ if (cdata->cmd != NULL) {
+ if (job_run(cdata->cmd, cdata->s, cdata->cwd, NULL,
+ cmd_run_shell_callback, cmd_run_shell_free, cdata, 0, -1,
+ -1) == NULL)
+ cmd_run_shell_free(cdata);
+ } else {
+ if (cdata->item != NULL)
+ cmdq_continue(cdata->item);
+ cmd_run_shell_free(cdata);
+ }
+}
+
+static void
cmd_run_shell_callback(struct job *job)
{
struct cmd_run_shell_data *cdata = job_get_data(job);
struct bufferevent *event = job_get_event(job);
+ struct cmdq_item *item = cdata->item;
char *cmd = cdata->cmd, *msg = NULL, *line;
size_t size;
int retcode, status;
@@ -149,13 +189,18 @@ cmd_run_shell_callback(struct job *job)
} else if (WIFSIGNALED(status)) {
retcode = WTERMSIG(status);
xasprintf(&msg, "'%s' terminated by signal %d", cmd, retcode);
+ retcode += 128;
}
if (msg != NULL)
cmd_run_shell_print(job, msg);
free(msg);
- if (cdata->item != NULL)
- cmdq_continue(cdata->item);
+ if (item != NULL) {
+ if (cmdq_get_client(item) != NULL &&
+ cmdq_get_client(item)->session == NULL)
+ cmdq_get_client(item)->retval = retcode;
+ cmdq_continue(item);
+ }
}
static void
@@ -163,6 +208,10 @@ cmd_run_shell_free(void *data)
{
struct cmd_run_shell_data *cdata = data;
+ evtimer_del(&cdata->timer);
+ if (cdata->s != NULL)
+ session_remove_ref(cdata->s, __func__);
+ free(cdata->cwd);
free(cdata->cmd);
free(cdata);
}
diff --git a/cmd-save-buffer.c b/cmd-save-buffer.c
index 84e50242..656a89e1 100644
--- a/cmd-save-buffer.c
+++ b/cmd-save-buffer.c
@@ -72,11 +72,7 @@ cmd_save_buffer_done(__unused struct client *c, const char *path, int error,
static enum cmd_retval
cmd_save_buffer_exec(struct cmd *self, struct cmdq_item *item)
{
- struct args *args = self->args;
- struct client *c = cmd_find_client(item, NULL, 1);
- struct session *s = item->target.s;
- struct winlink *wl = item->target.wl;
- struct window_pane *wp = item->target.wp;
+ struct args *args = cmd_get_args(self);
struct paste_buffer *pb;
int flags;
const char *bufname = args_get(args, 'b'), *bufdata;
@@ -97,15 +93,15 @@ cmd_save_buffer_exec(struct cmd *self, struct cmdq_item *item)
}
bufdata = paste_buffer_data(pb, &bufsize);
- if (self->entry == &cmd_show_buffer_entry)
+ if (cmd_get_entry(self) == &cmd_show_buffer_entry)
path = xstrdup("-");
else
- path = format_single(item, args->argv[0], c, s, wl, wp);
- if (args_has(self->args, 'a'))
+ path = format_single_from_target(item, args->argv[0]);
+ if (args_has(args, 'a'))
flags = O_APPEND;
else
flags = 0;
- file_write(item->client, path, flags, bufdata, bufsize,
+ file_write(cmdq_get_client(item), path, flags, bufdata, bufsize,
cmd_save_buffer_done, item);
free(path);
diff --git a/cmd-select-layout.c b/cmd-select-layout.c
index 775d32c5..7069eccc 100644
--- a/cmd-select-layout.c
+++ b/cmd-select-layout.c
@@ -71,20 +71,21 @@ const struct cmd_entry cmd_previous_layout_entry = {
static enum cmd_retval
cmd_select_layout_exec(struct cmd *self, struct cmdq_item *item)
{
- struct args *args = self->args;
- struct winlink *wl = item->target.wl;
+ struct args *args = cmd_get_args(self);
+ struct cmd_find_state *target = cmdq_get_target(item);
+ struct winlink *wl = target->wl;
struct window *w = wl->window;
- struct window_pane *wp = item->target.wp;
+ struct window_pane *wp = target->wp;
const char *layoutname;
char *oldlayout;
int next, previous, layout;
server_unzoom_window(w);
- next = self->entry == &cmd_next_layout_entry;
+ next = (cmd_get_entry(self) == &cmd_next_layout_entry);
if (args_has(args, 'n'))
next = 1;
- previous = self->entry == &cmd_previous_layout_entry;
+ previous = (cmd_get_entry(self) == &cmd_previous_layout_entry);
if (args_has(args, 'p'))
previous = 1;
diff --git a/cmd-select-pane.c b/cmd-select-pane.c
index c63c7e61..224370ab 100644
--- a/cmd-select-pane.c
+++ b/cmd-select-pane.c
@@ -83,19 +83,20 @@ cmd_select_pane_redraw(struct window *w)
static enum cmd_retval
cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
{
- struct args *args = self->args;
- struct cmd_find_state *current = &item->shared->current;
- struct client *c = cmd_find_client(item, NULL, 1);
- struct winlink *wl = item->target.wl;
+ struct args *args = cmd_get_args(self);
+ const struct cmd_entry *entry = cmd_get_entry(self);
+ struct cmd_find_state *current = cmdq_get_current(item);
+ struct cmd_find_state *target = cmdq_get_target(item);
+ struct winlink *wl = target->wl;
struct window *w = wl->window;
- struct session *s = item->target.s;
- struct window_pane *wp = item->target.wp, *lastwp, *markedwp;
- char *pane_title;
+ struct session *s = target->s;
+ struct window_pane *wp = target->wp, *lastwp, *markedwp;
+ struct options *oo = wp->options;
+ char *title;
const char *style;
- struct style *sy;
struct options_entry *o;
- if (self->entry == &cmd_last_pane_entry || args_has(args, 'l')) {
+ if (entry == &cmd_last_pane_entry || args_has(args, 'l')) {
lastwp = w->last;
if (lastwp == NULL && window_count_panes(w) == 2) {
lastwp = TAILQ_PREV(w->active, window_panes, entry);
@@ -106,12 +107,12 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
cmdq_error(item, "no last pane");
return (CMD_RETURN_ERROR);
}
- if (args_has(self->args, 'e'))
+ if (args_has(args, 'e'))
lastwp->flags &= ~PANE_INPUTOFF;
- else if (args_has(self->args, 'd'))
+ else if (args_has(args, 'd'))
lastwp->flags |= PANE_INPUTOFF;
else {
- if (window_push_zoom(w, args_has(self->args, 'Z')))
+ if (window_push_zoom(w, args_has(args, 'Z')))
server_redraw_window(w);
window_redraw_active_switch(w, lastwp);
if (window_set_active_pane(w, lastwp, 1)) {
@@ -146,38 +147,34 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_NORMAL);
}
- if (args_has(self->args, 'P') || args_has(self->args, 'g')) {
- if ((style = args_get(args, 'P')) != NULL) {
- o = options_set_style(wp->options, "window-style", 0,
- style);
- if (o == NULL) {
- cmdq_error(item, "bad style: %s", style);
- return (CMD_RETURN_ERROR);
- }
- options_set_style(wp->options, "window-active-style", 0,
- style);
- wp->flags |= (PANE_REDRAW|PANE_STYLECHANGED);
- }
- if (args_has(self->args, 'g')) {
- sy = options_get_style(wp->options, "window-style");
- cmdq_print(item, "%s", style_tostring(sy));
+ style = args_get(args, 'P');
+ if (style != NULL) {
+ o = options_set_string(oo, "window-style", 0, "%s", style);
+ if (o == NULL) {
+ cmdq_error(item, "bad style: %s", style);
+ return (CMD_RETURN_ERROR);
}
+ options_set_string(oo, "window-active-style", 0, "%s", style);
+ wp->flags |= (PANE_REDRAW|PANE_STYLECHANGED);
+ }
+ if (args_has(args, 'g')) {
+ cmdq_print(item, "%s", options_get_string(oo, "window-style"));
return (CMD_RETURN_NORMAL);
}
- if (args_has(self->args, 'L')) {
+ if (args_has(args, 'L')) {
window_push_zoom(w, 1);
wp = window_pane_find_left(wp);
window_pop_zoom(w);
- } else if (args_has(self->args, 'R')) {
+ } else if (args_has(args, 'R')) {
window_push_zoom(w, 1);
wp = window_pane_find_right(wp);
window_pop_zoom(w);
- } else if (args_has(self->args, 'U')) {
+ } else if (args_has(args, 'U')) {
window_push_zoom(w, 1);
wp = window_pane_find_up(wp);
window_pop_zoom(w);
- } else if (args_has(self->args, 'D')) {
+ } else if (args_has(args, 'D')) {
window_push_zoom(w, 1);
wp = window_pane_find_down(wp);
window_pop_zoom(w);
@@ -185,27 +182,28 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
if (wp == NULL)
return (CMD_RETURN_NORMAL);
- if (args_has(self->args, 'e')) {
+ if (args_has(args, 'e')) {
wp->flags &= ~PANE_INPUTOFF;
return (CMD_RETURN_NORMAL);
}
- if (args_has(self->args, 'd')) {
+ if (args_has(args, 'd')) {
wp->flags |= PANE_INPUTOFF;
return (CMD_RETURN_NORMAL);
}
- if (args_has(self->args, 'T')) {
- pane_title = format_single(item, args_get(self->args, 'T'),
- c, s, wl, wp);
- if (screen_set_title(&wp->base, pane_title))
+ if (args_has(args, 'T')) {
+ title = format_single_from_target(item, args_get(args, 'T'));
+ if (screen_set_title(&wp->base, title)) {
+ server_redraw_window_borders(wp->window);
server_status_window(wp->window);
- free(pane_title);
+ }
+ free(title);
return (CMD_RETURN_NORMAL);
}
if (wp == w->active)
return (CMD_RETURN_NORMAL);
- if (window_push_zoom(w, args_has(self->args, 'Z')))
+ if (window_push_zoom(w, args_has(args, 'Z')))
server_redraw_window(w);
window_redraw_active_switch(w, wp);
if (window_set_active_pane(w, wp, 1)) {
diff --git a/cmd-select-window.c b/cmd-select-window.c
index 54965e89..377e3633 100644
--- a/cmd-select-window.c
+++ b/cmd-select-window.c
@@ -84,23 +84,25 @@ const struct cmd_entry cmd_last_window_entry = {
static enum cmd_retval
cmd_select_window_exec(struct cmd *self, struct cmdq_item *item)
{
- struct cmd_find_state *current = &item->shared->current;
- struct winlink *wl = item->target.wl;
- struct session *s = item->target.s;
+ struct args *args = cmd_get_args(self);
+ struct cmd_find_state *current = cmdq_get_current(item);
+ struct cmd_find_state *target = cmdq_get_target(item);
+ struct winlink *wl = target->wl;
+ struct session *s = target->s;
int next, previous, last, activity;
- next = self->entry == &cmd_next_window_entry;
- if (args_has(self->args, 'n'))
+ next = (cmd_get_entry(self) == &cmd_next_window_entry);
+ if (args_has(args, 'n'))
next = 1;
- previous = self->entry == &cmd_previous_window_entry;
- if (args_has(self->args, 'p'))
+ previous = (cmd_get_entry(self) == &cmd_previous_window_entry);
+ if (args_has(args, 'p'))
previous = 1;
- last = self->entry == &cmd_last_window_entry;
- if (args_has(self->args, 'l'))
+ last = (cmd_get_entry(self) == &cmd_last_window_entry);
+ if (args_has(args, 'l'))
last = 1;
if (next || previous || last) {
- activity = args_has(self->args, 'a');
+ activity = args_has(args, 'a');
if (next) {
if (session_next(s, activity) != 0) {
cmdq_error(item, "no next window");
@@ -125,7 +127,7 @@ cmd_select_window_exec(struct cmd *self, struct cmdq_item *item)
* If -T and select-window is invoked on same window as
* current, switch to previous window.
*/
- if (args_has(self->args, 'T') && wl == s->curw) {
+ if (args_has(args, 'T') && wl == s->curw) {
if (session_last(s) != 0) {
cmdq_error(item, "no last window");
return (-1);
diff --git a/cmd-send-keys.c b/cmd-send-keys.c
index cc04a73f..afaf0a81 100644
--- a/cmd-send-keys.c
+++ b/cmd-send-keys.c
@@ -57,21 +57,23 @@ const struct cmd_entry cmd_send_prefix_entry = {
};
static struct cmdq_item *
-cmd_send_keys_inject_key(struct client *c, struct cmd_find_state *fs,
- struct cmdq_item *item, key_code key)
+cmd_send_keys_inject_key(struct cmdq_item *item, struct cmdq_item *after,
+ key_code key)
{
- struct session *s = fs->s;
- struct winlink *wl = fs->wl;
- struct window_pane *wp = fs->wp;
+ struct cmd_find_state *target = cmdq_get_target(item);
+ struct client *tc = cmdq_get_target_client(item);
+ struct session *s = target->s;
+ struct winlink *wl = target->wl;
+ struct window_pane *wp = target->wp;
struct window_mode_entry *wme;
struct key_table *table;
struct key_binding *bd;
- wme = TAILQ_FIRST(&fs->wp->modes);
+ wme = TAILQ_FIRST(&wp->modes);
if (wme == NULL || wme->mode->key_table == NULL) {
- if (options_get_number(fs->wp->window->options, "xterm-keys"))
+ if (options_get_number(wp->window->options, "xterm-keys"))
key |= KEYC_XTERM;
- if (window_pane_key(wp, item->client, s, wl, key, NULL) != 0)
+ if (window_pane_key(wp, tc, s, wl, key, NULL) != 0)
return (NULL);
return (item);
}
@@ -80,18 +82,17 @@ cmd_send_keys_inject_key(struct client *c, struct cmd_find_state *fs,
bd = key_bindings_get(table, key & ~KEYC_XTERM);
if (bd != NULL) {
table->references++;
- item = key_bindings_dispatch(bd, item, c, NULL, &item->target);
+ after = key_bindings_dispatch(bd, after, tc, NULL, target);
key_bindings_unref_table(table);
}
- return (item);
+ return (after);
}
static struct cmdq_item *
-cmd_send_keys_inject_string(struct client *c, struct cmd_find_state *fs,
- struct cmdq_item *item, struct args *args, int i)
+cmd_send_keys_inject_string(struct cmdq_item *item, struct cmdq_item *after,
+ struct args *args, int i)
{
const char *s = args->argv[i];
- struct cmdq_item *new_item;
struct utf8_data *ud, *uc;
wchar_t wc;
key_code key;
@@ -103,16 +104,16 @@ cmd_send_keys_inject_string(struct client *c, struct cmd_find_state *fs,
n = strtol(s, &endptr, 16);
if (*s =='\0' || n < 0 || n > 0xff || *endptr != '\0')
return (item);
- return (cmd_send_keys_inject_key(c, fs, item, KEYC_LITERAL|n));
+ return (cmd_send_keys_inject_key(item, after, KEYC_LITERAL|n));
}
literal = args_has(args, 'l');
if (!literal) {
key = key_string_lookup_string(s);
if (key != KEYC_NONE && key != KEYC_UNKNOWN) {
- new_item = cmd_send_keys_inject_key(c, fs, item, key);
- if (new_item != NULL)
- return (new_item);
+ after = cmd_send_keys_inject_key(item, after, key);
+ if (after != NULL)
+ return (after);
}
literal = 1;
}
@@ -121,24 +122,26 @@ cmd_send_keys_inject_string(struct client *c, struct cmd_find_state *fs,
for (uc = ud; uc->size != 0; uc++) {
if (utf8_combine(uc, &wc) != UTF8_DONE)
continue;
- item = cmd_send_keys_inject_key(c, fs, item, wc);
+ after = cmd_send_keys_inject_key(item, after, wc);
}
free(ud);
}
- return (item);
+ return (after);
}
static enum cmd_retval
cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
{
- struct args *args = self->args;
- struct client *c = cmd_find_client(item, NULL, 1);
- struct cmd_find_state *fs = &item->target;
- struct window_pane *wp = item->target.wp;
- struct session *s = item->target.s;
- struct winlink *wl = item->target.wl;
- struct mouse_event *m = &item->shared->mouse;
+ struct args *args = cmd_get_args(self);
+ struct cmd_find_state *target = cmdq_get_target(item);
+ struct client *tc = cmdq_get_target_client(item);
+ struct session *s = target->s;
+ struct winlink *wl = target->wl;
+ struct window_pane *wp = target->wp;
+ struct key_event *event = cmdq_get_event(item);
+ struct mouse_event *m = &event->m;
struct window_mode_entry *wme = TAILQ_FIRST(&wp->modes);
+ struct cmdq_item *after = item;
int i;
key_code key;
u_int np = 1;
@@ -152,7 +155,7 @@ cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_ERROR);
}
if (wme != NULL && (args_has(args, 'X') || args->argc == 0)) {
- if (wme == NULL || wme->mode->command == NULL) {
+ if (wme->mode->command == NULL) {
cmdq_error(item, "not in a mode");
return (CMD_RETURN_ERROR);
}
@@ -167,7 +170,7 @@ cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
}
if (!m->valid)
m = NULL;
- wme->mode->command(wme, c, s, wl, args, m);
+ wme->mode->command(wme, tc, s, wl, args, m);
return (CMD_RETURN_NORMAL);
}
@@ -177,27 +180,29 @@ cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
cmdq_error(item, "no mouse target");
return (CMD_RETURN_ERROR);
}
- window_pane_key(wp, item->client, s, wl, m->key, m);
+ window_pane_key(wp, tc, s, wl, m->key, m);
return (CMD_RETURN_NORMAL);
}
- if (self->entry == &cmd_send_prefix_entry) {
+ if (cmd_get_entry(self) == &cmd_send_prefix_entry) {
if (args_has(args, '2'))
key = options_get_number(s->options, "prefix2");
else
key = options_get_number(s->options, "prefix");
- cmd_send_keys_inject_key(c, fs, item, key);
+ cmd_send_keys_inject_key(item, item, key);
return (CMD_RETURN_NORMAL);
}
if (args_has(args, 'R')) {
window_pane_reset_palette(wp);
- input_reset(wp, 1);
+ input_reset(wp->ictx, 1);
}
for (; np != 0; np--) {
- for (i = 0; i < args->argc; i++)
- item = cmd_send_keys_inject_string(c, fs, item, args, i);
+ for (i = 0; i < args->argc; i++) {
+ after = cmd_send_keys_inject_string(item, after, args,
+ i);
+ }
}
return (CMD_RETURN_NORMAL);
diff --git a/cmd-set-buffer.c b/cmd-set-buffer.c
index 96fdf450..0f3fffce 100644
--- a/cmd-set-buffer.c
+++ b/cmd-set-buffer.c
@@ -54,7 +54,7 @@ const struct cmd_entry cmd_delete_buffer_entry = {
static enum cmd_retval
cmd_set_buffer_exec(struct cmd *self, struct cmdq_item *item)
{
- struct args *args = self->args;
+ struct args *args = cmd_get_args(self);
struct paste_buffer *pb;
char *bufdata, *cause;
const char *bufname, *olddata;
@@ -66,7 +66,7 @@ cmd_set_buffer_exec(struct cmd *self, struct cmdq_item *item)
else
pb = paste_get_name(bufname);
- if (self->entry == &cmd_delete_buffer_entry) {
+ if (cmd_get_entry(self) == &cmd_delete_buffer_entry) {
if (pb == NULL)
pb = paste_get_top(&bufname);
if (pb == NULL) {
diff --git a/cmd-set-environment.c b/cmd-set-environment.c
index a80acd01..3c43b635 100644
--- a/cmd-set-environment.c
+++ b/cmd-set-environment.c
@@ -34,8 +34,8 @@ const struct cmd_entry cmd_set_environment_entry = {
.name = "set-environment",
.alias = "setenv",
- .args = { "grt:u", 1, 2 },
- .usage = "[-gru] " CMD_TARGET_SESSION_USAGE " name [value]",
+ .args = { "hgrt:u", 1, 2 },
+ .usage = "[-hgru] " CMD_TARGET_SESSION_USAGE " name [value]",
.target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
@@ -46,9 +46,10 @@ const struct cmd_entry cmd_set_environment_entry = {
static enum cmd_retval
cmd_set_environment_exec(struct cmd *self, struct cmdq_item *item)
{
- struct args *args = self->args;
- struct environ *env;
- const char *name, *value, *target;
+ struct args *args = cmd_get_args(self);
+ struct cmd_find_state *target = cmdq_get_target(item);
+ struct environ *env;
+ const char *name, *value, *tflag;
name = args->argv[0];
if (*name == '\0') {
@@ -65,27 +66,27 @@ cmd_set_environment_exec(struct cmd *self, struct cmdq_item *item)
else
value = args->argv[1];
- if (args_has(self->args, 'g'))
+ if (args_has(args, 'g'))
env = global_environ;
else {
- if (item->target.s == NULL) {
- target = args_get(args, 't');
- if (target != NULL)
- cmdq_error(item, "no such session: %s", target);
+ if (target->s == NULL) {
+ tflag = args_get(args, 't');
+ if (tflag != NULL)
+ cmdq_error(item, "no such session: %s", tflag);
else
cmdq_error(item, "no current session");
return (CMD_RETURN_ERROR);
}
- env = item->target.s->environ;
+ env = target->s->environ;
}
- if (args_has(self->args, 'u')) {
+ if (args_has(args, 'u')) {
if (value != NULL) {
cmdq_error(item, "can't specify a value with -u");
return (CMD_RETURN_ERROR);
}
environ_unset(env, name);
- } else if (args_has(self->args, 'r')) {
+ } else if (args_has(args, 'r')) {
if (value != NULL) {
cmdq_error(item, "can't specify a value with -r");
return (CMD_RETURN_ERROR);
@@ -96,7 +97,10 @@ cmd_set_environment_exec(struct cmd *self, struct cmdq_item *item)
cmdq_error(item, "no value specified");
return (CMD_RETURN_ERROR);
}
- environ_set(env, name, "%s", value);
+ if (args_has(args, 'h'))
+ environ_set(env, name, ENVIRON_HIDDEN, "%s", value);
+ else
+ environ_set(env, name, 0, "%s", value);
}
return (CMD_RETURN_NORMAL);
diff --git a/cmd-set-option.c b/cmd-set-option.c
index 23b45230..e04aa7ff 100644
--- a/cmd-set-option.c
+++ b/cmd-set-option.c
@@ -69,10 +69,10 @@ const struct cmd_entry cmd_set_hook_entry = {
.name = "set-hook",
.alias = NULL,
- .args = { "agRt:u", 1, 2 },
- .usage = "[-agRu] " CMD_TARGET_SESSION_USAGE " hook [command]",
+ .args = { "agpRt:uw", 1, 2 },
+ .usage = "[-agpRuw] " CMD_TARGET_PANE_USAGE " hook [command]",
- .target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
+ .target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
.flags = CMD_AFTERHOOK,
.exec = cmd_set_option_exec
@@ -81,12 +81,11 @@ const struct cmd_entry cmd_set_hook_entry = {
static enum cmd_retval
cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
{
- struct args *args = self->args;
+ struct args *args = cmd_get_args(self);
int append = args_has(args, 'a');
- struct cmd_find_state *fs = &item->target;
- struct client *c, *loop;
- struct session *s = fs->s;
- struct winlink *wl = fs->wl;
+ struct cmd_find_state *target = cmdq_get_target(item);
+ struct client *loop;
+ struct session *s = target->s;
struct window *w;
struct window_pane *wp;
struct options *oo;
@@ -94,16 +93,14 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
char *name, *argument, *value = NULL, *cause;
int window, idx, already, error, ambiguous;
int scope;
- struct style *sy;
- window = (self->entry == &cmd_set_window_option_entry);
+ window = (cmd_get_entry(self) == &cmd_set_window_option_entry);
/* Expand argument. */
- c = cmd_find_client(item, NULL, 1);
- argument = format_single(item, args->argv[0], c, s, wl, NULL);
+ argument = format_single_from_target(item, args->argv[0]);
/* If set-hook -R, fire the hook straight away. */
- if (self->entry == &cmd_set_hook_entry && args_has(args, 'R')) {
+ if (cmd_get_entry(self) == &cmd_set_hook_entry && args_has(args, 'R')) {
notify_hook(item, argument);
free(argument);
return (CMD_RETURN_NORMAL);
@@ -123,12 +120,13 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
if (args->argc < 2)
value = NULL;
else if (args_has(args, 'F'))
- value = format_single(item, args->argv[1], c, s, wl, NULL);
+ value = format_single_from_target(item, args->argv[1]);
else
value = xstrdup(args->argv[1]);
/* Get the scope and table for the option .*/
- scope = options_scope_from_name(args, window, name, fs, &oo, &cause);
+ scope = options_scope_from_name(args, window, name, target, &oo,
+ &cause);
if (scope == OPTIONS_TABLE_NONE) {
if (args_has(args, 'q'))
goto out;
@@ -233,16 +231,6 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
tty_keys_build(&loop->tty);
}
}
- if (strcmp(name, "status-fg") == 0 || strcmp(name, "status-bg") == 0) {
- sy = options_get_style(oo, "status-style");
- sy->gc.fg = options_get_number(oo, "status-fg");
- sy->gc.bg = options_get_number(oo, "status-bg");
- }
- if (strcmp(name, "status-style") == 0) {
- sy = options_get_style(oo, "status-style");
- options_set_number(oo, "status-fg", sy->gc.fg);
- options_set_number(oo, "status-bg", sy->gc.bg);
- }
if (strcmp(name, "status") == 0 ||
strcmp(name, "status-interval") == 0)
status_timer_start_all();
@@ -284,16 +272,38 @@ fail:
}
static int
+cmd_set_option_check_string(const struct options_table_entry *oe,
+ const char *value, char **cause)
+{
+ struct style sy;
+
+ if (strcmp(oe->name, "default-shell") == 0 && !checkshell(value)) {
+ xasprintf(cause, "not a suitable shell: %s", value);
+ return (-1);
+ }
+ if (oe->pattern != NULL && fnmatch(oe->pattern, value, 0) != 0) {
+ xasprintf(cause, "value is invalid: %s", value);
+ return (-1);
+ }
+ if ((oe->flags & OPTIONS_TABLE_IS_STYLE) &&
+ strstr(value, "#{") == NULL &&
+ style_parse(&sy, &grid_default_cell, value) != 0) {
+ xasprintf(cause, "invalid style: %s", value);
+ return (-1);
+ }
+ return (0);
+}
+
+static int
cmd_set_option_set(struct cmd *self, struct cmdq_item *item, struct options *oo,
struct options_entry *parent, const char *value)
{
const struct options_table_entry *oe;
- struct args *args = self->args;
+ struct args *args = cmd_get_args(self);
int append = args_has(args, 'a');
- struct options_entry *o;
long long number;
const char *errstr, *new;
- char *old;
+ char *old, *cause;
key_code key;
oe = options_table_entry(parent);
@@ -309,10 +319,12 @@ cmd_set_option_set(struct cmd *self, struct cmdq_item *item, struct options *oo,
old = xstrdup(options_get_string(oo, oe->name));
options_set_string(oo, oe->name, append, "%s", value);
new = options_get_string(oo, oe->name);
- if (oe->pattern != NULL && fnmatch(oe->pattern, new, 0) != 0) {
+ if (cmd_set_option_check_string(oe, new, &cause) != 0) {
+ cmdq_error(item, "%s", cause);
+ free(cause);
+
options_set_string(oo, oe->name, 0, "%s", old);
free(old);
- cmdq_error(item, "value is invalid: %s", value);
return (-1);
}
free(old);
@@ -344,13 +356,6 @@ cmd_set_option_set(struct cmd *self, struct cmdq_item *item, struct options *oo,
return (cmd_set_option_flag(item, oe, oo, value));
case OPTIONS_TABLE_CHOICE:
return (cmd_set_option_choice(item, oe, oo, value));
- case OPTIONS_TABLE_STYLE:
- o = options_set_style(oo, oe->name, append, value);
- if (o == NULL) {
- cmdq_error(item, "bad style: %s", value);
- return (-1);
- }
- return (0);
case OPTIONS_TABLE_COMMAND:
break;
}
diff --git a/cmd-show-environment.c b/cmd-show-environment.c
index eb19cf20..3ad31400 100644
--- a/cmd-show-environment.c
+++ b/cmd-show-environment.c
@@ -38,8 +38,8 @@ const struct cmd_entry cmd_show_environment_entry = {
.name = "show-environment",
.alias = "showenv",
- .args = { "gst:", 0, 1 },
- .usage = "[-gs] " CMD_TARGET_SESSION_USAGE " [name]",
+ .args = { "hgst:", 0, 1 },
+ .usage = "[-hgs] " CMD_TARGET_SESSION_USAGE " [name]",
.target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
@@ -69,9 +69,15 @@ static void
cmd_show_environment_print(struct cmd *self, struct cmdq_item *item,
struct environ_entry *envent)
{
- char *escaped;
+ struct args *args = cmd_get_args(self);
+ char *escaped;
- if (!args_has(self->args, 's')) {
+ if (!args_has(args, 'h') && (envent->flags & ENVIRON_HIDDEN))
+ return;
+ if (args_has(args, 'h') && (~envent->flags & ENVIRON_HIDDEN))
+ return;
+
+ if (!args_has(args, 's')) {
if (envent->value != NULL)
cmdq_print(item, "%s=%s", envent->name, envent->value);
else
@@ -91,30 +97,31 @@ cmd_show_environment_print(struct cmd *self, struct cmdq_item *item,
static enum cmd_retval
cmd_show_environment_exec(struct cmd *self, struct cmdq_item *item)
{
- struct args *args = self->args;
+ struct args *args = cmd_get_args(self);
+ struct cmd_find_state *target = cmdq_get_target(item);
struct environ *env;
struct environ_entry *envent;
- const char *target;
+ const char *tflag;
- if ((target = args_get(args, 't')) != NULL) {
- if (item->target.s == NULL) {
- cmdq_error(item, "no such session: %s", target);
+ if ((tflag = args_get(args, 't')) != NULL) {
+ if (target->s == NULL) {
+ cmdq_error(item, "no such session: %s", tflag);
return (CMD_RETURN_ERROR);
}
}
- if (args_has(self->args, 'g'))
+ if (args_has(args, 'g'))
env = global_environ;
else {
- if (item->target.s == NULL) {
- target = args_get(args, 't');
- if (target != NULL)
- cmdq_error(item, "no such session: %s", target);
+ if (target->s == NULL) {
+ tflag = args_get(args, 't');
+ if (tflag != NULL)
+ cmdq_error(item, "no such session: %s", tflag);
else
cmdq_error(item, "no current session");
return (CMD_RETURN_ERROR);
}
- env = item->target.s->environ;
+ env = target->s->environ;
}
if (args->argc != 0) {
diff --git a/cmd-show-messages.c b/cmd-show-messages.c
index 8da12374..02fdb9cd 100644
--- a/cmd-show-messages.c
+++ b/cmd-show-messages.c
@@ -38,26 +38,28 @@ const struct cmd_entry cmd_show_messages_entry = {
.args = { "JTt:", 0, 0 },
.usage = "[-JT] " CMD_TARGET_CLIENT_USAGE,
- .flags = CMD_AFTERHOOK,
+ .flags = CMD_AFTERHOOK|CMD_CLIENT_TFLAG,
.exec = cmd_show_messages_exec
};
-static int cmd_show_messages_terminals(struct cmdq_item *, int);
-
static int
-cmd_show_messages_terminals(struct cmdq_item *item, int blank)
+cmd_show_messages_terminals(struct cmd *self, struct cmdq_item *item, int blank)
{
+ struct args *args = cmd_get_args(self);
+ struct client *tc = cmdq_get_target_client(item);
struct tty_term *term;
u_int i, n;
n = 0;
LIST_FOREACH(term, &tty_terms, entry) {
+ if (args_has(args, 't') && term != tc->tty.term)
+ continue;
if (blank) {
cmdq_print(item, "%s", "");
blank = 0;
}
- cmdq_print(item, "Terminal %u: %s [references=%u, flags=0x%x]:",
- n, term->name, term->references, term->flags);
+ cmdq_print(item, "Terminal %u: %s for %s, flags=0x%x:", n,
+ term->name, term->tty->client->name, term->flags);
n++;
for (i = 0; i < tty_term_ncodes(); i++)
cmdq_print(item, "%s", tty_term_describe(term, i));
@@ -68,18 +70,15 @@ cmd_show_messages_terminals(struct cmdq_item *item, int blank)
static enum cmd_retval
cmd_show_messages_exec(struct cmd *self, struct cmdq_item *item)
{
- struct args *args = self->args;
- struct client *c;
+ struct args *args = cmd_get_args(self);
+ struct client *tc = cmdq_get_target_client(item);
struct message_entry *msg;
char *tim;
int done, blank;
- if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
- return (CMD_RETURN_ERROR);
-
done = blank = 0;
if (args_has(args, 'T')) {
- blank = cmd_show_messages_terminals(item, blank);
+ blank = cmd_show_messages_terminals(self, item, blank);
done = 1;
}
if (args_has(args, 'J')) {
@@ -89,10 +88,9 @@ cmd_show_messages_exec(struct cmd *self, struct cmdq_item *item)
if (done)
return (CMD_RETURN_NORMAL);
- TAILQ_FOREACH(msg, &c->message_log, entry) {
+ TAILQ_FOREACH(msg, &tc->message_log, entry) {
tim = ctime(&msg->msg_time);
*strchr(tim, '\n') = '\0';
-
cmdq_print(item, "%s %s", tim, msg->msg);
}
diff --git a/cmd-show-options.c b/cmd-show-options.c
index da481139..1286037c 100644
--- a/cmd-show-options.c
+++ b/cmd-show-options.c
@@ -64,10 +64,10 @@ const struct cmd_entry cmd_show_hooks_entry = {
.name = "show-hooks",
.alias = NULL,
- .args = { "gt:", 0, 1 },
- .usage = "[-g] " CMD_TARGET_SESSION_USAGE,
+ .args = { "gpt:w", 0, 1 },
+ .usage = "[-gpw] " CMD_TARGET_PANE_USAGE,
- .target = { 't', CMD_FIND_SESSION, 0 },
+ .target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
.flags = CMD_AFTERHOOK,
.exec = cmd_show_options_exec
@@ -76,20 +76,18 @@ const struct cmd_entry cmd_show_hooks_entry = {
static enum cmd_retval
cmd_show_options_exec(struct cmd *self, struct cmdq_item *item)
{
- struct args *args = self->args;
- struct cmd_find_state *fs = &item->target;
- struct client *c = cmd_find_client(item, NULL, 1);
- struct session *s = item->target.s;
- struct winlink *wl = item->target.wl;
+ struct args *args = cmd_get_args(self);
+ struct cmd_find_state *target = cmdq_get_target(item);
struct options *oo;
char *argument, *name = NULL, *cause;
int window, idx, ambiguous, parent, scope;
struct options_entry *o;
- window = (self->entry == &cmd_show_window_options_entry);
+ window = (cmd_get_entry(self) == &cmd_show_window_options_entry);
if (args->argc == 0) {
- scope = options_scope_from_flags(args, window, fs, &oo, &cause);
+ scope = options_scope_from_flags(args, window, target, &oo,
+ &cause);
if (scope == OPTIONS_TABLE_NONE) {
if (args_has(args, 'q'))
return (CMD_RETURN_NORMAL);
@@ -99,7 +97,7 @@ cmd_show_options_exec(struct cmd *self, struct cmdq_item *item)
}
return (cmd_show_options_all(self, item, scope, oo));
}
- argument = format_single(item, args->argv[0], c, s, wl, NULL);
+ argument = format_single_from_target(item, args->argv[0]);
name = options_match(argument, &idx, &ambiguous);
if (name == NULL) {
@@ -111,7 +109,8 @@ cmd_show_options_exec(struct cmd *self, struct cmdq_item *item)
cmdq_error(item, "invalid option: %s", argument);
goto fail;
}
- scope = options_scope_from_name(args, window, name, fs, &oo, &cause);
+ scope = options_scope_from_name(args, window, name, target, &oo,
+ &cause);
if (scope == OPTIONS_TABLE_NONE) {
if (args_has(args, 'q'))
goto fail;
@@ -142,6 +141,7 @@ static void
cmd_show_options_print(struct cmd *self, struct cmdq_item *item,
struct options_entry *o, int idx, int parent)
{
+ struct args *args = cmd_get_args(self);
struct options_array_item *a;
const char *name = options_name(o);
char *value, *tmp = NULL, *escaped;
@@ -153,7 +153,7 @@ cmd_show_options_print(struct cmd *self, struct cmdq_item *item,
if (options_isarray(o)) {
a = options_array_first(o);
if (a == NULL) {
- if (!args_has(self->args, 'v'))
+ if (!args_has(args, 'v'))
cmdq_print(item, "%s", name);
return;
}
@@ -168,7 +168,7 @@ cmd_show_options_print(struct cmd *self, struct cmdq_item *item,
}
value = options_tostring(o, idx, 0);
- if (args_has(self->args, 'v'))
+ if (args_has(args, 'v'))
cmdq_print(item, "%s", value);
else if (options_isstring(o)) {
escaped = args_escape(value);
@@ -192,6 +192,7 @@ static enum cmd_retval
cmd_show_options_all(struct cmd *self, struct cmdq_item *item, int scope,
struct options *oo)
{
+ struct args *args = cmd_get_args(self);
const struct options_table_entry *oe;
struct options_entry *o;
struct options_array_item *a;
@@ -209,18 +210,16 @@ cmd_show_options_all(struct cmd *self, struct cmdq_item *item, int scope,
if (~oe->scope & scope)
continue;
- if ((self->entry != &cmd_show_hooks_entry &&
- !args_has(self->args, 'H') &&
- oe != NULL &&
+ if ((cmd_get_entry(self) != &cmd_show_hooks_entry &&
+ !args_has(args, 'H') &&
(oe->flags & OPTIONS_TABLE_IS_HOOK)) ||
- (self->entry == &cmd_show_hooks_entry &&
- (oe == NULL ||
- (~oe->flags & OPTIONS_TABLE_IS_HOOK))))
+ (cmd_get_entry(self) == &cmd_show_hooks_entry &&
+ (~oe->flags & OPTIONS_TABLE_IS_HOOK)))
continue;
o = options_get_only(oo, oe->name);
if (o == NULL) {
- if (!args_has(self->args, 'A'))
+ if (!args_has(args, 'A'))
continue;
o = options_get(oo, oe->name);
if (o == NULL)
@@ -232,7 +231,7 @@ cmd_show_options_all(struct cmd *self, struct cmdq_item *item, int scope,
if (!options_isarray(o))
cmd_show_options_print(self, item, o, -1, parent);
else if ((a = options_array_first(o)) == NULL) {
- if (!args_has(self->args, 'v')) {
+ if (!args_has(args, 'v')) {
name = options_name(o);
if (parent)
cmdq_print(item, "%s*", name);
diff --git a/cmd-source-file.c b/cmd-source-file.c
index afe45a54..f5a0ca4b 100644
--- a/cmd-source-file.c
+++ b/cmd-source-file.c
@@ -122,9 +122,9 @@ cmd_source_file_add(struct cmd_source_file_data *cdata, const char *path)
static enum cmd_retval
cmd_source_file_exec(struct cmd *self, struct cmdq_item *item)
{
- struct args *args = self->args;
+ struct args *args = cmd_get_args(self);
struct cmd_source_file_data *cdata;
- struct client *c = item->client;
+ struct client *c = cmdq_get_client(item);
enum cmd_retval retval = CMD_RETURN_NORMAL;
char *pattern, *cwd;
const char *path, *error;
diff --git a/cmd-split-window.c b/cmd-split-window.c
index a5fa3acc..130aca2e 100644
--- a/cmd-split-window.c
+++ b/cmd-split-window.c
@@ -52,13 +52,14 @@ const struct cmd_entry cmd_split_window_entry = {
static enum cmd_retval
cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
{
- struct args *args = self->args;
- struct cmd_find_state *current = &item->shared->current;
+ struct args *args = cmd_get_args(self);
+ struct cmd_find_state *current = cmdq_get_current(item);
+ struct cmd_find_state *target = cmdq_get_target(item);
struct spawn_context sc;
- struct client *c = cmd_find_client(item, NULL, 1);
- struct session *s = item->target.s;
- struct winlink *wl = item->target.wl;
- struct window_pane *wp = item->target.wp, *new_wp;
+ struct client *tc = cmdq_get_target_client(item);
+ struct session *s = target->s;
+ struct winlink *wl = target->wl;
+ struct window_pane *wp = target->wp, *new_wp;
enum layout_type type;
struct layout_cell *lc;
struct cmd_find_state fs;
@@ -141,7 +142,7 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
add = args_first_value(args, 'e', &value);
while (add != NULL) {
- environ_put(sc.environ, add);
+ environ_put(sc.environ, add, 0);
add = args_next_value(&value);
}
@@ -172,7 +173,7 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
if (args_has(args, 'P')) {
if ((template = args_get(args, 'F')) == NULL)
template = SPLIT_WINDOW_TEMPLATE;
- cp = format_single(item, template, c, s, wl, new_wp);
+ cp = format_single(item, template, tc, s, wl, new_wp);
cmdq_print(item, "%s", cp);
free(cp);
}
diff --git a/cmd-swap-pane.c b/cmd-swap-pane.c
index 3e0e6e60..021ac224 100644
--- a/cmd-swap-pane.c
+++ b/cmd-swap-pane.c
@@ -45,16 +45,18 @@ const struct cmd_entry cmd_swap_pane_entry = {
static enum cmd_retval
cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item)
{
- struct args *args = self->args;
+ struct args *args = cmd_get_args(self);
+ struct cmd_find_state *source = cmdq_get_source(item);
+ struct cmd_find_state *target = cmdq_get_target(item);
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;
- dst_w = item->target.wl->window;
- dst_wp = item->target.wp;
- src_w = item->source.wl->window;
- src_wp = item->source.wp;
+ dst_w = target->wl->window;
+ dst_wp = target->wp;
+ src_w = source->wl->window;
+ src_wp = source->wp;
if (window_push_zoom(dst_w, args_has(args, 'Z')))
server_redraw_window(dst_w);
diff --git a/cmd-swap-window.c b/cmd-swap-window.c
index 0c15479d..651a44da 100644
--- a/cmd-swap-window.c
+++ b/cmd-swap-window.c
@@ -45,20 +45,20 @@ const struct cmd_entry cmd_swap_window_entry = {
static enum cmd_retval
cmd_swap_window_exec(struct cmd *self, struct cmdq_item *item)
{
- struct session *src, *dst;
+ struct args *args = cmd_get_args(self);
+ struct cmd_find_state *source = cmdq_get_source(item);
+ struct cmd_find_state *target = cmdq_get_target(item);
+ struct session *src = source->s, *dst = target->s;
struct session_group *sg_src, *sg_dst;
- struct winlink *wl_src, *wl_dst;
+ struct winlink *wl_src = source->wl, *wl_dst = target->wl;
struct window *w_src, *w_dst;
- wl_src = item->source.wl;
- src = item->source.s;
sg_src = session_group_contains(src);
-
- wl_dst = item->target.wl;
- dst = item->target.s;
sg_dst = session_group_contains(dst);
- if (src != dst && sg_src != NULL && sg_dst != NULL &&
+ if (src != dst &&
+ sg_src != NULL &&
+ sg_dst != NULL &&
sg_src == sg_dst) {
cmdq_error(item, "can't move window, sessions are grouped");
return (CMD_RETURN_ERROR);
@@ -77,7 +77,7 @@ cmd_swap_window_exec(struct cmd *self, struct cmdq_item *item)
wl_src->window = w_dst;
TAILQ_INSERT_TAIL(&w_dst->winlinks, wl_src, wentry);
- if (args_has(self->args, 'd')) {
+ if (args_has(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 61677761..82510ce6 100644
--- a/cmd-switch-client.c
+++ b/cmd-switch-client.c
@@ -40,18 +40,20 @@ const struct cmd_entry cmd_switch_client_entry = {
/* -t is special */
- .flags = CMD_READONLY,
+ .flags = CMD_READONLY|CMD_CLIENT_CFLAG,
.exec = cmd_switch_client_exec
};
static enum cmd_retval
cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
{
- struct args *args = self->args;
+ struct args *args = cmd_get_args(self);
+ struct cmd_find_state *current = cmdq_get_current(item);
+ struct cmd_find_state target;
const char *tflag = args_get(args, 't');
enum cmd_find_type type;
int flags;
- struct client *c;
+ struct client *tc = cmdq_get_target_client(item);
struct session *s;
struct winlink *wl;
struct window *w;
@@ -59,9 +61,6 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
const char *tablename;
struct key_table *table;
- if ((c = cmd_find_client(item, args_get(args, 'c'), 0)) == NULL)
- return (CMD_RETURN_ERROR);
-
if (tflag != NULL && tflag[strcspn(tflag, ":.%")] != '\0') {
type = CMD_FIND_PANE;
flags = 0;
@@ -69,15 +68,14 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
type = CMD_FIND_SESSION;
flags = CMD_FIND_PREFER_UNATTACHED;
}
- if (cmd_find_target(&item->target, item, tflag, type, flags) != 0)
+ if (cmd_find_target(&target, item, tflag, type, flags) != 0)
return (CMD_RETURN_ERROR);
- s = item->target.s;
- wl = item->target.wl;
- w = wl->window;
- wp = item->target.wp;
+ s = target.s;
+ wl = target.wl;
+ wp = target.wp;
if (args_has(args, 'r'))
- c->flags ^= CLIENT_READONLY;
+ tc->flags ^= CLIENT_READONLY;
tablename = args_get(args, 'T');
if (tablename != NULL) {
@@ -87,24 +85,24 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_ERROR);
}
table->references++;
- key_bindings_unref_table(c->keytable);
- c->keytable = table;
+ key_bindings_unref_table(tc->keytable);
+ tc->keytable = table;
return (CMD_RETURN_NORMAL);
}
if (args_has(args, 'n')) {
- if ((s = session_next_session(c->session)) == NULL) {
+ if ((s = session_next_session(tc->session)) == NULL) {
cmdq_error(item, "can't find next session");
return (CMD_RETURN_ERROR);
}
} else if (args_has(args, 'p')) {
- if ((s = session_previous_session(c->session)) == NULL) {
+ if ((s = session_previous_session(tc->session)) == NULL) {
cmdq_error(item, "can't find previous session");
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 (tc->last_session != NULL && session_alive(tc->last_session))
+ s = tc->last_session;
else
s = NULL;
if (s == NULL) {
@@ -112,10 +110,11 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_ERROR);
}
} else {
- if (item->client == NULL)
+ if (cmdq_get_client(item) == NULL)
return (CMD_RETURN_NORMAL);
if (wl != NULL && wp != NULL) {
- if (window_push_zoom(w, args_has(self->args, 'Z')))
+ w = wl->window;
+ if (window_push_zoom(w, args_has(args, 'Z')))
server_redraw_window(w);
window_redraw_active_switch(w, wp);
window_set_active_pane(w, wp, 1);
@@ -124,28 +123,28 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
}
if (wl != NULL) {
session_set_current(s, wl);
- cmd_find_from_session(&item->shared->current, s, 0);
+ cmd_find_from_session(current, s, 0);
}
}
if (!args_has(args, 'E'))
- environ_update(s->options, c->environ, s->environ);
-
- if (c->session != NULL && c->session != s)
- c->last_session = c->session;
- c->session = s;
- if (~item->shared->flags & CMDQ_SHARED_REPEAT)
- server_client_set_key_table(c, NULL);
- tty_update_client_offset(c);
- status_timer_start(c);
- notify_client("client-session-changed", c);
+ environ_update(s->options, tc->environ, s->environ);
+
+ if (tc->session != NULL && tc->session != s)
+ tc->last_session = tc->session;
+ tc->session = s;
+ if (~cmdq_get_flags(item) & CMDQ_STATE_REPEAT)
+ server_client_set_key_table(tc, NULL);
+ tty_update_client_offset(tc);
+ status_timer_start(tc);
+ notify_client("client-session-changed", tc);
session_update_activity(s, NULL);
gettimeofday(&s->last_attached_time, NULL);
server_check_unattached();
- server_redraw_client(c);
+ server_redraw_client(tc);
s->curw->flags &= ~WINLINK_ALERTFLAGS;
- s->curw->window->latest = c;
+ s->curw->window->latest = tc;
recalculate_sizes();
alerts_check_session(s);
diff --git a/cmd-unbind-key.c b/cmd-unbind-key.c
index d65ac91a..4b9f39a6 100644
--- a/cmd-unbind-key.c
+++ b/cmd-unbind-key.c
@@ -42,7 +42,7 @@ const struct cmd_entry cmd_unbind_key_entry = {
static enum cmd_retval
cmd_unbind_key_exec(struct cmd *self, struct cmdq_item *item)
{
- struct args *args = self->args;
+ struct args *args = cmd_get_args(self);
key_code key;
const char *tablename;
diff --git a/cmd-wait-for.c b/cmd-wait-for.c
index 4f438a7f..807a661a 100644
--- a/cmd-wait-for.c
+++ b/cmd-wait-for.c
@@ -120,7 +120,7 @@ cmd_wait_for_remove(struct wait_channel *wc)
static enum cmd_retval
cmd_wait_for_exec(struct cmd *self, struct cmdq_item *item)
{
- struct args *args = self->args;
+ struct args *args = cmd_get_args(self);
const char *name = args->argv[0];
struct wait_channel *wc, wc0;
@@ -167,7 +167,7 @@ static enum cmd_retval
cmd_wait_for_wait(struct cmdq_item *item, const char *name,
struct wait_channel *wc)
{
- struct client *c = item->client;
+ struct client *c = cmdq_get_client(item);
struct wait_item *wi;
if (c == NULL) {
@@ -198,7 +198,7 @@ cmd_wait_for_lock(struct cmdq_item *item, const char *name,
{
struct wait_item *wi;
- if (item->client == NULL) {
+ if (cmdq_get_client(item) == NULL) {
cmdq_error(item, "not able to lock");
return (CMD_RETURN_ERROR);
}
diff --git a/cmd.c b/cmd.c
index 380eedcf..9cd5ab49 100644
--- a/cmd.c
+++ b/cmd.c
@@ -43,6 +43,7 @@ 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_menu_entry;
extern const struct cmd_entry cmd_display_message_entry;
+extern const struct cmd_entry cmd_display_popup_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;
@@ -132,6 +133,7 @@ const struct cmd_entry *cmd_table[] = {
&cmd_detach_client_entry,
&cmd_display_menu_entry,
&cmd_display_message_entry,
+ &cmd_display_popup_entry,
&cmd_display_panes_entry,
&cmd_find_window_entry,
&cmd_has_session_entry,
@@ -204,8 +206,27 @@ const struct cmd_entry *cmd_table[] = {
NULL
};
+/* Instance of a command. */
+struct cmd {
+ const struct cmd_entry *entry;
+ struct args *args;
+ u_int group;
+
+ char *file;
+ u_int line;
+
+ char *alias;
+ int argc;
+ char **argv;
+
+ TAILQ_ENTRY(cmd) qentry;
+};
+TAILQ_HEAD(cmds, cmd);
+
+/* Next group number for new command list. */
static u_int cmd_list_next_group = 1;
+/* Log an argument vector. */
void printflike(3, 4)
cmd_log_argv(int argc, char **argv, const char *fmt, ...)
{
@@ -222,6 +243,7 @@ cmd_log_argv(int argc, char **argv, const char *fmt, ...)
free(prefix);
}
+/* Prepend to an argument vector. */
void
cmd_prepend_argv(int *argc, char ***argv, char *arg)
{
@@ -238,6 +260,7 @@ cmd_prepend_argv(int *argc, char ***argv, char *arg)
(*argc)++;
}
+/* Append to an argument vector. */
void
cmd_append_argv(int *argc, char ***argv, char *arg)
{
@@ -245,6 +268,7 @@ cmd_append_argv(int *argc, char ***argv, char *arg)
(*argv)[(*argc)++] = xstrdup(arg);
}
+/* Pack an argument vector up into a buffer. */
int
cmd_pack_argv(int argc, char **argv, char *buf, size_t len)
{
@@ -267,6 +291,7 @@ cmd_pack_argv(int argc, char **argv, char *buf, size_t len)
return (0);
}
+/* Unpack an argument vector from a packed buffer. */
int
cmd_unpack_argv(char *buf, size_t len, int argc, char ***argv)
{
@@ -295,6 +320,7 @@ cmd_unpack_argv(char *buf, size_t len, int argc, char ***argv)
return (0);
}
+/* Copy an argument vector, ensuring it is terminated by NULL. */
char **
cmd_copy_argv(int argc, char **argv)
{
@@ -311,6 +337,7 @@ cmd_copy_argv(int argc, char **argv)
return (new_argv);
}
+/* Free an argument vector. */
void
cmd_free_argv(int argc, char **argv)
{
@@ -323,6 +350,7 @@ cmd_free_argv(int argc, char **argv)
free(argv);
}
+/* Convert argument vector to a string. */
char *
cmd_stringify_argv(int argc, char **argv)
{
@@ -349,6 +377,38 @@ cmd_stringify_argv(int argc, char **argv)
return (buf);
}
+/* Get entry for command. */
+const struct cmd_entry *
+cmd_get_entry(struct cmd *cmd)
+{
+ return (cmd->entry);
+}
+
+/* Get arguments for command. */
+struct args *
+cmd_get_args(struct cmd *cmd)
+{
+ return (cmd->args);
+}
+
+/* Get group for command. */
+u_int
+cmd_get_group(struct cmd *cmd)
+{
+ return (cmd->group);
+}
+
+/* Get file and line for command. */
+void
+cmd_get_source(struct cmd *cmd, const char **file, u_int *line)
+{
+ if (file != NULL)
+ *file = cmd->file;
+ if (line != NULL)
+ *line = cmd->line;
+}
+
+/* Look for an alias for a command. */
char *
cmd_get_alias(const char *name)
{
@@ -379,6 +439,7 @@ cmd_get_alias(const char *name)
return (NULL);
}
+/* Look up a command entry by name. */
static const struct cmd_entry *
cmd_find(const char *name, char **cause)
{
@@ -428,6 +489,7 @@ ambiguous:
return (NULL);
}
+/* Parse a single command from an argument vector. */
struct cmd *
cmd_parse(int argc, char **argv, const char *file, u_int line, char **cause)
{
@@ -476,6 +538,7 @@ usage:
return (NULL);
}
+/* Free a command. */
void
cmd_free(struct cmd *cmd)
{
@@ -488,6 +551,7 @@ cmd_free(struct cmd *cmd)
free(cmd);
}
+/* Get a command as a string. */
char *
cmd_print(struct cmd *cmd)
{
@@ -503,6 +567,7 @@ cmd_print(struct cmd *cmd)
return (out);
}
+/* Create a new command list. */
struct cmd_list *
cmd_list_new(void)
{
@@ -511,29 +576,33 @@ cmd_list_new(void)
cmdlist = xcalloc(1, sizeof *cmdlist);
cmdlist->references = 1;
cmdlist->group = cmd_list_next_group++;
- TAILQ_INIT(&cmdlist->list);
+ cmdlist->list = xcalloc(1, sizeof *cmdlist->list);
+ TAILQ_INIT(cmdlist->list);
return (cmdlist);
}
+/* Append a command to a command list. */
void
cmd_list_append(struct cmd_list *cmdlist, struct cmd *cmd)
{
cmd->group = cmdlist->group;
- TAILQ_INSERT_TAIL(&cmdlist->list, cmd, qentry);
+ TAILQ_INSERT_TAIL(cmdlist->list, cmd, qentry);
}
+/* Move all commands from one command list to another */
void
cmd_list_move(struct cmd_list *cmdlist, struct cmd_list *from)
{
struct cmd *cmd, *cmd1;
- TAILQ_FOREACH_SAFE(cmd, &from->list, qentry, cmd1) {
- TAILQ_REMOVE(&from->list, cmd, qentry);
- TAILQ_INSERT_TAIL(&cmdlist->list, cmd, qentry);
+ TAILQ_FOREACH_SAFE(cmd, from->list, qentry, cmd1) {
+ TAILQ_REMOVE(from->list, cmd, qentry);
+ TAILQ_INSERT_TAIL(cmdlist->list, cmd, qentry);
}
cmdlist->group = cmd_list_next_group++;
}
+/* Free a command list. */
void
cmd_list_free(struct cmd_list *cmdlist)
{
@@ -542,36 +611,46 @@ cmd_list_free(struct cmd_list *cmdlist)
if (--cmdlist->references != 0)
return;
- TAILQ_FOREACH_SAFE(cmd, &cmdlist->list, qentry, cmd1) {
- TAILQ_REMOVE(&cmdlist->list, cmd, qentry);
+ TAILQ_FOREACH_SAFE(cmd, cmdlist->list, qentry, cmd1) {
+ TAILQ_REMOVE(cmdlist->list, cmd, qentry);
cmd_free(cmd);
}
-
+ free(cmdlist->list);
free(cmdlist);
}
+/* Get a command list as a string. */
char *
cmd_list_print(struct cmd_list *cmdlist, int escaped)
{
- struct cmd *cmd;
+ struct cmd *cmd, *next;
char *buf, *this;
size_t len;
len = 1;
buf = xcalloc(1, len);
- TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
+ TAILQ_FOREACH(cmd, cmdlist->list, qentry) {
this = cmd_print(cmd);
- len += strlen(this) + 4;
+ len += strlen(this) + 6;
buf = xrealloc(buf, len);
strlcat(buf, this, len);
- if (TAILQ_NEXT(cmd, qentry) != NULL) {
- if (escaped)
- strlcat(buf, " \\; ", len);
- else
- strlcat(buf, " ; ", len);
+
+ next = TAILQ_NEXT(cmd, qentry);
+ if (next != NULL) {
+ if (cmd->group != next->group) {
+ if (escaped)
+ strlcat(buf, " \\;\\; ", len);
+ else
+ strlcat(buf, " ;; ", len);
+ } else {
+ if (escaped)
+ strlcat(buf, " \\; ", len);
+ else
+ strlcat(buf, " ; ", len);
+ }
}
free(this);
@@ -580,6 +659,46 @@ cmd_list_print(struct cmd_list *cmdlist, int escaped)
return (buf);
}
+/* Get first command in list. */
+struct cmd *
+cmd_list_first(struct cmd_list *cmdlist)
+{
+ return (TAILQ_FIRST(cmdlist->list));
+}
+
+/* Get next command in list. */
+struct cmd *
+cmd_list_next(struct cmd *cmd)
+{
+ return (TAILQ_NEXT(cmd, qentry));
+}
+
+/* Do all of the commands in this command list have this flag? */
+int
+cmd_list_all_have(struct cmd_list *cmdlist, int flag)
+{
+ struct cmd *cmd;
+
+ TAILQ_FOREACH(cmd, cmdlist->list, qentry) {
+ if (~cmd->entry->flags & flag)
+ return (0);
+ }
+ return (1);
+}
+
+/* Do any of the commands in this command list have this flag? */
+int
+cmd_list_any_have(struct cmd_list *cmdlist, int flag)
+{
+ struct cmd *cmd;
+
+ TAILQ_FOREACH(cmd, cmdlist->list, qentry) {
+ if (cmd->entry->flags & flag)
+ return (1);
+ }
+ return (0);
+}
+
/* Adjust current mouse position for a pane. */
int
cmd_mouse_at(struct window_pane *wp, struct mouse_event *m, u_int *xp,
diff --git a/compat.h b/compat.h
index b7ec5a69..736a14fc 100644
--- a/compat.h
+++ b/compat.h
@@ -90,6 +90,10 @@ void warnx(const char *, ...);
#define _PATH_DEFPATH "/usr/bin:/bin"
#endif
+#ifndef _PATH_VI
+#define _PATH_VI "/usr/bin/vi"
+#endif
+
#ifndef __OpenBSD__
#define pledge(s, p) (0)
#endif
diff --git a/configure.ac b/configure.ac
index d5dbd9c4..dc133c25 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,6 +1,6 @@
# configure.ac
-AC_INIT([tmux], 3.1b)
+AC_INIT([tmux], next-3.2)
AC_PREREQ([2.60])
AC_CONFIG_AUX_DIR(etc)
@@ -87,6 +87,12 @@ AC_CHECK_HEADERS([ \
util.h \
])
+# Look for sys_signame.
+AC_SEARCH_LIBS(sys_signame, , AC_DEFINE(HAVE_SYS_SIGNAME))
+
+# Look for fmod.
+AC_CHECK_LIB(m, fmod)
+
# Look for library needed for flock.
AC_SEARCH_LIBS(flock, bsd)
diff --git a/control.c b/control.c
index b8a16e73..bdc89de4 100644
--- a/control.c
+++ b/control.c
@@ -42,7 +42,7 @@ control_write(struct client *c, const char *fmt, ...)
static enum cmd_retval
control_error(struct cmdq_item *item, void *data)
{
- struct client *c = item->client;
+ struct client *c = cmdq_get_client(item);
char *error = data;
cmdq_guard(item, "begin", 1);
@@ -56,13 +56,13 @@ control_error(struct cmdq_item *item, void *data)
/* Control input callback. Read lines and fire commands. */
static void
control_callback(__unused struct client *c, __unused const char *path,
- int error, int closed, struct evbuffer *buffer, __unused void *data)
+ int read_error, int closed, struct evbuffer *buffer, __unused void *data)
{
- char *line;
- struct cmdq_item *item;
- struct cmd_parse_result *pr;
+ char *line, *error;
+ struct cmdq_state *state;
+ enum cmd_parse_status status;
- if (closed || error != 0)
+ if (closed || read_error != 0)
c->flags |= CLIENT_EXIT;
for (;;) {
@@ -76,21 +76,11 @@ control_callback(__unused struct client *c, __unused const char *path,
break;
}
- pr = cmd_parse_from_string(line, NULL);
- switch (pr->status) {
- case CMD_PARSE_EMPTY:
- break;
- case CMD_PARSE_ERROR:
- item = cmdq_get_callback(control_error, pr->error);
- cmdq_append(c, item);
- break;
- case CMD_PARSE_SUCCESS:
- item = cmdq_get_command(pr->cmdlist, NULL, NULL, 0);
- item->shared->flags |= CMDQ_SHARED_CONTROL;
- cmdq_append(c, item);
- cmd_list_free(pr->cmdlist);
- break;
- }
+ state = cmdq_new_state(NULL, NULL, CMDQ_STATE_CONTROL);
+ status = cmd_parse_and_append(line, NULL, c, state, &error);
+ if (status == CMD_PARSE_ERROR)
+ cmdq_append(c, cmdq_get_callback(control_error, error));
+ cmdq_free_state(state);
free(line);
}
diff --git a/environ.c b/environ.c
index 25968f7b..0ce717df 100644
--- a/environ.c
+++ b/environ.c
@@ -86,8 +86,10 @@ environ_copy(struct environ *srcenv, struct environ *dstenv)
RB_FOREACH(envent, environ, srcenv) {
if (envent->value == NULL)
environ_clear(dstenv, envent->name);
- else
- environ_set(dstenv, envent->name, "%s", envent->value);
+ else {
+ environ_set(dstenv, envent->name, envent->flags,
+ "%s", envent->value);
+ }
}
}
@@ -103,18 +105,21 @@ environ_find(struct environ *env, const char *name)
/* Set an environment variable. */
void
-environ_set(struct environ *env, const char *name, const char *fmt, ...)
+environ_set(struct environ *env, const char *name, int flags, const char *fmt,
+ ...)
{
struct environ_entry *envent;
va_list ap;
va_start(ap, fmt);
if ((envent = environ_find(env, name)) != NULL) {
+ envent->flags = flags;
free(envent->value);
xvasprintf(&envent->value, fmt, ap);
} else {
envent = xmalloc(sizeof *envent);
envent->name = xstrdup(name);
+ envent->flags = flags;
xvasprintf(&envent->value, fmt, ap);
RB_INSERT(environ, env, envent);
}
@@ -133,6 +138,7 @@ environ_clear(struct environ *env, const char *name)
} else {
envent = xmalloc(sizeof *envent);
envent->name = xstrdup(name);
+ envent->flags = 0;
envent->value = NULL;
RB_INSERT(environ, env, envent);
}
@@ -140,7 +146,7 @@ environ_clear(struct environ *env, const char *name)
/* Set an environment variable from a NAME=VALUE string. */
void
-environ_put(struct environ *env, const char *var)
+environ_put(struct environ *env, const char *var, int flags)
{
char *name, *value;
@@ -152,7 +158,7 @@ environ_put(struct environ *env, const char *var)
name = xstrdup(var);
name[strcspn(name, "=")] = '\0';
- environ_set(env, name, "%s", value);
+ environ_set(env, name, flags, "%s", value);
free(name);
}
@@ -170,7 +176,7 @@ environ_unset(struct environ *env, const char *name)
free(envent);
}
-/* Copy variables from a destination into a source * environment. */
+/* Copy variables from a destination into a source environment. */
void
environ_update(struct options *oo, struct environ *src, struct environ *dst)
{
@@ -188,7 +194,7 @@ environ_update(struct options *oo, struct environ *src, struct environ *dst)
if ((envent = environ_find(src, ov->string)) == NULL)
environ_clear(dst, ov->string);
else
- environ_set(dst, envent->name, "%s", envent->value);
+ environ_set(dst, envent->name, 0, "%s", envent->value);
a = options_array_next(a);
}
}
@@ -201,7 +207,9 @@ environ_push(struct environ *env)
environ = xcalloc(1, sizeof *environ);
RB_FOREACH(envent, environ, env) {
- if (envent->value != NULL && *envent->name != '\0')
+ if (envent->value != NULL &&
+ *envent->name != '\0' &&
+ (~envent->flags & ENVIRON_HIDDEN))
setenv(envent->name, envent->value, 1);
}
}
@@ -243,14 +251,15 @@ environ_for_session(struct session *s, int no_TERM)
if (!no_TERM) {
value = options_get_string(global_options, "default-terminal");
- environ_set(env, "TERM", "%s", value);
+ environ_set(env, "TERM", 0, "%s", value);
}
if (s != NULL)
idx = s->id;
else
idx = -1;
- environ_set(env, "TMUX", "%s,%ld,%d", socket_path, (long)getpid(), idx);
+ environ_set(env, "TMUX", 0, "%s,%ld,%d", socket_path, (long)getpid(),
+ idx);
return (env);
}
diff --git a/format-draw.c b/format-draw.c
index 85248aa6..3751082e 100644
--- a/format-draw.c
+++ b/format-draw.c
@@ -242,7 +242,7 @@ format_draw_left(struct screen_write_ctx *octx, u_int available, u_int ocx,
/* If there is no list left, pass off to the no list function. */
if (width_list == 0) {
- screen_write_start(&ctx, NULL, left);
+ screen_write_start(&ctx, left);
screen_write_fast_copy(&ctx, after, 0, 0, width_after, 1);
screen_write_stop(&ctx);
@@ -334,7 +334,7 @@ format_draw_centre(struct screen_write_ctx *octx, u_int available, u_int ocx,
/* If there is no list left, pass off to the no list function. */
if (width_list == 0) {
- screen_write_start(&ctx, NULL, centre);
+ screen_write_start(&ctx, centre);
screen_write_fast_copy(&ctx, after, 0, 0, width_after, 1);
screen_write_stop(&ctx);
@@ -431,7 +431,7 @@ format_draw_right(struct screen_write_ctx *octx, u_int available, u_int ocx,
/* If there is no list left, pass off to the no list function. */
if (width_list == 0) {
- screen_write_start(&ctx, NULL, right);
+ screen_write_start(&ctx, right);
screen_write_fast_copy(&ctx, after, 0, 0, width_after, 1);
screen_write_stop(&ctx);
@@ -536,7 +536,7 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base,
*/
for (i = 0; i < TOTAL; i++) {
screen_init(&s[i], size, 1, 0);
- screen_write_start(&ctx[i], NULL, &s[i]);
+ screen_write_start(&ctx[i], &s[i]);
screen_write_clearendofline(&ctx[i], current_default.bg);
width[i] = 0;
}
@@ -738,7 +738,7 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base,
/*
* Draw the screens. How they are arranged depends on where the list
- * appearsq.
+ * appears.
*/
switch (list_align) {
case STYLE_ALIGN_DEFAULT:
@@ -804,7 +804,7 @@ format_width(const char *expanded)
if (cp[0] == '#' && cp[1] == '[') {
end = format_skip(cp + 2, "]");
if (end == NULL)
- return 0;
+ return (0);
cp = end + 1;
} else if ((more = utf8_open(&ud, *cp)) == UTF8_MORE) {
while (*++cp != '\0' && more == UTF8_MORE)
diff --git a/format.c b/format.c
index 79e99b61..2e599c60 100644
--- a/format.c
+++ b/format.c
@@ -23,6 +23,7 @@
#include <errno.h>
#include <fnmatch.h>
#include <libgen.h>
+#include <math.h>
#include <regex.h>
#include <stdarg.h>
#include <stdlib.h>
@@ -49,7 +50,6 @@ static void format_add_tv(struct format_tree *, const char *,
struct timeval *);
static int format_replace(struct format_tree *, const char *, size_t,
char **, size_t *, size_t *);
-
static void format_defaults_session(struct format_tree *,
struct session *);
static void format_defaults_client(struct format_tree *, struct client *);
@@ -100,6 +100,7 @@ format_job_cmp(struct format_job *fj1, struct format_job *fj2)
#define FORMAT_SESSIONS 0x80
#define FORMAT_WINDOWS 0x100
#define FORMAT_PANES 0x200
+#define FORMAT_PRETTY 0x400
/* Limit on recursion. */
#define FORMAT_LOOP_LIMIT 10
@@ -354,7 +355,7 @@ format_job_get(struct format_tree *ft, const char *cmd)
if (force || (fj->job == NULL && fj->last != t)) {
fj->job = job_run(expanded, NULL,
server_client_get_cwd(ft->client, NULL), format_job_update,
- format_job_complete, NULL, fj, JOB_NOWAIT);
+ format_job_complete, NULL, fj, JOB_NOWAIT, -1, -1);
if (fj->job == NULL) {
free(fj->out);
xasprintf(&fj->out, "<'%s' didn't start>", fj->cmd);
@@ -900,11 +901,12 @@ static void
format_cb_pane_at_top(struct format_tree *ft, struct format_entry *fe)
{
struct window_pane *wp = ft->wp;
- struct window *w = wp->window;
+ struct window *w;
int status, flag;
if (wp == NULL)
return;
+ w = wp->window;
status = options_get_number(w->options, "pane-border-status");
if (status == PANE_STATUS_TOP)
@@ -919,11 +921,12 @@ static void
format_cb_pane_at_bottom(struct format_tree *ft, struct format_entry *fe)
{
struct window_pane *wp = ft->wp;
- struct window *w = wp->window;
+ struct window *w;
int status, flag;
if (wp == NULL)
return;
+ w = wp->window;
status = options_get_number(w->options, "pane-border-status");
if (status == PANE_STATUS_BOTTOM)
@@ -952,7 +955,7 @@ format_cb_cursor_character(struct format_tree *ft, struct format_entry *fe)
char *
format_grid_word(struct grid *gd, u_int x, u_int y)
{
- struct grid_line *gl;
+ const struct grid_line *gl;
struct grid_cell gc;
const char *ws;
struct utf8_data *ud = NULL;
@@ -963,7 +966,6 @@ format_grid_word(struct grid *gd, u_int x, u_int y)
ws = options_get_string(global_s_options, "word-separators");
- y = gd->hsize + y;
for (;;) {
grid_get_cell(gd, x, y, &gc);
if (gc.flags & GRID_FLAG_PADDING)
@@ -976,7 +978,7 @@ format_grid_word(struct grid *gd, u_int x, u_int y)
if (x == 0) {
if (y == 0)
break;
- gl = &gd->linedata[y - 1];
+ gl = grid_peek_line(gd, y - 1);
if (~gl->flags & GRID_LINE_WRAPPED)
break;
y--;
@@ -992,7 +994,7 @@ format_grid_word(struct grid *gd, u_int x, u_int y)
if (end == 0 || x == end - 1) {
if (y == gd->hsize + gd->sy - 1)
break;
- gl = &gd->linedata[y];
+ gl = grid_peek_line(gd, y);
if (~gl->flags & GRID_LINE_WRAPPED)
break;
y++;
@@ -1024,6 +1026,7 @@ static void
format_cb_mouse_word(struct format_tree *ft, struct format_entry *fe)
{
struct window_pane *wp;
+ struct grid *gd;
u_int x, y;
char *s;
@@ -1032,12 +1035,19 @@ format_cb_mouse_word(struct format_tree *ft, struct format_entry *fe)
wp = cmd_mouse_pane(&ft->m, NULL, NULL);
if (wp == NULL)
return;
- if (!TAILQ_EMPTY (&wp->modes))
- return;
if (cmd_mouse_at(wp, &ft->m, &x, &y, 0) != 0)
return;
- s = format_grid_word(wp->base.grid, x, y);
+ if (!TAILQ_EMPTY(&wp->modes)) {
+ if (TAILQ_FIRST(&wp->modes)->mode == &window_copy_mode ||
+ TAILQ_FIRST(&wp->modes)->mode == &window_view_mode)
+ s = window_copy_get_word(wp, x, y);
+ else
+ s = NULL;
+ } else {
+ gd = wp->base.grid;
+ s = format_grid_word(gd, x, gd->hsize + y);
+ }
if (s != NULL)
fe->value = s;
}
@@ -1052,7 +1062,6 @@ format_grid_line(struct grid *gd, u_int y)
size_t size = 0;
char *s = NULL;
- y = gd->hsize + y;
for (x = 0; x < grid_line_length(gd, y); x++) {
grid_get_cell(gd, x, y, &gc);
if (gc.flags & GRID_FLAG_PADDING)
@@ -1074,6 +1083,7 @@ static void
format_cb_mouse_line(struct format_tree *ft, struct format_entry *fe)
{
struct window_pane *wp;
+ struct grid *gd;
u_int x, y;
char *s;
@@ -1082,18 +1092,25 @@ format_cb_mouse_line(struct format_tree *ft, struct format_entry *fe)
wp = cmd_mouse_pane(&ft->m, NULL, NULL);
if (wp == NULL)
return;
- if (!TAILQ_EMPTY (&wp->modes))
- return;
if (cmd_mouse_at(wp, &ft->m, &x, &y, 0) != 0)
return;
- s = format_grid_line(wp->base.grid, y);
+ if (!TAILQ_EMPTY(&wp->modes)) {
+ if (TAILQ_FIRST(&wp->modes)->mode == &window_copy_mode ||
+ TAILQ_FIRST(&wp->modes)->mode == &window_view_mode)
+ s = window_copy_get_line(wp, y);
+ else
+ s = NULL;
+ } else {
+ gd = wp->base.grid;
+ s = format_grid_line(gd, gd->hsize + y);
+ }
if (s != NULL)
fe->value = s;
}
-/* Merge a format tree. */
-static void
+/* Merge one format tree into another. */
+void
format_merge(struct format_tree *ft, struct format_tree *from)
{
struct format_entry *fe;
@@ -1108,19 +1125,13 @@ format_merge(struct format_tree *ft, struct format_tree *from)
static void
format_create_add_item(struct format_tree *ft, struct cmdq_item *item)
{
- struct mouse_event *m;
+ struct key_event *event = cmdq_get_event(item);
+ struct mouse_event *m = &event->m;
struct window_pane *wp;
u_int x, y;
- if (item->cmd != NULL)
- format_add(ft, "command", "%s", item->cmd->entry->name);
-
- if (item->shared == NULL)
- return;
- if (item->shared->formats != NULL)
- format_merge(ft, item->shared->formats);
+ cmdq_merge_formats(item, ft);
- m = &item->shared->mouse;
if (m->valid && ((wp = cmd_mouse_pane(m, NULL, NULL)) != NULL)) {
format_add(ft, "mouse_pane", "%%%u", wp->id);
if (cmd_mouse_at(wp, m, &x, &y, 0) == 0) {
@@ -1312,6 +1323,53 @@ format_quote(const char *s)
return (out);
}
+/* Make a prettier time. */
+static char *
+format_pretty_time(time_t t)
+{
+ struct tm now_tm, tm;
+ time_t now;
+ char s[6];
+ int y, m, d;
+
+ time(&now);
+ if (now < t)
+ now = t;
+ localtime_r(&now, &now_tm);
+ localtime_r(&t, &tm);
+
+ y = now_tm.tm_year - 1;
+ if (tm.tm_year < y ||
+ (tm.tm_year == y &&
+ (tm.tm_mon <= now_tm.tm_mon || tm.tm_mday <= now_tm.tm_mday))) {
+ /* Last year. */
+ strftime(s, sizeof s, "%h%y", &tm);
+ return (xstrdup(s));
+ }
+ if (now_tm.tm_mon == 0)
+ m = 11;
+ else
+ m = now_tm.tm_mon - 1;
+ if (tm.tm_mon < m || (tm.tm_mon == m && tm.tm_mday < now_tm.tm_mday)) {
+ /* Last month. */
+ strftime(s, sizeof s, "%d%b", &tm);
+ return (xstrdup(s));
+ }
+ if (now_tm.tm_mday == 0)
+ d = 31;
+ else
+ d = now_tm.tm_mday - 1;
+ if (tm.tm_mday < d ||
+ (tm.tm_mday == d && tm.tm_mday < now_tm.tm_mday)) {
+ /* This day. */
+ strftime(s, sizeof s, "%a%d", &tm);
+ return (xstrdup(s));
+ }
+ /* Today. */
+ strftime(s, sizeof s, "%H:%M", &tm);
+ return (xstrdup(s));
+}
+
/* Find a format entry. */
static char *
format_find(struct format_tree *ft, const char *key, int modifiers)
@@ -1348,9 +1406,13 @@ format_find(struct format_tree *ft, const char *key, int modifiers)
if (modifiers & FORMAT_TIMESTRING) {
if (fe->t == 0)
return (NULL);
- ctime_r(&fe->t, s);
- s[strcspn(s, "\n")] = '\0';
- found = xstrdup(s);
+ if (modifiers & FORMAT_PRETTY)
+ found = format_pretty_time(fe->t);
+ else {
+ ctime_r(&fe->t, s);
+ s[strcspn(s, "\n")] = '\0';
+ found = xstrdup(s);
+ }
goto found;
}
if (fe->t != 0) {
@@ -1522,7 +1584,7 @@ format_build_modifiers(struct format_tree *ft, const char **s, u_int *count)
cp++;
/* Check single character modifiers with no arguments. */
- if (strchr("lbdtqETSWP<>", cp[0]) != NULL &&
+ if (strchr("lbdqETSWP<>", cp[0]) != NULL &&
format_is_end(cp[1])) {
format_add_modifier(&list, count, cp, 1, NULL, 0);
cp++;
@@ -1543,7 +1605,7 @@ format_build_modifiers(struct format_tree *ft, const char **s, u_int *count)
}
/* Now try single character with arguments. */
- if (strchr("mCs=p", cp[0]) == NULL)
+ if (strchr("mCst=pe", cp[0]) == NULL)
break;
c = cp[0];
@@ -1601,7 +1663,7 @@ format_build_modifiers(struct format_tree *ft, const char **s, u_int *count)
return (NULL);
}
*s = cp + 1;
- return list;
+ return (list);
}
/* Match against an fnmatch(3) pattern or regular expression. */
@@ -1799,6 +1861,108 @@ format_loop_panes(struct format_tree *ft, const char *fmt)
return (value);
}
+static char *
+format_replace_expression(struct format_modifier *mexp, struct format_tree *ft,
+ const char *copy)
+{
+ int argc = mexp->argc;
+ const char *errstr;
+ char *endch, *value, *left = NULL, *right = NULL;
+ int use_fp = 0;
+ u_int prec = 0;
+ double mleft, mright, result;
+ enum { ADD, SUBTRACT, MULTIPLY, DIVIDE, MODULUS } operator;
+
+ if (strcmp(mexp->argv[0], "+") == 0)
+ operator = ADD;
+ else if (strcmp(mexp->argv[0], "-") == 0)
+ operator = SUBTRACT;
+ else if (strcmp(mexp->argv[0], "*") == 0)
+ operator = MULTIPLY;
+ else if (strcmp(mexp->argv[0], "/") == 0)
+ operator = DIVIDE;
+ else if (strcmp(mexp->argv[0], "%") == 0 ||
+ strcmp(mexp->argv[0], "m") == 0)
+ operator = MODULUS;
+ else {
+ format_log(ft, "expression has no valid operator: '%s'",
+ mexp->argv[0]);
+ goto fail;
+ }
+
+ /* The second argument may be flags. */
+ if (argc >= 2 && strchr(mexp->argv[1], 'f') != NULL) {
+ use_fp = 1;
+ prec = 2;
+ }
+
+ /* The third argument may be precision. */
+ if (argc >= 3) {
+ prec = strtonum(mexp->argv[2], INT_MIN, INT_MAX, &errstr);
+ if (errstr != NULL) {
+ format_log (ft, "expression precision %s: %s", errstr,
+ mexp->argv[2]);
+ goto fail;
+ }
+ }
+
+ if (format_choose(ft, copy, &left, &right, 1) != 0) {
+ format_log(ft, "expression syntax error");
+ goto fail;
+ }
+
+ mleft = strtod(left, &endch);
+ if (*endch != '\0') {
+ format_log(ft, "expression left side is invalid: %s", left);
+ goto fail;
+ }
+
+ mright = strtod(right, &endch);
+ if (*endch != '\0') {
+ format_log(ft, "expression right side is invalid: %s", right);
+ goto fail;
+ }
+
+ if (!use_fp) {
+ mleft = (long long)mleft;
+ mright = (long long)mright;
+ }
+ format_log(ft, "expression left side is: %.*f", prec, mleft);
+ format_log(ft, "expression right side is: %.*f", prec, mright);
+
+ switch (operator) {
+ case ADD:
+ result = mleft + mright;
+ break;
+ case SUBTRACT:
+ result = mleft - mright;
+ break;
+ case MULTIPLY:
+ result = mleft * mright;
+ break;
+ case DIVIDE:
+ result = mleft / mright;
+ break;
+ case MODULUS:
+ result = fmod(mleft, mright);
+ break;
+ }
+ if (use_fp)
+ xasprintf(&value, "%.*f", prec, result);
+ else
+ xasprintf(&value, "%.*f", prec, (double)(long long)result);
+ format_log(ft, "expression result is %s", value);
+
+ free(right);
+ free(left);
+ return (value);
+
+fail:
+ free(right);
+ free(left);
+ return (NULL);
+}
+
/* Replace a key. */
static int
format_replace(struct format_tree *ft, const char *key, size_t keylen,
@@ -1811,7 +1975,7 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
size_t valuelen;
int modifiers = 0, limit = 0, width = 0, j;
struct format_modifier *list, *fm, *cmp = NULL, *search = NULL;
- struct format_modifier **sub = NULL;
+ struct format_modifier **sub = NULL, *mexp = NULL;
u_int i, count, nsub = 0;
/* Make a copy of the key. */
@@ -1863,6 +2027,11 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
if (errptr != NULL)
width = 0;
break;
+ case 'e':
+ if (fm->argc < 1 || fm->argc > 3)
+ break;
+ mexp = fm;
+ break;
case 'l':
modifiers |= FORMAT_LITERAL;
break;
@@ -1874,6 +2043,10 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
break;
case 't':
modifiers |= FORMAT_TIMESTRING;
+ if (fm->argc < 1)
+ break;
+ if (strchr(fm->argv[0], 'p') != NULL)
+ modifiers |= FORMAT_PRETTY;
break;
case 'q':
modifiers |= FORMAT_QUOTE;
@@ -2039,6 +2212,10 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
free(condition);
free(found);
+ } else if (mexp != NULL) {
+ value = format_replace_expression(mexp, ft, copy);
+ if (value == NULL)
+ value = xstrdup("");
} else {
/* Neither: look up directly. */
value = format_find(ft, copy, modifiers);
@@ -2295,15 +2472,59 @@ format_single(struct cmdq_item *item, const char *fmt, struct client *c,
struct format_tree *ft;
char *expanded;
+ ft = format_create_defaults(item, c, s, wl, wp);
+ expanded = format_expand(ft, fmt);
+ format_free(ft);
+ return (expanded);
+}
+
+/* Expand a single string using state. */
+char *
+format_single_from_state(struct cmdq_item *item, const char *fmt,
+ struct client *c, struct cmd_find_state *fs)
+{
+ return (format_single(item, fmt, c, fs->s, fs->wl, fs->wp));
+}
+
+/* Expand a single string using target. */
+char *
+format_single_from_target(struct cmdq_item *item, const char *fmt)
+{
+ struct client *tc = cmdq_get_target_client(item);
+
+ return (format_single_from_state(item, fmt, tc, cmdq_get_target(item)));
+}
+
+/* Create and add defaults. */
+struct format_tree *
+format_create_defaults(struct cmdq_item *item, struct client *c,
+ struct session *s, struct winlink *wl, struct window_pane *wp)
+{
+ struct format_tree *ft;
+
if (item != NULL)
- ft = format_create(item->client, item, FORMAT_NONE, 0);
+ ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0);
else
ft = format_create(NULL, item, FORMAT_NONE, 0);
format_defaults(ft, c, s, wl, wp);
+ return (ft);
+}
- expanded = format_expand(ft, fmt);
- format_free(ft);
- return (expanded);
+/* Create and add defaults using state. */
+struct format_tree *
+format_create_from_state(struct cmdq_item *item, struct client *c,
+ struct cmd_find_state *fs)
+{
+ return (format_create_defaults(item, c, fs->s, fs->wl, fs->wp));
+}
+
+/* Create and add defaults using target. */
+struct format_tree *
+format_create_from_target(struct cmdq_item *item)
+{
+ struct client *tc = cmdq_get_target_client(item);
+
+ return (format_create_from_state(item, tc, cmdq_get_target(item)));
}
/* Set defaults for any of arguments that are not NULL. */
@@ -2311,6 +2532,8 @@ void
format_defaults(struct format_tree *ft, struct client *c, struct session *s,
struct winlink *wl, struct window_pane *wp)
{
+ struct paste_buffer *pb;
+
if (c != NULL && c->name != NULL)
log_debug("%s: c=%s", __func__, c->name);
else
@@ -2320,7 +2543,7 @@ format_defaults(struct format_tree *ft, struct client *c, struct session *s,
else
log_debug("%s: s=none", __func__);
if (wl != NULL)
- log_debug("%s: wl=%u w=@%u", __func__, wl->idx, wl->window->id);
+ log_debug("%s: wl=%u", __func__, wl->idx);
else
log_debug("%s: wl=none", __func__);
if (wp != NULL)
@@ -2350,6 +2573,10 @@ format_defaults(struct format_tree *ft, struct client *c, struct session *s,
format_defaults_winlink(ft, wl);
if (wp != NULL)
format_defaults_pane(ft, wp);
+
+ pb = paste_get_top (NULL);
+ if (pb != NULL)
+ format_defaults_paste_buffer(ft, pb);
}
/* Set default format keys for a session. */
@@ -2361,6 +2588,7 @@ format_defaults_session(struct format_tree *ft, struct session *s)
ft->s = s;
format_add(ft, "session_name", "%s", s->name);
+ format_add(ft, "session_path", "%s", s->cwd);
format_add(ft, "session_windows", "%u", winlink_count(&s->windows));
format_add(ft, "session_id", "$%u", s->id);
@@ -2391,6 +2619,11 @@ format_defaults_session(struct format_tree *ft, struct session *s)
format_add_cb(ft, "session_alerts", format_cb_session_alerts);
format_add_cb(ft, "session_stack", format_cb_session_stack);
+
+ if (server_check_marked() && marked_pane.s == s)
+ format_add(ft, "session_marked", "1");
+ else
+ format_add(ft, "session_marked", "0");
}
/* Set default format keys for a client. */
@@ -2415,8 +2648,11 @@ format_defaults_client(struct format_tree *ft, struct client *c)
format_add(ft, "client_control_mode", "%d",
!!(c->flags & CLIENT_CONTROL));
- if (tty->term_name != NULL)
- format_add(ft, "client_termname", "%s", tty->term_name);
+ format_add(ft, "client_termname", "%s", c->term_name);
+ format_add(ft, "client_termfeatures", "%s",
+ tty_get_features(c->term_features));
+ if (c->term_type != NULL)
+ format_add(ft, "client_termtype", "%s", c->term_type);
format_add_tv(ft, "client_created", &c->creation_time);
format_add_tv(ft, "client_activity", &c->activity_time);
@@ -2431,7 +2667,7 @@ format_defaults_client(struct format_tree *ft, struct client *c)
format_add(ft, "client_prefix", "%d", 1);
format_add(ft, "client_key_table", "%s", c->keytable->name);
- if (tty->flags & TTY_UTF8)
+ if (c->flags & CLIENT_UTF8)
format_add(ft, "client_utf8", "%d", 1);
else
format_add(ft, "client_utf8", "%d", 0);
@@ -2481,11 +2717,9 @@ format_defaults_winlink(struct format_tree *ft, struct winlink *wl)
u_int ox, oy, sx, sy;
if (ft->w == NULL)
- ft->w = wl->window;
+ format_defaults_window(ft, w);
ft->wl = wl;
- format_defaults_window(ft, w);
-
if (c != NULL) {
flag = tty_window_offset(&c->tty, &ox, &oy, &sx, &sy);
format_add(ft, "window_bigger", "%d", flag);
@@ -2545,13 +2779,16 @@ format_defaults_pane(struct format_tree *ft, struct window_pane *wp)
struct window_mode_entry *wme;
if (ft->w == NULL)
- ft->w = w;
+ format_defaults_window(ft, w);
ft->wp = wp;
format_add(ft, "history_size", "%u", gd->hsize);
format_add(ft, "history_limit", "%u", gd->hlimit);
format_add_cb(ft, "history_bytes", format_cb_history_bytes);
+ format_add(ft, "pane_written", "%zu", wp->written);
+ format_add(ft, "pane_skipped", "%zu", wp->skipped);
+
if (window_pane_index(wp, &idx) != 0)
fatalx("index not found");
format_add(ft, "pane_index", "%u", idx);
@@ -2614,9 +2851,11 @@ format_defaults_pane(struct format_tree *ft, struct window_pane *wp)
format_add(ft, "scroll_region_upper", "%u", wp->base.rupper);
format_add(ft, "scroll_region_lower", "%u", wp->base.rlower);
- format_add(ft, "alternate_on", "%d", wp->saved_grid ? 1 : 0);
- format_add(ft, "alternate_saved_x", "%u", wp->saved_cx);
- format_add(ft, "alternate_saved_y", "%u", wp->saved_cy);
+ format_add(ft, "alternate_on", "%d", wp->base.saved_grid != NULL);
+ if (wp->base.saved_cx != UINT_MAX)
+ format_add(ft, "alternate_saved_x", "%u", wp->base.saved_cx);
+ if (wp->base.saved_cy != UINT_MAX)
+ format_add(ft, "alternate_saved_y", "%u", wp->base.saved_cy);
format_add(ft, "cursor_flag", "%d",
!!(wp->base.mode & MODE_CURSOR));
diff --git a/grid.c b/grid.c
index b2031045..81f3709c 100644
--- a/grid.c
+++ b/grid.c
@@ -48,8 +48,6 @@ static const struct grid_cell_entry grid_cleared_entry = {
GRID_FLAG_CLEARED, { .data = { 0, 8, 8, ' ' } }
};
-static void grid_empty_line(struct grid *, u_int, u_int);
-
/* Store cell in entry. */
static void
grid_store_cell(struct grid_cell_entry *gce, const struct grid_cell *gc,
@@ -213,19 +211,28 @@ grid_check_y(struct grid *gd, const char *from, u_int py)
return (0);
}
-/* Compare grid cells. Return 1 if equal, 0 if not. */
+/* Check if two styles are (visibly) the same. */
int
-grid_cells_equal(const struct grid_cell *gca, const struct grid_cell *gcb)
+grid_cells_look_equal(const struct grid_cell *gc1, const struct grid_cell *gc2)
{
- if (gca->fg != gcb->fg || gca->bg != gcb->bg)
+ if (gc1->fg != gc2->fg || gc1->bg != gc2->bg)
return (0);
- if (gca->attr != gcb->attr || gca->flags != gcb->flags)
+ if (gc1->attr != gc2->attr || gc1->flags != gc2->flags)
return (0);
- if (gca->data.width != gcb->data.width)
+ return (1);
+}
+
+/* Compare grid cells. Return 1 if equal, 0 if not. */
+int
+grid_cells_equal(const struct grid_cell *gc1, const struct grid_cell *gc2)
+{
+ if (!grid_cells_look_equal(gc1, gc2))
return (0);
- if (gca->data.size != gcb->data.size)
+ if (gc1->data.width != gc2->data.width)
return (0);
- return (memcmp(gca->data.data, gcb->data.data, gca->data.size) == 0);
+ if (gc1->data.size != gc2->data.size)
+ return (0);
+ return (memcmp(gc1->data.data, gc2->data.data, gc1->data.size) == 0);
}
/* Free one line. */
@@ -258,7 +265,10 @@ grid_create(u_int sx, u_int sy, u_int hlimit)
gd->sx = sx;
gd->sy = sy;
- gd->flags = GRID_HISTORY;
+ if (hlimit != 0)
+ gd->flags = GRID_HISTORY;
+ else
+ gd->flags = 0;
gd->hscrolled = 0;
gd->hsize = 0;
@@ -348,6 +358,19 @@ grid_collect_history(struct grid *gd)
gd->hscrolled = gd->hsize;
}
+/* Remove lines from the bottom of the history. */
+void
+grid_remove_history(struct grid *gd, u_int ny)
+{
+ u_int yy;
+
+ if (ny > gd->hsize)
+ return;
+ for (yy = 0; yy < ny; yy++)
+ grid_free_line(gd, gd->hsize + gd->sy - 1 - yy);
+ gd->hsize -= ny;
+}
+
/*
* 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.
@@ -438,7 +461,7 @@ grid_expand_line(struct grid *gd, u_int py, u_int sx, u_int bg)
}
/* Empty a line and set background colour if needed. */
-static void
+void
grid_empty_line(struct grid *gd, u_int py, u_int bg)
{
memset(&gd->linedata[py], 0, sizeof gd->linedata[py]);
@@ -755,15 +778,15 @@ grid_string_cells_bg(const struct grid_cell *gc, int *values)
case 8:
values[n++] = 49;
break;
- case 100:
- case 101:
- case 102:
- case 103:
- case 104:
- case 105:
- case 106:
- case 107:
- values[n++] = gc->bg - 10;
+ case 90:
+ case 91:
+ case 92:
+ case 93:
+ case 94:
+ case 95:
+ case 96:
+ case 97:
+ values[n++] = gc->bg + 10;
break;
}
}
@@ -1327,17 +1350,13 @@ grid_wrap_position(struct grid *gd, u_int px, u_int py, u_int *wx, u_int *wy)
void
grid_unwrap_position(struct grid *gd, u_int *px, u_int *py, u_int wx, u_int wy)
{
- u_int yy, ax = 0, ay = 0;
+ u_int yy, ay = 0;
for (yy = 0; yy < gd->hsize + gd->sy - 1; yy++) {
if (ay == wy)
break;
- if (gd->linedata[yy].flags & GRID_LINE_WRAPPED)
- ax += gd->linedata[yy].cellused;
- else {
- ax = 0;
+ if (~gd->linedata[yy].flags & GRID_LINE_WRAPPED)
ay++;
- }
}
/*
diff --git a/input-keys.c b/input-keys.c
index 69c5199e..04ecb264 100644
--- a/input-keys.c
+++ b/input-keys.c
@@ -148,9 +148,25 @@ input_split2(u_int c, u_char *dst)
return (1);
}
+/* Translate a key code into an output key sequence for a pane. */
+int
+input_key_pane(struct window_pane *wp, key_code key, struct mouse_event *m)
+{
+ log_debug("writing key 0x%llx (%s) to %%%u", key,
+ key_string_lookup_key(key), wp->id);
+
+ if (KEYC_IS_MOUSE(key)) {
+ if (m != NULL && m->wp != -1 && (u_int)m->wp == wp->id)
+ input_key_mouse(wp, m);
+ return (0);
+ }
+ return (input_key(wp, wp->screen, wp->event, key));
+}
+
/* Translate a key code into an output key sequence. */
int
-input_key(struct window_pane *wp, key_code key, struct mouse_event *m)
+input_key(struct window_pane *wp, struct screen *s, struct bufferevent *bev,
+ key_code key)
{
const struct input_key_ent *ike;
u_int i;
@@ -159,20 +175,14 @@ input_key(struct window_pane *wp, key_code key, struct mouse_event *m)
key_code justkey, newkey;
struct utf8_data ud;
- log_debug("writing key 0x%llx (%s) to %%%u", key,
- key_string_lookup_key(key), wp->id);
-
- /* If this is a mouse key, pass off to mouse function. */
- if (KEYC_IS_MOUSE(key)) {
- if (m != NULL && m->wp != -1 && (u_int)m->wp == wp->id)
- input_key_mouse(wp, m);
+ /* Mouse keys need a pane. */
+ if (KEYC_IS_MOUSE(key))
return (0);
- }
/* Literal keys go as themselves (can't be more than eight bits). */
if (key & KEYC_LITERAL) {
ud.data[0] = (u_char)key;
- bufferevent_write(wp->event, &ud.data[0], 1);
+ bufferevent_write(bev, &ud.data[0], 1);
return (0);
}
@@ -191,17 +201,17 @@ input_key(struct window_pane *wp, key_code key, struct mouse_event *m)
justkey = (key & ~(KEYC_XTERM|KEYC_ESCAPE));
if (justkey <= 0x7f) {
if (key & KEYC_ESCAPE)
- bufferevent_write(wp->event, "\033", 1);
+ bufferevent_write(bev, "\033", 1);
ud.data[0] = justkey;
- bufferevent_write(wp->event, &ud.data[0], 1);
+ bufferevent_write(bev, &ud.data[0], 1);
return (0);
}
if (justkey > 0x7f && justkey < KEYC_BASE) {
if (utf8_split(justkey, &ud) != UTF8_DONE)
return (-1);
if (key & KEYC_ESCAPE)
- bufferevent_write(wp->event, "\033", 1);
- bufferevent_write(wp->event, ud.data, ud.size);
+ bufferevent_write(bev, "\033", 1);
+ bufferevent_write(bev, ud.data, ud.size);
return (0);
}
@@ -209,9 +219,9 @@ input_key(struct window_pane *wp, key_code key, struct mouse_event *m)
* 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 (wp == NULL || options_get_number(wp->window->options, "xterm-keys")) {
if ((out = xterm_keys_lookup(key)) != NULL) {
- bufferevent_write(wp->event, out, strlen(out));
+ bufferevent_write(bev, out, strlen(out));
free(out);
return (0);
}
@@ -222,11 +232,9 @@ input_key(struct window_pane *wp, key_code key, struct mouse_event *m)
for (i = 0; i < nitems(input_keys); i++) {
ike = &input_keys[i];
- if ((ike->flags & INPUTKEY_KEYPAD) &&
- !(wp->screen->mode & MODE_KKEYPAD))
+ if ((ike->flags & INPUTKEY_KEYPAD) && (~s->mode & MODE_KKEYPAD))
continue;
- if ((ike->flags & INPUTKEY_CURSOR) &&
- !(wp->screen->mode & MODE_KCURSOR))
+ if ((ike->flags & INPUTKEY_CURSOR) && (~s->mode & MODE_KCURSOR))
continue;
if ((key & KEYC_ESCAPE) && (ike->key | KEYC_ESCAPE) == key)
@@ -243,32 +251,27 @@ input_key(struct window_pane *wp, key_code key, struct mouse_event *m)
/* Prefix a \033 for escape. */
if (key & KEYC_ESCAPE)
- bufferevent_write(wp->event, "\033", 1);
- bufferevent_write(wp->event, ike->data, dlen);
+ bufferevent_write(bev, "\033", 1);
+ bufferevent_write(bev, ike->data, dlen);
return (0);
}
-/* Translate mouse and output. */
-static void
-input_key_mouse(struct window_pane *wp, struct mouse_event *m)
+/* Get mouse event string. */
+int
+input_key_get_mouse(struct screen *s, struct mouse_event *m, u_int x, u_int y,
+ const char **rbuf, size_t *rlen)
{
- struct screen *s = wp->screen;
- int mode = s->mode;
- char buf[40];
+ static char buf[40];
size_t len;
- u_int x, y;
- if ((mode & ALL_MOUSE_MODES) == 0)
- return;
- if (cmd_mouse_at(wp, m, &x, &y, 0) != 0)
- return;
- if (!window_pane_visible(wp))
- return;
+ *rbuf = NULL;
+ *rlen = 0;
/* If this pane is not in button or all mode, discard motion events. */
- if (MOUSE_DRAG(m->b) &&
- (mode & (MODE_MOUSE_BUTTON|MODE_MOUSE_ALL)) == 0)
- return;
+ if (MOUSE_DRAG(m->b) && (s->mode & MOTION_MOUSE_MODES) == 0)
+ return (0);
+ if ((s->mode & ALL_MOUSE_MODES) == 0)
+ return (0);
/*
* If this event is a release event and not in all mode, discard it.
@@ -279,14 +282,14 @@ input_key_mouse(struct window_pane *wp, struct mouse_event *m)
if (m->sgr_type != ' ') {
if (MOUSE_DRAG(m->sgr_b) &&
MOUSE_BUTTONS(m->sgr_b) == 3 &&
- (~mode & MODE_MOUSE_ALL))
- return;
+ (~s->mode & MODE_MOUSE_ALL))
+ return (0);
} else {
if (MOUSE_DRAG(m->b) &&
MOUSE_BUTTONS(m->b) == 3 &&
MOUSE_BUTTONS(m->lb) == 3 &&
- (~mode & MODE_MOUSE_ALL))
- return;
+ (~s->mode & MODE_MOUSE_ALL))
+ return (0);
}
/*
@@ -303,19 +306,43 @@ input_key_mouse(struct window_pane *wp, struct mouse_event *m)
m->sgr_b, x + 1, y + 1, m->sgr_type);
} else if (s->mode & MODE_MOUSE_UTF8) {
if (m->b > 0x7ff - 32 || x > 0x7ff - 33 || y > 0x7ff - 33)
- return;
+ return (0);
len = xsnprintf(buf, sizeof buf, "\033[M");
len += input_split2(m->b + 32, &buf[len]);
len += input_split2(x + 33, &buf[len]);
len += input_split2(y + 33, &buf[len]);
} else {
if (m->b > 223)
- return;
+ return (0);
len = xsnprintf(buf, sizeof buf, "\033[M");
buf[len++] = m->b + 32;
buf[len++] = x + 33;
buf[len++] = y + 33;
}
+
+ *rbuf = buf;
+ *rlen = len;
+ return (1);
+}
+
+/* Translate mouse and output. */
+static void
+input_key_mouse(struct window_pane *wp, struct mouse_event *m)
+{
+ struct screen *s = wp->screen;
+ u_int x, y;
+ const char *buf;
+ size_t len;
+
+ /* Ignore events if no mouse mode or the pane is not visible. */
+ if (m->ignore || (s->mode & ALL_MOUSE_MODES) == 0)
+ return;
+ if (cmd_mouse_at(wp, m, &x, &y, 0) != 0)
+ return;
+ if (!window_pane_visible(wp))
+ return;
+ if (!input_key_get_mouse(s, m, x, y, &buf, &len))
+ return;
log_debug("writing mouse %.*s to %%%u", (int)len, buf, wp->id);
bufferevent_write(wp->event, buf, len);
}
diff --git a/input.c b/input.c
index e794be2a..70681e61 100644
--- a/input.c
+++ b/input.c
@@ -75,6 +75,7 @@ struct input_param {
/* Input parser context. */
struct input_ctx {
struct window_pane *wp;
+ struct bufferevent *event;
struct screen_write_ctx ctx;
struct input_cell cell;
@@ -128,7 +129,7 @@ struct input_transition;
static int input_split(struct input_ctx *);
static int input_get(struct input_ctx *, u_int, int, int);
static void printflike(2, 3) input_reply(struct input_ctx *, const char *, ...);
-static void input_set_state(struct window_pane *,
+static void input_set_state(struct input_ctx *,
const struct input_transition *);
static void input_reset_cell(struct input_ctx *);
@@ -253,6 +254,7 @@ enum input_csi_type {
INPUT_CSI_TBC,
INPUT_CSI_VPA,
INPUT_CSI_WINOPS,
+ INPUT_CSI_XDA,
};
/* Control (CSI) command table. */
@@ -289,6 +291,7 @@ static const struct input_table_entry input_csi_table[] = {
{ 'm', "", INPUT_CSI_SGR },
{ 'n', "", INPUT_CSI_DSR },
{ 'q', " ", INPUT_CSI_DECSCUSR },
+ { 'q', ">", INPUT_CSI_XDA },
{ 'r', "", INPUT_CSI_DECSTBM },
{ 's', "", INPUT_CSI_SCP },
{ 't', "", INPUT_CSI_WINOPS },
@@ -731,10 +734,9 @@ static void
input_timer_callback(__unused int fd, __unused short events, void *arg)
{
struct input_ctx *ictx = arg;
- struct window_pane *wp = ictx->wp;
- log_debug("%s: %%%u %s expired" , __func__, wp->id, ictx->state->name);
- input_reset(wp, 0);
+ log_debug("%s: %s expired" , __func__, ictx->state->name);
+ input_reset(ictx, 0);
}
/* Start the timer. */
@@ -788,12 +790,14 @@ input_restore_state(struct input_ctx *ictx)
}
/* Initialise input parser. */
-void
-input_init(struct window_pane *wp)
+struct input_ctx *
+input_init(struct window_pane *wp, struct bufferevent *bev)
{
struct input_ctx *ictx;
- ictx = wp->ictx = xcalloc(1, sizeof *ictx);
+ ictx = xcalloc(1, sizeof *ictx);
+ ictx->wp = wp;
+ ictx->event = bev;
ictx->input_space = INPUT_BUF_START;
ictx->input_buf = xmalloc(INPUT_BUF_START);
@@ -804,15 +808,15 @@ input_init(struct window_pane *wp)
evtimer_set(&ictx->timer, input_timer_callback, ictx);
- input_reset(wp, 0);
+ input_reset(ictx, 0);
+ return (ictx);
}
/* Destroy input parser. */
void
-input_free(struct window_pane *wp)
+input_free(struct input_ctx *ictx)
{
- struct input_ctx *ictx = wp->ictx;
- u_int i;
+ u_int i;
for (i = 0; i < ictx->param_list_len; i++) {
if (ictx->param_list[i].type == INPUT_STRING)
@@ -825,23 +829,22 @@ input_free(struct window_pane *wp)
evbuffer_free(ictx->since_ground);
free(ictx);
- wp->ictx = NULL;
}
/* Reset input state and clear screen. */
void
-input_reset(struct window_pane *wp, int clear)
+input_reset(struct input_ctx *ictx, int clear)
{
- struct input_ctx *ictx = wp->ictx;
struct screen_write_ctx *sctx = &ictx->ctx;
+ struct window_pane *wp = ictx->wp;
input_reset_cell(ictx);
- if (clear) {
+ if (clear && wp != NULL) {
if (TAILQ_EMPTY(&wp->modes))
- screen_write_start(sctx, wp, &wp->base);
+ screen_write_start_pane(sctx, wp, &wp->base);
else
- screen_write_start(sctx, NULL, &wp->base);
+ screen_write_start(sctx, &wp->base);
screen_write_reset(sctx);
screen_write_stop(sctx);
}
@@ -856,17 +859,15 @@ input_reset(struct window_pane *wp, int clear)
/* Return pending data. */
struct evbuffer *
-input_pending(struct window_pane *wp)
+input_pending(struct input_ctx *ictx)
{
- return (wp->ictx->since_ground);
+ return (ictx->since_ground);
}
/* Change input state. */
static void
-input_set_state(struct window_pane *wp, const struct input_transition *itr)
+input_set_state(struct input_ctx *ictx, const struct input_transition *itr)
{
- struct input_ctx *ictx = wp->ictx;
-
if (ictx->state->exit != NULL)
ictx->state->exit(ictx);
ictx->state = itr->state;
@@ -874,46 +875,15 @@ input_set_state(struct window_pane *wp, const struct input_transition *itr)
ictx->state->enter(ictx);
}
-/* Parse input. */
-void
-input_parse(struct window_pane *wp)
-{
- struct evbuffer *evb = wp->event->input;
-
- input_parse_buffer(wp, EVBUFFER_DATA(evb), EVBUFFER_LENGTH(evb));
- evbuffer_drain(evb, EVBUFFER_LENGTH(evb));
-}
-
-/* Parse given input. */
-void
-input_parse_buffer(struct window_pane *wp, u_char *buf, size_t len)
+/* Parse data. */
+static void
+input_parse(struct input_ctx *ictx, u_char *buf, size_t len)
{
- struct input_ctx *ictx = wp->ictx;
struct screen_write_ctx *sctx = &ictx->ctx;
const struct input_state *state = NULL;
const struct input_transition *itr = NULL;
size_t off = 0;
- if (len == 0)
- return;
-
- window_update_activity(wp->window);
- wp->flags |= PANE_CHANGED;
- notify_input(wp, buf, len);
-
- /*
- * Open the screen. Use NULL wp if there is a mode set as don't want to
- * update the tty.
- */
- if (TAILQ_EMPTY(&wp->modes))
- screen_write_start(sctx, wp, &wp->base);
- else
- screen_write_start(sctx, NULL, &wp->base);
- ictx->wp = wp;
-
- log_debug("%s: %%%u %s, %zu bytes: %.*s", __func__, wp->id,
- ictx->state->name, len, (int)len, buf);
-
/* Parse the input. */
while (off < len) {
ictx->ch = buf[off++];
@@ -956,14 +926,63 @@ input_parse_buffer(struct window_pane *wp, u_char *buf, size_t len)
/* And switch state, if necessary. */
if (itr->state != NULL)
- input_set_state(wp, itr);
+ input_set_state(ictx, itr);
/* If not in ground state, save input. */
if (ictx->state != &input_state_ground)
evbuffer_add(ictx->since_ground, &ictx->ch, 1);
}
+}
+
+/* Parse input from pane. */
+void
+input_parse_pane(struct window_pane *wp)
+{
+ struct evbuffer *evb = wp->event->input;
+
+ input_parse_buffer(wp, EVBUFFER_DATA(evb), EVBUFFER_LENGTH(evb));
+ evbuffer_drain(evb, EVBUFFER_LENGTH(evb));
+}
- /* Close the screen. */
+/* Parse given input. */
+void
+input_parse_buffer(struct window_pane *wp, u_char *buf, size_t len)
+{
+ struct input_ctx *ictx = wp->ictx;
+ struct screen_write_ctx *sctx = &ictx->ctx;
+
+ if (len == 0)
+ return;
+
+ window_update_activity(wp->window);
+ wp->flags |= PANE_CHANGED;
+ notify_input(wp, buf, len);
+
+ /* NULL wp if there is a mode set as don't want to update the tty. */
+ if (TAILQ_EMPTY(&wp->modes))
+ screen_write_start_pane(sctx, wp, &wp->base);
+ else
+ screen_write_start(sctx, &wp->base);
+
+ log_debug("%s: %%%u %s, %zu bytes: %.*s", __func__, wp->id,
+ ictx->state->name, len, (int)len, buf);
+
+ input_parse(ictx, buf, len);
+ screen_write_stop(sctx);
+}
+
+/* Parse given input for screen. */
+void
+input_parse_screen(struct input_ctx *ictx, struct screen *s,
+ screen_write_init_ctx_cb cb, void *arg, u_char *buf, size_t len)
+{
+ struct screen_write_ctx *sctx = &ictx->ctx;
+
+ if (len == 0)
+ return;
+
+ screen_write_start_callback(sctx, s, cb, arg);
+ input_parse(ictx, buf, len);
screen_write_stop(sctx);
}
@@ -1043,14 +1062,15 @@ input_get(struct input_ctx *ictx, u_int validx, int minval, int defval)
static void
input_reply(struct input_ctx *ictx, const char *fmt, ...)
{
- va_list ap;
- char *reply;
+ struct bufferevent *bev = ictx->event;
+ va_list ap;
+ char *reply;
va_start(ap, fmt);
xvasprintf(&reply, fmt, ap);
va_end(ap);
- bufferevent_write(ictx->wp->event, reply, strlen(reply));
+ bufferevent_write(bev, reply, strlen(reply));
free(reply);
}
@@ -1177,7 +1197,8 @@ input_c0_dispatch(struct input_ctx *ictx)
case '\000': /* NUL */
break;
case '\007': /* BEL */
- alerts_queue(wp->window, WINDOW_BELL);
+ if (wp != NULL)
+ alerts_queue(wp->window, WINDOW_BELL);
break;
case '\010': /* BS */
screen_write_backspace(sctx);
@@ -1224,6 +1245,7 @@ static int
input_esc_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;
@@ -1240,7 +1262,8 @@ input_esc_dispatch(struct input_ctx *ictx)
switch (entry->type) {
case INPUT_ESC_RIS:
- window_pane_reset_palette(ictx->wp);
+ if (wp != NULL)
+ window_pane_reset_palette(wp);
input_reset_cell(ictx);
screen_write_reset(sctx);
break;
@@ -1303,7 +1326,6 @@ input_csi_dispatch(struct input_ctx *ictx)
struct input_table_entry *entry;
int i, n, m;
u_int cx, bg = ictx->cell.cell.bg;
- char *copy, *cp;
if (ictx->flags & INPUT_DISCARD)
return (0);
@@ -1435,13 +1457,6 @@ input_csi_dispatch(struct input_ctx *ictx)
case 6:
input_reply(ictx, "\033[%u;%uR", s->cy + 1, s->cx + 1);
break;
- case 1337: /* Terminal version, from iTerm2. */
- copy = xstrdup(getversion());
- for (cp = copy; *cp != '\0'; cp++)
- *cp = toupper((u_char)*cp);
- input_reply(ictx, "\033[TMUX %sn", copy);
- free(copy);
- break;
default:
log_debug("%s: unknown '%c'", __func__, ictx->ch);
break;
@@ -1576,6 +1591,10 @@ input_csi_dispatch(struct input_ctx *ictx)
if (n != -1)
screen_set_cursor_style(s, n);
break;
+ case INPUT_CSI_XDA:
+ input_reply(ictx, "\033P>|tmux %s\033\\", getversion());
+ break;
+
}
ictx->last = -1;
@@ -1611,7 +1630,7 @@ static void
input_csi_dispatch_rm_private(struct input_ctx *ictx)
{
struct screen_write_ctx *sctx = &ictx->ctx;
- struct window_pane *wp = ictx->wp;
+ struct grid_cell *gc = &ictx->cell.cell;
u_int i;
for (i = 0; i < ictx->param_list_len; i++) {
@@ -1623,7 +1642,7 @@ input_csi_dispatch_rm_private(struct input_ctx *ictx)
break;
case 3: /* DECCOLM */
screen_write_cursormove(sctx, 0, 0, 1);
- screen_write_clearscreen(sctx, ictx->cell.cell.bg);
+ screen_write_clearscreen(sctx, gc->bg);
break;
case 6: /* DECOM */
screen_write_mode_clear(sctx, MODE_ORIGIN);
@@ -1655,10 +1674,10 @@ input_csi_dispatch_rm_private(struct input_ctx *ictx)
break;
case 47:
case 1047:
- window_pane_alternate_off(wp, &ictx->cell.cell, 0);
+ screen_write_alternateoff(sctx, gc, 0);
break;
case 1049:
- window_pane_alternate_off(wp, &ictx->cell.cell, 1);
+ screen_write_alternateoff(sctx, gc, 1);
break;
case 2004:
screen_write_mode_clear(sctx, MODE_BRACKETPASTE);
@@ -1700,6 +1719,7 @@ input_csi_dispatch_sm_private(struct input_ctx *ictx)
{
struct screen_write_ctx *sctx = &ictx->ctx;
struct window_pane *wp = ictx->wp;
+ struct grid_cell *gc = &ictx->cell.cell;
u_int i;
for (i = 0; i < ictx->param_list_len; i++) {
@@ -1742,7 +1762,8 @@ input_csi_dispatch_sm_private(struct input_ctx *ictx)
if (sctx->s->mode & MODE_FOCUSON)
break;
screen_write_mode_set(sctx, MODE_FOCUSON);
- wp->flags |= PANE_FOCUSPUSH; /* force update */
+ if (wp != NULL)
+ wp->flags |= PANE_FOCUSPUSH; /* force update */
break;
case 1005:
screen_write_mode_set(sctx, MODE_MOUSE_UTF8);
@@ -1752,10 +1773,10 @@ input_csi_dispatch_sm_private(struct input_ctx *ictx)
break;
case 47:
case 1047:
- window_pane_alternate_on(wp, &ictx->cell.cell, 0);
+ screen_write_alternateon(sctx, gc, 0);
break;
case 1049:
- window_pane_alternate_on(wp, &ictx->cell.cell, 1);
+ screen_write_alternateon(sctx, gc, 1);
break;
case 2004:
screen_write_mode_set(sctx, MODE_BRACKETPASTE);
@@ -1772,7 +1793,9 @@ static void
input_csi_dispatch_winops(struct input_ctx *ictx)
{
struct screen_write_ctx *sctx = &ictx->ctx;
+ struct screen *s = sctx->s;
struct window_pane *wp = ictx->wp;
+ u_int x = screen_size_x(s), y = screen_size_y(s);
int n, m;
m = 0;
@@ -1823,12 +1846,15 @@ input_csi_dispatch_winops(struct input_ctx *ictx)
case 0:
case 2:
screen_pop_title(sctx->s);
- server_status_window(ictx->wp->window);
+ if (wp != NULL) {
+ server_redraw_window_borders(wp->window);
+ server_status_window(wp->window);
+ }
break;
}
break;
case 18:
- input_reply(ictx, "\033[8;%u;%ut", wp->sy, wp->sx);
+ input_reply(ictx, "\033[8;%u;%ut", x, y);
break;
default:
log_debug("%s: unknown '%c'", __func__, ictx->ch);
@@ -2193,6 +2219,7 @@ static void
input_exit_osc(struct input_ctx *ictx)
{
struct screen_write_ctx *sctx = &ictx->ctx;
+ struct window_pane *wp = ictx->wp;
u_char *p = ictx->input_buf;
u_int option;
@@ -2213,8 +2240,10 @@ input_exit_osc(struct input_ctx *ictx)
switch (option) {
case 0:
case 2:
- if (screen_set_title(sctx->s, p))
- server_status_window(ictx->wp->window);
+ if (screen_set_title(sctx->s, p) && wp != NULL) {
+ server_redraw_window_borders(wp->window);
+ server_status_window(wp->window);
+ }
break;
case 4:
input_osc_4(ictx, p);
@@ -2222,7 +2251,10 @@ input_exit_osc(struct input_ctx *ictx)
case 7:
if (utf8_isvalid(p)) {
screen_set_path(sctx->s, p);
- server_status_window(ictx->wp->window);
+ if (wp != NULL) {
+ server_redraw_window_borders(wp->window);
+ server_status_window(wp->window);
+ }
}
break;
case 10:
@@ -2267,13 +2299,16 @@ static void
input_exit_apc(struct input_ctx *ictx)
{
struct screen_write_ctx *sctx = &ictx->ctx;
+ struct window_pane *wp = ictx->wp;
if (ictx->flags & INPUT_DISCARD)
return;
log_debug("%s: \"%s\"", __func__, ictx->input_buf);
- if (screen_set_title(sctx->s, ictx->input_buf))
- server_status_window(ictx->wp->window);
+ if (screen_set_title(sctx->s, ictx->input_buf) && wp != NULL) {
+ server_redraw_window_borders(wp->window);
+ server_status_window(wp->window);
+ }
}
/* Rename string started. */
@@ -2294,6 +2329,8 @@ input_exit_rename(struct input_ctx *ictx)
struct window_pane *wp = ictx->wp;
struct options_entry *oe;
+ if (wp == NULL)
+ return;
if (ictx->flags & INPUT_DISCARD)
return;
if (!options_get_number(ictx->wp->options, "allow-rename"))
@@ -2309,9 +2346,10 @@ input_exit_rename(struct input_ctx *ictx)
options_remove(oe);
return;
}
- 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);
+ window_set_name(wp->window, ictx->input_buf);
+ options_set_number(wp->window->options, "automatic-rename", 0);
+ server_redraw_window_borders(wp->window);
+ server_status_window(wp->window);
}
/* Open UTF-8 character. */
@@ -2407,6 +2445,9 @@ input_osc_4(struct input_ctx *ictx, const char *p)
long idx;
u_int r, g, b;
+ if (wp == NULL)
+ return;
+
copy = s = xstrdup(p);
while (s != NULL && *s != '\0') {
idx = strtol(s, &next, 10);
@@ -2439,16 +2480,15 @@ input_osc_10(struct input_ctx *ictx, const char *p)
{
struct window_pane *wp = ictx->wp;
u_int r, g, b;
- char tmp[16];
+ if (wp == NULL)
+ return;
if (strcmp(p, "?") == 0)
return;
if (!input_osc_parse_colour(p, &r, &g, &b))
goto bad;
- xsnprintf(tmp, sizeof tmp, "fg=#%02x%02x%02x", r, g, b);
- options_set_style(wp->options, "window-style", 1, tmp);
- options_set_style(wp->options, "window-active-style", 1, tmp);
+ wp->fg = colour_join_rgb(r, g, b);
wp->flags |= (PANE_REDRAW|PANE_STYLECHANGED);
return;
@@ -2463,16 +2503,15 @@ input_osc_11(struct input_ctx *ictx, const char *p)
{
struct window_pane *wp = ictx->wp;
u_int r, g, b;
- char tmp[16];
+ if (wp == NULL)
+ return;
if (strcmp(p, "?") == 0)
return;
if (!input_osc_parse_colour(p, &r, &g, &b))
goto bad;
- xsnprintf(tmp, sizeof tmp, "bg=#%02x%02x%02x", r, g, b);
- options_set_style(wp->options, "window-style", 1, tmp);
- options_set_style(wp->options, "window-active-style", 1, tmp);
+ wp->bg = colour_join_rgb(r, g, b);
wp->flags |= (PANE_REDRAW|PANE_STYLECHANGED);
return;
@@ -2494,6 +2533,8 @@ input_osc_52(struct input_ctx *ictx, const char *p)
struct screen_write_ctx ctx;
struct paste_buffer *pb;
+ if (wp == NULL)
+ return;
state = options_get_number(global_options, "set-clipboard");
if (state != 2)
return;
@@ -2518,13 +2559,13 @@ input_osc_52(struct input_ctx *ictx, const char *p)
outlen = 0;
out = NULL;
}
- bufferevent_write(wp->event, "\033]52;;", 6);
+ bufferevent_write(ictx->event, "\033]52;;", 6);
if (outlen != 0)
- bufferevent_write(wp->event, out, outlen);
+ bufferevent_write(ictx->event, out, outlen);
if (ictx->input_end == INPUT_END_BEL)
- bufferevent_write(wp->event, "\007", 1);
+ bufferevent_write(ictx->event, "\007", 1);
else
- bufferevent_write(wp->event, "\033\\", 2);
+ bufferevent_write(ictx->event, "\033\\", 2);
free(out);
return;
}
@@ -2539,7 +2580,7 @@ input_osc_52(struct input_ctx *ictx, const char *p)
return;
}
- screen_write_start(&ctx, wp, NULL);
+ screen_write_start_pane(&ctx, wp, NULL);
screen_write_setselection(&ctx, out, outlen);
screen_write_stop(&ctx);
notify_pane("pane-set-clipboard", wp);
@@ -2555,6 +2596,9 @@ input_osc_104(struct input_ctx *ictx, const char *p)
char *copy, *s;
long idx;
+ if (wp == NULL)
+ return;
+
if (*p == '\0') {
window_pane_reset_palette(wp);
return;
diff --git a/job.c b/job.c
index 10883e8e..6c1a3e09 100644
--- a/job.c
+++ b/job.c
@@ -17,7 +17,9 @@
*/
#include <sys/types.h>
+#include <sys/ioctl.h>
#include <sys/socket.h>
+#include <sys/wait.h>
#include <fcntl.h>
#include <signal.h>
@@ -68,18 +70,15 @@ static LIST_HEAD(joblist, job) all_jobs = LIST_HEAD_INITIALIZER(all_jobs);
struct job *
job_run(const char *cmd, struct session *s, const char *cwd,
job_update_cb updatecb, job_complete_cb completecb, job_free_cb freecb,
- void *data, int flags)
+ void *data, int flags, int sx, int sy)
{
struct job *job;
struct environ *env;
pid_t pid;
- int nullfd, out[2];
+ int nullfd, out[2], master;
const char *home;
sigset_t set, oldset;
-
- if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, out) != 0)
- return (NULL);
- log_debug("%s: cmd=%s, cwd=%s", __func__, cmd, cwd == NULL ? "" : cwd);
+ struct winsize ws;
/*
* Do not set TERM during .tmux.conf, it is nice to be able to use
@@ -89,13 +88,26 @@ job_run(const char *cmd, struct session *s, const char *cwd,
sigfillset(&set);
sigprocmask(SIG_BLOCK, &set, &oldset);
- switch (pid = fork()) {
+
+ if (flags & JOB_PTY) {
+ memset(&ws, 0, sizeof ws);
+ ws.ws_col = sx;
+ ws.ws_row = sy;
+ pid = fdforkpty(ptm_fd, &master, NULL, NULL, &ws);
+ } else {
+ if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, out) != 0)
+ goto fail;
+ pid = fork();
+ }
+ log_debug("%s: cmd=%s, cwd=%s", __func__, cmd, cwd == NULL ? "" : cwd);
+
+ switch (pid) {
case -1:
- sigprocmask(SIG_SETMASK, &oldset, NULL);
- environ_free(env);
- close(out[0]);
- close(out[1]);
- return (NULL);
+ if (~flags & JOB_PTY) {
+ close(out[0]);
+ close(out[1]);
+ }
+ goto fail;
case 0:
proc_clear_signals(server_proc, 1);
sigprocmask(SIG_SETMASK, &oldset, NULL);
@@ -108,22 +120,23 @@ job_run(const char *cmd, struct session *s, const char *cwd,
environ_push(env);
environ_free(env);
- if (dup2(out[1], STDIN_FILENO) == -1)
- fatal("dup2 failed");
- if (dup2(out[1], STDOUT_FILENO) == -1)
- fatal("dup2 failed");
- if (out[1] != STDIN_FILENO && out[1] != STDOUT_FILENO)
- close(out[1]);
- close(out[0]);
-
- nullfd = open(_PATH_DEVNULL, O_RDWR, 0);
- if (nullfd == -1)
- fatal("open failed");
- if (dup2(nullfd, STDERR_FILENO) == -1)
- fatal("dup2 failed");
- if (nullfd != STDERR_FILENO)
- close(nullfd);
-
+ if (~flags & JOB_PTY) {
+ if (dup2(out[1], STDIN_FILENO) == -1)
+ fatal("dup2 failed");
+ if (dup2(out[1], STDOUT_FILENO) == -1)
+ fatal("dup2 failed");
+ if (out[1] != STDIN_FILENO && out[1] != STDOUT_FILENO)
+ close(out[1]);
+ close(out[0]);
+
+ nullfd = open(_PATH_DEVNULL, O_RDWR, 0);
+ if (nullfd == -1)
+ fatal("open failed");
+ if (dup2(nullfd, STDERR_FILENO) == -1)
+ fatal("dup2 failed");
+ if (nullfd != STDERR_FILENO)
+ close(nullfd);
+ }
closefrom(STDERR_FILENO + 1);
execl(_PATH_BSHELL, "sh", "-c", cmd, (char *) NULL);
@@ -132,7 +145,6 @@ job_run(const char *cmd, struct session *s, const char *cwd,
sigprocmask(SIG_SETMASK, &oldset, NULL);
environ_free(env);
- close(out[1]);
job = xmalloc(sizeof *job);
job->state = JOB_RUNNING;
@@ -149,7 +161,11 @@ job_run(const char *cmd, struct session *s, const char *cwd,
job->freecb = freecb;
job->data = data;
- job->fd = out[0];
+ if (~flags & JOB_PTY) {
+ close(out[1]);
+ job->fd = out[0];
+ } else
+ job->fd = master;
setblocking(job->fd, 0);
job->event = bufferevent_new(job->fd, job_read_callback,
@@ -160,6 +176,11 @@ job_run(const char *cmd, struct session *s, const char *cwd,
log_debug("run job %p: %s, pid %ld", job, job->cmd, (long) job->pid);
return (job);
+
+fail:
+ sigprocmask(SIG_SETMASK, &oldset, NULL);
+ environ_free(env);
+ return (NULL);
}
/* Kill and free an individual job. */
@@ -184,6 +205,24 @@ job_free(struct job *job)
free(job);
}
+/* Resize job. */
+void
+job_resize(struct job *job, u_int sx, u_int sy)
+{
+ struct winsize ws;
+
+ if (job->fd == -1 || (~job->flags & JOB_PTY))
+ return;
+
+ log_debug("resize job %p: %ux%u", job, sx, sy);
+
+ memset(&ws, 0, sizeof ws);
+ ws.ws_col = sx;
+ ws.ws_row = sy;
+ if (ioctl(job->fd, TIOCSWINSZ, &ws) == -1)
+ fatal("ioctl failed");
+}
+
/* Job buffer read callback. */
static void
job_read_callback(__unused struct bufferevent *bufev, void *data)
@@ -208,7 +247,7 @@ job_write_callback(__unused struct bufferevent *bufev, void *data)
log_debug("job write %p: %s, pid %ld, output left %zu", job, job->cmd,
(long) job->pid, len);
- if (len == 0) {
+ if (len == 0 && (~job->flags & JOB_KEEPWRITE)) {
shutdown(job->fd, SHUT_WR);
bufferevent_disable(job->event, EV_WRITE);
}
@@ -245,6 +284,12 @@ job_check_died(pid_t pid, int status)
}
if (job == NULL)
return;
+ if (WIFSTOPPED(status)) {
+ if (WSTOPSIG(status) == SIGTTIN || WSTOPSIG(status) == SIGTTOU)
+ return;
+ killpg(job->pid, SIGCONT);
+ return;
+ }
log_debug("job died %p: %s, pid %ld", job, job->cmd, (long) job->pid);
job->status = status;
diff --git a/key-bindings.c b/key-bindings.c
index 4387c011..85bfb788 100644
--- a/key-bindings.c
+++ b/key-bindings.c
@@ -34,8 +34,8 @@
" 'New Session' 's' {new-session}" \
" 'New Window' 'w' {new-window}"
#define DEFAULT_WINDOW_MENU \
- " 'Swap Left' 'l' {swap-window -t:-1}" \
- " 'Swap Right' 'r' {swap-window -t:+1}" \
+ " '#{?#{>:#{session_windows},1},,-}Swap Left' 'l' {swap-window -t:-1}" \
+ " '#{?#{>:#{session_windows},1},,-}Swap Right' 'r' {swap-window -t:+1}" \
" '#{?pane_marked_set,,-}Swap Marked' 's' {swap-window}" \
" ''" \
" 'Kill' 'X' {kill-window}" \
@@ -46,22 +46,25 @@
" 'New After' 'w' {new-window -a}" \
" 'New At End' 'W' {new-window}"
#define DEFAULT_PANE_MENU \
- " '#{?mouse_word,Search For #[underscore]#{=/9/...:mouse_word},}' 'C-r' {copy-mode -t=; send -Xt= search-backward \"#{q:mouse_word}\"}" \
- " '#{?mouse_word,Type #[underscore]#{=/9/...:mouse_word},}' 'C-y' {send-keys -l -- \"#{q:mouse_word}\"}" \
- " '#{?mouse_word,Copy #[underscore]#{=/9/...:mouse_word},}' 'c' {set-buffer -- \"#{q:mouse_word}\"}" \
- " '#{?mouse_line,Copy Line,}' 'l' {set-buffer -- \"#{q:mouse_line}\"}" \
+ " '#{?#{m/r:(copy|view)-mode,#{pane_mode}},Go To Top,}' '<' {send -X history-top}" \
+ " '#{?#{m/r:(copy|view)-mode,#{pane_mode}},Go To Bottom,}' '>' {send -X history-bottom}" \
+ " ''" \
+ " '#{?mouse_word,Search For #[underscore]#{=/9/...:mouse_word},}' 'C-r' {if -F '#{?#{m/r:(copy|view)-mode,#{pane_mode}},0,1}' 'copy-mode -t='; send -Xt= search-backward \"#{q:mouse_word}\"}" \
+ " '#{?mouse_word,Type #[underscore]#{=/9/...:mouse_word},}' 'C-y' {copy-mode -q; send-keys -l -- \"#{q:mouse_word}\"}" \
+ " '#{?mouse_word,Copy #[underscore]#{=/9/...:mouse_word},}' 'c' {copy-mode -q; set-buffer -- \"#{q:mouse_word}\"}" \
+ " '#{?mouse_line,Copy Line,}' 'l' {copy-mode -q; set-buffer -- \"#{q:mouse_line}\"}" \
" ''" \
" 'Horizontal Split' 'h' {split-window -h}" \
" 'Vertical Split' 'v' {split-window -v}" \
" ''" \
- " 'Swap Up' 'u' {swap-pane -U}" \
- " 'Swap Down' 'd' {swap-pane -D}" \
+ " '#{?#{>:#{window_panes},1},,-}Swap Up' 'u' {swap-pane -U}" \
+ " '#{?#{>:#{window_panes},1},,-}Swap Down' 'd' {swap-pane -D}" \
" '#{?pane_marked_set,,-}Swap Marked' 's' {swap-pane}" \
" ''" \
" 'Kill' 'X' {kill-pane}" \
" 'Respawn' 'R' {respawn-pane -k}" \
" '#{?pane_marked,Unmark,Mark}' 'm' {select-pane -m}" \
- " '#{?window_zoomed_flag,Unzoom,Zoom}' 'z' {resize-pane -Z}"
+ " '#{?#{>:#{window_panes},1},,-}#{?window_zoomed_flag,Unzoom,Zoom}' 'z' {resize-pane -Z}"
static int key_bindings_cmp(struct key_binding *, struct key_binding *);
RB_GENERATE_STATIC(key_bindings, key_binding, entry, key_bindings_cmp);
@@ -229,6 +232,7 @@ void
key_bindings_init(void)
{
static const char *defaults[] = {
+ /* Prefix keys. */
"bind -N 'Send the prefix key' C-b send-prefix",
"bind -N 'Rotate through the panes' C-o rotate-window",
"bind -N 'Suspend the current client' C-z suspend-client",
@@ -239,12 +243,12 @@ key_bindings_init(void)
"bind -N 'Rename current session' '$' command-prompt -I'#S' \"rename-session -- '%%'\"",
"bind -N 'Split window horizontally' % split-window -h",
"bind -N 'Kill current window' & confirm-before -p\"kill-window #W? (y/n)\" kill-window",
- "bind -N 'Prompt for window index to select' \"'\" command-prompt -pindex \"select-window -t ':%%'\"",
+ "bind -N 'Prompt for window index to select' \"'\" command-prompt -Wpindex \"select-window -t ':%%'\"",
"bind -N 'Switch to previous client' ( switch-client -p",
"bind -N 'Switch to next client' ) switch-client -n",
"bind -N 'Rename current window' , command-prompt -I'#W' \"rename-window -- '%%'\"",
"bind -N 'Delete the most recent paste buffer' - delete-buffer",
- "bind -N 'Move the current window' . command-prompt \"move-window -t '%%'\"",
+ "bind -N 'Move the current window' . command-prompt -T \"move-window -t '%%'\"",
"bind -N 'Describe key binding' '/' command-prompt -kpkey 'list-keys -1N \"%%%\"'",
"bind -N 'Select window 0' 0 select-window -t:=0",
"bind -N 'Select window 1' 1 select-window -t:=1",
@@ -312,21 +316,51 @@ key_bindings_init(void)
"bind -N 'Resize the pane left' -r C-Left resize-pane -L",
"bind -N 'Resize the pane right' -r C-Right resize-pane -R",
- "bind -n MouseDown1Pane select-pane -t=\\; send-keys -M",
+ /* Menu keys */
+ "bind < display-menu -xW -yW -T '#[align=centre]#{window_index}:#{window_name}' " DEFAULT_WINDOW_MENU,
+ "bind > display-menu -xP -yP -T '#[align=centre]#{pane_index} (#{pane_id})' " DEFAULT_PANE_MENU,
+
+ /* Mouse button 1 down on pane. */
+ "bind -n MouseDown1Pane select-pane -t=\\; send -M",
+
+ /* Mouse button 1 drag on pane. */
+ "bind -n MouseDrag1Pane if -F '#{||:#{pane_in_mode},#{mouse_any_flag}}' { send -M } { copy-mode -M }",
+
+ /* Mouse wheel up on pane. */
+ "bind -n WheelUpPane if -F '#{||:#{pane_in_mode},#{mouse_any_flag}}' { send -M } { copy-mode -e }",
+
+ /* Mouse button 2 down on pane. */
+ "bind -n MouseDown2Pane select-pane -t=\\; if -F '#{||:#{pane_in_mode},#{mouse_any_flag}}' { send -M } { paste -p }",
+
+ /* Mouse button 1 double click on pane. */
+ "bind -n DoubleClick1Pane select-pane -t=\\; if -F '#{||:#{pane_in_mode},#{mouse_any_flag}}' { send -M } { copy-mode -H; send -X select-word; run -d0.3; send -X copy-pipe-and-cancel }",
+
+ /* Mouse button 1 triple click on pane. */
+ "bind -n TripleClick1Pane select-pane -t=\\; if -F '#{||:#{pane_in_mode},#{mouse_any_flag}}' { send -M } { copy-mode -H; send -X select-line; run -d0.3; send -X copy-pipe-and-cancel }",
+
+ /* Mouse button 1 drag on border. */
"bind -n MouseDrag1Border resize-pane -M",
+
+ /* Mouse button 1 down on status line. */
"bind -n MouseDown1Status select-window -t=",
+
+ /* Mouse wheel down on status line. */
"bind -n WheelDownStatus next-window",
+
+ /* Mouse wheel up on status line. */
"bind -n WheelUpStatus previous-window",
- "bind -n MouseDrag1Pane if -Ft= '#{mouse_any_flag}' 'if -Ft= \"#{pane_in_mode}\" \"copy-mode -M\" \"send-keys -M\"' 'copy-mode -M'",
- "bind -n WheelUpPane if -Ft= '#{mouse_any_flag}' 'send-keys -M' 'if -Ft= \"#{pane_in_mode}\" \"send-keys -M\" \"copy-mode -et=\"'",
- "bind -n MouseDown3StatusLeft display-menu -t= -xM -yS -T \"#[align=centre]#{session_name}\" " DEFAULT_SESSION_MENU,
- "bind -n MouseDown3Status display-menu -t= -xW -yS -T \"#[align=centre]#{window_index}:#{window_name}\" " DEFAULT_WINDOW_MENU,
- "bind < display-menu -xW -yS -T \"#[align=centre]#{window_index}:#{window_name}\" " DEFAULT_WINDOW_MENU,
- "bind -n MouseDown3Pane if -Ft= '#{||:#{mouse_any_flag},#{pane_in_mode}}' 'select-pane -t=; send-keys -M' {display-menu -t= -xM -yM -T \"#[align=centre]#{pane_index} (#{pane_id})\" " DEFAULT_PANE_MENU "}",
- "bind -n M-MouseDown3Pane display-menu -t= -xM -yM -T \"#[align=centre]#{pane_index} (#{pane_id})\" " DEFAULT_PANE_MENU,
- "bind > display-menu -xP -yP -T \"#[align=centre]#{pane_index} (#{pane_id})\" " DEFAULT_PANE_MENU,
+ /* Mouse button 3 down on status left. */
+ "bind -n MouseDown3StatusLeft display-menu -t= -xM -yW -T '#[align=centre]#{session_name}' " DEFAULT_SESSION_MENU,
+
+ /* Mouse button 3 down on status line. */
+ "bind -n MouseDown3Status display-menu -t= -xW -yW -T '#[align=centre]#{window_index}:#{window_name}' " DEFAULT_WINDOW_MENU,
+
+ /* Mouse button 3 down on pane. */
+ "bind -n MouseDown3Pane if -Ft= '#{||:#{mouse_any_flag},#{&&:#{pane_in_mode},#{?#{m/r:(copy|view)-mode,#{pane_mode}},0,1}}}' { select-pane -t=; send -M } { display-menu -t= -xM -yM -T '#[align=centre]#{pane_index} (#{pane_id})' " DEFAULT_PANE_MENU " }",
+ "bind -n M-MouseDown3Pane display-menu -t= -xM -yM -T '#[align=centre]#{pane_index} (#{pane_id})' " DEFAULT_PANE_MENU,
+ /* Copy mode (emacs) keys. */
"bind -Tcopy-mode C-Space send -X begin-selection",
"bind -Tcopy-mode C-a send -X start-of-line",
"bind -Tcopy-mode C-c send -X cancel",
@@ -340,7 +374,7 @@ key_bindings_init(void)
"bind -Tcopy-mode C-r command-prompt -ip'(search up)' -I'#{pane_search_string}' 'send -X search-backward-incremental \"%%%\"'",
"bind -Tcopy-mode C-s command-prompt -ip'(search down)' -I'#{pane_search_string}' 'send -X search-forward-incremental \"%%%\"'",
"bind -Tcopy-mode C-v send -X page-down",
- "bind -Tcopy-mode C-w send -X copy-selection-and-cancel",
+ "bind -Tcopy-mode C-w send -X copy-pipe-and-cancel",
"bind -Tcopy-mode Escape send -X cancel",
"bind -Tcopy-mode Space send -X page-down",
"bind -Tcopy-mode , send -X jump-reverse",
@@ -353,16 +387,17 @@ key_bindings_init(void)
"bind -Tcopy-mode g command-prompt -p'(goto line)' 'send -X goto-line \"%%%\"'",
"bind -Tcopy-mode n send -X search-again",
"bind -Tcopy-mode q send -X cancel",
+ "bind -Tcopy-mode r send -X refresh-from-pane",
"bind -Tcopy-mode t command-prompt -1p'(jump to forward)' 'send -X jump-to-forward \"%%%\"'",
"bind -Tcopy-mode Home send -X start-of-line",
"bind -Tcopy-mode End send -X end-of-line",
"bind -Tcopy-mode MouseDown1Pane select-pane",
"bind -Tcopy-mode MouseDrag1Pane select-pane\\; send -X begin-selection",
- "bind -Tcopy-mode MouseDragEnd1Pane send -X copy-selection-and-cancel",
+ "bind -Tcopy-mode MouseDragEnd1Pane send -X copy-pipe-and-cancel",
"bind -Tcopy-mode WheelUpPane select-pane\\; send -N5 -X scroll-up",
"bind -Tcopy-mode WheelDownPane select-pane\\; send -N5 -X scroll-down",
- "bind -Tcopy-mode DoubleClick1Pane select-pane\\; send -X select-word",
- "bind -Tcopy-mode TripleClick1Pane select-pane\\; send -X select-line",
+ "bind -Tcopy-mode DoubleClick1Pane select-pane\\; send -X select-word\\; run -d0.3\\; send -X copy-pipe-and-cancel",
+ "bind -Tcopy-mode TripleClick1Pane select-pane\\; send -X select-line\\; run -d0.3\\; send -X copy-pipe-and-cancel",
"bind -Tcopy-mode NPage send -X page-down",
"bind -Tcopy-mode PPage send -X page-up",
"bind -Tcopy-mode Up send -X cursor-up",
@@ -388,7 +423,7 @@ key_bindings_init(void)
"bind -Tcopy-mode M-m send -X back-to-indentation",
"bind -Tcopy-mode M-r send -X middle-line",
"bind -Tcopy-mode M-v send -X page-up",
- "bind -Tcopy-mode M-w send -X copy-selection-and-cancel",
+ "bind -Tcopy-mode M-w send -X copy-pipe-and-cancel",
"bind -Tcopy-mode 'M-{' send -X previous-paragraph",
"bind -Tcopy-mode 'M-}' send -X next-paragraph",
"bind -Tcopy-mode M-Up send -X halfpage-up",
@@ -396,6 +431,7 @@ key_bindings_init(void)
"bind -Tcopy-mode C-Up send -X scroll-up",
"bind -Tcopy-mode C-Down send -X scroll-down",
+ /* Copy mode (vi) keys. */
"bind -Tcopy-mode-vi '#' send -FX search-backward '#{copy_cursor_word}'",
"bind -Tcopy-mode-vi * send -FX search-forward '#{copy_cursor_word}'",
"bind -Tcopy-mode-vi C-c send -X cancel",
@@ -404,8 +440,8 @@ key_bindings_init(void)
"bind -Tcopy-mode-vi C-b send -X page-up",
"bind -Tcopy-mode-vi C-f send -X page-down",
"bind -Tcopy-mode-vi C-h send -X cursor-left",
- "bind -Tcopy-mode-vi C-j send -X copy-selection-and-cancel",
- "bind -Tcopy-mode-vi Enter send -X copy-selection-and-cancel",
+ "bind -Tcopy-mode-vi C-j send -X copy-pipe-and-cancel",
+ "bind -Tcopy-mode-vi Enter send -X copy-pipe-and-cancel",
"bind -Tcopy-mode-vi C-u send -X halfpage-up",
"bind -Tcopy-mode-vi C-v send -X rectangle-toggle",
"bind -Tcopy-mode-vi C-y send -X scroll-up",
@@ -454,6 +490,7 @@ key_bindings_init(void)
"bind -Tcopy-mode-vi n send -X search-again",
"bind -Tcopy-mode-vi o send -X other-end",
"bind -Tcopy-mode-vi q send -X cancel",
+ "bind -Tcopy-mode-vi r send -X refresh-from-pane",
"bind -Tcopy-mode-vi t command-prompt -1p'(jump to forward)' 'send -X jump-to-forward \"%%%\"'",
"bind -Tcopy-mode-vi v send -X rectangle-toggle",
"bind -Tcopy-mode-vi w send -X next-word",
@@ -462,11 +499,11 @@ key_bindings_init(void)
"bind -Tcopy-mode-vi % send -X next-matching-bracket",
"bind -Tcopy-mode-vi MouseDown1Pane select-pane",
"bind -Tcopy-mode-vi MouseDrag1Pane select-pane\\; send -X begin-selection",
- "bind -Tcopy-mode-vi MouseDragEnd1Pane send -X copy-selection-and-cancel",
+ "bind -Tcopy-mode-vi MouseDragEnd1Pane send -X copy-pipe-and-cancel",
"bind -Tcopy-mode-vi WheelUpPane select-pane\\; send -N5 -X scroll-up",
"bind -Tcopy-mode-vi WheelDownPane select-pane\\; send -N5 -X scroll-down",
- "bind -Tcopy-mode-vi DoubleClick1Pane select-pane\\; send -X select-word",
- "bind -Tcopy-mode-vi TripleClick1Pane select-pane\\; send -X select-line",
+ "bind -Tcopy-mode-vi DoubleClick1Pane select-pane\\; send -X select-word\\; run -d0.3\\; send -X copy-pipe-and-cancel",
+ "bind -Tcopy-mode-vi TripleClick1Pane select-pane\\; send -X select-line\\; run -d0.3\\; send -X copy-pipe-and-cancel",
"bind -Tcopy-mode-vi BSpace send -X cursor-left",
"bind -Tcopy-mode-vi NPage send -X page-down",
"bind -Tcopy-mode-vi PPage send -X page-up",
@@ -484,7 +521,7 @@ key_bindings_init(void)
pr = cmd_parse_from_string(defaults[i], NULL);
if (pr->status != CMD_PARSE_SUCCESS)
fatalx("bad default key: %s", defaults[i]);
- cmdq_append(NULL, cmdq_get_command(pr->cmdlist, NULL, NULL, 0));
+ cmdq_append(NULL, cmdq_get_command(pr->cmdlist, NULL));
cmd_list_free(pr->cmdlist);
}
}
@@ -498,27 +535,24 @@ key_bindings_read_only(struct cmdq_item *item, __unused void *data)
struct cmdq_item *
key_bindings_dispatch(struct key_binding *bd, struct cmdq_item *item,
- struct client *c, struct mouse_event *m, struct cmd_find_state *fs)
+ struct client *c, struct key_event *event, struct cmd_find_state *fs)
{
- struct cmd *cmd;
struct cmdq_item *new_item;
- int readonly;
+ struct cmdq_state *new_state;
+ int readonly, flags = 0;
if (c == NULL || (~c->flags & CLIENT_READONLY))
readonly = 1;
- else {
- readonly = 1;
- TAILQ_FOREACH(cmd, &bd->cmdlist->list, qentry) {
- if (~cmd->entry->flags & CMD_READONLY)
- readonly = 0;
- }
- }
+ else
+ readonly = cmd_list_all_have(bd->cmdlist, CMD_READONLY);
if (!readonly)
new_item = cmdq_get_callback(key_bindings_read_only, NULL);
else {
- new_item = cmdq_get_command(bd->cmdlist, fs, m, 0);
if (bd->flags & KEY_BINDING_REPEAT)
- new_item->shared->flags |= CMDQ_SHARED_REPEAT;
+ flags |= CMDQ_STATE_REPEAT;
+ new_state = cmdq_new_state(fs, event, flags);
+ new_item = cmdq_get_command(bd->cmdlist, new_state);
+ cmdq_free_state(new_state);
}
if (item != NULL)
new_item = cmdq_insert_after(item, new_item);
diff --git a/key-string.c b/key-string.c
index 38e5b8a7..2a0602b2 100644
--- a/key-string.c
+++ b/key-string.c
@@ -100,6 +100,9 @@ static const struct {
KEYC_MOUSE_STRING(MOUSEDRAGEND3, MouseDragEnd3),
KEYC_MOUSE_STRING(WHEELUP, WheelUp),
KEYC_MOUSE_STRING(WHEELDOWN, WheelDown),
+ KEYC_MOUSE_STRING(SECONDCLICK1, SecondClick1),
+ KEYC_MOUSE_STRING(SECONDCLICK2, SecondClick2),
+ KEYC_MOUSE_STRING(SECONDCLICK3, SecondClick3),
KEYC_MOUSE_STRING(DOUBLECLICK1, DoubleClick1),
KEYC_MOUSE_STRING(DOUBLECLICK2, DoubleClick2),
KEYC_MOUSE_STRING(DOUBLECLICK3, DoubleClick3),
@@ -226,10 +229,8 @@ key_string_lookup_string(const char *string)
key -= 64;
else if (key == 32)
key = 0;
- else if (key == '?')
- key = 127;
else if (key == 63)
- key = KEYC_BSPACE;
+ key = 127;
else
return (KEYC_UNKNOWN);
modifiers &= ~KEYC_CTRL;
diff --git a/layout-set.c b/layout-set.c
index f712b059..9ef28416 100644
--- a/layout-set.c
+++ b/layout-set.c
@@ -18,6 +18,7 @@
#include <sys/types.h>
+#include <stdlib.h>
#include <string.h>
#include "tmux.h"
@@ -186,6 +187,8 @@ layout_set_main_h(struct window *w)
struct window_pane *wp;
struct layout_cell *lc, *lcmain, *lcother, *lcchild;
u_int n, mainh, otherh, sx, sy;
+ char *cause;
+ const char *s;
layout_print_cell(w->layout_root, __func__, 1);
@@ -198,8 +201,15 @@ layout_set_main_h(struct window *w)
/* Find available height - take off one line for the border. */
sy = w->sy - 1;
- /* Get the main pane height and work out the other pane height. */
- mainh = options_get_number(w->options, "main-pane-height");
+ /* Get the main pane height. */
+ s = options_get_string(w->options, "main-pane-height");
+ mainh = args_string_percentage(s, 0, sy, sy, &cause);
+ if (cause != NULL) {
+ mainh = 24;
+ free(cause);
+ }
+
+ /* Work out the other pane height. */
if (mainh + PANE_MINIMUM >= sy) {
if (sy <= PANE_MINIMUM + PANE_MINIMUM)
mainh = PANE_MINIMUM;
@@ -207,10 +217,12 @@ layout_set_main_h(struct window *w)
mainh = sy - PANE_MINIMUM;
otherh = PANE_MINIMUM;
} else {
- otherh = options_get_number(w->options, "other-pane-height");
- if (otherh == 0)
+ s = options_get_string(w->options, "other-pane-height");
+ otherh = args_string_percentage(s, 0, sy, sy, &cause);
+ if (cause != NULL || otherh == 0) {
otherh = sy - mainh;
- else if (otherh > sy || sy - otherh < mainh)
+ free(cause);
+ } else if (otherh > sy || sy - otherh < mainh)
otherh = sy - mainh;
else
mainh = sy - otherh;
@@ -273,6 +285,8 @@ layout_set_main_v(struct window *w)
struct window_pane *wp;
struct layout_cell *lc, *lcmain, *lcother, *lcchild;
u_int n, mainw, otherw, sx, sy;
+ char *cause;
+ const char *s;
layout_print_cell(w->layout_root, __func__, 1);
@@ -285,8 +299,15 @@ layout_set_main_v(struct window *w)
/* Find available width - take off one line for the border. */
sx = w->sx - 1;
- /* Get the main pane width and work out the other pane width. */
- mainw = options_get_number(w->options, "main-pane-width");
+ /* Get the main pane width. */
+ s = options_get_string(w->options, "main-pane-width");
+ mainw = args_string_percentage(s, 0, sx, sx, &cause);
+ if (cause != NULL) {
+ mainw = 80;
+ free(cause);
+ }
+
+ /* Work out the other pane width. */
if (mainw + PANE_MINIMUM >= sx) {
if (sx <= PANE_MINIMUM + PANE_MINIMUM)
mainw = PANE_MINIMUM;
@@ -294,10 +315,12 @@ layout_set_main_v(struct window *w)
mainw = sx - PANE_MINIMUM;
otherw = PANE_MINIMUM;
} else {
- otherw = options_get_number(w->options, "other-pane-width");
- if (otherw == 0)
+ s = options_get_string(w->options, "other-pane-width");
+ otherw = args_string_percentage(s, 0, sx, sx, &cause);
+ if (cause != NULL || otherw == 0) {
otherw = sx - mainw;
- else if (otherw > sx || sx - otherw < mainw)
+ free(cause);
+ } else if (otherw > sx || sx - otherw < mainw)
otherw = sx - mainw;
else
mainw = sx - otherw;
diff --git a/menu.c b/menu.c
index 6024ba02..07fc8fa8 100644
--- a/menu.c
+++ b/menu.c
@@ -73,7 +73,7 @@ menu_add_item(struct menu *menu, const struct menu_item *item,
return;
if (fs != NULL)
- s = format_single(qitem, item->name, c, fs->s, fs->wl, fs->wp);
+ s = format_single_from_state(qitem, item->name, c, fs);
else
s = format_single(qitem, item->name, c, NULL, NULL, NULL);
if (*s == '\0') { /* no item if empty after format expanded */
@@ -91,7 +91,7 @@ menu_add_item(struct menu *menu, const struct menu_item *item,
cmd = item->command;
if (cmd != NULL) {
if (fs != NULL)
- s = format_single(qitem, cmd, c, fs->s, fs->wl, fs->wp);
+ s = format_single_from_state(qitem, cmd, c, fs);
else
s = format_single(qitem, cmd, c, NULL, NULL, NULL);
} else
@@ -130,6 +130,14 @@ menu_free(struct menu *menu)
free(menu);
}
+static struct screen *
+menu_mode_cb(struct client *c, __unused u_int *cx, __unused u_int *cy)
+{
+ struct menu_data *md = c->overlay_data;
+
+ return (&md->s);
+}
+
static void
menu_draw_cb(struct client *c, __unused struct screen_redraw_ctx *ctx0)
{
@@ -138,21 +146,20 @@ menu_draw_cb(struct client *c, __unused struct screen_redraw_ctx *ctx0)
struct screen *s = &md->s;
struct menu *menu = md->menu;
struct screen_write_ctx ctx;
- u_int i, px, py;
+ u_int i, px = md->px, py = md->py;
+ struct grid_cell gc;
- screen_write_start(&ctx, NULL, s);
+ style_apply(&gc, c->session->curw->window->options, "mode-style", NULL);
+
+ screen_write_start(&ctx, s);
screen_write_clearscreen(&ctx, 8);
- screen_write_menu(&ctx, menu, md->choice);
+ screen_write_menu(&ctx, menu, md->choice, &gc);
screen_write_stop(&ctx);
- px = md->px;
- py = md->py;
-
- for (i = 0; i < screen_size_y(&md->s); i++)
- tty_draw_line(tty, NULL, s, 0, i, menu->width + 4, px, py + i);
-
- if (~md->flags & MENU_NOMOUSE)
- tty_update_mode(tty, MODE_MOUSE_ALL, NULL);
+ for (i = 0; i < screen_size_y(&md->s); i++) {
+ tty_draw_line(tty, s, 0, i, menu->width + 4, px, py + i,
+ &grid_default_cell, NULL);
+ }
}
static void
@@ -179,10 +186,11 @@ menu_key_cb(struct client *c, struct key_event *event)
struct mouse_event *m = &event->m;
u_int i;
int count = menu->count, old = md->choice;
- const struct menu_item *item;
- struct cmdq_item *new_item;
- struct cmd_parse_result *pr;
const char *name;
+ const struct menu_item *item;
+ struct cmdq_state *state;
+ enum cmd_parse_status status;
+ char *error;
if (KEYC_IS_MOUSE(event->key)) {
if (md->flags & MENU_NOMOUSE) {
@@ -232,6 +240,16 @@ menu_key_cb(struct client *c, struct key_event *event)
} while ((name == NULL || *name == '-') && md->choice != old);
c->flags |= CLIENT_REDRAWOVERLAY;
return (0);
+ case KEYC_BSPACE:
+ if (~md->flags & MENU_TAB)
+ break;
+ return (1);
+ case '\011': /* Tab */
+ if (~md->flags & MENU_TAB)
+ break;
+ if (md->choice == count - 1)
+ return (1);
+ /* FALLTHROUGH */
case KEYC_DOWN:
case 'j':
if (old == -1)
@@ -245,6 +263,31 @@ menu_key_cb(struct client *c, struct key_event *event)
} while ((name == NULL || *name == '-') && md->choice != old);
c->flags |= CLIENT_REDRAWOVERLAY;
return (0);
+ case 'g':
+ case KEYC_PPAGE:
+ case '\002': /* C-b */
+ if (md->choice > 5)
+ md->choice -= 5;
+ else
+ md->choice = 0;
+ while (md->choice != count && (name == NULL || *name == '-'))
+ md->choice++;
+ if (md->choice == count)
+ md->choice = -1;
+ c->flags |= CLIENT_REDRAWOVERLAY;
+ break;
+ case 'G':
+ case KEYC_NPAGE:
+ if (md->choice > count - 6)
+ md->choice = count - 1;
+ else
+ md->choice += 5;
+ while (md->choice != -1 && (name == NULL || *name == '-'))
+ md->choice--;
+ c->flags |= CLIENT_REDRAWOVERLAY;
+ break;
+ case '\006': /* C-f */
+ break;
case '\r':
goto chosen;
case '\033': /* Escape */
@@ -267,26 +310,19 @@ chosen:
return (1);
}
- pr = cmd_parse_from_string(item->command, NULL);
- switch (pr->status) {
- case CMD_PARSE_EMPTY:
- new_item = NULL;
- break;
- case CMD_PARSE_ERROR:
- new_item = cmdq_get_error(pr->error);
- free(pr->error);
- cmdq_append(c, new_item);
- break;
- case CMD_PARSE_SUCCESS:
- if (md->item != NULL)
- m = &md->item->shared->mouse;
- else
- m = NULL;
- new_item = cmdq_get_command(pr->cmdlist, &md->fs, m, 0);
- cmd_list_free(pr->cmdlist);
- cmdq_append(c, new_item);
- break;
+ if (md->item != NULL)
+ event = cmdq_get_event(md->item);
+ else
+ event = NULL;
+ state = cmdq_new_state(&md->fs, event, 0);
+
+ status = cmd_parse_and_append(item->command, NULL, c, state, &error);
+ if (status == CMD_PARSE_ERROR) {
+ cmdq_append(c, cmdq_get_error(error));
+ free(error);
}
+ cmdq_free_state(state);
+
return (1);
}
@@ -296,9 +332,15 @@ menu_display(struct menu *menu, int flags, struct cmdq_item *item, u_int px,
void *data)
{
struct menu_data *md;
+ u_int i;
+ const char *name;
if (c->tty.sx < menu->width + 4 || c->tty.sy < menu->count + 2)
return (-1);
+ if (px + menu->width + 4 > c->tty.sx)
+ px = c->tty.sx - menu->width - 4;
+ if (py + menu->count + 2 > c->tty.sy)
+ py = c->tty.sy - menu->count - 2;
md = xcalloc(1, sizeof *md);
md->item = item;
@@ -307,17 +349,30 @@ menu_display(struct menu *menu, int flags, struct cmdq_item *item, u_int px,
if (fs != NULL)
cmd_find_copy_state(&md->fs, fs);
screen_init(&md->s, menu->width + 4, menu->count + 2, 0);
+ if (~md->flags & MENU_NOMOUSE)
+ md->s.mode |= MODE_MOUSE_ALL;
md->px = px;
md->py = py;
md->menu = menu;
- md->choice = -1;
+ if (md->flags & MENU_NOMOUSE) {
+ for (i = 0; i < menu->count; i++) {
+ name = menu->items[i].name;
+ if (name != NULL && *name != '-')
+ break;
+ }
+ if (i != menu->count)
+ md->choice = i;
+ else
+ md->choice = -1;
+ } else
+ md->choice = -1;
md->cb = cb;
md->data = data;
- server_client_set_overlay(c, 0, menu_draw_cb, menu_key_cb, menu_free_cb,
- md);
+ server_client_set_overlay(c, 0, NULL, menu_mode_cb, menu_draw_cb,
+ menu_key_cb, menu_free_cb, md);
return (0);
}
diff --git a/mode-tree.c b/mode-tree.c
index b9fa5f65..8d210d72 100644
--- a/mode-tree.c
+++ b/mode-tree.c
@@ -256,8 +256,8 @@ mode_tree_expand_current(struct mode_tree_data *mtd)
}
}
-void
-mode_tree_set_current(struct mode_tree_data *mtd, uint64_t tag)
+static int
+mode_tree_get_tag(struct mode_tree_data *mtd, uint64_t tag, u_int *found)
{
u_int i;
@@ -266,15 +266,41 @@ mode_tree_set_current(struct mode_tree_data *mtd, uint64_t tag)
break;
}
if (i != mtd->line_size) {
- mtd->current = i;
+ *found = i;
+ return (1);
+ }
+ return (0);
+}
+
+void
+mode_tree_expand(struct mode_tree_data *mtd, uint64_t tag)
+{
+ u_int found;
+
+ if (!mode_tree_get_tag(mtd, tag, &found))
+ return;
+ if (!mtd->line_list[found].item->expanded) {
+ mtd->line_list[found].item->expanded = 1;
+ mode_tree_build(mtd);
+ }
+}
+
+int
+mode_tree_set_current(struct mode_tree_data *mtd, uint64_t tag)
+{
+ u_int found;
+
+ if (mode_tree_get_tag(mtd, tag, &found)) {
+ mtd->current = found;
if (mtd->current > mtd->height - 1)
mtd->offset = mtd->current - mtd->height + 1;
else
mtd->offset = 0;
- } else {
- mtd->current = 0;
- mtd->offset = 0;
+ return (1);
}
+ mtd->current = 0;
+ mtd->offset = 0;
+ return (0);
}
u_int
@@ -531,12 +557,12 @@ mode_tree_draw(struct mode_tree_data *mtd)
memcpy(&gc0, &grid_default_cell, sizeof gc0);
memcpy(&gc, &grid_default_cell, sizeof gc);
- style_apply(&gc, oo, "mode-style");
+ style_apply(&gc, oo, "mode-style", NULL);
w = mtd->width;
h = mtd->height;
- screen_write_start(&ctx, NULL, s);
+ screen_write_start(&ctx, s);
screen_write_clearscreen(&ctx, 8);
if (mtd->line_size > 10)
@@ -847,6 +873,10 @@ mode_tree_display_menu(struct mode_tree_data *mtd, struct client *c, u_int x,
mtm->itemdata = mti->itemdata;
mtd->references++;
+ if (x >= (menu->width + 4) / 2)
+ x -= (menu->width + 4) / 2;
+ else
+ x = 0;
if (menu_display(menu, 0, NULL, x, y, c, NULL, mode_tree_menu_callback,
mtm) != 0)
menu_free(menu);
@@ -1059,33 +1089,22 @@ void
mode_tree_run_command(struct client *c, struct cmd_find_state *fs,
const char *template, const char *name)
{
- struct cmdq_item *new_item;
- char *command;
- struct cmd_parse_result *pr;
+ struct cmdq_state *state;
+ char *command, *error;
+ enum cmd_parse_status status;
command = cmd_template_replace(template, name, 1);
- if (command == NULL || *command == '\0') {
- free(command);
- return;
- }
-
- pr = cmd_parse_from_string(command, NULL);
- switch (pr->status) {
- case CMD_PARSE_EMPTY:
- break;
- case CMD_PARSE_ERROR:
- if (c != NULL) {
- *pr->error = toupper((u_char)*pr->error);
- status_message_set(c, "%s", pr->error);
+ if (command != NULL && *command != '\0') {
+ state = cmdq_new_state(fs, NULL, 0);
+ status = cmd_parse_and_append(command, NULL, c, state, &error);
+ if (status == CMD_PARSE_ERROR) {
+ if (c != NULL) {
+ *error = toupper((u_char)*error);
+ status_message_set(c, "%s", error);
+ }
+ free(error);
}
- free(pr->error);
- break;
- case CMD_PARSE_SUCCESS:
- new_item = cmdq_get_command(pr->cmdlist, fs, NULL, 0);
- cmdq_append(c, new_item);
- cmd_list_free(pr->cmdlist);
- break;
+ cmdq_free_state(state);
}
-
free(command);
}
diff --git a/names.c b/names.c
index 661ba06e..07c689d1 100644
--- a/names.c
+++ b/names.c
@@ -96,6 +96,7 @@ check_window_name(struct window *w)
if (strcmp(name, w->name) != 0) {
log_debug("@%u new name %s (was %s)", w->id, name, w->name);
window_set_name(w, name);
+ server_redraw_window_borders(w);
server_status_window(w);
} else
log_debug("@%u name not changed (still %s)", w->id, w->name);
diff --git a/notify.c b/notify.c
index 200e23d6..e5ce761b 100644
--- a/notify.c
+++ b/notify.c
@@ -35,19 +35,19 @@ struct notify_entry {
};
static void
-notify_hook_formats(struct cmdq_item *item, struct session *s, struct window *w,
- int pane)
+notify_hook_formats(struct cmdq_state *state, struct session *s,
+ struct window *w, int pane)
{
if (s != NULL) {
- cmdq_format(item, "hook_session", "$%u", s->id);
- cmdq_format(item, "hook_session_name", "%s", s->name);
+ cmdq_add_format(state, "hook_session", "$%u", s->id);
+ cmdq_add_format(state, "hook_session_name", "%s", s->name);
}
if (w != NULL) {
- cmdq_format(item, "hook_window", "@%u", w->id);
- cmdq_format(item, "hook_window_name", "%s", w->name);
+ cmdq_add_format(state, "hook_window", "@%u", w->id);
+ cmdq_add_format(state, "hook_window_name", "%s", w->name);
}
if (pane != -1)
- cmdq_format(item, "hook_pane", "%%%d", pane);
+ cmdq_add_format(state, "hook_pane", "%%%d", pane);
}
static void
@@ -56,6 +56,7 @@ notify_insert_hook(struct cmdq_item *item, struct notify_entry *ne)
struct cmd_find_state fs;
struct options *oo;
struct cmdq_item *new_item;
+ struct cmdq_state *new_state;
struct session *s = ne->session;
struct window *w = ne->window;
struct options_entry *o;
@@ -75,24 +76,32 @@ notify_insert_hook(struct cmdq_item *item, struct notify_entry *ne)
else
oo = fs.s->options;
o = options_get(oo, ne->name);
+ if (o == NULL && fs.wp != NULL) {
+ oo = fs.wp->options;
+ o = options_get(oo, ne->name);
+ }
+ if (o == NULL && fs.wl != NULL) {
+ oo = fs.wl->window->options;
+ o = options_get(oo, ne->name);
+ }
if (o == NULL)
return;
+ new_state = cmdq_new_state(&fs, NULL, CMDQ_STATE_NOHOOKS);
+ cmdq_add_format(new_state, "hook", "%s", ne->name);
+ notify_hook_formats(new_state, s, w, ne->pane);
+
a = options_array_first(o);
while (a != NULL) {
cmdlist = options_array_item_value(a)->cmdlist;
- if (cmdlist == NULL) {
- a = options_array_next(a);
- continue;
+ if (cmdlist != NULL) {
+ new_item = cmdq_get_command(cmdlist, new_state);
+ item = cmdq_insert_after(item, new_item);
}
-
- new_item = cmdq_get_command(cmdlist, &fs, NULL, CMDQ_NOHOOKS);
- cmdq_format(new_item, "hook", "%s", ne->name);
- notify_hook_formats(new_item, s, w, ne->pane);
- item = cmdq_insert_after(item, new_item);
-
a = options_array_next(a);
}
+
+ cmdq_free_state(new_state);
}
static enum cmd_retval
@@ -148,7 +157,11 @@ notify_add(const char *name, struct cmd_find_state *fs, struct client *c,
struct session *s, struct window *w, struct window_pane *wp)
{
struct notify_entry *ne;
- struct cmdq_item *new_item;
+ struct cmdq_item *item;
+
+ item = cmdq_running(NULL);
+ if (item != NULL && (cmdq_get_flags(item) & CMDQ_STATE_NOHOOKS))
+ return;
ne = xcalloc(1, sizeof *ne);
ne->name = xstrdup(name);
@@ -173,24 +186,24 @@ notify_add(const char *name, struct cmd_find_state *fs, struct client *c,
if (ne->fs.s != NULL) /* cmd_find_valid_state needs session */
session_add_ref(ne->fs.s, __func__);
- new_item = cmdq_get_callback(notify_callback, ne);
- cmdq_append(NULL, new_item);
+ cmdq_append(NULL, cmdq_get_callback(notify_callback, ne));
}
void
notify_hook(struct cmdq_item *item, const char *name)
{
- struct notify_entry ne;
+ struct cmd_find_state *target = cmdq_get_target(item);
+ struct notify_entry ne;
memset(&ne, 0, sizeof ne);
ne.name = name;
- cmd_find_copy_state(&ne.fs, &item->target);
+ cmd_find_copy_state(&ne.fs, target);
- ne.client = item->client;
- ne.session = item->target.s;
- ne.window = item->target.w;
- ne.pane = item->target.wp->id;
+ ne.client = cmdq_get_client(item);
+ ne.session = target->s;
+ ne.window = target->w;
+ ne.pane = target->wp->id;
notify_insert_hook(item, &ne);
}
diff --git a/options-table.c b/options-table.c
index be0d220d..b4aa47e2 100644
--- a/options-table.c
+++ b/options-table.c
@@ -139,7 +139,7 @@ static const char *options_table_status_format_default[] = {
OPTIONS_TABLE_STATUS_FORMAT1, OPTIONS_TABLE_STATUS_FORMAT2, NULL
};
-/* Helper for hook options. */
+/* Helpers for hook options. */
#define OPTIONS_TABLE_HOOK(hook_name, default_value) \
{ .name = hook_name, \
.type = OPTIONS_TABLE_COMMAND, \
@@ -149,6 +149,24 @@ static const char *options_table_status_format_default[] = {
.separator = "" \
}
+#define OPTIONS_TABLE_PANE_HOOK(hook_name, default_value) \
+ { .name = hook_name, \
+ .type = OPTIONS_TABLE_COMMAND, \
+ .scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE, \
+ .flags = OPTIONS_TABLE_IS_ARRAY|OPTIONS_TABLE_IS_HOOK, \
+ .default_str = default_value, \
+ .separator = "" \
+ }
+
+#define OPTIONS_TABLE_WINDOW_HOOK(hook_name, default_value) \
+ { .name = hook_name, \
+ .type = OPTIONS_TABLE_COMMAND, \
+ .scope = OPTIONS_TABLE_WINDOW, \
+ .flags = OPTIONS_TABLE_IS_ARRAY|OPTIONS_TABLE_IS_HOOK, \
+ .default_str = default_value, \
+ .separator = "" \
+ }
+
/* Top-level options. */
const struct options_table_entry options_table[] = {
/* Server options. */
@@ -179,12 +197,24 @@ const struct options_table_entry options_table[] = {
.separator = ","
},
+ { .name = "copy-command",
+ .type = OPTIONS_TABLE_STRING,
+ .scope = OPTIONS_TABLE_SERVER,
+ .default_str = ""
+ },
+
{ .name = "default-terminal",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SERVER,
.default_str = "screen"
},
+ { .name = "editor",
+ .type = OPTIONS_TABLE_STRING,
+ .scope = OPTIONS_TABLE_SERVER,
+ .default_str = _PATH_VI
+ },
+
{ .name = "escape-time",
.type = OPTIONS_TABLE_NUMBER,
.scope = OPTIONS_TABLE_SERVER,
@@ -236,9 +266,16 @@ const struct options_table_entry options_table[] = {
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SERVER,
.flags = OPTIONS_TABLE_IS_ARRAY,
- .default_str = "xterm*:XT:Ms=\\E]52;%p1%s;%p2%s\\007"
- ":Cs=\\E]12;%p1%s\\007:Cr=\\E]112\\007"
- ":Ss=\\E[%p1%d q:Se=\\E[2 q,screen*:XT",
+ .default_str = "",
+ .separator = ","
+ },
+
+ { .name = "terminal-features",
+ .type = OPTIONS_TABLE_STRING,
+ .scope = OPTIONS_TABLE_SERVER,
+ .flags = OPTIONS_TABLE_IS_ARRAY,
+ .default_str = "xterm*:clipboard:ccolour:cstyle:title,"
+ "screen*:title",
.separator = ","
},
@@ -369,15 +406,19 @@ const struct options_table_entry options_table[] = {
},
{ .name = "message-command-style",
- .type = OPTIONS_TABLE_STYLE,
+ .type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SESSION,
- .default_str = "bg=black,fg=yellow"
+ .default_str = "bg=black,fg=yellow",
+ .flags = OPTIONS_TABLE_IS_STYLE,
+ .separator = ","
},
{ .name = "message-style",
- .type = OPTIONS_TABLE_STYLE,
+ .type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SESSION,
- .default_str = "bg=yellow,fg=black"
+ .default_str = "bg=yellow,fg=black",
+ .flags = OPTIONS_TABLE_IS_STYLE,
+ .separator = ","
},
{ .name = "mouse",
@@ -441,13 +482,13 @@ const struct options_table_entry options_table[] = {
{ .name = "status-bg",
.type = OPTIONS_TABLE_COLOUR,
.scope = OPTIONS_TABLE_SESSION,
- .default_num = 2,
+ .default_num = 8,
},
{ .name = "status-fg",
.type = OPTIONS_TABLE_COLOUR,
.scope = OPTIONS_TABLE_SESSION,
- .default_num = 0,
+ .default_num = 8,
},
{ .name = "status-format",
@@ -494,9 +535,11 @@ const struct options_table_entry options_table[] = {
},
{ .name = "status-left-style",
- .type = OPTIONS_TABLE_STYLE,
+ .type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SESSION,
- .default_str = "default"
+ .default_str = "default",
+ .flags = OPTIONS_TABLE_IS_STYLE,
+ .separator = ","
},
{ .name = "status-position",
@@ -523,15 +566,19 @@ const struct options_table_entry options_table[] = {
},
{ .name = "status-right-style",
- .type = OPTIONS_TABLE_STYLE,
+ .type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SESSION,
- .default_str = "default"
+ .default_str = "default",
+ .flags = OPTIONS_TABLE_IS_STYLE,
+ .separator = ","
},
{ .name = "status-style",
- .type = OPTIONS_TABLE_STYLE,
+ .type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SESSION,
- .default_str = "bg=green,fg=black"
+ .default_str = "bg=green,fg=black",
+ .flags = OPTIONS_TABLE_IS_STYLE,
+ .separator = ","
},
{ .name = "update-environment",
@@ -614,20 +661,32 @@ const struct options_table_entry options_table[] = {
.default_num = 1
},
+ { .name = "copy-mode-match-style",
+ .type = OPTIONS_TABLE_STRING,
+ .scope = OPTIONS_TABLE_WINDOW,
+ .default_str = "bg=cyan,fg=black",
+ .flags = OPTIONS_TABLE_IS_STYLE,
+ .separator = ","
+ },
+
+ { .name = "copy-mode-current-match-style",
+ .type = OPTIONS_TABLE_STRING,
+ .scope = OPTIONS_TABLE_WINDOW,
+ .default_str = "bg=magenta,fg=black",
+ .flags = OPTIONS_TABLE_IS_STYLE,
+ .separator = ","
+ },
+
{ .name = "main-pane-height",
- .type = OPTIONS_TABLE_NUMBER,
+ .type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW,
- .minimum = 1,
- .maximum = INT_MAX,
- .default_num = 24
+ .default_str = "24"
},
{ .name = "main-pane-width",
- .type = OPTIONS_TABLE_NUMBER,
+ .type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW,
- .minimum = 1,
- .maximum = INT_MAX,
- .default_num = 80
+ .default_str = "80"
},
{ .name = "mode-keys",
@@ -638,9 +697,11 @@ const struct options_table_entry options_table[] = {
},
{ .name = "mode-style",
- .type = OPTIONS_TABLE_STYLE,
+ .type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW,
- .default_str = "bg=yellow,fg=black"
+ .default_str = "bg=yellow,fg=black",
+ .flags = OPTIONS_TABLE_IS_STYLE,
+ .separator = ","
},
{ .name = "monitor-activity",
@@ -664,25 +725,23 @@ const struct options_table_entry options_table[] = {
},
{ .name = "other-pane-height",
- .type = OPTIONS_TABLE_NUMBER,
+ .type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW,
- .minimum = 0,
- .maximum = INT_MAX,
- .default_num = 0
+ .default_str = "0"
},
{ .name = "other-pane-width",
- .type = OPTIONS_TABLE_NUMBER,
+ .type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW,
- .minimum = 0,
- .maximum = INT_MAX,
- .default_num = 0
+ .default_str = "0"
},
{ .name = "pane-active-border-style",
- .type = OPTIONS_TABLE_STYLE,
+ .type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW,
- .default_str = "fg=green"
+ .default_str = "#{?pane_in_mode,fg=yellow,#{?synchronize-panes,fg=red,fg=green}}",
+ .flags = OPTIONS_TABLE_IS_STYLE,
+ .separator = ","
},
{ .name = "pane-base-index",
@@ -708,9 +767,11 @@ const struct options_table_entry options_table[] = {
},
{ .name = "pane-border-style",
- .type = OPTIONS_TABLE_STYLE,
+ .type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW,
- .default_str = "default"
+ .default_str = "default",
+ .flags = OPTIONS_TABLE_IS_STYLE,
+ .separator = ","
},
{ .name = "remain-on-exit",
@@ -726,9 +787,11 @@ const struct options_table_entry options_table[] = {
},
{ .name = "window-active-style",
- .type = OPTIONS_TABLE_STYLE,
+ .type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE,
- .default_str = "default"
+ .default_str = "default",
+ .flags = OPTIONS_TABLE_IS_STYLE,
+ .separator = ","
},
{ .name = "window-size",
@@ -739,21 +802,27 @@ const struct options_table_entry options_table[] = {
},
{ .name = "window-style",
- .type = OPTIONS_TABLE_STYLE,
+ .type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE,
- .default_str = "default"
+ .default_str = "default",
+ .flags = OPTIONS_TABLE_IS_STYLE,
+ .separator = ","
},
{ .name = "window-status-activity-style",
- .type = OPTIONS_TABLE_STYLE,
+ .type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW,
- .default_str = "reverse"
+ .default_str = "reverse",
+ .flags = OPTIONS_TABLE_IS_STYLE,
+ .separator = ","
},
{ .name = "window-status-bell-style",
- .type = OPTIONS_TABLE_STYLE,
+ .type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW,
- .default_str = "reverse"
+ .default_str = "reverse",
+ .flags = OPTIONS_TABLE_IS_STYLE,
+ .separator = ","
},
{ .name = "window-status-current-format",
@@ -763,9 +832,11 @@ const struct options_table_entry options_table[] = {
},
{ .name = "window-status-current-style",
- .type = OPTIONS_TABLE_STYLE,
+ .type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW,
- .default_str = "default"
+ .default_str = "default",
+ .flags = OPTIONS_TABLE_IS_STYLE,
+ .separator = ","
},
{ .name = "window-status-format",
@@ -775,9 +846,11 @@ const struct options_table_entry options_table[] = {
},
{ .name = "window-status-last-style",
- .type = OPTIONS_TABLE_STYLE,
+ .type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW,
- .default_str = "default"
+ .default_str = "default",
+ .flags = OPTIONS_TABLE_IS_STYLE,
+ .separator = ","
},
{ .name = "window-status-separator",
@@ -787,9 +860,11 @@ const struct options_table_entry options_table[] = {
},
{ .name = "window-status-style",
- .type = OPTIONS_TABLE_STYLE,
+ .type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW,
- .default_str = "default"
+ .default_str = "default",
+ .flags = OPTIONS_TABLE_IS_STYLE,
+ .separator = ","
},
{ .name = "wrap-search",
@@ -850,21 +925,21 @@ const struct options_table_entry options_table[] = {
OPTIONS_TABLE_HOOK("client-detached", ""),
OPTIONS_TABLE_HOOK("client-resized", ""),
OPTIONS_TABLE_HOOK("client-session-changed", ""),
- OPTIONS_TABLE_HOOK("pane-died", ""),
- OPTIONS_TABLE_HOOK("pane-exited", ""),
- OPTIONS_TABLE_HOOK("pane-focus-in", ""),
- OPTIONS_TABLE_HOOK("pane-focus-out", ""),
- OPTIONS_TABLE_HOOK("pane-mode-changed", ""),
- OPTIONS_TABLE_HOOK("pane-set-clipboard", ""),
+ OPTIONS_TABLE_PANE_HOOK("pane-died", ""),
+ OPTIONS_TABLE_PANE_HOOK("pane-exited", ""),
+ OPTIONS_TABLE_PANE_HOOK("pane-focus-in", ""),
+ OPTIONS_TABLE_PANE_HOOK("pane-focus-out", ""),
+ OPTIONS_TABLE_PANE_HOOK("pane-mode-changed", ""),
+ OPTIONS_TABLE_PANE_HOOK("pane-set-clipboard", ""),
OPTIONS_TABLE_HOOK("session-closed", ""),
OPTIONS_TABLE_HOOK("session-created", ""),
OPTIONS_TABLE_HOOK("session-renamed", ""),
OPTIONS_TABLE_HOOK("session-window-changed", ""),
- OPTIONS_TABLE_HOOK("window-layout-changed", ""),
- OPTIONS_TABLE_HOOK("window-linked", ""),
- OPTIONS_TABLE_HOOK("window-pane-changed", ""),
- OPTIONS_TABLE_HOOK("window-renamed", ""),
- OPTIONS_TABLE_HOOK("window-unlinked", ""),
+ OPTIONS_TABLE_WINDOW_HOOK("window-layout-changed", ""),
+ OPTIONS_TABLE_WINDOW_HOOK("window-linked", ""),
+ OPTIONS_TABLE_WINDOW_HOOK("window-pane-changed", ""),
+ OPTIONS_TABLE_WINDOW_HOOK("window-renamed", ""),
+ OPTIONS_TABLE_WINDOW_HOOK("window-unlinked", ""),
{ .name = NULL }
};
diff --git a/options.c b/options.c
index 7402b724..39a0d08f 100644
--- a/options.c
+++ b/options.c
@@ -53,6 +53,9 @@ struct options_entry {
const struct options_table_entry *tableentry;
union options_value value;
+ int cached;
+ struct style style;
+
RB_ENTRY(options_entry) entry;
};
@@ -73,9 +76,6 @@ static struct options_entry *options_add(struct options *, const char *);
(o)->tableentry->type == OPTIONS_TABLE_COLOUR || \
(o)->tableentry->type == OPTIONS_TABLE_FLAG || \
(o)->tableentry->type == OPTIONS_TABLE_CHOICE))
-#define OPTIONS_IS_STYLE(o) \
- ((o)->tableentry != NULL && \
- (o)->tableentry->type == OPTIONS_TABLE_STYLE)
#define OPTIONS_IS_COMMAND(o) \
((o)->tableentry != NULL && \
(o)->tableentry->type == OPTIONS_TABLE_COMMAND)
@@ -123,8 +123,6 @@ options_value_tostring(struct options_entry *o, union options_value *ov,
if (OPTIONS_IS_COMMAND(o))
return (cmd_list_print(ov->cmdlist, 0));
- if (OPTIONS_IS_STYLE(o))
- return (xstrdup(style_tostring(&ov->style)));
if (OPTIONS_IS_NUMBER(o)) {
switch (o->tableentry->type) {
case OPTIONS_TABLE_NUMBER:
@@ -146,7 +144,6 @@ options_value_tostring(struct options_entry *o, union options_value *ov,
s = xstrdup(o->tableentry->choices[ov->number]);
break;
case OPTIONS_TABLE_STRING:
- case OPTIONS_TABLE_STYLE:
case OPTIONS_TABLE_COMMAND:
fatalx("not a number option type");
}
@@ -258,10 +255,6 @@ options_default(struct options *oo, const struct options_table_entry *oe)
case OPTIONS_TABLE_STRING:
ov->string = xstrdup(oe->default_str);
break;
- case OPTIONS_TABLE_STYLE:
- style_set(&ov->style, &grid_default_cell);
- style_parse(&ov->style, &grid_default_cell, oe->default_str);
- break;
default:
ov->number = oe->default_num;
break;
@@ -653,25 +646,13 @@ options_get_number(struct options *oo, const char *name)
return (o->value.number);
}
-struct style *
-options_get_style(struct options *oo, const char *name)
-{
- struct options_entry *o;
-
- o = options_get(oo, name);
- if (o == NULL)
- fatalx("missing option %s", name);
- if (!OPTIONS_IS_STYLE(o))
- fatalx("option %s is not a style", name);
- return (&o->value.style);
-}
-
struct options_entry *
options_set_string(struct options *oo, const char *name, int append,
const char *fmt, ...)
{
struct options_entry *o;
va_list ap;
+ const char *separator = "";
char *s, *value;
va_start(ap, fmt);
@@ -680,7 +661,12 @@ options_set_string(struct options *oo, const char *name, int append,
o = options_get_only(oo, name);
if (o != NULL && append && OPTIONS_IS_STRING(o)) {
- xasprintf(&value, "%s%s", o->value.string, s);
+ if (*name != '@') {
+ separator = o->tableentry->separator;
+ if (separator == NULL)
+ separator = "";
+ }
+ xasprintf(&value, "%s%s%s", o->value.string, separator, s);
free(s);
} else
value = s;
@@ -696,6 +682,7 @@ options_set_string(struct options *oo, const char *name, int append,
fatalx("option %s is not a string", name);
free(o->value.string);
o->value.string = value;
+ o->cached = 0;
return (o);
}
@@ -720,35 +707,6 @@ options_set_number(struct options *oo, const char *name, long long value)
return (o);
}
-struct options_entry *
-options_set_style(struct options *oo, const char *name, int append,
- const char *value)
-{
- struct options_entry *o;
- struct style sy;
-
- if (*name == '@')
- fatalx("user option %s must be a string", name);
-
- o = options_get_only(oo, name);
- if (o != NULL && append && OPTIONS_IS_STYLE(o))
- style_copy(&sy, &o->value.style);
- else
- style_set(&sy, &grid_default_cell);
- if (style_parse(&sy, &grid_default_cell, value) == -1)
- return (NULL);
- if (o == NULL) {
- o = options_default(oo, options_parent_table_entry(oo, name));
- if (o == NULL)
- return (NULL);
- }
-
- if (!OPTIONS_IS_STYLE(o))
- fatalx("option %s is not a style", name);
- style_copy(&o->value.style, &sy);
- return (o);
-}
-
int
options_scope_from_name(struct args *args, int window,
const char *name, struct cmd_find_state *fs, struct options **oo,
@@ -874,3 +832,37 @@ options_scope_from_flags(struct args *args, int window,
return (OPTIONS_TABLE_SESSION);
}
}
+
+struct style *
+options_string_to_style(struct options *oo, const char *name,
+ struct format_tree *ft)
+{
+ struct options_entry *o;
+ const char *s;
+ char *expanded;
+
+ o = options_get(oo, name);
+ if (o == NULL || !OPTIONS_IS_STRING(o))
+ return (NULL);
+
+ if (o->cached)
+ return (&o->style);
+ s = o->value.string;
+ log_debug("%s: %s is '%s'", __func__, name, s);
+
+ style_set(&o->style, &grid_default_cell);
+ o->cached = (strstr(s, "#{") == NULL);
+
+ if (ft != NULL && !o->cached) {
+ expanded = format_expand(ft, s);
+ if (style_parse(&o->style, &grid_default_cell, expanded) != 0) {
+ free(expanded);
+ return (NULL);
+ }
+ free(expanded);
+ } else {
+ if (style_parse(&o->style, &grid_default_cell, s) != 0)
+ return (NULL);
+ }
+ return (&o->style);
+}
diff --git a/osdep-darwin.c b/osdep-darwin.c
index d4a88028..6b2b1d72 100644
--- a/osdep-darwin.c
+++ b/osdep-darwin.c
@@ -61,7 +61,7 @@ osdep_get_name(int fd, __unused char *tty)
size = sizeof kp;
if (sysctl(mib, 4, &kp, &size, NULL, 0) == -1)
return (NULL);
- if (*kp.kp_proc.p_comm == '\0')
+ if (size != (sizeof kp) || *kp.kp_proc.p_comm == '\0')
return (NULL);
return (strdup(kp.kp_proc.p_comm));
diff --git a/paste.c b/paste.c
index c1036ad9..51ae2b1d 100644
--- a/paste.c
+++ b/paste.c
@@ -296,13 +296,22 @@ paste_set(char *data, size_t size, const char *name, char **cause)
return (0);
}
+/* Set paste data without otherwise changing it. */
+void
+paste_replace(struct paste_buffer *pb, char *data, size_t size)
+{
+ free(pb->data);
+ pb->data = data;
+ pb->size = size;
+}
+
/* Convert start of buffer into a nice string. */
char *
paste_make_sample(struct paste_buffer *pb)
{
char *buf;
size_t len, used;
- const int flags = VIS_OCTAL|VIS_TAB|VIS_NL;
+ const int flags = VIS_OCTAL|VIS_CSTYLE|VIS_TAB|VIS_NL;
const size_t width = 200;
len = pb->size;
diff --git a/popup.c b/popup.c
new file mode 100644
index 00000000..9937d586
--- /dev/null
+++ b/popup.c
@@ -0,0 +1,519 @@
+/* $OpenBSD$ */
+
+/*
+ * Copyright (c) 2020 Nicholas Marriott <nicholas.marriott@gmail.com>
+ *
+ * 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 <sys/types.h>
+#include <sys/wait.h>
+
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "tmux.h"
+
+struct popup_data {
+ struct client *c;
+ struct cmdq_item *item;
+ int flags;
+
+ char **lines;
+ u_int nlines;
+
+ char *cmd;
+ struct cmd_find_state fs;
+ struct screen s;
+
+ struct job *job;
+ struct input_ctx *ictx;
+ int status;
+ popup_close_cb cb;
+ void *arg;
+
+ u_int px;
+ u_int py;
+ u_int sx;
+ u_int sy;
+
+ enum { OFF, MOVE, SIZE } dragging;
+ u_int dx;
+ u_int dy;
+
+ u_int lx;
+ u_int ly;
+ u_int lb;
+};
+
+static void
+popup_redraw_cb(const struct tty_ctx *ttyctx)
+{
+ struct popup_data *pd = ttyctx->arg;
+
+ pd->c->flags |= CLIENT_REDRAWOVERLAY;
+}
+
+static int
+popup_set_client_cb(struct tty_ctx *ttyctx, struct client *c)
+{
+ struct popup_data *pd = ttyctx->arg;
+
+ if (pd->c->flags & CLIENT_REDRAWOVERLAY)
+ return (-1);
+
+ ttyctx->bigger = 0;
+ ttyctx->wox = 0;
+ ttyctx->woy = 0;
+ ttyctx->wsx = c->tty.sx;
+ ttyctx->wsy = c->tty.sy;
+
+ ttyctx->xoff = ttyctx->rxoff = pd->px + 1;
+ ttyctx->yoff = ttyctx->ryoff = pd->py + 1;
+
+ return (1);
+}
+
+static void
+popup_init_ctx_cb(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx)
+{
+ struct popup_data *pd = ctx->arg;
+
+ ttyctx->redraw_cb = popup_redraw_cb;
+ ttyctx->set_client_cb = popup_set_client_cb;
+ ttyctx->arg = pd;
+}
+
+static void
+popup_write_screen(struct client *c, struct popup_data *pd)
+{
+ struct cmdq_item *item = pd->item;
+ struct screen_write_ctx ctx;
+ char *copy, *next, *loop, *tmp;
+ struct format_tree *ft;
+ u_int i, y;
+
+ ft = format_create(c, item, FORMAT_NONE, 0);
+ if (cmd_find_valid_state(&pd->fs))
+ format_defaults(ft, c, pd->fs.s, pd->fs.wl, pd->fs.wp);
+ else
+ format_defaults(ft, c, NULL, NULL, NULL);
+
+ screen_write_start(&ctx, &pd->s);
+ screen_write_clearscreen(&ctx, 8);
+
+ y = 0;
+ for (i = 0; i < pd->nlines; i++) {
+ if (y == pd->sy - 2)
+ break;
+ copy = next = xstrdup(pd->lines[i]);
+ while ((loop = strsep(&next, "\n")) != NULL) {
+ if (y == pd->sy - 2)
+ break;
+ tmp = format_expand(ft, loop);
+ screen_write_cursormove(&ctx, 0, y, 0);
+ format_draw(&ctx, &grid_default_cell, pd->sx - 2, tmp,
+ NULL);
+ free(tmp);
+ y++;
+ }
+ free(copy);
+ }
+
+ format_free(ft);
+ screen_write_cursormove(&ctx, 0, y, 0);
+ screen_write_stop(&ctx);
+}
+
+static struct screen *
+popup_mode_cb(struct client *c, u_int *cx, u_int *cy)
+{
+ struct popup_data *pd = c->overlay_data;
+
+ if (pd->ictx == NULL)
+ return (0);
+ *cx = pd->px + 1 + pd->s.cx;
+ *cy = pd->py + 1 + pd->s.cy;
+ return (&pd->s);
+}
+
+static int
+popup_check_cb(struct client *c, u_int px, u_int py)
+{
+ struct popup_data *pd = c->overlay_data;
+
+ if (px < pd->px || px > pd->px + pd->sx - 1)
+ return (1);
+ if (py < pd->py || py > pd->py + pd->sy - 1)
+ return (1);
+ return (0);
+}
+
+static void
+popup_draw_cb(struct client *c, __unused struct screen_redraw_ctx *ctx0)
+{
+ struct popup_data *pd = c->overlay_data;
+ struct tty *tty = &c->tty;
+ struct screen s;
+ struct screen_write_ctx ctx;
+ u_int i, px = pd->px, py = pd->py;
+
+ screen_init(&s, pd->sx, pd->sy, 0);
+ screen_write_start(&ctx, &s);
+ screen_write_clearscreen(&ctx, 8);
+ screen_write_box(&ctx, pd->sx, pd->sy);
+ screen_write_cursormove(&ctx, 1, 1, 0);
+ screen_write_fast_copy(&ctx, &pd->s, 0, 0, pd->sx - 2, pd->sy - 2);
+ screen_write_stop(&ctx);
+
+ c->overlay_check = NULL;
+ for (i = 0; i < pd->sy; i++){
+ tty_draw_line(tty, &s, 0, i, pd->sx, px, py + i,
+ &grid_default_cell, NULL);
+ }
+ c->overlay_check = popup_check_cb;
+}
+
+static void
+popup_free_cb(struct client *c)
+{
+ struct popup_data *pd = c->overlay_data;
+ struct cmdq_item *item = pd->item;
+ u_int i;
+
+ if (pd->cb != NULL)
+ pd->cb(pd->status, pd->arg);
+
+ if (item != NULL) {
+ if (pd->ictx != NULL &&
+ cmdq_get_client(item) != NULL &&
+ cmdq_get_client(item)->session == NULL)
+ cmdq_get_client(item)->retval = pd->status;
+ cmdq_continue(item);
+ }
+ server_client_unref(pd->c);
+
+ if (pd->job != NULL)
+ job_free(pd->job);
+ if (pd->ictx != NULL)
+ input_free(pd->ictx);
+
+ for (i = 0; i < pd->nlines; i++)
+ free(pd->lines[i]);
+ free(pd->lines);
+
+ screen_free(&pd->s);
+ free(pd->cmd);
+ free(pd);
+}
+
+static void
+popup_handle_drag(struct client *c, struct popup_data *pd,
+ struct mouse_event *m)
+{
+ u_int px, py;
+
+ if (!MOUSE_DRAG(m->b))
+ pd->dragging = OFF;
+ else if (pd->dragging == MOVE) {
+ if (m->x < pd->dx)
+ px = 0;
+ else if (m->x - pd->dx + pd->sx > c->tty.sx)
+ px = c->tty.sx - pd->sx;
+ else
+ px = m->x - pd->dx;
+ if (m->y < pd->dy)
+ py = 0;
+ else if (m->y - pd->dy + pd->sy > c->tty.sy)
+ py = c->tty.sy - pd->sy;
+ else
+ py = m->y - pd->dy;
+ pd->px = px;
+ pd->py = py;
+ pd->dx = m->x - pd->px;
+ pd->dy = m->y - pd->py;
+ server_redraw_client(c);
+ } else if (pd->dragging == SIZE) {
+ if (m->x < pd->px + 3)
+ return;
+ if (m->y < pd->py + 3)
+ return;
+ pd->sx = m->x - pd->px;
+ pd->sy = m->y - pd->py;
+
+ screen_resize(&pd->s, pd->sx, pd->sy, 0);
+ if (pd->ictx == NULL)
+ popup_write_screen(c, pd);
+ else if (pd->job != NULL)
+ job_resize(pd->job, pd->sx - 2, pd->sy - 2);
+ server_redraw_client(c);
+ }
+}
+
+static int
+popup_key_cb(struct client *c, struct key_event *event)
+{
+ struct popup_data *pd = c->overlay_data;
+ struct mouse_event *m = &event->m;
+ struct cmd_find_state *fs = &pd->fs;
+ struct format_tree *ft;
+ const char *cmd, *buf;
+ size_t len;
+ struct cmdq_state *state;
+ enum cmd_parse_status status;
+ char *error;
+
+ if (KEYC_IS_MOUSE(event->key)) {
+ if (pd->dragging != OFF) {
+ popup_handle_drag(c, pd, m);
+ goto out;
+ }
+ if (m->x < pd->px ||
+ m->x > pd->px + pd->sx - 1 ||
+ m->y < pd->py ||
+ m->y > pd->py + pd->sy - 1) {
+ if (MOUSE_BUTTONS (m->b) == 1)
+ return (1);
+ return (0);
+ }
+ if ((m->b & MOUSE_MASK_META) ||
+ m->x == pd->px ||
+ m->x == pd->px + pd->sx - 1 ||
+ m->y == pd->py ||
+ m->y == pd->py + pd->sy - 1) {
+ if (!MOUSE_DRAG(m->b))
+ goto out;
+ if (MOUSE_BUTTONS(m->lb) == 0)
+ pd->dragging = MOVE;
+ else if (MOUSE_BUTTONS(m->lb) == 2)
+ pd->dragging = SIZE;
+ pd->dx = m->lx - pd->px;
+ pd->dy = m->ly - pd->py;
+ goto out;
+ }
+ }
+
+ if (pd->ictx != NULL && (pd->flags & POPUP_WRITEKEYS)) {
+ if (((pd->flags & (POPUP_CLOSEEXIT|POPUP_CLOSEEXITZERO)) == 0 ||
+ pd->job == NULL) &&
+ (event->key == '\033' || event->key == '\003'))
+ return (1);
+ if (pd->job == NULL)
+ return (0);
+ if (KEYC_IS_MOUSE(event->key)) {
+ /* Must be inside, checked already. */
+ if (!input_key_get_mouse(&pd->s, m, m->x - pd->px,
+ m->y - pd->py, &buf, &len))
+ return (0);
+ bufferevent_write(job_get_event(pd->job), buf, len);
+ return (0);
+ }
+ input_key(NULL, &pd->s, job_get_event(pd->job), event->key);
+ return (0);
+ }
+
+ if (pd->cmd == NULL)
+ return (1);
+
+ ft = format_create(NULL, pd->item, FORMAT_NONE, 0);
+ if (cmd_find_valid_state(fs))
+ format_defaults(ft, c, fs->s, fs->wl, fs->wp);
+ else
+ format_defaults(ft, c, NULL, NULL, NULL);
+ format_add(ft, "popup_key", "%s", key_string_lookup_key(event->key));
+ if (KEYC_IS_MOUSE(event->key)) {
+ format_add(ft, "popup_mouse", "1");
+ format_add(ft, "popup_mouse_x", "%u", m->x - pd->px);
+ format_add(ft, "popup_mouse_y", "%u", m->y - pd->py);
+ }
+ cmd = format_expand(ft, pd->cmd);
+ format_free(ft);
+
+ if (pd->item != NULL)
+ event = cmdq_get_event(pd->item);
+ else
+ event = NULL;
+ state = cmdq_new_state(&pd->fs, event, 0);
+
+ status = cmd_parse_and_append(cmd, NULL, c, state, &error);
+ if (status == CMD_PARSE_ERROR) {
+ cmdq_append(c, cmdq_get_error(error));
+ free(error);
+ }
+ cmdq_free_state(state);
+
+ return (1);
+
+out:
+ pd->lx = m->x;
+ pd->ly = m->y;
+ pd->lb = m->b;
+ return (0);
+}
+
+static void
+popup_job_update_cb(struct job *job)
+{
+ struct popup_data *pd = job_get_data(job);
+ struct evbuffer *evb = job_get_event(job)->input;
+ struct client *c = pd->c;
+ struct screen *s = &pd->s;
+ void *data = EVBUFFER_DATA(evb);
+ size_t size = EVBUFFER_LENGTH(evb);
+
+ if (size == 0)
+ return;
+
+ c->overlay_check = NULL;
+ c->tty.flags &= ~TTY_FREEZE;
+
+ input_parse_screen(pd->ictx, s, popup_init_ctx_cb, pd, data, size);
+
+ c->tty.flags |= TTY_FREEZE;
+ c->overlay_check = popup_check_cb;
+
+ evbuffer_drain(evb, size);
+}
+
+static void
+popup_job_complete_cb(struct job *job)
+{
+ struct popup_data *pd = job_get_data(job);
+ int status;
+
+ status = job_get_status(pd->job);
+ if (WIFEXITED(status))
+ pd->status = WEXITSTATUS(status);
+ else if (WIFSIGNALED(status))
+ pd->status = WTERMSIG(status);
+ else
+ pd->status = 0;
+ pd->job = NULL;
+
+ if ((pd->flags & POPUP_CLOSEEXIT) ||
+ ((pd->flags & POPUP_CLOSEEXITZERO) && pd->status == 0))
+ server_client_clear_overlay(pd->c);
+}
+
+u_int
+popup_height(u_int nlines, const char **lines)
+{
+ char *copy, *next, *loop;
+ u_int i, height = 0;
+
+ for (i = 0; i < nlines; i++) {
+ copy = next = xstrdup(lines[i]);
+ while ((loop = strsep(&next, "\n")) != NULL)
+ height++;
+ free(copy);
+ }
+
+ return (height);
+}
+
+u_int
+popup_width(struct cmdq_item *item, u_int nlines, const char **lines,
+ struct client *c, struct cmd_find_state *fs)
+{
+ char *copy, *next, *loop, *tmp;
+ struct format_tree *ft;
+ u_int i, width = 0, tmpwidth;
+
+ ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0);
+ if (fs != NULL && cmd_find_valid_state(fs))
+ format_defaults(ft, c, fs->s, fs->wl, fs->wp);
+ else
+ format_defaults(ft, c, NULL, NULL, NULL);
+
+ for (i = 0; i < nlines; i++) {
+ copy = next = xstrdup(lines[i]);
+ while ((loop = strsep(&next, "\n")) != NULL) {
+ tmp = format_expand(ft, loop);
+ tmpwidth = format_width(tmp);
+ if (tmpwidth > width)
+ width = tmpwidth;
+ free(tmp);
+ }
+ free(copy);
+ }
+
+ format_free(ft);
+ return (width);
+}
+
+int
+popup_display(int flags, struct cmdq_item *item, u_int px, u_int py, u_int sx,
+ u_int sy, u_int nlines, const char **lines, const char *shellcmd,
+ const char *cmd, const char *cwd, struct client *c,
+ struct cmd_find_state *fs, popup_close_cb cb, void *arg)
+{
+ struct popup_data *pd;
+ u_int i;
+ struct session *s;
+ int jobflags;
+
+ if (sx < 3 || sy < 3)
+ return (-1);
+ if (c->tty.sx < sx || c->tty.sy < sy)
+ return (-1);
+
+ pd = xcalloc(1, sizeof *pd);
+ pd->item = item;
+ pd->flags = flags;
+
+ pd->c = c;
+ pd->c->references++;
+
+ pd->cb = cb;
+ pd->arg = arg;
+ pd->status = 128 + SIGHUP;
+
+ if (fs != NULL)
+ cmd_find_copy_state(&pd->fs, fs);
+ screen_init(&pd->s, sx - 2, sy - 2, 0);
+
+ if (cmd != NULL)
+ pd->cmd = xstrdup(cmd);
+
+ pd->px = px;
+ pd->py = py;
+ pd->sx = sx;
+ pd->sy = sy;
+
+ pd->nlines = nlines;
+ if (pd->nlines != 0)
+ pd->lines = xreallocarray(NULL, pd->nlines, sizeof *pd->lines);
+
+ for (i = 0; i < pd->nlines; i++)
+ pd->lines[i] = xstrdup(lines[i]);
+ popup_write_screen(c, pd);
+
+ if (shellcmd != NULL) {
+ if (fs != NULL)
+ s = fs->s;
+ else
+ s = NULL;
+ jobflags = JOB_NOWAIT|JOB_PTY;
+ if (flags & POPUP_WRITEKEYS)
+ jobflags |= JOB_KEEPWRITE;
+ pd->job = job_run(shellcmd, s, cwd, popup_job_update_cb,
+ popup_job_complete_cb, NULL, pd, jobflags, pd->sx - 2,
+ pd->sy - 2);
+ pd->ictx = input_init(NULL, job_get_event(pd->job));
+ }
+
+ server_client_set_overlay(c, 0, popup_check_cb, popup_mode_cb,
+ popup_draw_cb, popup_key_cb, popup_free_cb, pd);
+ return (0);
+}
diff --git a/regress/capture-pane-sgr0.sh b/regress/capture-pane-sgr0.sh
index 79d96a38..0dd9cd82 100644
--- a/regress/capture-pane-sgr0.sh
+++ b/regress/capture-pane-sgr0.sh
@@ -13,11 +13,18 @@ $TMUX kill-server 2>/dev/null
TMP=$(mktemp)
trap "rm -f $TMP" 0 1 15
-$TMUX -f/dev/null new -d \
- "printf '\033[31;42;1mabc\033[0;31mdef'; $TMUX capturep -peS0 -E0 >$TMP"
+$TMUX -f/dev/null new -d "
+ printf '\033[31;42;1mabc\033[0;31mdef\n'
+ printf '\033[m\033[100m bright bg \033[m'
+ $TMUX capturep -peS0 -E1 >>$TMP"
+
+
sleep 1
-printf '\033[1m\033[31m\033[42mabc\033[0m\033[31m\033[49mdef\033[39m\n'| \
- cmp - $TMP || exit 1
+
+(
+ printf '\033[1m\033[31m\033[42mabc\033[0m\033[31m\033[49mdef\033[39m\n'
+ printf '\033[100m bright bg \033[49m\n'
+) | cmp - $TMP || exit 1
$TMUX has 2>/dev/null && exit 1
diff --git a/regsub.c b/regsub.c
index 22e236dc..4039b9be 100644
--- a/regsub.c
+++ b/regsub.c
@@ -24,8 +24,7 @@
#include "tmux.h"
static void
-regsub_copy(char **buf, size_t *len, const char *text, size_t start,
- size_t end)
+regsub_copy(char **buf, size_t *len, const char *text, size_t start, size_t end)
{
size_t add = end - start;
diff --git a/screen-redraw.c b/screen-redraw.c
index e7f4f077..dd5886b2 100644
--- a/screen-redraw.c
+++ b/screen-redraw.c
@@ -45,29 +45,88 @@ static void screen_redraw_draw_pane(struct screen_redraw_ctx *,
#define CELL_BORDERS " xqlkmjwvtun~"
+const struct grid_cell screen_redraw_border_cell = {
+ { { ' ' }, 0, 1, 1 }, GRID_ATTR_CHARSET, 0, 8, 8, 0
+};
+
+/* Return if window has only two panes. */
+static int
+screen_redraw_two_panes(struct window *w)
+{
+ struct window_pane *wp;
+
+ wp = TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry);
+ if (wp == NULL)
+ return (0); /* one pane */
+ if (TAILQ_NEXT(wp, entry) != NULL)
+ return (0); /* more than two panes */
+ return (1);
+}
+
/* Check if cell is on the border of a particular pane. */
static int
-screen_redraw_cell_border1(struct window_pane *wp, u_int px, u_int py)
+screen_redraw_cell_border1(struct window_pane *wp, u_int px, u_int py,
+ int pane_status)
{
+ u_int ex = wp->xoff + wp->sx, ey = wp->yoff + wp->sy;
+
/* Inside pane. */
- if (px >= wp->xoff && px < wp->xoff + wp->sx &&
- py >= wp->yoff && py < wp->yoff + wp->sy)
+ if (px >= wp->xoff && px < ex && py >= wp->yoff && py < ey)
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 (2);
+ if (pane_status == PANE_STATUS_OFF) {
+ if (screen_redraw_two_panes(wp->window)) {
+ if (wp->xoff == 0 && px == wp->sx && py <= wp->sy / 2)
+ return (2);
+ if (wp->xoff != 0 &&
+ px == wp->xoff - 1 &&
+ py > wp->sy / 2)
+ return (1);
+ } else {
+ if ((wp->yoff == 0 || py >= wp->yoff - 1) && py <= ey) {
+ if (wp->xoff != 0 && px == wp->xoff - 1)
+ return (1);
+ if (px == ex)
+ return (2);
+ }
+ }
+ } else {
+ if ((wp->yoff == 0 || py >= wp->yoff - 1) && py <= ey) {
+ if (wp->xoff != 0 && px == wp->xoff - 1)
+ return (1);
+ if (px == ex)
+ return (2);
+ }
}
/* 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 (3);
- if (py == wp->yoff + wp->sy)
- return (4);
+ if (pane_status == PANE_STATUS_OFF) {
+ if (screen_redraw_two_panes(wp->window)) {
+ if (wp->yoff == 0 && py == wp->sy && px <= wp->sx / 2)
+ return (4);
+ if (wp->yoff != 0 &&
+ py == wp->yoff - 1 &&
+ px > wp->sx / 2)
+ return (3);
+ } else {
+ if ((wp->xoff == 0 || px >= wp->xoff - 1) && px <= ex) {
+ if (wp->yoff != 0 && py == wp->yoff - 1)
+ return (3);
+ if (py == ey)
+ return (4);
+ }
+ }
+ } else if (pane_status == PANE_STATUS_TOP) {
+ if ((wp->xoff == 0 || px >= wp->xoff - 1) && px <= ex) {
+ if (wp->yoff != 0 && py == wp->yoff - 1)
+ return (3);
+ }
+ } else {
+ if ((wp->xoff == 0 || px >= wp->xoff - 1) && px <= ex) {
+ if (py == ey)
+ return (4);
+ }
}
/* Outside pane. */
@@ -76,7 +135,7 @@ screen_redraw_cell_border1(struct window_pane *wp, u_int px, u_int py)
/* Check if a cell is on the pane border. */
static int
-screen_redraw_cell_border(struct client *c, u_int px, u_int py)
+screen_redraw_cell_border(struct client *c, u_int px, u_int py, int pane_status)
{
struct window *w = c->session->curw->window;
struct window_pane *wp;
@@ -86,7 +145,8 @@ screen_redraw_cell_border(struct client *c, u_int px, u_int py)
TAILQ_FOREACH(wp, &w->panes, entry) {
if (!window_pane_visible(wp))
continue;
- if ((retval = screen_redraw_cell_border1(wp, px, py)) != -1)
+ retval = screen_redraw_cell_border1(wp, px, py, pane_status);
+ if (retval != -1)
return (!!retval);
}
@@ -100,7 +160,7 @@ screen_redraw_check_cell(struct client *c, u_int px, u_int py, int pane_status,
{
struct window *w = c->session->curw->window;
struct window_pane *wp;
- int borders;
+ int borders, border;
u_int right, line;
*wpp = NULL;
@@ -109,9 +169,10 @@ screen_redraw_check_cell(struct client *c, u_int px, u_int py, int pane_status,
return (CELL_OUTSIDE);
if (pane_status != PANE_STATUS_OFF) {
- TAILQ_FOREACH(wp, &w->panes, entry) {
+ wp = w->active;
+ do {
if (!window_pane_visible(wp))
- continue;
+ goto next1;
if (pane_status == PANE_STATUS_TOP)
line = wp->yoff - 1;
@@ -121,12 +182,18 @@ screen_redraw_check_cell(struct client *c, u_int px, u_int py, int pane_status,
if (py == line && px >= wp->xoff + 2 && px <= right)
return (CELL_INSIDE);
- }
+
+ next1:
+ wp = TAILQ_NEXT(wp, entry);
+ if (wp == NULL)
+ wp = TAILQ_FIRST(&w->panes);
+ } while (wp != w->active);
}
- TAILQ_FOREACH(wp, &w->panes, entry) {
+ wp = w->active;
+ do {
if (!window_pane_visible(wp))
- continue;
+ goto next2;
*wpp = wp;
/* If outside the pane and its border, skip it. */
@@ -134,29 +201,36 @@ screen_redraw_check_cell(struct client *c, u_int px, u_int py, int pane_status,
px > wp->xoff + wp->sx ||
(wp->yoff != 0 && py < wp->yoff - 1) ||
py > wp->yoff + wp->sy)
- continue;
+ goto next2;
- /* If definitely inside, return so. */
- if (!screen_redraw_cell_border(c, px, py))
+ /* If definitely inside, return. If not on border, skip. */
+ border = screen_redraw_cell_border1(wp, px, py, pane_status);
+ if (border == 0)
return (CELL_INSIDE);
+ if (border == -1)
+ goto next2;
/*
* 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))
+ if (px == 0 ||
+ screen_redraw_cell_border(c, px - 1, py, pane_status))
borders |= 8;
- if (px <= w->sx && screen_redraw_cell_border(c, px + 1, py))
+ if (px <= w->sx &&
+ screen_redraw_cell_border(c, px + 1, py, pane_status))
borders |= 4;
- if (pane_status == PANE_STATUS_TOP) {
- if (py != 0 && screen_redraw_cell_border(c, px, py - 1))
- borders |= 2;
- } else {
- 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))
+ if (pane_status == PANE_STATUS_TOP &&
+ py != 0 &&
+ screen_redraw_cell_border(c, px, py - 1, pane_status))
+ borders |= 2;
+ else if (pane_status != PANE_STATUS_TOP &&
+ (py == 0 ||
+ screen_redraw_cell_border(c, px, py - 1, pane_status)))
+ borders |= 2;
+ if (py <= w->sy &&
+ screen_redraw_cell_border(c, px, py + 1, pane_status))
borders |= 1;
/*
@@ -188,61 +262,26 @@ screen_redraw_check_cell(struct client *c, u_int px, u_int py, int pane_status,
case 3: /* 0011, top bottom */
return (CELL_LEFTRIGHT);
}
- }
+
+ next2:
+ wp = TAILQ_NEXT(wp, entry);
+ if (wp == NULL)
+ wp = TAILQ_FIRST(&w->panes);
+ } while (wp != w->active);
return (CELL_OUTSIDE);
}
/* Check if the border of a particular pane. */
static int
-screen_redraw_check_is(u_int px, u_int py, int type, int pane_status,
- struct window *w, struct window_pane *wantwp, struct window_pane *wp)
+screen_redraw_check_is(u_int px, u_int py, int pane_status,
+ struct window_pane *wp)
{
int border;
- /* Is this off the active pane border? */
- border = screen_redraw_cell_border1(wantwp, px, py);
+ border = screen_redraw_cell_border1(wp, px, py, pane_status);
if (border == 0 || border == -1)
return (0);
- if (pane_status == PANE_STATUS_TOP && border == 4)
- return (0);
- if (pane_status == PANE_STATUS_BOTTOM && border == 3)
- return (0);
-
- /* If there are more than two panes, that's enough. */
- if (window_count_panes(w) != 2)
- return (1);
-
- /* Else if the cell is not a border cell, forget it. */
- if (wp == NULL || (type == CELL_OUTSIDE || type == CELL_INSIDE))
- return (1);
-
- /* With status lines mark the entire line. */
- if (pane_status != PANE_STATUS_OFF)
- return (1);
-
- /* Check if the pane covers the whole width. */
- if (wp->xoff == 0 && wp->sx == w->sx) {
- /* This can either be the top pane or the bottom pane. */
- if (wp->yoff == 0) { /* top pane */
- if (wp == wantwp)
- return (px <= wp->sx / 2);
- return (px > wp->sx / 2);
- }
- return (0);
- }
-
- /* Check if the pane covers the whole height. */
- if (wp->yoff == 0 && wp->sy == w->sy) {
- /* This can either be the left pane or the right pane. */
- if (wp->xoff == 0) { /* left pane */
- if (wp == wantwp)
- return (py <= wp->sy / 2);
- return (py > wp->sy / 2);
- }
- return (0);
- }
-
return (1);
}
@@ -259,16 +298,15 @@ screen_redraw_make_pane_status(struct client *c, struct window *w,
struct screen_write_ctx ctx;
struct screen old;
+ ft = format_create(c, NULL, FORMAT_PANE|wp->id, FORMAT_STATUS);
+ format_defaults(ft, c, c->session, c->session->curw, wp);
+
if (wp == w->active)
- style_apply(&gc, w->options, "pane-active-border-style");
+ style_apply(&gc, w->options, "pane-active-border-style", ft);
else
- style_apply(&gc, w->options, "pane-border-style");
-
+ style_apply(&gc, w->options, "pane-border-style", ft);
fmt = options_get_string(w->options, "pane-border-format");
- ft = format_create(c, NULL, FORMAT_PANE|wp->id, FORMAT_STATUS);
- format_defaults(ft, c, NULL, NULL, wp);
-
expanded = format_expand_time(ft, fmt);
if (wp->sx < 4)
wp->status_size = width = 0;
@@ -279,7 +317,7 @@ screen_redraw_make_pane_status(struct client *c, struct window *w,
screen_init(&wp->status_screen, width, 1, 0);
wp->status_screen.mode = 0;
- screen_write_start(&ctx, NULL, &wp->status_screen);
+ screen_write_start(&ctx, &wp->status_screen);
gc.attr |= GRID_ATTR_CHARSET;
for (i = 0; i < width; i++)
@@ -356,7 +394,8 @@ screen_redraw_draw_pane_status(struct screen_redraw_ctx *ctx)
if (ctx->statustop)
yoff += ctx->statuslines;
- tty_draw_line(tty, NULL, s, i, 0, width, x, yoff - ctx->oy);
+ tty_draw_line(tty, s, i, 0, width, x, yoff - ctx->oy,
+ &grid_default_cell, NULL);
}
tty_cursor(tty, 0, 0);
}
@@ -434,20 +473,33 @@ screen_redraw_screen(struct client *c)
return;
flags = screen_redraw_update(c, c->flags);
+ if ((flags & CLIENT_ALLREDRAWFLAGS) == 0)
+ return;
+
screen_redraw_set_context(c, &ctx);
+ tty_update_mode(&c->tty, c->tty.mode, NULL);
+ tty_sync_start(&c->tty);
if (flags & (CLIENT_REDRAWWINDOW|CLIENT_REDRAWBORDERS)) {
+ log_debug("%s: redrawing borders", c->name);
if (ctx.pane_status != PANE_STATUS_OFF)
screen_redraw_draw_pane_status(&ctx);
screen_redraw_draw_borders(&ctx);
}
- if (flags & CLIENT_REDRAWWINDOW)
+ if (flags & CLIENT_REDRAWWINDOW) {
+ log_debug("%s: redrawing panes", c->name);
screen_redraw_draw_panes(&ctx);
+ }
if (ctx.statuslines != 0 &&
- (flags & (CLIENT_REDRAWSTATUS|CLIENT_REDRAWSTATUSALWAYS)))
+ (flags & (CLIENT_REDRAWSTATUS|CLIENT_REDRAWSTATUSALWAYS))) {
+ log_debug("%s: redrawing status", c->name);
screen_redraw_draw_status(&ctx);
- if (c->overlay_draw != NULL && (flags & CLIENT_REDRAWOVERLAY))
+ }
+ if (c->overlay_draw != NULL && (flags & CLIENT_REDRAWOVERLAY)) {
+ log_debug("%s: redrawing overlay", c->name);
c->overlay_draw(c, &ctx);
+ }
+
tty_reset(&c->tty);
}
@@ -461,42 +513,81 @@ screen_redraw_pane(struct client *c, struct window_pane *wp)
return;
screen_redraw_set_context(c, &ctx);
+ tty_update_mode(&c->tty, c->tty.mode, NULL);
+ tty_sync_start(&c->tty);
screen_redraw_draw_pane(&ctx, wp);
+
tty_reset(&c->tty);
}
+/* Get border cell style. */
+static const struct grid_cell *
+screen_redraw_draw_borders_style(struct screen_redraw_ctx *ctx, u_int x,
+ u_int y, struct window_pane *wp)
+{
+ struct client *c = ctx->c;
+ struct session *s = c->session;
+ struct window *w = s->curw->window;
+ struct options *oo = w->options;
+ struct grid_cell *gc;
+ struct format_tree *ft;
+
+ if (wp->border_gc_set)
+ return (&wp->border_gc);
+ wp->border_gc_set = 1;
+
+ ft = format_create_defaults(NULL, c, s, s->curw, wp);
+ gc = &wp->border_gc;
+
+ if (screen_redraw_check_is(x, y, ctx->pane_status, w->active)) {
+ style_apply(gc, oo, "pane-active-border-style", ft);
+ gc->attr |= GRID_ATTR_CHARSET;
+ } else {
+ style_apply(gc, oo, "pane-border-style", ft);
+ gc->attr |= GRID_ATTR_CHARSET;
+ }
+
+ format_free(ft);
+ return (gc);
+}
+
/* Draw a border cell. */
static void
-screen_redraw_draw_borders_cell(struct screen_redraw_ctx *ctx, u_int i, u_int j,
- struct grid_cell *m_active_gc, struct grid_cell *active_gc,
- struct grid_cell *m_other_gc, struct grid_cell *other_gc)
+screen_redraw_draw_borders_cell(struct screen_redraw_ctx *ctx, u_int i, u_int j)
{
struct client *c = ctx->c;
struct session *s = c->session;
- struct window *w = s->curw->window;
struct tty *tty = &c->tty;
struct window_pane *wp;
- struct window_pane *active = w->active;
- struct window_pane *marked = marked_pane.wp;
u_int type, x = ctx->ox + i, y = ctx->oy + j;
- int flag, pane_status = ctx->pane_status;
+ int pane_status = ctx->pane_status;
+ const struct grid_cell *gc;
+ struct grid_cell copy;
+
+ if (c->overlay_check != NULL && !c->overlay_check(c, x, y))
+ return;
type = screen_redraw_check_cell(c, x, y, pane_status, &wp);
if (type == CELL_INSIDE)
return;
- flag = screen_redraw_check_is(x, y, type, pane_status, w, active, wp);
- if (server_is_marked(s, s->curw, marked_pane.wp) &&
- screen_redraw_check_is(x, y, type, pane_status, w, marked, wp)) {
- if (flag)
- tty_attributes(tty, m_active_gc, NULL);
- else
- tty_attributes(tty, m_other_gc, NULL);
- } else if (flag)
- tty_attributes(tty, active_gc, NULL);
- else
- tty_attributes(tty, other_gc, NULL);
+ if (wp == NULL)
+ gc = &screen_redraw_border_cell;
+ else {
+ gc = screen_redraw_draw_borders_style(ctx, x, y, wp);
+ if (gc == NULL)
+ return;
+
+ if (server_is_marked(s, s->curw, marked_pane.wp) &&
+ screen_redraw_check_is(x, y, pane_status, marked_pane.wp)) {
+ memcpy(&copy, gc, sizeof copy);
+ copy.attr ^= GRID_ATTR_REVERSE;
+ gc = &copy;
+ }
+ }
+
+ tty_attributes(tty, gc, &grid_default_cell, NULL);
if (ctx->statustop)
tty_cursor(tty, i, ctx->statuslines + j);
else
@@ -511,27 +602,17 @@ screen_redraw_draw_borders(struct screen_redraw_ctx *ctx)
struct client *c = ctx->c;
struct session *s = c->session;
struct window *w = s->curw->window;
- struct tty *tty = &c->tty;
- struct options *oo = w->options;
- struct grid_cell m_active_gc, active_gc, m_other_gc, other_gc;
+ struct window_pane *wp;
u_int i, j;
log_debug("%s: %s @%u", __func__, c->name, w->id);
- style_apply(&other_gc, oo, "pane-border-style");
- style_apply(&active_gc, oo, "pane-active-border-style");
- active_gc.attr = other_gc.attr = GRID_ATTR_CHARSET;
-
- memcpy(&m_other_gc, &other_gc, sizeof m_other_gc);
- m_other_gc.attr ^= GRID_ATTR_REVERSE;
- memcpy(&m_active_gc, &active_gc, sizeof m_active_gc);
- m_active_gc.attr ^= GRID_ATTR_REVERSE;
+ TAILQ_FOREACH(wp, &w->panes, entry)
+ wp->border_gc_set = 0;
- for (j = 0; j < tty->sy - ctx->statuslines; j++) {
- for (i = 0; i < tty->sx; i++) {
- screen_redraw_draw_borders_cell(ctx, i, j,
- &m_active_gc, &active_gc, &m_other_gc, &other_gc);
- }
+ for (j = 0; j < c->tty.sy - ctx->statuslines; j++) {
+ for (i = 0; i < c->tty.sx; i++)
+ screen_redraw_draw_borders_cell(ctx, i, j);
}
}
@@ -567,8 +648,10 @@ screen_redraw_draw_status(struct screen_redraw_ctx *ctx)
y = 0;
else
y = c->tty.sy - ctx->statuslines;
- for (i = 0; i < ctx->statuslines; i++)
- tty_draw_line(tty, NULL, s, 0, i, UINT_MAX, 0, y + i);
+ for (i = 0; i < ctx->statuslines; i++) {
+ tty_draw_line(tty, s, 0, i, UINT_MAX, 0, y + i,
+ &grid_default_cell, NULL);
+ }
}
/* Draw one pane. */
@@ -579,6 +662,7 @@ screen_redraw_draw_pane(struct screen_redraw_ctx *ctx, struct window_pane *wp)
struct window *w = c->session->curw->window;
struct tty *tty = &c->tty;
struct screen *s;
+ struct grid_cell defaults;
u_int i, j, top, x, y, width;
log_debug("%s: %s @%u %%%u", __func__, c->name, w->id, wp->id);
@@ -622,6 +706,8 @@ screen_redraw_draw_pane(struct screen_redraw_ctx *ctx, struct window_pane *wp)
log_debug("%s: %s %%%u line %u,%u at %u,%u, width %u",
__func__, c->name, wp->id, i, j, x, y, width);
- tty_draw_line(tty, wp, s, i, j, width, x, y);
+ tty_default_colours(&defaults, wp);
+ tty_draw_line(tty, s, i, j, width, x, y, &defaults,
+ wp->palette);
}
}
diff --git a/screen-write.c b/screen-write.c
index 43cb42b4..909b8531 100644
--- a/screen-write.c
+++ b/screen-write.c
@@ -23,12 +23,15 @@
#include "tmux.h"
-static void screen_write_initctx(struct screen_write_ctx *,
- struct tty_ctx *);
static void screen_write_collect_clear(struct screen_write_ctx *, u_int,
u_int);
+static int screen_write_collect_clear_end(struct screen_write_ctx *, u_int,
+ u_int, u_int);
+static int screen_write_collect_clear_start(struct screen_write_ctx *,
+ u_int, u_int, u_int);
static void screen_write_collect_scroll(struct screen_write_ctx *);
-static void screen_write_collect_flush(struct screen_write_ctx *, int);
+static void screen_write_collect_flush(struct screen_write_ctx *, int,
+ const char *);
static int screen_write_overwrite(struct screen_write_ctx *,
struct grid_cell *, u_int);
@@ -43,15 +46,18 @@ struct screen_write_collect_item {
u_int x;
int wrapped;
+ enum { TEXT, CLEAR_END, CLEAR_START } type;
u_int used;
- char data[256];
+ u_int bg;
struct grid_cell gc;
TAILQ_ENTRY(screen_write_collect_item) entry;
};
struct screen_write_collect_line {
- TAILQ_HEAD(, screen_write_collect_item) items;
+ u_int bg;
+ char *data;
+ TAILQ_HEAD(, screen_write_collect_item) items;
};
static void
@@ -95,39 +101,177 @@ screen_write_set_cursor(struct screen_write_ctx *ctx, int cx, int cy)
evtimer_add(&w->offset_timer, &tv);
}
-/* Initialize writing with a window. */
+/* Do a full redraw. */
+static void
+screen_write_redraw_cb(const struct tty_ctx *ttyctx)
+{
+ struct window_pane *wp = ttyctx->arg;
+
+ wp->flags |= PANE_REDRAW;
+}
+
+/* Update context for client. */
+static int
+screen_write_set_client_cb(struct tty_ctx *ttyctx, struct client *c)
+{
+ struct window_pane *wp = ttyctx->arg;
+
+ if (c->session->curw->window != wp->window)
+ return (0);
+ if (wp->layout_cell == NULL)
+ return (0);
+
+ if (wp->flags & (PANE_REDRAW|PANE_DROP))
+ return (-1);
+ if (c->flags & CLIENT_REDRAWPANES) {
+ /*
+ * Redraw is already deferred to redraw another pane - redraw
+ * this one also when that happens.
+ */
+ log_debug("adding %%%u to deferred redraw", wp->id);
+ wp->flags |= PANE_REDRAW;
+ return (-1);
+ }
+
+ ttyctx->bigger = tty_window_offset(&c->tty, &ttyctx->wox, &ttyctx->woy,
+ &ttyctx->wsx, &ttyctx->wsy);
+
+ ttyctx->xoff = ttyctx->rxoff = wp->xoff;
+ ttyctx->yoff = ttyctx->ryoff = wp->yoff;
+
+ if (status_at_line(c) == 0)
+ ttyctx->yoff += status_line_size(c);
+
+ return (1);
+}
+
+/* Set up context for TTY command. */
+static void
+screen_write_initctx(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx,
+ int sync)
+{
+ struct screen *s = ctx->s;
+
+ memset(ttyctx, 0, sizeof *ttyctx);
+
+ if (ctx->wp != NULL) {
+ tty_default_colours(&ttyctx->defaults, ctx->wp);
+ ttyctx->palette = ctx->wp->palette;
+ } else {
+ memcpy(&ttyctx->defaults, &grid_default_cell,
+ sizeof ttyctx->defaults);
+ ttyctx->palette = NULL;
+ }
+
+ ttyctx->s = s;
+ ttyctx->sx = screen_size_x(s);
+ ttyctx->sy = screen_size_y(s);
+
+ ttyctx->ocx = s->cx;
+ ttyctx->ocy = s->cy;
+ ttyctx->orlower = s->rlower;
+ ttyctx->orupper = s->rupper;
+
+ if (ctx->init_ctx_cb != NULL)
+ ctx->init_ctx_cb(ctx, ttyctx);
+ else {
+ ttyctx->redraw_cb = screen_write_redraw_cb;
+ if (ctx->wp == NULL)
+ ttyctx->set_client_cb = NULL;
+ else
+ ttyctx->set_client_cb = screen_write_set_client_cb;
+ ttyctx->arg = ctx->wp;
+ }
+
+ if (ctx->wp != NULL &&
+ !ctx->sync &&
+ (sync || ctx->wp != ctx->wp->window->active)) {
+ tty_write(tty_cmd_syncstart, ttyctx);
+ ctx->sync = 1;
+ }
+}
+
+/* Make write list. */
void
-screen_write_start(struct screen_write_ctx *ctx, struct window_pane *wp,
- struct screen *s)
+screen_write_make_list(struct screen *s)
+{
+ u_int y;
+
+ s->write_list = xcalloc(screen_size_y(s), sizeof *s->write_list);
+ for (y = 0; y < screen_size_y(s); y++)
+ TAILQ_INIT(&s->write_list[y].items);
+}
+
+/* Free write list. */
+void
+screen_write_free_list(struct screen *s)
{
u_int y;
+ for (y = 0; y < screen_size_y(s); y++)
+ free(s->write_list[y].data);
+ free(s->write_list);
+}
+
+/* Set up for writing. */
+static void
+screen_write_init(struct screen_write_ctx *ctx, struct screen *s)
+{
memset(ctx, 0, sizeof *ctx);
- ctx->wp = wp;
- if (wp != NULL && s == NULL)
- ctx->s = wp->screen;
- else
- ctx->s = s;
+ ctx->s = s;
- ctx->list = xcalloc(screen_size_y(ctx->s), sizeof *ctx->list);
- for (y = 0; y < screen_size_y(ctx->s); y++)
- TAILQ_INIT(&ctx->list[y].items);
+ if (ctx->s->write_list == NULL)
+ screen_write_make_list(ctx->s);
ctx->item = xcalloc(1, sizeof *ctx->item);
ctx->scrolled = 0;
ctx->bg = 8;
+}
+
+/* Initialize writing with a pane. */
+void
+screen_write_start_pane(struct screen_write_ctx *ctx, struct window_pane *wp,
+ struct screen *s)
+{
+ if (s == NULL)
+ s = wp->screen;
+ screen_write_init(ctx, s);
+ ctx->wp = wp;
if (log_get_level() != 0) {
- if (wp != NULL) {
- log_debug("%s: size %ux%u, pane %%%u (at %u,%u)",
- __func__, screen_size_x(ctx->s),
- screen_size_y(ctx->s), wp->id, wp->xoff, wp->yoff);
- } else {
- log_debug("%s: size %ux%u, no pane",
- __func__, screen_size_x(ctx->s),
- screen_size_y(ctx->s));
- }
+ log_debug("%s: size %ux%u, pane %%%u (at %u,%u)",
+ __func__, screen_size_x(ctx->s), screen_size_y(ctx->s),
+ wp->id, wp->xoff, wp->yoff);
+ }
+}
+
+/* Initialize writing with a callback. */
+void
+screen_write_start_callback(struct screen_write_ctx *ctx, struct screen *s,
+ screen_write_init_ctx_cb cb, void *arg)
+{
+ screen_write_init(ctx, s);
+
+ ctx->init_ctx_cb = cb;
+ ctx->arg = arg;
+
+ if (log_get_level() != 0) {
+ log_debug("%s: size %ux%u, with callback", __func__,
+ screen_size_x(ctx->s), screen_size_y(ctx->s));
+ }
+}
+
+
+/* Initialize writing. */
+void
+screen_write_start(struct screen_write_ctx *ctx, struct screen *s)
+{
+ screen_write_init(ctx, s);
+
+ if (log_get_level() != 0) {
+ log_debug("%s: size %ux%u, no pane", __func__,
+ screen_size_x(ctx->s), screen_size_y(ctx->s));
}
}
@@ -136,13 +280,16 @@ void
screen_write_stop(struct screen_write_ctx *ctx)
{
screen_write_collect_end(ctx);
- screen_write_collect_flush(ctx, 0);
+ screen_write_collect_flush(ctx, 0, __func__);
log_debug("%s: %u cells (%u written, %u skipped)", __func__,
ctx->cells, ctx->written, ctx->skipped);
+ if (ctx->wp != NULL) {
+ ctx->wp->written += ctx->written;
+ ctx->wp->skipped += ctx->skipped;
+ }
free(ctx->item);
- free(ctx->list); /* flush will have emptied */
}
/* Reset screen state. */
@@ -291,44 +438,9 @@ screen_write_vnputs(struct screen_write_ctx *ctx, ssize_t maxlen,
free(msg);
}
-/* Copy from another screen. Assumes target region is big enough. */
-void
-screen_write_copy(struct screen_write_ctx *ctx, struct screen *src, u_int px,
- u_int py, u_int nx, u_int ny, bitstr_t *mbs, const struct grid_cell *mgc)
-{
- struct screen *s = ctx->s;
- struct grid *gd = src->grid;
- struct grid_cell gc;
- u_int xx, yy, cx, cy, b;
-
- if (nx == 0 || ny == 0)
- return;
-
- cx = s->cx;
- cy = s->cy;
-
- for (yy = py; yy < py + ny; yy++) {
- for (xx = px; xx < px + nx; xx++) {
- grid_get_cell(gd, xx, yy, &gc);
- if (mbs != NULL) {
- b = (yy * screen_size_x(src)) + xx;
- if (bit_test(mbs, b)) {
- gc.attr = mgc->attr;
- gc.fg = mgc->fg;
- gc.bg = mgc->bg;
- }
- }
- if (xx + gc.data.width <= px + nx)
- screen_write_cell(ctx, &gc);
- }
- cy++;
- screen_write_set_cursor(ctx, cx, cy);
- }
-}
-
/*
- * Copy from another screen but without the selection stuff. Also assumes the
- * target region is already big enough.
+ * Copy from another screen but without the selection stuff. Assumes the target
+ * region is already big enough.
*/
void
screen_write_fast_copy(struct screen_write_ctx *ctx, struct screen *src,
@@ -409,21 +521,23 @@ screen_write_vline(struct screen_write_ctx *ctx, u_int ny, int top, int bottom)
/* Draw a menu on screen. */
void
-screen_write_menu(struct screen_write_ctx *ctx, struct menu *menu, int choice)
+screen_write_menu(struct screen_write_ctx *ctx, struct menu *menu,
+ int choice, const struct grid_cell *choice_gc)
{
struct screen *s = ctx->s;
- struct grid_cell gc;
+ struct grid_cell default_gc;
+ const struct grid_cell *gc = &default_gc;
u_int cx, cy, i, j;
const char *name;
cx = s->cx;
cy = s->cy;
- memcpy(&gc, &grid_default_cell, sizeof gc);
+ memcpy(&default_gc, &grid_default_cell, sizeof default_gc);
screen_write_box(ctx, menu->width + 4, menu->count + 2);
screen_write_cursormove(ctx, cx + 2, cy, 0);
- format_draw(ctx, &gc, menu->width, menu->title, NULL);
+ format_draw(ctx, &default_gc, menu->width, menu->title, NULL);
for (i = 0; i < menu->count; i++) {
name = menu->items[i].name;
@@ -432,20 +546,19 @@ screen_write_menu(struct screen_write_ctx *ctx, struct menu *menu, int choice)
screen_write_hline(ctx, menu->width + 4, 1, 1);
} else {
if (choice >= 0 && i == (u_int)choice && *name != '-')
- gc.attr |= GRID_ATTR_REVERSE;
+ gc = choice_gc;
screen_write_cursormove(ctx, cx + 2, cy + 1 + i, 0);
for (j = 0; j < menu->width; j++)
- screen_write_putc(ctx, &gc, ' ');
+ screen_write_putc(ctx, gc, ' ');
screen_write_cursormove(ctx, cx + 2, cy + 1 + i, 0);
if (*name == '-') {
name++;
- gc.attr |= GRID_ATTR_DIM;
- format_draw(ctx, &gc, menu->width, name, NULL);
- gc.attr &= ~GRID_ATTR_DIM;
+ default_gc.attr |= GRID_ATTR_DIM;
+ format_draw(ctx, gc, menu->width, name, NULL);
+ default_gc.attr &= ~GRID_ATTR_DIM;
} else
- format_draw(ctx, &gc, menu->width, name, NULL);
- if (choice >= 0 && i == (u_int)choice)
- gc.attr &= ~GRID_ATTR_REVERSE;
+ format_draw(ctx, gc, menu->width, name, NULL);
+ gc = &default_gc;
}
}
@@ -547,23 +660,6 @@ screen_write_preview(struct screen_write_ctx *ctx, struct screen *src, u_int nx,
}
}
-/* Set up context for TTY command. */
-static void
-screen_write_initctx(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx)
-{
- struct screen *s = ctx->s;
-
- memset(ttyctx, 0, sizeof *ttyctx);
-
- ttyctx->wp = ctx->wp;
-
- ttyctx->ocx = s->cx;
- ttyctx->ocy = s->cy;
-
- ttyctx->orlower = s->rlower;
- ttyctx->orupper = s->rupper;
-}
-
/* Set a mode. */
void
screen_write_mode_set(struct screen_write_ctx *ctx, int mode)
@@ -722,7 +818,7 @@ screen_write_alignmenttest(struct screen_write_ctx *ctx)
s->rupper = 0;
s->rlower = screen_size_y(s) - 1;
- screen_write_initctx(ctx, &ttyctx);
+ screen_write_initctx(ctx, &ttyctx, 1);
screen_write_collect_clear(ctx, 0, screen_size_y(s) - 1);
tty_write(tty_cmd_alignmenttest, &ttyctx);
@@ -746,12 +842,12 @@ screen_write_insertcharacter(struct screen_write_ctx *ctx, u_int nx, u_int bg)
if (s->cx > screen_size_x(s) - 1)
return;
- screen_write_initctx(ctx, &ttyctx);
+ screen_write_initctx(ctx, &ttyctx, 0);
ttyctx.bg = bg;
grid_view_insert_cells(s->grid, s->cx, s->cy, nx, bg);
- screen_write_collect_flush(ctx, 0);
+ screen_write_collect_flush(ctx, 0, __func__);
ttyctx.num = nx;
tty_write(tty_cmd_insertcharacter, &ttyctx);
}
@@ -774,12 +870,12 @@ screen_write_deletecharacter(struct screen_write_ctx *ctx, u_int nx, u_int bg)
if (s->cx > screen_size_x(s) - 1)
return;
- screen_write_initctx(ctx, &ttyctx);
+ screen_write_initctx(ctx, &ttyctx, 0);
ttyctx.bg = bg;
grid_view_delete_cells(s->grid, s->cx, s->cy, nx, bg);
- screen_write_collect_flush(ctx, 0);
+ screen_write_collect_flush(ctx, 0, __func__);
ttyctx.num = nx;
tty_write(tty_cmd_deletecharacter, &ttyctx);
}
@@ -802,12 +898,12 @@ screen_write_clearcharacter(struct screen_write_ctx *ctx, u_int nx, u_int bg)
if (s->cx > screen_size_x(s) - 1)
return;
- screen_write_initctx(ctx, &ttyctx);
+ screen_write_initctx(ctx, &ttyctx, 0);
ttyctx.bg = bg;
grid_view_clear(s->grid, s->cx, s->cy, nx, 1, bg);
- screen_write_collect_flush(ctx, 0);
+ screen_write_collect_flush(ctx, 0, __func__);
ttyctx.num = nx;
tty_write(tty_cmd_clearcharacter, &ttyctx);
}
@@ -829,12 +925,12 @@ screen_write_insertline(struct screen_write_ctx *ctx, u_int ny, u_int bg)
if (ny == 0)
return;
- screen_write_initctx(ctx, &ttyctx);
+ screen_write_initctx(ctx, &ttyctx, 1);
ttyctx.bg = bg;
grid_view_insert_lines(gd, s->cy, ny, bg);
- screen_write_collect_flush(ctx, 0);
+ screen_write_collect_flush(ctx, 0, __func__);
ttyctx.num = ny;
tty_write(tty_cmd_insertline, &ttyctx);
return;
@@ -845,7 +941,7 @@ screen_write_insertline(struct screen_write_ctx *ctx, u_int ny, u_int bg)
if (ny == 0)
return;
- screen_write_initctx(ctx, &ttyctx);
+ screen_write_initctx(ctx, &ttyctx, 1);
ttyctx.bg = bg;
if (s->cy < s->rupper || s->cy > s->rlower)
@@ -853,7 +949,8 @@ screen_write_insertline(struct screen_write_ctx *ctx, u_int ny, u_int bg)
else
grid_view_insert_lines_region(gd, s->rlower, s->cy, ny, bg);
- screen_write_collect_flush(ctx, 0);
+ screen_write_collect_flush(ctx, 0, __func__);
+
ttyctx.num = ny;
tty_write(tty_cmd_insertline, &ttyctx);
}
@@ -875,12 +972,12 @@ screen_write_deleteline(struct screen_write_ctx *ctx, u_int ny, u_int bg)
if (ny == 0)
return;
- screen_write_initctx(ctx, &ttyctx);
+ screen_write_initctx(ctx, &ttyctx, 1);
ttyctx.bg = bg;
grid_view_delete_lines(gd, s->cy, ny, bg);
- screen_write_collect_flush(ctx, 0);
+ screen_write_collect_flush(ctx, 0, __func__);
ttyctx.num = ny;
tty_write(tty_cmd_deleteline, &ttyctx);
return;
@@ -891,7 +988,7 @@ screen_write_deleteline(struct screen_write_ctx *ctx, u_int ny, u_int bg)
if (ny == 0)
return;
- screen_write_initctx(ctx, &ttyctx);
+ screen_write_initctx(ctx, &ttyctx, 1);
ttyctx.bg = bg;
if (s->cy < s->rupper || s->cy > s->rlower)
@@ -899,7 +996,7 @@ screen_write_deleteline(struct screen_write_ctx *ctx, u_int ny, u_int bg)
else
grid_view_delete_lines_region(gd, s->rlower, s->cy, ny, bg);
- screen_write_collect_flush(ctx, 0);
+ screen_write_collect_flush(ctx, 0, __func__);
ttyctx.num = ny;
tty_write(tty_cmd_deleteline, &ttyctx);
}
@@ -908,69 +1005,75 @@ screen_write_deleteline(struct screen_write_ctx *ctx, u_int ny, u_int bg)
void
screen_write_clearline(struct screen_write_ctx *ctx, u_int bg)
{
- struct screen *s = ctx->s;
- struct grid_line *gl;
- struct tty_ctx ttyctx;
- u_int sx = screen_size_x(s);
+ struct screen *s = ctx->s;
+ struct grid_line *gl;
+ u_int sx = screen_size_x(s);
gl = grid_get_line(s->grid, s->grid->hsize + s->cy);
if (gl->cellsize == 0 && COLOUR_DEFAULT(bg))
return;
- screen_write_initctx(ctx, &ttyctx);
- ttyctx.bg = bg;
-
grid_view_clear(s->grid, 0, s->cy, sx, 1, bg);
screen_write_collect_clear(ctx, s->cy, 1);
- screen_write_collect_flush(ctx, 0);
- tty_write(tty_cmd_clearline, &ttyctx);
+ ctx->s->write_list[s->cy].bg = 1 + bg;
+ ctx->item->used = 0;
}
/* Clear to end of line from cursor. */
void
screen_write_clearendofline(struct screen_write_ctx *ctx, u_int bg)
{
- struct screen *s = ctx->s;
- struct grid_line *gl;
- struct tty_ctx ttyctx;
- u_int sx = screen_size_x(s);
+ struct screen *s = ctx->s;
+ struct grid_line *gl;
+ u_int sx = screen_size_x(s);
+ struct screen_write_collect_item *ci = ctx->item;
+
+ if (s->cx == 0) {
+ screen_write_clearline(ctx, bg);
+ return;
+ }
gl = grid_get_line(s->grid, s->grid->hsize + s->cy);
if (s->cx > sx - 1 || (s->cx >= gl->cellsize && COLOUR_DEFAULT(bg)))
return;
- screen_write_initctx(ctx, &ttyctx);
- ttyctx.bg = bg;
-
grid_view_clear(s->grid, s->cx, s->cy, sx - s->cx, 1, bg);
- if (s->cx == 0)
- screen_write_collect_clear(ctx, s->cy, 1);
- screen_write_collect_flush(ctx, 0);
- tty_write(tty_cmd_clearendofline, &ttyctx);
+ if (!screen_write_collect_clear_end(ctx, s->cy, s->cx, bg)) {
+ ci->x = s->cx;
+ ci->type = CLEAR_END;
+ ci->bg = bg;
+ TAILQ_INSERT_TAIL(&ctx->s->write_list[s->cy].items, ci, entry);
+ ctx->item = xcalloc(1, sizeof *ctx->item);
+ }
}
/* Clear to start of line from cursor. */
void
screen_write_clearstartofline(struct screen_write_ctx *ctx, u_int bg)
{
- struct screen *s = ctx->s;
- struct tty_ctx ttyctx;
- u_int sx = screen_size_x(s);
+ struct screen *s = ctx->s;
+ u_int sx = screen_size_x(s);
+ struct screen_write_collect_item *ci = ctx->item;
- screen_write_initctx(ctx, &ttyctx);
- ttyctx.bg = bg;
+ if (s->cx >= sx - 1) {
+ screen_write_clearline(ctx, bg);
+ return;
+ }
if (s->cx > sx - 1)
grid_view_clear(s->grid, 0, s->cy, sx, 1, bg);
else
grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1, bg);
- if (s->cx > sx - 1)
- screen_write_collect_clear(ctx, s->cy, 1);
- screen_write_collect_flush(ctx, 0);
- tty_write(tty_cmd_clearstartofline, &ttyctx);
+ if (!screen_write_collect_clear_start(ctx, s->cy, s->cx, bg)) {
+ ci->x = s->cx;
+ ci->type = CLEAR_START;
+ ci->bg = bg;
+ TAILQ_INSERT_TAIL(&ctx->s->write_list[s->cy].items, ci, entry);
+ ctx->item = xcalloc(1, sizeof *ctx->item);
+ }
}
/* Move cursor to px,py. */
@@ -1002,16 +1105,17 @@ screen_write_reverseindex(struct screen_write_ctx *ctx, u_int bg)
struct screen *s = ctx->s;
struct tty_ctx ttyctx;
- screen_write_initctx(ctx, &ttyctx);
- ttyctx.bg = bg;
-
- if (s->cy == s->rupper)
+ if (s->cy == s->rupper) {
grid_view_scroll_region_down(s->grid, s->rupper, s->rlower, bg);
- else if (s->cy > 0)
+ screen_write_collect_flush(ctx, 0, __func__);
+
+ screen_write_initctx(ctx, &ttyctx, 1);
+ ttyctx.bg = bg;
+
+ tty_write(tty_cmd_reverseindex, &ttyctx);
+ } else if (s->cy > 0)
screen_write_set_cursor(ctx, -1, s->cy - 1);
- screen_write_collect_flush(ctx, 0);
- tty_write(tty_cmd_reverseindex, &ttyctx);
}
/* Set scroll region. */
@@ -1028,7 +1132,7 @@ screen_write_scrollregion(struct screen_write_ctx *ctx, u_int rupper,
if (rupper >= rlower) /* cannot be one line */
return;
- screen_write_collect_flush(ctx, 0);
+ screen_write_collect_flush(ctx, 0, __func__);
/* Cursor moves to top-left. */
screen_write_set_cursor(ctx, 0, 0);
@@ -1055,7 +1159,7 @@ screen_write_linefeed(struct screen_write_ctx *ctx, int wrapped, u_int bg)
s->rupper, s->rlower);
if (bg != ctx->bg) {
- screen_write_collect_flush(ctx, 1);
+ screen_write_collect_flush(ctx, 1, __func__);
ctx->bg = bg;
}
@@ -1081,7 +1185,7 @@ screen_write_scrollup(struct screen_write_ctx *ctx, u_int lines, u_int bg)
lines = s->rlower - s->rupper + 1;
if (bg != ctx->bg) {
- screen_write_collect_flush(ctx, 1);
+ screen_write_collect_flush(ctx, 1, __func__);
ctx->bg = bg;
}
@@ -1101,7 +1205,7 @@ screen_write_scrolldown(struct screen_write_ctx *ctx, u_int lines, u_int bg)
struct tty_ctx ttyctx;
u_int i;
- screen_write_initctx(ctx, &ttyctx);
+ screen_write_initctx(ctx, &ttyctx, 1);
ttyctx.bg = bg;
if (lines == 0)
@@ -1112,7 +1216,7 @@ screen_write_scrolldown(struct screen_write_ctx *ctx, u_int lines, u_int bg)
for (i = 0; i < lines; i++)
grid_view_scroll_region_down(gd, s->rupper, s->rlower, bg);
- screen_write_collect_flush(ctx, 0);
+ screen_write_collect_flush(ctx, 0, __func__);
ttyctx.num = lines;
tty_write(tty_cmd_scrolldown, &ttyctx);
}
@@ -1133,7 +1237,7 @@ screen_write_clearendofscreen(struct screen_write_ctx *ctx, u_int bg)
struct tty_ctx ttyctx;
u_int sx = screen_size_x(s), sy = screen_size_y(s);
- screen_write_initctx(ctx, &ttyctx);
+ screen_write_initctx(ctx, &ttyctx, 1);
ttyctx.bg = bg;
/* Scroll into history if it is enabled and clearing entire screen. */
@@ -1146,7 +1250,7 @@ screen_write_clearendofscreen(struct screen_write_ctx *ctx, u_int bg)
}
screen_write_collect_clear(ctx, s->cy + 1, sy - (s->cy + 1));
- screen_write_collect_flush(ctx, 0);
+ screen_write_collect_flush(ctx, 0, __func__);
tty_write(tty_cmd_clearendofscreen, &ttyctx);
}
@@ -1158,7 +1262,7 @@ screen_write_clearstartofscreen(struct screen_write_ctx *ctx, u_int bg)
struct tty_ctx ttyctx;
u_int sx = screen_size_x(s);
- screen_write_initctx(ctx, &ttyctx);
+ screen_write_initctx(ctx, &ttyctx, 1);
ttyctx.bg = bg;
if (s->cy > 0)
@@ -1169,7 +1273,7 @@ screen_write_clearstartofscreen(struct screen_write_ctx *ctx, u_int bg)
grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1, bg);
screen_write_collect_clear(ctx, 0, s->cy);
- screen_write_collect_flush(ctx, 0);
+ screen_write_collect_flush(ctx, 0, __func__);
tty_write(tty_cmd_clearstartofscreen, &ttyctx);
}
@@ -1181,7 +1285,7 @@ screen_write_clearscreen(struct screen_write_ctx *ctx, u_int bg)
struct tty_ctx ttyctx;
u_int sx = screen_size_x(s), sy = screen_size_y(s);
- screen_write_initctx(ctx, &ttyctx);
+ screen_write_initctx(ctx, &ttyctx, 1);
ttyctx.bg = bg;
/* Scroll into history if it is enabled. */
@@ -1201,25 +1305,112 @@ screen_write_clearhistory(struct screen_write_ctx *ctx)
grid_clear_history(ctx->s->grid);
}
-/* Clear a collected line. */
+/* Clear to start of a collected line. */
+static int
+screen_write_collect_clear_start(struct screen_write_ctx *ctx, u_int y, u_int x,
+ u_int bg)
+{
+ struct screen_write_collect_item *ci, *tmp;
+ size_t size = 0;
+ u_int items = 0;
+ int redundant = 0;
+
+ if (TAILQ_EMPTY(&ctx->s->write_list[y].items))
+ return (0);
+ TAILQ_FOREACH_SAFE(ci, &ctx->s->write_list[y].items, entry, tmp) {
+ switch (ci->type) {
+ case CLEAR_START:
+ if (ci->x >= x) {
+ if (ci->bg == bg)
+ redundant = 1;
+ continue;
+ }
+ break;
+ case CLEAR_END:
+ if (ci->x <= x)
+ ci->x = x;
+ continue;
+ case TEXT:
+ if (ci->x > x)
+ continue;
+ break;
+ }
+ items++;
+ size += ci->used;
+ TAILQ_REMOVE(&ctx->s->write_list[y].items, ci, entry);
+ free(ci);
+ }
+ ctx->skipped += size;
+ log_debug("%s: dropped %u items (%zu bytes) (line %u)", __func__, items,
+ size, y);
+ return (redundant);
+}
+
+/* Clear to end of a collected line. */
+static int
+screen_write_collect_clear_end(struct screen_write_ctx *ctx, u_int y, u_int x,
+ u_int bg)
+{
+ struct screen_write_collect_item *ci, *tmp;
+ size_t size = 0;
+ int redundant = 0;
+ u_int items = 0;
+
+ if (TAILQ_EMPTY(&ctx->s->write_list[y].items))
+ return (0);
+ TAILQ_FOREACH_SAFE(ci, &ctx->s->write_list[y].items, entry, tmp) {
+ switch (ci->type) {
+ case CLEAR_START:
+ if (ci->x >= x)
+ ci->x = x;
+ continue;
+ case CLEAR_END:
+ if (ci->x <= x) {
+ if (ci->bg == bg)
+ redundant = 1;
+ continue;
+ }
+ break;
+ case TEXT:
+ if (ci->x < x)
+ continue;
+ break;
+ }
+ items++;
+ size += ci->used;
+ TAILQ_REMOVE(&ctx->s->write_list[y].items, ci, entry);
+ free(ci);
+ }
+ ctx->skipped += size;
+ log_debug("%s: dropped %u items (%zu bytes) (line %u)", __func__, items,
+ size, y);
+ return (redundant);
+}
+
+/* Clear collected lines. */
static void
screen_write_collect_clear(struct screen_write_ctx *ctx, u_int y, u_int n)
{
struct screen_write_collect_item *ci, *tmp;
- u_int i;
+ struct screen_write_collect_line *cl;
+ u_int i, items;
size_t size;
for (i = y; i < y + n; i++) {
- if (TAILQ_EMPTY(&ctx->list[i].items))
+ if (TAILQ_EMPTY(&ctx->s->write_list[i].items))
continue;
+ items = 0;
size = 0;
- TAILQ_FOREACH_SAFE(ci, &ctx->list[i].items, entry, tmp) {
+ cl = &ctx->s->write_list[i];
+ TAILQ_FOREACH_SAFE(ci, &cl->items, entry, tmp) {
+ items++;
size += ci->used;
- TAILQ_REMOVE(&ctx->list[i].items, ci, entry);
+ TAILQ_REMOVE(&cl->items, ci, entry);
free(ci);
}
ctx->skipped += size;
- log_debug("%s: dropped %zu bytes (line %u)", __func__, size, i);
+ log_debug("%s: dropped %u items (%zu bytes) (line %u)",
+ __func__, items, size, y);
}
}
@@ -1230,23 +1421,31 @@ screen_write_collect_scroll(struct screen_write_ctx *ctx)
struct screen *s = ctx->s;
struct screen_write_collect_line *cl;
u_int y;
+ char *saved;
log_debug("%s: at %u,%u (region %u-%u)", __func__, s->cx, s->cy,
s->rupper, s->rlower);
screen_write_collect_clear(ctx, s->rupper, 1);
+ saved = ctx->s->write_list[s->rupper].data;
for (y = s->rupper; y < s->rlower; y++) {
- cl = &ctx->list[y + 1];
- TAILQ_CONCAT(&ctx->list[y].items, &cl->items, entry);
+ cl = &ctx->s->write_list[y + 1];
+ TAILQ_CONCAT(&ctx->s->write_list[y].items, &cl->items, entry);
+ ctx->s->write_list[y].bg = cl->bg;
+ ctx->s->write_list[y].data = cl->data;
}
+ ctx->s->write_list[s->rlower].bg = 1 + 8;
+ ctx->s->write_list[s->rlower].data = saved;
}
/* Flush collected lines. */
static void
-screen_write_collect_flush(struct screen_write_ctx *ctx, int scroll_only)
+screen_write_collect_flush(struct screen_write_ctx *ctx, int scroll_only,
+ const char *from)
{
struct screen *s = ctx->s;
struct screen_write_collect_item *ci, *tmp;
+ struct screen_write_collect_line *cl;
u_int y, cx, cy, items = 0;
struct tty_ctx ttyctx;
size_t written = 0;
@@ -1257,7 +1456,7 @@ screen_write_collect_flush(struct screen_write_ctx *ctx, int scroll_only)
if (ctx->scrolled > s->rlower - s->rupper + 1)
ctx->scrolled = s->rlower - s->rupper + 1;
- screen_write_initctx(ctx, &ttyctx);
+ screen_write_initctx(ctx, &ttyctx, 1);
ttyctx.num = ctx->scrolled;
ttyctx.bg = ctx->bg;
tty_write(tty_cmd_scrollup, &ttyctx);
@@ -1270,25 +1469,44 @@ screen_write_collect_flush(struct screen_write_ctx *ctx, int scroll_only)
cx = s->cx; cy = s->cy;
for (y = 0; y < screen_size_y(s); y++) {
- TAILQ_FOREACH_SAFE(ci, &ctx->list[y].items, entry, tmp) {
+ cl = &ctx->s->write_list[y];
+ if (cl->bg != 0) {
+ screen_write_set_cursor(ctx, 0, y);
+ screen_write_initctx(ctx, &ttyctx, 1);
+ ttyctx.bg = cl->bg - 1;
+ tty_write(tty_cmd_clearline, &ttyctx);
+ }
+ TAILQ_FOREACH_SAFE(ci, &cl->items, entry, tmp) {
screen_write_set_cursor(ctx, ci->x, y);
- screen_write_initctx(ctx, &ttyctx);
- ttyctx.cell = &ci->gc;
- ttyctx.wrapped = ci->wrapped;
- ttyctx.ptr = ci->data;
- ttyctx.num = ci->used;
- tty_write(tty_cmd_cells, &ttyctx);
+ if (ci->type == CLEAR_END) {
+ screen_write_initctx(ctx, &ttyctx, 1);
+ ttyctx.bg = ci->bg;
+ tty_write(tty_cmd_clearendofline, &ttyctx);
+ } else if (ci->type == CLEAR_START) {
+ screen_write_initctx(ctx, &ttyctx, 1);
+ ttyctx.bg = ci->bg;
+ tty_write(tty_cmd_clearstartofline, &ttyctx);
+ } else {
+ screen_write_initctx(ctx, &ttyctx, 0);
+ ttyctx.cell = &ci->gc;
+ ttyctx.wrapped = ci->wrapped;
+ ttyctx.ptr = cl->data + ci->x;
+ ttyctx.num = ci->used;
+ tty_write(tty_cmd_cells, &ttyctx);
+ }
items++;
written += ci->used;
- TAILQ_REMOVE(&ctx->list[y].items, ci, entry);
+ TAILQ_REMOVE(&cl->items, ci, entry);
free(ci);
}
+ cl->bg = 0;
}
s->cx = cx; s->cy = cy;
- log_debug("%s: flushed %u items (%zu bytes)", __func__, items, written);
+ log_debug("%s: flushed %u items (%zu bytes) (%s)", __func__, items,
+ written, from);
ctx->written += written;
}
@@ -1298,19 +1516,19 @@ screen_write_collect_end(struct screen_write_ctx *ctx)
{
struct screen *s = ctx->s;
struct screen_write_collect_item *ci = ctx->item;
+ struct screen_write_collect_line *cl = &s->write_list[s->cy];
struct grid_cell gc;
u_int xx;
if (ci->used == 0)
return;
- ci->data[ci->used] = '\0';
ci->x = s->cx;
- TAILQ_INSERT_TAIL(&ctx->list[s->cy].items, ci, entry);
+ TAILQ_INSERT_TAIL(&cl->items, ci, entry);
ctx->item = xcalloc(1, sizeof *ctx->item);
- log_debug("%s: %u %s (at %u,%u)", __func__, ci->used, ci->data, s->cx,
- s->cy);
+ log_debug("%s: %u %.*s (at %u,%u)", __func__, ci->used,
+ (int)ci->used, cl->data + ci->x, s->cx, s->cy);
if (s->cx != 0) {
for (xx = s->cx; xx > 0; xx--) {
@@ -1326,7 +1544,8 @@ screen_write_collect_end(struct screen_write_ctx *ctx)
}
}
- grid_view_set_cells(s->grid, s->cx, s->cy, &ci->gc, ci->data, ci->used);
+ grid_view_set_cells(s->grid, s->cx, s->cy, &ci->gc, cl->data + ci->x,
+ ci->used);
screen_write_set_cursor(ctx, s->cx + ci->used, -1);
for (xx = s->cx; xx < screen_size_x(s); xx++) {
@@ -1366,7 +1585,7 @@ screen_write_collect_add(struct screen_write_ctx *ctx,
collect = 0;
if (!collect) {
screen_write_collect_end(ctx);
- screen_write_collect_flush(ctx, 0);
+ screen_write_collect_flush(ctx, 0, __func__);
screen_write_cell(ctx, gc);
return;
}
@@ -1385,9 +1604,9 @@ screen_write_collect_add(struct screen_write_ctx *ctx,
if (ci->used == 0)
memcpy(&ci->gc, gc, sizeof ci->gc);
- ci->data[ci->used++] = gc->data.data[0];
- if (ci->used == (sizeof ci->data) - 1)
- screen_write_collect_end(ctx);
+ if (ctx->s->write_list[s->cy].data == NULL)
+ ctx->s->write_list[s->cy].data = xmalloc(screen_size_x(ctx->s));
+ ctx->s->write_list[s->cy].data[s->cx + ci->used++] = gc->data.data[0];
}
/* Write cell data. */
@@ -1411,11 +1630,11 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc)
/* If the width is zero, combine onto the previous character. */
if (width == 0) {
- screen_write_collect_flush(ctx, 0);
+ screen_write_collect_flush(ctx, 0, __func__);
if ((gc = screen_write_combine(ctx, &gc->data, &xx)) != 0) {
cx = s->cx; cy = s->cy;
screen_write_set_cursor(ctx, xx, s->cy);
- screen_write_initctx(ctx, &ttyctx);
+ screen_write_initctx(ctx, &ttyctx, 0);
ttyctx.cell = gc;
tty_write(tty_cmd_cell, &ttyctx);
s->cx = cx; s->cy = cy;
@@ -1424,7 +1643,7 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc)
}
/* Flush any existing scrolling. */
- screen_write_collect_flush(ctx, 1);
+ screen_write_collect_flush(ctx, 1, __func__);
/* If this character doesn't fit, ignore it. */
if ((~s->mode & MODE_WRAP) &&
@@ -1443,13 +1662,13 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc)
log_debug("%s: wrapped at %u,%u", __func__, s->cx, s->cy);
screen_write_linefeed(ctx, 1, 8);
screen_write_set_cursor(ctx, 0, -1);
- screen_write_collect_flush(ctx, 1);
+ screen_write_collect_flush(ctx, 1, __func__);
}
/* Sanity check cursor position. */
if (s->cx > sx - width || s->cy > sy - 1)
return;
- screen_write_initctx(ctx, &ttyctx);
+ screen_write_initctx(ctx, &ttyctx, 0);
/* Handle overwriting of UTF-8 characters. */
gl = grid_get_line(s->grid, s->grid->hsize + s->cy);
@@ -1521,7 +1740,7 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc)
/* Create space for character in insert mode. */
if (s->mode & MODE_INSERT) {
- screen_write_collect_flush(ctx, 0);
+ screen_write_collect_flush(ctx, 0, __func__);
ttyctx.num = width;
tty_write(tty_cmd_insertcharacter, &ttyctx);
}
@@ -1652,7 +1871,7 @@ screen_write_setselection(struct screen_write_ctx *ctx, u_char *str, u_int len)
{
struct tty_ctx ttyctx;
- screen_write_initctx(ctx, &ttyctx);
+ screen_write_initctx(ctx, &ttyctx, 0);
ttyctx.ptr = str;
ttyctx.num = len;
@@ -1665,9 +1884,41 @@ screen_write_rawstring(struct screen_write_ctx *ctx, u_char *str, u_int len)
{
struct tty_ctx ttyctx;
- screen_write_initctx(ctx, &ttyctx);
+ screen_write_initctx(ctx, &ttyctx, 0);
ttyctx.ptr = str;
ttyctx.num = len;
tty_write(tty_cmd_rawstring, &ttyctx);
}
+
+/* Turn alternate screen on. */
+void
+screen_write_alternateon(struct screen_write_ctx *ctx, struct grid_cell *gc,
+ int cursor)
+{
+ struct tty_ctx ttyctx;
+ struct window_pane *wp = ctx->wp;
+
+ if (wp != NULL && !options_get_number(wp->options, "alternate-screen"))
+ return;
+ screen_alternate_on(ctx->s, gc, cursor);
+
+ screen_write_initctx(ctx, &ttyctx, 1);
+ ttyctx.redraw_cb(&ttyctx);
+}
+
+/* Turn alternate screen off. */
+void
+screen_write_alternateoff(struct screen_write_ctx *ctx, struct grid_cell *gc,
+ int cursor)
+{
+ struct tty_ctx ttyctx;
+ struct window_pane *wp = ctx->wp;
+
+ if (wp != NULL && !options_get_number(wp->options, "alternate-screen"))
+ return;
+ screen_alternate_off(ctx->s, gc, cursor);
+
+ screen_write_initctx(ctx, &ttyctx, 1);
+ ttyctx.redraw_cb(&ttyctx);
+}
diff --git a/screen.c b/screen.c
index fafb3456..dbd418a1 100644
--- a/screen.c
+++ b/screen.c
@@ -47,9 +47,8 @@ struct screen_title_entry {
};
TAILQ_HEAD(screen_titles, screen_title_entry);
-static void screen_resize_y(struct screen *, u_int);
-
-static void screen_reflow(struct screen *, u_int);
+static void screen_resize_y(struct screen *, u_int, int, u_int *);
+static void screen_reflow(struct screen *, u_int, u_int *, u_int *);
/* Free titles stack. */
static void
@@ -75,6 +74,8 @@ void
screen_init(struct screen *s, u_int sx, u_int sy, u_int hlimit)
{
s->grid = grid_create(sx, sy, hlimit);
+ s->saved_grid = NULL;
+
s->title = xstrdup("");
s->titles = NULL;
@@ -83,6 +84,8 @@ screen_init(struct screen *s, u_int sx, u_int sy, u_int hlimit)
s->tabs = NULL;
s->sel = NULL;
+ s->write_list = NULL;
+
screen_reinit(s);
}
@@ -98,6 +101,11 @@ screen_reinit(struct screen *s)
s->mode = MODE_CURSOR | MODE_WRAP;
+ if (s->saved_grid != NULL)
+ screen_alternate_off(s, NULL, 0);
+ s->saved_cx = UINT_MAX;
+ s->saved_cy = UINT_MAX;
+
screen_reset_tabs(s);
grid_clear_lines(s->grid, s->grid->hsize, s->grid->sy, 8);
@@ -115,6 +123,11 @@ screen_free(struct screen *s)
free(s->title);
free(s->ccolour);
+ if (s->write_list != NULL)
+ screen_write_free_list(s);
+
+ if (s->saved_grid != NULL)
+ grid_destroy(s->saved_grid);
grid_destroy(s->grid);
screen_free_titles(s);
@@ -206,10 +219,28 @@ screen_pop_title(struct screen *s)
}
}
-/* Resize screen. */
+/* Resize screen and return cursor position. */
void
-screen_resize(struct screen *s, u_int sx, u_int sy, int reflow)
+screen_resize_cursor(struct screen *s, u_int sx, u_int sy, int reflow,
+ int eat_empty, u_int *cx, u_int *cy)
{
+ u_int tcx, tcy;
+
+ if (s->write_list != NULL)
+ screen_write_free_list(s);
+
+ if (cx == NULL)
+ cx = &tcx;
+ *cx = s->cx;
+
+ if (cy == NULL)
+ cy = &tcy;
+ *cy = s->grid->hsize + s->cy;
+
+ log_debug("%s: new size %ux%u, now %ux%u (cursor %u,%u = %u,%u)",
+ __func__, sx, sy, screen_size_x(s), screen_size_y(s), s->cx, s->cy,
+ *cx, *cy);
+
if (sx < 1)
sx = 1;
if (sy < 1)
@@ -222,14 +253,34 @@ screen_resize(struct screen *s, u_int sx, u_int sy, int reflow)
reflow = 0;
if (sy != screen_size_y(s))
- screen_resize_y(s, sy);
+ screen_resize_y(s, sy, eat_empty, cy);
if (reflow)
- screen_reflow(s, sx);
+ screen_reflow(s, sx, cx, cy);
+
+ if (*cy >= s->grid->hsize) {
+ s->cx = *cx;
+ s->cy = (*cy) - s->grid->hsize;
+ } else {
+ s->cx = 0;
+ s->cy = 0;
+ }
+ log_debug("%s: cursor finished at %u,%u = %u,%u", __func__, s->cx,
+ s->cy, *cx, *cy);
+
+ if (s->write_list != NULL)
+ screen_write_make_list(s);
+}
+
+/* Resize screen. */
+void
+screen_resize(struct screen *s, u_int sx, u_int sy, int reflow)
+{
+ screen_resize_cursor(s, sx, sy, reflow, 1, NULL, NULL);
}
static void
-screen_resize_y(struct screen *s, u_int sy)
+screen_resize_y(struct screen *s, u_int sy, int eat_empty, u_int *cy)
{
struct grid *gd = s->grid;
u_int needed, available, oldy, i;
@@ -254,14 +305,16 @@ screen_resize_y(struct screen *s, u_int sy)
needed = oldy - sy;
/* 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,
- 8);
+ if (eat_empty) {
+ available = oldy - 1 - s->cy;
+ if (available > 0) {
+ if (available > needed)
+ available = needed;
+ grid_view_delete_lines(gd, oldy - available,
+ available, 8);
+ }
+ needed -= available;
}
- needed -= available;
/*
* Now just increase the history size, if possible, to take
@@ -276,8 +329,8 @@ screen_resize_y(struct screen *s, u_int sy)
if (available > needed)
available = needed;
grid_view_delete_lines(gd, 0, available, 8);
+ (*cy) -= available;
}
- s->cy -= needed;
}
/* Resize line array. */
@@ -297,14 +350,13 @@ screen_resize_y(struct screen *s, u_int sy)
available = needed;
gd->hscrolled -= available;
gd->hsize -= available;
- s->cy += available;
} else
available = 0;
needed -= available;
/* Then fill the rest in with blanks. */
for (i = gd->hsize + sy - needed; i < gd->hsize + sy; i++)
- memset(grid_get_line(gd, i), 0, sizeof(struct grid_line));
+ grid_empty_line(gd, i, 8);
}
/* Set the new size, and reset the scroll region. */
@@ -472,32 +524,92 @@ screen_select_cell(struct screen *s, struct grid_cell *dst,
/* Reflow wrapped lines. */
static void
-screen_reflow(struct screen *s, u_int new_x)
+screen_reflow(struct screen *s, u_int new_x, u_int *cx, u_int *cy)
{
- u_int cx = s->cx, cy = s->grid->hsize + s->cy, wx, wy;
- struct timeval start, tv;
-
- gettimeofday(&start, NULL);
+ u_int wx, wy;
- grid_wrap_position(s->grid, cx, cy, &wx, &wy);
- log_debug("%s: cursor %u,%u is %u,%u", __func__, cx, cy, wx, wy);
+ grid_wrap_position(s->grid, *cx, *cy, &wx, &wy);
+ log_debug("%s: cursor %u,%u is %u,%u", __func__, *cx, *cy, wx, wy);
grid_reflow(s->grid, new_x);
- grid_unwrap_position(s->grid, &cx, &cy, wx, wy);
- log_debug("%s: new cursor is %u,%u", __func__, cx, cy);
+ grid_unwrap_position(s->grid, cx, cy, wx, wy);
+ log_debug("%s: new cursor is %u,%u", __func__, *cx,* cy);
+}
- if (cy >= s->grid->hsize) {
- s->cx = cx;
- s->cy = cy - s->grid->hsize;
- } else {
- s->cx = 0;
- s->cy = 0;
+/*
+ * Enter alternative screen mode. A copy of the visible screen is saved and the
+ * history is not updated.
+ */
+void
+screen_alternate_on(struct screen *s, struct grid_cell *gc, int cursor)
+{
+ u_int sx, sy;
+
+ if (s->saved_grid != NULL)
+ return;
+ sx = screen_size_x(s);
+ sy = screen_size_y(s);
+
+ s->saved_grid = grid_create(sx, sy, 0);
+ grid_duplicate_lines(s->saved_grid, 0, s->grid, screen_hsize(s), sy);
+ if (cursor) {
+ s->saved_cx = s->cx;
+ s->saved_cy = s->cy;
+ }
+ memcpy(&s->saved_cell, gc, sizeof s->saved_cell);
+
+ grid_view_clear(s->grid, 0, 0, sx, sy, 8);
+
+ s->saved_flags = s->grid->flags;
+ s->grid->flags &= ~GRID_HISTORY;
+}
+
+/* Exit alternate screen mode and restore the copied grid. */
+void
+screen_alternate_off(struct screen *s, struct grid_cell *gc, int cursor)
+{
+ u_int sx, sy;
+
+ /*
+ * Restore the cursor position and cell. This happens even if not
+ * currently in the alternate screen.
+ */
+ if (cursor && s->saved_cx != UINT_MAX && s->saved_cy != UINT_MAX) {
+ s->cx = s->saved_cx;
+ if (s->cx > screen_size_x(s) - 1)
+ s->cx = screen_size_x(s) - 1;
+ s->cy = s->saved_cy;
+ if (s->cy > screen_size_y(s) - 1)
+ s->cy = screen_size_y(s) - 1;
+ if (gc != NULL)
+ memcpy(gc, &s->saved_cell, sizeof *gc);
}
- gettimeofday(&tv, NULL);
- timersub(&tv, &start, &tv);
+ if (s->saved_grid == NULL)
+ 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 > s->saved_grid->sy)
+ screen_resize(s, sx, s->saved_grid->sy, 1);
+
+ /* Restore the saved grid. */
+ grid_duplicate_lines(s->grid, screen_hsize(s), s->saved_grid, 0, sy);
+
+ /*
+ * Turn history back on (so resize can use it) and then resize back to
+ * the current size.
+ */
+ if (s->saved_flags & GRID_HISTORY)
+ s->grid->flags |= GRID_HISTORY;
+ if (sy > s->saved_grid->sy || sx != s->saved_grid->sx)
+ screen_resize(s, sx, sy, 1);
- log_debug("%s: reflow took %llu.%06u seconds", __func__,
- (unsigned long long)tv.tv_sec, (u_int)tv.tv_usec);
+ grid_destroy(s->saved_grid);
+ s->saved_grid = NULL;
}
diff --git a/server-client.c b/server-client.c
index fe72317a..a9762c56 100644
--- a/server-client.c
+++ b/server-client.c
@@ -41,7 +41,6 @@ static void server_client_check_redraw(struct client *);
static void server_client_set_title(struct client *);
static void server_client_reset_state(struct client *);
static int server_client_assume_paste(struct session *);
-static void server_client_clear_overlay(struct client *);
static void server_client_resize_event(int, short, void *);
static void server_client_dispatch(struct imsg *, void *);
@@ -79,8 +78,10 @@ server_client_overlay_timer(__unused int fd, __unused short events, void *data)
/* Set an overlay on client. */
void
-server_client_set_overlay(struct client *c, u_int delay, overlay_draw_cb drawcb,
- overlay_key_cb keycb, overlay_free_cb freecb, void *data)
+server_client_set_overlay(struct client *c, u_int delay,
+ overlay_check_cb checkcb, overlay_mode_cb modecb,
+ overlay_draw_cb drawcb, overlay_key_cb keycb, overlay_free_cb freecb,
+ void *data)
{
struct timeval tv;
@@ -96,17 +97,21 @@ server_client_set_overlay(struct client *c, u_int delay, overlay_draw_cb drawcb,
if (delay != 0)
evtimer_add(&c->overlay_timer, &tv);
+ c->overlay_check = checkcb;
+ c->overlay_mode = modecb;
c->overlay_draw = drawcb;
c->overlay_key = keycb;
c->overlay_free = freecb;
c->overlay_data = data;
- c->tty.flags |= (TTY_FREEZE|TTY_NOCURSOR);
+ c->tty.flags |= TTY_FREEZE;
+ if (c->overlay_mode == NULL)
+ c->tty.flags |= TTY_NOCURSOR;
server_redraw_client(c);
}
/* Clear overlay mode on client. */
-static void
+void
server_client_clear_overlay(struct client *c)
{
if (c->overlay_draw == NULL)
@@ -118,8 +123,12 @@ server_client_clear_overlay(struct client *c)
if (c->overlay_free != NULL)
c->overlay_free(c);
+ c->overlay_check = NULL;
+ c->overlay_mode = NULL;
c->overlay_draw = NULL;
c->overlay_key = NULL;
+ c->overlay_free = NULL;
+ c->overlay_data = NULL;
c->tty.flags &= ~(TTY_FREEZE|TTY_NOCURSOR);
server_redraw_client(c);
@@ -199,7 +208,7 @@ server_client_create(int fd)
c->fd = -1;
c->cwd = NULL;
- TAILQ_INIT(&c->queue);
+ c->queue = cmdq_new();
c->tty.fd = -1;
c->title = NULL;
@@ -285,7 +294,9 @@ server_client_lost(struct client *c)
if (c->flags & CLIENT_TERMINAL)
tty_free(&c->tty);
free(c->ttyname);
- free(c->term);
+
+ free(c->term_name);
+ free(c->term_type);
status_free(c);
@@ -344,8 +355,7 @@ server_client_free(__unused int fd, __unused short events, void *arg)
log_debug("free client %p (%d references)", c, c->references);
- if (!TAILQ_EMPTY(&c->queue))
- fatalx("queue not empty");
+ cmdq_free(c->queue);
if (c->references == 0) {
free((void *)c->name);
@@ -398,6 +408,8 @@ server_client_exec(struct client *c, const char *cmd)
shell = options_get_string(s->options, "default-shell");
else
shell = options_get_string(global_s_options, "default-shell");
+ if (!checkshell(shell))
+ shell = _PATH_BSHELL;
shellsize = strlen(shell) + 1;
msg = xmalloc(cmdsize + shellsize);
@@ -417,7 +429,7 @@ server_client_check_mouse(struct client *c, struct key_event *event)
struct winlink *wl;
struct window_pane *wp;
u_int x, y, b, sx, sy, px, py;
- int flag;
+ int ignore = 0;
key_code key;
struct timeval tv;
struct style_range *sr;
@@ -427,6 +439,7 @@ server_client_check_mouse(struct client *c, struct key_event *event)
UP,
DRAG,
WHEEL,
+ SECOND,
DOUBLE,
TRIPLE } type = NOTYPE;
enum { NOWHERE,
@@ -441,7 +454,12 @@ server_client_check_mouse(struct client *c, struct key_event *event)
m->x, m->y, m->lx, m->ly, c->tty.mouse_drag_flag);
/* What type of event is this? */
- if ((m->sgr_type != ' ' &&
+ if (event->key == KEYC_DOUBLECLICK) {
+ type = DOUBLE;
+ x = m->x, y = m->y, b = m->b;
+ ignore = 1;
+ log_debug("double-click at %u,%u", x, y);
+ } else if ((m->sgr_type != ' ' &&
MOUSE_DRAG(m->sgr_b) &&
MOUSE_BUTTONS(m->sgr_b) == 3) ||
(m->sgr_type == ' ' &&
@@ -475,11 +493,10 @@ server_client_check_mouse(struct client *c, struct key_event *event)
evtimer_del(&c->click_timer);
c->flags &= ~CLIENT_DOUBLECLICK;
if (m->b == c->click_button) {
- type = DOUBLE;
+ type = SECOND;
x = m->x, y = m->y, b = m->b;
- log_debug("double-click at %u,%u", x, y);
- flag = CLIENT_TRIPLECLICK;
- goto add_timer;
+ log_debug("second-click at %u,%u", x, y);
+ c->flags |= CLIENT_TRIPLECLICK;
}
} else if (c->flags & CLIENT_TRIPLECLICK) {
evtimer_del(&c->click_timer);
@@ -490,18 +507,18 @@ server_client_check_mouse(struct client *c, struct key_event *event)
log_debug("triple-click at %u,%u", x, y);
goto have_event;
}
+ } else {
+ type = DOWN;
+ x = m->x, y = m->y, b = m->b;
+ log_debug("down at %u,%u", x, y);
+ c->flags |= CLIENT_DOUBLECLICK;
}
- type = DOWN;
- x = m->x, y = m->y, b = m->b;
- log_debug("down at %u,%u", x, y);
- flag = CLIENT_DOUBLECLICK;
-
- add_timer:
if (KEYC_CLICK_TIMEOUT != 0) {
- c->flags |= flag;
+ memcpy(&c->click_event, m, sizeof c->click_event);
c->click_button = m->b;
+ log_debug("click timer started");
tv.tv_sec = KEYC_CLICK_TIMEOUT / 1000;
tv.tv_usec = (KEYC_CLICK_TIMEOUT % 1000) * 1000L;
evtimer_del(&c->click_timer);
@@ -516,6 +533,7 @@ have_event:
/* Save the session. */
m->s = s->id;
m->w = -1;
+ m->ignore = ignore;
/* Is this on the status line? */
m->statusat = status_at_line(c);
@@ -587,10 +605,9 @@ have_event:
wp = window_get_active_at(s->curw->window, px, py);
if (wp != NULL)
where = PANE;
+ else
+ return (KEYC_UNKNOWN);
}
-
- if (where == NOWHERE)
- return (KEYC_UNKNOWN);
if (where == PANE)
log_debug("mouse %u,%u on pane %%%u", x, y, wp->id);
else if (where == BORDER)
@@ -859,6 +876,52 @@ have_event:
break;
}
break;
+ case SECOND:
+ switch (MOUSE_BUTTONS(b)) {
+ case 0:
+ if (where == PANE)
+ key = KEYC_SECONDCLICK1_PANE;
+ if (where == STATUS)
+ key = KEYC_SECONDCLICK1_STATUS;
+ if (where == STATUS_LEFT)
+ key = KEYC_SECONDCLICK1_STATUS_LEFT;
+ if (where == STATUS_RIGHT)
+ key = KEYC_SECONDCLICK1_STATUS_RIGHT;
+ if (where == STATUS_DEFAULT)
+ key = KEYC_SECONDCLICK1_STATUS_DEFAULT;
+ if (where == BORDER)
+ key = KEYC_SECONDCLICK1_BORDER;
+ break;
+ case 1:
+ if (where == PANE)
+ key = KEYC_SECONDCLICK2_PANE;
+ if (where == STATUS)
+ key = KEYC_SECONDCLICK2_STATUS;
+ if (where == STATUS_LEFT)
+ key = KEYC_SECONDCLICK2_STATUS_LEFT;
+ if (where == STATUS_RIGHT)
+ key = KEYC_SECONDCLICK2_STATUS_RIGHT;
+ if (where == STATUS_DEFAULT)
+ key = KEYC_SECONDCLICK2_STATUS_DEFAULT;
+ if (where == BORDER)
+ key = KEYC_SECONDCLICK2_BORDER;
+ break;
+ case 2:
+ if (where == PANE)
+ key = KEYC_SECONDCLICK3_PANE;
+ if (where == STATUS)
+ key = KEYC_SECONDCLICK3_STATUS;
+ if (where == STATUS_LEFT)
+ key = KEYC_SECONDCLICK3_STATUS_LEFT;
+ if (where == STATUS_RIGHT)
+ key = KEYC_SECONDCLICK3_STATUS_RIGHT;
+ if (where == STATUS_DEFAULT)
+ key = KEYC_SECONDCLICK3_STATUS_DEFAULT;
+ if (where == BORDER)
+ key = KEYC_SECONDCLICK3_BORDER;
+ break;
+ }
+ break;
case DOUBLE:
switch (MOUSE_BUTTONS(b)) {
case 0:
@@ -1018,7 +1081,7 @@ server_client_update_latest(struct client *c)
static enum cmd_retval
server_client_key_callback(struct cmdq_item *item, void *data)
{
- struct client *c = item->client;
+ struct client *c = cmdq_get_client(item);
struct key_event *event = data;
key_code key = event->key;
struct mouse_event *m = &event->m;
@@ -1045,7 +1108,7 @@ server_client_key_callback(struct cmdq_item *item, void *data)
/* Check for mouse keys. */
m->valid = 0;
- if (key == KEYC_MOUSE) {
+ if (key == KEYC_MOUSE || key == KEYC_DOUBLECLICK) {
if (c->flags & CLIENT_READONLY)
goto out;
key = server_client_check_mouse(c, event);
@@ -1160,7 +1223,7 @@ try_again:
server_status_client(c);
/* Execute the key binding. */
- key_bindings_dispatch(bd, item, c, m, &fs);
+ key_bindings_dispatch(bd, item, c, event, &fs);
key_bindings_unref_table(table);
goto out;
}
@@ -1231,10 +1294,6 @@ server_client_handle_key(struct client *c, struct key_event *event)
*/
if (~c->flags & CLIENT_READONLY) {
status_message_clear(c);
- if (c->prompt_string != NULL) {
- if (status_prompt_key(c, event->key) == 0)
- return (0);
- }
if (c->overlay_key != NULL) {
switch (c->overlay_key(c, event)) {
case 0:
@@ -1245,6 +1304,10 @@ server_client_handle_key(struct client *c, struct key_event *event)
}
}
server_client_clear_overlay(c);
+ if (c->prompt_string != NULL) {
+ if (status_prompt_key(c, event->key) == 0)
+ return (0);
+ }
}
/*
@@ -1382,7 +1445,7 @@ server_client_resize_event(__unused int fd, __unused short events, void *data)
log_debug("%s: %%%u timer fired (was%s resized)", __func__, wp->id,
(wp->flags & PANE_RESIZED) ? "" : " not");
- if (wp->saved_grid == NULL && (wp->flags & PANE_RESIZED)) {
+ if (wp->base.saved_grid == NULL && (wp->flags & PANE_RESIZED)) {
log_debug("%s: %%%u deferring timer", __func__, wp->id);
server_client_start_resize_timer(wp);
} else if (!server_client_resize_force(wp)) {
@@ -1474,38 +1537,56 @@ focused:
static void
server_client_reset_state(struct client *c)
{
+ struct tty *tty = &c->tty;
struct window *w = c->session->curw->window;
struct window_pane *wp = w->active, *loop;
- struct screen *s = wp->screen;
+ struct screen *s = NULL;
struct options *oo = c->session->options;
- int mode, cursor = 0;
+ int mode = 0, cursor, flags;
u_int cx = 0, cy = 0, ox, oy, sx, sy;
if (c->flags & (CLIENT_CONTROL|CLIENT_SUSPENDED))
return;
- if (c->overlay_draw != NULL)
- return;
- mode = s->mode;
- tty_region_off(&c->tty);
- tty_margin_off(&c->tty);
+ /* Disable the block flag. */
+ flags = (tty->flags & TTY_BLOCK);
+ tty->flags &= ~TTY_BLOCK;
- /* Move cursor to pane cursor and offset. */
- cursor = 0;
- tty_window_offset(&c->tty, &ox, &oy, &sx, &sy);
- if (wp->xoff + s->cx >= ox && wp->xoff + s->cx <= ox + sx &&
- wp->yoff + s->cy >= oy && wp->yoff + s->cy <= oy + sy) {
- cursor = 1;
+ /* Get mode from overlay if any, else from screen. */
+ if (c->overlay_draw != NULL) {
+ if (c->overlay_mode != NULL)
+ s = c->overlay_mode(c, &cx, &cy);
+ } else
+ s = wp->screen;
+ if (s != NULL)
+ mode = s->mode;
+ if (c->prompt_string != NULL || c->message_string != NULL)
+ mode &= ~MODE_CURSOR;
+ log_debug("%s: client %s mode %x", __func__, c->name, mode);
- cx = wp->xoff + s->cx - ox;
- cy = wp->yoff + s->cy - oy;
+ /* Reset region and margin. */
+ tty_region_off(tty);
+ tty_margin_off(tty);
- if (status_at_line(c) == 0)
- cy += status_line_size(c);
+ /* Move cursor to pane cursor and offset. */
+ if (c->overlay_draw == NULL) {
+ cursor = 0;
+ tty_window_offset(tty, &ox, &oy, &sx, &sy);
+ if (wp->xoff + s->cx >= ox && wp->xoff + s->cx <= ox + sx &&
+ wp->yoff + s->cy >= oy && wp->yoff + s->cy <= oy + sy) {
+ cursor = 1;
+
+ cx = wp->xoff + s->cx - ox;
+ cy = wp->yoff + s->cy - oy;
+
+ if (status_at_line(c) == 0)
+ cy += status_line_size(c);
+ }
+ if (!cursor)
+ mode &= ~MODE_CURSOR;
}
- if (!cursor)
- mode &= ~MODE_CURSOR;
- tty_cursor(&c->tty, cx, cy);
+ log_debug("%s: cursor to %u,%u", __func__, cx, cy);
+ tty_cursor(tty, cx, cy);
/*
* Set mouse mode if requested. To support dragging, always use button
@@ -1513,21 +1594,27 @@ server_client_reset_state(struct client *c)
*/
if (options_get_number(oo, "mouse")) {
mode &= ~ALL_MOUSE_MODES;
- TAILQ_FOREACH(loop, &w->panes, entry) {
- if (loop->screen->mode & MODE_MOUSE_ALL)
- mode |= MODE_MOUSE_ALL;
+ if (c->overlay_draw == NULL) {
+ TAILQ_FOREACH(loop, &w->panes, entry) {
+ if (loop->screen->mode & MODE_MOUSE_ALL)
+ mode |= MODE_MOUSE_ALL;
+ }
}
if (~mode & MODE_MOUSE_ALL)
mode |= MODE_MOUSE_BUTTON;
}
/* Clear bracketed paste mode if at the prompt. */
- if (c->prompt_string != NULL)
+ if (c->overlay_draw == NULL && c->prompt_string != NULL)
mode &= ~MODE_BRACKETPASTE;
/* Set the terminal mode and reset attributes. */
- tty_update_mode(&c->tty, mode, s);
- tty_reset(&c->tty);
+ tty_update_mode(tty, mode, s);
+ tty_reset(tty);
+
+ /* All writing must be done, send a sync end (if it was started). */
+ tty_sync_end(tty);
+ tty->flags |= flags;
}
/* Repeat time callback. */
@@ -1547,8 +1634,22 @@ server_client_repeat_timer(__unused int fd, __unused short events, void *data)
static void
server_client_click_timer(__unused int fd, __unused short events, void *data)
{
- struct client *c = data;
+ struct client *c = data;
+ struct key_event *event;
+ log_debug("click timer expired");
+
+ if (c->flags & CLIENT_TRIPLECLICK) {
+ /*
+ * Waiting for a third click that hasn't happened, so this must
+ * have been a double click.
+ */
+ event = xmalloc(sizeof *event);
+ event->key = KEYC_DOUBLECLICK;
+ memcpy(&event->m, &c->click_event, sizeof event->m);
+ if (!server_client_handle_key(c, event))
+ free(event);
+ }
c->flags &= ~(CLIENT_DOUBLECLICK|CLIENT_TRIPLECLICK);
}
@@ -1588,8 +1689,11 @@ server_client_check_redraw(struct client *c)
{
struct session *s = c->session;
struct tty *tty = &c->tty;
+ struct window *w = c->session->curw->window;
struct window_pane *wp;
- int needed, flags;
+ int needed, flags, mode = tty->mode, new_flags = 0;
+ int redraw;
+ u_int bit = 0;
struct timeval tv = { .tv_usec = 1000 };
static struct event ev;
size_t left;
@@ -1597,11 +1701,12 @@ server_client_check_redraw(struct client *c)
if (c->flags & (CLIENT_CONTROL|CLIENT_SUSPENDED))
return;
if (c->flags & CLIENT_ALLREDRAWFLAGS) {
- log_debug("%s: redraw%s%s%s%s", c->name,
+ log_debug("%s: redraw%s%s%s%s%s", c->name,
(c->flags & CLIENT_REDRAWWINDOW) ? " window" : "",
(c->flags & CLIENT_REDRAWSTATUS) ? " status" : "",
(c->flags & CLIENT_REDRAWBORDERS) ? " borders" : "",
- (c->flags & CLIENT_REDRAWOVERLAY) ? " overlay" : "");
+ (c->flags & CLIENT_REDRAWOVERLAY) ? " overlay" : "",
+ (c->flags & CLIENT_REDRAWPANES) ? " panes" : "");
}
/*
@@ -1613,12 +1718,14 @@ server_client_check_redraw(struct client *c)
if (c->flags & CLIENT_ALLREDRAWFLAGS)
needed = 1;
else {
- TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry) {
+ TAILQ_FOREACH(wp, &w->panes, entry) {
if (wp->flags & PANE_REDRAW) {
needed = 1;
break;
}
}
+ if (needed)
+ new_flags |= CLIENT_REDRAWPANES;
}
if (needed && (left = EVBUFFER_LENGTH(tty->out)) != 0) {
log_debug("%s: redraw deferred (%zu left)", c->name, left);
@@ -1629,29 +1736,53 @@ server_client_check_redraw(struct client *c)
evtimer_add(&ev, &tv);
}
- /*
- * We may have got here for a single pane redraw, but force a
- * full redraw next time in case other panes have been updated.
- */
- c->flags |= CLIENT_ALLREDRAWFLAGS;
+ if (~c->flags & CLIENT_REDRAWWINDOW) {
+ TAILQ_FOREACH(wp, &w->panes, entry) {
+ if (wp->flags & PANE_REDRAW) {
+ log_debug("%s: pane %%%u needs redraw",
+ c->name, wp->id);
+ c->redraw_panes |= (1 << bit);
+ }
+ if (++bit == 64) {
+ /*
+ * If more that 64 panes, give up and
+ * just redraw the window.
+ */
+ new_flags &= CLIENT_REDRAWPANES;
+ new_flags |= CLIENT_REDRAWWINDOW;
+ break;
+ }
+ }
+ if (c->redraw_panes != 0)
+ c->flags |= CLIENT_REDRAWPANES;
+ }
+ c->flags |= new_flags;
return;
} else if (needed)
log_debug("%s: redraw needed", c->name);
flags = tty->flags & (TTY_BLOCK|TTY_FREEZE|TTY_NOCURSOR);
- tty->flags = (tty->flags & ~(TTY_BLOCK|TTY_FREEZE)) | TTY_NOCURSOR;
+ tty->flags = (tty->flags & ~(TTY_BLOCK|TTY_FREEZE))|TTY_NOCURSOR;
if (~c->flags & CLIENT_REDRAWWINDOW) {
/*
* If not redrawing the entire window, check whether each pane
* needs to be redrawn.
*/
- TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry) {
- if (wp->flags & PANE_REDRAW) {
- tty_update_mode(tty, tty->mode, NULL);
- screen_redraw_pane(c, wp);
- }
+ TAILQ_FOREACH(wp, &w->panes, entry) {
+ redraw = 0;
+ if (wp->flags & PANE_REDRAW)
+ redraw = 1;
+ else if (c->flags & CLIENT_REDRAWPANES)
+ redraw = !!(c->redraw_panes & (1 << bit));
+ bit++;
+ if (!redraw)
+ continue;
+ log_debug("%s: redrawing pane %%%u", __func__, wp->id);
+ screen_redraw_pane(c, wp);
}
+ c->redraw_panes = 0;
+ c->flags &= ~CLIENT_REDRAWPANES;
}
if (c->flags & CLIENT_ALLREDRAWFLAGS) {
@@ -1660,8 +1791,9 @@ server_client_check_redraw(struct client *c)
screen_redraw_screen(c);
}
- tty->flags = (tty->flags & ~(TTY_FREEZE|TTY_NOCURSOR)) | flags;
- tty_update_mode(tty, tty->mode, NULL);
+ tty->flags = (tty->flags & ~TTY_NOCURSOR)|(flags & TTY_NOCURSOR);
+ tty_update_mode(tty, mode, NULL);
+ tty->flags = (tty->flags & ~(TTY_BLOCK|TTY_FREEZE|TTY_NOCURSOR))|flags;
c->flags &= ~(CLIENT_ALLREDRAWFLAGS|CLIENT_STATUSFORCE);
@@ -1720,6 +1852,7 @@ server_client_dispatch(struct imsg *imsg, void *arg)
datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
switch (imsg->hdr.type) {
+ case MSG_IDENTIFY_FEATURES:
case MSG_IDENTIFY_FLAGS:
case MSG_IDENTIFY_TERM:
case MSG_IDENTIFY_TTYNAME:
@@ -1800,10 +1933,12 @@ server_client_dispatch(struct imsg *imsg, void *arg)
static enum cmd_retval
server_client_command_done(struct cmdq_item *item, __unused void *data)
{
- struct client *c = item->client;
+ struct client *c = cmdq_get_client(item);
if (~c->flags & CLIENT_ATTACHED)
c->flags |= CLIENT_EXIT;
+ else if (~c->flags & CLIENT_DETACHING)
+ tty_send_requests(&c->tty);
return (CMD_RETURN_NORMAL);
}
@@ -1855,7 +1990,7 @@ server_client_dispatch_command(struct client *c, struct imsg *imsg)
}
cmd_free_argv(argc, argv);
- cmdq_append(c, cmdq_get_command(pr->cmdlist, NULL, NULL, 0));
+ cmdq_append(c, cmdq_get_command(pr->cmdlist, NULL));
cmdq_append(c, cmdq_get_callback(server_client_command_done, NULL));
cmd_list_free(pr->cmdlist);
@@ -1876,7 +2011,7 @@ server_client_dispatch_identify(struct client *c, struct imsg *imsg)
{
const char *data, *home;
size_t datalen;
- int flags;
+ int flags, feat;
char *name;
if (c->flags & CLIENT_IDENTIFIED)
@@ -1886,6 +2021,14 @@ server_client_dispatch_identify(struct client *c, struct imsg *imsg)
datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
switch (imsg->hdr.type) {
+ case MSG_IDENTIFY_FEATURES:
+ if (datalen != sizeof feat)
+ fatalx("bad MSG_IDENTIFY_FEATURES size");
+ memcpy(&feat, data, sizeof feat);
+ c->term_features |= feat;
+ log_debug("client %p IDENTIFY_FEATURES %s", c,
+ tty_get_features(feat));
+ break;
case MSG_IDENTIFY_FLAGS:
if (datalen != sizeof flags)
fatalx("bad MSG_IDENTIFY_FLAGS size");
@@ -1896,7 +2039,10 @@ server_client_dispatch_identify(struct client *c, struct imsg *imsg)
case MSG_IDENTIFY_TERM:
if (datalen == 0 || data[datalen - 1] != '\0')
fatalx("bad MSG_IDENTIFY_TERM string");
- c->term = xstrdup(data);
+ if (*data == '\0')
+ c->term_name = xstrdup("unknown");
+ else
+ c->term_name = xstrdup(data);
log_debug("client %p IDENTIFY_TERM %s", c, data);
break;
case MSG_IDENTIFY_TTYNAME:
@@ -1926,7 +2072,7 @@ server_client_dispatch_identify(struct client *c, struct imsg *imsg)
if (datalen == 0 || data[datalen - 1] != '\0')
fatalx("bad MSG_IDENTIFY_ENVIRON string");
if (strchr(data, '=') != NULL)
- environ_put(c->environ, data);
+ environ_put(c->environ, data, 0);
log_debug("client %p IDENTIFY_ENVIRON %s", c, data);
break;
case MSG_IDENTIFY_CLIENTPID:
@@ -1961,14 +2107,10 @@ server_client_dispatch_identify(struct client *c, struct imsg *imsg)
control_start(c);
c->tty.fd = -1;
} else if (c->fd != -1) {
- if (tty_init(&c->tty, c, c->fd, c->term) != 0) {
+ if (tty_init(&c->tty, c, c->fd) != 0) {
close(c->fd);
c->fd = -1;
} else {
- if (c->flags & CLIENT_UTF8)
- c->tty.flags |= TTY_UTF8;
- if (c->flags & CLIENT_256COLOURS)
- c->tty.term_flags |= TERM_256COLOURS;
tty_resize(&c->tty);
c->flags |= CLIENT_TERMINAL;
}
@@ -1992,7 +2134,7 @@ server_client_dispatch_shell(struct client *c)
const char *shell;
shell = options_get_string(global_s_options, "default-shell");
- if (*shell == '\0' || areshell(shell))
+ if (!checkshell(shell))
shell = _PATH_BSHELL;
proc_send(c->peer, MSG_SHELL, -1, shell, strlen(shell) + 1);
diff --git a/server-fn.c b/server-fn.c
index 2247f1c5..127afb6b 100644
--- a/server-fn.c
+++ b/server-fn.c
@@ -319,7 +319,7 @@ server_destroy_pane(struct window_pane *wp, int notify)
if (notify)
notify_pane("pane-died", wp);
- screen_write_start(&ctx, wp, &wp->base);
+ screen_write_start_pane(&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, 0);
screen_write_linefeed(&ctx, 1, 8);
@@ -335,8 +335,8 @@ server_destroy_pane(struct window_pane *wp, int notify)
tim);
} else if (WIFSIGNALED(wp->status)) {
screen_write_nputs(&ctx, -1, &gc,
- "Pane is dead (signal %d, %s)",
- WTERMSIG(wp->status),
+ "Pane is dead (signal %s, %s)",
+ sig2name(WTERMSIG(wp->status)),
tim);
}
diff --git a/server.c b/server.c
index a5d5e37f..1077377b 100644
--- a/server.c
+++ b/server.c
@@ -44,6 +44,7 @@ struct clients clients;
struct tmuxproc *server_proc;
static int server_fd = -1;
+static int server_client_flags;
static int server_exit;
static struct event server_ev_accept;
@@ -97,7 +98,7 @@ server_check_marked(void)
/* Create server socket. */
static int
-server_create_socket(char **cause)
+server_create_socket(int flags, char **cause)
{
struct sockaddr_un sa;
size_t size;
@@ -116,7 +117,10 @@ server_create_socket(char **cause)
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
goto fail;
- mask = umask(S_IXUSR|S_IXGRP|S_IRWXO);
+ if (flags & CLIENT_DEFAULTSOCKET)
+ mask = umask(S_IXUSR|S_IXGRP|S_IRWXO);
+ else
+ mask = umask(S_IXUSR|S_IRWXG|S_IRWXO);
if (bind(fd, (struct sockaddr *)&sa, sizeof sa) == -1) {
saved_errno = errno;
close(fd);
@@ -145,8 +149,8 @@ fail:
/* Fork new server. */
int
-server_start(struct tmuxproc *client, struct event_base *base, int lockfd,
- char *lockfile)
+server_start(struct tmuxproc *client, int flags, struct event_base *base,
+ int lockfd, char *lockfile)
{
int pair[2];
sigset_t set, oldset;
@@ -155,6 +159,7 @@ server_start(struct tmuxproc *client, struct event_base *base, int lockfd,
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) != 0)
fatal("socketpair failed");
+ server_client_flags = flags;
sigfillset(&set);
sigprocmask(SIG_BLOCK, &set, &oldset);
@@ -192,7 +197,7 @@ server_start(struct tmuxproc *client, struct event_base *base, int lockfd,
gettimeofday(&start_time, NULL);
- server_fd = server_create_socket(&cause);
+ server_fd = server_create_socket(flags, &cause);
if (server_fd != -1)
server_update_socket();
c = server_client_create(pair[1]);
@@ -395,7 +400,7 @@ server_signal(int sig)
break;
case SIGUSR1:
event_del(&server_ev_accept);
- fd = server_create_socket(NULL);
+ fd = server_create_socket(server_client_flags, NULL);
if (fd != -1) {
close(server_fd);
server_fd = fd;
@@ -475,4 +480,5 @@ server_child_stopped(pid_t pid, int status)
}
}
}
+ job_check_died(pid, status);
}
diff --git a/session.c b/session.c
index eddafa2c..87c5b83c 100644
--- a/session.c
+++ b/session.c
@@ -122,7 +122,6 @@ session_create(const char *prefix, const char *name, const char *cwd,
s->cwd = xstrdup(cwd);
- s->curw = NULL;
TAILQ_INIT(&s->lastw);
RB_INIT(&s->windows);
@@ -141,7 +140,6 @@ session_create(const char *prefix, const char *name, const char *cwd,
s->name = xstrdup(name);
s->id = next_session_id++;
} else {
- s->name = NULL;
do {
s->id = next_session_id++;
free(s->name);
@@ -231,11 +229,20 @@ session_destroy(struct session *s, int notify, const char *from)
session_remove_ref(s, __func__);
}
-/* Check a session name is valid: not empty and no colons or periods. */
-int
+/* Sanitize session name. */
+char *
session_check_name(const char *name)
{
- return (*name != '\0' && name[strcspn(name, ":.")] == '\0');
+ char *copy, *cp, *new_name;
+
+ copy = xstrdup(name);
+ for (cp = copy; *cp != '\0'; cp++) {
+ if (*cp == ':' || *cp == '.')
+ *cp = '_';
+ }
+ utf8_stravis(&new_name, copy, VIS_OCTAL|VIS_CSTYLE|VIS_TAB|VIS_NL);
+ free(copy);
+ return (new_name);
}
/* Lock session if it has timed out. */
@@ -555,6 +562,7 @@ session_group_remove(struct session *s)
TAILQ_REMOVE(&sg->sessions, s, gentry);
if (TAILQ_EMPTY(&sg->sessions)) {
RB_REMOVE(session_groups, &session_groups, sg);
+ free((void *)sg->name);
free(sg);
}
}
diff --git a/spawn.c b/spawn.c
index ee19cb9d..f1ea87d2 100644
--- a/spawn.c
+++ b/spawn.c
@@ -54,10 +54,10 @@ spawn_log(const char *from, struct spawn_context *sc)
struct session *s = sc->s;
struct winlink *wl = sc->wl;
struct window_pane *wp0 = sc->wp0;
+ const char *name = cmdq_get_name(sc->item);
char tmp[128];
- const char *name;
- log_debug("%s: %s, flags=%#x", from, sc->item->name, sc->flags);
+ log_debug("%s: %s, flags=%#x", from, name, sc->flags);
if (wl != NULL && wp0 != NULL)
xsnprintf(tmp, sizeof tmp, "wl=%d wp0=%%%u", wl->idx, wp0->id);
@@ -68,18 +68,14 @@ spawn_log(const char *from, struct spawn_context *sc)
else
xsnprintf(tmp, sizeof tmp, "wl=none wp0=none");
log_debug("%s: s=$%u %s idx=%d", from, s->id, tmp, sc->idx);
-
- name = sc->name;
- if (name == NULL)
- name = "none";
- log_debug("%s: name=%s", from, name);
+ log_debug("%s: name=%s", from, sc->name == NULL ? "none" : sc->name);
}
struct winlink *
spawn_window(struct spawn_context *sc, char **cause)
{
struct cmdq_item *item = sc->item;
- struct client *c = item->client;
+ struct client *c = cmdq_get_client(item);
struct session *s = sc->s;
struct window *w;
struct window_pane *wp;
@@ -155,7 +151,7 @@ spawn_window(struct spawn_context *sc, char **cause)
xasprintf(cause, "couldn't add window %d", idx);
return (NULL);
}
- default_window_size(sc->c, s, NULL, &sx, &sy, &xpixel, &ypixel,
+ default_window_size(sc->tc, s, NULL, &sx, &sy, &xpixel, &ypixel,
-1);
if ((w = window_create(sx, sy, xpixel, ypixel)) == NULL) {
winlink_remove(&s->windows, sc->wl);
@@ -165,7 +161,7 @@ spawn_window(struct spawn_context *sc, char **cause)
if (s->curw == NULL)
s->curw = sc->wl;
sc->wl->session = s;
- w->latest = sc->c;
+ w->latest = sc->tc;
winlink_set_window(sc->wl, w);
} else
w = NULL;
@@ -205,7 +201,8 @@ struct window_pane *
spawn_pane(struct spawn_context *sc, char **cause)
{
struct cmdq_item *item = sc->item;
- struct client *c = item->client;
+ struct cmd_find_state *target = cmdq_get_target(item);
+ struct client *c = cmdq_get_client(item);
struct session *s = sc->s;
struct window *w = sc->wl->window;
struct window_pane *new_wp;
@@ -228,9 +225,9 @@ spawn_pane(struct spawn_context *sc, char **cause)
* the pane's stored one unless specified.
*/
if (sc->cwd != NULL)
- cwd = format_single(item, sc->cwd, c, item->target.s, NULL, NULL);
+ cwd = format_single(item, sc->cwd, c, target->s, NULL, NULL);
else if (~sc->flags & SPAWN_RESPAWN)
- cwd = xstrdup(server_client_get_cwd(c, item->target.s));
+ cwd = xstrdup(server_client_get_cwd(c, target->s));
else
cwd = NULL;
@@ -253,7 +250,8 @@ spawn_pane(struct spawn_context *sc, char **cause)
}
window_pane_reset_mode_all(sc->wp0);
screen_reinit(&sc->wp0->base);
- input_init(sc->wp0);
+ input_free(sc->wp0->ictx);
+ sc->wp0->ictx = NULL;
new_wp = sc->wp0;
new_wp->flags &= ~(PANE_STATUSREADY|PANE_STATUSDRAWN);
} else if (sc->lc == NULL) {
@@ -300,7 +298,7 @@ spawn_pane(struct spawn_context *sc, char **cause)
child = environ_for_session(s, 0);
if (sc->environ != NULL)
environ_copy(sc->environ, child);
- environ_set(child, "TMUX_PANE", "%%%u", new_wp->id);
+ environ_set(child, "TMUX_PANE", 0, "%%%u", new_wp->id);
/*
* Then the PATH environment variable. The session one is replaced from
@@ -310,20 +308,20 @@ spawn_pane(struct spawn_context *sc, char **cause)
if (c != NULL && c->session == NULL) { /* only unattached clients */
ee = environ_find(c->environ, "PATH");
if (ee != NULL)
- environ_set(child, "PATH", "%s", ee->value);
+ environ_set(child, "PATH", 0, "%s", ee->value);
}
if (environ_find(child, "PATH") == NULL)
- environ_set(child, "%s", _PATH_DEFPATH);
+ environ_set(child, "PATH", 0, "%s", _PATH_DEFPATH);
/* Then the shell. If respawning, use the old one. */
if (~sc->flags & SPAWN_RESPAWN) {
tmp = options_get_string(s->options, "default-shell");
- if (*tmp == '\0' || areshell(tmp))
+ if (!checkshell(tmp))
tmp = _PATH_BSHELL;
free(new_wp->shell);
new_wp->shell = xstrdup(tmp);
}
- environ_set(child, "SHELL", "%s", new_wp->shell);
+ environ_set(child, "SHELL", 0, "%s", new_wp->shell);
/* Log the arguments we are going to use. */
log_debug("%s: shell=%s", __func__, new_wp->shell);
@@ -366,6 +364,7 @@ spawn_pane(struct spawn_context *sc, char **cause)
window_remove_pane(w, new_wp);
}
sigprocmask(SIG_SETMASK, &oldset, NULL);
+ environ_free(child);
return (NULL);
}
@@ -452,6 +451,8 @@ complete:
sigprocmask(SIG_SETMASK, &oldset, NULL);
window_pane_set_event(new_wp);
+ environ_free(child);
+
if (sc->flags & SPAWN_RESPAWN)
return (new_wp);
if ((~sc->flags & SPAWN_DETACHED) || w->active == NULL) {
diff --git a/status.c b/status.c
index 33f6c47a..b5442550 100644
--- a/status.c
+++ b/status.c
@@ -37,9 +37,17 @@ static const char *status_prompt_up_history(u_int *);
static const char *status_prompt_down_history(u_int *);
static void status_prompt_add_history(const char *);
-static char **status_prompt_complete_list(u_int *, const char *);
-static char *status_prompt_complete_prefix(char **, u_int);
-static char *status_prompt_complete(struct session *, const char *);
+static char *status_prompt_complete(struct client *, const char *, u_int);
+static char *status_prompt_complete_window_menu(struct client *,
+ struct session *, const char *, u_int, char);
+
+struct status_prompt_menu {
+ struct client *c;
+ u_int start;
+ u_int size;
+ char **list;
+ char flag;
+};
/* Status prompt history. */
#define PROMPT_HISTORY 100
@@ -321,7 +329,7 @@ status_redraw(struct client *c)
struct screen_write_ctx ctx;
struct grid_cell gc;
u_int lines, i, n, width = c->tty.sx;
- int flags, force = 0, changed = 0;
+ int flags, force = 0, changed = 0, fg, bg;
struct options_entry *o;
union options_value *ov;
struct format_tree *ft;
@@ -338,8 +346,21 @@ status_redraw(struct client *c)
if (c->tty.sy == 0 || lines == 0)
return (1);
+ /* Create format tree. */
+ flags = FORMAT_STATUS;
+ if (c->flags & CLIENT_STATUSFORCE)
+ flags |= FORMAT_FORCE;
+ ft = format_create(c, NULL, FORMAT_NONE, flags);
+ format_defaults(ft, c, NULL, NULL, NULL);
+
/* Set up default colour. */
- style_apply(&gc, s->options, "status-style");
+ style_apply(&gc, s->options, "status-style", ft);
+ fg = options_get_number(s->options, "status-fg");
+ if (fg != 8)
+ gc.fg = fg;
+ bg = options_get_number(s->options, "status-bg");
+ if (bg != 8)
+ gc.bg = bg;
if (!grid_cells_equal(&gc, &sl->style)) {
force = 1;
memcpy(&sl->style, &gc, sizeof sl->style);
@@ -351,14 +372,7 @@ status_redraw(struct client *c)
screen_resize(&sl->screen, width, lines, 0);
changed = force = 1;
}
- screen_write_start(&ctx, NULL, &sl->screen);
-
- /* Create format tree. */
- flags = FORMAT_STATUS;
- if (c->flags & CLIENT_STATUSFORCE)
- flags |= FORMAT_FORCE;
- ft = format_create(c, NULL, FORMAT_NONE, flags);
- format_defaults(ft, c, NULL, NULL, NULL);
+ screen_write_start(&ctx, &sl->screen);
/* Write the status lines. */
o = options_get(s->options, "status-format");
@@ -476,6 +490,7 @@ status_message_redraw(struct client *c)
size_t len;
u_int lines, offset;
struct grid_cell gc;
+ struct format_tree *ft;
if (c->tty.sx == 0 || c->tty.sy == 0)
return (0);
@@ -490,9 +505,11 @@ status_message_redraw(struct client *c)
if (len > c->tty.sx)
len = c->tty.sx;
- style_apply(&gc, s->options, "message-style");
+ ft = format_create_defaults(NULL, c, NULL, NULL, NULL);
+ style_apply(&gc, s->options, "message-style", ft);
+ format_free(ft);
- screen_write_start(&ctx, NULL, sl->active);
+ screen_write_start(&ctx, sl->active);
screen_write_fast_copy(&ctx, &sl->screen, 0, 0, c->tty.sx, lines - 1);
screen_write_cursormove(&ctx, 0, lines - 1, 0);
for (offset = 0; offset < c->tty.sx; offset++)
@@ -622,6 +639,7 @@ status_prompt_redraw(struct client *c)
u_int i, lines, offset, left, start, width;
u_int pcursor, pwidth;
struct grid_cell gc, cursorgc;
+ struct format_tree *ft;
if (c->tty.sx == 0 || c->tty.sy == 0)
return (0);
@@ -632,10 +650,12 @@ status_prompt_redraw(struct client *c)
lines = 1;
screen_init(sl->active, c->tty.sx, lines, 0);
+ ft = format_create_defaults(NULL, c, NULL, NULL, NULL);
if (c->prompt_mode == PROMPT_COMMAND)
- style_apply(&gc, s->options, "message-command-style");
+ style_apply(&gc, s->options, "message-command-style", ft);
else
- style_apply(&gc, s->options, "message-style");
+ style_apply(&gc, s->options, "message-style", ft);
+ format_free(ft);
memcpy(&cursorgc, &gc, sizeof cursorgc);
cursorgc.attr ^= GRID_ATTR_REVERSE;
@@ -644,7 +664,7 @@ status_prompt_redraw(struct client *c)
if (start > c->tty.sx)
start = c->tty.sx;
- screen_write_start(&ctx, NULL, sl->active);
+ screen_write_start(&ctx, sl->active);
screen_write_fast_copy(&ctx, &sl->screen, 0, 0, c->tty.sx, lines - 1);
screen_write_cursormove(&ctx, 0, lines - 1, 0);
for (offset = 0; offset < c->tty.sx; offset++)
@@ -733,6 +753,7 @@ status_prompt_translate_key(struct client *c, key_code key, key_code *new_key)
if (c->prompt_mode == PROMPT_ENTRY) {
switch (key) {
case '\003': /* C-c */
+ case '\007': /* C-g */
case '\010': /* C-h */
case '\011': /* Tab */
case '\025': /* C-u */
@@ -813,6 +834,9 @@ status_prompt_translate_key(struct client *c, key_code key, key_code *new_key)
case 'p':
*new_key = '\031'; /* C-y */
return (1);
+ case 'q':
+ *new_key = '\003'; /* C-c */
+ return (1);
case 's':
case KEYC_DC:
case 'x':
@@ -909,15 +933,86 @@ status_prompt_paste(struct client *c)
return (1);
}
+/* Finish completion. */
+static int
+status_prompt_replace_complete(struct client *c, const char *s)
+{
+ char word[64], *allocated = NULL;
+ size_t size, n, off, idx, used;
+ struct utf8_data *first, *last, *ud;
+
+ /* Work out where the cursor currently is. */
+ idx = c->prompt_index;
+ if (idx != 0)
+ idx--;
+ size = utf8_strlen(c->prompt_buffer);
+
+ /* Find the word we are in. */
+ first = &c->prompt_buffer[idx];
+ while (first > c->prompt_buffer && !status_prompt_space(first))
+ first--;
+ while (first->size != 0 && status_prompt_space(first))
+ first++;
+ last = &c->prompt_buffer[idx];
+ while (last->size != 0 && !status_prompt_space(last))
+ last++;
+ while (last > c->prompt_buffer && status_prompt_space(last))
+ last--;
+ if (last->size != 0)
+ last++;
+ if (last < first)
+ return (0);
+ if (s == NULL) {
+ used = 0;
+ for (ud = first; ud < last; ud++) {
+ if (used + ud->size >= sizeof word)
+ break;
+ memcpy(word + used, ud->data, ud->size);
+ used += ud->size;
+ }
+ if (ud != last)
+ return (0);
+ word[used] = '\0';
+ }
+
+ /* Try to complete it. */
+ if (s == NULL) {
+ allocated = status_prompt_complete(c, word,
+ first - c->prompt_buffer);
+ if (allocated == NULL)
+ return (0);
+ s = allocated;
+ }
+
+ /* Trim out word. */
+ n = size - (last - c->prompt_buffer) + 1; /* with \0 */
+ memmove(first, last, n * sizeof *c->prompt_buffer);
+ size -= last - first;
+
+ /* Insert the new word. */
+ size += strlen(s);
+ off = first - c->prompt_buffer;
+ c->prompt_buffer = xreallocarray(c->prompt_buffer, size + 1,
+ sizeof *c->prompt_buffer);
+ first = c->prompt_buffer + off;
+ memmove(first + strlen(s), first, n * sizeof *c->prompt_buffer);
+ for (idx = 0; idx < strlen(s); idx++)
+ utf8_set(&first[idx], s[idx]);
+ c->prompt_index = (first - c->prompt_buffer) + strlen(s);
+
+ free(allocated);
+ return (1);
+}
+
/* Handle keys in prompt. */
int
status_prompt_key(struct client *c, key_code key)
{
struct options *oo = c->session->options;
- char *s, *cp, word[64], prefix = '=';
+ char *s, *cp, prefix = '=';
const char *histstr, *ws = NULL, *keystring;
- size_t size, n, off, idx, used;
- struct utf8_data tmp, *first, *last, *ud;
+ size_t size, idx;
+ struct utf8_data tmp;
int keys;
if (c->prompt_flags & PROMPT_KEY) {
@@ -982,63 +1077,9 @@ process_key:
}
break;
case '\011': /* Tab */
- if (c->prompt_buffer[0].size == 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 && !status_prompt_space(first))
- first--;
- while (first->size != 0 && status_prompt_space(first))
- first++;
- last = &c->prompt_buffer[idx];
- while (last->size != 0 && !status_prompt_space(last))
- last++;
- while (last > c->prompt_buffer && status_prompt_space(last))
- last--;
- if (last->size != 0)
- last++;
- if (last <= first)
- break;
-
- used = 0;
- for (ud = first; ud < last; ud++) {
- if (used + ud->size >= sizeof word)
- break;
- memcpy(word + used, ud->data, ud->size);
- used += ud->size;
- }
- if (ud != last)
- break;
- word[used] = '\0';
-
- /* And try to complete it. */
- if ((s = status_prompt_complete(c->session, word)) == NULL)
- break;
-
- /* Trim out word. */
- n = size - (last - c->prompt_buffer) + 1; /* with \0 */
- memmove(first, last, n * sizeof *c->prompt_buffer);
- size -= last - first;
-
- /* Insert the new word. */
- size += strlen(s);
- off = first - c->prompt_buffer;
- c->prompt_buffer = xreallocarray(c->prompt_buffer, size + 1,
- sizeof *c->prompt_buffer);
- first = c->prompt_buffer + off;
- memmove(first + strlen(s), first, n * sizeof *c->prompt_buffer);
- for (idx = 0; idx < strlen(s); idx++)
- utf8_set(&first[idx], s[idx]);
-
- c->prompt_index = (first - c->prompt_buffer) + strlen(s);
- free(s);
-
- goto changed;
+ if (status_prompt_replace_complete(c, NULL))
+ goto changed;
+ break;
case KEYC_BSPACE:
case '\010': /* C-h */
if (c->prompt_index != 0) {
@@ -1320,14 +1361,13 @@ status_prompt_add_history(const char *line)
}
/* Build completion list. */
-char **
-status_prompt_complete_list(u_int *size, const char *s)
+static char **
+status_prompt_complete_list(u_int *size, const char *s, int at_start)
{
char **list = NULL;
const char **layout, *value, *cp;
const struct cmd_entry **cmdent;
const struct options_table_entry *oe;
- u_int idx;
size_t slen = strlen(s), valuelen;
struct options_entry *o;
struct options_array_item *a;
@@ -1342,17 +1382,10 @@ status_prompt_complete_list(u_int *size, const char *s)
list = xreallocarray(list, (*size) + 1, sizeof *list);
list[(*size)++] = xstrdup((*cmdent)->name);
}
- }
- for (oe = options_table; oe->name != NULL; oe++) {
- if (strncmp(oe->name, s, slen) == 0) {
- list = xreallocarray(list, (*size) + 1, sizeof *list);
- list[(*size)++] = xstrdup(oe->name);
- }
- }
- for (layout = layouts; *layout != NULL; layout++) {
- if (strncmp(*layout, s, slen) == 0) {
+ if ((*cmdent)->alias != NULL &&
+ strncmp((*cmdent)->alias, s, slen) == 0) {
list = xreallocarray(list, (*size) + 1, sizeof *list);
- list[(*size)++] = xstrdup(*layout);
+ list[(*size)++] = xstrdup((*cmdent)->alias);
}
}
o = options_get_only(global_options, "command-alias");
@@ -1373,8 +1406,21 @@ status_prompt_complete_list(u_int *size, const char *s)
a = options_array_next(a);
}
}
- for (idx = 0; idx < (*size); idx++)
- log_debug("complete %u: %s", idx, list[idx]);
+ if (at_start)
+ return (list);
+
+ for (oe = options_table; oe->name != NULL; oe++) {
+ if (strncmp(oe->name, s, slen) == 0) {
+ list = xreallocarray(list, (*size) + 1, sizeof *list);
+ list[(*size)++] = xstrdup(oe->name);
+ }
+ }
+ for (layout = layouts; *layout != NULL; layout++) {
+ if (strncmp(*layout, s, slen) == 0) {
+ list = xreallocarray(list, (*size) + 1, sizeof *list);
+ list[(*size)++] = xstrdup(*layout);
+ }
+ }
return (list);
}
@@ -1399,124 +1445,302 @@ status_prompt_complete_prefix(char **list, u_int size)
return (out);
}
+/* Complete word menu callback. */
+static void
+status_prompt_menu_callback(__unused struct menu *menu, u_int idx, key_code key,
+ void *data)
+{
+ struct status_prompt_menu *spm = data;
+ struct client *c = spm->c;
+ u_int i;
+ char *s;
+
+ if (key != KEYC_NONE) {
+ idx += spm->start;
+ if (spm->flag == '\0')
+ s = xstrdup(spm->list[idx]);
+ else
+ xasprintf(&s, "-%c%s", spm->flag, spm->list[idx]);
+ if (c->prompt_flags & PROMPT_WINDOW) {
+ free(c->prompt_buffer);
+ c->prompt_buffer = utf8_fromcstr(s);
+ c->prompt_index = utf8_strlen(c->prompt_buffer);
+ c->flags |= CLIENT_REDRAWSTATUS;
+ } else if (status_prompt_replace_complete(c, s))
+ c->flags |= CLIENT_REDRAWSTATUS;
+ free(s);
+ }
+
+ for (i = 0; i < spm->size; i++)
+ free(spm->list[i]);
+ free(spm->list);
+}
+
+/* Show complete word menu. */
+static int
+status_prompt_complete_list_menu(struct client *c, char **list, u_int size,
+ u_int offset, char flag)
+{
+ struct menu *menu;
+ struct menu_item item;
+ struct status_prompt_menu *spm;
+ u_int lines = status_line_size(c), height, i;
+ u_int py;
+
+ if (size <= 1)
+ return (0);
+ if (c->tty.sy - lines < 3)
+ return (0);
+
+ spm = xmalloc(sizeof *spm);
+ spm->c = c;
+ spm->size = size;
+ spm->list = list;
+ spm->flag = flag;
+
+ height = c->tty.sy - lines - 2;
+ if (height > 10)
+ height = 10;
+ if (height > size)
+ height = size;
+ spm->start = size - height;
+
+ menu = menu_create("");
+ for (i = spm->start; i < size; i++) {
+ item.name = list[i];
+ item.key = '0' + (i - spm->start);
+ item.command = NULL;
+ menu_add_item(menu, &item, NULL, NULL, NULL);
+ }
+
+ if (options_get_number(c->session->options, "status-position") == 0)
+ py = lines;
+ else
+ py = c->tty.sy - 3 - height;
+ offset += utf8_cstrwidth(c->prompt_string);
+ if (offset > 2)
+ offset -= 2;
+ else
+ offset = 0;
+
+ if (menu_display(menu, MENU_NOMOUSE|MENU_TAB, NULL, offset,
+ py, c, NULL, status_prompt_menu_callback, spm) != 0) {
+ menu_free(menu);
+ free(spm);
+ return (0);
+ }
+ return (1);
+}
+
+/* Show complete word menu. */
+static char *
+status_prompt_complete_window_menu(struct client *c, struct session *s,
+ const char *word, u_int offset, char flag)
+{
+ struct menu *menu;
+ struct menu_item item;
+ struct status_prompt_menu *spm;
+ struct winlink *wl;
+ char **list = NULL, *tmp;
+ u_int lines = status_line_size(c), height;
+ u_int py, size = 0;
+
+ if (c->tty.sy - lines < 3)
+ return (NULL);
+
+ spm = xmalloc(sizeof *spm);
+ spm->c = c;
+ spm->flag = flag;
+
+ height = c->tty.sy - lines - 2;
+ if (height > 10)
+ height = 10;
+ spm->start = 0;
+
+ menu = menu_create("");
+ RB_FOREACH(wl, winlinks, &s->windows) {
+ if (word != NULL && *word != '\0') {
+ xasprintf(&tmp, "%d", wl->idx);
+ if (strncmp(tmp, word, strlen(word)) != 0) {
+ free(tmp);
+ continue;
+ }
+ free(tmp);
+ }
+
+ list = xreallocarray(list, size + 1, sizeof *list);
+ if (c->prompt_flags & PROMPT_WINDOW) {
+ xasprintf(&tmp, "%d (%s)", wl->idx, wl->window->name);
+ xasprintf(&list[size++], "%d", wl->idx);
+ } else {
+ xasprintf(&tmp, "%s:%d (%s)", s->name, wl->idx,
+ wl->window->name);
+ xasprintf(&list[size++], "%s:%d", s->name, wl->idx);
+ }
+ item.name = tmp;
+ item.key = '0' + size - 1;
+ item.command = NULL;
+ menu_add_item(menu, &item, NULL, NULL, NULL);
+ free(tmp);
+
+ if (size == height)
+ break;
+ }
+ if (size == 0) {
+ menu_free(menu);
+ return (NULL);
+ }
+ if (size == 1) {
+ menu_free(menu);
+ if (flag != '\0') {
+ xasprintf(&tmp, "-%c%s", flag, list[0]);
+ free(list[0]);
+ } else
+ tmp = list[0];
+ free(list);
+ return (tmp);
+ }
+ if (height > size)
+ height = size;
+
+ spm->size = size;
+ spm->list = list;
+
+ if (options_get_number(c->session->options, "status-position") == 0)
+ py = lines;
+ else
+ py = c->tty.sy - 3 - height;
+ offset += utf8_cstrwidth(c->prompt_string);
+ if (offset > 2)
+ offset -= 2;
+ else
+ offset = 0;
+
+ if (menu_display(menu, MENU_NOMOUSE|MENU_TAB, NULL, offset,
+ py, c, NULL, status_prompt_menu_callback, spm) != 0) {
+ menu_free(menu);
+ free(spm);
+ return (NULL);
+ }
+ return (NULL);
+}
+
+/* Sort complete list. */
+static int
+status_prompt_complete_sort(const void *a, const void *b)
+{
+ const char **aa = (const char **)a, **bb = (const char **)b;
+
+ return (strcmp(*aa, *bb));
+}
+
+/* Complete a session. */
+static char *
+status_prompt_complete_session(char ***list, u_int *size, const char *s,
+ char flag)
+{
+ struct session *loop;
+ char *out, *tmp;
+
+ RB_FOREACH(loop, sessions, &sessions) {
+ if (*s != '\0' && strncmp(loop->name, s, strlen(s)) != 0)
+ continue;
+ *list = xreallocarray(*list, (*size) + 2, sizeof **list);
+ xasprintf(&(*list)[(*size)++], "%s:", loop->name);
+ }
+ out = status_prompt_complete_prefix(*list, *size);
+ if (out != NULL && flag != '\0') {
+ xasprintf(&tmp, "-%c%s", flag, out);
+ free(out);
+ out = tmp;
+ }
+ return (out);
+}
+
/* Complete word. */
static char *
-status_prompt_complete(struct session *session, const char *s)
+status_prompt_complete(struct client *c, const char *word, u_int offset)
{
- char **list = NULL;
- const char *colon;
+ struct session *session;
+ const char *s, *colon;
+ char **list = NULL, *copy = NULL, *out = NULL;
+ char flag = '\0';
u_int size = 0, i;
- struct session *s_loop;
- struct winlink *wl;
- struct window *w;
- char *copy, *out, *tmp;
- if (*s == '\0')
+ if (*word == '\0' &&
+ ((c->prompt_flags & (PROMPT_TARGET|PROMPT_WINDOW)) == 0))
return (NULL);
- out = NULL;
- if (strncmp(s, "-t", 2) != 0 && strncmp(s, "-s", 2) != 0) {
- list = status_prompt_complete_list(&size, s);
+ if (((c->prompt_flags & (PROMPT_TARGET|PROMPT_WINDOW)) == 0) &&
+ strncmp(word, "-t", 2) != 0 &&
+ strncmp(word, "-s", 2) != 0) {
+ list = status_prompt_complete_list(&size, word, offset == 0);
if (size == 0)
out = NULL;
else if (size == 1)
xasprintf(&out, "%s ", list[0]);
else
out = status_prompt_complete_prefix(list, size);
- for (i = 0; i < size; i++)
- free(list[i]);
- free(list);
- return (out);
+ goto found;
}
- copy = xstrdup(s);
-
- colon = ":";
- if (copy[strlen(copy) - 1] == ':')
- copy[strlen(copy) - 1] = '\0';
- else
- colon = "";
- s = copy + 2;
- RB_FOREACH(s_loop, sessions, &sessions) {
- if (strncmp(s_loop->name, s, strlen(s)) == 0) {
- list = xreallocarray(list, size + 2, sizeof *list);
- list[size++] = s_loop->name;
- }
+ if (c->prompt_flags & (PROMPT_TARGET|PROMPT_WINDOW)) {
+ s = word;
+ flag = '\0';
+ } else {
+ s = word + 2;
+ flag = word[1];
+ offset += 2;
}
- if (size == 1) {
- out = xstrdup(list[0]);
- if (session_find(list[0]) != NULL)
- colon = ":";
- } else if (size != 0)
- out = status_prompt_complete_prefix(list, size);
- if (out != NULL) {
- xasprintf(&tmp, "-%c%s%s", copy[1], out, colon);
- free(out);
- out = tmp;
+
+ /* If this is a window completion, open the window menu. */
+ if (c->prompt_flags & PROMPT_WINDOW) {
+ out = status_prompt_complete_window_menu(c, c->session, s,
+ offset, '\0');
goto found;
}
+ colon = strchr(s, ':');
- colon = "";
- if (*s == ':') {
- RB_FOREACH(wl, winlinks, &session->windows) {
- xasprintf(&tmp, ":%s", wl->window->name);
- if (strncmp(tmp, s, strlen(s)) == 0){
- list = xreallocarray(list, size + 1,
- sizeof *list);
- list[size++] = tmp;
- continue;
- }
- free(tmp);
-
- xasprintf(&tmp, ":%d", wl->idx);
- if (strncmp(tmp, s, strlen(s)) == 0) {
- list = xreallocarray(list, size + 1,
- sizeof *list);
- list[size++] = tmp;
- continue;
- }
- free(tmp);
- }
- } else {
- RB_FOREACH(s_loop, sessions, &sessions) {
- RB_FOREACH(wl, winlinks, &s_loop->windows) {
- w = wl->window;
-
- xasprintf(&tmp, "%s:%s", s_loop->name, w->name);
- if (strncmp(tmp, s, strlen(s)) == 0) {
- list = xreallocarray(list, size + 1,
- sizeof *list);
- list[size++] = tmp;
- continue;
- }
- free(tmp);
+ /* If there is no colon, complete as a session. */
+ if (colon == NULL) {
+ out = status_prompt_complete_session(&list, &size, s, flag);
+ goto found;
+ }
- xasprintf(&tmp, "%s:%d", s_loop->name, wl->idx);
- if (strncmp(tmp, s, strlen(s)) == 0) {
- list = xreallocarray(list, size + 1,
- sizeof *list);
- list[size++] = tmp;
- continue;
- }
- free(tmp);
- }
+ /* If there is a colon but no period, find session and show a menu. */
+ if (strchr(colon + 1, '.') == NULL) {
+ if (*s == ':')
+ session = c->session;
+ else {
+ copy = xstrdup(s);
+ *strchr(copy, ':') = '\0';
+ session = session_find(copy);
+ free(copy);
+ if (session == NULL)
+ goto found;
}
+ out = status_prompt_complete_window_menu(c, session, colon + 1,
+ offset, flag);
+ if (out == NULL)
+ return (NULL);
}
- if (size == 1) {
- out = xstrdup(list[0]);
- colon = " ";
- } else if (size != 0)
- out = status_prompt_complete_prefix(list, size);
- if (out != NULL) {
- xasprintf(&tmp, "-%c%s%s", copy[1], out, colon);
- out = tmp;
- }
-
- for (i = 0; i < size; i++)
- free((void *)list[i]);
found:
- free(copy);
- free(list);
+ if (size != 0) {
+ qsort(list, size, sizeof *list, status_prompt_complete_sort);
+ for (i = 0; i < size; i++)
+ log_debug("complete %u: %s", i, list[i]);
+ }
+
+ if (out != NULL && strcmp(word, out) == 0) {
+ free(out);
+ out = NULL;
+ }
+ if (out != NULL ||
+ !status_prompt_complete_list_menu(c, list, size, offset, flag)) {
+ for (i = 0; i < size; i++)
+ free(list[i]);
+ free(list);
+ }
return (out);
}
diff --git a/style.c b/style.c
index 6ba4c524..3c615852 100644
--- a/style.c
+++ b/style.c
@@ -26,7 +26,7 @@
#include "tmux.h"
/* Mask for bits not included in style. */
-#define STYLE_ATTR_MASK (~GRID_ATTR_CHARSET)
+#define STYLE_ATTR_MASK (~0)
/* Default style. */
static struct style style_default = {
@@ -59,6 +59,7 @@ style_parse(struct style *sy, const struct grid_cell *base, const char *in)
return (0);
style_copy(&saved, sy);
+ log_debug("%s: %s", __func__, in);
do {
while (*in != '\0' && strchr(delimiters, *in) != NULL)
in++;
@@ -71,6 +72,7 @@ style_parse(struct style *sy, const struct grid_cell *base, const char *in)
memcpy(tmp, in, end);
tmp[end] = '\0';
+ log_debug("%s: %s", __func__, tmp);
if (strcasecmp(tmp, "default") == 0) {
sy->gc.fg = base->fg;
sy->gc.bg = base->bg;
@@ -247,7 +249,7 @@ style_tostring(struct style *sy)
colour_tostring(gc->bg));
comma = ",";
}
- if (gc->attr != 0 && gc->attr != GRID_ATTR_CHARSET) {
+ if (gc->attr != 0) {
xsnprintf(s + off, sizeof s - off, "%s%s", comma,
attributes_tostring(gc->attr));
comma = ",";
@@ -258,17 +260,37 @@ style_tostring(struct style *sy)
return (s);
}
-/* Apply a style. */
+/* Apply a style on top of the given style. */
void
-style_apply(struct grid_cell *gc, struct options *oo, const char *name)
+style_add(struct grid_cell *gc, struct options *oo, const char *name,
+ struct format_tree *ft)
{
- struct style *sy;
+ struct style *sy;
+ struct format_tree *ft0 = NULL;
- memcpy(gc, &grid_default_cell, sizeof *gc);
- sy = options_get_style(oo, name);
- gc->fg = sy->gc.fg;
- gc->bg = sy->gc.bg;
+ if (ft == NULL)
+ ft = ft0 = format_create(NULL, NULL, 0, FORMAT_NOJOBS);
+
+ sy = options_string_to_style(oo, name, ft);
+ if (sy == NULL)
+ sy = &style_default;
+ if (sy->gc.fg != 8)
+ gc->fg = sy->gc.fg;
+ if (sy->gc.bg != 8)
+ gc->bg = sy->gc.bg;
gc->attr |= sy->gc.attr;
+
+ if (ft0 != NULL)
+ format_free(ft0);
+}
+
+/* Apply a style on top of the default style. */
+void
+style_apply(struct grid_cell *gc, struct options *oo, const char *name,
+ struct format_tree *ft)
+{
+ memcpy(gc, &grid_default_cell, sizeof *gc);
+ style_add(gc, oo, name, ft);
}
/* Initialize style from cell. */
@@ -285,30 +307,3 @@ style_copy(struct style *dst, struct style *src)
{
memcpy(dst, src, sizeof *dst);
}
-
-/* Check if two styles are (visibly) the same. */
-int
-style_equal(struct style *sy1, struct style *sy2)
-{
- struct grid_cell *gc1 = &sy1->gc;
- struct grid_cell *gc2 = &sy2->gc;
-
- if (gc1->fg != gc2->fg)
- return (0);
- if (gc1->bg != gc2->bg)
- return (0);
- if ((gc1->attr & STYLE_ATTR_MASK) != (gc2->attr & STYLE_ATTR_MASK))
- return (0);
- if (sy1->fill != sy2->fill)
- return (0);
- if (sy1->align != sy2->align)
- return (0);
- return (1);
-}
-
-/* Is this style default? */
-int
-style_is_default(struct style *sy)
-{
- return (style_equal(sy, &style_default));
-}
diff --git a/tmux.1 b/tmux.1
index 615274bf..2b460519 100644
--- a/tmux.1
+++ b/tmux.1
@@ -28,6 +28,7 @@
.Op Fl f Ar file
.Op Fl L Ar socket-name
.Op Fl S Ar socket-path
+.Op Fl T Ar features
.Op Ar command Op Ar flags
.Ek
.Sh DESCRIPTION
@@ -98,6 +99,8 @@ The options are as follows:
Force
.Nm
to assume the terminal supports 256 colours.
+This is equivalent to
+.Fl T Ar 256 .
.It Fl C
Start in control mode (see the
.Sx CONTROL MODE
@@ -186,6 +189,14 @@ that is set does not contain
.Qq UTF-8
or
.Qq UTF8 .
+This is equivalent to
+.Fl T Ar UTF-8 .
+.It Fl T Ar features
+Set terminal features for the client.
+This is a comma-separated list of features.
+See the
+.Ic terminal-features
+option.
.It Fl v
Request verbose logging.
Log messages will be saved into
@@ -565,6 +576,18 @@ Environment variables may be set by using the syntax
for example
.Ql HOME=/home/user .
Variables set during parsing are added to the global environment.
+A hidden variable may be set with
+.Ql %hidden ,
+for example:
+.Bd -literal -offset indent
+%hidden MYVAR=42
+.Ed
+.Pp
+Hidden variables are not passed to the environment of processes created
+by tmux.
+See the
+.Sx GLOBAL AND SESSION ENVIRONMENT
+section.
.Pp
Commands may be parsed conditionally by surrounding them with
.Ql %if ,
@@ -1043,12 +1066,18 @@ List the syntax of
.Ar command
or - if omitted - of all commands supported by
.Nm .
-.It Ic list-sessions Op Fl F Ar format
+.It Xo Ic list-sessions
+.Op Fl F Ar format
+.Op Fl f Ar filter
+.Xc
.D1 (alias: Ic ls )
List all sessions managed by the server.
-For the meaning of the
.Fl F
-flag, see the
+specifies the format of each line and
+.Fl f
+a filter.
+Only sessions for which the filter is true are shown.
+See the
.Sx FORMATS
section.
.It Ic lock-client Op Fl t Ar target-client
@@ -1065,6 +1094,7 @@ Lock all clients attached to
.It Xo Ic new-session
.Op Fl AdDEPX
.Op Fl c Ar start-directory
+.Op Fl e Ar environment
.Op Fl F Ar format
.Op Fl n Ar window-name
.Op Fl s Ar session-name
@@ -1171,6 +1201,11 @@ If
is used, the
.Ic update-environment
option will not be applied.
+.Fl e
+takes the form
+.Ql VARIABLE=value
+and sets an environment variable for the newly created session; it may be
+specified multiple times.
.It Xo Ic refresh-client
.Op Fl cDlLRSU
.Op Fl C Ar XxY
@@ -1413,6 +1448,10 @@ This mode is entered with the
command, bound to
.Ql \&[
by default.
+Copied text can be pasted with the
+.Ic paste-buffer
+command, bound to
+.Ql \&] .
.It
View mode, which is like copy mode but is entered when a command that produces
output, such as
@@ -1461,9 +1500,9 @@ The following commands are supported in copy mode:
.It Li "clear-selection" Ta "Escape" Ta "C-g"
.It Li "copy-end-of-line [<prefix>]" Ta "D" Ta "C-k"
.It Li "copy-line [<prefix>]" Ta "" Ta ""
-.It Li "copy-pipe <command> [<prefix>]" Ta "" Ta ""
-.It Li "copy-pipe-no-clear <command> [<prefix>]" Ta "" Ta ""
-.It Li "copy-pipe-and-cancel <command> [<prefix>]" Ta "" Ta ""
+.It Li "copy-pipe [<command>] [<prefix>]" Ta "" Ta ""
+.It Li "copy-pipe-no-clear [<command>] [<prefix>]" Ta "" Ta ""
+.It Li "copy-pipe-and-cancel [<command>] [<prefix>]" Ta "" Ta ""
.It Li "copy-selection [<prefix>]" Ta "" Ta ""
.It Li "copy-selection-no-clear [<prefix>]" Ta "" Ta ""
.It Li "copy-selection-and-cancel [<prefix>]" Ta "Enter" Ta "M-w"
@@ -1501,6 +1540,7 @@ The following commands are supported in copy mode:
.It Li "previous-space" Ta "B" Ta ""
.It Li "previous-word" Ta "b" Ta "M-b"
.It Li "rectangle-toggle" Ta "v" Ta "R"
+.It Li "refresh-from-pane" Ta "r" Ta "r"
.It Li "scroll-down" Ta "C-e" Ta "C-Down"
.It Li "scroll-down-and-cancel" Ta "" Ta ""
.It Li "scroll-up" Ta "C-y" Ta "C-Up"
@@ -1591,6 +1631,7 @@ command is:
.Bl -tag -width Ds
.It Xo Ic copy-mode
.Op Fl eHMqu
+.Op Fl s Ar src-pane
.Op Fl t Ar target-pane
.Xc
Enter copy mode.
@@ -1604,6 +1645,11 @@ begins a mouse drag (only valid if bound to a mouse key binding, see
hides the position indicator in the top right.
.Fl q
cancels copy mode and any other modes.
+.Fl s
+copies from
+.Ar src-pane
+instead of
+.Ar target-pane .
.Pp
.Fl e
specifies that scrolling to the bottom of the history (to the visible screen)
@@ -1674,7 +1720,7 @@ 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 dP
+.Op Fl adP
.Op Fl F Ar format
.Op Fl n Ar window-name
.Op Fl s Ar src-pane
@@ -1685,6 +1731,10 @@ Break
.Ar src-pane
off from its containing window to make it the only pane in
.Ar dst-window .
+With
+.Fl a ,
+the window is moved to the next index up (following windows
+are moved if necessary).
If
.Fl d
is given, the new window does not become the current window.
@@ -1833,12 +1883,15 @@ The following keys may be used in tree mode:
.It Li "<" Ta "Scroll list of previews left"
.It Li ">" Ta "Scroll list of previews right"
.It Li "C-s" Ta "Search by name"
+.It Li "m" Ta "Set the marked pane"
+.It Li "M" Ta "Clear the marked pane"
.It Li "n" Ta "Repeat last search"
.It Li "t" Ta "Toggle if item is tagged"
.It Li "T" Ta "Tag no items"
.It Li "C-t" Ta "Tag all items"
.It Li "\&:" Ta "Run a command for each tagged item"
.It Li "f" Ta "Enter a format to filter items"
+.It Li "H" Ta "Jump to the starting pane"
.It Li "O" Ta "Change sort field"
.It Li "r" Ta "Reverse sort order"
.It Li "v" Ta "Toggle preview"
@@ -2039,6 +2092,7 @@ is given, the newly linked window is not selected.
.It Xo Ic list-panes
.Op Fl as
.Op Fl F Ar format
+.Op Fl f Ar filter
.Op Fl t Ar target
.Xc
.D1 (alias: Ic lsp )
@@ -2055,14 +2109,18 @@ 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
+specifies the format of each line and
+.Fl f
+a filter.
+Only panes for which the filter is true are shown.
+See the
.Sx FORMATS
section.
.It Xo Ic list-windows
.Op Fl a
.Op Fl F Ar format
+.Op Fl f Ar filter
.Op Fl t Ar target-session
.Xc
.D1 (alias: Ic lsw )
@@ -2071,25 +2129,23 @@ 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
+specifies the format of each line and
+.Fl f
+a filter.
+Only windows for which the filter is true are shown.
+See the
.Sx FORMATS
section.
.It Xo Ic move-pane
-.Op Fl bdhv
+.Op Fl bdfhv
.Op Fl l Ar size
.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.
+Does the same as
+.Ic join-pane .
.It Xo Ic move-window
.Op Fl ardk
.Op Fl s Ar src-window
@@ -2264,7 +2320,7 @@ Rename the current window, or the window at
if specified, to
.Ar new-name .
.It Xo Ic resize-pane
-.Op Fl DLMRUZ
+.Op Fl DLMRTUZ
.Op Fl t Ar target-pane
.Op Fl x Ar width
.Op Fl y Ar height
@@ -2303,6 +2359,10 @@ and unzoomed (its normal position in the layout).
.Fl M
begins mouse resizing (only valid if bound to a mouse key binding, see
.Sx MOUSE SUPPORT ) .
+.Pp
+.Fl T
+trims all lines below the current cursor position and moves lines out of the
+history to replace them.
.It Xo Ic resize-window
.Op Fl aADLRU
.Op Fl t Ar target-window
@@ -2661,7 +2721,7 @@ Commands related to key bindings are as follows:
.Op Fl nr
.Op Fl N Ar note
.Op Fl T Ar key-table
-.Ar key Ar command Op Ar arguments
+.Ar key command Op Ar arguments
.Xc
.D1 (alias: Ic bind )
Bind key
@@ -3049,12 +3109,20 @@ be set to
.Ql screen ,
.Ql tmux
or a derivative of them.
+.It Ic copy-command Ar shell-command
+Give the command to pipe to if the
+.Ic copy-pipe
+copy mode command is used without arguments.
.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 editor Ar shell-command
+Set the command used when
+.Nm
+runs an editor.
.It Xo Ic exit-empty
.Op Ic on | off
.Xc
@@ -3121,6 +3189,63 @@ disallowedWindowOps: 20,21,SetXprop
Or changing this property from the
.Xr xterm 1
interactive menu when required.
+.It Ic terminal-features[] Ar string
+Set terminal features for terminal types read from
+.Xr terminfo 5 .
+.Nm
+has a set of named terminal features.
+Each will apply appropriate changes to the
+.Xr terminfo 5
+entry in use.
+.Pp
+.Nm
+can detect features for a few common terminals; this option can be used to
+easily tell tmux about features supported by terminals it cannot detect.
+The
+.Ic terminal-overrides
+option allows individual
+.Xr terminfo 5
+capabilities to be set instead,
+.Ic terminal-features
+is intended for classes of functionality supported in a standard way but not
+reported by
+.Xr terminfo 5 .
+Care must be taken only to configure this with features the terminal actually
+support.
+.Pp
+This is an array option where each entry is a colon-separated string made up
+of a terminal type pattern (matched using
+.Xr fnmatch 3 )
+followed by a list of terminal features.
+The available features are:
+.Bl -tag -width Ds
+.It 256
+Supports 256 colours with the SGR escape sequences.
+.It clipboard
+Allows setting the system clipboard.
+.It ccolour
+Allows setting the cursor colour.
+.It cstyle
+Allows setting the cursor style.
+.It margins
+Supports DECSLRM margins.
+.It overline
+Supports the overline SGR attribute.
+.It rectfill
+Supports the DECFRA rectangle fill escape sequence.
+.It RGB
+Supports RGB colour with the SGR escape sequences.
+.It sync
+Supports synchronized updates.
+.It title
+Supports
+.Xr xterm 1
+title setting.
+.It usstyle
+Allows underscore style and colour to be set.
+.It UTF-8
+Is able to handle UTF-8 output.
+.El
.It Ic terminal-overrides[] Ar string
Allow terminal descriptions read using
.Xr terminfo 5
@@ -3291,6 +3416,9 @@ with
.Fl np .
.It Ic message-command-style Ar style
Set status line message command style.
+This is used for the command prompt with
+.Xr vi 1
+keys when in command mode.
For how to specify
.Ar style ,
see the
@@ -3298,6 +3426,7 @@ see the
section.
.It Ic message-style Ar style
Set status line message style.
+This is used for messages and for the command prompt.
For how to specify
.Ar style ,
see the
@@ -3594,6 +3723,25 @@ Set the width or height of the main (left or top) pane in the
or
.Ic main-vertical
layouts.
+If suffixed by
+.Ql % ,
+this is a percentage of the window size.
+.Pp
+.It Ic copy-mode-match-style Ar style
+Set the style of search matches in copy mode.
+For how to specify
+.Ar style ,
+see the
+.Sx STYLES
+section.
+.Pp
+.It Ic copy-mode-current-match-style Ar style
+Set the style of the current search match in copy mode.
+For how to specify
+.Ar style ,
+see the
+.Sx STYLES
+section.
.Pp
.It Xo Ic mode-keys
.Op Ic vi | emacs
@@ -3647,6 +3795,9 @@ 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.
+If suffixed by
+.Ql % ,
+this is a percentage of the window size.
.Pp
.It Ic other-pane-width Ar width
Like
@@ -3852,6 +4003,7 @@ hook and there are a number of hooks not associated with commands.
.Pp
Hooks are stored as array options, members of the array are executed in
order when the hook is triggered.
+Like options different hooks may be global or belong to a session, window or pane.
Hooks may be configured with the
.Ic set-hook
or
@@ -3944,8 +4096,8 @@ Run when a window is unlinked from a session.
Hooks are managed with these commands:
.Bl -tag -width Ds
.It Xo Ic set-hook
-.Op Fl agRu
-.Op Fl t Ar target-session
+.Op Fl agpRuw
+.Op Fl t Ar target-pane
.Ar hook-name
.Ar command
.Xc
@@ -3957,18 +4109,8 @@ unsets) hook
.Ar hook-name
to
.Ar command .
-If
-.Fl g
-is given,
-.Em hook-name
-is added to the global list of hooks, otherwise it is added to the session
-hooks (for
-.Ar target-session
-with
-.Fl t ) .
-.Fl a
-appends to a hook.
-Like options, session hooks inherit from the global ones.
+The flags are the same as for
+.Ic set-option .
.Pp
With
.Fl R ,
@@ -3976,12 +4118,12 @@ run
.Ar hook-name
immediately.
.It Xo Ic show-hooks
-.Op Fl g
-.Op Fl t Ar target-session
+.Op Fl gpw
+.Op Fl t Ar target-pane
.Xc
-Shows the global list of hooks with
-.Fl g ,
-otherwise the session hooks.
+Shows hooks.
+The flags are the same as for
+.Ic show-options .
.El
.Sh MOUSE SUPPORT
If the
@@ -4007,10 +4149,19 @@ The following mouse events are available:
.It Li "MouseDown1" Ta "MouseUp1" Ta "MouseDrag1" Ta "MouseDragEnd1"
.It Li "MouseDown2" Ta "MouseUp2" Ta "MouseDrag2" Ta "MouseDragEnd2"
.It Li "MouseDown3" Ta "MouseUp3" Ta "MouseDrag3" Ta "MouseDragEnd3"
+.It Li "SecondClick1" Ta "SecondClick2" Ta "SecondClick3"
.It Li "DoubleClick1" Ta "DoubleClick2" Ta "DoubleClick3"
.It Li "TripleClick1" Ta "TripleClick2" Ta "TripleClick3"
.El
.Pp
+The
+.Ql SecondClick
+events are fired for the second click of a double click, even if there may be a
+third click which will fire
+.Ql TripleClick
+instead of
+.Ql DoubleClick .
+.Pp
Each should be suffixed with a location, for example
.Ql MouseDown1Status .
.Pp
@@ -4137,7 +4288,7 @@ specifies an
.Xr fnmatch 3
or regular expression comparison.
The first argument is the pattern and the second the string to compare.
-An optional third argument specifies flags:
+An optional argument specifies flags:
.Ql r
means the pattern is a regular expression instead of the default
.Xr fnmatch 3
@@ -4164,6 +4315,38 @@ ignores case.
For example:
.Ql #{C/r:^Start}
.Pp
+Numeric operators may be performed by prefixing two comma-separated alternatives with an
+.Ql e
+and an operator.
+An optional
+.Ql f
+flag may be given after the operator to use floating point numbers, otherwise integers are used.
+This may be followed by a number giving the number of decimal places to use for the result.
+The available operators are:
+addition
+.Ql + ,
+subtraction
+.Ql - ,
+multiplication
+.Ql * ,
+division
+.Ql / ,
+and modulus
+.Ql m
+or
+.Ql %
+(note that
+.Ql %
+must be escaped as
+.Ql %%
+in formats which are also expanded by
+.Xr strftime 3 ) .
+For example,
+.Ql #{e|*|f|4:5.5,3}
+multiplies 5.5 by 3 for a result with four decimal places and
+.Ql #{e|%%:7,3}
+returns the modulus of 7 and 3.
+.Pp
A limit may be placed on the length of the resultant string by prefixing it
by an
.Ql = ,
@@ -4196,6 +4379,10 @@ gives
.Ql #{t:window_activity}
gives
.Ql Sun Oct 25 09:25:02 2015 .
+Adding
+.Ql p (
+.Ql `t/p` )
+will use shorter but less accurate time format for times in the past.
The
.Ql b:\&
and
@@ -4302,6 +4489,8 @@ The following variables are available, where appropriate:
.It Li "client_readonly" Ta "" Ta "1 if client is readonly"
.It Li "client_session" Ta "" Ta "Name of the client's session"
.It Li "client_termname" Ta "" Ta "Terminal name of client"
+.It Li "client_termtype" Ta "" Ta "Terminal type of client, if available"
+.It Li "client_termfeatures" Ta "" Ta "Terminal features of client, if any"
.It Li "client_tty" Ta "" Ta "Pseudo terminal of client"
.It Li "client_utf8" Ta "" Ta "1 if client supports UTF-8"
.It Li "client_width" Ta "" Ta "Width of client"
@@ -4369,6 +4558,7 @@ The following variables are available, where appropriate:
.It Li "pane_pipe" Ta "" Ta "1 if pane is being piped"
.It Li "pane_right" Ta "" Ta "Right of pane"
.It Li "pane_search_string" Ta "" Ta "Last search string in copy mode"
+.It Li "pane_skipped" Ta "" Ta "Bytes skipped as not visible in pane"
.It Li "pane_start_command" Ta "" Ta "Command pane started with"
.It Li "pane_synchronized" Ta "" Ta "1 if pane is synchronized"
.It Li "pane_tabs" Ta "" Ta "Pane tab positions"
@@ -4376,7 +4566,11 @@ The following variables are available, where appropriate:
.It Li "pane_top" Ta "" Ta "Top of pane"
.It Li "pane_tty" Ta "" Ta "Pseudo terminal of pane"
.It Li "pane_width" Ta "" Ta "Width of pane"
-.It Li "pid" Ta "" Ta "Server PID"
+.It Li "pane_written" Ta "" Ta "Bytes written by pane (aside from redrawing)"
+.It Li "pid" Ta "" Ta "Server PID"
+.It Li "popup_key" Ta "" Ta "Key pressed in popup"
+.It Li "popup_mouse_x" Ta "" Ta "Mouse X position in popup"
+.It Li "popup_mouse_y" Ta "" Ta "Mouse Y position in popup"
.It Li "rectangle_toggle" Ta "" Ta "1 if rectangle selection is activated"
.It Li "scroll_position" Ta "" Ta "Scroll position in copy mode"
.It Li "scroll_region_lower" Ta "" Ta "Bottom of scroll region in pane"
@@ -4403,7 +4597,9 @@ The following variables are available, where appropriate:
.It Li "session_id" Ta "" Ta "Unique session ID"
.It Li "session_last_attached" Ta "" Ta "Time session last attached"
.It Li "session_many_attached" Ta "" Ta "1 if multiple clients attached"
+.It Li "session_marked" Ta "" Ta "1 if this session contains the marked pane"
.It Li "session_name" Ta "#S" Ta "Name of session"
+.It Li "session_path" Ta "" Ta "Working directory of session"
.It Li "session_stack" Ta "" Ta "Window indexes in most recent order"
.It Li "session_windows" Ta "" Ta "Number of windows in session"
.It Li "socket_path" Ta "" Ta "Server socket path"
@@ -4492,7 +4688,8 @@ for the terminal default colour; or a hexadecimal RGB string such as
Set the background colour.
.It Ic none
Set no attributes (turn off any active attributes).
-.It Xo Ic bright
+.It Xo Ic acs ,
+.Ic bright
(or
.Ic bold ) ,
.Ic dim ,
@@ -4512,6 +4709,8 @@ Set an attribute.
Any of the attributes may be prefixed with
.Ql no
to unset.
+.Ic acs
+is the terminal alternate character set.
.It Xo Ic align=left
(or
.Ic noalign ) ,
@@ -4667,10 +4866,16 @@ from inside, and the
variable with the correct terminal setting of
.Ql screen .
.Pp
+Variables in both session and global environments may be marked as hidden.
+Hidden variables are not passed into the environment of new processes and
+instead can only be used by tmux itself (for example in formats, see the
+.Sx FORMATS
+section).
+.Pp
Commands to alter and view the environment are:
.Bl -tag -width Ds
.It Xo Ic set-environment
-.Op Fl gru
+.Op Fl hgru
.Op Fl t Ar target-session
.Ar name Op Ar value
.Xc
@@ -4687,8 +4892,10 @@ flag unsets a variable.
.Fl r
indicates the variable is to be removed from the environment before starting a
new process.
+.Fl h
+marks the variable as hidden.
.It Xo Ic show-environment
-.Op Fl gs
+.Op Fl hgs
.Op Fl t Ar target-session
.Op Ar variable
.Xc
@@ -4705,6 +4912,8 @@ Variables removed from the environment are prefixed with
If
.Fl s
is used, the output is formatted as a set of Bourne shell commands.
+.Fl h
+shows hidden variables (omitted by default).
.El
.Sh STATUS LINE
.Nm
@@ -4770,7 +4979,7 @@ session option.
Commands related to the status line are as follows:
.Bl -tag -width Ds
.It Xo Ic command-prompt
-.Op Fl 1ikN
+.Op Fl 1ikNTW
.Op Fl I Ar inputs
.Op Fl p Ar prompts
.Op Fl t Ar target-client
@@ -4829,6 +5038,14 @@ makes the prompt only accept numeric key presses.
.Fl i
executes the command every time the prompt input changes instead of when the
user exits the command prompt.
+.Fl T
+tells
+.Nm
+that the prompt is for a target which affects what completions are offered when
+.Em Tab
+is pressed;
+.Fl W
+is similar but indicates the prompt is for a window.
.Pp
The following keys have a special meaning in the command prompt, depending
on the value of the
@@ -4836,7 +5053,7 @@ on the value of the
option:
.Bl -column "FunctionXXXXXXXXXXXXXXXXXXXXXXXXX" "viXXXX" "emacsX" -offset indent
.It Sy "Function" Ta Sy "vi" Ta Sy "emacs"
-.It Li "Cancel command prompt" Ta "Escape" Ta "Escape"
+.It Li "Cancel command prompt" Ta "q" Ta "Escape"
.It Li "Delete from cursor to start of word" Ta "" Ta "C-w"
.It Li "Delete entire command" Ta "d" Ta "C-u"
.It Li "Delete from cursor to end" Ta "D" Ta "C-k"
@@ -4914,10 +5131,11 @@ give the position of the menu.
Both may be a row or column number, or one of the following special values:
.Bl -column "XXXXX" "XXXX" -offset indent
.It Sy "Value" Ta Sy "Flag" Ta Sy "Meaning"
+.It Li "C" Ta "Both" Ta "The centre of the terminal"
.It Li "R" Ta Fl x Ta "The right side of the terminal"
.It Li "P" Ta "Both" Ta "The bottom left of the pane"
.It Li "M" Ta "Both" Ta "The mouse position"
-.It Li "W" Ta Fl x Ta "The window position on the status line"
+.It Li "W" Ta "Both" Ta "The window position on the status line"
.It Li "S" Ta Fl y Ta "The line above or below the status line"
.El
.Pp
@@ -4965,6 +5183,97 @@ lists the format variables and their values.
.Fl I
forwards any input read from stdin to the empty pane given by
.Ar target-pane .
+.It Xo Ic display-popup
+.Op Fl CEK
+.Op Fl c Ar target-client
+.Op Fl d Ar start-directory
+.Op Fl h Ar height
+.Op Fl R Ar shell-command
+.Op Fl t Ar target-pane
+.Op Fl w Ar width
+.Op Fl x Ar position
+.Op Fl y Ar position
+.Op Ar command Ar line Ar ...
+.Xc
+.D1 (alias: Ic popup )
+Display a popup on
+.Ar target-client .
+A popup is a rectangular box drawn over the top of any panes.
+Panes are not updated while a popup is present.
+The popup content may be given in two ways:
+.Bl -enum -offset Ds
+.It
+A set of lines as arguments.
+Each line is a format which is expanded using
+.Ar target-pane
+as the target.
+If a line contains newlines it is split into multiple lines.
+Lines may use styles, see the
+.Sx STYLES
+section.
+.It
+A shell command given by
+.Fl R
+which is run and any output shown in the pane.
+.El
+.Pp
+The first argument,
+.Ar command ,
+is a
+.Nm
+command which is run when a key is pressed.
+The key is available in the
+.Ql popup_key
+format.
+After
+.Ar command
+is run, the popup is closed.
+It may be empty to discard any key presses.
+If
+.Fl K
+is given together with
+.Fl R ,
+key presses are instead passed to the
+.Fl R
+shell command.
+.Fl E
+closes the popup automatically when
+.Ar shell-command
+exits.
+Two
+.Fl E
+closes the popup only if
+.Ar shell-command
+exited with success.
+With
+.Fl K ,
+.Ql Escape
+and
+.Ql C-c
+close the popup unless
+.Fl E
+is also given.
+.Pp
+.Fl x
+and
+.Fl y
+give the position of the popup, they have the same meaning as for the
+.Ic display-menu
+command.
+.Fl w
+and
+.Fl h
+give the width and height - both may be a percentage (followed by
+.Ql % ) .
+If omitted, without
+.Fl R
+they are calculated from the given lines and with
+.Fl R
+they use half the terminal size.
+.Pp
+The
+.Fl C
+flag closes any popup on the client.
.El
.Sh BUFFERS
.Nm
@@ -5040,6 +5349,7 @@ The following keys may be used in buffer mode:
.It Li "P" Ta "Paste tagged buffers"
.It Li "d" Ta "Delete selected buffer"
.It Li "D" Ta "Delete tagged buffers"
+.It Li "e" Ta "Open the buffer in an editor"
.It Li "f" Ta "Enter a format to filter items"
.It Li "O" Ta "Change sort field"
.It Li "r" Ta "Reverse sort order"
@@ -5083,12 +5393,16 @@ Delete the buffer named
or the most recently added automatically named buffer if not specified.
.It Xo Ic list-buffers
.Op Fl F Ar format
+.Op Fl f Ar filter
.Xc
.D1 (alias: Ic lsb )
List the global buffers.
-For the meaning of the
.Fl F
-flag, see the
+specifies the format of each line and
+.Fl f
+a filter.
+Only buffers for which the filter is true are shown.
+See the
.Sx FORMATS
section.
.It Xo Ic load-buffer
@@ -5198,8 +5512,9 @@ Lock each client individually by running the command specified by the
option.
.It Xo Ic run-shell
.Op Fl b
+.Op Fl d Ar delay
.Op Fl t Ar target-pane
-.Ar shell-command
+.Op Ar shell-command
.Xc
.D1 (alias: Ic run )
Execute
@@ -5212,8 +5527,12 @@ section.
With
.Fl b ,
the command is run in the background.
-After it finishes, any output to stdout is displayed in copy mode (in the pane
-specified by
+.Fl d
+waits for
+.Ar delay
+seconds before starting the command.
+After the command finishes, any output to stdout is displayed in view mode (in
+the pane specified by
.Fl t
or the current pane if omitted).
If the command doesn't return success, the exit status is also displayed.
@@ -5267,9 +5586,16 @@ The server crashed or otherwise exited without telling the client the reason.
.Sh TERMINFO EXTENSIONS
.Nm
understands some unofficial extensions to
-.Xr terminfo 5 :
+.Xr terminfo 5 .
+It is not normally necessary to set these manually, instead the
+.Ic terminal-features
+option should be used.
.Bl -tag -width Ds
-.It Em Cs , Cr
+.It Em \&AX
+An existing extension that tells
+.Nm
+the terminal supports default colours.
+.It Em \&Cs , Cr
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.
@@ -5279,35 +5605,32 @@ to change the cursor colour from inside
.Bd -literal -offset indent
$ printf '\e033]12;red\e033\e\e'
.Ed
+.It Em \&Cmg, \&Clmg, \&Dsmg , \&Enmg
+Set, clear, disable or enable DECSLRM margins.
+These are set automatically if the terminal reports it is
+.Em VT420
+compatible.
+.It Em \&Dsbp , \&Enbp
+Disable and enable bracketed paste.
+These are set automatically if the
+.Em XT
+capability is present.
+.It Em \&Dsfcs , \&Enfcs
+Disable and enable focus reporting.
+These are set automatically if the
+.Em XT
+capability is present.
.It Em \&Smol
Enable the overline attribute.
-The capability is usually SGR 53 and can be added to
-.Ic terminal-overrides
-as:
-.Bd -literal -offset indent
-Smol=\eE[53m
-.Ed
.It Em \&Smulx
Set a styled underscore.
The single parameter is one of: 0 for no underscore, 1 for normal
underscore, 2 for double underscore, 3 for curly underscore, 4 for dotted
underscore and 5 for dashed underscore.
-The capability can typically be added to
-.Ic terminal-overrides
-as:
-.Bd -literal -offset indent
-Smulx=\eE[4::%p1%dm
-.Ed
.It Em \&Setulc
Set the underscore colour.
The argument is (red * 65536) + (green * 256) + blue where each is between 0
and 255.
-The capability can typically be added to
-.Ic terminal-overrides
-as:
-.Bd -literal -offset indent
-Setulc=\eE[58::2::%p1%{65536}%/%d::%p1%{256}%/%{255}%&%d::%p1%{255}%&%d%;m
-.Ed
.It Em \&Ss , Se
Set or reset the cursor style.
If set, a sequence such as this may be used
@@ -5319,6 +5642,8 @@ $ printf '\e033[4 q'
If
.Em Se
is not set, \&Ss with argument 0 will be used to reset the cursor style instead.
+.It Em \&Sync
+Start (parameter is 1) or end (parameter is 2) a synchronized update.
.It Em \&Tc
Indicate that the terminal supports the
.Ql direct colour
@@ -5333,6 +5658,11 @@ capabilities to the
.Nm
.Xr terminfo 5
entry).
+.Pp
+This is equivalent to the
+.Em RGB
+.Xr terminfo 5
+capability.
.It Em \&Ms
Store the current buffer in the host terminal's selection (clipboard).
See the
@@ -5340,6 +5670,11 @@ See the
option above and the
.Xr xterm 1
man page.
+.It Em \&XT
+This is an existing extension capability that tmux uses to mean that the
+terminal supports the
+.Xr xterm 1
+title set sequences and to automatically set some of the capabilities above.
.El
.Sh CONTROL MODE
.Nm
@@ -5385,7 +5720,7 @@ A notification will never occur inside an output block.
.Pp
The following notifications are defined:
.Bl -tag -width Ds
-.It Ic %client-session-changed Ar client Ar session-id Ar name
+.It Ic %client-session-changed Ar client session-id name
The client is now attached to the session with ID
.Ar session-id ,
which is named
diff --git a/tmux.c b/tmux.c
index 3c1feccc..48b3b8b9 100644
--- a/tmux.c
+++ b/tmux.c
@@ -26,6 +26,7 @@
#include <langinfo.h>
#include <locale.h>
#include <pwd.h>
+#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
@@ -46,15 +47,15 @@ const char *shell_command;
static __dead void usage(void);
static char *make_label(const char *, char **);
+static int areshell(const char *);
static const char *getshell(void);
-static int checkshell(const char *);
static __dead void
usage(void)
{
fprintf(stderr,
"usage: %s [-2CluvV] [-c shell-command] [-f file] [-L socket-name]\n"
- " [-S socket-path] [command [flags]]\n",
+ " [-S socket-path] [-T features] [command [flags]]\n",
getprogname());
exit(1);
}
@@ -76,7 +77,7 @@ getshell(void)
return (_PATH_BSHELL);
}
-static int
+int
checkshell(const char *shell)
{
if (shell == NULL || *shell != '/')
@@ -88,7 +89,7 @@ checkshell(const char *shell)
return (1);
}
-int
+static int
areshell(const char *shell)
{
const char *progname, *ptr;
@@ -106,33 +107,103 @@ areshell(const char *shell)
}
static char *
+expand_path(const char *path, const char *home)
+{
+ char *expanded, *name;
+ const char *end;
+ struct environ_entry *value;
+
+ if (strncmp(path, "~/", 2) == 0) {
+ if (home == NULL)
+ return (NULL);
+ xasprintf(&expanded, "%s%s", home, path + 1);
+ return (expanded);
+ }
+
+ if (*path == '$') {
+ end = strchr(path, '/');
+ if (end == NULL)
+ name = xstrdup(path + 1);
+ else
+ name = xstrndup(path + 1, end - path - 1);
+ value = environ_find(global_environ, name);
+ free(name);
+ if (value == NULL)
+ return (NULL);
+ if (end == NULL)
+ end = "";
+ xasprintf(&expanded, "%s%s", value->value, end);
+ return (expanded);
+ }
+
+ return (xstrdup(path));
+}
+
+void
+expand_paths(const char *s, char ***paths, u_int *n)
+{
+ const char *home = find_home();
+ char *copy, *next, *tmp, resolved[PATH_MAX], *expanded;
+ u_int i;
+
+ *paths = NULL;
+ *n = 0;
+
+ copy = tmp = xstrdup(s);
+ while ((next = strsep(&tmp, ":")) != NULL) {
+ expanded = expand_path(next, home);
+ if (expanded == NULL) {
+ log_debug("%s: invalid path: %s", __func__, next);
+ continue;
+ }
+ if (realpath(expanded, resolved) == NULL) {
+ log_debug("%s: realpath(\"%s\") failed: %s", __func__,
+ expanded, strerror(errno));
+ free(expanded);
+ continue;
+ }
+ free(expanded);
+ for (i = 0; i < *n; i++) {
+ if (strcmp(resolved, (*paths)[i]) == 0)
+ break;
+ }
+ if (i != *n) {
+ log_debug("%s: duplicate path: %s", __func__, resolved);
+ continue;
+ }
+ *paths = xreallocarray(*paths, (*n) + 1, sizeof *paths);
+ (*paths)[(*n)++] = xstrdup(resolved);
+ }
+ free(copy);
+}
+
+static char *
make_label(const char *label, char **cause)
{
- char *base, resolved[PATH_MAX], *path, *s;
- struct stat sb;
- uid_t uid;
+ char **paths, *path, *base;
+ u_int i, n;
+ struct stat sb;
+ uid_t uid;
*cause = NULL;
-
if (label == NULL)
label = "default";
uid = getuid();
- if ((s = getenv("TMUX_TMPDIR")) != NULL && *s != '\0')
- xasprintf(&base, "%s/tmux-%ld", s, (long)uid);
- else
- xasprintf(&base, "%s/tmux-%ld", _PATH_TMP, (long)uid);
- if (realpath(base, resolved) == NULL &&
- strlcpy(resolved, base, sizeof resolved) >= sizeof resolved) {
- errno = ERANGE;
- free(base);
- goto fail;
+ expand_paths(TMUX_SOCK, &paths, &n);
+ if (n == 0) {
+ xasprintf(cause, "no suitable socket path");
+ return (NULL);
}
- free(base);
+ path = paths[0]; /* can only have one socket! */
+ for (i = 1; i < n; i++)
+ free(paths[i]);
+ free(paths);
- if (mkdir(resolved, S_IRWXU) != 0 && errno != EEXIST)
+ xasprintf(&base, "%s/tmux-%ld", path, (long)uid);
+ if (mkdir(base, S_IRWXU) != 0 && errno != EEXIST)
goto fail;
- if (lstat(resolved, &sb) != 0)
+ if (lstat(base, &sb) != 0)
goto fail;
if (!S_ISDIR(sb.st_mode)) {
errno = ENOTDIR;
@@ -142,11 +213,13 @@ make_label(const char *label, char **cause)
errno = EACCES;
goto fail;
}
- xasprintf(&path, "%s/%s", resolved, label);
+ xasprintf(&path, "%s/%s", base, label);
+ free(base);
return (path);
fail:
- xasprintf(cause, "error creating %s (%s)", resolved, strerror(errno));
+ xasprintf(cause, "error creating %s (%s)", base, strerror(errno));
+ free(base);
return (NULL);
}
@@ -165,6 +238,19 @@ setblocking(int fd, int state)
}
const char *
+sig2name(int signo)
+{
+ static char s[11];
+
+#ifdef HAVE_SYS_SIGNAME
+ if (signo > 0 && signo < NSIG)
+ return (sys_signame[signo]);
+#endif
+ xsnprintf(s, sizeof s, "%d", signo);
+ return (s);
+}
+
+const char *
find_cwd(void)
{
char resolved1[PATH_MAX], resolved2[PATH_MAX];
@@ -219,9 +305,11 @@ getversion(void)
int
main(int argc, char **argv)
{
- char *path, *label, *cause, **var;
+ char *path = NULL, *label = NULL;
+ char *cause, **var;
const char *s, *shell, *cwd;
- int opt, flags, keys;
+ int opt, flags = 0, keys;
+ int feat = 0;
const struct options_table_entry *oe;
if (setlocale(LC_CTYPE, "en_US.UTF-8") == NULL &&
@@ -238,14 +326,11 @@ main(int argc, char **argv)
if (**argv == '-')
flags = CLIENT_LOGIN;
- else
- flags = 0;
- label = path = NULL;
- while ((opt = getopt(argc, argv, "2c:Cdf:lL:qS:uUvV")) != -1) {
+ while ((opt = getopt(argc, argv, "2c:Cdf:lL:qS:T:uUvV")) != -1) {
switch (opt) {
case '2':
- flags |= CLIENT_256COLOURS;
+ tty_add_features(&feat, "256", ":,");
break;
case 'c':
shell_command = optarg;
@@ -275,6 +360,9 @@ main(int argc, char **argv)
free(path);
path = xstrdup(optarg);
break;
+ case 'T':
+ tty_add_features(&feat, optarg, ":,");
+ break;
case 'u':
flags |= CLIENT_UTF8;
break;
@@ -321,9 +409,9 @@ main(int argc, char **argv)
global_environ = environ_create();
for (var = environ; *var != NULL; var++)
- environ_put(global_environ, *var);
+ environ_put(global_environ, *var, 0);
if ((cwd = find_cwd()) != NULL)
- environ_set(global_environ, "PWD", "%s", cwd);
+ environ_set(global_environ, "PWD", 0, "%s", cwd);
global_options = options_create(NULL);
global_s_options = options_create(NULL);
@@ -346,6 +434,7 @@ main(int argc, char **argv)
/* Override keys to vi if VISUAL or EDITOR are set. */
if ((s = getenv("VISUAL")) != NULL || (s = getenv("EDITOR")) != NULL) {
+ options_set_string(global_options, "editor", 0, "%s", s);
if (strrchr(s, '/') != NULL)
s = strrchr(s, '/') + 1;
if (strstr(s, "vi") != NULL)
@@ -368,16 +457,19 @@ main(int argc, char **argv)
path[strcspn(path, ",")] = '\0';
}
}
- if (path == NULL && (path = make_label(label, &cause)) == NULL) {
- if (cause != NULL) {
- fprintf(stderr, "%s\n", cause);
- free(cause);
+ if (path == NULL) {
+ if ((path = make_label(label, &cause)) == NULL) {
+ if (cause != NULL) {
+ fprintf(stderr, "%s\n", cause);
+ free(cause);
+ }
+ exit(1);
}
- exit(1);
+ flags |= CLIENT_DEFAULTSOCKET;
}
socket_path = path;
free(label);
/* Pass control to the client. */
- exit(client_main(osdep_event_init(), argc, argv, flags));
+ exit(client_main(osdep_event_init(), argc, argv, flags, feat));
}
diff --git a/tmux.h b/tmux.h
index 3720beee..a1f6d924 100644
--- a/tmux.h
+++ b/tmux.h
@@ -41,9 +41,12 @@ extern char **environ;
struct args;
struct args_value;
struct client;
+struct cmd;
struct cmd_find_state;
struct cmdq_item;
struct cmdq_list;
+struct cmdq_state;
+struct cmds;
struct environ;
struct format_job_tree;
struct format_tree;
@@ -52,9 +55,13 @@ struct job;
struct mode_tree_data;
struct mouse_event;
struct options;
-struct options_entry;
struct options_array_item;
+struct options_entry;
+struct screen_write_collect_item;
+struct screen_write_collect_line;
+struct screen_write_ctx;
struct session;
+struct tty_ctx;
struct tmuxpeer;
struct tmuxproc;
struct winlink;
@@ -62,10 +69,13 @@ struct winlink;
/* Client-server protocol version. */
#define PROTOCOL_VERSION 8
-/* Default configuration files. */
+/* Default configuration files and socket paths. */
#ifndef TMUX_CONF
#define TMUX_CONF "/etc/tmux.conf:~/.tmux.conf"
#endif
+#ifndef TMUX_SOCK
+#define TMUX_SOCK "$TMUX_TMPDIR:" _PATH_TMP
+#endif
/* Minimum layout cell size, NOT including border lines. */
#define PANE_MINIMUM 1
@@ -78,7 +88,7 @@ struct winlink;
#define NAME_INTERVAL 500000
/* Maximum size of data to hold from a pane. */
-#define READ_SIZE 4096
+#define READ_SIZE 8192
/* Default pixel cell sizes. */
#define DEFAULT_XPIXEL 16
@@ -104,24 +114,24 @@ struct winlink;
#define VISUAL_BOTH 2
/* Special key codes. */
-#define KEYC_NONE 0xffff00000000ULL
-#define KEYC_UNKNOWN 0xfffe00000000ULL
-#define KEYC_BASE 0x000010000000ULL
-#define KEYC_USER 0x000020000000ULL
+#define KEYC_NONE 0x00ff000000000ULL
+#define KEYC_UNKNOWN 0x00fe000000000ULL
+#define KEYC_BASE 0x0001000000000ULL
+#define KEYC_USER 0x0002000000000ULL
+
+/* Key modifier bits. */
+#define KEYC_ESCAPE 0x0100000000000ULL
+#define KEYC_CTRL 0x0200000000000ULL
+#define KEYC_SHIFT 0x0400000000000ULL
+#define KEYC_XTERM 0x0800000000000ULL
+#define KEYC_LITERAL 0x1000000000000ULL
/* Available user keys. */
#define KEYC_NUSER 1000
-/* Key modifier bits. */
-#define KEYC_ESCAPE 0x200000000000ULL
-#define KEYC_CTRL 0x400000000000ULL
-#define KEYC_SHIFT 0x800000000000ULL
-#define KEYC_XTERM 0x1000000000000ULL
-#define KEYC_LITERAL 0x2000000000000ULL
-
/* Mask to obtain key w/o modifiers. */
-#define KEYC_MASK_MOD (KEYC_ESCAPE|KEYC_CTRL|KEYC_SHIFT|KEYC_XTERM|KEYC_LITERAL)
-#define KEYC_MASK_KEY (~KEYC_MASK_MOD)
+#define KEYC_MASK_MOD 0xff00000000000ULL
+#define KEYC_MASK_KEY 0x00fffffffffffULL
/* Is this a mouse key? */
#define KEYC_IS_MOUSE(key) (((key) & KEYC_MASK_KEY) >= KEYC_MOUSE && \
@@ -168,6 +178,7 @@ enum {
/* Mouse keys. */
KEYC_MOUSE, /* unclassified mouse event */
KEYC_DRAGGING, /* dragging in progress */
+ KEYC_DOUBLECLICK, /* double click complete */
KEYC_MOUSE_KEY(MOUSEMOVE),
KEYC_MOUSE_KEY(MOUSEDOWN1),
KEYC_MOUSE_KEY(MOUSEDOWN2),
@@ -183,6 +194,9 @@ enum {
KEYC_MOUSE_KEY(MOUSEDRAGEND3),
KEYC_MOUSE_KEY(WHEELUP),
KEYC_MOUSE_KEY(WHEELDOWN),
+ KEYC_MOUSE_KEY(SECONDCLICK1),
+ KEYC_MOUSE_KEY(SECONDCLICK2),
+ KEYC_MOUSE_KEY(SECONDCLICK3),
KEYC_MOUSE_KEY(DOUBLECLICK1),
KEYC_MOUSE_KEY(DOUBLECLICK2),
KEYC_MOUSE_KEY(DOUBLECLICK3),
@@ -249,6 +263,8 @@ enum tty_code_code {
TTYC_BOLD,
TTYC_CIVIS,
TTYC_CLEAR,
+ TTYC_CLMG,
+ TTYC_CMG,
TTYC_CNORM,
TTYC_COLORS,
TTYC_CR,
@@ -269,12 +285,18 @@ enum tty_code_code {
TTYC_DIM,
TTYC_DL,
TTYC_DL1,
+ TTYC_DSBP,
+ TTYC_DSFCS,
+ TTYC_DSMG,
TTYC_E3,
TTYC_ECH,
TTYC_ED,
TTYC_EL,
TTYC_EL1,
TTYC_ENACS,
+ TTYC_ENBP,
+ TTYC_ENFCS,
+ TTYC_ENMG,
TTYC_FSL,
TTYC_HOME,
TTYC_HPA,
@@ -440,19 +462,20 @@ enum tty_code_code {
TTYC_SITM,
TTYC_SMACS,
TTYC_SMCUP,
- TTYC_SMOL,
TTYC_SMKX,
+ TTYC_SMOL,
TTYC_SMSO,
- TTYC_SMULX,
TTYC_SMUL,
+ TTYC_SMULX,
TTYC_SMXX,
TTYC_SS,
+ TTYC_SYNC,
TTYC_TC,
TTYC_TSL,
TTYC_U8,
TTYC_VPA,
TTYC_XENL,
- TTYC_XT,
+ TTYC_XT
};
/* Message codes. */
@@ -468,6 +491,7 @@ enum msgtype {
MSG_IDENTIFY_DONE,
MSG_IDENTIFY_CLIENTPID,
MSG_IDENTIFY_CWD,
+ MSG_IDENTIFY_FEATURES,
MSG_COMMAND = 200,
MSG_DETACH,
@@ -562,6 +586,7 @@ struct msg_write_close {
#define ALL_MODES 0xffffff
#define ALL_MOUSE_MODES (MODE_MOUSE_STANDARD|MODE_MOUSE_BUTTON|MODE_MOUSE_ALL)
+#define MOTION_MOUSE_MODES (MODE_MOUSE_BUTTON|MODE_MOUSE_ALL)
/*
* A single UTF-8 character. UTF8_SIZE must be big enough to hold
@@ -754,20 +779,30 @@ struct screen {
int mode;
- bitstr_t *tabs;
+ u_int saved_cx;
+ u_int saved_cy;
+ struct grid *saved_grid;
+ struct grid_cell saved_cell;
+ int saved_flags;
+ bitstr_t *tabs;
struct screen_sel *sel;
+
+ struct screen_write_collect_line *write_list;
};
/* Screen write context. */
-struct screen_write_collect_item;
-struct screen_write_collect_line;
+typedef void (*screen_write_init_ctx_cb)(struct screen_write_ctx *,
+ struct tty_ctx *);
struct screen_write_ctx {
struct window_pane *wp;
struct screen *s;
+ int sync;
+
+ screen_write_init_ctx_cb init_ctx_cb;
+ void *arg;
struct screen_write_collect_item *item;
- struct screen_write_collect_line *list;
u_int scrolled;
u_int bg;
@@ -810,7 +845,6 @@ struct menu {
u_int width;
};
typedef void (*menu_choice_cb)(struct menu *, u_int, key_code, void *);
-#define MENU_NOMOUSE 0x1
/*
* Window mode. Windows can be in several modes and this is used to call the
@@ -836,11 +870,11 @@ struct window_mode {
void (*formats)(struct window_mode_entry *,
struct format_tree *);
};
-#define WINDOW_MODE_TIMEOUT 180
/* Active window mode. */
struct window_mode_entry {
struct window_pane *wp;
+ struct window_pane *swp;
const struct window_mode *mode;
void *data;
@@ -871,6 +905,9 @@ struct window_pane {
u_int xoff;
u_int yoff;
+ int fg;
+ int bg;
+
int flags;
#define PANE_REDRAW 0x1
#define PANE_DROP 0x2
@@ -898,14 +935,13 @@ struct window_pane {
int fd;
struct bufferevent *event;
- u_int disabled;
struct event resize_timer;
struct input_ctx *ictx;
- struct style cached_style;
- struct style cached_active_style;
+ struct grid_cell cached_gc;
+ struct grid_cell cached_active_gc;
int *palette;
int pipe_fd;
@@ -918,19 +954,17 @@ struct window_pane {
struct screen status_screen;
size_t status_size;
- /* Saved in alternative screen mode. */
- u_int saved_cx;
- u_int saved_cy;
- struct grid *saved_grid;
- struct grid_cell saved_cell;
-
TAILQ_HEAD (, window_mode_entry) modes;
- struct event modetimer;
- time_t modelast;
char *searchstr;
int searchregex;
+ size_t written;
+ size_t skipped;
+
+ int border_gc_set;
+ struct grid_cell border_gc;
+
TAILQ_ENTRY(window_pane) entry;
RB_ENTRY(window_pane) tree_entry;
};
@@ -1048,6 +1082,9 @@ struct environ_entry {
char *name;
char *value;
+ int flags;
+#define ENVIRON_HIDDEN 0x1
+
RB_ENTRY(environ_entry) entry;
};
@@ -1120,6 +1157,7 @@ RB_HEAD(sessions, session);
/* Mouse input. */
struct mouse_event {
int valid;
+ int ignore;
key_code key;
@@ -1165,7 +1203,8 @@ struct tty_key {
struct tty_code;
struct tty_term {
char *name;
- u_int references;
+ struct tty *tty;
+ int features;
char acs[UCHAR_MAX + 1][2];
@@ -1176,6 +1215,7 @@ struct tty_term {
#define TERM_DECSLRM 0x4
#define TERM_DECFRA 0x8
#define TERM_RGBCOLOURS 0x10
+#define TERM_VT100LIKE 0x20
int flags;
LIST_ENTRY(tty_term) entry;
@@ -1221,25 +1261,22 @@ struct tty {
struct termios tio;
struct grid_cell cell;
-
- int last_wp;
struct grid_cell last_cell;
#define TTY_NOCURSOR 0x1
#define TTY_FREEZE 0x2
#define TTY_TIMER 0x4
-#define TTY_UTF8 0x8
+/* 0x8 unused */
#define TTY_STARTED 0x10
#define TTY_OPENED 0x20
#define TTY_FOCUS 0x40
#define TTY_BLOCK 0x80
#define TTY_HAVEDA 0x100
-#define TTY_HAVEDSR 0x200
+#define TTY_HAVEXDA 0x200
+#define TTY_SYNCING 0x400
int flags;
struct tty_term *term;
- char *term_name;
- int term_flags;
u_int mouse_last_x;
u_int mouse_last_y;
@@ -1255,8 +1292,14 @@ struct tty {
};
/* TTY command context. */
+typedef void (*tty_ctx_redraw_cb)(const struct tty_ctx *);
+typedef int (*tty_ctx_set_client_cb)(struct tty_ctx *, struct client *);
struct tty_ctx {
- struct window_pane *wp;
+ struct screen *s;
+
+ tty_ctx_redraw_cb redraw_cb;
+ tty_ctx_set_client_cb set_client_cb;
+ void *arg;
const struct grid_cell *cell;
int wrapped;
@@ -1275,19 +1318,27 @@ struct tty_ctx {
u_int orupper;
u_int orlower;
- /* Pane offset. */
+ /* Target region (usually pane) offset and size. */
u_int xoff;
u_int yoff;
+ u_int rxoff;
+ u_int ryoff;
+ u_int sx;
+ u_int sy;
/* The background colour used for clearing (erasing). */
u_int bg;
- /* Window offset and size. */
+ /* The default colours and palette. */
+ struct grid_cell defaults;
+ int *palette;
+
+ /* Containing region (usually window) offset and size. */
int bigger;
- u_int ox;
- u_int oy;
- u_int sx;
- u_int sy;
+ u_int wox;
+ u_int woy;
+ u_int wsx;
+ u_int wsy;
};
/* Saved message entry. */
@@ -1333,27 +1384,11 @@ struct cmd_find_state {
#define CMD_FIND_EXACT_WINDOW 0x20
#define CMD_FIND_CANFAIL 0x40
-/* Command and list of commands. */
-struct cmd {
- const struct cmd_entry *entry;
- struct args *args;
- u_int group;
-
- char *file;
- u_int line;
-
- char *alias;
- int argc;
- char **argv;
-
- TAILQ_ENTRY(cmd) qentry;
-};
-TAILQ_HEAD(cmds, cmd);
-
+/* List of commands. */
struct cmd_list {
- int references;
- u_int group;
- struct cmds list;
+ int references;
+ u_int group;
+ struct cmds *list;
};
/* Command return values. */
@@ -1381,6 +1416,7 @@ struct cmd_parse_input {
#define CMD_PARSE_PARSEONLY 0x2
#define CMD_PARSE_NOALIAS 0x4
#define CMD_PARSE_VERBOSE 0x8
+#define CMD_PARSE_ONEGROUP 0x10
const char *file;
u_int line;
@@ -1390,59 +1426,13 @@ struct cmd_parse_input {
struct cmd_find_state fs;
};
-/* Command queue item type. */
-enum cmdq_type {
- CMDQ_COMMAND,
- CMDQ_CALLBACK,
-};
-
-/* Command queue item shared state. */
-struct cmdq_shared {
- int references;
-
- int flags;
-#define CMDQ_SHARED_REPEAT 0x1
-#define CMDQ_SHARED_CONTROL 0x2
-
- struct format_tree *formats;
-
- struct mouse_event mouse;
- struct cmd_find_state current;
-};
+/* Command queue flags. */
+#define CMDQ_STATE_REPEAT 0x1
+#define CMDQ_STATE_CONTROL 0x2
+#define CMDQ_STATE_NOHOOKS 0x4
-/* Command queue item. */
+/* Command queue callback. */
typedef enum cmd_retval (*cmdq_cb) (struct cmdq_item *, void *);
-struct cmdq_item {
- char *name;
- struct cmdq_list *queue;
- struct cmdq_item *next;
-
- struct client *client;
-
- enum cmdq_type type;
- u_int group;
-
- u_int number;
- time_t time;
-
- int flags;
-#define CMDQ_FIRED 0x1
-#define CMDQ_WAITING 0x2
-#define CMDQ_NOHOOKS 0x4
-
- struct cmdq_shared *shared;
- struct cmd_find_state source;
- struct cmd_find_state target;
-
- struct cmd_list *cmdlist;
- struct cmd *cmd;
-
- cmdq_cb cb;
- void *data;
-
- TAILQ_ENTRY(cmdq_item) entry;
-};
-TAILQ_HEAD(cmdq_list, cmdq_item);
/* Command definition flag. */
struct cmd_entry_flag {
@@ -1469,6 +1459,9 @@ struct cmd_entry {
#define CMD_STARTSERVER 0x1
#define CMD_READONLY 0x2
#define CMD_AFTERHOOK 0x4
+#define CMD_CLIENT_CFLAG 0x8
+#define CMD_CLIENT_TFLAG 0x10
+#define CMD_CLIENT_CANFAIL 0x20
int flags;
enum cmd_retval (*exec)(struct cmd *, struct cmdq_item *);
@@ -1517,13 +1510,15 @@ RB_HEAD(client_files, client_file);
/* Client connection. */
typedef int (*prompt_input_cb)(struct client *, void *, const char *, int);
typedef void (*prompt_free_cb)(void *);
+typedef int (*overlay_check_cb)(struct client *, u_int, u_int);
+typedef struct screen *(*overlay_mode_cb)(struct client *, u_int *, u_int *);
typedef void (*overlay_draw_cb)(struct client *, struct screen_redraw_ctx *);
typedef int (*overlay_key_cb)(struct client *, struct key_event *);
typedef void (*overlay_free_cb)(struct client *);
struct client {
const char *name;
struct tmuxpeer *peer;
- struct cmdq_list queue;
+ struct cmdq_list *queue;
pid_t pid;
int fd;
@@ -1539,7 +1534,10 @@ struct client {
char *title;
const char *cwd;
- char *term;
+ char *term_name;
+ int term_features;
+ char *term_type;
+
char *ttyname;
struct tty tty;
@@ -1551,6 +1549,7 @@ struct client {
struct event click_timer;
u_int click_button;
+ struct mouse_event click_event;
struct status_line status;
@@ -1571,7 +1570,7 @@ struct client {
#define CLIENT_CONTROLCONTROL 0x4000
#define CLIENT_FOCUSED 0x8000
#define CLIENT_UTF8 0x10000
-#define CLIENT_256COLOURS 0x20000
+/* 0x20000 unused */
#define CLIENT_IDENTIFIED 0x40000
#define CLIENT_STATUSFORCE 0x80000
#define CLIENT_DOUBLECLICK 0x100000
@@ -1581,12 +1580,16 @@ struct client {
#define CLIENT_REDRAWSTATUSALWAYS 0x1000000
#define CLIENT_REDRAWOVERLAY 0x2000000
#define CLIENT_CONTROL_NOOUTPUT 0x4000000
+#define CLIENT_DEFAULTSOCKET 0x8000000
+#define CLIENT_STARTSERVER 0x10000000
+#define CLIENT_REDRAWPANES 0x20000000
#define CLIENT_ALLREDRAWFLAGS \
(CLIENT_REDRAWWINDOW| \
CLIENT_REDRAWSTATUS| \
CLIENT_REDRAWSTATUSALWAYS| \
CLIENT_REDRAWBORDERS| \
- CLIENT_REDRAWOVERLAY)
+ CLIENT_REDRAWOVERLAY| \
+ CLIENT_REDRAWPANES)
#define CLIENT_UNATTACHEDFLAGS \
(CLIENT_DEAD| \
CLIENT_SUSPENDED| \
@@ -1598,6 +1601,8 @@ struct client {
int flags;
struct key_table *keytable;
+ uint64_t redraw_panes;
+
char *message_string;
struct event message_timer;
u_int message_next;
@@ -1618,6 +1623,8 @@ struct client {
#define PROMPT_INCREMENTAL 0x4
#define PROMPT_NOFORMAT 0x8
#define PROMPT_KEY 0x10
+#define PROMPT_WINDOW 0x20
+#define PROMPT_TARGET 0x40
int prompt_flags;
struct session *session;
@@ -1629,6 +1636,8 @@ struct client {
u_int pan_ox;
u_int pan_oy;
+ overlay_check_cb overlay_check;
+ overlay_mode_cb overlay_mode;
overlay_draw_cb overlay_draw;
overlay_key_cb overlay_key;
overlay_free_cb overlay_free;
@@ -1682,7 +1691,6 @@ enum options_table_type {
OPTIONS_TABLE_COLOUR,
OPTIONS_TABLE_FLAG,
OPTIONS_TABLE_CHOICE,
- OPTIONS_TABLE_STYLE,
OPTIONS_TABLE_COMMAND
};
@@ -1694,12 +1702,13 @@ enum options_table_type {
#define OPTIONS_TABLE_IS_ARRAY 0x1
#define OPTIONS_TABLE_IS_HOOK 0x2
+#define OPTIONS_TABLE_IS_STYLE 0x4
struct options_table_entry {
const char *name;
enum options_table_type type;
int scope;
- int flags;
+ int flags;
u_int minimum;
u_int maximum;
@@ -1730,7 +1739,7 @@ struct spawn_context {
struct session *s;
struct winlink *wl;
- struct client *c;
+ struct client *tc;
struct window_pane *wp0;
struct layout_cell *lc;
@@ -1738,7 +1747,7 @@ struct spawn_context {
const char *name;
char **argv;
int argc;
- struct environ *environ;
+ struct environ *environ;
int idx;
const char *cwd;
@@ -1769,11 +1778,14 @@ extern const char *socket_path;
extern const char *shell_command;
extern int ptm_fd;
extern const char *shell_command;
-int areshell(const char *);
+int checkshell(const char *);
void setblocking(int, int);
+const char *sig2name(int);
const char *find_cwd(void);
const char *find_home(void);
const char *getversion(void);
+void expand_paths(const char *, char ***, u_int *);
+
/* proc.c */
struct imsg;
@@ -1815,6 +1827,7 @@ void paste_free(struct paste_buffer *);
void paste_add(const char *, char *, size_t);
int paste_rename(const char *, const char *, char **);
int paste_set(char *, size_t, const char *, char **);
+void paste_replace(struct paste_buffer *, char *, size_t);
char *paste_make_sample(struct paste_buffer *);
/* format.c */
@@ -1826,11 +1839,13 @@ char *paste_make_sample(struct paste_buffer *);
#define FORMAT_PANE 0x80000000U
#define FORMAT_WINDOW 0x40000000U
struct format_tree;
+struct format_modifier;
const char *format_skip(const char *, const char *);
int format_true(const char *);
struct format_tree *format_create(struct client *, struct cmdq_item *, int,
int);
void format_free(struct format_tree *);
+void format_merge(struct format_tree *, struct format_tree *);
void printflike(3, 4) format_add(struct format_tree *, const char *,
const char *, ...);
void format_each(struct format_tree *, void (*)(const char *,
@@ -1840,6 +1855,14 @@ char *format_expand(struct format_tree *, const char *);
char *format_single(struct cmdq_item *, const char *,
struct client *, struct session *, struct winlink *,
struct window_pane *);
+char *format_single_from_state(struct cmdq_item *, const char *,
+ struct client *, struct cmd_find_state *);
+char *format_single_from_target(struct cmdq_item *, const char *);
+struct format_tree *format_create_defaults(struct cmdq_item *, struct client *,
+ struct session *, struct winlink *, struct window_pane *);
+struct format_tree *format_create_from_state(struct cmdq_item *,
+ struct client *, struct cmd_find_state *);
+struct format_tree *format_create_from_target(struct cmdq_item *);
void format_defaults(struct format_tree *, struct client *,
struct session *, struct winlink *, struct window_pane *);
void format_defaults_window(struct format_tree *, struct window *);
@@ -1905,18 +1928,17 @@ struct options_entry *options_match_get(struct options *, const char *, int *,
int, int *);
const char *options_get_string(struct options *, const char *);
long long options_get_number(struct options *, const char *);
-struct style *options_get_style(struct options *, const char *);
struct options_entry * printflike(4, 5) options_set_string(struct options *,
const char *, int, const char *, ...);
struct options_entry *options_set_number(struct options *, const char *,
long long);
-struct options_entry *options_set_style(struct options *, const char *, int,
- const char *);
int options_scope_from_name(struct args *, int,
const char *, struct cmd_find_state *, struct options **,
char **);
int options_scope_from_flags(struct args *, int,
struct cmd_find_state *, struct options **, char **);
+struct style *options_string_to_style(struct options *, const char *,
+ struct format_tree *);
/* options-table.c */
extern const struct options_table_entry options_table[];
@@ -1926,9 +1948,13 @@ typedef void (*job_update_cb) (struct job *);
typedef void (*job_complete_cb) (struct job *);
typedef void (*job_free_cb) (void *);
#define JOB_NOWAIT 0x1
+#define JOB_KEEPWRITE 0x2
+#define JOB_PTY 0x4
struct job *job_run(const char *, struct session *, const char *,
- job_update_cb, job_complete_cb, job_free_cb, void *, int);
+ job_update_cb, job_complete_cb, job_free_cb, void *, int,
+ int, int);
void job_free(struct job *);
+void job_resize(struct job *, u_int, u_int);
void job_check_died(pid_t, int);
int job_get_status(struct job *);
void *job_get_data(struct job *);
@@ -1944,10 +1970,10 @@ struct environ_entry *environ_first(struct environ *);
struct environ_entry *environ_next(struct environ_entry *);
void environ_copy(struct environ *, struct environ *);
struct environ_entry *environ_find(struct environ *, const char *);
-void printflike(3, 4) environ_set(struct environ *, const char *, const char *,
- ...);
+void printflike(4, 5) environ_set(struct environ *, const char *, int,
+ const char *, ...);
void environ_clear(struct environ *, const char *);
-void environ_put(struct environ *, const char *);
+void environ_put(struct environ *, const char *, int);
void environ_unset(struct environ *, const char *);
void environ_update(struct options *, struct environ *, struct environ *);
void environ_push(struct environ *);
@@ -1962,7 +1988,7 @@ void tty_update_window_offset(struct window *);
void tty_update_client_offset(struct client *);
void tty_raw(struct tty *, const char *);
void tty_attributes(struct tty *, const struct grid_cell *,
- struct window_pane *);
+ const struct grid_cell *, int *);
void tty_reset(struct tty *);
void tty_region_off(struct tty *);
void tty_margin_off(struct tty *);
@@ -1977,19 +2003,22 @@ void tty_putcode_ptr2(struct tty *, enum tty_code_code, const void *,
void tty_puts(struct tty *, const char *);
void tty_putc(struct tty *, u_char);
void tty_putn(struct tty *, const void *, size_t, u_int);
-int tty_init(struct tty *, struct client *, int, char *);
+int tty_init(struct tty *, struct client *, int);
void tty_resize(struct tty *);
void tty_set_size(struct tty *, u_int, u_int, u_int, u_int);
void tty_start_tty(struct tty *);
+void tty_send_requests(struct tty *);
void tty_stop_tty(struct tty *);
void tty_set_title(struct tty *, const char *);
void tty_update_mode(struct tty *, int, struct screen *);
-void tty_draw_line(struct tty *, struct window_pane *, struct screen *,
- u_int, u_int, u_int, u_int, u_int);
+void tty_draw_line(struct tty *, struct screen *, u_int, u_int, u_int,
+ u_int, u_int, const struct grid_cell *, int *);
+void tty_sync_start(struct tty *);
+void tty_sync_end(struct tty *);
int tty_open(struct tty *, char **);
void tty_close(struct tty *);
void tty_free(struct tty *);
-void tty_set_flags(struct tty *, int);
+void tty_update_features(struct tty *);
void tty_write(void (*)(struct tty *, const struct tty_ctx *),
struct tty_ctx *);
void tty_cmd_alignmenttest(struct tty *, const struct tty_ctx *);
@@ -2013,11 +2042,15 @@ void tty_cmd_scrolldown(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_cmd_syncstart(struct tty *, const struct tty_ctx *);
+void tty_default_colours(struct grid_cell *, struct window_pane *);
/* tty-term.c */
extern struct tty_terms tty_terms;
u_int tty_term_ncodes(void);
-struct tty_term *tty_term_find(char *, int, char **);
+void tty_term_apply(struct tty_term *, const char *, int);
+void tty_term_apply_overrides(struct tty_term *);
+struct tty_term *tty_term_create(struct tty *, char *, int *, 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);
@@ -2034,6 +2067,12 @@ int tty_term_number(struct tty_term *, enum tty_code_code);
int tty_term_flag(struct tty_term *, enum tty_code_code);
const char *tty_term_describe(struct tty_term *, enum tty_code_code);
+/* tty-features.c */
+void tty_add_features(int *, const char *, const char *);
+const char *tty_get_features(int);
+int tty_apply_features(struct tty_term *, int);
+void tty_default_features(int *, const char *, u_int);
+
/* tty-acs.c */
int tty_acs_needed(struct tty *);
const char *tty_acs_get(struct tty *, u_char);
@@ -2055,6 +2094,10 @@ const char *args_first_value(struct args *, u_char, struct args_value **);
const char *args_next_value(struct args_value **);
long long args_strtonum(struct args *, u_char, long long, long long,
char **);
+long long args_percentage(struct args *, u_char, long long,
+ long long, long long, char **);
+long long args_string_percentage(const char *, long long, long long,
+ long long, char **);
/* cmd-find.c */
int cmd_find_target(struct cmd_find_state *, struct cmdq_item *,
@@ -2085,6 +2128,7 @@ int cmd_find_from_mouse(struct cmd_find_state *,
int cmd_find_from_nothing(struct cmd_find_state *, int);
/* cmd.c */
+extern const struct cmd_entry *cmd_table[];
void printflike(3, 4) cmd_log_argv(int, char **, const char *, ...);
void cmd_prepend_argv(int *, char ***, char *);
void cmd_append_argv(int *, char ***, char *);
@@ -2094,41 +2138,70 @@ char **cmd_copy_argv(int, char **);
void cmd_free_argv(int, char **);
char *cmd_stringify_argv(int, char **);
char *cmd_get_alias(const char *);
+const struct cmd_entry *cmd_get_entry(struct cmd *);
+struct args *cmd_get_args(struct cmd *);
+u_int cmd_get_group(struct cmd *);
+void cmd_get_source(struct cmd *, const char **, u_int *);
struct cmd *cmd_parse(int, char **, const char *, u_int, char **);
void cmd_free(struct cmd *);
char *cmd_print(struct cmd *);
+struct cmd_list *cmd_list_new(void);
+void cmd_list_append(struct cmd_list *, struct cmd *);
+void cmd_list_move(struct cmd_list *, struct cmd_list *);
+void cmd_list_free(struct cmd_list *);
+char *cmd_list_print(struct cmd_list *, int);
+struct cmd *cmd_list_first(struct cmd_list *);
+struct cmd *cmd_list_next(struct cmd *);
+int cmd_list_all_have(struct cmd_list *, int);
+int cmd_list_any_have(struct cmd_list *, int);
int cmd_mouse_at(struct window_pane *, struct mouse_event *,
u_int *, u_int *, int);
struct winlink *cmd_mouse_window(struct mouse_event *, struct session **);
struct window_pane *cmd_mouse_pane(struct mouse_event *, struct session **,
struct winlink **);
char *cmd_template_replace(const char *, const char *, int);
-extern const struct cmd_entry *cmd_table[];
/* cmd-attach-session.c */
enum cmd_retval cmd_attach_session(struct cmdq_item *, const char *, int, int,
int, const char *, int);
/* cmd-parse.c */
-void cmd_parse_empty(struct cmd_parse_input *);
+void cmd_parse_empty(struct cmd_parse_input *);
struct cmd_parse_result *cmd_parse_from_file(FILE *, struct cmd_parse_input *);
struct cmd_parse_result *cmd_parse_from_string(const char *,
struct cmd_parse_input *);
+enum cmd_parse_status cmd_parse_and_insert(const char *,
+ struct cmd_parse_input *, struct cmdq_item *,
+ struct cmdq_state *, char **);
+enum cmd_parse_status cmd_parse_and_append(const char *,
+ struct cmd_parse_input *, struct client *,
+ struct cmdq_state *, char **);
struct cmd_parse_result *cmd_parse_from_buffer(const void *, size_t,
struct cmd_parse_input *);
struct cmd_parse_result *cmd_parse_from_arguments(int, char **,
struct cmd_parse_input *);
-/* cmd-list.c */
-struct cmd_list *cmd_list_new(void);
-void cmd_list_append(struct cmd_list *, struct cmd *);
-void cmd_list_move(struct cmd_list *, struct cmd_list *);
-void cmd_list_free(struct cmd_list *);
-char *cmd_list_print(struct cmd_list *, int);
-
/* cmd-queue.c */
-struct cmdq_item *cmdq_get_command(struct cmd_list *, struct cmd_find_state *,
- struct mouse_event *, int);
+struct cmdq_state *cmdq_new_state(struct cmd_find_state *, struct key_event *,
+ int);
+struct cmdq_state *cmdq_link_state(struct cmdq_state *);
+struct cmdq_state *cmdq_copy_state(struct cmdq_state *);
+void cmdq_free_state(struct cmdq_state *);
+void printflike(3, 4) cmdq_add_format(struct cmdq_state *, const char *,
+ const char *, ...);
+void cmdq_merge_formats(struct cmdq_item *, struct format_tree *);
+struct cmdq_list *cmdq_new(void);
+void cmdq_free(struct cmdq_list *);
+const char *cmdq_get_name(struct cmdq_item *);
+struct client *cmdq_get_client(struct cmdq_item *);
+struct client *cmdq_get_target_client(struct cmdq_item *);
+struct cmdq_state *cmdq_get_state(struct cmdq_item *);
+struct cmd_find_state *cmdq_get_target(struct cmdq_item *);
+struct cmd_find_state *cmdq_get_source(struct cmdq_item *);
+struct key_event *cmdq_get_event(struct cmdq_item *);
+struct cmd_find_state *cmdq_get_current(struct cmdq_item *);
+int cmdq_get_flags(struct cmdq_item *);
+struct cmdq_item *cmdq_get_command(struct cmd_list *, struct cmdq_state *);
#define cmdq_get_callback(cb, data) cmdq_get_callback1(#cb, cb, data)
struct cmdq_item *cmdq_get_callback1(const char *, cmdq_cb, void *);
struct cmdq_item *cmdq_get_error(const char *);
@@ -2137,9 +2210,8 @@ struct cmdq_item *cmdq_append(struct client *, struct cmdq_item *);
void cmdq_insert_hook(struct session *, struct cmdq_item *,
struct cmd_find_state *, const char *, ...);
void cmdq_continue(struct cmdq_item *);
-void printflike(3, 4) cmdq_format(struct cmdq_item *, const char *,
- const char *, ...);
u_int cmdq_next(struct client *);
+struct cmdq_item *cmdq_running(struct client *);
void cmdq_guard(struct cmdq_item *, const char *, int);
void printflike(2, 3) cmdq_print(struct cmdq_item *, const char *, ...);
void printflike(2, 3) cmdq_error(struct cmdq_item *, const char *, ...);
@@ -2148,7 +2220,7 @@ void printflike(2, 3) cmdq_error(struct cmdq_item *, const char *, ...);
void cmd_wait_for_flush(void);
/* client.c */
-int client_main(struct event_base *, int, char **, int);
+int client_main(struct event_base *, int, char **, int, int);
/* key-bindings.c */
struct key_table *key_bindings_get_table(const char *, int);
@@ -2164,7 +2236,7 @@ void key_bindings_remove(const char *, key_code);
void key_bindings_remove_table(const char *);
void key_bindings_init(void);
struct cmdq_item *key_bindings_dispatch(struct key_binding *,
- struct cmdq_item *, struct client *, struct mouse_event *,
+ struct cmdq_item *, struct client *, struct key_event *,
struct cmd_find_state *);
/* key-string.c */
@@ -2185,8 +2257,8 @@ void file_fire_done(struct client_file *);
void file_fire_read(struct client_file *);
int file_can_print(struct client *);
void printflike(2, 3) file_print(struct client *, const char *, ...);
-void file_vprint(struct client *, const char *, va_list);
-void file_print_buffer(struct client *, void *, size_t);
+void file_vprint(struct client *, const char *, va_list);
+void file_print_buffer(struct client *, void *, size_t);
void printflike(2, 3) file_error(struct client *, const char *, ...);
void file_write(struct client *, const char *, int, const void *, size_t,
client_file_cb, void *);
@@ -2203,14 +2275,16 @@ void server_clear_marked(void);
int server_is_marked(struct session *, struct winlink *,
struct window_pane *);
int server_check_marked(void);
-int server_start(struct tmuxproc *, struct event_base *, int, char *);
+int server_start(struct tmuxproc *, int, struct event_base *, int, char *);
void server_update_socket(void);
void server_add_accept(int);
/* server-client.c */
u_int server_client_how_many(void);
-void server_client_set_overlay(struct client *, u_int, overlay_draw_cb,
- overlay_key_cb, overlay_free_cb, void *);
+void server_client_set_overlay(struct client *, u_int, overlay_check_cb,
+ overlay_mode_cb, overlay_draw_cb, overlay_key_cb,
+ overlay_free_cb, void *);
+void server_client_clear_overlay(struct client *);
void server_client_set_key_table(struct client *, const char *);
const char *server_client_get_key_table(struct client *);
int server_client_check_nested(struct client *);
@@ -2282,15 +2356,21 @@ void recalculate_size(struct window *);
void recalculate_sizes(void);
/* input.c */
-void input_init(struct window_pane *);
-void input_free(struct window_pane *);
-void input_reset(struct window_pane *, int);
-struct evbuffer *input_pending(struct window_pane *);
-void input_parse(struct window_pane *);
+struct input_ctx *input_init(struct window_pane *, struct bufferevent *);
+void input_free(struct input_ctx *);
+void input_reset(struct input_ctx *, int);
+struct evbuffer *input_pending(struct input_ctx *);
+void input_parse_pane(struct window_pane *);
void input_parse_buffer(struct window_pane *, u_char *, size_t);
+void input_parse_screen(struct input_ctx *, struct screen *,
+ screen_write_init_ctx_cb, void *, u_char *, size_t);
/* input-key.c */
-int input_key(struct window_pane *, key_code, struct mouse_event *);
+int input_key_pane(struct window_pane *, key_code, struct mouse_event *);
+int input_key(struct window_pane *, struct screen *, struct bufferevent *,
+ key_code);
+int input_key_get_mouse(struct screen *, struct mouse_event *, u_int,
+ u_int, const char **, size_t *);
/* xterm-keys.c */
char *xterm_keys_lookup(key_code);
@@ -2311,11 +2391,15 @@ int attributes_fromstring(const char *);
/* grid.c */
extern const struct grid_cell grid_default_cell;
+void grid_empty_line(struct grid *, u_int, u_int);
int grid_cells_equal(const struct grid_cell *, const struct grid_cell *);
+int grid_cells_look_equal(const struct grid_cell *,
+ const struct grid_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_remove_history(struct grid *, u_int );
void grid_scroll_history(struct grid *, u_int);
void grid_scroll_history_region(struct grid *, u_int, u_int, u_int);
void grid_clear_history(struct grid *);
@@ -2360,8 +2444,13 @@ void grid_view_delete_cells(struct grid *, u_int, 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(struct screen_write_ctx *, struct window_pane *,
- struct screen *);
+void screen_write_make_list(struct screen *);
+void screen_write_free_list(struct screen *);
+void screen_write_start_pane(struct screen_write_ctx *,
+ struct window_pane *, struct screen *);
+void screen_write_start(struct screen_write_ctx *, struct screen *);
+void screen_write_start_callback(struct screen_write_ctx *, struct screen *,
+ screen_write_init_ctx_cb, void *);
void screen_write_stop(struct screen_write_ctx *);
void screen_write_reset(struct screen_write_ctx *);
size_t printflike(1, 2) screen_write_strlen(const char *, ...);
@@ -2373,13 +2462,12 @@ void screen_write_vnputs(struct screen_write_ctx *, ssize_t,
const struct grid_cell *, const char *, va_list);
void screen_write_putc(struct screen_write_ctx *, const struct grid_cell *,
u_char);
-void screen_write_copy(struct screen_write_ctx *, struct screen *, u_int,
- u_int, u_int, u_int, bitstr_t *, const struct grid_cell *);
void screen_write_fast_copy(struct screen_write_ctx *, struct screen *,
u_int, u_int, u_int, u_int);
void screen_write_hline(struct screen_write_ctx *, u_int, int, int);
void screen_write_vline(struct screen_write_ctx *, u_int, int, int);
-void screen_write_menu(struct screen_write_ctx *, struct menu *, int);
+void screen_write_menu(struct screen_write_ctx *, struct menu *, int,
+ const struct grid_cell *);
void screen_write_box(struct screen_write_ctx *, u_int, u_int);
void screen_write_preview(struct screen_write_ctx *, struct screen *, u_int,
u_int);
@@ -2416,6 +2504,10 @@ void screen_write_collect_add(struct screen_write_ctx *,
void screen_write_cell(struct screen_write_ctx *, const struct grid_cell *);
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_alternateon(struct screen_write_ctx *,
+ struct grid_cell *, int);
+void screen_write_alternateoff(struct screen_write_ctx *,
+ struct grid_cell *, int);
/* screen-redraw.c */
void screen_redraw_screen(struct client *);
@@ -2433,6 +2525,8 @@ void screen_set_path(struct screen *, const char *);
void screen_push_title(struct screen *);
void screen_pop_title(struct screen *);
void screen_resize(struct screen *, u_int, u_int, int);
+void screen_resize_cursor(struct screen *, u_int, u_int, int, int, u_int *,
+ u_int *);
void screen_set_selection(struct screen *, u_int, u_int, u_int, u_int,
u_int, int, struct grid_cell *);
void screen_clear_selection(struct screen *);
@@ -2440,6 +2534,8 @@ void screen_hide_selection(struct screen *);
int screen_check_selection(struct screen *, u_int, u_int);
void screen_select_cell(struct screen *, struct grid_cell *,
const struct grid_cell *);
+void screen_alternate_on(struct screen *, struct grid_cell *, int);
+void screen_alternate_off(struct screen *, struct grid_cell *, int);
/* window.c */
extern struct windows windows;
@@ -2500,17 +2596,13 @@ struct window_pane *window_pane_find_by_id_str(const char *);
struct window_pane *window_pane_find_by_id(u_int);
int window_pane_destroy_ready(struct window_pane *);
void window_pane_resize(struct window_pane *, u_int, u_int);
-void window_pane_alternate_on(struct window_pane *,
- struct grid_cell *, int);
-void window_pane_alternate_off(struct window_pane *,
- struct grid_cell *, int);
void window_pane_set_palette(struct window_pane *, u_int, int);
void window_pane_unset_palette(struct window_pane *, u_int);
void window_pane_reset_palette(struct window_pane *);
int window_pane_get_palette(struct window_pane *, int);
int window_pane_set_mode(struct window_pane *,
- const struct window_mode *, struct cmd_find_state *,
- struct args *);
+ struct window_pane *, const struct window_mode *,
+ struct cmd_find_state *, struct args *);
void window_pane_reset_mode(struct window_pane *);
void window_pane_reset_mode_all(struct window_pane *);
int window_pane_key(struct window_pane *, struct client *,
@@ -2585,7 +2677,8 @@ typedef void (*mode_tree_each_cb)(void *, void *, struct client *, key_code);
u_int mode_tree_count_tagged(struct mode_tree_data *);
void *mode_tree_get_current(struct mode_tree_data *);
void mode_tree_expand_current(struct mode_tree_data *);
-void mode_tree_set_current(struct mode_tree_data *, uint64_t);
+void mode_tree_expand(struct mode_tree_data *, uint64_t);
+int mode_tree_set_current(struct mode_tree_data *, uint64_t);
void mode_tree_each_tagged(struct mode_tree_data *, mode_tree_each_cb,
struct client *, key_code, int);
void mode_tree_down(struct mode_tree_data *, int);
@@ -2627,6 +2720,8 @@ void printflike(2, 3) 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 *, int);
void window_copy_start_drag(struct client *, struct mouse_event *);
+char *window_copy_get_word(struct window_pane *, u_int, u_int);
+char *window_copy_get_line(struct window_pane *, u_int);
/* names.c */
void check_window_name(struct window *);
@@ -2662,10 +2757,10 @@ struct session *session_find_by_id_str(const char *);
struct session *session_find_by_id(u_int);
struct session *session_create(const char *, const char *, const char *,
struct environ *, struct options *, struct termios *);
-void session_destroy(struct session *, int, const char *);
+void session_destroy(struct session *, int, const char *);
void session_add_ref(struct session *, const char *);
void session_remove_ref(struct session *, const char *);
-int session_check_name(const char *);
+char *session_check_name(const char *);
void session_update_activity(struct session *, struct timeval *);
struct session *session_next_session(struct session *);
struct session *session_previous_session(struct session *);
@@ -2727,29 +2822,43 @@ __dead void printflike(1, 2) fatal(const char *, ...);
__dead void printflike(1, 2) fatalx(const char *, ...);
/* menu.c */
+#define MENU_NOMOUSE 0x1
+#define MENU_TAB 0x2
struct menu *menu_create(const char *);
void menu_add_items(struct menu *, const struct menu_item *,
struct cmdq_item *, struct client *,
struct cmd_find_state *);
-void menu_add_item(struct menu *, const struct menu_item *,
+void menu_add_item(struct menu *, const struct menu_item *,
struct cmdq_item *, struct client *,
struct cmd_find_state *);
-
void menu_free(struct menu *);
int menu_display(struct menu *, int, struct cmdq_item *, u_int,
u_int, struct client *, struct cmd_find_state *,
menu_choice_cb, void *);
+/* popup.c */
+#define POPUP_WRITEKEYS 0x1
+#define POPUP_CLOSEEXIT 0x2
+#define POPUP_CLOSEEXITZERO 0x4
+typedef void (*popup_close_cb)(int, void *);
+u_int popup_width(struct cmdq_item *, u_int, const char **,
+ struct client *, struct cmd_find_state *);
+u_int popup_height(u_int, const char **);
+int popup_display(int, struct cmdq_item *, u_int, u_int, u_int,
+ u_int, u_int, const char **, const char *, const char *,
+ const char *, struct client *, struct cmd_find_state *,
+ popup_close_cb, void *);
+
/* style.c */
int style_parse(struct style *,const struct grid_cell *,
const char *);
const char *style_tostring(struct style *);
+void style_add(struct grid_cell *, struct options *,
+ const char *, struct format_tree *);
void style_apply(struct grid_cell *, struct options *,
- const char *);
-int style_equal(struct style *, struct style *);
+ const char *, struct format_tree *);
void style_set(struct style *, const struct grid_cell *);
void style_copy(struct style *, struct style *);
-int style_is_default(struct style *);
/* spawn.c */
struct winlink *spawn_window(struct spawn_context *, char **);
diff --git a/tty-acs.c b/tty-acs.c
index 14634120..3e811103 100644
--- a/tty-acs.c
+++ b/tty-acs.c
@@ -99,7 +99,7 @@ tty_acs_needed(struct tty *tty)
tty_term_number(tty->term, TTYC_U8) == 0)
return (1);
- if (tty->flags & TTY_UTF8)
+ if (tty->client->flags & CLIENT_UTF8)
return (0);
return (1);
}
diff --git a/tty-features.c b/tty-features.c
new file mode 100644
index 00000000..30d3d1a0
--- /dev/null
+++ b/tty-features.c
@@ -0,0 +1,348 @@
+/* $OpenBSD$ */
+
+/*
+ * Copyright (c) 2020 Nicholas Marriott <nicholas.marriott@gmail.com>
+ *
+ * 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 <sys/types.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "tmux.h"
+
+/*
+ * Still hardcoded:
+ * - mouse (under kmous capability);
+ * - default colours (under AX or op capabilities);
+ * - AIX colours (under colors >= 16);
+ * - alternate escape (if terminal is VT100-like).
+ *
+ * Also:
+ * - DECFRA uses a flag instead of capabilities;
+ * - UTF-8 is a separate flag on the client; needed for unattached clients.
+ */
+
+/* A named terminal feature. */
+struct tty_feature {
+ const char *name;
+ const char **capabilities;
+ int flags;
+};
+
+/* Terminal has xterm(1) title setting. */
+static const char *tty_feature_title_capabilities[] = {
+ "tsl=\\E]0;", /* should be using TS really */
+ "fsl=\\a",
+ NULL
+};
+static const struct tty_feature tty_feature_title = {
+ "title",
+ tty_feature_title_capabilities,
+ 0
+};
+
+/* Terminal can set the clipboard with OSC 52. */
+static const char *tty_feature_clipboard_capabilities[] = {
+ "Ms=\\E]52;%p1%s;%p2%s\\a",
+ NULL
+};
+static const struct tty_feature tty_feature_clipboard = {
+ "clipboard",
+ tty_feature_clipboard_capabilities,
+ 0
+};
+
+/*
+ * Terminal supports RGB colour. This replaces setab and setaf also since
+ * terminals with RGB have versions that do not allow setting colours from the
+ * 256 palette.
+ */
+static const char *tty_feature_rgb_capabilities[] = {
+ "AX",
+ "setrgbf=\\E[38;2;%p1%d;%p2%d;%p3%dm",
+ "setrgbb=\\E[48;2;%p1%d;%p2%d;%p3%dm",
+ "setab=\\E[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m",
+ "setaf=\\E[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m",
+ NULL
+};
+static const struct tty_feature tty_feature_rgb = {
+ "RGB",
+ tty_feature_rgb_capabilities,
+ TERM_256COLOURS|TERM_RGBCOLOURS
+};
+
+/* Terminal supports 256 colours. */
+static const char *tty_feature_256_capabilities[] = {
+ "AX",
+ "setab=\\E[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m",
+ "setaf=\\E[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m",
+ NULL
+};
+static const struct tty_feature tty_feature_256 = {
+ "256",
+ tty_feature_256_capabilities,
+ TERM_256COLOURS
+};
+
+/* Terminal supports overline. */
+static const char *tty_feature_overline_capabilities[] = {
+ "Smol=\\E[53m",
+ NULL
+};
+static const struct tty_feature tty_feature_overline = {
+ "overline",
+ tty_feature_overline_capabilities,
+ 0
+};
+
+/* Terminal supports underscore styles. */
+static const char *tty_feature_usstyle_capabilities[] = {
+ "Smulx=\E[4::%p1%dm",
+ "Setulc=\E[58::2::%p1%{65536}%/%d::%p1%{256}%/%{255}%&%d::%p1%{255}%&%d%;m",
+ NULL
+};
+static const struct tty_feature tty_feature_usstyle = {
+ "usstyle",
+ tty_feature_usstyle_capabilities,
+ 0
+};
+
+/* Terminal supports bracketed paste. */
+static const char *tty_feature_bpaste_capabilities[] = {
+ "Enbp=\\E[?2004h",
+ "Dsbp=\\E[?2004l",
+ NULL
+};
+static const struct tty_feature tty_feature_bpaste = {
+ "bpaste",
+ tty_feature_bpaste_capabilities,
+ 0
+};
+
+/* Terminal supports focus reporting. */
+static const char *tty_feature_focus_capabilities[] = {
+ "Enfcs=\\E[?1004h",
+ "Dsfcs=\\E[?1004l",
+ NULL
+};
+static const struct tty_feature tty_feature_focus = {
+ "focus",
+ tty_feature_focus_capabilities,
+ 0
+};
+
+/* Terminal supports cursor styles. */
+static const char *tty_feature_cstyle_capabilities[] = {
+ "Ss=\\E[%p1%d q",
+ "Se=\\E[2 q",
+ NULL
+};
+static const struct tty_feature tty_feature_cstyle = {
+ "cstyle",
+ tty_feature_cstyle_capabilities,
+ 0
+};
+
+/* Terminal supports cursor colours. */
+static const char *tty_feature_ccolour_capabilities[] = {
+ "Cs=\\E]12;%p1%s\\a",
+ "Cr=\\E]112\\a",
+ NULL
+};
+static const struct tty_feature tty_feature_ccolour = {
+ "ccolour",
+ tty_feature_ccolour_capabilities,
+ 0
+};
+
+/* Terminal supports strikethrough. */
+static const char *tty_feature_strikethrough_capabilities[] = {
+ "smxx=\\E[9m",
+ NULL
+};
+static const struct tty_feature tty_feature_strikethrough = {
+ "strikethrough",
+ tty_feature_strikethrough_capabilities,
+ 0
+};
+
+/* Terminal supports synchronized updates. */
+static const char *tty_feature_sync_capabilities[] = {
+ "Sync=\\EP=%p1%ds\\E\\\\",
+ NULL
+};
+static const struct tty_feature tty_feature_sync = {
+ "sync",
+ tty_feature_sync_capabilities,
+ 0
+};
+
+/* Terminal supports DECSLRM margins. */
+static const char *tty_feature_margins_capabilities[] = {
+ "Enmg=\\E[?69h",
+ "Dsmg=\\E[?69l",
+ "Clmg=\\E[s",
+ "Cmg=\\E[%i%p1%d;%p2%ds",
+ NULL
+};
+static const struct tty_feature tty_feature_margins = {
+ "margins",
+ tty_feature_margins_capabilities,
+ TERM_DECSLRM
+};
+
+/* Terminal supports DECFRA rectangle fill. */
+static const struct tty_feature tty_feature_rectfill = {
+ "rectfill",
+ NULL,
+ TERM_DECFRA
+};
+
+/* Available terminal features. */
+static const struct tty_feature *tty_features[] = {
+ &tty_feature_256,
+ &tty_feature_bpaste,
+ &tty_feature_ccolour,
+ &tty_feature_clipboard,
+ &tty_feature_cstyle,
+ &tty_feature_focus,
+ &tty_feature_margins,
+ &tty_feature_overline,
+ &tty_feature_rectfill,
+ &tty_feature_rgb,
+ &tty_feature_strikethrough,
+ &tty_feature_sync,
+ &tty_feature_title,
+ &tty_feature_usstyle
+};
+
+void
+tty_add_features(int *feat, const char *s, const char *separators)
+{
+ const struct tty_feature *tf;
+ char *next, *loop, *copy;
+ u_int i;
+
+ log_debug("adding terminal features %s", s);
+
+ loop = copy = xstrdup(s);
+ while ((next = strsep(&loop, separators)) != NULL) {
+ for (i = 0; i < nitems(tty_features); i++) {
+ tf = tty_features[i];
+ if (strcasecmp(tf->name, next) == 0)
+ break;
+ }
+ if (i == nitems(tty_features)) {
+ log_debug("unknown terminal feature: %s", next);
+ break;
+ }
+ if (~(*feat) & (1 << i)) {
+ log_debug("adding terminal feature: %s", tf->name);
+ (*feat) |= (1 << i);
+ }
+ }
+ free(copy);
+}
+
+const char *
+tty_get_features(int feat)
+{
+ const struct tty_feature *tf;
+ static char s[512];
+ u_int i;
+
+ *s = '\0';
+ for (i = 0; i < nitems(tty_features); i++) {
+ if (~feat & (1 << i))
+ continue;
+ tf = tty_features[i];
+
+ strlcat(s, tf->name, sizeof s);
+ strlcat(s, ",", sizeof s);
+ }
+ if (*s != '\0')
+ s[strlen(s) - 1] = '\0';
+ return (s);
+}
+
+int
+tty_apply_features(struct tty_term *term, int feat)
+{
+ const struct tty_feature *tf;
+ const char **capability;
+ u_int i;
+
+ if (feat == 0)
+ return (0);
+ log_debug("applying terminal features: %s", tty_get_features(feat));
+
+ for (i = 0; i < nitems(tty_features); i++) {
+ if ((term->features & (1 << i)) || (~feat & (1 << i)))
+ continue;
+ tf = tty_features[i];
+
+ log_debug("applying terminal feature: %s", tf->name);
+ if (tf->capabilities != NULL) {
+ capability = tf->capabilities;
+ while (*capability != NULL) {
+ log_debug("adding capability: %s", *capability);
+ tty_term_apply(term, *capability, 1);
+ capability++;
+ }
+ }
+ term->flags |= tf->flags;
+ }
+ if ((term->features | feat) == term->features)
+ return (0);
+ term->features |= feat;
+ return (1);
+}
+
+void
+tty_default_features(int *feat, const char *name, u_int version)
+{
+ static struct {
+ const char *name;
+ u_int version;
+ const char *features;
+ } table[] = {
+#define TTY_FEATURES_BASE_MODERN_XTERM "256,RGB,bpaste,clipboard,strikethrough,title"
+ { .name = "mintty",
+ .features = TTY_FEATURES_BASE_MODERN_XTERM ",ccolour,cstyle,margins,overline"
+ },
+ { .name = "tmux",
+ .features = TTY_FEATURES_BASE_MODERN_XTERM ",ccolour,cstyle,focus,overline,usstyle"
+ },
+ { .name = "rxvt-unicode",
+ .features = "256,bpaste,ccolour,cstyle,title"
+ },
+ { .name = "iTerm2",
+ .features = TTY_FEATURES_BASE_MODERN_XTERM ",cstyle,margins,sync"
+ },
+ { .name = "XTerm",
+ .features = TTY_FEATURES_BASE_MODERN_XTERM ",ccolour,cstyle,focus,margins,rectfill"
+ }
+ };
+ u_int i;
+
+ for (i = 0; i < nitems(table); i++) {
+ if (strcmp(table[i].name, name) != 0)
+ continue;
+ if (version != 0 && version < table[i].version)
+ continue;
+ tty_add_features(feat, table[i].features, ",");
+ }
+}
diff --git a/tty-keys.c b/tty-keys.c
index 064f2172..f5a3418f 100644
--- a/tty-keys.c
+++ b/tty-keys.c
@@ -52,7 +52,7 @@ static int tty_keys_clipboard(struct tty *, const char *, size_t,
size_t *);
static int tty_keys_device_attributes(struct tty *, const char *, size_t,
size_t *);
-static int tty_keys_device_status_report(struct tty *, const char *,
+static int tty_keys_extended_device_attributes(struct tty *, const char *,
size_t, size_t *);
/* Default raw keys. */
@@ -61,6 +61,9 @@ struct tty_default_key_raw {
key_code key;
};
static const struct tty_default_key_raw tty_default_raw_keys[] = {
+ /* Application escape. */
+ { "\033O[", '\033' },
+
/*
* Numeric keypad. Just use the vt100 escape sequences here and always
* put the terminal into keypad_xmit mode. Translation of numbers
@@ -609,8 +612,8 @@ tty_keys_next(struct tty *tty)
goto partial_key;
}
- /* Is this a device status report response? */
- switch (tty_keys_device_status_report(tty, buf, len, &size)) {
+ /* Is this an extended device attributes response? */
+ switch (tty_keys_extended_device_attributes(tty, buf, len, &size)) {
case 0: /* yes */
key = KEYC_UNKNOWN;
goto complete_key;
@@ -933,7 +936,7 @@ tty_keys_clipboard(__unused struct tty *tty, const char *buf, size_t len,
*size = 0;
- /* First three bytes are always \033]52;. */
+ /* First five bytes are always \033]52;. */
if (buf[0] != '\033')
return (-1);
if (len == 1)
@@ -1007,8 +1010,8 @@ tty_keys_clipboard(__unused struct tty *tty, const char *buf, size_t len,
}
/*
- * Handle device attributes input. Returns 0 for success, -1 for failure, 1 for
- * partial.
+ * Handle secondary device attributes input. Returns 0 for success, -1 for
+ * failure, 1 for partial.
*/
static int
tty_keys_device_attributes(struct tty *tty, const char *buf, size_t len,
@@ -1017,7 +1020,6 @@ tty_keys_device_attributes(struct tty *tty, const char *buf, size_t len,
struct client *c = tty->client;
u_int i, n = 0;
char tmp[64], *endptr, p[32] = { 0 }, *cp, *next;
- int flags = 0;
*size = 0;
if (tty->flags & TTY_HAVEDA)
@@ -1032,15 +1034,17 @@ tty_keys_device_attributes(struct tty *tty, const char *buf, size_t len,
return (-1);
if (len == 2)
return (1);
- if (buf[2] != '?')
+ 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++) {
+ for (i = 0; i < (sizeof tmp) - 1; i++) {
if (3 + i == len)
return (1);
+ if (buf[3 + i] == 'c')
+ break;
tmp[i] = buf[3 + i];
}
if (i == (sizeof tmp) - 1)
@@ -1048,7 +1052,7 @@ tty_keys_device_attributes(struct tty *tty, const char *buf, size_t len,
tmp[i] = '\0';
*size = 4 + i;
- /* Convert version numbers. */
+ /* Convert all arguments to numbers. */
cp = tmp;
while ((next = strsep(&cp, ";")) != NULL) {
p[n] = strtoul(next, &endptr, 10);
@@ -1057,73 +1061,95 @@ tty_keys_device_attributes(struct tty *tty, const char *buf, size_t len,
n++;
}
- /* Set terminal flags. */
+ /* Add terminal features. */
switch (p[0]) {
- case 64: /* VT420 */
- flags |= (TERM_DECFRA|TERM_DECSLRM);
+ case 41: /* VT420 */
+ tty_add_features(&c->term_features,
+ "margins,"
+ "rectfill",
+ ",");
+ break;
+ case 'M': /* mintty */
+ tty_default_features(&c->term_features, "mintty", 0);
+ break;
+ case 'T': /* tmux */
+ tty_default_features(&c->term_features, "tmux", 0);
+ break;
+ case 'U': /* rxvt-unicode */
+ tty_default_features(&c->term_features, "rxvt-unicode", 0);
break;
}
- for (i = 1; i < n; i++)
- log_debug("%s: DA feature: %d", c->name, p[i]);
- log_debug("%s: received DA %.*s", c->name, (int)*size, buf);
+ log_debug("%s: received secondary DA %.*s", c->name, (int)*size, buf);
- tty_set_flags(tty, flags);
+ tty_update_features(tty);
tty->flags |= TTY_HAVEDA;
return (0);
}
/*
- * Handle device status report input. Returns 0 for success, -1 for failure, 1
- * for partial.
+ * Handle extended device attributes input. Returns 0 for success, -1 for
+ * failure, 1 for partial.
*/
static int
-tty_keys_device_status_report(struct tty *tty, const char *buf, size_t len,
- size_t *size)
+tty_keys_extended_device_attributes(struct tty *tty, const char *buf,
+ size_t len, size_t *size)
{
struct client *c = tty->client;
u_int i;
- char tmp[64];
- int flags = 0;
+ char tmp[128];
*size = 0;
- if (tty->flags & TTY_HAVEDSR)
+ if (tty->flags & TTY_HAVEXDA)
return (-1);
- /* First three bytes are always \033[. */
+ /* First four bytes are always \033P>|. */
if (buf[0] != '\033')
return (-1);
if (len == 1)
return (1);
- if (buf[1] != '[')
+ if (buf[1] != 'P')
return (-1);
if (len == 2)
return (1);
- if (buf[2] != 'I' && buf[2] != 'T')
+ if (buf[2] != '>')
return (-1);
if (len == 3)
return (1);
+ if (buf[3] != '|')
+ return (-1);
+ if (len == 4)
+ return (1);
- /* Copy the rest up to a 'n'. */
- for (i = 0; i < (sizeof tmp) - 1 && buf[2 + i] != 'n'; i++) {
- if (2 + i == len)
+ /* Copy the rest up to a '\033\\'. */
+ for (i = 0; i < (sizeof tmp) - 1; i++) {
+ if (4 + i == len)
return (1);
- tmp[i] = buf[2 + i];
+ if (buf[4 + i - 1] == '\033' && buf[4 + i] == '\\')
+ break;
+ tmp[i] = buf[4 + i];
}
if (i == (sizeof tmp) - 1)
return (-1);
- tmp[i] = '\0';
- *size = 3 + i;
-
- /* Set terminal flags. */
- if (strncmp(tmp, "ITERM2 ", 7) == 0)
- flags |= (TERM_DECSLRM|TERM_256COLOURS|TERM_RGBCOLOURS);
- if (strncmp(tmp, "TMUX ", 5) == 0)
- flags |= (TERM_256COLOURS|TERM_RGBCOLOURS);
- log_debug("%s: received DSR %.*s", c->name, (int)*size, buf);
-
- tty_set_flags(tty, flags);
- tty->flags |= TTY_HAVEDSR;
+ tmp[i - 1] = '\0';
+ *size = 5 + i;
+
+ /* Add terminal features. */
+ if (strncmp(tmp, "iTerm2 ", 7) == 0)
+ tty_default_features(&c->term_features, "iTerm2", 0);
+ else if (strncmp(tmp, "tmux ", 5) == 0)
+ tty_default_features(&c->term_features, "tmux", 0);
+ else if (strncmp(tmp, "XTerm(", 6) == 0)
+ tty_default_features(&c->term_features, "xterm", 0);
+ else if (strncmp(tmp, "mintty ", 7) == 0)
+ tty_default_features(&c->term_features, "mintty", 0);
+ log_debug("%s: received extended DA %.*s", c->name, (int)*size, buf);
+
+ free(c->term_type);
+ c->term_type = xstrdup(tmp);
+
+ tty_update_features(tty);
+ tty->flags |= TTY_HAVEXDA;
return (0);
}
diff --git a/tty-term.c b/tty-term.c
index e556df6f..e8ac6634 100644
--- a/tty-term.c
+++ b/tty-term.c
@@ -30,7 +30,6 @@
#include "tmux.h"
-static void tty_term_override(struct tty_term *, const char *);
static char *tty_term_strip(const char *);
struct tty_terms tty_terms = LIST_HEAD_INITIALIZER(tty_terms);
@@ -65,6 +64,8 @@ static const struct tty_term_code_entry tty_term_codes[] = {
[TTYC_BOLD] = { TTYCODE_STRING, "bold" },
[TTYC_CIVIS] = { TTYCODE_STRING, "civis" },
[TTYC_CLEAR] = { TTYCODE_STRING, "clear" },
+ [TTYC_CLMG] = { TTYCODE_STRING, "Clmg" },
+ [TTYC_CMG] = { TTYCODE_STRING, "Cmg" },
[TTYC_CNORM] = { TTYCODE_STRING, "cnorm" },
[TTYC_COLORS] = { TTYCODE_NUMBER, "colors" },
[TTYC_CR] = { TTYCODE_STRING, "Cr" },
@@ -85,12 +86,18 @@ static const struct tty_term_code_entry tty_term_codes[] = {
[TTYC_DIM] = { TTYCODE_STRING, "dim" },
[TTYC_DL1] = { TTYCODE_STRING, "dl1" },
[TTYC_DL] = { TTYCODE_STRING, "dl" },
+ [TTYC_DSFCS] = { TTYCODE_STRING, "Dsfcs" },
+ [TTYC_DSBP] = { TTYCODE_STRING, "Dsbp" },
+ [TTYC_DSMG] = { TTYCODE_STRING, "Dsmg" },
[TTYC_E3] = { TTYCODE_STRING, "E3" },
[TTYC_ECH] = { TTYCODE_STRING, "ech" },
[TTYC_ED] = { TTYCODE_STRING, "ed" },
[TTYC_EL1] = { TTYCODE_STRING, "el1" },
[TTYC_EL] = { TTYCODE_STRING, "el" },
[TTYC_ENACS] = { TTYCODE_STRING, "enacs" },
+ [TTYC_ENBP] = { TTYCODE_STRING, "Enbp" },
+ [TTYC_ENFCS] = { TTYCODE_STRING, "Enfcs" },
+ [TTYC_ENMG] = { TTYCODE_STRING, "Enmg" },
[TTYC_FSL] = { TTYCODE_STRING, "fsl" },
[TTYC_HOME] = { TTYCODE_STRING, "home" },
[TTYC_HPA] = { TTYCODE_STRING, "hpa" },
@@ -241,8 +248,8 @@ static const struct tty_term_code_entry tty_term_codes[] = {
[TTYC_OP] = { TTYCODE_STRING, "op" },
[TTYC_REV] = { TTYCODE_STRING, "rev" },
[TTYC_RGB] = { TTYCODE_FLAG, "RGB" },
- [TTYC_RI] = { TTYCODE_STRING, "ri" },
[TTYC_RIN] = { TTYCODE_STRING, "rin" },
+ [TTYC_RI] = { TTYCODE_STRING, "ri" },
[TTYC_RMACS] = { TTYCODE_STRING, "rmacs" },
[TTYC_RMCUP] = { TTYCODE_STRING, "rmcup" },
[TTYC_RMKX] = { TTYCODE_STRING, "rmkx" },
@@ -263,12 +270,13 @@ static const struct tty_term_code_entry tty_term_codes[] = {
[TTYC_SMUL] = { TTYCODE_STRING, "smul" },
[TTYC_SMXX] = { TTYCODE_STRING, "smxx" },
[TTYC_SS] = { TTYCODE_STRING, "Ss" },
+ [TTYC_SYNC] = { TTYCODE_STRING, "Sync" },
[TTYC_TC] = { TTYCODE_FLAG, "Tc" },
[TTYC_TSL] = { TTYCODE_STRING, "tsl" },
[TTYC_U8] = { TTYCODE_NUMBER, "U8" },
[TTYC_VPA] = { TTYCODE_STRING, "vpa" },
[TTYC_XENL] = { TTYCODE_FLAG, "xenl" },
- [TTYC_XT] = { TTYCODE_FLAG, "XT" },
+ [TTYC_XT] = { TTYCODE_FLAG, "XT" }
};
u_int
@@ -337,22 +345,18 @@ tty_term_override_next(const char *s, size_t *offset)
return (value);
}
-static void
-tty_term_override(struct tty_term *term, const char *override)
+void
+tty_term_apply(struct tty_term *term, const char *capabilities, int quiet)
{
const struct tty_term_code_entry *ent;
struct tty_code *code;
size_t offset = 0;
char *cp, *value, *s;
- const char *errstr;
+ const char *errstr, *name = term->name;
u_int i;
int n, remove;
- s = tty_term_override_next(override, &offset);
- if (s == NULL || fnmatch(s, term->name, 0) != 0)
- return;
-
- while ((s = tty_term_override_next(override, &offset)) != NULL) {
+ while ((s = tty_term_override_next(capabilities, &offset)) != NULL) {
if (*s == '\0')
continue;
value = NULL;
@@ -371,12 +375,14 @@ tty_term_override(struct tty_term *term, const char *override)
} else
value = xstrdup("");
- if (remove)
- log_debug("%s override: %s@", term->name, s);
- else if (*value == '\0')
- log_debug("%s override: %s", term->name, s);
- else
- log_debug("%s override: %s=%s", term->name, s, value);
+ if (!quiet) {
+ if (remove)
+ log_debug("%s override: %s@", name, s);
+ else if (*value == '\0')
+ log_debug("%s override: %s", name, s);
+ else
+ log_debug("%s override: %s=%s", name, s, value);
+ }
for (i = 0; i < tty_term_ncodes(); i++) {
ent = &tty_term_codes[i];
@@ -415,8 +421,32 @@ tty_term_override(struct tty_term *term, const char *override)
}
}
+void
+tty_term_apply_overrides(struct tty_term *term)
+{
+ struct options_entry *o;
+ struct options_array_item *a;
+ union options_value *ov;
+ const char *s;
+ size_t offset;
+ char *first;
+
+ o = options_get_only(global_options, "terminal-overrides");
+ a = options_array_first(o);
+ while (a != NULL) {
+ ov = options_array_item_value(a);
+ s = ov->string;
+
+ offset = 0;
+ first = tty_term_override_next(s, &offset);
+ if (first != NULL && fnmatch(first, term->name, 0) == 0)
+ tty_term_apply(term, s + offset, 0);
+ a = options_array_next(a);
+ }
+}
+
struct tty_term *
-tty_term_find(char *name, int fd, char **cause)
+tty_term_create(struct tty *tty, char *name, int *feat, int fd, char **cause)
{
struct tty_term *term;
const struct tty_term_code_entry *ent;
@@ -427,19 +457,14 @@ tty_term_find(char *name, int fd, char **cause)
u_int i;
int n, error;
const char *s, *acs;
+ size_t offset;
+ char *first;
- LIST_FOREACH(term, &tty_terms, entry) {
- if (strcmp(term->name, name) == 0) {
- term->references++;
- return (term);
- }
- }
- log_debug("new term: %s", name);
+ log_debug("adding term %s", name);
- term = xmalloc(sizeof *term);
+ term = xcalloc(1, sizeof *term);
+ term->tty = tty;
term->name = xstrdup(name);
- term->references = 1;
- term->flags = 0;
term->codes = xcalloc(tty_term_ncodes(), sizeof *term->codes);
LIST_INSERT_HEAD(&tty_terms, term, entry);
@@ -497,12 +522,17 @@ tty_term_find(char *name, int fd, char **cause)
}
}
- /* Apply terminal overrides. */
- o = options_get_only(global_options, "terminal-overrides");
+ /* Apply terminal features. */
+ o = options_get_only(global_options, "terminal-features");
a = options_array_first(o);
while (a != NULL) {
ov = options_array_item_value(a);
- tty_term_override(term, ov->string);
+ s = ov->string;
+
+ offset = 0;
+ first = tty_term_override_next(s, &offset);
+ if (first != NULL && fnmatch(first, term->name, 0) == 0)
+ tty_add_features(feat, s + offset, ":");
a = options_array_next(a);
}
@@ -512,6 +542,9 @@ tty_term_find(char *name, int fd, char **cause)
del_curterm(cur_term);
#endif
+ /* Apply overrides so any capabilities used for features are changed. */
+ tty_term_apply_overrides(term);
+
/* These are always required. */
if (!tty_term_has(term, TTYC_CLEAR)) {
xasprintf(cause, "terminal does not support clear");
@@ -522,21 +555,33 @@ tty_term_find(char *name, int fd, char **cause)
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 TERM has XT or clear starts with CSI then it is safe to assume
+ * the terminal is derived from the VT100. This controls whether device
+ * attributes requests are sent to get more information.
+ *
+ * This is a bit of a hack but there aren't that many alternatives.
+ * Worst case tmux will just fall back to using whatever terminfo(5)
+ * says without trying to correct anything that is missing.
+ *
+ * Also add few features that VT100-like terminals should either
+ * support or safely ignore.
+ */
+ s = tty_term_string(term, TTYC_CLEAR);
+ if (tty_term_flag(term, TTYC_XT) || strncmp(s, "\033[", 2) == 0) {
+ term->flags |= TERM_VT100LIKE;
+ tty_add_features(feat, "bpaste,focus,title", ",");
}
- /* Set flag if terminal has 256 colours. */
- if (tty_term_number(term, TTYC_COLORS) >= 256)
- term->flags |= TERM_256COLOURS;
+ /* Add RGB feature if terminal has RGB colours. */
+ if ((tty_term_flag(term, TTYC_TC) || tty_term_has(term, TTYC_RGB)) &&
+ (!tty_term_has(term, TTYC_SETRGBF) ||
+ !tty_term_has(term, TTYC_SETRGBB)))
+ tty_add_features(feat, "RGB", ",");
- /* Set flag if terminal has RGB colours. */
- if ((tty_term_flag(term, TTYC_TC) || tty_term_has(term, TTYC_RGB)) ||
- (tty_term_has(term, TTYC_SETRGBF) &&
- tty_term_has(term, TTYC_SETRGBB)))
- term->flags |= TERM_RGBCOLOURS;
+ /* Apply the features and overrides again. */
+ tty_apply_features(term, *feat);
+ tty_term_apply_overrides(term);
/*
* Terminals without xenl (eat newline glitch) wrap at at $COLUMNS - 1
@@ -560,18 +605,6 @@ tty_term_find(char *name, int fd, 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;
- }
-
/* Log the capabilities. */
for (i = 0; i < tty_term_ncodes(); i++)
log_debug("%s%s", name, tty_term_describe(term, i));
@@ -588,10 +621,7 @@ tty_term_free(struct tty_term *term)
{
u_int i;
- if (--term->references != 0)
- return;
-
- LIST_REMOVE(term, entry);
+ log_debug("removing term %s", term->name);
for (i = 0; i < tty_term_ncodes(); i++) {
if (term->codes[i].type == TTYCODE_STRING)
@@ -599,6 +629,7 @@ tty_term_free(struct tty_term *term)
}
free(term->codes);
+ LIST_REMOVE(term, entry);
free(term->name);
free(term);
}
diff --git a/tty.c b/tty.c
index 8efe57b5..c8efeac7 100644
--- a/tty.c
+++ b/tty.c
@@ -34,7 +34,7 @@
static int tty_log_fd = -1;
-static int tty_client_ready(struct client *, struct window_pane *);
+static int tty_client_ready(struct client *);
static void tty_set_italics(struct tty *);
static int tty_try_colour(struct tty *, int, const char *);
@@ -45,12 +45,9 @@ static void tty_cursor_pane_unless_wrap(struct tty *,
const struct tty_ctx *, u_int, u_int);
static void tty_invalidate(struct tty *);
static void tty_colours(struct tty *, const struct grid_cell *);
-static void tty_check_fg(struct tty *, struct window_pane *,
- struct grid_cell *);
-static void tty_check_bg(struct tty *, struct window_pane *,
- struct grid_cell *);
-static void tty_check_us(struct tty *, struct window_pane *,
- struct grid_cell *);
+static void tty_check_fg(struct tty *, int *, struct grid_cell *);
+static void tty_check_bg(struct tty *, int *, struct grid_cell *);
+static void tty_check_us(struct tty *, int *, struct grid_cell *);
static void tty_colours_fg(struct tty *, const struct grid_cell *);
static void tty_colours_bg(struct tty *, const struct grid_cell *);
static void tty_colours_us(struct tty *, const struct grid_cell *);
@@ -61,23 +58,22 @@ static void tty_region(struct tty *, u_int, u_int);
static void tty_margin_pane(struct tty *, const struct tty_ctx *);
static void tty_margin(struct tty *, u_int, u_int);
static int tty_large_region(struct tty *, const struct tty_ctx *);
-static int tty_fake_bce(const struct tty *, struct window_pane *, u_int);
+static int tty_fake_bce(const struct tty *, const struct grid_cell *,
+ u_int);
static void tty_redraw_region(struct tty *, const struct tty_ctx *);
static void tty_emulate_repeat(struct tty *, enum tty_code_code,
enum tty_code_code, u_int);
static void tty_repeat_space(struct tty *, u_int);
static void tty_draw_pane(struct tty *, const struct tty_ctx *, u_int);
static void tty_cell(struct tty *, const struct grid_cell *,
- struct window_pane *);
-static void tty_default_colours(struct grid_cell *, struct window_pane *);
-static void tty_default_attributes(struct tty *, struct window_pane *,
- u_int);
+ const struct grid_cell *, int *);
+static void tty_default_attributes(struct tty *, const struct grid_cell *,
+ int *, u_int);
#define tty_use_margin(tty) \
- ((tty->term->flags|tty->term_flags) & TERM_DECSLRM)
-
-#define tty_pane_full_width(tty, ctx) \
- ((ctx)->xoff == 0 && screen_size_x((ctx)->wp->screen) >= (tty)->sx)
+ (tty->term->flags & TERM_DECSLRM)
+#define tty_full_width(tty, ctx) \
+ ((ctx)->xoff == 0 && (ctx)->sx >= (tty)->sx)
#define TTY_BLOCK_INTERVAL (100000 /* 100 milliseconds */)
#define TTY_BLOCK_START(tty) (1 + ((tty)->sx * (tty)->sy) * 8)
@@ -96,27 +92,19 @@ tty_create_log(void)
}
int
-tty_init(struct tty *tty, struct client *c, int fd, char *term)
+tty_init(struct tty *tty, struct client *c, int fd)
{
if (!isatty(fd))
return (-1);
memset(tty, 0, sizeof *tty);
- if (term == NULL || *term == '\0')
- tty->term_name = xstrdup("unknown");
- else
- tty->term_name = xstrdup(term);
-
tty->fd = fd;
tty->client = c;
tty->cstyle = 0;
tty->ccolour = xstrdup("");
- tty->flags = 0;
- tty->term_flags = 0;
-
return (0);
}
@@ -256,7 +244,10 @@ tty_write_callback(__unused int fd, __unused short events, void *data)
int
tty_open(struct tty *tty, char **cause)
{
- tty->term = tty_term_find(tty->term_name, tty->fd, cause);
+ struct client *c = tty->client;
+
+ tty->term = tty_term_create(tty, c->term_name, &c->term_features,
+ tty->fd, cause);
if (tty->term == NULL) {
tty_close(tty);
return (-1);
@@ -292,7 +283,7 @@ tty_start_timer_callback(__unused int fd, __unused short events, void *data)
struct client *c = tty->client;
log_debug("%s: start timer fired", c->name);
- tty->flags |= (TTY_HAVEDA|TTY_HAVEDSR);
+ tty->flags |= (TTY_HAVEDA|TTY_HAVEXDA);
}
void
@@ -335,17 +326,12 @@ tty_start_tty(struct tty *tty)
tty_puts(tty, "\033[?1006l\033[?1005l");
}
- if (tty_term_flag(tty->term, TTYC_XT)) {
- if (options_get_number(global_options, "focus-events")) {
- tty->flags |= TTY_FOCUS;
- tty_puts(tty, "\033[?1004h");
- }
- if (~tty->flags & TTY_HAVEDA)
- tty_puts(tty, "\033[c");
- if (~tty->flags & TTY_HAVEDSR)
- tty_puts(tty, "\033[1337n");
- } else
- tty->flags |= (TTY_HAVEDA|TTY_HAVEDSR);
+ if (options_get_number(global_options, "focus-events")) {
+ tty->flags |= TTY_FOCUS;
+ tty_raw(tty, tty_term_string(tty->term, TTYC_ENFCS));
+ }
+ if (tty->term->flags & TERM_VT100LIKE)
+ tty_puts(tty, "\033[?7727h");
evtimer_set(&tty->start_timer, tty_start_timer_callback, tty);
evtimer_add(&tty->start_timer, &tv);
@@ -362,6 +348,21 @@ tty_start_tty(struct tty *tty)
}
void
+tty_send_requests(struct tty *tty)
+{
+ if (~tty->flags & TTY_STARTED)
+ return;
+
+ if (tty->term->flags & TERM_VT100LIKE) {
+ if (~tty->flags & TTY_HAVEDA)
+ tty_puts(tty, "\033[>c");
+ if (~tty->flags & TTY_HAVEXDA)
+ tty_puts(tty, "\033[>q");
+ } else
+ tty->flags |= (TTY_HAVEDA|TTY_HAVEXDA);
+}
+
+void
tty_stop_tty(struct tty *tty)
{
struct winsize ws;
@@ -401,7 +402,7 @@ tty_stop_tty(struct tty *tty)
tty_raw(tty, tty_term_string1(tty->term, TTYC_SS, 0));
}
if (tty->mode & MODE_BRACKETPASTE)
- tty_raw(tty, "\033[?2004l");
+ tty_raw(tty, tty_term_string(tty->term, TTYC_DSBP));
if (*tty->ccolour != '\0')
tty_raw(tty, tty_term_string(tty->term, TTYC_CR));
@@ -411,15 +412,15 @@ tty_stop_tty(struct tty *tty)
tty_raw(tty, "\033[?1006l\033[?1005l");
}
- if (tty_term_flag(tty->term, TTYC_XT)) {
- if (tty->flags & TTY_FOCUS) {
- tty->flags &= ~TTY_FOCUS;
- tty_raw(tty, "\033[?1004l");
- }
+ if (tty->flags & TTY_FOCUS) {
+ tty->flags &= ~TTY_FOCUS;
+ tty_raw(tty, tty_term_string(tty->term, TTYC_DSFCS));
}
+ if (tty->term->flags & TERM_VT100LIKE)
+ tty_raw(tty, "\033[?7727l");
if (tty_use_margin(tty))
- tty_raw(tty, "\033[?69l"); /* DECLRMM */
+ tty_raw(tty, tty_term_string(tty->term, TTYC_DSMG));
tty_raw(tty, tty_term_string(tty->term, TTYC_RMCUP));
setblocking(tty->fd, 1);
@@ -454,18 +455,19 @@ void
tty_free(struct tty *tty)
{
tty_close(tty);
-
free(tty->ccolour);
- free(tty->term_name);
}
void
-tty_set_flags(struct tty *tty, int flags)
+tty_update_features(struct tty *tty)
{
- tty->term_flags |= flags;
+ struct client *c = tty->client;
+
+ if (tty_apply_features(tty->term, c->term_features))
+ tty_term_apply_overrides(tty->term);
if (tty_use_margin(tty))
- tty_puts(tty, "\033[?69h"); /* DECLRMM */
+ tty_putcode(tty, TTYC_ENMG);
}
void
@@ -658,7 +660,8 @@ tty_force_cursor_colour(struct tty *tty, const char *ccolour)
void
tty_update_mode(struct tty *tty, int mode, struct screen *s)
{
- int changed;
+ struct client *c = tty->client;
+ int changed;
if (s != NULL && strcmp(s->ccolour, tty->ccolour) != 0)
tty_force_cursor_colour(tty, s->ccolour);
@@ -667,6 +670,9 @@ tty_update_mode(struct tty *tty, int mode, struct screen *s)
mode &= ~MODE_CURSOR;
changed = mode ^ tty->mode;
+ if (changed != 0)
+ log_debug("%s: update mode %x to %x", c->name, tty->mode, mode);
+
if (changed & MODE_BLINKING) {
if (tty_term_has(tty->term, TTYC_CVVIS))
tty_putcode(tty, TTYC_CVVIS);
@@ -690,34 +696,37 @@ tty_update_mode(struct tty *tty, int mode, struct screen *s)
}
tty->cstyle = s->cstyle;
}
- if (changed & ALL_MOUSE_MODES) {
- if (mode & ALL_MOUSE_MODES) {
- /*
- * Enable the SGR (1006) extension unconditionally, as
- * it is safe from misinterpretation.
- */
- tty_puts(tty, "\033[?1006h");
- if (mode & MODE_MOUSE_ALL)
- tty_puts(tty, "\033[?1003h");
- else if (mode & MODE_MOUSE_BUTTON)
- tty_puts(tty, "\033[?1002h");
- else if (mode & MODE_MOUSE_STANDARD)
- tty_puts(tty, "\033[?1000h");
- } else {
- if (tty->mode & MODE_MOUSE_ALL)
- tty_puts(tty, "\033[?1003l");
- else if (tty->mode & MODE_MOUSE_BUTTON)
- tty_puts(tty, "\033[?1002l");
- else if (tty->mode & MODE_MOUSE_STANDARD)
- tty_puts(tty, "\033[?1000l");
+ if ((changed & ALL_MOUSE_MODES) &&
+ tty_term_has(tty->term, TTYC_KMOUS)) {
+ if ((mode & ALL_MOUSE_MODES) == 0)
tty_puts(tty, "\033[?1006l");
- }
+ if ((changed & MODE_MOUSE_STANDARD) &&
+ (~mode & MODE_MOUSE_STANDARD))
+ tty_puts(tty, "\033[?1000l");
+ if ((changed & MODE_MOUSE_BUTTON) &&
+ (~mode & MODE_MOUSE_BUTTON))
+ tty_puts(tty, "\033[?1002l");
+ if ((changed & MODE_MOUSE_ALL) &&
+ (~mode & MODE_MOUSE_ALL))
+ tty_puts(tty, "\033[?1003l");
+
+ if (mode & ALL_MOUSE_MODES)
+ tty_puts(tty, "\033[?1006h");
+ if ((changed & MODE_MOUSE_STANDARD) &&
+ (mode & MODE_MOUSE_STANDARD))
+ tty_puts(tty, "\033[?1000h");
+ if ((changed & MODE_MOUSE_BUTTON) &&
+ (mode & MODE_MOUSE_BUTTON))
+ tty_puts(tty, "\033[?1002h");
+ if ((changed & MODE_MOUSE_ALL) &&
+ (mode & MODE_MOUSE_ALL))
+ tty_puts(tty, "\033[?1003h");
}
if (changed & MODE_BRACKETPASTE) {
if (mode & MODE_BRACKETPASTE)
- tty_puts(tty, "\033[?2004h");
+ tty_putcode(tty, TTYC_ENBP);
else
- tty_puts(tty, "\033[?2004l");
+ tty_putcode(tty, TTYC_DSBP);
}
tty->mode = mode;
}
@@ -876,6 +885,27 @@ tty_update_client_offset(struct client *c)
c->flags |= (CLIENT_REDRAWWINDOW|CLIENT_REDRAWSTATUS);
}
+/* Get a palette entry. */
+static int
+tty_get_palette(int *palette, int c)
+{
+ int new;
+
+ if (palette == NULL)
+ return (-1);
+
+ new = -1;
+ if (c < 8)
+ new = palette[c];
+ else if (c >= 90 && c <= 97)
+ new = palette[8 + c - 90];
+ else if (c & COLOUR_FLAG_256)
+ new = palette[c & ~COLOUR_FLAG_256];
+ if (new == 0)
+ return (-1);
+ return (new);
+}
+
/*
* 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
@@ -884,9 +914,7 @@ tty_update_client_offset(struct client *c)
static 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);
+ return (ctx->orlower - ctx->orupper >= ctx->sy / 2);
}
/*
@@ -894,18 +922,11 @@ tty_large_region(__unused struct tty *tty, const struct tty_ctx *ctx)
* emulated.
*/
static int
-tty_fake_bce(const struct tty *tty, struct window_pane *wp, u_int bg)
+tty_fake_bce(const struct tty *tty, const struct grid_cell *gc, u_int bg)
{
- struct grid_cell gc;
-
if (tty_term_flag(tty->term, TTYC_BCE))
return (0);
-
- memcpy(&gc, &grid_default_cell, sizeof gc);
- if (wp != NULL)
- tty_default_colours(&gc, wp);
-
- if (!COLOUR_DEFAULT(bg) || !COLOUR_DEFAULT(gc.bg))
+ if (!COLOUR_DEFAULT(bg) || !COLOUR_DEFAULT(gc->bg))
return (1);
return (0);
}
@@ -918,21 +939,21 @@ tty_fake_bce(const struct tty *tty, struct window_pane *wp, u_int bg)
static void
tty_redraw_region(struct tty *tty, const struct tty_ctx *ctx)
{
- struct window_pane *wp = ctx->wp;
- struct screen *s = wp->screen;
+ struct client *c = tty->client;
u_int i;
/*
- * If region is large, schedule a window redraw. In most cases this is
- * likely to be followed by some more scrolling.
+ * If region is large, schedule a redraw. In most cases this is likely
+ * to be followed by some more scrolling.
*/
if (tty_large_region(tty, ctx)) {
- wp->flags |= PANE_REDRAW;
+ log_debug("%s: %s large redraw", __func__, c->name);
+ ctx->redraw_cb(ctx);
return;
}
if (ctx->ocy < ctx->orupper || ctx->ocy > ctx->orlower) {
- for (i = ctx->ocy; i < screen_size_y(s); i++)
+ for (i = ctx->ocy; i < ctx->sy; i++)
tty_draw_pane(tty, ctx, i);
} else {
for (i = ctx->orupper; i <= ctx->orlower; i++)
@@ -942,21 +963,16 @@ tty_redraw_region(struct tty *tty, const struct tty_ctx *ctx)
/* Is this position visible in the pane? */
static int
-tty_is_visible(struct tty *tty, const struct tty_ctx *ctx, u_int px, u_int py,
- u_int nx, u_int ny)
+tty_is_visible(__unused struct tty *tty, const struct tty_ctx *ctx, u_int px,
+ u_int py, u_int nx, u_int ny)
{
- u_int xoff = ctx->xoff + px, yoff = ctx->yoff + py, lines;
+ u_int xoff = ctx->rxoff + px, yoff = ctx->ryoff + py;
if (!ctx->bigger)
return (1);
- if (status_at_line(tty->client) == 0)
- lines = status_line_size(tty->client);
- else
- lines = 0;
-
- if (xoff + nx <= ctx->ox || xoff >= ctx->ox + ctx->sx ||
- yoff + ny <= ctx->oy || yoff >= lines + ctx->oy + ctx->sy)
+ if (xoff + nx <= ctx->wox || xoff >= ctx->wox + ctx->wsx ||
+ yoff + ny <= ctx->woy || yoff >= ctx->woy + ctx->wsy)
return (0);
return (1);
}
@@ -966,33 +982,32 @@ static int
tty_clamp_line(struct tty *tty, const struct tty_ctx *ctx, u_int px, u_int py,
u_int nx, u_int *i, u_int *x, u_int *rx, u_int *ry)
{
- struct window_pane *wp = ctx->wp;
- u_int xoff = wp->xoff + px;
+ u_int xoff = ctx->rxoff + px;
if (!tty_is_visible(tty, ctx, px, py, nx, 1))
return (0);
- *ry = ctx->yoff + py - ctx->oy;
+ *ry = ctx->yoff + py - ctx->woy;
- if (xoff >= ctx->ox && xoff + nx <= ctx->ox + ctx->sx) {
+ if (xoff >= ctx->wox && xoff + nx <= ctx->wox + ctx->wsx) {
/* All visible. */
*i = 0;
- *x = ctx->xoff + px - ctx->ox;
+ *x = ctx->xoff + px - ctx->wox;
*rx = nx;
- } else if (xoff < ctx->ox && xoff + nx > ctx->ox + ctx->sx) {
+ } else if (xoff < ctx->wox && xoff + nx > ctx->wox + ctx->wsx) {
/* Both left and right not visible. */
- *i = ctx->ox;
+ *i = ctx->wox;
*x = 0;
- *rx = ctx->sx;
- } else if (xoff < ctx->ox) {
+ *rx = ctx->wsx;
+ } else if (xoff < ctx->wox) {
/* Left not visible. */
- *i = ctx->ox - (ctx->xoff + px);
+ *i = ctx->wox - (ctx->xoff + px);
*x = 0;
*rx = nx - *i;
} else {
/* Right not visible. */
*i = 0;
- *x = (ctx->xoff + px) - ctx->ox;
- *rx = ctx->sx - *x;
+ *x = (ctx->xoff + px) - ctx->wox;
+ *rx = ctx->wsx - *x;
}
if (*rx > nx)
fatalx("%s: x too big, %u > %u", __func__, *rx, nx);
@@ -1002,8 +1017,8 @@ tty_clamp_line(struct tty *tty, const struct tty_ctx *ctx, u_int px, u_int py,
/* Clear a line. */
static void
-tty_clear_line(struct tty *tty, struct window_pane *wp, u_int py, u_int px,
- u_int nx, u_int bg)
+tty_clear_line(struct tty *tty, const struct grid_cell *defaults, u_int py,
+ u_int px, u_int nx, u_int bg)
{
struct client *c = tty->client;
@@ -1014,7 +1029,7 @@ tty_clear_line(struct tty *tty, struct window_pane *wp, u_int py, u_int px,
return;
/* If genuine BCE is available, can try escape sequences. */
- if (!tty_fake_bce(tty, wp, bg)) {
+ if (!tty_fake_bce(tty, defaults, bg)) {
/* Off the end of the line, use EL if available. */
if (px + nx >= tty->sx && tty_term_has(tty->term, TTYC_EL)) {
tty_cursor(tty, px, py);
@@ -1053,7 +1068,7 @@ tty_clear_pane_line(struct tty *tty, const struct tty_ctx *ctx, u_int py,
log_debug("%s: %s, %u at %u,%u", __func__, c->name, nx, px, py);
if (tty_clamp_line(tty, ctx, px, py, nx, &i, &x, &rx, &ry))
- tty_clear_line(tty, ctx->wp, ry, x, rx, bg);
+ tty_clear_line(tty, &ctx->defaults, ry, x, rx, bg);
}
/* Clamp area position to visible part of pane. */
@@ -1062,56 +1077,55 @@ tty_clamp_area(struct tty *tty, const struct tty_ctx *ctx, u_int px, u_int py,
u_int nx, u_int ny, u_int *i, u_int *j, u_int *x, u_int *y, u_int *rx,
u_int *ry)
{
- struct window_pane *wp = ctx->wp;
- u_int xoff = wp->xoff + px, yoff = wp->yoff + py;
+ u_int xoff = ctx->rxoff + px, yoff = ctx->ryoff + py;
if (!tty_is_visible(tty, ctx, px, py, nx, ny))
return (0);
- if (xoff >= ctx->ox && xoff + nx <= ctx->ox + ctx->sx) {
+ if (xoff >= ctx->wox && xoff + nx <= ctx->wox + ctx->wsx) {
/* All visible. */
*i = 0;
- *x = ctx->xoff + px - ctx->ox;
+ *x = ctx->xoff + px - ctx->wox;
*rx = nx;
- } else if (xoff < ctx->ox && xoff + nx > ctx->ox + ctx->sx) {
+ } else if (xoff < ctx->wox && xoff + nx > ctx->wox + ctx->wsx) {
/* Both left and right not visible. */
- *i = ctx->ox;
+ *i = ctx->wox;
*x = 0;
- *rx = ctx->sx;
- } else if (xoff < ctx->ox) {
+ *rx = ctx->wsx;
+ } else if (xoff < ctx->wox) {
/* Left not visible. */
- *i = ctx->ox - (ctx->xoff + px);
+ *i = ctx->wox - (ctx->xoff + px);
*x = 0;
*rx = nx - *i;
} else {
/* Right not visible. */
*i = 0;
- *x = (ctx->xoff + px) - ctx->ox;
- *rx = ctx->sx - *x;
+ *x = (ctx->xoff + px) - ctx->wox;
+ *rx = ctx->wsx - *x;
}
if (*rx > nx)
fatalx("%s: x too big, %u > %u", __func__, *rx, nx);
- if (yoff >= ctx->oy && yoff + ny <= ctx->oy + ctx->sy) {
+ if (yoff >= ctx->woy && yoff + ny <= ctx->woy + ctx->wsy) {
/* All visible. */
*j = 0;
- *y = ctx->yoff + py - ctx->oy;
+ *y = ctx->yoff + py - ctx->woy;
*ry = ny;
- } else if (yoff < ctx->oy && yoff + ny > ctx->oy + ctx->sy) {
+ } else if (yoff < ctx->woy && yoff + ny > ctx->woy + ctx->wsy) {
/* Both top and bottom not visible. */
- *j = ctx->oy;
+ *j = ctx->woy;
*y = 0;
- *ry = ctx->sy;
- } else if (yoff < ctx->oy) {
+ *ry = ctx->wsy;
+ } else if (yoff < ctx->woy) {
/* Top not visible. */
- *j = ctx->oy - (ctx->yoff + py);
+ *j = ctx->woy - (ctx->yoff + py);
*y = 0;
*ry = ny - *j;
} else {
/* Bottom not visible. */
*j = 0;
- *y = (ctx->yoff + py) - ctx->oy;
- *ry = ctx->sy - *y;
+ *y = (ctx->yoff + py) - ctx->woy;
+ *ry = ctx->wsy - *y;
}
if (*ry > ny)
fatalx("%s: y too big, %u > %u", __func__, *ry, ny);
@@ -1121,8 +1135,8 @@ tty_clamp_area(struct tty *tty, const struct tty_ctx *ctx, u_int px, u_int py,
/* Clear an area, adjusting to visible part of pane. */
static void
-tty_clear_area(struct tty *tty, struct window_pane *wp, u_int py, u_int ny,
- u_int px, u_int nx, u_int bg)
+tty_clear_area(struct tty *tty, const struct grid_cell *defaults, u_int py,
+ u_int ny, u_int px, u_int nx, u_int bg)
{
struct client *c = tty->client;
u_int yy;
@@ -1135,7 +1149,7 @@ tty_clear_area(struct tty *tty, struct window_pane *wp, u_int py, u_int ny,
return;
/* If genuine BCE is available, can try escape sequences. */
- if (!tty_fake_bce(tty, wp, bg)) {
+ if (!tty_fake_bce(tty, defaults, bg)) {
/* Use ED if clearing off the bottom of the terminal. */
if (px == 0 &&
px + nx >= tty->sx &&
@@ -1151,8 +1165,7 @@ tty_clear_area(struct tty *tty, struct window_pane *wp, u_int py, u_int ny,
* background colour isn't default (because it doesn't work
* after SGR 0).
*/
- if (((tty->term->flags|tty->term_flags) & TERM_DECFRA) &&
- !COLOUR_DEFAULT(bg)) {
+ if ((tty->term->flags & TERM_DECFRA) && !COLOUR_DEFAULT(bg)) {
xsnprintf(tmp, sizeof tmp, "\033[32;%u;%u;%u;%u$x",
py + 1, px + 1, py + ny, px + nx);
tty_puts(tty, tmp);
@@ -1189,7 +1202,7 @@ tty_clear_area(struct tty *tty, struct window_pane *wp, u_int py, u_int ny,
/* Couldn't use an escape sequence, loop over the lines. */
for (yy = py; yy < py + ny; yy++)
- tty_clear_line(tty, wp, yy, px, nx, bg);
+ tty_clear_line(tty, defaults, yy, px, nx, bg);
}
/* Clear an area in a pane. */
@@ -1200,24 +1213,26 @@ tty_clear_pane_area(struct tty *tty, const struct tty_ctx *ctx, u_int py,
u_int i, j, x, y, rx, ry;
if (tty_clamp_area(tty, ctx, px, py, nx, ny, &i, &j, &x, &y, &rx, &ry))
- tty_clear_area(tty, ctx->wp, y, ry, x, rx, bg);
+ tty_clear_area(tty, &ctx->defaults, y, ry, x, rx, bg);
}
static void
tty_draw_pane(struct tty *tty, const struct tty_ctx *ctx, u_int py)
{
- struct window_pane *wp = ctx->wp;
- struct screen *s = wp->screen;
- u_int nx = screen_size_x(s), i, x, rx, ry;
+ struct screen *s = ctx->s;
+ u_int nx = ctx->sx, i, x, rx, ry;
log_debug("%s: %s %u %d", __func__, tty->client->name, py, ctx->bigger);
if (!ctx->bigger) {
- tty_draw_line(tty, wp, s, 0, py, nx, ctx->xoff, ctx->yoff + py);
+ tty_draw_line(tty, s, 0, py, nx, ctx->xoff, ctx->yoff + py,
+ &ctx->defaults, ctx->palette);
return;
}
- if (tty_clamp_line(tty, ctx, 0, py, nx, &i, &x, &rx, &ry))
- tty_draw_line(tty, wp, s, i, py, rx, x, ry);
+ if (tty_clamp_line(tty, ctx, 0, py, nx, &i, &x, &rx, &ry)) {
+ tty_draw_line(tty, s, i, py, rx, x, ry, &ctx->defaults,
+ ctx->palette);
+ }
}
static const struct grid_cell *
@@ -1231,7 +1246,7 @@ tty_check_codeset(struct tty *tty, const struct grid_cell *gc)
return (gc);
/* UTF-8 terminal and a UTF-8 character - fine. */
- if (tty->flags & TTY_UTF8)
+ if (tty->client->flags & CLIENT_UTF8)
return (gc);
/* Replace by the right number of underscores. */
@@ -1244,9 +1259,19 @@ tty_check_codeset(struct tty *tty, const struct grid_cell *gc)
return (&new);
}
+static int
+tty_check_overlay(struct tty *tty, u_int px, u_int py)
+{
+ struct client *c = tty->client;
+
+ if (c->overlay_check == NULL)
+ return (1);
+ return (c->overlay_check(c, px, py));
+}
+
void
-tty_draw_line(struct tty *tty, struct window_pane *wp, struct screen *s,
- u_int px, u_int py, u_int nx, u_int atx, u_int aty)
+tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx,
+ u_int atx, u_int aty, const struct grid_cell *defaults, int *palette)
{
struct grid *gd = s->grid;
struct grid_cell gc, last;
@@ -1294,8 +1319,7 @@ tty_draw_line(struct tty *tty, struct window_pane *wp, struct screen *s,
gl = NULL;
else
gl = grid_get_line(gd, gd->hsize + py - 1);
- if (wp == NULL ||
- gl == NULL ||
+ if (gl == NULL ||
(~gl->flags & GRID_LINE_WRAPPED) ||
atx != 0 ||
tty->cx < tty->sx ||
@@ -1304,8 +1328,8 @@ tty_draw_line(struct tty *tty, struct window_pane *wp, struct screen *s,
atx == 0 &&
px + sx != nx &&
tty_term_has(tty->term, TTYC_EL1) &&
- !tty_fake_bce(tty, wp, 8)) {
- tty_default_attributes(tty, wp, 8);
+ !tty_fake_bce(tty, defaults, 8)) {
+ tty_default_attributes(tty, defaults, palette, 8);
tty_cursor(tty, nx - 1, aty);
tty_putcode(tty, TTYC_EL1);
cleared = 1;
@@ -1323,7 +1347,8 @@ tty_draw_line(struct tty *tty, struct window_pane *wp, struct screen *s,
grid_view_get_cell(gd, px + i, py, &gc);
gcp = tty_check_codeset(tty, &gc);
if (len != 0 &&
- ((gcp->attr & GRID_ATTR_CHARSET) ||
+ (!tty_check_overlay(tty, atx + ux + width, aty) ||
+ (gcp->attr & GRID_ATTR_CHARSET) ||
gcp->flags != last.flags ||
gcp->attr != last.attr ||
gcp->fg != last.fg ||
@@ -1331,11 +1356,11 @@ tty_draw_line(struct tty *tty, struct window_pane *wp, struct screen *s,
gcp->us != last.us ||
ux + width + gcp->data.width > nx ||
(sizeof buf) - len < gcp->data.size)) {
- tty_attributes(tty, &last, wp);
+ tty_attributes(tty, &last, defaults, palette);
if (last.flags & GRID_FLAG_CLEARED) {
log_debug("%s: %zu cleared", __func__, len);
- tty_clear_line(tty, wp, aty, atx + ux, width,
- last.bg);
+ tty_clear_line(tty, defaults, aty, atx + ux,
+ width, last.bg);
} else {
if (!wrapped || atx != 0 || ux != 0)
tty_cursor(tty, atx + ux, aty);
@@ -1352,8 +1377,10 @@ tty_draw_line(struct tty *tty, struct window_pane *wp, struct screen *s,
screen_select_cell(s, &last, gcp);
else
memcpy(&last, gcp, sizeof last);
- if (ux + gcp->data.width > nx) {
- tty_attributes(tty, &last, wp);
+ if (!tty_check_overlay(tty, atx + ux, aty))
+ ux += gcp->data.width;
+ else if (ux + gcp->data.width > nx) {
+ tty_attributes(tty, &last, defaults, palette);
tty_cursor(tty, atx + ux, aty);
for (j = 0; j < gcp->data.width; j++) {
if (ux + j > nx)
@@ -1362,11 +1389,11 @@ tty_draw_line(struct tty *tty, struct window_pane *wp, struct screen *s,
ux++;
}
} else if (gcp->attr & GRID_ATTR_CHARSET) {
- tty_attributes(tty, &last, wp);
+ tty_attributes(tty, &last, defaults, palette);
tty_cursor(tty, atx + ux, aty);
for (j = 0; j < gcp->data.size; j++)
tty_putc(tty, gcp->data.data[j]);
- ux += gc.data.width;
+ ux += gcp->data.width;
} else {
memcpy(buf + len, gcp->data.data, gcp->data.size);
len += gcp->data.size;
@@ -1374,10 +1401,11 @@ tty_draw_line(struct tty *tty, struct window_pane *wp, struct screen *s,
}
}
if (len != 0 && ((~last.flags & GRID_FLAG_CLEARED) || last.bg != 8)) {
- tty_attributes(tty, &last, wp);
+ tty_attributes(tty, &last, defaults, palette);
if (last.flags & GRID_FLAG_CLEARED) {
log_debug("%s: %zu cleared (end)", __func__, len);
- tty_clear_line(tty, wp, aty, atx + ux, width, last.bg);
+ tty_clear_line(tty, defaults, aty, atx + ux, width,
+ last.bg);
} else {
if (!wrapped || atx != 0 || ux != 0)
tty_cursor(tty, atx + ux, aty);
@@ -1389,16 +1417,46 @@ tty_draw_line(struct tty *tty, struct window_pane *wp, struct screen *s,
if (!cleared && ux < nx) {
log_debug("%s: %u to end of line (%zu cleared)", __func__,
nx - ux, len);
- tty_default_attributes(tty, wp, 8);
- tty_clear_line(tty, wp, aty, atx + ux, nx - ux, 8);
+ tty_default_attributes(tty, defaults, palette, 8);
+ tty_clear_line(tty, defaults, aty, atx + ux, nx - ux, 8);
}
tty->flags = (tty->flags & ~TTY_NOCURSOR) | flags;
tty_update_mode(tty, tty->mode, s);
}
+void
+tty_sync_start(struct tty *tty)
+{
+ if (tty->flags & TTY_BLOCK)
+ return;
+ if (tty->flags & TTY_SYNCING)
+ return;
+ tty->flags |= TTY_SYNCING;
+
+ if (tty_term_has(tty->term, TTYC_SYNC)) {
+ log_debug("%s sync start", tty->client->name);
+ tty_putcode1(tty, TTYC_SYNC, 1);
+ }
+}
+
+void
+tty_sync_end(struct tty *tty)
+{
+ if (tty->flags & TTY_BLOCK)
+ return;
+ if (~tty->flags & TTY_SYNCING)
+ return;
+ tty->flags &= ~TTY_SYNCING;
+
+ if (tty_term_has(tty->term, TTYC_SYNC)) {
+ log_debug("%s sync end", tty->client->name);
+ tty_putcode1(tty, TTYC_SYNC, 2);
+ }
+}
+
static int
-tty_client_ready(struct client *c, struct window_pane *wp)
+tty_client_ready(struct client *c)
{
if (c->session == NULL || c->tty.term == NULL)
return (0);
@@ -1406,10 +1464,6 @@ tty_client_ready(struct client *c, struct window_pane *wp)
return (0);
if (c->tty.flags & TTY_FREEZE)
return (0);
- if (c->session->curw->window != wp->window)
- return (0);
- if (wp->layout_cell == NULL)
- return (0);
return (1);
}
@@ -1417,27 +1471,19 @@ void
tty_write(void (*cmdfn)(struct tty *, const struct tty_ctx *),
struct tty_ctx *ctx)
{
- struct window_pane *wp = ctx->wp;
- struct client *c;
+ struct client *c;
+ int state;
- if (wp == NULL)
+ if (ctx->set_client_cb == NULL)
return;
- if (wp->flags & (PANE_REDRAW|PANE_DROP))
- return;
-
TAILQ_FOREACH(c, &clients, entry) {
- if (!tty_client_ready(c, wp))
+ if (!tty_client_ready(c))
+ continue;
+ state = ctx->set_client_cb(ctx, c);
+ if (state == -1)
+ break;
+ if (state == 0)
continue;
-
- ctx->bigger = tty_window_offset(&c->tty, &ctx->ox, &ctx->oy,
- &ctx->sx, &ctx->sy);
-
- ctx->xoff = wp->xoff;
- ctx->yoff = wp->yoff;
-
- if (status_at_line(c) == 0)
- ctx->yoff += status_line_size(c);
-
cmdfn(&c->tty, ctx);
}
}
@@ -1445,18 +1491,16 @@ tty_write(void (*cmdfn)(struct tty *, const struct tty_ctx *),
void
tty_cmd_insertcharacter(struct tty *tty, const struct tty_ctx *ctx)
{
- struct window_pane *wp = ctx->wp;
-
if (ctx->bigger ||
- !tty_pane_full_width(tty, ctx) ||
- tty_fake_bce(tty, wp, ctx->bg) ||
+ !tty_full_width(tty, ctx) ||
+ tty_fake_bce(tty, &ctx->defaults, ctx->bg) ||
(!tty_term_has(tty->term, TTYC_ICH) &&
!tty_term_has(tty->term, TTYC_ICH1))) {
tty_draw_pane(tty, ctx, ctx->ocy);
return;
}
- tty_default_attributes(tty, wp, ctx->bg);
+ tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg);
tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy);
@@ -1466,18 +1510,16 @@ 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;
-
if (ctx->bigger ||
- !tty_pane_full_width(tty, ctx) ||
- tty_fake_bce(tty, wp, ctx->bg) ||
+ !tty_full_width(tty, ctx) ||
+ tty_fake_bce(tty, &ctx->defaults, ctx->bg) ||
(!tty_term_has(tty->term, TTYC_DCH) &&
!tty_term_has(tty->term, TTYC_DCH1))) {
tty_draw_pane(tty, ctx, ctx->ocy);
return;
}
- tty_default_attributes(tty, wp, ctx->bg);
+ tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg);
tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy);
@@ -1492,12 +1534,12 @@ tty_cmd_clearcharacter(struct tty *tty, const struct tty_ctx *ctx)
return;
}
- tty_default_attributes(tty, ctx->wp, ctx->bg);
+ tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg);
tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy);
if (tty_term_has(tty->term, TTYC_ECH) &&
- !tty_fake_bce(tty, ctx->wp, 8))
+ !tty_fake_bce(tty, &ctx->defaults, 8))
tty_putcode1(tty, TTYC_ECH, ctx->num);
else
tty_repeat_space(tty, ctx->num);
@@ -1507,17 +1549,17 @@ void
tty_cmd_insertline(struct tty *tty, const struct tty_ctx *ctx)
{
if (ctx->bigger ||
- !tty_pane_full_width(tty, ctx) ||
- tty_fake_bce(tty, ctx->wp, ctx->bg) ||
+ !tty_full_width(tty, ctx) ||
+ tty_fake_bce(tty, &ctx->defaults, ctx->bg) ||
!tty_term_has(tty->term, TTYC_CSR) ||
!tty_term_has(tty->term, TTYC_IL1) ||
- ctx->wp->sx == 1 ||
- ctx->wp->sy == 1) {
+ ctx->sx == 1 ||
+ ctx->sy == 1) {
tty_redraw_region(tty, ctx);
return;
}
- tty_default_attributes(tty, ctx->wp, ctx->bg);
+ tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg);
tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower);
tty_margin_off(tty);
@@ -1531,17 +1573,17 @@ void
tty_cmd_deleteline(struct tty *tty, const struct tty_ctx *ctx)
{
if (ctx->bigger ||
- !tty_pane_full_width(tty, ctx) ||
- tty_fake_bce(tty, ctx->wp, ctx->bg) ||
+ !tty_full_width(tty, ctx) ||
+ tty_fake_bce(tty, &ctx->defaults, ctx->bg) ||
!tty_term_has(tty->term, TTYC_CSR) ||
!tty_term_has(tty->term, TTYC_DL1) ||
- ctx->wp->sx == 1 ||
- ctx->wp->sy == 1) {
+ ctx->sx == 1 ||
+ ctx->sy == 1) {
tty_redraw_region(tty, ctx);
return;
}
- tty_default_attributes(tty, ctx->wp, ctx->bg);
+ tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg);
tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower);
tty_margin_off(tty);
@@ -1554,33 +1596,25 @@ 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;
- u_int nx;
+ tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg);
- tty_default_attributes(tty, wp, ctx->bg);
-
- nx = screen_size_x(wp->screen);
- tty_clear_pane_line(tty, ctx, ctx->ocy, 0, nx, ctx->bg);
+ tty_clear_pane_line(tty, ctx, ctx->ocy, 0, ctx->sx, ctx->bg);
}
void
tty_cmd_clearendofline(struct tty *tty, const struct tty_ctx *ctx)
{
- struct window_pane *wp = ctx->wp;
- u_int nx;
+ u_int nx = ctx->sx - ctx->ocx;
- tty_default_attributes(tty, wp, ctx->bg);
+ tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg);
- nx = screen_size_x(wp->screen) - ctx->ocx;
tty_clear_pane_line(tty, ctx, ctx->ocy, ctx->ocx, nx, ctx->bg);
}
void
tty_cmd_clearstartofline(struct tty *tty, const struct tty_ctx *ctx)
{
- struct window_pane *wp = ctx->wp;
-
- tty_default_attributes(tty, wp, ctx->bg);
+ tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg);
tty_clear_pane_line(tty, ctx, ctx->ocy, 0, ctx->ocx + 1, ctx->bg);
}
@@ -1588,24 +1622,22 @@ 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;
-
if (ctx->ocy != ctx->orupper)
return;
if (ctx->bigger ||
- (!tty_pane_full_width(tty, ctx) && !tty_use_margin(tty)) ||
- tty_fake_bce(tty, wp, 8) ||
+ (!tty_full_width(tty, ctx) && !tty_use_margin(tty)) ||
+ tty_fake_bce(tty, &ctx->defaults, 8) ||
!tty_term_has(tty->term, TTYC_CSR) ||
(!tty_term_has(tty->term, TTYC_RI) &&
!tty_term_has(tty->term, TTYC_RIN)) ||
- ctx->wp->sx == 1 ||
- ctx->wp->sy == 1) {
+ ctx->sx == 1 ||
+ ctx->sy == 1) {
tty_redraw_region(tty, ctx);
return;
}
- tty_default_attributes(tty, wp, ctx->bg);
+ tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg);
tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower);
tty_margin_pane(tty, ctx);
@@ -1620,22 +1652,20 @@ tty_cmd_reverseindex(struct tty *tty, const struct tty_ctx *ctx)
void
tty_cmd_linefeed(struct tty *tty, const struct tty_ctx *ctx)
{
- struct window_pane *wp = ctx->wp;
-
if (ctx->ocy != ctx->orlower)
return;
if (ctx->bigger ||
- (!tty_pane_full_width(tty, ctx) && !tty_use_margin(tty)) ||
- tty_fake_bce(tty, wp, 8) ||
+ (!tty_full_width(tty, ctx) && !tty_use_margin(tty)) ||
+ tty_fake_bce(tty, &ctx->defaults, 8) ||
!tty_term_has(tty->term, TTYC_CSR) ||
- wp->sx == 1 ||
- wp->sy == 1) {
+ ctx->sx == 1 ||
+ ctx->sy == 1) {
tty_redraw_region(tty, ctx);
return;
}
- tty_default_attributes(tty, wp, ctx->bg);
+ tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg);
tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower);
tty_margin_pane(tty, ctx);
@@ -1661,20 +1691,19 @@ tty_cmd_linefeed(struct tty *tty, const struct tty_ctx *ctx)
void
tty_cmd_scrollup(struct tty *tty, const struct tty_ctx *ctx)
{
- struct window_pane *wp = ctx->wp;
- u_int i;
+ u_int i;
if (ctx->bigger ||
- (!tty_pane_full_width(tty, ctx) && !tty_use_margin(tty)) ||
- tty_fake_bce(tty, wp, 8) ||
+ (!tty_full_width(tty, ctx) && !tty_use_margin(tty)) ||
+ tty_fake_bce(tty, &ctx->defaults, 8) ||
!tty_term_has(tty->term, TTYC_CSR) ||
- wp->sx == 1 ||
- wp->sy == 1) {
+ ctx->sx == 1 ||
+ ctx->sy == 1) {
tty_redraw_region(tty, ctx);
return;
}
- tty_default_attributes(tty, wp, ctx->bg);
+ tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg);
tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower);
tty_margin_pane(tty, ctx);
@@ -1687,7 +1716,10 @@ tty_cmd_scrollup(struct tty *tty, const struct tty_ctx *ctx)
for (i = 0; i < ctx->num; i++)
tty_putc(tty, '\n');
} else {
- tty_cursor(tty, 0, tty->cy);
+ if (tty->cy == UINT_MAX)
+ tty_cursor(tty, 0, 0);
+ else
+ tty_cursor(tty, 0, tty->cy);
tty_putcode1(tty, TTYC_INDN, ctx->num);
}
}
@@ -1695,22 +1727,21 @@ tty_cmd_scrollup(struct tty *tty, const struct tty_ctx *ctx)
void
tty_cmd_scrolldown(struct tty *tty, const struct tty_ctx *ctx)
{
- struct window_pane *wp = ctx->wp;
- u_int i;
+ u_int i;
if (ctx->bigger ||
- (!tty_pane_full_width(tty, ctx) && !tty_use_margin(tty)) ||
- tty_fake_bce(tty, wp, 8) ||
+ (!tty_full_width(tty, ctx) && !tty_use_margin(tty)) ||
+ tty_fake_bce(tty, &ctx->defaults, 8) ||
!tty_term_has(tty->term, TTYC_CSR) ||
(!tty_term_has(tty->term, TTYC_RI) &&
!tty_term_has(tty->term, TTYC_RIN)) ||
- wp->sx == 1 ||
- wp->sy == 1) {
+ ctx->sx == 1 ||
+ ctx->sy == 1) {
tty_redraw_region(tty, ctx);
return;
}
- tty_default_attributes(tty, wp, ctx->bg);
+ tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg);
tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower);
tty_margin_pane(tty, ctx);
@@ -1727,23 +1758,22 @@ tty_cmd_scrolldown(struct tty *tty, const struct tty_ctx *ctx)
void
tty_cmd_clearendofscreen(struct tty *tty, const struct tty_ctx *ctx)
{
- struct window_pane *wp = ctx->wp;
- u_int px, py, nx, ny;
+ u_int px, py, nx, ny;
- tty_default_attributes(tty, wp, ctx->bg);
+ tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg);
- tty_region_pane(tty, ctx, 0, screen_size_y(wp->screen) - 1);
+ tty_region_pane(tty, ctx, 0, ctx->sy - 1);
tty_margin_off(tty);
px = 0;
- nx = screen_size_x(wp->screen);
+ nx = ctx->sx;
py = ctx->ocy + 1;
- ny = screen_size_y(wp->screen) - ctx->ocy - 1;
+ ny = ctx->sy - ctx->ocy - 1;
tty_clear_pane_area(tty, ctx, py, ny, px, nx, ctx->bg);
px = ctx->ocx;
- nx = screen_size_x(wp->screen) - ctx->ocx;
+ nx = ctx->sx - ctx->ocx;
py = ctx->ocy;
tty_clear_pane_line(tty, ctx, py, px, nx, ctx->bg);
@@ -1752,16 +1782,15 @@ 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;
- u_int px, py, nx, ny;
+ u_int px, py, nx, ny;
- tty_default_attributes(tty, wp, ctx->bg);
+ tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg);
- tty_region_pane(tty, ctx, 0, screen_size_y(wp->screen) - 1);
+ tty_region_pane(tty, ctx, 0, ctx->sy - 1);
tty_margin_off(tty);
px = 0;
- nx = screen_size_x(wp->screen);
+ nx = ctx->sx;
py = 0;
ny = ctx->ocy;
@@ -1777,18 +1806,17 @@ 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;
- u_int px, py, nx, ny;
+ u_int px, py, nx, ny;
- tty_default_attributes(tty, wp, ctx->bg);
+ tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg);
- tty_region_pane(tty, ctx, 0, screen_size_y(wp->screen) - 1);
+ tty_region_pane(tty, ctx, 0, ctx->sy - 1);
tty_margin_off(tty);
px = 0;
- nx = screen_size_x(wp->screen);
+ nx = ctx->sx;
py = 0;
- ny = screen_size_y(wp->screen);
+ ny = ctx->sy;
tty_clear_pane_area(tty, ctx, py, ny, px, nx, ctx->bg);
}
@@ -1796,23 +1824,21 @@ tty_cmd_clearscreen(struct tty *tty, const struct tty_ctx *ctx)
void
tty_cmd_alignmenttest(struct tty *tty, const struct tty_ctx *ctx)
{
- struct window_pane *wp = ctx->wp;
- struct screen *s = wp->screen;
- u_int i, j;
+ u_int i, j;
if (ctx->bigger) {
- wp->flags |= PANE_REDRAW;
+ ctx->redraw_cb(ctx);
return;
}
- tty_attributes(tty, &grid_default_cell, wp);
+ tty_attributes(tty, &grid_default_cell, &ctx->defaults, ctx->palette);
- tty_region_pane(tty, ctx, 0, screen_size_y(s) - 1);
+ tty_region_pane(tty, ctx, 0, ctx->sy - 1);
tty_margin_off(tty);
- for (j = 0; j < screen_size_y(s); j++) {
+ for (j = 0; j < ctx->sy; j++) {
tty_cursor_pane(tty, ctx, 0, j);
- for (i = 0; i < screen_size_x(s); i++)
+ for (i = 0; i < ctx->sx; i++)
tty_putc(tty, 'E');
}
}
@@ -1823,30 +1849,28 @@ tty_cmd_cell(struct tty *tty, const struct tty_ctx *ctx)
if (!tty_is_visible(tty, ctx, ctx->ocx, ctx->ocy, 1, 1))
return;
- if (ctx->xoff + ctx->ocx - ctx->ox > tty->sx - 1 &&
+ if (ctx->xoff + ctx->ocx - ctx->wox > tty->sx - 1 &&
ctx->ocy == ctx->orlower &&
- tty_pane_full_width(tty, ctx))
+ tty_full_width(tty, ctx))
tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower);
tty_margin_off(tty);
tty_cursor_pane_unless_wrap(tty, ctx, ctx->ocx, ctx->ocy);
- tty_cell(tty, ctx->cell, ctx->wp);
+ tty_cell(tty, ctx->cell, &ctx->defaults, ctx->palette);
}
void
tty_cmd_cells(struct tty *tty, const struct tty_ctx *ctx)
{
- struct window_pane *wp = ctx->wp;
-
if (!tty_is_visible(tty, ctx, ctx->ocx, ctx->ocy, ctx->num, 1))
return;
if (ctx->bigger &&
- (ctx->xoff + ctx->ocx < ctx->ox ||
- ctx->xoff + ctx->ocx + ctx->num > ctx->ox + ctx->sx)) {
+ (ctx->xoff + ctx->ocx < ctx->wox ||
+ ctx->xoff + ctx->ocx + ctx->num > ctx->wox + ctx->wsx)) {
if (!ctx->wrapped ||
- !tty_pane_full_width(tty, ctx) ||
+ !tty_full_width(tty, ctx) ||
(tty->term->flags & TERM_NOXENL) ||
ctx->xoff + ctx->ocx != 0 ||
ctx->yoff + ctx->ocy != tty->cy + 1 ||
@@ -1854,14 +1878,14 @@ tty_cmd_cells(struct tty *tty, const struct tty_ctx *ctx)
tty->cy == tty->rlower)
tty_draw_pane(tty, ctx, ctx->ocy);
else
- wp->flags |= PANE_REDRAW;
+ ctx->redraw_cb(ctx);
return;
}
tty_margin_off(tty);
tty_cursor_pane_unless_wrap(tty, ctx, ctx->ocx, ctx->ocy);
- tty_attributes(tty, ctx->cell, ctx->wp);
+ tty_attributes(tty, ctx->cell, &ctx->defaults, ctx->palette);
tty_putn(tty, ctx->ptr, ctx->num, ctx->num);
}
@@ -1890,8 +1914,15 @@ tty_cmd_rawstring(struct tty *tty, const struct tty_ctx *ctx)
tty_invalidate(tty);
}
+void
+tty_cmd_syncstart(struct tty *tty, __unused const struct tty_ctx *ctx)
+{
+ tty_sync_start(tty);
+}
+
static void
-tty_cell(struct tty *tty, const struct grid_cell *gc, struct window_pane *wp)
+tty_cell(struct tty *tty, const struct grid_cell *gc,
+ const struct grid_cell *defaults, int *palette)
{
const struct grid_cell *gcp;
@@ -1906,7 +1937,7 @@ tty_cell(struct tty *tty, const struct grid_cell *gc, struct window_pane *wp)
return;
/* Set the attributes. */
- tty_attributes(tty, gc, wp);
+ tty_attributes(tty, gc, defaults, palette);
/* Get the cell and if ASCII write with putc to do ACS translation. */
gcp = tty_check_codeset(tty, gc);
@@ -1932,27 +1963,22 @@ tty_reset(struct tty *tty)
tty_putcode(tty, TTYC_SGR0);
memcpy(gc, &grid_default_cell, sizeof *gc);
}
-
memcpy(&tty->last_cell, &grid_default_cell, sizeof tty->last_cell);
- tty->last_wp = -1;
}
static void
tty_invalidate(struct tty *tty)
{
memcpy(&tty->cell, &grid_default_cell, sizeof tty->cell);
-
memcpy(&tty->last_cell, &grid_default_cell, sizeof tty->last_cell);
- tty->last_wp = -1;
tty->cx = tty->cy = UINT_MAX;
-
tty->rupper = tty->rleft = UINT_MAX;
tty->rlower = tty->rright = UINT_MAX;
if (tty->flags & TTY_STARTED) {
if (tty_use_margin(tty))
- tty_puts(tty, "\033[?69h"); /* DECLRMM */
+ tty_putcode(tty, TTYC_ENMG);
tty_putcode(tty, TTYC_SGR0);
tty->mode = ALL_MODES;
@@ -1977,8 +2003,8 @@ static void
tty_region_pane(struct tty *tty, const struct tty_ctx *ctx, u_int rupper,
u_int rlower)
{
- tty_region(tty, ctx->yoff + rupper - ctx->oy,
- ctx->yoff + rlower - ctx->oy);
+ tty_region(tty, ctx->yoff + rupper - ctx->woy,
+ ctx->yoff + rlower - ctx->woy);
}
/* Set region at absolute position. */
@@ -1999,8 +2025,12 @@ tty_region(struct tty *tty, u_int rupper, u_int rlower)
* 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);
+ if (tty->cx >= tty->sx) {
+ if (tty->cy == UINT_MAX)
+ tty_cursor(tty, 0, 0);
+ else
+ tty_cursor(tty, 0, tty->cy);
+ }
tty_putcode2(tty, TTYC_CSR, tty->rupper, tty->rlower);
tty->cx = tty->cy = UINT_MAX;
@@ -2017,16 +2047,14 @@ tty_margin_off(struct tty *tty)
static void
tty_margin_pane(struct tty *tty, const struct tty_ctx *ctx)
{
- tty_margin(tty, ctx->xoff - ctx->ox,
- ctx->xoff + ctx->wp->sx - 1 - ctx->ox);
+ tty_margin(tty, ctx->xoff - ctx->wox,
+ ctx->xoff + ctx->sx - 1 - ctx->wox);
}
/* Set margin at absolute position. */
static void
tty_margin(struct tty *tty, u_int rleft, u_int rright)
{
- char s[64];
-
if (!tty_use_margin(tty))
return;
if (tty->rleft == rleft && tty->rright == rright)
@@ -2038,10 +2066,9 @@ tty_margin(struct tty *tty, u_int rleft, u_int rright)
tty->rright = rright;
if (rleft == 0 && rright == tty->sx - 1)
- snprintf(s, sizeof s, "\033[s");
+ tty_putcode(tty, TTYC_CLMG);
else
- snprintf(s, sizeof s, "\033[%u;%us", rleft + 1, rright + 1);
- tty_puts(tty, s);
+ tty_putcode2(tty, TTYC_CMG, rleft, rright);
tty->cx = tty->cy = UINT_MAX;
}
@@ -2054,7 +2081,7 @@ tty_cursor_pane_unless_wrap(struct tty *tty, const struct tty_ctx *ctx,
u_int cx, u_int cy)
{
if (!ctx->wrapped ||
- !tty_pane_full_width(tty, ctx) ||
+ !tty_full_width(tty, ctx) ||
(tty->term->flags & TERM_NOXENL) ||
ctx->xoff + cx != 0 ||
ctx->yoff + cy != tty->cy + 1 ||
@@ -2069,7 +2096,7 @@ tty_cursor_pane_unless_wrap(struct tty *tty, const struct tty_ctx *ctx,
static void
tty_cursor_pane(struct tty *tty, const struct tty_ctx *ctx, u_int cx, u_int cy)
{
- tty_cursor(tty, ctx->xoff + cx - ctx->ox, ctx->yoff + cy - ctx->oy);
+ tty_cursor(tty, ctx->xoff + cx - ctx->wox, ctx->yoff + cy - ctx->woy);
}
/* Move cursor to absolute position. */
@@ -2080,6 +2107,9 @@ tty_cursor(struct tty *tty, u_int cx, u_int cy)
u_int thisx, thisy;
int change;
+ if (tty->flags & TTY_BLOCK)
+ return;
+
if (cx > tty->sx - 1)
cx = tty->sx - 1;
@@ -2211,27 +2241,24 @@ out:
void
tty_attributes(struct tty *tty, const struct grid_cell *gc,
- struct window_pane *wp)
+ const struct grid_cell *defaults, int *palette)
{
struct grid_cell *tc = &tty->cell, gc2;
int changed;
- /* Ignore cell if it is the same as the last one. */
- if (wp != NULL &&
- (int)wp->id == tty->last_wp &&
- ~(wp->flags & PANE_STYLECHANGED) &&
- gc->attr == tty->last_cell.attr &&
- gc->fg == tty->last_cell.fg &&
- gc->bg == tty->last_cell.bg &&
- gc->us == tty->last_cell.us)
- return;
- tty->last_wp = (wp != NULL ? (int)wp->id : -1);
- memcpy(&tty->last_cell, gc, sizeof tty->last_cell);
-
/* Copy cell and update default colours. */
memcpy(&gc2, gc, sizeof gc2);
- if (wp != NULL)
- tty_default_colours(&gc2, wp);
+ if (gc2.fg == 8)
+ gc2.fg = defaults->fg;
+ if (gc2.bg == 8)
+ gc2.bg = defaults->bg;
+
+ /* Ignore cell if it is the same as the last one. */
+ if (gc2.attr == tty->last_cell.attr &&
+ gc2.fg == tty->last_cell.fg &&
+ gc2.bg == tty->last_cell.bg &&
+ gc2.us == tty->last_cell.us)
+ return;
/*
* If no setab, try to use the reverse attribute as a best-effort for a
@@ -2249,9 +2276,9 @@ tty_attributes(struct tty *tty, const struct grid_cell *gc,
}
/* Fix up the colours if necessary. */
- tty_check_fg(tty, wp, &gc2);
- tty_check_bg(tty, wp, &gc2);
- tty_check_us(tty, wp, &gc2);
+ tty_check_fg(tty, palette, &gc2);
+ tty_check_bg(tty, palette, &gc2);
+ tty_check_us(tty, palette, &gc2);
/*
* If any bits are being cleared or the underline colour is now default,
@@ -2306,6 +2333,8 @@ tty_attributes(struct tty *tty, const struct grid_cell *gc,
tty_putcode(tty, TTYC_SMOL);
if ((changed & GRID_ATTR_CHARSET) && tty_acs_needed(tty))
tty_putcode(tty, TTYC_SMACS);
+
+ memcpy(&tty->last_cell, &gc2, sizeof tty->last_cell);
}
static void
@@ -2370,7 +2399,7 @@ tty_colours(struct tty *tty, const struct grid_cell *gc)
}
static void
-tty_check_fg(struct tty *tty, struct window_pane *wp, struct grid_cell *gc)
+tty_check_fg(struct tty *tty, int *palette, struct grid_cell *gc)
{
u_char r, g, b;
u_int colours;
@@ -2385,21 +2414,21 @@ tty_check_fg(struct tty *tty, struct window_pane *wp, struct grid_cell *gc)
c = gc->fg;
if (c < 8 && gc->attr & GRID_ATTR_BRIGHT)
c += 90;
- if ((c = window_pane_get_palette(wp, c)) != -1)
+ if ((c = tty_get_palette(palette, c)) != -1)
gc->fg = c;
}
/* Is this a 24-bit colour? */
if (gc->fg & COLOUR_FLAG_RGB) {
/* Not a 24-bit terminal? Translate to 256-colour palette. */
- if ((tty->term->flags|tty->term_flags) & TERM_RGBCOLOURS)
+ if (tty->term->flags & TERM_RGBCOLOURS)
return;
colour_split_rgb(gc->fg, &r, &g, &b);
gc->fg = colour_find_rgb(r, g, b);
}
/* How many colours does this terminal have? */
- if ((tty->term->flags|tty->term_flags) & TERM_256COLOURS)
+ if (tty->term->flags & TERM_256COLOURS)
colours = 256;
else
colours = tty_term_number(tty->term, TTYC_COLORS);
@@ -2426,7 +2455,7 @@ tty_check_fg(struct tty *tty, struct window_pane *wp, struct grid_cell *gc)
}
static void
-tty_check_bg(struct tty *tty, struct window_pane *wp, struct grid_cell *gc)
+tty_check_bg(struct tty *tty, int *palette, struct grid_cell *gc)
{
u_char r, g, b;
u_int colours;
@@ -2434,21 +2463,21 @@ tty_check_bg(struct tty *tty, struct window_pane *wp, struct grid_cell *gc)
/* Perform substitution if this pane has a palette. */
if (~gc->flags & GRID_FLAG_NOPALETTE) {
- if ((c = window_pane_get_palette(wp, gc->bg)) != -1)
+ if ((c = tty_get_palette(palette, gc->bg)) != -1)
gc->bg = c;
}
/* Is this a 24-bit colour? */
if (gc->bg & COLOUR_FLAG_RGB) {
/* Not a 24-bit terminal? Translate to 256-colour palette. */
- if ((tty->term->flags|tty->term_flags) & TERM_RGBCOLOURS)
+ if (tty->term->flags & TERM_RGBCOLOURS)
return;
colour_split_rgb(gc->bg, &r, &g, &b);
gc->bg = colour_find_rgb(r, g, b);
}
/* How many colours does this terminal have? */
- if ((tty->term->flags|tty->term_flags) & TERM_256COLOURS)
+ if (tty->term->flags & TERM_256COLOURS)
colours = 256;
else
colours = tty_term_number(tty->term, TTYC_COLORS);
@@ -2477,14 +2506,13 @@ tty_check_bg(struct tty *tty, struct window_pane *wp, struct grid_cell *gc)
}
static void
-tty_check_us(__unused struct tty *tty, struct window_pane *wp,
- struct grid_cell *gc)
+tty_check_us(__unused struct tty *tty, int *palette, struct grid_cell *gc)
{
int c;
/* Perform substitution if this pane has a palette. */
if (~gc->flags & GRID_FLAG_NOPALETTE) {
- if ((c = window_pane_get_palette(wp, gc->us)) != -1)
+ if ((c = tty_get_palette(palette, gc->us)) != -1)
gc->us = c;
}
@@ -2509,7 +2537,7 @@ tty_colours_fg(struct tty *tty, const struct grid_cell *gc)
/* Is this an aixterm bright colour? */
if (gc->fg >= 90 && gc->fg <= 97) {
- if (tty->term_flags & TERM_256COLOURS) {
+ if (tty->term->flags & TERM_256COLOURS) {
xsnprintf(s, sizeof s, "\033[%dm", gc->fg);
tty_puts(tty, s);
} else
@@ -2541,7 +2569,7 @@ tty_colours_bg(struct tty *tty, const struct grid_cell *gc)
/* Is this an aixterm bright colour? */
if (gc->bg >= 90 && gc->bg <= 97) {
- if (tty->term_flags & TERM_256COLOURS) {
+ if (tty->term->flags & TERM_256COLOURS) {
xsnprintf(s, sizeof s, "\033[%dm", gc->bg + 10);
tty_puts(tty, s);
} else
@@ -2586,122 +2614,74 @@ static int
tty_try_colour(struct tty *tty, int colour, const char *type)
{
u_char r, g, b;
- char s[32];
if (colour & COLOUR_FLAG_256) {
- /*
- * If the user has specified -2 to the client (meaning
- * TERM_256COLOURS is set), setaf and setab may not work (or
- * they may not want to use them), so send the usual sequence.
- *
- * Also if RGB is set, setaf and setab do not support the 256
- * colour palette so use the sequences directly there too.
- */
- if ((tty->term_flags & TERM_256COLOURS) ||
- tty_term_has(tty->term, TTYC_RGB))
- goto fallback_256;
-
- /*
- * If the terminfo entry has 256 colours and setaf and setab
- * exist, assume that they work correctly.
- */
- if (tty->term->flags & TERM_256COLOURS) {
- if (*type == '3') {
- if (!tty_term_has(tty->term, TTYC_SETAF))
- goto fallback_256;
- tty_putcode1(tty, TTYC_SETAF, colour & 0xff);
- } else {
- if (!tty_term_has(tty->term, TTYC_SETAB))
- goto fallback_256;
- tty_putcode1(tty, TTYC_SETAB, colour & 0xff);
- }
- return (0);
- }
- goto fallback_256;
+ if (*type == '3' && tty_term_has(tty->term, TTYC_SETAF))
+ tty_putcode1(tty, TTYC_SETAF, colour & 0xff);
+ else if (tty_term_has(tty->term, TTYC_SETAB))
+ tty_putcode1(tty, TTYC_SETAB, colour & 0xff);
+ return (0);
}
if (colour & COLOUR_FLAG_RGB) {
colour_split_rgb(colour & 0xffffff, &r, &g, &b);
- if (*type == '3') {
- if (!tty_term_has(tty->term, TTYC_SETRGBF))
- goto fallback_rgb;
+ if (*type == '3' && tty_term_has(tty->term, TTYC_SETRGBF))
tty_putcode3(tty, TTYC_SETRGBF, r, g, b);
- } else {
- if (!tty_term_has(tty->term, TTYC_SETRGBB))
- goto fallback_rgb;
+ else if (tty_term_has(tty->term, TTYC_SETRGBB))
tty_putcode3(tty, TTYC_SETRGBB, r, g, b);
- }
return (0);
}
return (-1);
-
-fallback_256:
- xsnprintf(s, sizeof s, "\033[%s;5;%dm", type, colour & 0xff);
- log_debug("%s: 256 colour fallback: %s", tty->client->name, s);
- tty_puts(tty, s);
- return (0);
-
-fallback_rgb:
- xsnprintf(s, sizeof s, "\033[%s;2;%d;%d;%dm", type, r, g, b);
- log_debug("%s: RGB colour fallback: %s", tty->client->name, s);
- tty_puts(tty, s);
- return (0);
}
static void
+tty_window_default_style(struct grid_cell *gc, struct window_pane *wp)
+{
+ memcpy(gc, &grid_default_cell, sizeof *gc);
+ gc->fg = wp->fg;
+ gc->bg = wp->bg;
+}
+
+void
tty_default_colours(struct grid_cell *gc, struct window_pane *wp)
{
struct options *oo = wp->options;
- struct style *style, *active_style;
- int c;
+
+ memcpy(gc, &grid_default_cell, sizeof *gc);
if (wp->flags & PANE_STYLECHANGED) {
wp->flags &= ~PANE_STYLECHANGED;
- active_style = options_get_style(oo, "window-active-style");
- style = options_get_style(oo, "window-style");
-
- style_copy(&wp->cached_active_style, active_style);
- style_copy(&wp->cached_style, style);
- } else {
- active_style = &wp->cached_active_style;
- style = &wp->cached_style;
+ tty_window_default_style(&wp->cached_active_gc, wp);
+ style_add(&wp->cached_active_gc, oo, "window-active-style",
+ NULL);
+ tty_window_default_style(&wp->cached_gc, wp);
+ style_add(&wp->cached_gc, oo, "window-style", NULL);
}
if (gc->fg == 8) {
- if (wp == wp->window->active && active_style->gc.fg != 8)
- gc->fg = active_style->gc.fg;
+ if (wp == wp->window->active && wp->cached_active_gc.fg != 8)
+ gc->fg = wp->cached_active_gc.fg;
else
- gc->fg = style->gc.fg;
-
- if (gc->fg != 8) {
- c = window_pane_get_palette(wp, gc->fg);
- if (c != -1)
- gc->fg = c;
- }
+ gc->fg = wp->cached_gc.fg;
}
if (gc->bg == 8) {
- if (wp == wp->window->active && active_style->gc.bg != 8)
- gc->bg = active_style->gc.bg;
+ if (wp == wp->window->active && wp->cached_active_gc.bg != 8)
+ gc->bg = wp->cached_active_gc.bg;
else
- gc->bg = style->gc.bg;
-
- if (gc->bg != 8) {
- c = window_pane_get_palette(wp, gc->bg);
- if (c != -1)
- gc->bg = c;
- }
+ gc->bg = wp->cached_gc.bg;
}
}
static void
-tty_default_attributes(struct tty *tty, struct window_pane *wp, u_int bg)
+tty_default_attributes(struct tty *tty, const struct grid_cell *defaults,
+ int *palette, u_int bg)
{
- static struct grid_cell gc;
+ struct grid_cell gc;
memcpy(&gc, &grid_default_cell, sizeof gc);
gc.bg = bg;
- tty_attributes(tty, &gc, wp);
+ tty_attributes(tty, &gc, defaults, palette);
}
diff --git a/window-buffer.c b/window-buffer.c
index a1939b0f..16adbc61 100644
--- a/window-buffer.c
+++ b/window-buffer.c
@@ -18,9 +18,11 @@
#include <sys/types.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
+#include <unistd.h>
#include "tmux.h"
@@ -36,7 +38,7 @@ static void window_buffer_key(struct window_mode_entry *,
#define WINDOW_BUFFER_DEFAULT_COMMAND "paste-buffer -b '%%'"
#define WINDOW_BUFFER_DEFAULT_FORMAT \
- "#{buffer_size} bytes (#{t:buffer_created})"
+ "#{t/p:buffer_created}: #{buffer_sample}"
static const struct menu_item window_buffer_menu_items[] = {
{ "Paste", 'p', NULL },
@@ -94,6 +96,13 @@ struct window_buffer_modedata {
u_int item_size;
};
+struct window_buffer_editdata {
+ u_int wp_id;
+ char *path;
+ char *name;
+ struct paste_buffer *pb;
+};
+
static struct window_buffer_itemdata *
window_buffer_add_item(struct window_buffer_modedata *data)
{
@@ -222,7 +231,7 @@ window_buffer_draw(__unused void *modedata, void *itemdata,
while (end != pdata + psize && *end != '\n')
end++;
buf = xreallocarray(buf, 4, end - start + 1);
- utf8_strvis(buf, start, end - start, VIS_OCTAL|VIS_TAB);
+ utf8_strvis(buf, start, end - start, VIS_OCTAL|VIS_CSTYLE|VIS_TAB);
if (*buf != '\0') {
screen_write_cursormove(ctx, cx, cy + i, 0);
screen_write_nputs(ctx, sx, &grid_default_cell, "%s",
@@ -347,13 +356,132 @@ window_buffer_do_paste(void *modedata, void *itemdata, struct client *c,
{
struct window_buffer_modedata *data = modedata;
struct window_buffer_itemdata *item = itemdata;
- struct paste_buffer *pb;
- if ((pb = paste_get_name(item->name)) != NULL)
+ if (paste_get_name(item->name) != NULL)
mode_tree_run_command(c, NULL, data->command, item->name);
}
static void
+window_buffer_finish_edit(struct window_buffer_editdata *ed)
+{
+ unlink(ed->path);
+ free(ed->path);
+ free(ed->name);
+ free(ed);
+}
+
+static void
+window_buffer_edit_close_cb(int status, void *arg)
+{
+ struct window_buffer_editdata *ed = arg;
+ FILE *f;
+ off_t len;
+ char *buf;
+ size_t oldlen;
+ const char *oldbuf;
+ struct paste_buffer *pb;
+ struct window_pane *wp;
+ struct window_buffer_modedata *data;
+ struct window_mode_entry *wme;
+
+ if (status != 0) {
+ window_buffer_finish_edit(ed);
+ return;
+ }
+
+ pb = paste_get_name(ed->name);
+ if (pb == NULL || pb != ed->pb) {
+ window_buffer_finish_edit(ed);
+ return;
+ }
+
+ f = fopen(ed->path, "r");
+ if (f != NULL) {
+ fseeko(f, 0, SEEK_END);
+ len = ftello(f);
+ fseeko(f, 0, SEEK_SET);
+
+ if (len > 0 &&
+ (uintmax_t)len <= (uintmax_t)SIZE_MAX &&
+ (buf = malloc(len)) != NULL &&
+ fread(buf, len, 1, f) == 1) {
+ oldbuf = paste_buffer_data(pb, &oldlen);
+ if (oldlen != '\0' &&
+ oldbuf[oldlen - 1] != '\n' &&
+ buf[len - 1] == '\n')
+ len--;
+ if (len != 0)
+ paste_replace(pb, buf, len);
+ }
+ fclose(f);
+ }
+
+ wp = window_pane_find_by_id(ed->wp_id);
+ if (wp != NULL) {
+ wme = TAILQ_FIRST(&wp->modes);
+ if (wme->mode == &window_buffer_mode) {
+ data = wme->data;
+ mode_tree_build(data->data);
+ mode_tree_draw(data->data);
+ }
+ wp->flags |= PANE_REDRAW;
+ }
+ window_buffer_finish_edit(ed);
+}
+
+static void
+window_buffer_start_edit(struct window_buffer_modedata *data,
+ struct window_buffer_itemdata *item, struct client *c)
+{
+ struct paste_buffer *pb;
+ int fd;
+ FILE *f;
+ const char *buf;
+ size_t len;
+ struct window_buffer_editdata *ed;
+ char *cmd;
+ char path[] = _PATH_TMP "tmux.XXXXXXXX";
+ const char *editor;
+ u_int px, py, sx, sy;
+
+ if ((pb = paste_get_name(item->name)) == NULL)
+ return;
+ buf = paste_buffer_data(pb, &len);
+
+ editor = options_get_string(global_options, "editor");
+ if (*editor == '\0')
+ return;
+
+ fd = mkstemp(path);
+ if (fd == -1)
+ return;
+ f = fdopen(fd, "w");
+ if (fwrite(buf, len, 1, f) != 1) {
+ fclose(f);
+ return;
+ }
+ fclose(f);
+
+ ed = xcalloc(1, sizeof *ed);
+ ed->wp_id = data->wp->id;
+ ed->path = xstrdup(path);
+ ed->name = xstrdup(paste_buffer_name(pb));
+ ed->pb = pb;
+
+ sx = c->tty.sx * 9 / 10;
+ sy = c->tty.sy * 9 / 10;
+ px = (c->tty.sx / 2) - (sx / 2);
+ py = (c->tty.sy / 2) - (sy / 2);
+
+ xasprintf(&cmd, "%s %s", editor, path);
+ if (popup_display(POPUP_WRITEKEYS|POPUP_CLOSEEXIT, NULL, px, py, sx, sy,
+ 0, NULL, cmd, NULL, _PATH_TMP, c, NULL, window_buffer_edit_close_cb,
+ ed) != 0)
+ window_buffer_finish_edit(ed);
+ free(cmd);
+}
+
+static void
window_buffer_key(struct window_mode_entry *wme, struct client *c,
__unused struct session *s, __unused struct winlink *wl, key_code key,
struct mouse_event *m)
@@ -366,6 +494,10 @@ window_buffer_key(struct window_mode_entry *wme, struct client *c,
finished = mode_tree_key(mtd, c, &key, m, NULL, NULL);
switch (key) {
+ case 'e':
+ item = mode_tree_get_current(mtd);
+ window_buffer_start_edit(data, item, c);
+ break;
case 'd':
item = mode_tree_get_current(mtd);
window_buffer_do_delete(data, item, c, key);
diff --git a/window-client.c b/window-client.c
index 4688cbf3..cd424dd7 100644
--- a/window-client.c
+++ b/window-client.c
@@ -37,8 +37,7 @@ static void window_client_key(struct window_mode_entry *,
#define WINDOW_CLIENT_DEFAULT_COMMAND "detach-client -t '%%'"
#define WINDOW_CLIENT_DEFAULT_FORMAT \
- "session #{session_name} " \
- "(#{client_width}x#{client_height}, #{t:client_activity})"
+ "#{t/p:client_activity}: session #{session_name}"
static const struct menu_item window_client_menu_items[] = {
{ "Detach", 'd', NULL },
diff --git a/window-clock.c b/window-clock.c
index 45d4d47b..8cef3f9a 100644
--- a/window-clock.c
+++ b/window-clock.c
@@ -219,7 +219,7 @@ window_clock_draw_screen(struct window_mode_entry *wme)
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, s);
+ screen_write_start(&ctx, s);
t = time(NULL);
tm = localtime(&t);
diff --git a/window-copy.c b/window-copy.c
index 2a47e9b0..38e87b67 100644
--- a/window-copy.c
+++ b/window-copy.c
@@ -22,6 +22,7 @@
#include <regex.h>
#include <stdlib.h>
#include <string.h>
+#include <time.h>
#include "tmux.h"
@@ -205,6 +206,8 @@ struct window_copy_mode_data {
struct screen *backing;
int backing_written; /* backing display started */
+ int viewmode; /* view mode entered */
+
u_int oy; /* number of lines scrolled up */
u_int selx; /* beginning of selection */
@@ -254,15 +257,18 @@ struct window_copy_mode_data {
int searchtype;
int searchregex;
char *searchstr;
- bitstr_t *searchmark;
- u_int searchcount;
+ u_char *searchmark;
+ int searchcount;
+ int searchmore;
int searchthis;
int searchx;
int searchy;
int searcho;
+ u_char searchgen;
int timeout; /* search has timed out */
-#define WINDOW_COPY_SEARCH_TIMEOUT 10
+#define WINDOW_COPY_SEARCH_TIMEOUT 10000
+#define WINDOW_COPY_SEARCH_ALL_TIMEOUT 200
int jumptype;
char jumpchar;
@@ -295,6 +301,48 @@ window_copy_scroll_timer(__unused int fd, __unused short events, void *arg)
}
}
+static struct screen *
+window_copy_clone_screen(struct screen *src, struct screen *hint, u_int *cx,
+ u_int *cy, int trim)
+{
+ struct screen *dst;
+ u_int sy;
+ const struct grid_line *gl;
+
+ dst = xcalloc(1, sizeof *dst);
+
+ sy = screen_hsize(src) + screen_size_y(src);
+ if (trim) {
+ while (sy > screen_hsize(src)) {
+ gl = grid_peek_line(src->grid, sy - 1);
+ if (gl->cellused != 0)
+ break;
+ sy--;
+ }
+ }
+ log_debug("%s: target screen is %ux%u, source %ux%u", __func__,
+ screen_size_x(src), sy, screen_size_x(hint),
+ screen_hsize(src) + screen_size_y(src));
+ screen_init(dst, screen_size_x(src), sy, screen_hlimit(src));
+ grid_duplicate_lines(dst->grid, 0, src->grid, 0, sy);
+
+ dst->grid->sy = sy - screen_hsize(src);
+ dst->grid->hsize = screen_hsize(src);
+ dst->grid->hscrolled = src->grid->hscrolled;
+ if (src->cy > dst->grid->sy - 1) {
+ dst->cx = 0;
+ dst->cy = dst->grid->sy - 1;
+ } else {
+ dst->cx = src->cx;
+ dst->cy = src->cy;
+ }
+
+ screen_resize_cursor(dst, screen_size_x(hint), screen_size_y(hint), 1,
+ 0, cx, cy);
+
+ return (dst);
+}
+
static struct window_copy_mode_data *
window_copy_common_init(struct window_mode_entry *wme)
{
@@ -317,9 +365,7 @@ window_copy_common_init(struct window_mode_entry *wme)
data->searchregex = 0;
data->searchstr = NULL;
}
- data->searchmark = NULL;
data->searchx = data->searchy = data->searcho = -1;
- data->timeout = 0;
data->jumptype = WINDOW_COPY_OFF;
data->jumpchar = '\0';
@@ -336,19 +382,25 @@ static struct screen *
window_copy_init(struct window_mode_entry *wme,
__unused struct cmd_find_state *fs, struct args *args)
{
- struct window_pane *wp = wme->wp;
+ struct window_pane *wp = wme->swp;
struct window_copy_mode_data *data;
+ struct screen *base = &wp->base;
struct screen_write_ctx ctx;
- u_int i;
+ u_int i, cx, cy;
data = window_copy_common_init(wme);
+ data->backing = window_copy_clone_screen(base, &data->screen, &cx, &cy,
+ wme->swp != wme->wp);
- if (wp->fd != -1 && wp->disabled++ == 0)
- bufferevent_disable(wp->event, EV_READ|EV_WRITE);
-
- data->backing = &wp->base;
- data->cx = data->backing->cx;
- data->cy = data->backing->cy;
+ if (cy < screen_hsize(data->backing)) {
+ data->cx = cx;
+ data->cy = 0;
+ data->oy = screen_hsize(data->backing) - cy;
+ } else {
+ data->cx = data->backing->cx;
+ data->cy = data->backing->cy;
+ data->oy = 0;
+ }
data->scroll_exit = args_has(args, 'e');
data->hide_position = args_has(args, 'H');
@@ -356,7 +408,7 @@ window_copy_init(struct window_mode_entry *wme,
data->screen.cx = data->cx;
data->screen.cy = data->cy;
- screen_write_start(&ctx, NULL, &data->screen);
+ screen_write_start(&ctx, &data->screen);
for (i = 0; i < screen_size_y(&data->screen); i++)
window_copy_write_line(wme, &ctx, i);
screen_write_cursormove(&ctx, data->cx, data->cy, 0);
@@ -375,6 +427,7 @@ window_copy_view_init(struct window_mode_entry *wme,
struct screen *s;
data = window_copy_common_init(wme);
+ data->viewmode = 1;
data->backing = s = xmalloc(sizeof *data->backing);
screen_init(s, screen_size_x(base), screen_size_y(base), UINT_MAX);
@@ -385,23 +438,17 @@ window_copy_view_init(struct window_mode_entry *wme,
static void
window_copy_free(struct window_mode_entry *wme)
{
- struct window_pane *wp = wme->wp;
struct window_copy_mode_data *data = wme->data;
evtimer_del(&data->dragtimer);
- if (wp->fd != -1 && --wp->disabled == 0)
- bufferevent_enable(wp->event, EV_READ|EV_WRITE);
-
free(data->searchmark);
free(data->searchstr);
- if (data->backing != &wp->base) {
- screen_free(data->backing);
- free(data->backing);
- }
- screen_free(&data->screen);
+ screen_free(data->backing);
+ free(data->backing);
+ screen_free(&data->screen);
free(data);
}
@@ -425,13 +472,10 @@ window_copy_vadd(struct window_pane *wp, const char *fmt, va_list ap)
struct grid_cell gc;
u_int old_hsize, old_cy;
- if (backing == &wp->base)
- return;
-
memcpy(&gc, &grid_default_cell, sizeof gc);
old_hsize = screen_hsize(data->backing);
- screen_write_start(&back_ctx, NULL, backing);
+ screen_write_start(&back_ctx, backing);
if (data->backing_written) {
/*
* On the second or later line, do a CRLF before writing
@@ -447,7 +491,7 @@ window_copy_vadd(struct window_pane *wp, const char *fmt, va_list ap)
data->oy += screen_hsize(data->backing) - old_hsize;
- screen_write_start(&ctx, wp, &data->screen);
+ screen_write_start_pane(&ctx, wp, &data->screen);
/*
* If the history has changed, draw the top line.
@@ -661,31 +705,18 @@ window_copy_formats(struct window_mode_entry *wme, struct format_tree *ft)
}
static void
-window_copy_resize(struct window_mode_entry *wme, u_int sx, u_int sy)
+window_copy_size_changed(struct window_mode_entry *wme)
{
- struct window_pane *wp = wme->wp;
struct window_copy_mode_data *data = wme->data;
struct screen *s = &data->screen;
- struct screen_write_ctx ctx;
- int search;
-
- screen_resize(s, sx, sy, 1);
- if (data->backing != &wp->base)
- screen_resize(data->backing, sx, sy, 1);
-
- if (data->cy > sy - 1)
- data->cy = sy - 1;
- if (data->cx > sx)
- data->cx = sx;
- if (data->oy > screen_hsize(data->backing))
- data->oy = screen_hsize(data->backing);
+ struct screen_write_ctx ctx;
+ int search = (data->searchmark != NULL);
- search = (data->searchmark != NULL);
window_copy_clear_selection(wme);
window_copy_clear_marks(wme);
- screen_write_start(&ctx, NULL, s);
- window_copy_write_lines(wme, &ctx, 0, screen_size_y(s) - 1);
+ screen_write_start(&ctx, s);
+ window_copy_write_lines(wme, &ctx, 0, screen_size_y(s));
screen_write_stop(&ctx);
if (search && !data->timeout)
@@ -693,7 +724,25 @@ window_copy_resize(struct window_mode_entry *wme, u_int sx, u_int sy)
data->searchx = data->cx;
data->searchy = data->cy;
data->searcho = data->oy;
+}
+
+static void
+window_copy_resize(struct window_mode_entry *wme, u_int sx, u_int sy)
+{
+ struct window_copy_mode_data *data = wme->data;
+ struct screen *s = &data->screen;
+
+ screen_resize(s, sx, sy, 0);
+ screen_resize_cursor(data->backing, sx, sy, 1, 0, NULL, NULL);
+
+ if (data->cy > sy - 1)
+ 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_size_changed(wme);
window_copy_redraw_screen(wme);
}
@@ -1043,14 +1092,15 @@ window_copy_cmd_history_bottom(struct window_copy_cmd_state *cs)
{
struct window_mode_entry *wme = cs->wme;
struct window_copy_mode_data *data = wme->data;
+ struct screen *s = data->backing;
u_int oy;
- oy = screen_hsize(data->backing) + data->cy - data->oy;
+ oy = screen_hsize(s) + data->cy - data->oy;
if (data->lineflag == LINE_SEL_RIGHT_LEFT && oy == data->endsely)
window_copy_other_end(wme);
data->cy = screen_size_y(&data->screen) - 1;
- data->cx = window_copy_find_length(wme, data->cy);
+ data->cx = window_copy_find_length(wme, screen_hsize(s) + data->cy);
data->oy = 0;
if (data->searchmark != NULL && !data->timeout)
@@ -1690,11 +1740,10 @@ window_copy_cmd_copy_pipe_no_clear(struct window_copy_cmd_state *cs)
if (cs->args->argc == 3)
prefix = format_single(NULL, cs->args->argv[2], c, s, wl, wp);
- if (s != NULL && *cs->args->argv[1] != '\0') {
+ if (s != NULL && cs->args->argc > 1 && *cs->args->argv[1] != '\0')
command = format_single(NULL, cs->args->argv[1], c, s, wl, wp);
- window_copy_copy_pipe(wme, s, prefix, command);
- free(command);
- }
+ window_copy_copy_pipe(wme, s, prefix, command);
+ free(command);
free(prefix);
return (WINDOW_COPY_CMD_NOTHING);
@@ -1984,6 +2033,25 @@ window_copy_cmd_search_forward_incremental(struct window_copy_cmd_state *cs)
return (action);
}
+static enum window_copy_cmd_action
+window_copy_cmd_refresh_from_pane(struct window_copy_cmd_state *cs)
+{
+ struct window_mode_entry *wme = cs->wme;
+ struct window_pane *wp = wme->swp;
+ struct window_copy_mode_data *data = wme->data;
+
+ if (data->viewmode)
+ return (WINDOW_COPY_CMD_NOTHING);
+
+ screen_free(data->backing);
+ free(data->backing);
+ data->backing = window_copy_clone_screen(&wp->base, &data->screen, NULL,
+ NULL, wme->swp != wme->wp);
+
+ window_copy_size_changed(wme);
+ return (WINDOW_COPY_CMD_REDRAW);
+}
+
static const struct {
const char *command;
int minargs;
@@ -2009,11 +2077,11 @@ static const struct {
window_copy_cmd_copy_end_of_line },
{ "copy-line", 0, 1, 0,
window_copy_cmd_copy_line },
- { "copy-pipe-no-clear", 1, 2, 0,
+ { "copy-pipe-no-clear", 0, 2, 0,
window_copy_cmd_copy_pipe_no_clear },
- { "copy-pipe", 1, 2, 0,
+ { "copy-pipe", 0, 2, 0,
window_copy_cmd_copy_pipe },
- { "copy-pipe-and-cancel", 1, 2, 0,
+ { "copy-pipe-and-cancel", 0, 2, 0,
window_copy_cmd_copy_pipe_and_cancel },
{ "copy-selection-no-clear", 0, 1, 0,
window_copy_cmd_copy_selection_no_clear },
@@ -2089,6 +2157,8 @@ static const struct {
window_copy_cmd_previous_word },
{ "rectangle-toggle", 0, 0, 0,
window_copy_cmd_rectangle_toggle },
+ { "refresh-from-pane", 0, 0, 0,
+ window_copy_cmd_refresh_from_pane },
{ "scroll-down", 0, 0, 1,
window_copy_cmd_scroll_down },
{ "scroll-down-and-cancel", 0, 0, 0,
@@ -2754,7 +2824,7 @@ window_copy_search(struct window_mode_entry *wme, int direction, int regex)
fy = screen_hsize(data->backing) - data->oy + data->cy;
screen_init(&ss, screen_write_strlen("%s", str), 1, 0);
- screen_write_start(&ctx, NULL, &ss);
+ screen_write_start(&ctx, &ss);
screen_write_nputs(&ctx, -1, &grid_default_cell, "%s", str);
screen_write_stop(&ctx);
@@ -2779,6 +2849,15 @@ window_copy_search(struct window_mode_entry *wme, int direction, int regex)
return (found);
}
+static uint64_t
+window_copy_get_time(void)
+{
+ struct timeval tv;
+
+ gettimeofday(&tv, NULL);
+ return ((tv.tv_sec * 1000ULL) + (tv.tv_usec / 1000ULL));
+}
+
static int
window_copy_search_marks(struct window_mode_entry *wme, struct screen *ssp,
int regex)
@@ -2788,18 +2867,18 @@ window_copy_search_marks(struct window_mode_entry *wme, struct screen *ssp,
struct screen_write_ctx ctx;
struct grid *gd = s->grid;
const struct grid_line *gl;
- int found, cis, which = -1;
+ int found, cis, which = -1, stopped = 0;
int cflags = REG_EXTENDED;
- u_int px, py, b, nfound = 0, width;
- u_int ssize = 1;
+ u_int px, py, i, b, nfound = 0, width;
+ u_int ssize = 1, start, end;
char *sbuf;
regex_t reg;
- time_t tstart, t;
+ uint64_t stop = 0, tstart, t;
if (ssp == NULL) {
width = screen_write_strlen("%s", data->searchstr);
screen_init(&ss, width, 1, 0);
- screen_write_start(&ctx, NULL, &ss);
+ screen_write_start(&ctx, &ss);
screen_write_nputs(&ctx, -1, &grid_default_cell, "%s",
data->searchstr);
screen_write_stop(&ctx);
@@ -2809,9 +2888,6 @@ window_copy_search_marks(struct window_mode_entry *wme, struct screen *ssp,
cis = window_copy_is_lowercase(data->searchstr);
- free(data->searchmark);
- data->searchmark = bit_alloc((gd->hsize + gd->sy) * gd->sx);
-
if (regex) {
sbuf = xmalloc(ssize);
sbuf[0] = '\0';
@@ -2824,13 +2900,18 @@ window_copy_search_marks(struct window_mode_entry *wme, struct screen *ssp,
return (0);
}
}
- time(&tstart);
- for (py = gd->hsize - data->oy; py > 0; py--) {
- gl = grid_peek_line(gd, py - 1);
- if (~gl->flags & GRID_LINE_WRAPPED)
- break;
- }
- for (; py < gd->hsize - data->oy + gd->sy; py++) {
+ tstart = window_copy_get_time();
+
+ start = 0;
+ end = gd->hsize + gd->sy;
+ stop = window_copy_get_time() + WINDOW_COPY_SEARCH_ALL_TIMEOUT;
+
+again:
+ free(data->searchmark);
+ data->searchmark = xcalloc(gd->hsize + gd->sy, gd->sx);
+ data->searchgen = 1;
+
+ for (py = start; py < end; py++) {
px = 0;
for (;;) {
if (regex) {
@@ -2851,34 +2932,70 @@ window_copy_search_marks(struct window_mode_entry *wme, struct screen *ssp,
which = nfound;
b = (py * gd->sx) + px;
- bit_nset(data->searchmark, b, b + width - 1);
+ for (i = b; i < b + width; i++)
+ data->searchmark[i] = data->searchgen;
+ if (data->searchgen == UCHAR_MAX)
+ data->searchgen = 1;
+ else
+ data->searchgen++;
px++;
}
- time(&t);
+ t = window_copy_get_time();
if (t - tstart > WINDOW_COPY_SEARCH_TIMEOUT) {
data->timeout = 1;
break;
}
- }
- if (regex) {
- free(sbuf);
- regfree(&reg);
+ if (stop != 0 && t > stop) {
+ stopped = 1;
+ break;
+ }
}
if (data->timeout) {
window_copy_clear_marks(wme);
- return (1);
+ goto out;
}
- if (which != -1)
- data->searchthis = 1 + nfound - which;
- else
+ if (stopped && stop != 0) {
+ /* Try again but just the visible context. */
+ for (start = gd->hsize - data->oy; start > 0; start--) {
+ gl = grid_peek_line(gd, start - 1);
+ if (~gl->flags & GRID_LINE_WRAPPED)
+ break;
+ }
+ end = gd->hsize - data->oy + gd->sy;
+ stop = 0;
+ goto again;
+ }
+
+ if (stopped) {
data->searchthis = -1;
- data->searchcount = nfound;
+ if (nfound > 1000)
+ data->searchcount = 1000;
+ else if (nfound > 100)
+ data->searchcount = 100;
+ else if (nfound > 10)
+ data->searchcount = 10;
+ else
+ data->searchcount = -1;
+ data->searchmore = 1;
+ } else {
+ if (which != -1)
+ data->searchthis = 1 + nfound - which;
+ else
+ data->searchthis = -1;
+ data->searchcount = nfound;
+ data->searchmore = 0;
+ }
+out:
if (ssp == &ss)
screen_free(&ss);
+ if (regex) {
+ free(sbuf);
+ regfree(&reg);
+ }
return (1);
}
@@ -2922,6 +3039,117 @@ window_copy_goto_line(struct window_mode_entry *wme, const char *linestr)
}
static void
+window_copy_match_start_end(struct window_copy_mode_data *data, u_int at,
+ u_int *start, u_int *end)
+{
+ struct grid *gd = data->backing->grid;
+ u_int last = (gd->hsize + gd->sy) * gd->sx - 1;
+ u_char mark = data->searchmark[at];
+
+ *start = *end = at;
+ while (*start != 0 && data->searchmark[*start] == mark)
+ (*start)--;
+ if (data->searchmark[*start] != mark)
+ (*start)++;
+ while (*end != last && data->searchmark[*end] == mark)
+ (*end)++;
+ if (data->searchmark[*end] != mark)
+ (*end)--;
+}
+
+static char *
+window_copy_match_at_cursor(struct window_copy_mode_data *data)
+{
+ struct grid *gd = data->backing->grid;
+ struct grid_cell gc;
+ u_int at, start, end, cy, px, py;
+ u_int sx = screen_size_x(data->backing);
+ char *buf = NULL;
+ size_t len = 0;
+
+ if (data->searchmark == NULL)
+ return (NULL);
+
+ cy = screen_hsize(data->backing) - data->oy + data->cy;
+ at = (cy * sx) + data->cx;
+ if (data->searchmark[at] == 0)
+ return (NULL);
+ window_copy_match_start_end(data, at, &start, &end);
+
+ /*
+ * Cells will not be set in the marked array unless they are valid text
+ * and wrapping will be taken care of, so we can just copy.
+ */
+ for (at = start; at <= end; at++) {
+ py = at / sx;
+ px = at % (py * sx);
+
+ grid_get_cell(gd, px, py, &gc);
+ buf = xrealloc(buf, len + gc.data.size + 1);
+ memcpy(buf + len, gc.data.data, gc.data.size);
+ len += gc.data.size;
+ }
+ if (len != 0)
+ buf[len] = '\0';
+ return (buf);
+}
+
+static void
+window_copy_update_style(struct window_mode_entry *wme, u_int fx, u_int fy,
+ struct grid_cell *gc, const struct grid_cell *mgc,
+ const struct grid_cell *cgc)
+{
+ struct window_copy_mode_data *data = wme->data;
+ u_int mark, start, end, cy, cursor, current;
+ u_int sx = screen_size_x(data->backing);
+
+ if (data->searchmark == NULL)
+ return;
+
+ current = (fy * sx) + fx;
+
+ mark = data->searchmark[current];
+ if (mark == 0)
+ return;
+
+ cy = screen_hsize(data->backing) - data->oy + data->cy;
+ cursor = (cy * sx) + data->cx;
+ if (data->searchmark[cursor] == mark) {
+ window_copy_match_start_end(data, cursor, &start, &end);
+ if (current >= start && current <= end) {
+ gc->attr = cgc->attr;
+ gc->fg = cgc->fg;
+ gc->bg = cgc->bg;
+ return;
+ }
+ }
+
+ gc->attr = mgc->attr;
+ gc->fg = mgc->fg;
+ gc->bg = mgc->bg;
+}
+
+static void
+window_copy_write_one(struct window_mode_entry *wme,
+ struct screen_write_ctx *ctx, u_int py, u_int fy, u_int nx,
+ const struct grid_cell *mgc, const struct grid_cell *cgc)
+{
+ struct window_copy_mode_data *data = wme->data;
+ struct grid *gd = data->backing->grid;
+ struct grid_cell gc;
+ u_int fx;
+
+ screen_write_cursormove(ctx, 0, py, 0);
+ for (fx = 0; fx < nx; fx++) {
+ grid_get_cell(gd, fx, fy, &gc);
+ if (fx + gc.data.width <= nx) {
+ window_copy_update_style(wme, fx, fy, &gc, mgc, cgc);
+ screen_write_cell(ctx, &gc);
+ }
+ }
+}
+
+static void
window_copy_write_line(struct window_mode_entry *wme,
struct screen_write_ctx *ctx, u_int py)
{
@@ -2929,34 +3157,39 @@ window_copy_write_line(struct window_mode_entry *wme,
struct window_copy_mode_data *data = wme->data;
struct screen *s = &data->screen;
struct options *oo = wp->window->options;
- struct grid_cell gc;
+ struct grid_cell gc, mgc, cgc;
char hdr[512];
size_t size = 0;
+ u_int hsize = screen_hsize(data->backing);
- style_apply(&gc, oo, "mode-style");
+ style_apply(&gc, oo, "mode-style", NULL);
gc.flags |= GRID_FLAG_NOPALETTE;
+ style_apply(&mgc, oo, "copy-mode-match-style", NULL);
+ mgc.flags |= GRID_FLAG_NOPALETTE;
+ style_apply(&cgc, oo, "copy-mode-current-match-style", NULL);
+ cgc.flags |= GRID_FLAG_NOPALETTE;
if (py == 0 && s->rupper < s->rlower && !data->hide_position) {
if (data->searchmark == NULL) {
if (data->timeout) {
size = xsnprintf(hdr, sizeof hdr,
- "(timed out) [%u/%u]", data->oy,
- screen_hsize(data->backing));
+ "(timed out) [%u/%u]", data->oy, hsize);
} else {
size = xsnprintf(hdr, sizeof hdr,
- "[%u/%u]", data->oy,
- screen_hsize(data->backing));
+ "[%u/%u]", data->oy, hsize);
}
} else {
- if (data->searchthis == -1) {
+ if (data->searchcount == -1) {
size = xsnprintf(hdr, sizeof hdr,
- "(%u results) [%d/%u]", data->searchcount,
- data->oy, screen_hsize(data->backing));
+ "[%u/%u]", data->oy, hsize);
+ } else if (data->searchthis == -1) {
+ size = xsnprintf(hdr, sizeof hdr,
+ "(%d%s results) [%u/%u]", data->searchcount,
+ data->searchmore ? "+" : "", data->oy, hsize);
} else {
size = xsnprintf(hdr, sizeof hdr,
- "(%u/%u results) [%d/%u]", data->searchthis,
- data->searchcount, data->oy,
- screen_hsize(data->backing));
+ "(%d/%d results) [%u/%u]", data->searchthis,
+ data->searchcount, data->oy, hsize);
}
}
if (size > screen_size_x(s))
@@ -2967,16 +3200,13 @@ window_copy_write_line(struct window_mode_entry *wme,
size = 0;
if (size < screen_size_x(s)) {
- screen_write_cursormove(ctx, 0, py, 0);
- screen_write_copy(ctx, data->backing, 0,
- (screen_hsize(data->backing) - data->oy) + py,
- screen_size_x(s) - size, 1, data->searchmark, &gc);
+ window_copy_write_one(wme, ctx, py, hsize - data->oy + py,
+ screen_size_x(s) - size, &mgc, &cgc);
}
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, 0);
- screen_write_putc(ctx, &gc, '$');
+ screen_write_putc(ctx, &grid_default_cell, '$');
}
}
@@ -3026,7 +3256,7 @@ window_copy_redraw_lines(struct window_mode_entry *wme, u_int py, u_int ny)
struct screen_write_ctx ctx;
u_int i;
- screen_write_start(&ctx, wp, NULL);
+ screen_write_start_pane(&ctx, wp, NULL);
for (i = py; i < py + ny; i++)
window_copy_write_line(wme, &ctx, i);
screen_write_cursormove(&ctx, data->cx, data->cy, 0);
@@ -3145,7 +3375,7 @@ window_copy_update_cursor(struct window_mode_entry *wme, u_int cx, u_int cy)
if (data->cx == screen_size_x(s))
window_copy_redraw_lines(wme, data->cy, 1);
else {
- screen_write_start(&ctx, wp, NULL);
+ screen_write_start_pane(&ctx, wp, NULL);
screen_write_cursormove(&ctx, data->cx, data->cy, 0);
screen_write_stop(&ctx);
}
@@ -3244,7 +3474,7 @@ window_copy_set_selection(struct window_mode_entry *wme, int may_redraw,
}
/* Set colours and selection. */
- style_apply(&gc, oo, "mode-style");
+ style_apply(&gc, oo, "mode-style", NULL);
gc.flags |= GRID_FLAG_NOPALETTE;
screen_set_selection(s, sx, sy, endsx, endsy, data->rectflag,
data->modekeys, &gc);
@@ -3287,8 +3517,12 @@ window_copy_get_selection(struct window_mode_entry *wme, size_t *len)
u_int firstsx, lastex, restex, restsx, selx;
int keys;
- if (data->screen.sel == NULL && data->lineflag == LINE_SEL_NONE)
- return (NULL);
+ if (data->screen.sel == NULL && data->lineflag == LINE_SEL_NONE) {
+ buf = window_copy_match_at_cursor(data);
+ if (buf != NULL)
+ *len = strlen(buf);
+ return (buf);
+ }
buf = xmalloc(1);
off = 0;
@@ -3394,7 +3628,7 @@ window_copy_copy_buffer(struct window_mode_entry *wme, const char *prefix,
struct screen_write_ctx ctx;
if (options_get_number(global_options, "set-clipboard") != 0) {
- screen_write_start(&ctx, wp, NULL);
+ screen_write_start_pane(&ctx, wp, NULL);
screen_write_setselection(&ctx, buf, len);
screen_write_stop(&ctx);
notify_pane("pane-set-clipboard", wp);
@@ -3415,8 +3649,13 @@ window_copy_copy_pipe(struct window_mode_entry *wme, struct session *s,
if (buf == NULL)
return;
- job = job_run(cmd, s, NULL, NULL, NULL, NULL, NULL, JOB_NOWAIT);
- bufferevent_write(job_get_event(job), buf, len);
+ if (cmd == NULL || *cmd == '\0')
+ cmd = options_get_string(global_options, "copy-command");
+ if (cmd != NULL && *cmd != '\0') {
+ job = job_run(cmd, s, NULL, NULL, NULL, NULL, NULL, JOB_NOWAIT,
+ -1, -1);
+ bufferevent_write(job_get_event(job), buf, len);
+ }
window_copy_copy_buffer(wme, prefix, buf, len);
}
@@ -3446,7 +3685,7 @@ window_copy_append_selection(struct window_mode_entry *wme)
return;
if (options_get_number(global_options, "set-clipboard") != 0) {
- screen_write_start(&ctx, wp, NULL);
+ screen_write_start_pane(&ctx, wp, NULL);
screen_write_setselection(&ctx, buf, len);
screen_write_stop(&ctx);
notify_pane("pane-set-clipboard", wp);
@@ -4120,7 +4359,6 @@ window_copy_cursor_previous_word_pos(struct window_mode_entry *wme,
data->oy >=
screen_hsize(data->backing) - 1))
goto out;
- py--;
py = screen_hsize(data->backing) + data->cy -
data->oy;
@@ -4210,7 +4448,7 @@ window_copy_scroll_up(struct window_mode_entry *wme, u_int ny)
window_copy_search_marks(wme, NULL, data->searchregex);
window_copy_update_selection(wme, 0, 0);
- screen_write_start(&ctx, wp, NULL);
+ screen_write_start_pane(&ctx, wp, NULL);
screen_write_cursormove(&ctx, 0, 0, 0);
screen_write_deleteline(&ctx, ny, 8);
window_copy_write_lines(wme, &ctx, screen_size_y(s) - ny, ny);
@@ -4246,7 +4484,7 @@ window_copy_scroll_down(struct window_mode_entry *wme, u_int ny)
window_copy_search_marks(wme, NULL, data->searchregex);
window_copy_update_selection(wme, 0, 0);
- screen_write_start(&ctx, wp, NULL);
+ screen_write_start_pane(&ctx, wp, NULL);
screen_write_cursormove(&ctx, 0, 0, 0);
screen_write_insertline(&ctx, ny, 8);
window_copy_write_lines(wme, &ctx, 0, ny);
@@ -4329,7 +4567,7 @@ window_copy_start_drag(struct client *c, struct mouse_event *m)
data->selflag = SEL_CHAR;
switch (data->selflag) {
case SEL_WORD:
- if (data->ws) {
+ if (data->ws != NULL) {
window_copy_update_cursor(wme, x, y);
window_copy_cursor_previous_word_pos(wme,
data->ws, 0, &x, &y);
diff --git a/window-tree.c b/window-tree.c
index 009e93c6..d245a715 100644
--- a/window-tree.c
+++ b/window-tree.c
@@ -37,12 +37,14 @@ static void window_tree_key(struct window_mode_entry *,
#define WINDOW_TREE_DEFAULT_FORMAT \
"#{?pane_format," \
- "#{pane_current_command} \"#{pane_title}\"" \
+ "#{?pane_marked,#[reverse],}" \
+ "#{pane_current_command}#{?pane_active,*,}#{?pane_marked,M,}" \
+ "#{?#{&&:#{pane_title},#{!=:#{pane_title},#{host_short}}},: \"#{pane_title}\",}" \
"," \
"#{?window_format," \
- "#{window_name}#{window_flags} " \
- "(#{window_panes} panes)" \
- "#{?#{==:#{window_panes},1}, \"#{pane_title}\",}" \
+ "#{?window_marked_flag,#[reverse],}" \
+ "#{window_name}#{window_flags}" \
+ "#{?#{&&:#{==:#{window_panes},1},#{&&:#{pane_title},#{!=:#{pane_title},#{host_short}}}},: \"#{pane_title}\",}" \
"," \
"#{session_windows} windows" \
"#{?session_grouped, " \
@@ -54,8 +56,9 @@ static void window_tree_key(struct window_mode_entry *,
"}"
static const struct menu_item window_tree_menu_items[] = {
- { "Select", 'E', NULL },
- { "Expand", 'R', NULL },
+ { "Select", '\r', NULL },
+ { "Expand", KEYC_RIGHT, NULL },
+ { "Mark", 'm', NULL },
{ "", KEYC_NONE, NULL },
{ "Tag", 't', NULL },
{ "Tag All", '\024', NULL },
@@ -833,7 +836,7 @@ window_tree_search(__unused void *modedata, void *itemdata, const char *ss)
return (0);
retval = (strstr(cmd, ss) != NULL);
free(cmd);
- return retval;
+ return (retval);
}
return (0);
}
@@ -1170,7 +1173,7 @@ window_tree_key(struct window_mode_entry *wme, struct client *c,
struct window_tree_modedata *data = wme->data;
struct window_tree_itemdata *item, *new_item;
char *name, *prompt = NULL;
- struct cmd_find_state fs;
+ struct cmd_find_state fs, *fsp = &data->fs;
int finished;
u_int tagged, x, y, idx;
struct session *ns;
@@ -1192,6 +1195,21 @@ window_tree_key(struct window_mode_entry *wme, struct client *c,
case '>':
data->offset++;
break;
+ case 'H':
+ mode_tree_expand(data->data, (uint64_t)fsp->s);
+ mode_tree_expand(data->data, (uint64_t)fsp->wl);
+ if (!mode_tree_set_current(data->data, (uint64_t)wme->wp))
+ mode_tree_set_current(data->data, (uint64_t)fsp->wl);
+ break;
+ case 'm':
+ window_tree_pull_item(item, &ns, &nwl, &nwp);
+ server_set_marked(ns, nwl, nwp);
+ mode_tree_build(data->data);
+ break;
+ case 'M':
+ server_clear_marked();
+ mode_tree_build(data->data);
+ break;
case 'x':
window_tree_pull_item(item, &ns, &nwl, &nwp);
switch (item->type) {
diff --git a/window.c b/window.c
index f911f186..8121ba2d 100644
--- a/window.c
+++ b/window.c
@@ -423,8 +423,8 @@ window_resize(struct window *w, u_int sx, u_int sy, int xpixel, int ypixel)
ypixel = DEFAULT_YPIXEL;
log_debug("%s: @%u resize %ux%u (%ux%u)", __func__, w->id, sx, sy,
- xpixel == -1 ? w->xpixel : xpixel,
- ypixel == -1 ? w->ypixel : ypixel);
+ xpixel == -1 ? w->xpixel : (u_int)xpixel,
+ ypixel == -1 ? w->ypixel : (u_int)ypixel);
w->sx = sx;
w->sy = sy;
if (xpixel != -1)
@@ -495,8 +495,8 @@ window_set_active_pane(struct window *w, struct window_pane *wp, int notify)
void
window_redraw_active_switch(struct window *w, struct window_pane *wp)
{
- struct style *sy1, *sy2;
- int c1, c2;
+ struct grid_cell *gc1, *gc2;
+ int c1, c2;
if (wp == w->active)
return;
@@ -506,18 +506,18 @@ window_redraw_active_switch(struct window *w, struct window_pane *wp)
* If the active and inactive styles or palettes are different,
* need to redraw the panes.
*/
- sy1 = &wp->cached_style;
- sy2 = &wp->cached_active_style;
- if (!style_equal(sy1, sy2))
+ gc1 = &wp->cached_gc;
+ gc2 = &wp->cached_active_gc;
+ if (!grid_cells_look_equal(gc1, gc2))
wp->flags |= PANE_REDRAW;
else {
- c1 = window_pane_get_palette(wp, sy1->gc.fg);
- c2 = window_pane_get_palette(wp, sy2->gc.fg);
+ c1 = window_pane_get_palette(wp, gc1->fg);
+ c2 = window_pane_get_palette(wp, gc2->fg);
if (c1 != c2)
wp->flags |= PANE_REDRAW;
else {
- c1 = window_pane_get_palette(wp, sy1->gc.bg);
- c2 = window_pane_get_palette(wp, sy2->gc.bg);
+ c1 = window_pane_get_palette(wp, gc1->bg);
+ c2 = window_pane_get_palette(wp, gc2->bg);
if (c1 != c2)
wp->flags |= PANE_REDRAW;
}
@@ -872,6 +872,9 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit)
wp->fd = -1;
wp->event = NULL;
+ wp->fg = 8;
+ wp->bg = 8;
+
TAILQ_INIT(&wp->modes);
wp->layout_cell = NULL;
@@ -886,10 +889,6 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit)
wp->pipe_off = 0;
wp->pipe_event = NULL;
- wp->saved_grid = NULL;
- wp->saved_cx = UINT_MAX;
- wp->saved_cy = UINT_MAX;
-
screen_init(&wp->base, sx, sy, hlimit);
wp->screen = &wp->base;
@@ -898,8 +897,6 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit)
if (gethostname(host, sizeof host) == 0)
screen_set_title(&wp->base, host);
- input_init(wp);
-
return (wp);
}
@@ -916,14 +913,12 @@ window_pane_destroy(struct window_pane *wp)
bufferevent_free(wp->event);
close(wp->fd);
}
-
- input_free(wp);
+ if (wp->ictx != NULL)
+ input_free(wp->ictx);
screen_free(&wp->status_screen);
screen_free(&wp->base);
- if (wp->saved_grid != NULL)
- grid_destroy(wp->saved_grid);
if (wp->pipe_fd != -1) {
bufferevent_free(wp->pipe_event);
@@ -959,7 +954,7 @@ window_pane_read_callback(__unused struct bufferevent *bufev, void *data)
}
log_debug("%%%u has %zu bytes", wp->id, size);
- input_parse(wp);
+ input_parse_pane(wp);
wp->pipe_off = EVBUFFER_LENGTH(evb);
}
@@ -984,6 +979,7 @@ window_pane_set_event(struct window_pane *wp)
wp->event = bufferevent_new(wp->fd, window_pane_read_callback,
NULL, window_pane_error_callback, wp);
+ wp->ictx = input_init(wp, wp->event);
bufferevent_setwatermark(wp->event, EV_READ, 0, READ_SIZE);
bufferevent_enable(wp->event, EV_READ|EV_WRITE);
@@ -1000,7 +996,7 @@ window_pane_resize(struct window_pane *wp, u_int sx, u_int sy)
wp->sy = sy;
log_debug("%s: %%%u resize %ux%u", __func__, wp->id, sx, sy);
- screen_resize(&wp->base, sx, sy, wp->saved_grid == NULL);
+ screen_resize(&wp->base, sx, sy, wp->base.saved_grid == NULL);
wme = TAILQ_FIRST(&wp->modes);
if (wme != NULL && wme->mode->resize != NULL)
@@ -1009,93 +1005,6 @@ window_pane_resize(struct window_pane *wp, u_int sx, u_int sy)
wp->flags |= (PANE_RESIZE|PANE_RESIZED);
}
-/*
- * 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,
- int cursor)
-{
- struct screen *s = &wp->base;
- u_int sx, sy;
-
- if (wp->saved_grid != NULL)
- return;
- if (!options_get_number(wp->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);
- if (cursor) {
- 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, 8);
-
- 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,
- int cursor)
-{
- struct screen *s = &wp->base;
- u_int sx, sy;
-
- if (!options_get_number(wp->options, "alternate-screen"))
- return;
-
- /*
- * Restore the cursor position and cell. This happens even if not
- * currently in the alternate screen.
- */
- if (cursor && wp->saved_cx != UINT_MAX && wp->saved_cy != UINT_MAX) {
- 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);
- }
-
- if (wp->saved_grid == NULL)
- 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, 1);
-
- /* Restore the saved grid. */
- grid_duplicate_lines(s->grid, screen_hsize(s), wp->saved_grid, 0, sy);
-
- /*
- * 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 || sx != wp->saved_grid->sx)
- screen_resize(s, sx, sy, 1);
-
- grid_destroy(wp->saved_grid);
- wp->saved_grid = NULL;
-
- wp->flags |= PANE_REDRAW;
-}
-
void
window_pane_set_palette(struct window_pane *wp, u_int n, int colour)
{
@@ -1150,40 +1059,16 @@ window_pane_get_palette(struct window_pane *wp, int c)
return (new);
}
-static void
-window_pane_mode_timer(__unused int fd, __unused short events, void *arg)
-{
- struct window_pane *wp = arg;
- struct timeval tv = { .tv_sec = 10 };
- int n = 0;
-
- evtimer_del(&wp->modetimer);
- evtimer_add(&wp->modetimer, &tv);
-
- log_debug("%%%u in mode: last=%ld", wp->id, (long)wp->modelast);
-
- if (wp->modelast < time(NULL) - WINDOW_MODE_TIMEOUT) {
- if (ioctl(wp->fd, FIONREAD, &n) == -1 || n > 0)
- window_pane_reset_mode_all(wp);
- }
-}
-
int
-window_pane_set_mode(struct window_pane *wp, const struct window_mode *mode,
- struct cmd_find_state *fs, struct args *args)
+window_pane_set_mode(struct window_pane *wp, struct window_pane *swp,
+ const struct window_mode *mode, struct cmd_find_state *fs,
+ struct args *args)
{
- struct timeval tv = { .tv_sec = 10 };
struct window_mode_entry *wme;
if (!TAILQ_EMPTY(&wp->modes) && TAILQ_FIRST(&wp->modes)->mode == mode)
return (1);
- wp->modelast = time(NULL);
- if (TAILQ_EMPTY(&wp->modes)) {
- evtimer_set(&wp->modetimer, window_pane_mode_timer, wp);
- evtimer_add(&wp->modetimer, &tv);
- }
-
TAILQ_FOREACH(wme, &wp->modes, entry) {
if (wme->mode == mode)
break;
@@ -1194,6 +1079,7 @@ window_pane_set_mode(struct window_pane *wp, const struct window_mode *mode,
} else {
wme = xcalloc(1, sizeof *wme);
wme->wp = wp;
+ wme->swp = swp;
wme->mode = mode;
wme->prefix = 1;
TAILQ_INSERT_HEAD(&wp->modes, wme, entry);
@@ -1203,6 +1089,7 @@ window_pane_set_mode(struct window_pane *wp, const struct window_mode *mode,
wp->screen = wme->screen;
wp->flags |= (PANE_REDRAW|PANE_CHANGED);
+ server_redraw_window_borders(wp->window);
server_status_window(wp->window);
notify_pane("pane-mode-changed", wp);
@@ -1225,7 +1112,6 @@ window_pane_reset_mode(struct window_pane *wp)
next = TAILQ_FIRST(&wp->modes);
if (next == NULL) {
log_debug("%s: no next mode", __func__);
- evtimer_del(&wp->modetimer);
wp->screen = &wp->base;
} else {
log_debug("%s: next mode is %s", __func__, next->mode->name);
@@ -1235,6 +1121,7 @@ window_pane_reset_mode(struct window_pane *wp)
}
wp->flags |= (PANE_REDRAW|PANE_CHANGED);
+ server_redraw_window_borders(wp->window);
server_status_window(wp->window);
notify_pane("pane-mode-changed", wp);
}
@@ -1258,8 +1145,7 @@ window_pane_key(struct window_pane *wp, struct client *c, struct session *s,
wme = TAILQ_FIRST(&wp->modes);
if (wme != NULL) {
- wp->modelast = time(NULL);
- if (wme->mode->key != NULL)
+ if (wme->mode->key != NULL && c != NULL)
wme->mode->key(wme, c, s, wl, (key & ~KEYC_XTERM), m);
return (0);
}
@@ -1267,7 +1153,7 @@ window_pane_key(struct window_pane *wp, struct client *c, struct session *s,
if (wp->fd == -1 || wp->flags & PANE_INPUTOFF)
return (0);
- if (input_key(wp, key, m) != 0)
+ if (input_key_pane(wp, key, m) != 0)
return (-1);
if (KEYC_IS_MOUSE(key))
@@ -1279,7 +1165,7 @@ window_pane_key(struct window_pane *wp, struct client *c, struct session *s,
wp2->fd != -1 &&
(~wp2->flags & PANE_INPUTOFF) &&
window_pane_visible(wp2))
- input_key(wp2, key, NULL);
+ input_key_pane(wp2, key, NULL);
}
}
return (0);
@@ -1324,7 +1210,7 @@ window_pane_search(struct window_pane *wp, const char *term, int regex,
}
log_debug("%s: %s", __func__, line);
if (!regex)
- found = (fnmatch(new, line, 0) == 0);
+ found = (fnmatch(new, line, flags) == 0);
else
found = (regexec(&r, line, 0, NULL, 0) == 0);
free(line);
@@ -1645,7 +1531,7 @@ int
window_pane_start_input(struct window_pane *wp, struct cmdq_item *item,
char **cause)
{
- struct client *c = item->client;
+ struct client *c = cmdq_get_client(item);
struct window_pane_input_data *cdata;
if (~wp->flags & PANE_EMPTY) {