aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicholas Marriott <nicholas.marriott@gmail.com>2019-07-29 10:51:30 +0100
committerNicholas Marriott <nicholas.marriott@gmail.com>2019-07-29 10:51:30 +0100
commitda552eb73b80bab3c0a28dfb9ae2c75fa6d4bdaf (patch)
treecf9c86c3218659faf46e606a1e38bc6ebb570dcd
parent5a501a8ae27c2d0128870caa48c5708e97528567 (diff)
parentb90a9fcd13f4434aed0fe1785d619aa668bbc77d (diff)
downloadrtmux-da552eb73b80bab3c0a28dfb9ae2c75fa6d4bdaf.tar.gz
rtmux-da552eb73b80bab3c0a28dfb9ae2c75fa6d4bdaf.tar.bz2
rtmux-da552eb73b80bab3c0a28dfb9ae2c75fa6d4bdaf.zip
Merge branch 'master' into 3.0-rc
-rw-r--r--.github/CONTRIBUTING.md9
-rw-r--r--.github/ISSUE_TEMPLATE.md3
-rw-r--r--.github/README.md19
-rw-r--r--CHANGES53
-rw-r--r--Makefile.am1
-rw-r--r--README6
-rw-r--r--arguments.c22
-rw-r--r--cfg.c10
-rw-r--r--client.c4
-rw-r--r--cmd-attach-session.c27
-rw-r--r--cmd-break-pane.c2
-rw-r--r--cmd-display-message.c3
-rw-r--r--cmd-display-panes.c2
-rw-r--r--cmd-find-window.c81
-rw-r--r--cmd-find.c73
-rw-r--r--cmd-if-shell.c20
-rw-r--r--cmd-join-pane.c2
-rw-r--r--cmd-load-buffer.c2
-rw-r--r--cmd-new-session.c7
-rw-r--r--cmd-parse.y61
-rw-r--r--cmd-queue.c7
-rw-r--r--cmd-refresh-client.c62
-rw-r--r--cmd-resize-pane.c8
-rw-r--r--cmd-run-shell.c2
-rw-r--r--cmd-select-pane.c18
-rw-r--r--cmd-send-keys.c76
-rw-r--r--cmd-set-option.c68
-rw-r--r--cmd-show-options.c132
-rw-r--r--cmd-source-file.c6
-rw-r--r--cmd-swap-pane.c4
-rw-r--r--cmd-wait-for.c8
-rw-r--r--cmd.c4
-rw-r--r--colour.c84
-rw-r--r--configure.ac2
-rw-r--r--control-notify.c3
-rw-r--r--control.c1
-rw-r--r--format-draw.c17
-rw-r--r--format.c133
-rw-r--r--grid-view.c1
-rw-r--r--grid.c35
-rw-r--r--input-keys.c7
-rw-r--r--input.c29
-rw-r--r--job.c2
-rw-r--r--key-string.c6
-rw-r--r--layout-custom.c12
-rw-r--r--layout-set.c8
-rw-r--r--layout.c139
-rw-r--r--menu.c22
-rw-r--r--mode-tree.c6
-rw-r--r--options-table.c12
-rw-r--r--options.c105
-rw-r--r--osdep-netbsd.c17
-rw-r--r--regress/command-order.sh6
-rw-r--r--regress/conf/21867280ff7e99631046f9cc669b80d2.conf8
-rw-r--r--regress/conf/99749670b62bcb99a9b2e3d59708e357.conf93
-rw-r--r--regress/xenl-terminal.sh29
-rw-r--r--regsub.c115
-rw-r--r--screen-redraw.c24
-rw-r--r--screen-write.c8
-rw-r--r--server-client.c99
-rw-r--r--server-fn.c2
-rw-r--r--server.c7
-rw-r--r--spawn.c4
-rw-r--r--style.c14
-rw-r--r--tmux.1513
-rw-r--r--tmux.c6
-rw-r--r--tmux.h64
-rw-r--r--tty-term.c3
-rw-r--r--tty.c140
-rw-r--r--window-buffer.c2
-rw-r--r--window-copy.c15
-rw-r--r--window.c185
-rw-r--r--xmalloc.c2
73 files changed, 1843 insertions, 939 deletions
diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
index 49e2b90b..3a589484 100644
--- a/.github/CONTRIBUTING.md
+++ b/.github/CONTRIBUTING.md
@@ -2,13 +2,20 @@
Before opening an issue, please ensure that:
+- Your problem is a specific problem or question or suggestion, not a general
+ complaint.
+
- `$TERM` inside tmux is screen, screen-256color, tmux or tmux-256color. Check
by running `echo $TERM` inside tmux.
- You can reproduce the problem with the latest tmux release, or a build from
Git master.
-- Your question or issue is not covered in the manual (run man tmux).
+- Your question or issue is not covered [in the
+ manual](https://man.openbsd.org/tmux.1) (run `man tmux`).
+
+- Your problem is not mentioned in the [CHANGES
+ file](https://raw.githubusercontent.com/tmux/tmux/master/CHANGES) file.
- Nobody else has opened the same issue recently.
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
index ee457237..8bf1e66a 100644
--- a/.github/ISSUE_TEMPLATE.md
+++ b/.github/ISSUE_TEMPLATE.md
@@ -3,6 +3,9 @@
Please read https://github.com/tmux/tmux/blob/master/.github/CONTRIBUTING.md
before opening an issue.
+If you have upgraded, make sure your issue is not covered in the CHANGES file
+for your version: https://raw.githubusercontent.com/tmux/tmux/master/CHANGES
+
Describe the problem and the steps to reproduce. Add a minimal tmux config if
necessary. Screenshots can be helpful, but no more than one or two.
diff --git a/.github/README.md b/.github/README.md
index 6e262ef5..2b299cc5 100644
--- a/.github/README.md
+++ b/.github/README.md
@@ -30,7 +30,8 @@ configure with `--enable-utempter` to enable this.
### From version control
-To get and build the latest from version control:
+To get and build the latest from version control - note that this requires
+`autoconf`, `automake` and `pkg-config`:
~~~bash
git clone https://github.com/tmux/tmux.git
@@ -39,10 +40,6 @@ sh autogen.sh
./configure && make
~~~
-(Note that this requires at least a working C compiler, `make`, `autoconf`,
-`automake`, `pkg-config` as well as `libevent` and `ncurses` libraries and
-headers.)
-
## Contributing
Bug reports, feature suggestions and especially code contributions are most
@@ -50,14 +47,12 @@ welcome. Please send by email to:
tmux-users@googlegroups.com
-Or open a GitHub issue or pull request.
-
-There is [a TODO list](https://github.com/tmux/tmux/wiki/Contributing) which
-explains some ideas for tmux not yet developed. Please feel free to ask for
-clarifications on the mailing list if you're thinking of working on these or
-need further information.
+Or open a GitHub issue or pull request. **Please read [this
+document](CONTRIBUTING.md) before opening an issue.**
-Please read the CONTRIBUTING file before opening an issue.
+There is [a list of suggestions for contributions](https://github.com/tmux/tmux/wiki/Contributing).
+Please feel free to ask on the mailing list if you're thinking of working on something or need
+further information.
## Documentation
diff --git a/CHANGES b/CHANGES
index 3563bcbc..952a95a6 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,56 @@
+CHANGES FROM 3.0 to X.X
+
+* Expand arguments to C and s format modifiers to match the m modifier.
+
+* Add support for underscore colours (Setulc capability must be added with
+ terminal-overrides as described in tmux(1)).
+
+* Add a "fill" style attribute for the fill colour of the drawing area (where
+ appropriate).
+
+* New -H flag to send-keys to send literal keys.
+
+* Format variables for pane mouse modes (mouse_utf8_flag and mouse_sgr_flag)
+ and for origin mode (origin_flag).
+
+* Add -F to refresh-client for flags for control mode clients, only one flag
+ (no-output) supported at the moment.
+
+* Add a few vi(1) keys for menus.
+
+* Add pane options, set with set-option -p and displayed with show-options -p.
+ Pane options inherit from window options (so every pane option is also
+ a window option). The pane style is now configured by setting window-style
+ and window-active-style in the pane options; select-pane -P and -g now change
+ the option but are no longer documented.
+
+* Do not document set-window-option and show-window-options. set-option -w and
+ show-options -w should be used instead.
+
+* Add a -A flag to show-options to show parent options as well (they are marked
+ with a *).
+
+* Resize panes lazily - do not resize unless they are in an attached, active
+ window.
+
+* Add regular expression support for the format search, match and substitute
+ modifiers and make them able to ignore case. find-window now accepts -r to
+ use regular expressions.
+
+* Do not use $TMUX to find the session because for windows in multiple sessions
+ it is wrong as often as it is right, and for windows in one session it is
+ pointless. Instead use TMUX_PANE if it is present.
+
+* Do not always resize the window back to its original size after applying a
+ layout, keep it at the layout size until it must be resized (for example when
+ attached and window-size is not manual).
+
+* Add new-session -X and attach-session -x to send SIGHUP to parent when
+ detaching (like detach-client -P).
+
+* Support for octal escapes in strings (such as \007) and improve list-keys
+ output so it parses correctly if copied into a configuration file.
+
CHANGES FROM 2.9 to 3.0
* INCOMPATIBLE: Add a new {} syntax to the configuration file. This is a string
diff --git a/Makefile.am b/Makefile.am
index 2b88892f..94b1564b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -151,6 +151,7 @@ dist_tmux_SOURCES = \
options.c \
paste.c \
proc.c \
+ regsub.c \
resize.c \
screen-redraw.c \
screen-write.c \
diff --git a/README b/README
index 8a9070b8..4f577060 100644
--- a/README
+++ b/README
@@ -26,16 +26,14 @@ To build and install tmux from a release tarball, use:
tmux can use the utempter library to update utmp(5), if it is installed - run
configure with --enable-utempter to enable this.
-To get and build the latest from version control:
+To get and build the latest from version control - note that this requires
+autoconf, automake and pkg-config:
$ git clone https://github.com/tmux/tmux.git
$ cd tmux
$ sh autogen.sh
$ ./configure && make
-(Note that this requires at least a working C compiler, make, autoconf,
-automake, pkg-config as well as libevent and ncurses libraries and headers.)
-
* Contributing
Bug reports, feature suggestions and especially code contributions are most
diff --git a/arguments.c b/arguments.c
index 38e50829..026272af 100644
--- a/arguments.c
+++ b/arguments.c
@@ -37,6 +37,7 @@ TAILQ_HEAD(args_values, args_value);
struct args_entry {
u_char flag;
struct args_values values;
+ u_int count;
RB_ENTRY(args_entry) entry;
};
@@ -173,6 +174,7 @@ args_print(struct args *args)
size_t len;
char *buf;
int i;
+ u_int j;
struct args_entry *entry;
struct args_value *value;
@@ -186,7 +188,8 @@ args_print(struct args *args)
if (*buf == '\0')
args_print_add(&buf, &len, "-");
- args_print_add(&buf, &len, "%c", entry->flag);
+ for (j = 0; j < entry->count; j++)
+ args_print_add(&buf, &len, "%c", entry->flag);
}
/* Then the flags with arguments. */
@@ -212,12 +215,14 @@ args_escape(const char *s)
if (*s == '\0')
return (xstrdup(s));
- if ((strchr(quoted, s[0]) != NULL || s[0] == '~') && s[1] == '\0') {
+ if (s[0] != ' ' &&
+ (strchr(quoted, s[0]) != NULL || s[0] == '~') &&
+ s[1] == '\0') {
xasprintf(&escaped, "\\%c", s[0]);
return (escaped);
}
- flags = VIS_OCTAL|VIS_TAB|VIS_NL;
+ flags = VIS_OCTAL|VIS_CSTYLE|VIS_TAB|VIS_NL;
if (s[strcspn(s, quoted)] != '\0')
flags |= VIS_DQ;
utf8_stravis(&escaped, s, flags);
@@ -241,7 +246,12 @@ args_escape(const char *s)
int
args_has(struct args *args, u_char ch)
{
- return (args_find(args, ch) != NULL);
+ struct args_entry *entry;
+
+ entry = args_find(args, ch);
+ if (entry == NULL)
+ return (0);
+ return (entry->count);
}
/* Set argument value in the arguments tree. */
@@ -255,9 +265,11 @@ args_set(struct args *args, u_char ch, const char *s)
if (entry == NULL) {
entry = xcalloc(1, sizeof *entry);
entry->flag = ch;
+ entry->count = 1;
TAILQ_INIT(&entry->values);
RB_INSERT(args_tree, &args->tree, entry);
- }
+ } else
+ entry->count++;
if (s != NULL) {
value = xcalloc(1, sizeof *value);
diff --git a/cfg.c b/cfg.c
index 18386b56..c29292b2 100644
--- a/cfg.c
+++ b/cfg.c
@@ -52,7 +52,7 @@ cfg_done(__unused struct cmdq_item *item, __unused void *data)
cfg_show_causes(RB_MIN(sessions, &sessions));
if (cfg_item != NULL)
- cfg_item->flags &= ~CMDQ_WAITING;
+ cmdq_continue(cfg_item);
status_prompt_load_history();
@@ -90,14 +90,14 @@ start_cfg(void)
}
if (cfg_file == NULL)
- load_cfg(TMUX_CONF, NULL, NULL, CMD_PARSE_QUIET, NULL);
+ load_cfg(TMUX_CONF, c, NULL, CMD_PARSE_QUIET, NULL);
if (cfg_file == NULL && (home = find_home()) != NULL) {
xasprintf(&cfg_file, "%s/.tmux.conf", home);
flags = CMD_PARSE_QUIET;
}
if (cfg_file != NULL)
- load_cfg(cfg_file, NULL, NULL, flags, NULL);
+ load_cfg(cfg_file, c, NULL, flags, NULL);
cmdq_append(NULL, cmdq_get_callback(cfg_done, NULL));
}
@@ -126,6 +126,8 @@ load_cfg(const char *path, struct client *c, struct cmdq_item *item, int flags,
pi.flags = flags;
pi.file = path;
pi.line = 1;
+ pi.item = item;
+ pi.c = c;
pr = cmd_parse_from_file(f, &pi);
fclose(f);
@@ -145,7 +147,7 @@ load_cfg(const char *path, struct client *c, struct cmdq_item *item, int flags,
if (item != NULL)
cmdq_insert_after(item, new_item0);
else
- cmdq_append(c, new_item0);
+ cmdq_append(NULL, new_item0);
cmd_list_free(pr->cmdlist);
if (new_item != NULL)
diff --git a/client.c b/client.c
index d137501a..204a431b 100644
--- a/client.c
+++ b/client.c
@@ -202,7 +202,7 @@ client_exit_message(void)
case CLIENT_EXIT_TERMINATED:
return ("terminated");
case CLIENT_EXIT_LOST_SERVER:
- return ("lost server");
+ return ("server exited unexpectedly");
case CLIENT_EXIT_EXITED:
return ("exited");
case CLIENT_EXIT_SERVER_EXITED:
@@ -436,7 +436,7 @@ client_stdin_callback(__unused int fd, __unused short events,
struct msg_stdin_data data;
data.size = read(STDIN_FILENO, data.data, sizeof data.data);
- if (data.size < 0 && (errno == EINTR || errno == EAGAIN))
+ if (data.size == -1 && (errno == EINTR || errno == EAGAIN))
return;
proc_send(client_peer, MSG_STDIN, -1, &data, sizeof data);
diff --git a/cmd-attach-session.c b/cmd-attach-session.c
index bcd6d895..6de734e5 100644
--- a/cmd-attach-session.c
+++ b/cmd-attach-session.c
@@ -37,8 +37,8 @@ const struct cmd_entry cmd_attach_session_entry = {
.name = "attach-session",
.alias = "attach",
- .args = { "c:dErt:", 0, 0 },
- .usage = "[-dEr] [-c working-directory] " CMD_TARGET_SESSION_USAGE,
+ .args = { "c:dErt:x", 0, 0 },
+ .usage = "[-dErx] [-c working-directory] " CMD_TARGET_SESSION_USAGE,
/* -t is special */
@@ -48,7 +48,7 @@ const struct cmd_entry cmd_attach_session_entry = {
enum cmd_retval
cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
- int rflag, const char *cflag, int Eflag)
+ int xflag, int rflag, const char *cflag, int Eflag)
{
struct cmd_find_state *current = &item->shared->current;
enum cmd_find_type type;
@@ -58,6 +58,7 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
struct winlink *wl;
struct window_pane *wp;
char *cause;
+ enum msgtype msgtype;
if (RB_EMPTY(&sessions)) {
cmdq_error(item, "no sessions");
@@ -102,11 +103,15 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
c->last_session = c->session;
if (c->session != NULL) {
- if (dflag) {
+ if (dflag || xflag) {
+ if (xflag)
+ msgtype = MSG_DETACHKILL;
+ else
+ msgtype = MSG_DETACH;
TAILQ_FOREACH(c_loop, &clients, entry) {
if (c_loop->session != s || c == c_loop)
continue;
- server_client_detach(c_loop, MSG_DETACH);
+ server_client_detach(c_loop, msgtype);
}
}
if (!Eflag)
@@ -131,11 +136,15 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
if (rflag)
c->flags |= CLIENT_READONLY;
- if (dflag) {
+ if (dflag || xflag) {
+ if (xflag)
+ msgtype = MSG_DETACHKILL;
+ else
+ msgtype = MSG_DETACH;
TAILQ_FOREACH(c_loop, &clients, entry) {
if (c_loop->session != s || c == c_loop)
continue;
- server_client_detach(c_loop, MSG_DETACH);
+ server_client_detach(c_loop, msgtype);
}
}
if (!Eflag)
@@ -169,6 +178,6 @@ cmd_attach_session_exec(struct cmd *self, struct cmdq_item *item)
struct args *args = self->args;
return (cmd_attach_session(item, args_get(args, 't'),
- args_has(args, 'd'), args_has(args, 'r'), args_get(args, 'c'),
- args_has(args, 'E')));
+ args_has(args, 'd'), args_has(args, 'x'), args_has(args, 'r'),
+ args_get(args, 'c'), args_has(args, 'E')));
}
diff --git a/cmd-break-pane.c b/cmd-break-pane.c
index 3b929dee..b4c5b7cd 100644
--- a/cmd-break-pane.c
+++ b/cmd-break-pane.c
@@ -77,6 +77,8 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
layout_close_pane(wp);
w = wp->window = window_create(w->sx, w->sy);
+ options_set_parent(wp->options, w->options);
+ wp->flags |= PANE_STYLECHANGED;
TAILQ_INSERT_HEAD(&w->panes, wp, entry);
w->active = wp;
diff --git a/cmd-display-message.c b/cmd-display-message.c
index 8c1ad5f6..4d9bccb6 100644
--- a/cmd-display-message.c
+++ b/cmd-display-message.c
@@ -109,8 +109,7 @@ cmd_display_message_exec(struct cmd *self, struct cmdq_item *item)
format_defaults(ft, target_c, s, wl, wp);
if (args_has(args, 'a')) {
- if (item != NULL)
- format_each(ft, cmd_display_message_each, item);
+ format_each(ft, cmd_display_message_each, item);
return (CMD_RETURN_NORMAL);
}
diff --git a/cmd-display-panes.c b/cmd-display-panes.c
index 7f38cd9e..df97819c 100644
--- a/cmd-display-panes.c
+++ b/cmd-display-panes.c
@@ -188,7 +188,7 @@ cmd_display_panes_free(struct client *c)
struct cmd_display_panes_data *cdata = c->overlay_data;
if (cdata->item != NULL)
- cdata->item->flags &= ~CMDQ_WAITING;
+ cmdq_continue(cdata->item);
free(cdata->command);
free(cdata);
}
diff --git a/cmd-find-window.c b/cmd-find-window.c
index c2d230a5..c29878b5 100644
--- a/cmd-find-window.c
+++ b/cmd-find-window.c
@@ -32,8 +32,8 @@ const struct cmd_entry cmd_find_window_entry = {
.name = "find-window",
.alias = "findw",
- .args = { "CNt:TZ", 1, 1 },
- .usage = "[-CNTZ] " CMD_TARGET_PANE_USAGE " match-string",
+ .args = { "CNrt:TZ", 1, 1 },
+ .usage = "[-CNrTZ] " CMD_TARGET_PANE_USAGE " match-string",
.target = { 't', CMD_FIND_PANE, 0 },
@@ -57,30 +57,59 @@ cmd_find_window_exec(struct cmd *self, struct cmdq_item *item)
if (!C && !N && !T)
C = N = T = 1;
- if (C && N && T) {
- xasprintf(&filter,
- "#{||:"
- "#{C:%s},#{||:#{m:*%s*,#{window_name}},"
- "#{m:*%s*,#{pane_title}}}}",
- s, s, s);
- } else if (C && N) {
- xasprintf(&filter,
- "#{||:#{C:%s},#{m:*%s*,#{window_name}}}",
- s, s);
- } else if (C && T) {
- xasprintf(&filter,
- "#{||:#{C:%s},#{m:*%s*,#{pane_title}}}",
- s, s);
- } else if (N && T) {
- xasprintf(&filter,
- "#{||:#{m:*%s*,#{window_name}},#{m:*%s*,#{pane_title}}}",
- s, s);
- } else if (C)
- xasprintf(&filter, "#{C:%s}", s);
- else if (N)
- xasprintf(&filter, "#{m:*%s*,#{window_name}}", s);
- else
- xasprintf(&filter, "#{m:*%s*,#{pane_title}}", s);
+ if (!args_has(args, 'r')) {
+ if (C && N && T) {
+ xasprintf(&filter,
+ "#{||:"
+ "#{C:%s},#{||:#{m:*%s*,#{window_name}},"
+ "#{m:*%s*,#{pane_title}}}}",
+ s, s, s);
+ } else if (C && N) {
+ xasprintf(&filter,
+ "#{||:#{C:%s},#{m:*%s*,#{window_name}}}",
+ s, s);
+ } else if (C && T) {
+ xasprintf(&filter,
+ "#{||:#{C:%s},#{m:*%s*,#{pane_title}}}",
+ s, s);
+ } else if (N && T) {
+ xasprintf(&filter,
+ "#{||:#{m:*%s*,#{window_name}},"
+ "#{m:*%s*,#{pane_title}}}",
+ s, s);
+ } else if (C)
+ xasprintf(&filter, "#{C:%s}", s);
+ else if (N)
+ xasprintf(&filter, "#{m:*%s*,#{window_name}}", s);
+ else
+ xasprintf(&filter, "#{m:*%s*,#{pane_title}}", s);
+ } else {
+ if (C && N && T) {
+ xasprintf(&filter,
+ "#{||:"
+ "#{C/r:%s},#{||:#{m/r:%s,#{window_name}},"
+ "#{m/r:%s,#{pane_title}}}}",
+ s, s, s);
+ } else if (C && N) {
+ xasprintf(&filter,
+ "#{||:#{C/r:%s},#{m/r:%s,#{window_name}}}",
+ s, s);
+ } else if (C && T) {
+ xasprintf(&filter,
+ "#{||:#{C/r:%s},#{m/r:%s,#{pane_title}}}",
+ s, s);
+ } else if (N && T) {
+ xasprintf(&filter,
+ "#{||:#{m/r:%s,#{window_name}},"
+ "#{m/r:%s,#{pane_title}}}",
+ s, s);
+ } else if (C)
+ xasprintf(&filter, "#{C/r:%s}", s);
+ else if (N)
+ xasprintf(&filter, "#{m/r:%s,#{window_name}}", s);
+ else
+ xasprintf(&filter, "#{m/r:%s,#{pane_title}}", s);
+ }
new_args = args_parse("", 1, &argv);
if (args_has(args, 'Z'))
diff --git a/cmd-find.c b/cmd-find.c
index 7ad8ad7a..154842ab 100644
--- a/cmd-find.c
+++ b/cmd-find.c
@@ -75,38 +75,12 @@ static const char *cmd_find_pane_table[][2] = {
{ NULL, NULL }
};
-/* Get session from TMUX if present. */
-static struct session *
-cmd_find_try_TMUX(struct client *c)
-{
- struct environ_entry *envent;
- char tmp[256];
- long long pid;
- u_int session;
- struct session *s;
-
- envent = environ_find(c->environ, "TMUX");
- if (envent == NULL)
- return (NULL);
-
- if (sscanf(envent->value, "%255[^,],%lld,%d", tmp, &pid, &session) != 3)
- return (NULL);
- if (pid != getpid())
- return (NULL);
- log_debug("%s: client %p TMUX %s (session $%u)", __func__, c,
- envent->value, session);
-
- s = session_find_by_id(session);
- if (s != NULL)
- log_debug("%s: session $%u still exists", __func__, s->id);
- return (s);
-}
-
/* Find pane containing client if any. */
static struct window_pane *
cmd_find_inside_pane(struct client *c)
{
struct window_pane *wp;
+ struct environ_entry *envent;
if (c == NULL)
return (NULL);
@@ -115,6 +89,11 @@ cmd_find_inside_pane(struct client *c)
if (wp->fd != -1 && strcmp(wp->tty, c->ttyname) == 0)
break;
}
+ if (wp == NULL) {
+ envent = environ_find(c->environ, "TMUX_PANE");
+ if (envent != NULL)
+ wp = window_pane_find_by_id_str(envent->value);
+ }
if (wp != NULL)
log_debug("%s: got pane %%%u (%s)", __func__, wp->id, wp->tty);
return (wp);
@@ -879,8 +858,6 @@ cmd_find_from_mouse(struct cmd_find_state *fs, struct mouse_event *m, int flags)
int
cmd_find_from_client(struct cmd_find_state *fs, struct client *c, int flags)
{
- struct session *s;
- struct winlink *wl;
struct window_pane *wp;
/* If no client, treat as from nothing. */
@@ -902,30 +879,6 @@ cmd_find_from_client(struct cmd_find_state *fs, struct client *c, int flags)
if (wp == NULL)
goto unknown_pane;
- /* If we have a session in TMUX, see if it has this pane. */
- s = cmd_find_try_TMUX(c);
- if (s != NULL) {
- RB_FOREACH(wl, winlinks, &s->windows) {
- if (window_has_pane(wl->window, wp))
- break;
- }
- if (wl != NULL) {
- log_debug("%s: session $%u has pane %%%u", __func__,
- s->id, wp->id);
-
- fs->s = s;
- fs->wl = s->curw; /* use current session */
- fs->w = fs->wl->window;
- fs->wp = fs->w->active; /* use active pane */
-
- cmd_find_log_state(__func__, fs);
- return (0);
- } else {
- log_debug("%s: session $%u does not have pane %%%u",
- __func__, s->id, wp->id);
- }
- }
-
/*
* Don't have a session, or it doesn't have this pane. Try all
* sessions.
@@ -947,17 +900,7 @@ cmd_find_from_client(struct cmd_find_state *fs, struct client *c, int flags)
return (0);
unknown_pane:
- /*
- * We're not running in a known pane, but maybe this client has TMUX
- * in the environment. That'd give us a session.
- */
- s = cmd_find_try_TMUX(c);
- if (s != NULL) {
- cmd_find_from_session(fs, s, flags);
- return (0);
- }
-
- /* Otherwise we need to guess. */
+ /* We can't find the pane so need to guess. */
return (cmd_find_from_nothing(fs, flags));
}
@@ -1005,6 +948,8 @@ cmd_find_target(struct cmd_find_state *fs, struct cmdq_item *item,
strlcat(tmp, "CANFAIL,", sizeof tmp);
if (*tmp != '\0')
tmp[strlen(tmp) - 1] = '\0';
+ else
+ strlcat(tmp, "NONE", sizeof tmp);
log_debug("%s: target %s, type %s, item %p, flags %s", __func__,
target == NULL ? "none" : target, s, item, tmp);
diff --git a/cmd-if-shell.c b/cmd-if-shell.c
index 84f66657..2befbc0c 100644
--- a/cmd-if-shell.c
+++ b/cmd-if-shell.c
@@ -67,10 +67,11 @@ cmd_if_shell_exec(struct cmd *self, struct cmdq_item *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 = item->target.s;
- struct winlink *wl = item->target.wl;
- struct window_pane *wp = item->target.wp;
+ struct session *s = fs->s;
+ struct winlink *wl = fs->wl;
+ struct window_pane *wp = fs->wp;
struct cmd_parse_input pi;
struct cmd_parse_result *pr;
@@ -92,7 +93,7 @@ cmd_if_shell_exec(struct cmd *self, struct cmdq_item *item)
pi.line = self->line;
pi.item = item;
pi.c = c;
- cmd_find_copy_state(&pi.fs, &item->target);
+ cmd_find_copy_state(&pi.fs, fs);
pr = cmd_parse_from_string(cmd, &pi);
switch (pr->status) {
@@ -103,7 +104,7 @@ cmd_if_shell_exec(struct cmd *self, struct cmdq_item *item)
free(pr->error);
return (CMD_RETURN_ERROR);
case CMD_PARSE_SUCCESS:
- new_item = cmdq_get_command(pr->cmdlist, NULL, m, 0);
+ new_item = cmdq_get_command(pr->cmdlist, fs, m, 0);
cmdq_insert_after(item, new_item);
cmd_list_free(pr->cmdlist);
break;
@@ -120,7 +121,10 @@ cmd_if_shell_exec(struct cmd *self, struct cmdq_item *item)
cdata->cmd_else = NULL;
memcpy(&cdata->mouse, m, sizeof cdata->mouse);
- cdata->client = item->client;
+ if (!args_has(args, 'b'))
+ cdata->client = item->client;
+ else
+ cdata->client = c;
if (cdata->client != NULL)
cdata->client->references++;
@@ -137,7 +141,7 @@ cmd_if_shell_exec(struct cmd *self, struct cmdq_item *item)
cdata->input.c = c;
if (cdata->input.c != NULL)
cdata->input.c->references++;
- cmd_find_copy_state(&cdata->input.fs, &item->target);
+ cmd_find_copy_state(&cdata->input.fs, fs);
if (job_run(shellcmd, s, server_client_get_cwd(item->client, s), NULL,
cmd_if_shell_callback, cmd_if_shell_free, cdata, 0) == NULL) {
@@ -195,7 +199,7 @@ cmd_if_shell_callback(struct job *job)
out:
if (cdata->item != NULL)
- cdata->item->flags &= ~CMDQ_WAITING;
+ cmdq_continue(cdata->item);
}
static void
diff --git a/cmd-join-pane.c b/cmd-join-pane.c
index 3d798e09..5d0e0d6a 100644
--- a/cmd-join-pane.c
+++ b/cmd-join-pane.c
@@ -139,6 +139,8 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
TAILQ_REMOVE(&src_w->panes, src_wp, entry);
src_wp->window = dst_w;
+ options_set_parent(src_wp->options, dst_w->options);
+ src_wp->flags |= PANE_STYLECHANGED;
TAILQ_INSERT_AFTER(&dst_w->panes, dst_wp, src_wp, entry);
layout_assign_pane(lc, src_wp);
diff --git a/cmd-load-buffer.c b/cmd-load-buffer.c
index 3e669093..cdf44bf7 100644
--- a/cmd-load-buffer.c
+++ b/cmd-load-buffer.c
@@ -176,7 +176,7 @@ cmd_load_buffer_callback(struct client *c, int closed, void *data)
free(cause);
}
out:
- cdata->item->flags &= ~CMDQ_WAITING;
+ cmdq_continue(cdata->item);
free(cdata->bufname);
free(cdata);
diff --git a/cmd-new-session.c b/cmd-new-session.c
index 559c268c..e0540815 100644
--- a/cmd-new-session.c
+++ b/cmd-new-session.c
@@ -39,8 +39,8 @@ const struct cmd_entry cmd_new_session_entry = {
.name = "new-session",
.alias = "new",
- .args = { "Ac:dDEF:n:Ps:t:x:y:", 0, -1 },
- .usage = "[-AdDEP] [-c start-directory] [-F format] [-n window-name] "
+ .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]",
@@ -105,7 +105,8 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
if (args_has(args, 'A')) {
retval = cmd_attach_session(item,
newname, args_has(args, 'D'),
- 0, NULL, args_has(args, 'E'));
+ args_has(args, 'X'), 0, NULL,
+ args_has(args, 'E'));
free(newname);
return (retval);
}
diff --git a/cmd-parse.y b/cmd-parse.y
index ce7b344b..6d2b970c 100644
--- a/cmd-parse.y
+++ b/cmd-parse.y
@@ -77,6 +77,8 @@ static char *cmd_parse_get_error(const char *, u_int, const char *);
static void cmd_parse_free_command(struct cmd_parse_command *);
static struct cmd_parse_commands *cmd_parse_new_commands(void);
static void cmd_parse_free_commands(struct cmd_parse_commands *);
+static void cmd_parse_print_commands(struct cmd_parse_input *, u_int,
+ struct cmd_list *);
%}
@@ -508,6 +510,22 @@ cmd_parse_get_error(const char *file, u_int line, const char *error)
}
static void
+cmd_parse_print_commands(struct cmd_parse_input *pi, u_int line,
+ struct cmd_list *cmdlist)
+{
+ char *s;
+
+ if (pi->item != NULL && (pi->flags & CMD_PARSE_VERBOSE)) {
+ s = cmd_list_print(cmdlist, 0);
+ if (pi->file != NULL)
+ cmdq_print(pi->item, "%s:%u: %s", pi->file, line, s);
+ else
+ cmdq_print(pi->item, "%u: %s", line, s);
+ free(s);
+ }
+}
+
+static void
cmd_parse_free_command(struct cmd_parse_command *cmd)
{
free(cmd->name);
@@ -663,6 +681,7 @@ cmd_parse_build_commands(struct cmd_parse_commands *cmds,
if (cmdlist == NULL || cmd->line != line) {
if (cmdlist != NULL) {
+ cmd_parse_print_commands(pi, line, cmdlist);
cmd_list_move(result, cmdlist);
cmd_list_free(cmdlist);
}
@@ -682,6 +701,7 @@ cmd_parse_build_commands(struct cmd_parse_commands *cmds,
cmd_list_append(cmdlist, add);
}
if (cmdlist != NULL) {
+ cmd_parse_print_commands(pi, line, cmdlist);
cmd_list_move(result, cmdlist);
cmd_list_free(cmdlist);
}
@@ -1124,17 +1144,54 @@ error:
static int
yylex_token_escape(char **buf, size_t *len)
{
- int ch, type;
+ int ch, type, o2, o3;
u_int size, i, tmp;
char s[9];
struct utf8_data ud;
- switch (ch = yylex_getc()) {
+ ch = yylex_getc();
+
+ if (ch >= '4' && ch <= '7') {
+ yyerror("invalid octal escape");
+ return (0);
+ }
+ if (ch >= '0' && ch <= '3') {
+ o2 = yylex_getc();
+ if (o2 >= '0' && o2 <= '7') {
+ o3 = yylex_getc();
+ if (o3 >= '0' && o3 <= '7') {
+ ch = 64 * (ch - '0') +
+ 8 * (o2 - '0') +
+ (o3 - '0');
+ yylex_append1(buf, len, ch);
+ return (1);
+ }
+ }
+ yyerror("invalid octal escape");
+ return (0);
+ }
+
+ switch (ch) {
case EOF:
return (0);
+ case 'a':
+ ch = '\a';
+ break;
+ case 'b':
+ ch = '\b';
+ break;
case 'e':
ch = '\033';
break;
+ case 'f':
+ ch = '\f';
+ break;
+ case 's':
+ ch = ' ';
+ break;
+ case 'v':
+ ch = '\v';
+ break;
case 'r':
ch = '\r';
break;
diff --git a/cmd-queue.c b/cmd-queue.c
index 1ee43508..ef68d5d5 100644
--- a/cmd-queue.c
+++ b/cmd-queue.c
@@ -156,6 +156,13 @@ cmdq_insert_hook(struct session *s, struct cmdq_item *item,
free(name);
}
+/* Continue processing command queue. */
+void
+cmdq_continue(struct cmdq_item *item)
+{
+ item->flags &= ~CMDQ_WAITING;
+}
+
/* Remove an item. */
static void
cmdq_remove(struct cmdq_item *item)
diff --git a/cmd-refresh-client.c b/cmd-refresh-client.c
index e5ae099f..49921a74 100644
--- a/cmd-refresh-client.c
+++ b/cmd-refresh-client.c
@@ -19,6 +19,7 @@
#include <sys/types.h>
#include <stdlib.h>
+#include <string.h>
#include "tmux.h"
@@ -33,8 +34,9 @@ const struct cmd_entry cmd_refresh_client_entry = {
.name = "refresh-client",
.alias = "refresh",
- .args = { "cC:DlLRSt:U", 0, 1 },
- .usage = "[-cDlLRSU] [-C size] " CMD_TARGET_CLIENT_USAGE " [adjustment]",
+ .args = { "cC:DF:lLRSt:U", 0, 1 },
+ .usage = "[-cDlLRSU] [-C XxY] [-F flags] " CMD_TARGET_CLIENT_USAGE
+ " [adjustment]",
.flags = CMD_AFTERHOOK,
.exec = cmd_refresh_client_exec
@@ -48,6 +50,7 @@ cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item)
struct tty *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)
@@ -107,28 +110,43 @@ cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item)
if (args_has(args, 'l')) {
if (c->session != NULL)
tty_putcode_ptr2(&c->tty, TTYC_MS, "", "?");
- } else if (args_has(args, 'C')) {
- if ((size = args_get(args, 'C')) == NULL) {
- cmdq_error(item, "missing size");
- return (CMD_RETURN_ERROR);
- }
- if (sscanf(size, "%u,%u", &x, &y) != 2 &&
- sscanf(size, "%ux%u", &x, &y)) {
- cmdq_error(item, "bad size argument");
- return (CMD_RETURN_ERROR);
- }
- if (x < WINDOW_MINIMUM || x > WINDOW_MAXIMUM ||
- y < WINDOW_MINIMUM || y > WINDOW_MAXIMUM) {
- cmdq_error(item, "size too small or too big");
- return (CMD_RETURN_ERROR);
+ return (CMD_RETURN_NORMAL);
+ }
+
+ if (args_has(args, 'C') || args_has(args, 'F')) {
+ if (args_has(args, 'C')) {
+ if (!(c->flags & CLIENT_CONTROL)) {
+ cmdq_error(item, "not a control client");
+ return (CMD_RETURN_ERROR);
+ }
+ size = args_get(args, 'C');
+ if (sscanf(size, "%u,%u", &x, &y) != 2 &&
+ sscanf(size, "%ux%u", &x, &y) != 2) {
+ cmdq_error(item, "bad size argument");
+ return (CMD_RETURN_ERROR);
+ }
+ if (x < WINDOW_MINIMUM || x > WINDOW_MAXIMUM ||
+ y < WINDOW_MINIMUM || y > WINDOW_MAXIMUM) {
+ cmdq_error(item, "size too small or too big");
+ return (CMD_RETURN_ERROR);
+ }
+ tty_set_size(&c->tty, x, y);
+ c->flags |= CLIENT_SIZECHANGED;
+ recalculate_sizes();
}
- if (!(c->flags & CLIENT_CONTROL)) {
- cmdq_error(item, "not a control client");
- return (CMD_RETURN_ERROR);
+ if (args_has(args, 'F')) {
+ if (!(c->flags & CLIENT_CONTROL)) {
+ cmdq_error(item, "not a control client");
+ return (CMD_RETURN_ERROR);
+ }
+ s = copy = xstrdup(args_get(args, 'F'));
+ while ((next = strsep(&s, ",")) != NULL) {
+ /* Unknown flags are ignored. */
+ if (strcmp(next, "no-output") == 0)
+ c->flags |= CLIENT_CONTROL_NOOUTPUT;
+ }
+ free(copy);
}
- tty_set_size(&c->tty, x, y);
- c->flags |= CLIENT_SIZECHANGED;
- recalculate_sizes();
return (CMD_RETURN_NORMAL);
}
diff --git a/cmd-resize-pane.c b/cmd-resize-pane.c
index c978edfb..8d35d96f 100644
--- a/cmd-resize-pane.c
+++ b/cmd-resize-pane.c
@@ -144,13 +144,13 @@ cmd_resize_pane_mouse_update(struct client *c, struct mouse_event *m)
w = wl->window;
y = m->y + m->oy; x = m->x + m->ox;
- if (m->statusat == 0 && y > 0)
- y--;
+ if (m->statusat == 0 && y >= m->statuslines)
+ y -= m->statuslines;
else if (m->statusat > 0 && y >= (u_int)m->statusat)
y = m->statusat - 1;
ly = m->ly + m->oy; lx = m->lx + m->ox;
- if (m->statusat == 0 && ly > 0)
- ly--;
+ if (m->statusat == 0 && ly >= m->statuslines)
+ ly -= m->statuslines;
else if (m->statusat > 0 && ly >= (u_int)m->statusat)
ly = m->statusat - 1;
diff --git a/cmd-run-shell.c b/cmd-run-shell.c
index c9a478c7..2f45f492 100644
--- a/cmd-run-shell.c
+++ b/cmd-run-shell.c
@@ -155,7 +155,7 @@ cmd_run_shell_callback(struct job *job)
free(msg);
if (cdata->item != NULL)
- cdata->item->flags &= ~CMDQ_WAITING;
+ cmdq_continue(cdata->item);
}
static void
diff --git a/cmd-select-pane.c b/cmd-select-pane.c
index 92ecb734..52c58dbc 100644
--- a/cmd-select-pane.c
+++ b/cmd-select-pane.c
@@ -33,8 +33,8 @@ const struct cmd_entry cmd_select_pane_entry = {
.name = "select-pane",
.alias = "selectp",
- .args = { "DdegLlMmP:RT:t:U", 0, 0 },
- .usage = "[-DdegLlMmRU] [-P style] [-T title] " CMD_TARGET_PANE_USAGE,
+ .args = { "DdegLlMmP:RT:t:U", 0, 0 }, /* -P and -g deprecated */
+ .usage = "[-DdeLlMmRU] [-T title] " CMD_TARGET_PANE_USAGE,
.target = { 't', CMD_FIND_PANE, 0 },
@@ -90,9 +90,10 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
struct window *w = wl->window;
struct session *s = item->target.s;
struct window_pane *wp = item->target.wp, *lastwp, *markedwp;
- struct style *sy = &wp->style;
char *pane_title;
const char *style;
+ struct style *sy;
+ struct options_entry *o;
if (self->entry == &cmd_last_pane_entry || args_has(args, 'l')) {
lastwp = w->last;
@@ -144,15 +145,18 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
if (args_has(self->args, 'P') || args_has(self->args, 'g')) {
if ((style = args_get(args, 'P')) != NULL) {
- style_set(sy, &grid_default_cell);
- if (style_parse(sy, &grid_default_cell, style) == -1) {
+ o = options_set_style(wp->options, "window-style", 0,
+ style);
+ if (o == NULL) {
cmdq_error(item, "bad style: %s", style);
return (CMD_RETURN_ERROR);
}
- wp->flags |= PANE_REDRAW;
+ wp->flags |= (PANE_REDRAW|PANE_STYLECHANGED);
}
- if (args_has(self->args, 'g'))
+ if (args_has(self->args, 'g')) {
+ sy = options_get_style(wp->options, "window-style");
cmdq_print(item, "%s", style_tostring(sy));
+ }
return (CMD_RETURN_NORMAL);
}
diff --git a/cmd-send-keys.c b/cmd-send-keys.c
index fd1c1ab9..fe202335 100644
--- a/cmd-send-keys.c
+++ b/cmd-send-keys.c
@@ -33,8 +33,8 @@ const struct cmd_entry cmd_send_keys_entry = {
.name = "send-keys",
.alias = "send",
- .args = { "lXRMN:t:", 0, -1 },
- .usage = "[-lXRM] [-N repeat-count] " CMD_TARGET_PANE_USAGE " key ...",
+ .args = { "HlXRMN:t:", 0, -1 },
+ .usage = "[-HlXRM] [-N repeat-count] " CMD_TARGET_PANE_USAGE " key ...",
.target = { 't', CMD_FIND_PANE, 0 },
@@ -56,7 +56,7 @@ const struct cmd_entry cmd_send_prefix_entry = {
};
static struct cmdq_item *
-cmd_send_keys_inject(struct client *c, struct cmd_find_state *fs,
+cmd_send_keys_inject_key(struct client *c, struct cmd_find_state *fs,
struct cmdq_item *item, key_code key)
{
struct window_mode_entry *wme;
@@ -81,20 +81,56 @@ cmd_send_keys_inject(struct client *c, struct cmd_find_state *fs,
return (item);
}
+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)
+{
+ const char *s = args->argv[i];
+ struct utf8_data *ud, *uc;
+ wchar_t wc;
+ key_code key;
+ char *endptr;
+ long n;
+ int literal;
+
+ if (args_has(args, 'H')) {
+ 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));
+ }
+
+ literal = args_has(args, 'l');
+ if (!literal) {
+ key = key_string_lookup_string(s);
+ if (key != KEYC_NONE && key != KEYC_UNKNOWN)
+ return (cmd_send_keys_inject_key(c, fs, item, key));
+ literal = 1;
+ }
+ if (literal) {
+ ud = utf8_fromcstr(s);
+ 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);
+ }
+ free(ud);
+ }
+ return (item);
+}
+
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 cmd_find_state *fs = &item->target;
struct window_mode_entry *wme = TAILQ_FIRST(&wp->modes);
- struct utf8_data *ud, *uc;
- wchar_t wc;
- int i, literal;
+ int i;
key_code key;
u_int np = 1;
char *cause = NULL;
@@ -141,7 +177,7 @@ cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
key = options_get_number(s->options, "prefix2");
else
key = options_get_number(s->options, "prefix");
- cmd_send_keys_inject(c, fs, item, key);
+ cmd_send_keys_inject_key(c, fs, item, key);
return (CMD_RETURN_NORMAL);
}
@@ -151,28 +187,8 @@ cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
}
for (; np != 0; np--) {
- for (i = 0; i < args->argc; i++) {
- literal = args_has(args, 'l');
- if (!literal) {
- key = key_string_lookup_string(args->argv[i]);
- if (key != KEYC_NONE && key != KEYC_UNKNOWN) {
- item = cmd_send_keys_inject(c, fs, item,
- key);
- } else
- literal = 1;
- }
- if (literal) {
- ud = utf8_fromcstr(args->argv[i]);
- for (uc = ud; uc->size != 0; uc++) {
- if (utf8_combine(uc, &wc) != UTF8_DONE)
- continue;
- item = cmd_send_keys_inject(c, fs, item,
- wc);
- }
- free(ud);
- }
- }
-
+ for (i = 0; i < args->argc; i++)
+ item = cmd_send_keys_inject_string(c, fs, item, args, i);
}
return (CMD_RETURN_NORMAL);
diff --git a/cmd-set-option.c b/cmd-set-option.c
index 7be561f2..23b45230 100644
--- a/cmd-set-option.c
+++ b/cmd-set-option.c
@@ -43,10 +43,10 @@ const struct cmd_entry cmd_set_option_entry = {
.name = "set-option",
.alias = "set",
- .args = { "aFgoqst:uw", 1, 2 },
- .usage = "[-aFgosquw] [-t target-window] option [value]",
+ .args = { "aFgopqst:uw", 1, 2 },
+ .usage = "[-aFgopqsuw] " CMD_TARGET_PANE_USAGE " option [value]",
- .target = { 't', CMD_FIND_WINDOW, CMD_FIND_CANFAIL },
+ .target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
.flags = CMD_AFTERHOOK,
.exec = cmd_set_option_exec
@@ -88,20 +88,24 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
struct session *s = fs->s;
struct winlink *wl = fs->wl;
struct window *w;
- enum options_table_scope scope;
+ struct window_pane *wp;
struct options *oo;
struct options_entry *parent, *o;
char *name, *argument, *value = NULL, *cause;
- const char *target;
int window, idx, already, error, ambiguous;
+ int scope;
struct style *sy;
+ window = (self->entry == &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);
+ /* If set-hook -R, fire the hook straight away. */
if (self->entry == &cmd_set_hook_entry && args_has(args, 'R')) {
notify_hook(item, argument);
+ free(argument);
return (CMD_RETURN_NORMAL);
}
@@ -123,25 +127,8 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
else
value = xstrdup(args->argv[1]);
- /*
- * Figure out the scope: for user options it comes from the arguments,
- * otherwise from the option name.
- */
- if (*name == '@') {
- window = (self->entry == &cmd_set_window_option_entry);
- scope = options_scope_from_flags(args, window, fs, &oo, &cause);
- } else {
- if (options_get_only(global_options, name) != NULL)
- scope = OPTIONS_TABLE_SERVER;
- else if (options_get_only(global_s_options, name) != NULL)
- scope = OPTIONS_TABLE_SESSION;
- else if (options_get_only(global_w_options, name) != NULL)
- scope = OPTIONS_TABLE_WINDOW;
- else {
- scope = OPTIONS_TABLE_NONE;
- xasprintf(&cause, "unknown option: %s", argument);
- }
- }
+ /* Get the scope and table for the option .*/
+ scope = options_scope_from_name(args, window, name, fs, &oo, &cause);
if (scope == OPTIONS_TABLE_NONE) {
if (args_has(args, 'q'))
goto out;
@@ -149,35 +136,6 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
free(cause);
goto fail;
}
-
- /* Which table should this option go into? */
- if (scope == OPTIONS_TABLE_SERVER)
- oo = global_options;
- else if (scope == OPTIONS_TABLE_SESSION) {
- if (args_has(self->args, 'g'))
- oo = global_s_options;
- else if (s == NULL) {
- target = args_get(args, 't');
- if (target != NULL)
- cmdq_error(item, "no such session: %s", target);
- else
- cmdq_error(item, "no current session");
- goto fail;
- } else
- oo = s->options;
- } else if (scope == OPTIONS_TABLE_WINDOW) {
- if (args_has(self->args, 'g'))
- oo = global_w_options;
- else if (wl == NULL) {
- target = args_get(args, 't');
- if (target != NULL)
- cmdq_error(item, "no such window: %s", target);
- else
- cmdq_error(item, "no current window");
- goto fail;
- } else
- oo = wl->window->options;
- }
o = options_get_only(oo, name);
parent = options_get(oo, name);
@@ -292,8 +250,8 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
alerts_reset_all();
if (strcmp(name, "window-style") == 0 ||
strcmp(name, "window-active-style") == 0) {
- RB_FOREACH(w, windows, &windows)
- w->flags |= WINDOW_STYLECHANGED;
+ RB_FOREACH(wp, window_pane_tree, &all_window_panes)
+ wp->flags |= PANE_STYLECHANGED;
}
if (strcmp(name, "pane-border-status") == 0) {
RB_FOREACH(w, windows, &windows)
diff --git a/cmd-show-options.c b/cmd-show-options.c
index 756f763c..da481139 100644
--- a/cmd-show-options.c
+++ b/cmd-show-options.c
@@ -30,18 +30,18 @@
static enum cmd_retval cmd_show_options_exec(struct cmd *, struct cmdq_item *);
static void cmd_show_options_print(struct cmd *, struct cmdq_item *,
- struct options_entry *, int);
+ struct options_entry *, int, int);
static enum cmd_retval cmd_show_options_all(struct cmd *, struct cmdq_item *,
- struct options *);
+ int, struct options *);
const struct cmd_entry cmd_show_options_entry = {
.name = "show-options",
.alias = "show",
- .args = { "gHqst:vw", 0, 1 },
- .usage = "[-gHqsvw] [-t target-session|target-window] [option]",
+ .args = { "AgHpqst:vw", 0, 1 },
+ .usage = "[-AgHpqsvw] " CMD_TARGET_PANE_USAGE " [option]",
- .target = { 't', CMD_FIND_WINDOW, CMD_FIND_CANFAIL },
+ .target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
.flags = CMD_AFTERHOOK,
.exec = cmd_show_options_exec
@@ -82,13 +82,12 @@ cmd_show_options_exec(struct cmd *self, struct cmdq_item *item)
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
struct options *oo;
- enum options_table_scope scope;
char *argument, *name = NULL, *cause;
- const char *target;
- int window, idx, ambiguous;
+ int window, idx, ambiguous, parent, scope;
struct options_entry *o;
window = (self->entry == &cmd_show_window_options_entry);
+
if (args->argc == 0) {
scope = options_scope_from_flags(args, window, fs, &oo, &cause);
if (scope == OPTIONS_TABLE_NONE) {
@@ -98,7 +97,7 @@ cmd_show_options_exec(struct cmd *self, struct cmdq_item *item)
free(cause);
return (CMD_RETURN_ERROR);
}
- return (cmd_show_options_all(self, item, oo));
+ return (cmd_show_options_all(self, item, scope, oo));
}
argument = format_single(item, args->argv[0], c, s, wl, NULL);
@@ -112,49 +111,7 @@ cmd_show_options_exec(struct cmd *self, struct cmdq_item *item)
cmdq_error(item, "invalid option: %s", argument);
goto fail;
}
- if (*name == '@')
- scope = options_scope_from_flags(args, window, fs, &oo, &cause);
- else {
- if (options_get_only(global_options, name) != NULL)
- scope = OPTIONS_TABLE_SERVER;
- else if (options_get_only(global_s_options, name) != NULL)
- scope = OPTIONS_TABLE_SESSION;
- else if (options_get_only(global_w_options, name) != NULL)
- scope = OPTIONS_TABLE_WINDOW;
- else {
- scope = OPTIONS_TABLE_NONE;
- xasprintf(&cause, "unknown option: %s", argument);
- }
- if (scope == OPTIONS_TABLE_SERVER)
- oo = global_options;
- else if (scope == OPTIONS_TABLE_SESSION) {
- if (args_has(self->args, 'g'))
- oo = global_s_options;
- else if (s == NULL) {
- target = args_get(args, 't');
- if (target != NULL) {
- cmdq_error(item, "no such session: %s",
- target);
- } else
- cmdq_error(item, "no current session");
- goto fail;
- } else
- oo = s->options;
- } else if (scope == OPTIONS_TABLE_WINDOW) {
- if (args_has(self->args, 'g'))
- oo = global_w_options;
- else if (wl == NULL) {
- target = args_get(args, 't');
- if (target != NULL) {
- cmdq_error(item, "no such window: %s",
- target);
- } else
- cmdq_error(item, "no current window");
- goto fail;
- } else
- oo = wl->window->options;
- }
- }
+ scope = options_scope_from_name(args, window, name, fs, &oo, &cause);
if (scope == OPTIONS_TABLE_NONE) {
if (args_has(args, 'q'))
goto fail;
@@ -163,8 +120,13 @@ cmd_show_options_exec(struct cmd *self, struct cmdq_item *item)
goto fail;
}
o = options_get_only(oo, name);
+ if (args_has(args, 'A') && o == NULL) {
+ o = options_get(oo, name);
+ parent = 1;
+ } else
+ parent = 0;
if (o != NULL)
- cmd_show_options_print(self, item, o, idx);
+ cmd_show_options_print(self, item, o, idx, parent);
free(name);
free(argument);
@@ -178,7 +140,7 @@ fail:
static void
cmd_show_options_print(struct cmd *self, struct cmdq_item *item,
- struct options_entry *o, int idx)
+ struct options_entry *o, int idx, int parent)
{
struct options_array_item *a;
const char *name = options_name(o);
@@ -197,7 +159,8 @@ cmd_show_options_print(struct cmd *self, struct cmdq_item *item,
}
while (a != NULL) {
idx = options_array_item_index(a);
- cmd_show_options_print(self, item, o, idx);
+ cmd_show_options_print(self, item, o, idx,
+ parent);
a = options_array_next(a);
}
return;
@@ -209,50 +172,81 @@ cmd_show_options_print(struct cmd *self, struct cmdq_item *item,
cmdq_print(item, "%s", value);
else if (options_isstring(o)) {
escaped = args_escape(value);
- cmdq_print(item, "%s %s", name, escaped);
+ if (parent)
+ cmdq_print(item, "%s* %s", name, escaped);
+ else
+ cmdq_print(item, "%s %s", name, escaped);
free(escaped);
- } else
- cmdq_print(item, "%s %s", name, value);
+ } else {
+ if (parent)
+ cmdq_print(item, "%s* %s", name, value);
+ else
+ cmdq_print(item, "%s %s", name, value);
+ }
free(value);
free(tmp);
}
static enum cmd_retval
-cmd_show_options_all(struct cmd *self, struct cmdq_item *item,
+cmd_show_options_all(struct cmd *self, struct cmdq_item *item, int scope,
struct options *oo)
{
+ const struct options_table_entry *oe;
struct options_entry *o;
struct options_array_item *a;
+ const char *name;
u_int idx;
- const struct options_table_entry *oe;
+ int parent;
o = options_first(oo);
while (o != NULL) {
- oe = options_table_entry(o);
+ if (options_table_entry(o) == NULL)
+ cmd_show_options_print(self, item, o, -1, 0);
+ o = options_next(o);
+ }
+ for (oe = options_table; oe->name != NULL; oe++) {
+ if (~oe->scope & scope)
+ continue;
+
if ((self->entry != &cmd_show_hooks_entry &&
!args_has(self->args, 'H') &&
oe != NULL &&
(oe->flags & OPTIONS_TABLE_IS_HOOK)) ||
(self->entry == &cmd_show_hooks_entry &&
(oe == NULL ||
- (~oe->flags & OPTIONS_TABLE_IS_HOOK)))) {
- o = options_next(o);
+ (~oe->flags & OPTIONS_TABLE_IS_HOOK))))
continue;
- }
+
+ o = options_get_only(oo, oe->name);
+ if (o == NULL) {
+ if (!args_has(self->args, 'A'))
+ continue;
+ o = options_get(oo, oe->name);
+ if (o == NULL)
+ continue;
+ parent = 1;
+ } else
+ parent = 0;
+
if (!options_isarray(o))
- cmd_show_options_print(self, item, o, -1);
+ cmd_show_options_print(self, item, o, -1, parent);
else if ((a = options_array_first(o)) == NULL) {
- if (!args_has(self->args, 'v'))
- cmdq_print(item, "%s", options_name(o));
+ if (!args_has(self->args, 'v')) {
+ name = options_name(o);
+ if (parent)
+ cmdq_print(item, "%s*", name);
+ else
+ cmdq_print(item, "%s", name);
+ }
} else {
while (a != NULL) {
idx = options_array_item_index(a);
- cmd_show_options_print(self, item, o, idx);
+ cmd_show_options_print(self, item, o, idx,
+ parent);
a = options_array_next(a);
}
}
- o = options_next(o);
}
return (CMD_RETURN_NORMAL);
}
diff --git a/cmd-source-file.c b/cmd-source-file.c
index 38aede0c..2e01ae67 100644
--- a/cmd-source-file.c
+++ b/cmd-source-file.c
@@ -37,8 +37,8 @@ const struct cmd_entry cmd_source_file_entry = {
.name = "source-file",
.alias = "source",
- .args = { "nq", 1, -1 },
- .usage = "[-nq] path ...",
+ .args = { "nqv", 1, -1 },
+ .usage = "[-nqv] path ...",
.flags = 0,
.exec = cmd_source_file_exec
@@ -62,6 +62,8 @@ cmd_source_file_exec(struct cmd *self, struct cmdq_item *item)
flags |= CMD_PARSE_QUIET;
if (args_has(args, 'n'))
flags |= CMD_PARSE_PARSEONLY;
+ if (args_has(args, 'v'))
+ flags |= CMD_PARSE_VERBOSE;
utf8_stravis(&cwd, server_client_get_cwd(c, NULL), VIS_GLOB);
retval = CMD_RETURN_NORMAL;
diff --git a/cmd-swap-pane.c b/cmd-swap-pane.c
index 2ad05561..994ad0e8 100644
--- a/cmd-swap-pane.c
+++ b/cmd-swap-pane.c
@@ -90,7 +90,11 @@ cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item)
src_wp->layout_cell = dst_lc;
src_wp->window = dst_w;
+ options_set_parent(src_wp->options, dst_w->options);
+ src_wp->flags |= PANE_STYLECHANGED;
dst_wp->window = src_w;
+ options_set_parent(dst_wp->options, src_w->options);
+ dst_wp->flags |= PANE_STYLECHANGED;
sx = src_wp->sx; sy = src_wp->sy;
xoff = src_wp->xoff; yoff = src_wp->yoff;
diff --git a/cmd-wait-for.c b/cmd-wait-for.c
index 33600eda..4f438a7f 100644
--- a/cmd-wait-for.c
+++ b/cmd-wait-for.c
@@ -153,7 +153,7 @@ cmd_wait_for_signal(__unused struct cmdq_item *item, const char *name,
log_debug("signal wait channel %s, with waiters", wc->name);
TAILQ_FOREACH_SAFE(wi, &wc->waiters, entry, wi1) {
- wi->item->flags &= ~CMDQ_WAITING;
+ cmdq_continue(wi->item);
TAILQ_REMOVE(&wc->waiters, wi, entry);
free(wi);
@@ -229,7 +229,7 @@ cmd_wait_for_unlock(struct cmdq_item *item, const char *name,
}
if ((wi = TAILQ_FIRST(&wc->lockers)) != NULL) {
- wi->item->flags &= ~CMDQ_WAITING;
+ cmdq_continue(wi->item);
TAILQ_REMOVE(&wc->lockers, wi, entry);
free(wi);
} else {
@@ -248,13 +248,13 @@ cmd_wait_for_flush(void)
RB_FOREACH_SAFE(wc, wait_channels, &wait_channels, wc1) {
TAILQ_FOREACH_SAFE(wi, &wc->waiters, entry, wi1) {
- wi->item->flags &= ~CMDQ_WAITING;
+ cmdq_continue(wi->item);
TAILQ_REMOVE(&wc->waiters, wi, entry);
free(wi);
}
wc->woken = 1;
TAILQ_FOREACH_SAFE(wi, &wc->lockers, entry, wi1) {
- wi->item->flags &= ~CMDQ_WAITING;
+ cmdq_continue(wi->item);
TAILQ_REMOVE(&wc->lockers, wi, entry);
free(wi);
}
diff --git a/cmd.c b/cmd.c
index 74d2f5ef..7c9d89c8 100644
--- a/cmd.c
+++ b/cmd.c
@@ -596,8 +596,8 @@ cmd_mouse_at(struct window_pane *wp, struct mouse_event *m, u_int *xp,
}
log_debug("%s: x=%u, y=%u%s", __func__, x, y, last ? " (last)" : "");
- if (m->statusat == 0 && y > 0)
- y--;
+ if (m->statusat == 0 && y >= m->statuslines)
+ y -= m->statuslines;
if (x < wp->xoff || x >= wp->xoff + wp->sx)
return (-1);
diff --git a/colour.c b/colour.c
index eaee6058..c7972878 100644
--- a/colour.c
+++ b/colour.c
@@ -230,11 +230,85 @@ colour_fromstring(const char *s)
return (-1);
}
-/* Convert 256 colour palette to 16. */
-u_char
-colour_256to16(u_char c)
+/* Convert 256 colour to RGB colour. */
+int
+colour_256toRGB(int c)
+{
+ static const int table[256] = {
+ 0x000000, 0x800000, 0x008000, 0x808000,
+ 0x000080, 0x800080, 0x008080, 0xc0c0c0,
+ 0x808080, 0xff0000, 0x00ff00, 0xffff00,
+ 0x0000ff, 0xff00ff, 0x00ffff, 0xffffff,
+ 0x000000, 0x00005f, 0x000087, 0x0000af,
+ 0x0000d7, 0x0000ff, 0x005f00, 0x005f5f,
+ 0x005f87, 0x005faf, 0x005fd7, 0x005fff,
+ 0x008700, 0x00875f, 0x008787, 0x0087af,
+ 0x0087d7, 0x0087ff, 0x00af00, 0x00af5f,
+ 0x00af87, 0x00afaf, 0x00afd7, 0x00afff,
+ 0x00d700, 0x00d75f, 0x00d787, 0x00d7af,
+ 0x00d7d7, 0x00d7ff, 0x00ff00, 0x00ff5f,
+ 0x00ff87, 0x00ffaf, 0x00ffd7, 0x00ffff,
+ 0x5f0000, 0x5f005f, 0x5f0087, 0x5f00af,
+ 0x5f00d7, 0x5f00ff, 0x5f5f00, 0x5f5f5f,
+ 0x5f5f87, 0x5f5faf, 0x5f5fd7, 0x5f5fff,
+ 0x5f8700, 0x5f875f, 0x5f8787, 0x5f87af,
+ 0x5f87d7, 0x5f87ff, 0x5faf00, 0x5faf5f,
+ 0x5faf87, 0x5fafaf, 0x5fafd7, 0x5fafff,
+ 0x5fd700, 0x5fd75f, 0x5fd787, 0x5fd7af,
+ 0x5fd7d7, 0x5fd7ff, 0x5fff00, 0x5fff5f,
+ 0x5fff87, 0x5fffaf, 0x5fffd7, 0x5fffff,
+ 0x870000, 0x87005f, 0x870087, 0x8700af,
+ 0x8700d7, 0x8700ff, 0x875f00, 0x875f5f,
+ 0x875f87, 0x875faf, 0x875fd7, 0x875fff,
+ 0x878700, 0x87875f, 0x878787, 0x8787af,
+ 0x8787d7, 0x8787ff, 0x87af00, 0x87af5f,
+ 0x87af87, 0x87afaf, 0x87afd7, 0x87afff,
+ 0x87d700, 0x87d75f, 0x87d787, 0x87d7af,
+ 0x87d7d7, 0x87d7ff, 0x87ff00, 0x87ff5f,
+ 0x87ff87, 0x87ffaf, 0x87ffd7, 0x87ffff,
+ 0xaf0000, 0xaf005f, 0xaf0087, 0xaf00af,
+ 0xaf00d7, 0xaf00ff, 0xaf5f00, 0xaf5f5f,
+ 0xaf5f87, 0xaf5faf, 0xaf5fd7, 0xaf5fff,
+ 0xaf8700, 0xaf875f, 0xaf8787, 0xaf87af,
+ 0xaf87d7, 0xaf87ff, 0xafaf00, 0xafaf5f,
+ 0xafaf87, 0xafafaf, 0xafafd7, 0xafafff,
+ 0xafd700, 0xafd75f, 0xafd787, 0xafd7af,
+ 0xafd7d7, 0xafd7ff, 0xafff00, 0xafff5f,
+ 0xafff87, 0xafffaf, 0xafffd7, 0xafffff,
+ 0xd70000, 0xd7005f, 0xd70087, 0xd700af,
+ 0xd700d7, 0xd700ff, 0xd75f00, 0xd75f5f,
+ 0xd75f87, 0xd75faf, 0xd75fd7, 0xd75fff,
+ 0xd78700, 0xd7875f, 0xd78787, 0xd787af,
+ 0xd787d7, 0xd787ff, 0xd7af00, 0xd7af5f,
+ 0xd7af87, 0xd7afaf, 0xd7afd7, 0xd7afff,
+ 0xd7d700, 0xd7d75f, 0xd7d787, 0xd7d7af,
+ 0xd7d7d7, 0xd7d7ff, 0xd7ff00, 0xd7ff5f,
+ 0xd7ff87, 0xd7ffaf, 0xd7ffd7, 0xd7ffff,
+ 0xff0000, 0xff005f, 0xff0087, 0xff00af,
+ 0xff00d7, 0xff00ff, 0xff5f00, 0xff5f5f,
+ 0xff5f87, 0xff5faf, 0xff5fd7, 0xff5fff,
+ 0xff8700, 0xff875f, 0xff8787, 0xff87af,
+ 0xff87d7, 0xff87ff, 0xffaf00, 0xffaf5f,
+ 0xffaf87, 0xffafaf, 0xffafd7, 0xffafff,
+ 0xffd700, 0xffd75f, 0xffd787, 0xffd7af,
+ 0xffd7d7, 0xffd7ff, 0xffff00, 0xffff5f,
+ 0xffff87, 0xffffaf, 0xffffd7, 0xffffff,
+ 0x080808, 0x121212, 0x1c1c1c, 0x262626,
+ 0x303030, 0x3a3a3a, 0x444444, 0x4e4e4e,
+ 0x585858, 0x626262, 0x6c6c6c, 0x767676,
+ 0x808080, 0x8a8a8a, 0x949494, 0x9e9e9e,
+ 0xa8a8a8, 0xb2b2b2, 0xbcbcbc, 0xc6c6c6,
+ 0xd0d0d0, 0xdadada, 0xe4e4e4, 0xeeeeee
+ };
+
+ return (table[c & 0xff] | COLOUR_FLAG_RGB);
+}
+
+/* Convert 256 colour to 16 colour. */
+int
+colour_256to16(int c)
{
- static const u_char table[256] = {
+ static const char table[256] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
0, 4, 4, 4, 12, 12, 2, 6, 4, 4, 12, 12, 2, 2, 6, 4,
12, 12, 2, 2, 2, 6, 12, 12, 10, 10, 10, 10, 14, 12, 10, 10,
@@ -253,5 +327,5 @@ colour_256to16(u_char c)
8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 15, 15, 15, 15, 15, 15
};
- return (table[c]);
+ return (table[c & 0xff]);
}
diff --git a/configure.ac b/configure.ac
index 8473a0d2..5fba1eaf 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,6 +1,6 @@
# configure.ac
-AC_INIT([tmux], 3.0-rc3)
+AC_INIT([tmux], next-3.1)
AC_PREREQ([2.60])
AC_CONFIG_AUX_DIR(etc)
diff --git a/control-notify.c b/control-notify.c
index 340dab73..a1e2b7bf 100644
--- a/control-notify.c
+++ b/control-notify.c
@@ -36,6 +36,9 @@ control_notify_input(struct client *c, struct window_pane *wp,
if (c->session == NULL)
return;
+ if (c->flags & CLIENT_CONTROL_NOOUTPUT)
+ return;
+
/*
* Only write input if the window pane is linked to a window belonging
* to the client's session.
diff --git a/control.c b/control.c
index 16fa71bb..c4cf5338 100644
--- a/control.c
+++ b/control.c
@@ -80,6 +80,7 @@ control_callback(struct client *c, int closed, __unused void *data)
if (line == NULL)
break;
if (*line == '\0') { /* empty line exit */
+ free(line);
c->flags |= CLIENT_EXIT;
break;
}
diff --git a/format-draw.c b/format-draw.c
index b589ca5e..e0ca89f0 100644
--- a/format-draw.c
+++ b/format-draw.c
@@ -511,8 +511,9 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base,
u_int ocx = os->cx, ocy = os->cy, i, width[TOTAL];
u_int map[] = { LEFT, LEFT, CENTRE, RIGHT };
int focus_start = -1, focus_end = -1;
- int list_state = -1;
+ int list_state = -1, fill = -1;
enum style_align list_align = STYLE_ALIGN_DEFAULT;
+ struct grid_cell gc;
struct style sy;
struct utf8_data *ud = &sy.gc.data;
const char *cp, *end;
@@ -564,7 +565,7 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base,
cp++;
}
- /* Draw the cell to th current screen. */
+ /* Draw the cell to the current screen. */
screen_write_cell(&ctx[current], &sy.gc);
width[current] += ud->width;
continue;
@@ -590,6 +591,10 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base,
style_tostring(&sy));
free(tmp);
+ /* If this style has a fill colour, store it for later. */
+ if (sy.fill != 8)
+ fill = sy.fill;
+
/* Check the list state. */
switch (sy.list) {
case STYLE_LIST_ON:
@@ -711,6 +716,14 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base,
fr->argument, names[fr->index], fr->start, fr->end);
}
+ /* Clear the available area. */
+ if (fill != -1) {
+ memcpy(&gc, &grid_default_cell, sizeof gc);
+ gc.bg = fill;
+ for (i = 0; i < available; i++)
+ screen_write_putc(octx, &gc, ' ');
+ }
+
/*
* Draw the screens. How they are arranged depends on where the list
* appearsq.
diff --git a/format.c b/format.c
index 3d649a29..eb7a9e53 100644
--- a/format.c
+++ b/format.c
@@ -23,6 +23,7 @@
#include <errno.h>
#include <fnmatch.h>
#include <libgen.h>
+#include <regex.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
@@ -1067,6 +1068,8 @@ format_find(struct format_tree *ft, const char *key, int modifiers)
if (~modifiers & FORMAT_TIMESTRING) {
o = options_parse_get(global_options, key, &idx, 0);
+ if (o == NULL && ft->wp != NULL)
+ o = options_parse_get(ft->wp->options, key, &idx, 0);
if (o == NULL && ft->w != NULL)
o = options_parse_get(ft->w->options, key, &idx, 0);
if (o == NULL)
@@ -1263,7 +1266,7 @@ format_build_modifiers(struct format_tree *ft, const char **s, u_int *count)
cp++;
/* Check single character modifiers with no arguments. */
- if (strchr("lmCbdtqETSWP<>", cp[0]) != NULL &&
+ if (strchr("lbdtqETSWP<>", cp[0]) != NULL &&
format_is_end(cp[1])) {
format_add_modifier(&list, count, cp, 1, NULL, 0);
cp++;
@@ -1284,7 +1287,7 @@ format_build_modifiers(struct format_tree *ft, const char **s, u_int *count)
}
/* Now try single character with arguments. */
- if (strchr("s=", cp[0]) == NULL)
+ if (strchr("mCs=", cp[0]) == NULL)
break;
c = cp[0];
@@ -1345,39 +1348,67 @@ format_build_modifiers(struct format_tree *ft, const char **s, u_int *count)
return list;
}
-/* Perform substitution in string. */
+/* Match against an fnmatch(3) pattern or regular expression. */
static char *
-format_substitute(const char *source, const char *from, const char *to)
+format_match(struct format_modifier *fm, const char *pattern, const char *text)
{
- char *copy, *new;
- const char *cp;
- size_t fromlen, tolen, newlen, used;
-
- fromlen = strlen(from);
- tolen = strlen(to);
-
- newlen = strlen(source) + 1;
- copy = new = xmalloc(newlen);
-
- for (cp = source; *cp != '\0'; /* nothing */) {
- if (strncmp(cp, from, fromlen) != 0) {
- *new++ = *cp++;
- continue;
+ const char *s = "";
+ regex_t r;
+ int flags = 0;
+
+ if (fm->argc >= 1)
+ s = fm->argv[0];
+ if (strchr(s, 'r') == NULL) {
+ if (strchr(s, 'i') != NULL)
+ flags |= FNM_CASEFOLD;
+ if (fnmatch(pattern, text, flags) != 0)
+ return (xstrdup("0"));
+ } else {
+ flags = REG_EXTENDED|REG_NOSUB;
+ if (strchr(s, 'i') != NULL)
+ flags |= REG_ICASE;
+ if (regcomp(&r, pattern, flags) != 0)
+ return (xstrdup("0"));
+ if (regexec(&r, text, 0, NULL, 0) != 0) {
+ regfree(&r);
+ return (xstrdup("0"));
}
- used = new - copy;
-
- newlen += tolen;
- copy = xrealloc(copy, newlen);
+ regfree(&r);
+ }
+ return (xstrdup("1"));
+}
- new = copy + used;
- memcpy(new, to, tolen);
+/* Perform substitution in string. */
+static char *
+format_sub(struct format_modifier *fm, const char *text, const char *pattern,
+ const char *with)
+{
+ char *value;
+ int flags = REG_EXTENDED;
+
+ if (fm->argc >= 3 && strchr(fm->argv[2], 'i') != NULL)
+ flags |= REG_ICASE;
+ value = regsub(pattern, with, text, flags);
+ if (value == NULL)
+ return (xstrdup(text));
+ return (value);
+}
- new += tolen;
- cp += fromlen;
+/* Search inside pane. */
+static char *
+format_search(struct format_modifier *fm, struct window_pane *wp, const char *s)
+{
+ int ignore = 0, regex = 0;
+ char *value;
+
+ if (fm->argc >= 1) {
+ if (strchr(fm->argv[0], 'i') != NULL)
+ ignore = 1;
+ if (strchr(fm->argv[0], 'r') != NULL)
+ regex = 1;
}
-
- *new = '\0';
- return (copy);
+ xasprintf(&value, "%u", window_pane_search(wp, s, regex, ignore));
+ return (value);
}
/* Loop over sessions. */
@@ -1522,11 +1553,10 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
char *copy0, *condition, *found, *new;
char *value, *left, *right;
size_t valuelen;
- int modifiers = 0, limit = 0;
+ int modifiers = 0, limit = 0, j;
struct format_modifier *list, *fm, *cmp = NULL, *search = NULL;
struct format_modifier *sub = NULL;
u_int i, count;
- int j;
/* Make a copy of the key. */
copy = copy0 = xstrndup(key, keylen);
@@ -1553,18 +1583,18 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
search = fm;
break;
case 's':
- if (fm->argc != 2)
+ if (fm->argc < 2)
break;
sub = fm;
break;
case '=':
- if (fm->argc != 1 && fm->argc != 2)
+ if (fm->argc < 1)
break;
limit = strtonum(fm->argv[0], INT_MIN, INT_MAX,
&errptr);
if (errptr != NULL)
limit = 0;
- if (fm->argc == 2 && fm->argv[1] != NULL)
+ if (fm->argc >= 2 && fm->argv[1] != NULL)
marker = fm->argv[1];
break;
case 'l':
@@ -1630,13 +1660,15 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
goto fail;
} else if (search != NULL) {
/* Search in pane. */
+ new = format_expand(ft, copy);
if (wp == NULL) {
- format_log(ft, "search '%s' but no pane", copy);
+ format_log(ft, "search '%s' but no pane", new);
value = xstrdup("0");
} else {
- format_log(ft, "search '%s' pane %%%u", copy, wp->id);
- xasprintf(&value, "%u", window_pane_search(wp, copy));
+ format_log(ft, "search '%s' pane %%%u", new, wp->id);
+ value = format_search(fm, wp, new);
}
+ free(new);
} else if (cmp != NULL) {
/* Comparison of left and right. */
if (format_choose(ft, copy, &left, &right, 1) != 0) {
@@ -1687,12 +1719,8 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
value = xstrdup("1");
else
value = xstrdup("0");
- } else if (strcmp(cmp->modifier, "m") == 0) {
- if (fnmatch(left, right, 0) == 0)
- value = xstrdup("1");
- else
- value = xstrdup("0");
- }
+ } else if (strcmp(cmp->modifier, "m") == 0)
+ value = format_match(cmp, left, right);
free(right);
free(left);
@@ -1770,11 +1798,14 @@ done:
/* Perform substitution if any. */
if (sub != NULL) {
- new = format_substitute(value, sub->argv[0], sub->argv[1]);
- format_log(ft, "substituted '%s' to '%s: %s", sub->argv[0],
- sub->argv[1], new);
+ left = format_expand(ft, sub->argv[0]);
+ right = format_expand(ft, sub->argv[1]);
+ new = format_sub(sub, value, left, right);
+ format_log(ft, "substitute '%s' to '%s': %s", left, right, new);
free(value);
value = new;
+ free(right);
+ free(left);
}
/* Truncate the value if needed. */
@@ -1998,10 +2029,10 @@ void
format_defaults(struct format_tree *ft, struct client *c, struct session *s,
struct winlink *wl, struct window_pane *wp)
{
- if (c != NULL)
+ if (c != NULL && c->name != NULL)
log_debug("%s: c=%s", __func__, c->name);
else
- log_debug("%s: s=none", __func__);
+ log_debug("%s: c=none", __func__);
if (s != NULL)
log_debug("%s: s=$%u", __func__, s->id);
else
@@ -2286,6 +2317,8 @@ format_defaults_pane(struct format_tree *ft, struct window_pane *wp)
!!(wp->base.mode & MODE_KKEYPAD));
format_add(ft, "wrap_flag", "%d",
!!(wp->base.mode & MODE_WRAP));
+ format_add(ft, "origin_flag", "%d",
+ !!(wp->base.mode & MODE_ORIGIN));
format_add(ft, "mouse_any_flag", "%d",
!!(wp->base.mode & ALL_MOUSE_MODES));
@@ -2295,6 +2328,10 @@ format_defaults_pane(struct format_tree *ft, struct window_pane *wp)
!!(wp->base.mode & MODE_MOUSE_BUTTON));
format_add(ft, "mouse_all_flag", "%d",
!!(wp->base.mode & MODE_MOUSE_ALL));
+ format_add(ft, "mouse_utf8_flag", "%d",
+ !!(wp->base.mode & MODE_MOUSE_UTF8));
+ format_add(ft, "mouse_sgr_flag", "%d",
+ !!(wp->base.mode & MODE_MOUSE_SGR));
format_add_cb(ft, "pane_tabs", format_cb_pane_tabs);
}
diff --git a/grid-view.c b/grid-view.c
index a4bd5ba2..fa3bfbf6 100644
--- a/grid-view.c
+++ b/grid-view.c
@@ -214,7 +214,6 @@ grid_view_delete_cells(struct grid *gd, u_int px, u_int py, u_int nx, u_int bg)
sx = grid_view_x(gd, gd->sx);
grid_move_cells(gd, px, px + nx, py, sx - px - nx, bg);
- grid_clear(gd, sx - nx, py, px + nx - (sx - nx), 1, bg);
}
/* Convert cells into a string. */
diff --git a/grid.c b/grid.c
index d185f364..f33eef72 100644
--- a/grid.c
+++ b/grid.c
@@ -37,12 +37,12 @@
/* Default grid cell data. */
const struct grid_cell grid_default_cell = {
- 0, 0, 8, 8, { { ' ' }, 0, 1, 1 }
+ { { ' ' }, 0, 1, 1 }, 0, 0, 8, 8, 0
};
/* Cleared grid cell data. */
const struct grid_cell grid_cleared_cell = {
- GRID_FLAG_CLEARED, 0, 8, 8, { { ' ' }, 0, 1, 1 }
+ { { ' ' }, 0, 1, 1 }, 0, GRID_FLAG_CLEARED, 8, 8, 0
};
static const struct grid_cell_entry grid_cleared_entry = {
GRID_FLAG_CLEARED, { .data = { 0, 8, 8, ' ' } }
@@ -82,6 +82,8 @@ grid_need_extended_cell(const struct grid_cell_entry *gce,
return (1);
if ((gc->fg & COLOUR_FLAG_RGB) || (gc->bg & COLOUR_FLAG_RGB))
return (1);
+ if (gc->us != 0) /* only supports 256 or RGB */
+ return (1);
return (0);
}
@@ -473,6 +475,7 @@ grid_get_cell1(struct grid_line *gl, u_int px, struct grid_cell *gc)
gc->bg = gce->data.bg;
if (gce->flags & GRID_FLAG_BG256)
gc->bg |= COLOUR_FLAG_256;
+ gc->us = 0;
utf8_set(&gc->data, gce->data.data);
}
@@ -544,7 +547,7 @@ void
grid_clear(struct grid *gd, u_int px, u_int py, u_int nx, u_int ny, u_int bg)
{
struct grid_line *gl;
- u_int xx, yy;
+ u_int xx, yy, ox, sx;
if (nx == 0 || ny == 0)
return;
@@ -561,16 +564,20 @@ grid_clear(struct grid *gd, u_int px, u_int py, u_int nx, u_int ny, u_int bg)
for (yy = py; yy < py + ny; yy++) {
gl = &gd->linedata[yy];
- if (px + nx >= gd->sx && px < gl->cellused)
- gl->cellused = px;
- if (px > gl->cellsize && COLOUR_DEFAULT(bg))
- continue;
- if (px + nx >= gl->cellsize && COLOUR_DEFAULT(bg)) {
- gl->cellsize = px;
- continue;
+
+ sx = gd->sx;
+ if (sx > gl->cellsize)
+ sx = gl->cellsize;
+ ox = nx;
+ if (COLOUR_DEFAULT(bg)) {
+ if (px > sx)
+ continue;
+ if (px + nx > sx)
+ ox = sx - px;
}
- grid_expand_line(gd, yy, px + nx, 8); /* default bg first */
- for (xx = px; xx < px + nx; xx++)
+
+ grid_expand_line(gd, yy, px + ox, 8); /* default bg first */
+ for (xx = px; xx < px + ox; xx++)
grid_clear_cell(gd, xx, yy, bg);
}
}
@@ -1213,6 +1220,10 @@ grid_reflow(struct grid *gd, u_int sx)
struct grid_cell gc;
u_int yy, width, i, at, first;
+ /* Do not reflow to the same size. */
+ if (sx == gd->sx)
+ return;
+
/*
* Create a destination grid. This is just used as a container for the
* line data and may not be fully valid.
diff --git a/input-keys.c b/input-keys.c
index f0a38c09..9e47a553 100644
--- a/input-keys.c
+++ b/input-keys.c
@@ -172,6 +172,13 @@ input_key(struct window_pane *wp, key_code key, struct mouse_event *m)
return;
}
+ /* 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);
+ return;
+ }
+
/*
* If this is a normal 7-bit key, just send it, with a leading escape
* if necessary. If it is a UTF-8 key, split it and send it.
diff --git a/input.c b/input.c
index e54b5ac0..ff8d7a17 100644
--- a/input.c
+++ b/input.c
@@ -1829,6 +1829,8 @@ input_csi_dispatch_sgr_256_do(struct input_ctx *ictx, int fgbg, int c)
gc->fg = c | COLOUR_FLAG_256;
else if (fgbg == 48)
gc->bg = c | COLOUR_FLAG_256;
+ else if (fgbg == 58)
+ gc->us = c | COLOUR_FLAG_256;
}
return (1);
}
@@ -1862,6 +1864,8 @@ input_csi_dispatch_sgr_rgb_do(struct input_ctx *ictx, int fgbg, int r, int g,
gc->fg = colour_join_rgb(r, g, b);
else if (fgbg == 48)
gc->bg = colour_join_rgb(r, g, b);
+ else if (fgbg == 58)
+ gc->us = colour_join_rgb(r, g, b);
return (1);
}
@@ -1938,7 +1942,7 @@ input_csi_dispatch_sgr_colon(struct input_ctx *ictx, u_int i)
}
return;
}
- if (n < 2 || (p[0] != 38 && p[0] != 48))
+ if (n < 2 || (p[0] != 38 && p[0] != 48 && p[0] != 58))
return;
switch (p[1]) {
case 2:
@@ -1983,7 +1987,7 @@ input_csi_dispatch_sgr(struct input_ctx *ictx)
if (n == -1)
continue;
- if (n == 38 || n == 48) {
+ if (n == 38 || n == 48 || n == 58) {
i++;
switch (input_get(ictx, i, 0, -1)) {
case 2:
@@ -2078,6 +2082,9 @@ input_csi_dispatch_sgr(struct input_ctx *ictx)
case 55:
gc->attr &= ~GRID_ATTR_OVERLINE;
break;
+ case 59:
+ gc->us = 0;
+ break;
case 90:
case 91:
case 92:
@@ -2259,7 +2266,7 @@ input_exit_rename(struct input_ctx *ictx)
{
if (ictx->flags & INPUT_DISCARD)
return;
- if (!options_get_number(ictx->wp->window->options, "allow-rename"))
+ if (!options_get_number(ictx->wp->options, "allow-rename"))
return;
log_debug("%s: \"%s\"", __func__, ictx->input_buf);
@@ -2347,12 +2354,14 @@ 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 (sscanf(p, "rgb:%2x/%2x/%2x", &r, &g, &b) != 3)
goto bad;
-
- wp->style.gc.fg = colour_join_rgb(r, g, b);
- wp->flags |= PANE_REDRAW;
+ 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->flags |= (PANE_REDRAW|PANE_STYLECHANGED);
return;
@@ -2366,12 +2375,14 @@ 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 (sscanf(p, "rgb:%2x/%2x/%2x", &r, &g, &b) != 3)
goto bad;
-
- wp->style.gc.bg = colour_join_rgb(r, g, b);
- wp->flags |= PANE_REDRAW;
+ 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->flags |= (PANE_REDRAW|PANE_STYLECHANGED);
return;
diff --git a/job.c b/job.c
index dac38ed9..10883e8e 100644
--- a/job.c
+++ b/job.c
@@ -117,7 +117,7 @@ job_run(const char *cmd, struct session *s, const char *cwd,
close(out[0]);
nullfd = open(_PATH_DEVNULL, O_RDWR, 0);
- if (nullfd < 0)
+ if (nullfd == -1)
fatal("open failed");
if (dup2(nullfd, STDERR_FILENO) == -1)
fatal("dup2 failed");
diff --git a/key-string.c b/key-string.c
index 8442727d..a1ef4f51 100644
--- a/key-string.c
+++ b/key-string.c
@@ -284,6 +284,12 @@ key_string_lookup_key(key_code key)
return (out);
}
+ /* Literal keys are themselves. */
+ if (key & KEYC_LITERAL) {
+ snprintf(out, sizeof out, "%c", (int)(key & 0xff));
+ return (out);
+ }
+
/*
* Special case: display C-@ as C-Space. Could do this below in
* the (key >= 0 && key <= 32), but this way we let it be found
diff --git a/layout-custom.c b/layout-custom.c
index 9886afe1..d759c206 100644
--- a/layout-custom.c
+++ b/layout-custom.c
@@ -122,7 +122,7 @@ layout_parse(struct window *w, const char *layout)
{
struct layout_cell *lc, *lcchild;
struct window_pane *wp;
- u_int npanes, ncells, sx, sy;
+ u_int npanes, ncells;
u_short csum;
/* Check validity. */
@@ -153,8 +153,7 @@ layout_parse(struct window *w, const char *layout)
layout_destroy_cell(w, lcchild, &lc);
}
- /* Save the old window size and resize to the layout size. */
- sx = w->sx; sy = w->sy;
+ /* Resize to the layout size. */
window_resize(w, lc->sx, lc->sy);
/* Destroy the old layout and swap to the new. */
@@ -166,12 +165,9 @@ layout_parse(struct window *w, const char *layout)
layout_assign(&wp, lc);
/* Update pane offsets and sizes. */
- layout_fix_offsets(lc);
+ layout_fix_offsets(w);
layout_fix_panes(w);
-
- /* Then resize the layout back to the original window size. */
- layout_resize(w, sx, sy);
- window_resize(w, sx, sy);
+ recalculate_sizes();
layout_print_cell(lc, __func__, 0);
diff --git a/layout-set.c b/layout-set.c
index 12b4780f..82247149 100644
--- a/layout-set.c
+++ b/layout-set.c
@@ -158,7 +158,7 @@ layout_set_even(struct window *w, enum layout_type type)
layout_spread_cell(w, lc);
/* Fix cell offsets. */
- layout_fix_offsets(lc);
+ layout_fix_offsets(w);
layout_fix_panes(w);
layout_print_cell(w->layout_root, __func__, 1);
@@ -257,7 +257,7 @@ layout_set_main_h(struct window *w)
}
/* Fix cell offsets. */
- layout_fix_offsets(lc);
+ layout_fix_offsets(w);
layout_fix_panes(w);
layout_print_cell(w->layout_root, __func__, 1);
@@ -344,7 +344,7 @@ layout_set_main_v(struct window *w)
}
/* Fix cell offsets. */
- layout_fix_offsets(lc);
+ layout_fix_offsets(w);
layout_fix_panes(w);
layout_print_cell(w->layout_root, __func__, 1);
@@ -453,7 +453,7 @@ layout_set_tiled(struct window *w)
}
/* Fix cell offsets. */
- layout_fix_offsets(lc);
+ layout_fix_offsets(w);
layout_fix_panes(w);
layout_print_cell(w->layout_root, __func__, 1);
diff --git a/layout.c b/layout.c
index 86d307ef..37214d02 100644
--- a/layout.c
+++ b/layout.c
@@ -39,7 +39,6 @@ static int layout_resize_pane_grow(struct window *, struct layout_cell *,
enum layout_type, int, int);
static int layout_resize_pane_shrink(struct window *, struct layout_cell *,
enum layout_type, int);
-static int layout_need_status(struct layout_cell *, int);
static u_int layout_new_pane_size(struct window *, u_int,
struct layout_cell *, enum layout_type, u_int, u_int,
u_int);
@@ -199,9 +198,9 @@ layout_make_node(struct layout_cell *lc, enum layout_type type)
lc->wp = NULL;
}
-/* Fix cell offsets based on their sizes. */
-void
-layout_fix_offsets(struct layout_cell *lc)
+/* Fix cell offsets for a child cell. */
+static void
+layout_fix_offsets1(struct layout_cell *lc)
{
struct layout_cell *lcchild;
u_int xoff, yoff;
@@ -212,7 +211,7 @@ layout_fix_offsets(struct layout_cell *lc)
lcchild->xoff = xoff;
lcchild->yoff = lc->yoff;
if (lcchild->type != LAYOUT_WINDOWPANE)
- layout_fix_offsets(lcchild);
+ layout_fix_offsets1(lcchild);
xoff += lcchild->sx + 1;
}
} else {
@@ -221,61 +220,92 @@ layout_fix_offsets(struct layout_cell *lc)
lcchild->xoff = lc->xoff;
lcchild->yoff = yoff;
if (lcchild->type != LAYOUT_WINDOWPANE)
- layout_fix_offsets(lcchild);
+ layout_fix_offsets1(lcchild);
yoff += lcchild->sy + 1;
}
}
}
-/*
- * Returns 1 if we need to reserve space for the pane status line. This is the
- * case for the most upper panes only.
- */
+/* Update cell offsets based on their sizes. */
+void
+layout_fix_offsets(struct window *w)
+{
+ struct layout_cell *lc = w->layout_root;
+
+ lc->xoff = 0;
+ lc->yoff = 0;
+
+ layout_fix_offsets1(lc);
+}
+
+/* Is this a top cell? */
static int
-layout_need_status(struct layout_cell *lc, int at_top)
+layout_cell_is_top(struct window *w, struct layout_cell *lc)
{
- struct layout_cell *first_lc;
+ struct layout_cell *next;
- if (lc->parent != NULL) {
- if (lc->parent->type == LAYOUT_LEFTRIGHT)
- return (layout_need_status(lc->parent, at_top));
+ while (lc != w->layout_root) {
+ next = lc->parent;
+ if (next->type == LAYOUT_TOPBOTTOM &&
+ lc != TAILQ_FIRST(&next->cells))
+ return (0);
+ lc = next;
+ }
+ return (1);
+}
- if (at_top)
- first_lc = TAILQ_FIRST(&lc->parent->cells);
- else
- first_lc = TAILQ_LAST(&lc->parent->cells,layout_cells);
- if (lc == first_lc)
- return (layout_need_status(lc->parent, at_top));
- return (0);
+/* Is this a bottom cell? */
+static int
+layout_cell_is_bottom(struct window *w, struct layout_cell *lc)
+{
+ struct layout_cell *next;
+
+ while (lc != w->layout_root) {
+ next = lc->parent;
+ if (next->type == LAYOUT_TOPBOTTOM &&
+ lc != TAILQ_LAST(&next->cells, layout_cells))
+ return (0);
+ lc = next;
}
return (1);
}
+/*
+ * Returns 1 if we need to add an extra line for the pane status line. This is
+ * the case for the most upper or lower panes only.
+ */
+static int
+layout_add_border(struct window *w, struct layout_cell *lc, int status)
+{
+ if (status == PANE_STATUS_TOP)
+ return (layout_cell_is_top(w, lc));
+ if (status == PANE_STATUS_BOTTOM)
+ return (layout_cell_is_bottom(w, lc));
+ return (0);
+}
+
/* Update pane offsets and sizes based on their cells. */
void
layout_fix_panes(struct window *w)
{
struct window_pane *wp;
struct layout_cell *lc;
- int shift, status;
+ int status;
status = options_get_number(w->options, "pane-border-status");
TAILQ_FOREACH(wp, &w->panes, entry) {
if ((lc = wp->layout_cell) == NULL)
continue;
- if (status != 0)
- shift = layout_need_status(lc, status == 1);
- else
- shift = 0;
-
wp->xoff = lc->xoff;
wp->yoff = lc->yoff;
- if (shift && status == 1)
- wp->yoff += 1;
-
- window_pane_resize(wp, lc->sx, lc->sy - shift);
+ if (layout_add_border(w, lc, status)) {
+ if (status == PANE_STATUS_TOP)
+ wp->yoff++;
+ window_pane_resize(wp, lc->sx, lc->sy - 1);
+ } else
+ window_pane_resize(wp, lc->sx, lc->sy);
}
}
@@ -312,13 +342,15 @@ layout_resize_check(struct window *w, struct layout_cell *lc,
status = options_get_number(w->options, "pane-border-status");
if (lc->type == LAYOUT_WINDOWPANE) {
/* Space available in this cell only. */
- minimum = PANE_MINIMUM;
- if (type == LAYOUT_LEFTRIGHT)
+ if (type == LAYOUT_LEFTRIGHT) {
available = lc->sx;
- else {
+ minimum = PANE_MINIMUM;
+ } else {
available = lc->sy;
- if (status != 0)
- minimum += layout_need_status(lc, status == 1);
+ if (layout_add_border(w, lc, status))
+ minimum = PANE_MINIMUM + 1;
+ else
+ minimum = PANE_MINIMUM;
}
if (available > minimum)
available -= minimum;
@@ -507,7 +539,7 @@ layout_resize(struct window *w, u_int sx, u_int sy)
layout_resize_adjust(w, lc, LAYOUT_TOPBOTTOM, ychange);
/* Fix cell offsets. */
- layout_fix_offsets(lc);
+ layout_fix_offsets(w);
layout_fix_panes(w);
}
@@ -567,7 +599,7 @@ layout_resize_layout(struct window *w, struct layout_cell *lc,
}
/* Fix cell offsets. */
- layout_fix_offsets(w->layout_root);
+ layout_fix_offsets(w);
layout_fix_panes(w);
notify_window("window-layout-changed", w);
}
@@ -861,9 +893,10 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size,
return (NULL);
break;
case LAYOUT_TOPBOTTOM:
- minimum = PANE_MINIMUM * 2 + 1;
- if (status != 0)
- minimum += layout_need_status(lc, status == 1);
+ if (layout_add_border(wp->window, lc, status))
+ minimum = PANE_MINIMUM * 2 + 2;
+ else
+ minimum = PANE_MINIMUM * 2 + 1;
if (sy < minimum)
return (NULL);
break;
@@ -988,7 +1021,7 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size,
if (full_size) {
if (!resize_first)
layout_resize_child_cells(wp->window, lc);
- layout_fix_offsets(wp->window->layout_root);
+ layout_fix_offsets(wp->window);
} else
layout_make_leaf(lc, wp);
@@ -1006,7 +1039,7 @@ layout_close_pane(struct window_pane *wp)
/* Fix pane offsets and sizes. */
if (w->layout_root != NULL) {
- layout_fix_offsets(w->layout_root);
+ layout_fix_offsets(w);
layout_fix_panes(w);
}
notify_window("window-layout-changed", w);
@@ -1021,7 +1054,7 @@ layout_spread_cell(struct window *w, struct layout_cell *parent)
number = 0;
TAILQ_FOREACH (lc, &parent->cells, entry)
- number++;
+ number++;
if (number <= 1)
return (0);
status = options_get_number(w->options, "pane-border-status");
@@ -1029,9 +1062,10 @@ layout_spread_cell(struct window *w, struct layout_cell *parent)
if (parent->type == LAYOUT_LEFTRIGHT)
size = parent->sx;
else if (parent->type == LAYOUT_TOPBOTTOM) {
- size = parent->sy;
- if (status != 0)
- size -= layout_need_status(parent, status == 1);
+ if (layout_add_border(w, parent, status))
+ size = parent->sy - 1;
+ else
+ size = parent->sy;
} else
return (0);
if (size < number - 1)
@@ -1049,9 +1083,10 @@ layout_spread_cell(struct window *w, struct layout_cell *parent)
change = each - (int)lc->sx;
layout_resize_adjust(w, lc, LAYOUT_LEFTRIGHT, change);
} else if (parent->type == LAYOUT_TOPBOTTOM) {
- this = each;
- if (status != 0)
- this += layout_need_status(lc, status == 1);
+ if (layout_add_border(w, lc, status))
+ this = each + 1;
+ else
+ this = each;
change = this - (int)lc->sy;
layout_resize_adjust(w, lc, LAYOUT_TOPBOTTOM, change);
}
@@ -1073,7 +1108,7 @@ layout_spread_out(struct window_pane *wp)
do {
if (layout_spread_cell(w, parent)) {
- layout_fix_offsets(parent);
+ layout_fix_offsets(w);
layout_fix_panes(w);
break;
}
diff --git a/menu.c b/menu.c
index fd35399b..da8d89c4 100644
--- a/menu.c
+++ b/menu.c
@@ -161,7 +161,7 @@ menu_free_cb(struct client *c)
struct menu_data *md = c->overlay_data;
if (md->item != NULL)
- md->item->flags &= ~CMDQ_WAITING;
+ cmdq_continue(md->item);
if (md->cb != NULL)
md->cb(md->menu, UINT_MAX, KEYC_NONE, md->data);
@@ -206,8 +206,18 @@ menu_key_cb(struct client *c, struct key_event *event)
c->flags |= CLIENT_REDRAWOVERLAY;
return (0);
}
+ for (i = 0; i < (u_int)count; i++) {
+ name = menu->items[i].name;
+ if (name == NULL || *name == '-')
+ continue;
+ if (event->key == menu->items[i].key) {
+ md->choice = i;
+ goto chosen;
+ }
+ }
switch (event->key) {
case KEYC_UP:
+ case 'k':
if (old == -1)
old = 0;
do {
@@ -220,6 +230,7 @@ menu_key_cb(struct client *c, struct key_event *event)
c->flags |= CLIENT_REDRAWOVERLAY;
return (0);
case KEYC_DOWN:
+ case 'j':
if (old == -1)
old = 0;
do {
@@ -239,15 +250,6 @@ menu_key_cb(struct client *c, struct key_event *event)
case 'q':
return (1);
}
- for (i = 0; i < (u_int)count; i++) {
- name = menu->items[i].name;
- if (name == NULL || *name == '-')
- continue;
- if (event->key == menu->items[i].key) {
- md->choice = i;
- goto chosen;
- }
- }
return (0);
chosen:
diff --git a/mode-tree.c b/mode-tree.c
index 75034675..03a91ef8 100644
--- a/mode-tree.c
+++ b/mode-tree.c
@@ -480,7 +480,7 @@ mode_tree_add(struct mode_tree_data *mtd, struct mode_tree_item *parent,
saved = mode_tree_find_item(&mtd->saved, tag);
if (saved != NULL) {
- if (parent == NULL || (parent != NULL && parent->expanded))
+ if (parent == NULL || parent->expanded)
mti->tagged = saved->tagged;
mti->expanded = saved->expanded;
} else if (expanded == -1)
@@ -933,6 +933,7 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key,
case '\016': /* C-n */
mode_tree_down(mtd, 1);
break;
+ case 'g':
case KEYC_PPAGE:
case '\002': /* C-b */
for (i = 0; i < mtd->height; i++) {
@@ -941,6 +942,7 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key,
mode_tree_up(mtd, 1);
}
break;
+ case 'G':
case KEYC_NPAGE:
case '\006': /* C-f */
for (i = 0; i < mtd->height; i++) {
@@ -1019,6 +1021,8 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key,
mode_tree_build(mtd);
}
break;
+ case '?':
+ case '/':
case '\023': /* C-s */
mtd->references++;
status_prompt_set(c, "(search) ", "",
diff --git a/options-table.c b/options-table.c
index cb258014..ba7db3e1 100644
--- a/options-table.c
+++ b/options-table.c
@@ -562,13 +562,13 @@ const struct options_table_entry options_table[] = {
{ .name = "allow-rename",
.type = OPTIONS_TABLE_FLAG,
- .scope = OPTIONS_TABLE_WINDOW,
+ .scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE,
.default_num = 0
},
{ .name = "alternate-screen",
.type = OPTIONS_TABLE_FLAG,
- .scope = OPTIONS_TABLE_WINDOW,
+ .scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE,
.default_num = 1
},
@@ -688,7 +688,7 @@ const struct options_table_entry options_table[] = {
.type = OPTIONS_TABLE_CHOICE,
.scope = OPTIONS_TABLE_WINDOW,
.choices = options_table_pane_status_list,
- .default_num = 0
+ .default_num = PANE_STATUS_OFF
},
{ .name = "pane-border-style",
@@ -699,7 +699,7 @@ const struct options_table_entry options_table[] = {
{ .name = "remain-on-exit",
.type = OPTIONS_TABLE_FLAG,
- .scope = OPTIONS_TABLE_WINDOW,
+ .scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE,
.default_num = 0
},
@@ -711,7 +711,7 @@ const struct options_table_entry options_table[] = {
{ .name = "window-active-style",
.type = OPTIONS_TABLE_STYLE,
- .scope = OPTIONS_TABLE_WINDOW,
+ .scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE,
.default_str = "default"
},
@@ -724,7 +724,7 @@ const struct options_table_entry options_table[] = {
{ .name = "window-style",
.type = OPTIONS_TABLE_STYLE,
- .scope = OPTIONS_TABLE_WINDOW,
+ .scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE,
.default_str = "default"
},
diff --git a/options.c b/options.c
index 26ce3b6f..1be9f8cd 100644
--- a/options.c
+++ b/options.c
@@ -100,7 +100,7 @@ options_parent_table_entry(struct options *oo, const char *s)
if (oo->parent == NULL)
fatalx("no parent options for %s", s);
- o = options_get_only(oo->parent, s);
+ o = options_get(oo->parent, s);
if (o == NULL)
fatalx("%s not in parent options", s);
return (o->tableentry);
@@ -178,6 +178,12 @@ options_free(struct options *oo)
free(oo);
}
+void
+options_set_parent(struct options *oo, struct options *parent)
+{
+ oo->parent = parent;
+}
+
struct options_entry *
options_first(struct options *oo)
{
@@ -365,7 +371,8 @@ options_array_set(struct options_entry *o, u_int idx, const char *value,
pr = cmd_parse_from_string(value, NULL);
switch (pr->status) {
case CMD_PARSE_EMPTY:
- *cause = xstrdup("empty command");
+ if (cause != NULL)
+ *cause = xstrdup("empty command");
return (-1);
case CMD_PARSE_ERROR:
if (cause != NULL)
@@ -544,7 +551,7 @@ options_parse_get(struct options *oo, const char *s, int *idx, int only)
}
char *
-options_match(const char *s, int *idx, int* ambiguous)
+options_match(const char *s, int *idx, int *ambiguous)
{
const struct options_table_entry *oe, *found;
char *name;
@@ -724,20 +731,102 @@ options_set_style(struct options *oo, const char *name, int append,
return (o);
}
-enum options_table_scope
+int
+options_scope_from_name(struct args *args, int window,
+ const char *name, struct cmd_find_state *fs, struct options **oo,
+ char **cause)
+{
+ struct session *s = fs->s;
+ struct winlink *wl = fs->wl;
+ struct window_pane *wp = fs->wp;
+ const char *target = args_get(args, 't');
+ const struct options_table_entry *oe;
+ int scope = OPTIONS_TABLE_NONE;
+
+ if (*name == '@')
+ return (options_scope_from_flags(args, window, fs, oo, cause));
+
+ for (oe = options_table; oe->name != NULL; oe++) {
+ if (strcmp(oe->name, name) == 0)
+ break;
+ }
+ if (oe->name == NULL) {
+ xasprintf(cause, "unknown option: %s", name);
+ return (OPTIONS_TABLE_NONE);
+ }
+ switch (oe->scope) {
+ case OPTIONS_TABLE_SERVER:
+ *oo = global_options;
+ scope = OPTIONS_TABLE_SERVER;
+ break;
+ case OPTIONS_TABLE_SESSION:
+ if (args_has(args, 'g')) {
+ *oo = global_s_options;
+ scope = OPTIONS_TABLE_SESSION;
+ } else if (s == NULL && target != NULL)
+ xasprintf(cause, "no such session: %s", target);
+ else if (s == NULL)
+ xasprintf(cause, "no current session");
+ else {
+ *oo = s->options;
+ scope = OPTIONS_TABLE_SESSION;
+ }
+ break;
+ case OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE:
+ if (args_has(args, 'p')) {
+ if (wp == NULL && target != NULL)
+ xasprintf(cause, "no such pane: %s", target);
+ else if (wp == NULL)
+ xasprintf(cause, "no current pane");
+ else {
+ *oo = wp->options;
+ scope = OPTIONS_TABLE_PANE;
+ }
+ break;
+ }
+ /* FALLTHROUGH */
+ case OPTIONS_TABLE_WINDOW:
+ if (args_has(args, 'g')) {
+ *oo = global_w_options;
+ scope = OPTIONS_TABLE_WINDOW;
+ } else if (wl == NULL && target != NULL)
+ xasprintf(cause, "no such window: %s", target);
+ else if (wl == NULL)
+ xasprintf(cause, "no current window");
+ else {
+ *oo = wl->window->options;
+ scope = OPTIONS_TABLE_WINDOW;
+ }
+ break;
+ }
+ return (scope);
+}
+
+int
options_scope_from_flags(struct args *args, int window,
struct cmd_find_state *fs, struct options **oo, char **cause)
{
- struct session *s = fs->s;
- struct winlink *wl = fs->wl;
- const char *target= args_get(args, 't');
+ struct session *s = fs->s;
+ struct winlink *wl = fs->wl;
+ struct window_pane *wp = fs->wp;
+ const char *target = args_get(args, 't');
if (args_has(args, 's')) {
*oo = global_options;
return (OPTIONS_TABLE_SERVER);
}
- if (window || args_has(args, 'w')) {
+ if (args_has(args, 'p')) {
+ if (wp == NULL) {
+ if (target != NULL)
+ xasprintf(cause, "no such pane: %s", target);
+ else
+ xasprintf(cause, "no current pane");
+ return (OPTIONS_TABLE_NONE);
+ }
+ *oo = wp->options;
+ return (OPTIONS_TABLE_PANE);
+ } else if (window || args_has(args, 'w')) {
if (args_has(args, 'g')) {
*oo = global_w_options;
return (OPTIONS_TABLE_WINDOW);
diff --git a/osdep-netbsd.c b/osdep-netbsd.c
index daca1abb..67894175 100644
--- a/osdep-netbsd.c
+++ b/osdep-netbsd.c
@@ -133,13 +133,27 @@ char *
osdep_get_cwd(int fd)
{
static char target[PATH_MAX + 1];
- char *path;
pid_t pgrp;
+#ifdef KERN_PROC_CWD
+ int mib[4];
+ size_t len;
+#else
+ char *path;
ssize_t n;
+#endif
if ((pgrp = tcgetpgrp(fd)) == -1)
return (NULL);
+#ifdef KERN_PROC_CWD
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC_ARGS;
+ mib[2] = pgrp;
+ mib[3] = KERN_PROC_CWD;
+ len = sizeof(target);
+ if (sysctl(mib, __arraycount(mib), target, &len, NULL, 0) == 0)
+ return (target);
+#else
xasprintf(&path, "/proc/%lld/cwd", (long long) pgrp);
n = readlink(path, target, sizeof(target) - 1);
free(path);
@@ -147,6 +161,7 @@ osdep_get_cwd(int fd)
target[n] = '\0';
return (target);
}
+#endif
return (NULL);
}
diff --git a/regress/command-order.sh b/regress/command-order.sh
index fb4e0324..04046f0d 100644
--- a/regress/command-order.sh
+++ b/regress/command-order.sh
@@ -1,7 +1,5 @@
#!/bin/sh
-# new-session without clients should be the right size
-
PATH=/bin:/usr/bin
TERM=screen
@@ -19,6 +17,7 @@ EOF
$TMUX -f$TMP start </dev/null || exit 1
sleep 1
$TMUX lsw -aF '#{session_name},#{window_name}'|sort >$TMP || exit 1
+$TMUX kill-server 2>/dev/null
cat <<EOF|cmp -s $TMP - || exit 1
bar,bar0
bar,bar1
@@ -27,7 +26,6 @@ foo,foo0
foo,foo1
foo,foo2
EOF
-$TMUX kill-server 2>/dev/null
cat <<EOF >$TMP
new -sfoo -nfoo0
@@ -40,6 +38,7 @@ EOF
$TMUX -f$TMP start </dev/null || exit 1
sleep 1
$TMUX lsw -aF '#{session_name},#{window_name}'|sort >$TMP || exit 1
+$TMUX kill-server 2>/dev/null
cat <<EOF|cmp -s $TMP - || exit 1
bar,bar0
bar,bar1
@@ -48,6 +47,5 @@ foo,foo0
foo,foo1
foo,foo2
EOF
-$TMUX kill-server 2>/dev/null
exit 0
diff --git a/regress/conf/21867280ff7e99631046f9cc669b80d2.conf b/regress/conf/21867280ff7e99631046f9cc669b80d2.conf
new file mode 100644
index 00000000..43b142b4
--- /dev/null
+++ b/regress/conf/21867280ff7e99631046f9cc669b80d2.conf
@@ -0,0 +1,8 @@
+%if #{l:1}
+set -g status-style fg=cyan,bg='#001040'
+%elif #{l:1}
+set -g status-style fg=white,bg='#400040'
+%else
+set -g status-style fg=white,bg='#800000'
+%endif
+bind ^X last-window
diff --git a/regress/conf/99749670b62bcb99a9b2e3d59708e357.conf b/regress/conf/99749670b62bcb99a9b2e3d59708e357.conf
new file mode 100644
index 00000000..dd1700b0
--- /dev/null
+++ b/regress/conf/99749670b62bcb99a9b2e3d59708e357.conf
@@ -0,0 +1,93 @@
+# -----------------------------------------------------------------------------
+# This config is targeted for tmux 2.1+ and should be placed in $HOME.
+#
+# Read the "Plugin Manager" section (bottom) before trying to use this config!
+# -----------------------------------------------------------------------------
+
+# -----------------------------------------------------------------------------
+# Global options
+# -----------------------------------------------------------------------------
+
+# Set a new prefix / leader key.
+set -g prefix `
+bind ` send-prefix
+
+# Allow opening multiple terminals to view the same session at different sizes.
+setw -g aggressive-resize on
+
+# Remove delay when switching between Vim modes.
+set -s escape-time 0
+
+# Allow Vim's FocusGained to work when your terminal gains focus.
+# Requires Vim plugin: https://github.com/tmux-plugins/vim-tmux-focus-events
+set -g focus-events on
+
+# Add a bit more scroll history in the buffer.
+set -g history-limit 50000
+
+# Enable color support inside of tmux.
+set -g default-terminal "screen-256color"
+
+# Ensure window titles get renamed automatically.
+setw -g automatic-rename
+
+# Start windows and panes index at 1, not 0.
+set -g base-index 1
+setw -g pane-base-index 1
+
+# Enable full mouse support.
+set -g mouse on
+
+# Status bar optimized for Gruvbox.
+set -g status-fg colour244
+set -g status-bg default
+set -g status-left ''
+set -g status-right-length 0
+#set -g status-right-length 20
+#set -g status-right '%a %Y-%m-%d %H:%M'
+
+set -g pane-border-fg default
+set -g pane-border-bg default
+set -g pane-active-border-fg colour250
+set -g pane-active-border-bg default
+
+set-window-option -g window-status-current-attr bold
+set-window-option -g window-status-current-fg colour223
+
+# -----------------------------------------------------------------------------
+# Key bindings
+# -----------------------------------------------------------------------------
+
+# Unbind default keys
+unbind C-b
+unbind '"'
+unbind %
+
+# Reload the tmux config.
+bind-key r source-file ~/.tmux.conf
+
+# Split panes.
+bind-key h split-window -v
+bind-key v split-window -h
+
+# Move around panes with ALT + arrow keys.
+bind-key -n M-Up select-pane -U
+bind-key -n M-Left select-pane -L
+bind-key -n M-Down select-pane -D
+bind-key -n M-Right select-pane -R
+
+# -----------------------------------------------------------------------------
+# Plugin Manager - https://github.com/tmux-plugins/tpm
+# In order to use the plugins below you need to install TPM and the plugins.
+# Step 1) git clone https://github.com/tmux-plugins/tpm ~/.tmux/plugins/tpm
+# Step 2) Reload tmux if it's already started with `r
+# Step 3) Launch tmux and hit `I (capital i) to fetch any plugins
+# -----------------------------------------------------------------------------
+
+# List of plugins.
+set -g @plugin 'tmux-plugins/tpm'
+set -g @plugin 'tmux-plugins/tmux-resurrect'
+set -g @plugin 'tmux-plugins/tmux-yank'
+
+# Initialize TPM (keep this line at the very bottom of your tmux.conf).
+run -b '~/.tmux/plugins/tpm/tpm'
diff --git a/regress/xenl-terminal.sh b/regress/xenl-terminal.sh
new file mode 100644
index 00000000..07469ceb
--- /dev/null
+++ b/regress/xenl-terminal.sh
@@ -0,0 +1,29 @@
+#!/bin/sh
+
+PATH=/bin:/usr/bin
+TERM=screen
+
+[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
+TMUX="$TEST_TMUX -Ltest"
+$TMUX kill-server 2>/dev/null
+TMUX2="$TEST_TMUX -Ltest2"
+$TMUX2 kill-server 2>/dev/null
+
+TMP=$(mktemp)
+trap "rm -f $TMP" 0 1 15
+
+$TMUX2 -f/dev/null new -d || exit 1
+$TMUX2 set -as terminal-overrides ',*:xenl@' || exit 1
+$TMUX2 set -g status-right 'RRR' || exit 1
+$TMUX2 set -g status-left 'LLL' || exit 1
+$TMUX2 set -g window-status-current-format 'WWW' || exit 1
+$TMUX -f/dev/null new -x20 -y2 -d "$TMUX2 attach" || exit 1
+sleep 1
+$TMUX capturep -p|tail -1 >$TMP || exit 1
+$TMUX kill-server 2>/dev/null
+$TMUX2 kill-server 2>/dev/null
+cat <<EOF|cmp -s $TMP - || exit 1
+LLLWWW RR
+EOF
+
+exit 0
diff --git a/regsub.c b/regsub.c
new file mode 100644
index 00000000..89355bef
--- /dev/null
+++ b/regsub.c
@@ -0,0 +1,115 @@
+/* $OpenBSD$ */
+
+/*
+ * Copyright (c) 2019 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 <regex.h>
+#include <string.h>
+
+#include "tmux.h"
+
+static void
+regsub_copy(char **buf, size_t *len, const char *text, size_t start,
+ size_t end)
+{
+ size_t add = end - start;
+
+ *buf = xrealloc(*buf, (*len) + add + 1);
+ memcpy((*buf) + *len, text + start, add);
+ (*len) += add;
+}
+
+static void
+regsub_expand(char **buf, size_t *len, const char *with, const char *text,
+ regmatch_t *m, u_int n)
+{
+ const char *cp;
+ u_int i;
+
+ for (cp = with; *cp != '\0'; cp++) {
+ if (*cp == '\\') {
+ cp++;
+ if (*cp >= '0' && *cp <= '9') {
+ i = *cp - '0';
+ if (i < n && m[i].rm_so != m[i].rm_eo) {
+ regsub_copy(buf, len, text, m[i].rm_so,
+ m[i].rm_eo);
+ continue;
+ }
+ }
+ }
+ *buf = xrealloc(*buf, (*len) + 2);
+ (*buf)[(*len)++] = *cp;
+ }
+}
+
+char *
+regsub(const char *pattern, const char *with, const char *text, int flags)
+{
+ regex_t r;
+ regmatch_t m[10];
+ ssize_t start, end, last, len = 0;
+ int empty = 0;
+ char *buf = NULL;
+
+ if (*text == '\0')
+ return (xstrdup(""));
+ if (regcomp(&r, pattern, flags) != 0)
+ return (NULL);
+
+ start = 0;
+ last = 0;
+ end = strlen(text);
+
+ while (start <= end) {
+ m[0].rm_so = start;
+ m[0].rm_eo = end;
+
+ if (regexec(&r, text, nitems(m), m, REG_STARTEND) != 0) {
+ regsub_copy(&buf, &len, text, start, end);
+ break;
+ }
+
+ /*
+ * Append any text not part of this match (from the end of the
+ * last match).
+ */
+ regsub_copy(&buf, &len, text, last, m[0].rm_so);
+
+ /*
+ * If the last match was empty and this one isn't (it is either
+ * later or has matched text), expand this match. If it is
+ * empty, move on one character and try again from there.
+ */
+ if (empty || m[0].rm_so != last || m[0].rm_so != m[0].rm_eo) {
+ regsub_expand(&buf, &len, with, text, m, nitems(m));
+
+ last = m[0].rm_eo;
+ start = m[0].rm_eo;
+ empty = 0;
+ } else {
+ last = m[0].rm_eo;
+ start = m[0].rm_eo + 1;
+ empty = 1;
+ }
+ }
+ buf[len] = '\0';
+
+ regfree(&r);
+ return (buf);
+}
diff --git a/screen-redraw.c b/screen-redraw.c
index 65e890b6..e7f4f077 100644
--- a/screen-redraw.c
+++ b/screen-redraw.c
@@ -45,10 +45,6 @@ static void screen_redraw_draw_pane(struct screen_redraw_ctx *,
#define CELL_BORDERS " xqlkmjwvtun~"
-#define CELL_STATUS_OFF 0
-#define CELL_STATUS_TOP 1
-#define CELL_STATUS_BOTTOM 2
-
/* 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)
@@ -112,12 +108,12 @@ screen_redraw_check_cell(struct client *c, u_int px, u_int py, int pane_status,
if (px > w->sx || py > w->sy)
return (CELL_OUTSIDE);
- if (pane_status != CELL_STATUS_OFF) {
+ if (pane_status != PANE_STATUS_OFF) {
TAILQ_FOREACH(wp, &w->panes, entry) {
if (!window_pane_visible(wp))
continue;
- if (pane_status == CELL_STATUS_TOP)
+ if (pane_status == PANE_STATUS_TOP)
line = wp->yoff - 1;
else
line = wp->yoff + wp->sy;
@@ -153,7 +149,7 @@ screen_redraw_check_cell(struct client *c, u_int px, u_int py, int pane_status,
borders |= 8;
if (px <= w->sx && screen_redraw_cell_border(c, px + 1, py))
borders |= 4;
- if (pane_status == CELL_STATUS_TOP) {
+ if (pane_status == PANE_STATUS_TOP) {
if (py != 0 && screen_redraw_cell_border(c, px, py - 1))
borders |= 2;
} else {
@@ -208,9 +204,9 @@ screen_redraw_check_is(u_int px, u_int py, int type, int pane_status,
border = screen_redraw_cell_border1(wantwp, px, py);
if (border == 0 || border == -1)
return (0);
- if (pane_status == CELL_STATUS_TOP && border == 4)
+ if (pane_status == PANE_STATUS_TOP && border == 4)
return (0);
- if (pane_status == CELL_STATUS_BOTTOM && border == 3)
+ if (pane_status == PANE_STATUS_BOTTOM && border == 3)
return (0);
/* If there are more than two panes, that's enough. */
@@ -222,7 +218,7 @@ screen_redraw_check_is(u_int px, u_int py, int type, int pane_status,
return (1);
/* With status lines mark the entire line. */
- if (pane_status != CELL_STATUS_OFF)
+ if (pane_status != PANE_STATUS_OFF)
return (1);
/* Check if the pane covers the whole width. */
@@ -270,7 +266,7 @@ screen_redraw_make_pane_status(struct client *c, struct window *w,
fmt = options_get_string(w->options, "pane-border-format");
- ft = format_create(c, NULL, FORMAT_PANE|wp->id, 0);
+ ft = format_create(c, NULL, FORMAT_PANE|wp->id, FORMAT_STATUS);
format_defaults(ft, c, NULL, NULL, wp);
expanded = format_expand_time(ft, fmt);
@@ -324,7 +320,7 @@ screen_redraw_draw_pane_status(struct screen_redraw_ctx *ctx)
s = &wp->status_screen;
size = wp->status_size;
- if (ctx->pane_status == CELL_STATUS_TOP)
+ if (ctx->pane_status == PANE_STATUS_TOP)
yoff = wp->yoff - 1;
else
yoff = wp->yoff + wp->sy;
@@ -386,7 +382,7 @@ screen_redraw_update(struct client *c, int flags)
if (c->overlay_draw != NULL)
flags |= CLIENT_REDRAWOVERLAY;
- if (options_get_number(wo, "pane-border-status") != CELL_STATUS_OFF) {
+ if (options_get_number(wo, "pane-border-status") != PANE_STATUS_OFF) {
redraw = 0;
TAILQ_FOREACH(wp, &w->panes, entry) {
if (screen_redraw_make_pane_status(c, w, wp))
@@ -441,7 +437,7 @@ screen_redraw_screen(struct client *c)
screen_redraw_set_context(c, &ctx);
if (flags & (CLIENT_REDRAWWINDOW|CLIENT_REDRAWBORDERS)) {
- if (ctx.pane_status != CELL_STATUS_OFF)
+ if (ctx.pane_status != PANE_STATUS_OFF)
screen_redraw_draw_pane_status(&ctx);
screen_redraw_draw_borders(&ctx);
}
diff --git a/screen-write.c b/screen-write.c
index 174c7a82..98cdf158 100644
--- a/screen-write.c
+++ b/screen-write.c
@@ -36,7 +36,7 @@ static const struct grid_cell *screen_write_combine(struct screen_write_ctx *,
const struct utf8_data *, u_int *);
static const struct grid_cell screen_write_pad_cell = {
- GRID_FLAG_PADDING, 0, 8, 8, { { 0 }, 0, 0, 0 }
+ { { 0 }, 0, 0, 0 }, 0, GRID_FLAG_PADDING, 0, 8, 8
};
struct screen_write_collect_item {
@@ -1169,11 +1169,7 @@ screen_write_clearscreen(struct screen_write_ctx *ctx, u_int bg)
void
screen_write_clearhistory(struct screen_write_ctx *ctx)
{
- struct screen *s = ctx->s;
- struct grid *gd = s->grid;
-
- grid_move_lines(gd, 0, gd->hsize, gd->sy, 8);
- gd->hscrolled = gd->hsize = 0;
+ grid_clear_history(ctx->s->grid);
}
/* Clear a collected line. */
diff --git a/server-client.c b/server-client.c
index 0d0d561c..f44631c9 100644
--- a/server-client.c
+++ b/server-client.c
@@ -522,9 +522,10 @@ have_event:
/* Is this on the status line? */
m->statusat = status_at_line(c);
+ m->statuslines = status_line_size(c);
if (m->statusat != -1 &&
y >= (u_int)m->statusat &&
- y < m->statusat + status_line_size(c)) {
+ y < m->statusat + m->statuslines) {
sr = status_get_range(c, x, y - m->statusat);
if (sr == NULL) {
where = STATUS_DEFAULT;
@@ -553,8 +554,8 @@ have_event:
/* Not on status line. Adjust position and check for border or pane. */
if (where == NOWHERE) {
px = x;
- if (m->statusat == 0 && y > 0)
- py = y - 1;
+ if (m->statusat == 0 && y >= m->statuslines)
+ py = y - m->statuslines;
else if (m->statusat > 0 && y >= (u_int)m->statusat)
py = m->statusat - 1;
else
@@ -1024,16 +1025,6 @@ server_client_key_callback(struct cmdq_item *item, void *data)
fatal("gettimeofday failed");
session_update_activity(s, &c->activity_time);
- /* Handle status line. */
- if (~c->flags & CLIENT_READONLY)
- status_message_clear(c);
- if (c->prompt_string != NULL) {
- if (c->flags & CLIENT_READONLY)
- goto out;
- if (status_prompt_key(c, key) == 0)
- goto out;
- }
-
/* Check for mouse keys. */
m->valid = 0;
if (key == KEYC_MOUSE) {
@@ -1214,17 +1205,26 @@ server_client_handle_key(struct client *c, struct key_event *event)
return (0);
/*
- * Key presses in overlay mode are a special case. The queue might be
- * blocked so they need to be processed immediately rather than queued.
+ * Key presses in overlay mode and the command prompt are a special
+ * case. The queue might be blocked so they need to be processed
+ * immediately rather than queued.
*/
- if ((~c->flags & CLIENT_READONLY) && c->overlay_key != NULL) {
- switch (c->overlay_key(c, event)) {
- case 0:
- return (0);
- case 1:
- server_client_clear_overlay(c);
- return (0);
+ 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:
+ return (0);
+ case 1:
+ server_client_clear_overlay(c);
+ return (0);
+ }
}
+ server_client_clear_overlay(c);
}
/*
@@ -1243,6 +1243,8 @@ server_client_loop(void)
struct client *c;
struct window *w;
struct window_pane *wp;
+ struct winlink *wl;
+ struct session *s;
int focus;
TAILQ_FOREACH(c, &clients, entry) {
@@ -1259,11 +1261,17 @@ server_client_loop(void)
*/
focus = options_get_number(global_options, "focus-events");
RB_FOREACH(w, windows, &windows) {
+ TAILQ_FOREACH(wl, &w->winlinks, wentry) {
+ s = wl->session;
+ if (s->attached != 0 && s->curw == wl)
+ break;
+ }
TAILQ_FOREACH(wp, &w->panes, entry) {
if (wp->fd != -1) {
if (focus)
server_client_check_focus(wp);
- server_client_check_resize(wp);
+ if (wl != NULL)
+ server_client_check_resize(wp);
}
wp->flags &= ~PANE_REDRAW;
}
@@ -1525,7 +1533,9 @@ server_client_click_timer(__unused int fd, __unused short events, void *data)
static void
server_client_check_exit(struct client *c)
{
- if (!(c->flags & CLIENT_EXIT))
+ if (~c->flags & CLIENT_EXIT)
+ return;
+ if (c->flags & CLIENT_EXITED)
return;
if (EVBUFFER_LENGTH(c->stdin_data) != 0)
@@ -1538,7 +1548,7 @@ server_client_check_exit(struct client *c)
if (c->flags & CLIENT_ATTACHED)
notify_client("client-detached", c);
proc_send(c->peer, MSG_EXIT, -1, &c->retval, sizeof c->retval);
- c->flags &= ~CLIENT_EXIT;
+ c->flags |= CLIENT_EXITED;
}
/* Redraw timer callback. */
@@ -1943,26 +1953,29 @@ server_client_dispatch_identify(struct client *c, struct imsg *imsg)
close(c->fd);
c->fd = -1;
-
- return;
- }
-
- if (c->fd == -1)
- return;
- if (tty_init(&c->tty, c, c->fd, c->term) != 0) {
- close(c->fd);
- c->fd = -1;
- return;
+ } else if (c->fd != -1) {
+ if (tty_init(&c->tty, c, c->fd, c->term) != 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;
+ }
}
- 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);
- if (!(c->flags & CLIENT_CONTROL))
- c->flags |= CLIENT_TERMINAL;
+ /*
+ * If this is the first client that has finished identifying, load
+ * configuration files.
+ */
+ if ((~c->flags & CLIENT_EXIT) &&
+ !cfg_finished &&
+ c == TAILQ_FIRST(&clients) &&
+ TAILQ_NEXT(c, entry) == NULL)
+ start_cfg();
}
/* Handle shell message. */
diff --git a/server-fn.c b/server-fn.c
index 213d72ea..cfafef21 100644
--- a/server-fn.c
+++ b/server-fn.c
@@ -308,7 +308,7 @@ server_destroy_pane(struct window_pane *wp, int notify)
wp->fd = -1;
}
- if (options_get_number(w->options, "remain-on-exit")) {
+ if (options_get_number(wp->options, "remain-on-exit")) {
if (~wp->flags & PANE_STATUSREADY)
return;
diff --git a/server.c b/server.c
index af966501..a5d5e37f 100644
--- a/server.c
+++ b/server.c
@@ -43,7 +43,7 @@
struct clients clients;
struct tmuxproc *server_proc;
-static int server_fd;
+static int server_fd = -1;
static int server_exit;
static struct event server_ev_accept;
@@ -209,9 +209,7 @@ server_start(struct tmuxproc *client, struct event_base *base, int lockfd,
c->flags |= CLIENT_EXIT;
}
- start_cfg();
server_add_accept(0);
-
proc_loop(server_proc, server_loop);
job_kill_all();
@@ -363,6 +361,9 @@ server_add_accept(int timeout)
{
struct timeval tv = { timeout, 0 };
+ if (server_fd == -1)
+ return;
+
if (event_initialized(&server_ev_accept))
event_del(&server_ev_accept);
diff --git a/spawn.c b/spawn.c
index 8be26fa3..2a588b6b 100644
--- a/spawn.c
+++ b/spawn.c
@@ -170,10 +170,8 @@ spawn_window(struct spawn_context *sc, char **cause)
/* Spawn the pane. */
wp = spawn_pane(sc, cause);
if (wp == NULL) {
- if (~sc->flags & SPAWN_RESPAWN) {
- window_destroy(w);
+ if (~sc->flags & SPAWN_RESPAWN)
winlink_remove(&s->windows, sc->wl);
- }
return (NULL);
}
diff --git a/style.c b/style.c
index ce78175a..9f986314 100644
--- a/style.c
+++ b/style.c
@@ -30,8 +30,9 @@
/* Default style. */
static struct style style_default = {
- { 0, 0, 8, 8, { { ' ' }, 0, 1, 1 } },
+ { { { ' ' }, 0, 1, 1 }, 0, 0, 8, 8, 0 },
+ 8,
STYLE_ALIGN_DEFAULT,
STYLE_LIST_OFF,
@@ -127,6 +128,10 @@ style_parse(struct style *sy, const struct grid_cell *base, const char *in)
sy->align = STYLE_ALIGN_RIGHT;
else
goto error;
+ } else if (end > 5 && strncasecmp(tmp, "fill=", 5) == 0) {
+ if ((value = colour_fromstring(tmp + 5)) == -1)
+ goto error;
+ sy->fill = value;
} else if (end > 3 && strncasecmp(tmp + 1, "g=", 2) == 0) {
if ((value = colour_fromstring(tmp + 3)) == -1)
goto error;
@@ -213,6 +218,11 @@ style_tostring(struct style *sy)
tmp);
comma = ",";
}
+ if (sy->fill != 8) {
+ off += xsnprintf(s + off, sizeof s - off, "%sfill=%s", comma,
+ colour_tostring(sy->fill));
+ comma = ",";
+ }
if (gc->fg != 8) {
off += xsnprintf(s + off, sizeof s - off, "%sfg=%s", comma,
colour_tostring(gc->fg));
@@ -290,6 +300,8 @@ style_equal(struct style *sy1, struct style *sy2)
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);
diff --git a/tmux.1 b/tmux.1
index 286192a3..227ed36b 100644
--- a/tmux.1
+++ b/tmux.1
@@ -461,7 +461,7 @@ Will execute
.Ic if-shell ,
the shell command
.Xr true 1 ,
-.Ic new-window
+.Ic split-window
and
.Ic kill-session
in that order.
@@ -475,7 +475,7 @@ commands and their arguments.
This section describes the syntax of commands parsed by
.Nm ,
for example in a configuration file or at the command prompt.
-Note the when commands are entered into the shell, they are parsed by the shell
+Note that when commands are entered into the shell, they are parsed by the shell
- see for example
.Xr ksh 1
or
@@ -520,7 +520,11 @@ the given four or eight digit hexadecimal number.
When preceded (escaped) by a \e, the following characters are replaced: \ee by
the escape character; \er by a carriage return; \en by a newline; and \et by a
tab.
-.Pp
+.It
+\eooo is replaced by a character of the octal value ooo.
+Three octal digits are required, for example \e001.
+The largest valid character is \e377.
+.It
Any other characters preceded by \e are replaced by themselves (that is, the \e
is removed) and are not treated as having any special meaning - so for example
\e; will not mark a command sequence and \e$ will not expand an environment
@@ -610,7 +614,7 @@ Most commands accept the optional
.Fl s )
argument with one of
.Ar target-client ,
-.Ar target-session
+.Ar target-session ,
.Ar target-window ,
or
.Ar target-pane .
@@ -777,7 +781,7 @@ may consist entirely of the token
.Ql {mouse}
(alternative form
.Ql = )
-to specify the most recent mouse event
+to specify the session, window or pane where the most recent mouse event occurred
(see the
.Sx MOUSE SUPPORT
section)
@@ -877,7 +881,7 @@ refresh-client -t/dev/ttyp2
rename-session -tfirst newname
-set-window-option -t:0 monitor-activity on
+set-option -wt:0 monitor-activity on
new-window ; split-window -d
@@ -919,7 +923,7 @@ section.
The following commands are available to manage clients and sessions:
.Bl -tag -width Ds
.It Xo Ic attach-session
-.Op Fl dEr
+.Op Fl dErx
.Op Fl c Ar working-directory
.Op Fl t Ar target-session
.Xc
@@ -932,6 +936,10 @@ If used from inside, switch the current client.
If
.Fl d
is specified, any other clients attached to the session are detached.
+If
+.Fl x
+is given, send SIGHUP to the parent process of the client as well as
+detaching the client, typically causing it to exit.
.Fl r
signifies the client is read-only (only keys bound to the
.Ic detach-client
@@ -1049,7 +1057,7 @@ command.
Lock all clients attached to
.Ar target-session .
.It Xo Ic new-session
-.Op Fl AdDEP
+.Op Fl AdDEPX
.Op Fl c Ar start-directory
.Op Fl F Ar format
.Op Fl n Ar window-name
@@ -1106,6 +1114,12 @@ already exists; in this case,
behaves like
.Fl d
to
+.Ic attach-session ,
+and
+.Fl X
+behaves like
+.Fl x
+to
.Ic attach-session .
.Pp
If
@@ -1153,7 +1167,8 @@ is used, the
option will not be applied.
.It Xo Ic refresh-client
.Op Fl cDlLRSU
-.Op Fl C Ar width,height
+.Op Fl C Ar XxY
+.Op Fl F Ar flags
.Op Fl t Ar target-client
.Op Ar adjustment
.Xc
@@ -1196,7 +1211,13 @@ window, changing the current window in the attached session will reset
it.
.Pp
.Fl C
-sets the width and height of a control client.
+sets the width and height of a control client and
+.Fl F
+sets a comma-separated list of flags.
+Currently the only flag available is
+.Ql no-output
+to disable receiving pane output.
+.Pp
.Fl l
requests the clipboard from the client using the
.Xr xterm 1
@@ -1242,7 +1263,7 @@ and
.Fl T
show debugging information about jobs and terminals.
.It Xo Ic source-file
-.Op Fl nq
+.Op Fl nqv
.Ar path
.Ar ...
.Xc
@@ -1260,6 +1281,8 @@ does not exist.
With
.Fl n ,
the file is parsed but no commands are executed.
+.Fl v
+shows the parsed commands and line numbers if possible.
.It Ic start-server
.D1 (alias: Ic start )
Start the
@@ -1343,6 +1366,9 @@ It is also entered when a command that produces output, such as
.Ic list-keys ,
is executed from a key binding.
.Pp
+In copy mode an indicator is displayed in the top-right corner of the pane with
+the current position and the number of lines in the history.
+.Pp
Commands are sent to copy mode using the
.Fl X
flag to the
@@ -1396,6 +1422,7 @@ The following commands are supported in copy mode:
.It Li "jump-to-backward <to>" Ta "T" Ta ""
.It Li "jump-to-forward <to>" Ta "t" Ta ""
.It Li "middle-line" Ta "M" Ta "M-r"
+.It Li "next-matching-bracket" Ta "%" Ta "M-C-f"
.It Li "next-paragraph" Ta "}" Ta "M-}"
.It Li "next-space" Ta "W" Ta ""
.It Li "next-space-end" Ta "E" Ta ""
@@ -1405,6 +1432,7 @@ The following commands are supported in copy mode:
.It Li "page-down" Ta "C-f" Ta "PageDown"
.It Li "page-down-and-cancel" Ta "" Ta ""
.It Li "page-up" Ta "C-b" Ta "PageUp"
+.It Li "previous-matching-bracket" Ta "" Ta "M-C-b"
.It Li "previous-paragraph" Ta "{" Ta "M-{"
.It Li "previous-space" Ta "B" Ta ""
.It Li "previous-word" Ta "b" Ta "M-b"
@@ -1817,14 +1845,16 @@ With
.Fl b ,
other commands are not blocked from running until the indicator is closed.
.It Xo Ic find-window
-.Op Fl CNTZ
+.Op Fl rCNTZ
.Op Fl t Ar target-pane
.Ar match-string
.Xc
.D1 (alias: Ic findw )
-Search for the
+Search for a
.Xr fnmatch 3
-pattern
+pattern or, with
+.Fl r ,
+regular expression
.Ar match-string
in window names, titles, and visible content (but not history).
The flags control matching behavior:
@@ -2312,8 +2342,7 @@ applies the last set layout if possible (undoes the most recent layout change).
.Fl E
spreads the current pane and any panes next to it out evenly.
.It Xo Ic select-pane
-.Op Fl DdegLlMmRU
-.Op Fl P Ar style
+.Op Fl DdeLlMmRU
.Op Fl T Ar title
.Op Fl t Ar target-pane
.Xc
@@ -2321,9 +2350,7 @@ spreads the current pane and any panes next to it out evenly.
Make pane
.Ar target-pane
the active pane in window
-.Ar target-window ,
-or set its style (with
-.Fl P ) .
+.Ar target-window .
If one of
.Fl D ,
.Fl L ,
@@ -2340,6 +2367,8 @@ command.
enables or
.Fl d
disables input to the pane.
+.Fl T
+sets the pane title.
.Pp
.Fl m
and
@@ -2354,25 +2383,6 @@ to
.Ic swap-pane
and
.Ic swap-window .
-.Pp
-Each pane has a style: by default the
-.Ic window-style
-and
-.Ic window-active-style
-options are used,
-.Ic select-pane
-.Fl P
-sets the style for a single pane.
-For example, to set the pane 1 background to red:
-.Bd -literal -offset indent
-select-pane -t:.1 -P 'bg=red'
-.Ed
-.Pp
-.Fl g
-shows the current pane style.
-.Pp
-.Fl T
-sets the pane title.
.It Xo Ic select-window
.Op Fl lnpT
.Op Fl t Ar target-window
@@ -2629,7 +2639,7 @@ With
only
.Ar key-table .
.It Xo Ic send-keys
-.Op Fl lMRX
+.Op Fl HlMRX
.Op Fl N Ar repeat-count
.Op Fl t Ar target-pane
.Ar key Ar ...
@@ -2644,10 +2654,16 @@ or
.Ql NPage )
to send; if the string is not recognised as a key, it is sent as a series of
characters.
+All arguments are sent sequentially from first to last.
+.Pp
The
.Fl l
-flag disables key name lookup and sends the keys literally.
-All arguments are sent sequentially from first to last.
+flag disables key name lookup and processes the keys as literal UTF-8
+characters.
+The
+.Fl H
+flag expects each key to be a hexadecimal number for an ASCII character.
+.Pp
The
.Fl R
flag causes the terminal state to be reset.
@@ -2691,16 +2707,17 @@ is present, all key bindings are removed.
The appearance and behaviour of
.Nm
may be modified by changing the value of various options.
-There are three types of option:
+There are four types of option:
.Em server options ,
.Em session options
+.Em window options
and
-.Em window options .
+.Em pane options .
.Pp
The
.Nm
server has a set of global options which do not apply to any particular
-window or session.
+window or session or pane.
These are altered with the
.Ic set-option
.Fl s
@@ -2722,16 +2739,29 @@ The available server and session options are listed under the
.Ic set-option
command.
.Pp
-Similarly, a set of window options is attached to each window, and there is
-a set of global window options from which any unset options are inherited.
-Window options are altered with the
-.Ic set-window-option
-command and can be listed with the
-.Ic show-window-options
-command.
-All window options are documented with the
-.Ic set-window-option
-command.
+Similarly, a set of window options is attached to each window and a set of pane
+options to each pane.
+Pane options inherit from window options.
+This means any pane option may be set as a window option to apply the option to
+all panes in the window without the option set, for example these commands will
+set the background colour to red for all panes except pane 0:
+.Bd -literal -offset indent
+set -w window-style bg=red
+set -pt:.0 window-style bg=blue
+.Ed
+.Pp
+There is also a set of global window options from which any unset window or
+pane options are inherited.
+Window and pane options are altered with
+.Ic set-option
+.Fl w
+and
+.Fl p
+commands and displayed with
+.Ic show-option
+.Fl w
+and
+.Fl p .
.Pp
.Nm
also supports user options which are prefixed with a
@@ -2749,26 +2779,27 @@ abc123
Commands which set options are as follows:
.Bl -tag -width Ds
.It Xo Ic set-option
-.Op Fl aFgoqsuw
-.Op Fl t Ar target-session | Ar target-window
+.Op Fl aFgopqsuw
+.Op Fl t Ar target-pane
.Ar option Ar value
.Xc
.D1 (alias: Ic set )
-Set a window option with
-.Fl w
-(equivalent to the
-.Ic set-window-option
-command),
+Set a pane option with
+.Fl p ,
+a window option with
+.Fl w ,
a server option with
.Fl s ,
otherwise a session option.
If the option is not a user option,
.Fl w
-and
+or
.Fl s
-are unnecessary -
+may be unnecessary -
.Nm
-will infer the type from the option name.
+will infer the type from the option name, assuming
+.Fl w
+for pane options.
If
.Fl g
is given, the global session or window option is set.
@@ -2813,13 +2844,49 @@ blue foreground.
Without
.Fl a ,
the result would be the default background and a blue foreground.
-.Pp
-Available window options are listed under
-.Ic set-window-option .
-.Pp
+.It Xo Ic show-options
+.Op Fl AgHpqsvw
+.Op Fl t Ar target-pane
+.Op Ar option
+.Xc
+.D1 (alias: Ic show )
+Show the pane options (or a single option if
+.Ar option
+is provided) with
+.Fl p ,
+the window options with
+.Fl w ,
+the server options with
+.Fl s ,
+otherwise the session options.
+If the option is not a user option,
+.Fl w
+or
+.Fl s
+may be unnecessary -
+.Nm
+will infer the type from the option name, assuming
+.Fl w
+for pane options.
+Global session or window options are listed if
+.Fl g
+is used.
+.Fl v
+shows only the option value, not the name.
+If
+.Fl q
+is set, no error will be returned if
+.Ar option
+is unset.
+.Fl H
+includes hooks (omitted by default).
+.Fl A
+includes options inherited from a parent set of options, such options are
+marked with an asterisk.
.Ar value
depends on the option and may be a number, a string, or a flag (on, off, or
omitted to toggle).
+.El
.Pp
Available server options are:
.Bl -tag -width Ds
@@ -2960,6 +3027,18 @@ for all terminal types matching
The terminal entry value is passed through
.Xr strunvis 3
before interpretation.
+.It Ic user-keys[] Ar key
+Set list of user-defined key escape sequences.
+Each item is associated with a key named
+.Ql User0 ,
+.Ql User1 ,
+and so on.
+.Pp
+For example:
+.Bd -literal -offset indent
+set -s user-keys[0] "\ee[5;30012~"
+bind User0 resize-pane -L 3
+.Ed
.El
.Pp
Available session options are:
@@ -3166,7 +3245,7 @@ the terminal appears to be
.Xr xterm 1 .
This option is off by default.
.It Ic set-titles-string Ar string
-String used to set the window title if
+String used to set the client terminal title if
.Ic set-titles
is on.
Formats are expanded, see the
@@ -3300,18 +3379,6 @@ removed from the session environment (as if
was given to the
.Ic set-environment
command).
-.It Ic user-keys[] Ar key
-Set list of user-defined key escape sequences.
-Each item is associated with a key named
-.Ql User0 ,
-.Ql User1 ,
-and so on.
-.Pp
-For example:
-.Bd -literal -offset indent
-set -s user-keys[0] "\ee[5;30012~"
-bind User0 resize-pane -L 3
-.Ed
.It Xo Ic visual-activity
.Op Ic on | off | both
.Xc
@@ -3346,26 +3413,8 @@ copy mode.
The default is
.Ql \ -_@ .
.El
-.It Xo Ic set-window-option
-.Op Fl aFgoqu
-.Op Fl t Ar target-window
-.Ar option Ar value
-.Xc
-.D1 (alias: Ic setw )
-Set a window option.
-The
-.Fl a ,
-.Fl F ,
-.Fl g ,
-.Fl o ,
-.Fl q
-and
-.Fl u
-flags work similarly to the
-.Ic set-option
-command.
.Pp
-Supported window options are:
+Available window options are:
.Pp
.Bl -tag -width Ds -compact
.It Xo Ic aggressive-resize
@@ -3384,29 +3433,6 @@ session; this option is good for full-screen programs which support
.Dv SIGWINCH
and poor for interactive programs such as shells.
.Pp
-.It Xo Ic allow-rename
-.Op Ic on | off
-.Xc
-Allow programs to change the window name using a terminal escape
-sequence (\eek...\ee\e\e).
-The default is off.
-.Pp
-.It Xo Ic alternate-screen
-.Op Ic on | off
-.Xc
-This option configures whether programs running inside
-.Nm
-may use the terminal alternate screen feature, which allows the
-.Em smcup
-and
-.Em rmcup
-.Xr terminfo 5
-capabilities.
-The alternate screen feature preserves the contents of the window when an
-interactive application starts and restores it on exit, so that any output
-visible before the application starts reappears unchanged after it exits.
-The default is on.
-.Pp
.It Xo Ic automatic-rename
.Op Ic on | off
.Xc
@@ -3425,7 +3451,7 @@ or later with
or with a terminal escape sequence.
It may be switched off globally with:
.Bd -literal -offset indent
-set-window-option -g automatic-rename off
+set-option -wg automatic-rename off
.Ed
.Pp
.It Ic automatic-rename-format Ar format
@@ -3542,29 +3568,12 @@ see the
section.
Attributes are ignored.
.Pp
-.It Xo Ic remain-on-exit
-.Op Ic on | off
-.Xc
-A window with this flag set is not destroyed when the program running in it
-exits.
-The window may be reactivated with the
-.Ic respawn-window
-command.
-.Pp
.It Xo Ic synchronize-panes
.Op Ic on | off
.Xc
Duplicate input to any pane to all other panes in the same window (only
for panes that are not in any special mode).
.Pp
-.It Ic window-active-style Ar style
-Set the style for the window's active pane.
-For how to specify
-.Ar style ,
-see the
-.Sx STYLES
-section.
-.Pp
.It Ic window-status-activity-style Ar style
Set status line style for windows with an activity alert.
For how to specify
@@ -3644,14 +3653,6 @@ command and the
.Ic aggressive-resize
option.
.Pp
-.It Ic window-style Ar style
-Set the default window style.
-For how to specify
-.Ar style ,
-see the
-.Sx STYLES
-section.
-.Pp
.It Xo Ic wrap-search
.Op Ic on | off
.Xc
@@ -3668,54 +3669,54 @@ will generate
function key sequences; these have a number included to indicate modifiers such
as Shift, Alt or Ctrl.
.El
-.It Xo Ic show-options
-.Op Fl gHqsvw
-.Op Fl t Ar target-session | Ar target-window
-.Op Ar option
+.Pp
+Available pane options are:
+.Pp
+.Bl -tag -width Ds -compact
+.It Xo Ic allow-rename
+.Op Ic on | off
.Xc
-.D1 (alias: Ic show )
-Show the window options (or a single window option if given) with
-.Fl w
-(equivalent to
-.Ic show-window-options ) ,
-the server options with
-.Fl s ,
-otherwise the session options for
-.Ar target session .
-If
-.Ar option
-is given and is not a user option,
-.Fl w
+Allow programs in the pane to change the window name using a terminal escape
+sequence (\eek...\ee\e\e).
+.Pp
+.It Xo Ic alternate-screen
+.Op Ic on | off
+.Xc
+This option configures whether programs running inside the pane may use the
+terminal alternate screen feature, which allows the
+.Em smcup
and
-.Fl s
-are unnecessary -
-.Nm
-will infer the type from the option name.
-Global session or window options are listed if
-.Fl g
-is used.
-.Fl v
-shows only the option value, not the name.
-If
-.Fl q
-is set, no error will be returned if
-.Ar option
-is unset.
-.Fl H
-includes hooks (omitted by default).
-.It Xo Ic show-window-options
-.Op Fl gv
-.Op Fl t Ar target-window
-.Op Ar option
+.Em rmcup
+.Xr terminfo 5
+capabilities.
+The alternate screen feature preserves the contents of the window when an
+interactive application starts and restores it on exit, so that any output
+visible before the application starts reappears unchanged after it exits.
+.Pp
+.It Xo Ic remain-on-exit
+.Op Ic on | off
.Xc
-.D1 (alias: Ic showw )
-List the window options or a single option for
-.Ar target-window ,
-or the global window options if
-.Fl g
-is used.
-.Fl v
-shows only the option value, not the name.
+A pane with this flag set is not destroyed when the program running in it
+exits.
+The pane may be reactivated with the
+.Ic respawn-pane
+command.
+.Pp
+.It Ic window-active-style Ar style
+Set the pane style when it is the active pane.
+For how to specify
+.Ar style ,
+see the
+.Sx STYLES
+section.
+.Pp
+.It Ic window-style Ar style
+Set the pane style.
+For how to specify
+.Ar style ,
+see the
+.Sx STYLES
+section.
.El
.Sh HOOKS
.Nm
@@ -3924,7 +3925,7 @@ flag with a
.Ar format
argument.
This is a string which controls the output format of the command.
-Replacement variables are enclosed in
+Format variables are enclosed in
.Ql #{
and
.Ql } ,
@@ -3983,7 +3984,7 @@ For example:
#{?pane_in_mode,#[fg=white#,bg=red],#[fg=red#,bg=white]}#W .
.Ed
.Pp
-Comparisons may be expressed by prefixing two comma-separated
+String comparisons may be expressed by prefixing two comma-separated
alternatives by
.Ql == ,
.Ql != ,
@@ -4001,25 +4002,45 @@ if running on
.Ql myhost ,
otherwise by
.Ql 0 .
-An
-.Ql m
-specifies an
-.Xr fnmatch 3
-comparison where the first argument is the pattern and the second the string to
-compare, for example
-.Ql #{m:*foo*,#{host}} .
.Ql ||
and
.Ql &&
evaluate to true if either or both of two comma-separated alternatives are
true, for example
.Ql #{||:#{pane_in_mode},#{alternate_on}} .
+.Pp
+An
+.Ql m
+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:
+.Ql r
+means the pattern is a regular expression instead of the default
+.Xr fnmatch 3
+pattern, and
+.Ql i
+means to ignore case.
+For example:
+.Ql #{m:*foo*,#{host}}
+or
+.Ql #{m/ri:^A,MYVAR} .
A
.Ql C
performs a search for an
.Xr fnmatch 3
-pattern in the pane content and evaluates to zero if not found, or a line
-number if found.
+pattern or regular expression in the pane content and evaluates to zero if not
+found, or a line number if found.
+Like
+.Ql m ,
+an
+.Ql r
+flag means search for a regular expression and
+.Ql i
+ignores case.
+For example:
+.Ql #{C/r:^Start}
.Pp
A limit may be placed on the length of the resultant string by prefixing it
by an
@@ -4065,7 +4086,7 @@ will expand the format twice, for example
.Ql #{E:status-left}
is the result of expanding the content of the
.Ic status-left
-option rather than the content itself.
+option rather than the option itself.
.Ql T:
is like
.Ql E:
@@ -4092,8 +4113,16 @@ will substitute
with
.Ql bar
throughout.
-.Pp
-In addition, the first line of a shell command's output may be inserted using
+The first argument may be an extended regular expression and a final argument may be
+.Ql i
+to ignore case, for example
+.Ql s/a(.)/\e1x/i:
+would change
+.Ql abABab
+into
+.Ql bxBxbx .
+.Pp
+In addition, the last line of a shell command's output may be inserted using
.Ql #() .
For example,
.Ql #(uptime)
@@ -4112,10 +4141,18 @@ global environment set (see the
.Sx GLOBAL AND SESSION ENVIRONMENT
section).
.Pp
+An
+.Ql l
+specifies that a string should be interpreted literally and not expanded.
+For example
+.Ql #{l:#{?pane_in_mode,yes,no}}
+will be replaced by
+.Ql #{?pane_in_mode,yes,no} .
+.Pp
The following variables are available, where appropriate:
.Bl -column "XXXXXXXXXXXXXXXXXXX" "XXXXX"
.It Sy "Variable name" Ta Sy "Alias" Ta Sy "Replaced with"
-.It Li "alternate_on" Ta "" Ta "If pane is in alternate screen"
+.It Li "alternate_on" Ta "" Ta "1 if pane is in alternate screen"
.It Li "alternate_saved_x" Ta "" Ta "Saved cursor X in alternate screen"
.It Li "alternate_saved_y" Ta "" Ta "Saved cursor Y in alternate screen"
.It Li "buffer_created" Ta "" Ta "Time buffer created"
@@ -4166,11 +4203,14 @@ The following variables are available, where appropriate:
.It Li "mouse_all_flag" Ta "" Ta "Pane mouse all flag"
.It Li "mouse_any_flag" Ta "" Ta "Pane mouse any flag"
.It Li "mouse_button_flag" Ta "" Ta "Pane mouse button flag"
+.It Li "mouse_line" Ta "" Ta "Line under mouse, if any"
+.It Li "mouse_sgr_flag" Ta "" Ta "Pane mouse SGR flag"
.It Li "mouse_standard_flag" Ta "" Ta "Pane mouse standard flag"
+.It Li "mouse_utf8_flag" Ta "" Ta "Pane mouse UTF-8 flag"
+.It Li "mouse_word" Ta "" Ta "Word under mouse, if any"
.It Li "mouse_x" Ta "" Ta "Mouse X position, if any"
.It Li "mouse_y" Ta "" Ta "Mouse Y position, if any"
-.It Li "mouse_word" Ta "" Ta "Word under mouse, if any"
-.It Li "mouse_line" Ta "" Ta "Line under mouse, if any"
+.It Li "origin_flag" Ta "" Ta "Pane origin flag"
.It Li "pane_active" Ta "" Ta "1 if active pane"
.It Li "pane_at_bottom" Ta "" Ta "1 if pane is at the bottom of window"
.It Li "pane_at_left" Ta "" Ta "1 if pane is at the left of window"
@@ -4184,19 +4224,19 @@ The following variables are available, where appropriate:
.It Li "pane_format" Ta "" Ta "1 if format is for a pane (not assuming the current)"
.It Li "pane_height" Ta "" Ta "Height of pane"
.It Li "pane_id" Ta "#D" Ta "Unique pane ID"
-.It Li "pane_in_mode" Ta "" Ta "If pane is in a mode"
+.It Li "pane_in_mode" Ta "" Ta "1 if pane is in a mode"
.It Li "pane_index" Ta "#P" Ta "Index of pane"
-.It Li "pane_input_off" Ta "" Ta "If input to pane is disabled"
+.It Li "pane_input_off" Ta "" Ta "1 if input to pane is disabled"
.It Li "pane_left" Ta "" Ta "Left of pane"
.It Li "pane_marked" Ta "" Ta "1 if this is the marked pane"
.It Li "pane_marked_set" Ta "" Ta "1 if a marked pane is set"
-.It Li "pane_mode" Ta "" Ta "Name of pane mode, if any."
+.It Li "pane_mode" Ta "" Ta "Name of pane mode, if any"
.It Li "pane_pid" Ta "" Ta "PID of first process in pane"
.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_start_command" Ta "" Ta "Command pane started with"
-.It Li "pane_synchronized" Ta "" Ta "If pane is synchronized"
+.It Li "pane_synchronized" Ta "" Ta "1 if pane is synchronized"
.It Li "pane_tabs" Ta "" Ta "Pane tab positions"
.It Li "pane_title" Ta "#T" Ta "Title of pane"
.It Li "pane_top" Ta "" Ta "Top of pane"
@@ -4325,10 +4365,12 @@ to unset.
.Ic align=right
.Xc
Align text to the left, centre or right of the available space if appropriate.
+.It Ic fill=colour
+Fill the available space with a background colour if appropriate.
.It Xo Ic list=on ,
.Ic list=focus ,
.Ic list=left-marker ,
-.Ic list=right=marker ,
+.Ic list=right-marker ,
.Ic nolist
.Xc
Mark the position of the various window list components in the
@@ -4560,7 +4602,7 @@ session option.
Commands related to the status line are as follows:
.Bl -tag -width Ds
.It Xo Ic command-prompt
-.Op Fl 1i
+.Op Fl 1Ni
.Op Fl I Ar inputs
.Op Fl p Ar prompts
.Op Fl t Ar target-client
@@ -4610,6 +4652,8 @@ but any quotation marks are escaped.
.Fl 1
makes the prompt only accept one key press, in this case the resulting input
is a single character.
+.Fl N
+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.
@@ -4621,7 +4665,7 @@ 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 "Delete current word" Ta "" Ta "C-w"
+.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"
.It Li "Execute command" Ta "Enter" Ta "Enter"
@@ -4739,8 +4783,7 @@ section; information is taken from
.Ar target-pane
if
.Fl t
-is given, otherwise the active pane for the session attached to
-.Ar target-client .
+is given, otherwise the active pane.
.Pp
.Fl v
prints verbose logging as the format is parsed and
@@ -5032,11 +5075,33 @@ $ printf '\e033]12;red\e033\e\e'
.Ed
.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 underline.
-The single parameter is one of: 0 for no underline, 1 for normal
-underline, 2 for double underline, 3 for curly underline, 4 for dotted
-underline and 5 for dashed underline.
+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
diff --git a/tmux.c b/tmux.c
index 685827d4..f9de920c 100644
--- a/tmux.c
+++ b/tmux.c
@@ -321,11 +321,11 @@ main(int argc, char **argv)
global_s_options = options_create(NULL);
global_w_options = options_create(NULL);
for (oe = options_table; oe->name != NULL; oe++) {
- if (oe->scope == OPTIONS_TABLE_SERVER)
+ if (oe->scope & OPTIONS_TABLE_SERVER)
options_default(global_options, oe);
- if (oe->scope == OPTIONS_TABLE_SESSION)
+ if (oe->scope & OPTIONS_TABLE_SESSION)
options_default(global_s_options, oe);
- if (oe->scope == OPTIONS_TABLE_WINDOW)
+ if (oe->scope & OPTIONS_TABLE_WINDOW)
options_default(global_w_options, oe);
}
diff --git a/tmux.h b/tmux.h
index 3aa6aa81..5c10420a 100644
--- a/tmux.h
+++ b/tmux.h
@@ -113,9 +113,10 @@ struct winlink;
#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)
+#define KEYC_MASK_MOD (KEYC_ESCAPE|KEYC_CTRL|KEYC_SHIFT|KEYC_XTERM|KEYC_LITERAL)
#define KEYC_MASK_KEY (~KEYC_MASK_MOD)
/* Is this a mouse key? */
@@ -429,6 +430,7 @@ enum tty_code_code {
TTYC_SETAF,
TTYC_SETRGBB,
TTYC_SETRGBF,
+ TTYC_SETULC,
TTYC_SGR0,
TTYC_SITM,
TTYC_SMACS,
@@ -597,12 +599,13 @@ enum utf8_state {
/* Grid cell data. */
struct grid_cell {
- u_char flags;
+ struct utf8_data data; /* 21 bytes */
u_short attr;
+ u_char flags;
int fg;
int bg;
- struct utf8_data data;
-};
+ int us;
+} __packed;
struct grid_cell_entry {
u_char flags;
union {
@@ -682,6 +685,7 @@ TAILQ_HEAD(style_ranges, style_range);
struct style {
struct grid_cell gc;
+ int fill;
enum style_align align;
enum style_list list;
@@ -812,6 +816,7 @@ struct window_pane {
u_int active_point;
struct window *window;
+ struct options *options;
struct layout_cell *layout_cell;
struct layout_cell *saved_layout_cell;
@@ -838,6 +843,7 @@ struct window_pane {
#define PANE_STATUSREADY 0x200
#define PANE_STATUSDRAWN 0x400
#define PANE_EMPTY 0x800
+#define PANE_STYLECHANGED 0x1000
int argc;
char **argv;
@@ -856,7 +862,8 @@ struct window_pane {
struct input_ctx *ictx;
- struct style style;
+ struct style cached_style;
+ struct style cached_active_style;
int *palette;
int pipe_fd;
@@ -916,7 +923,6 @@ struct window {
#define WINDOW_ACTIVITY 0x2
#define WINDOW_SILENCE 0x4
#define WINDOW_ZOOMED 0x8
-#define WINDOW_STYLECHANGED 0x10
#define WINDOW_ALERTFLAGS (WINDOW_BELL|WINDOW_ACTIVITY|WINDOW_SILENCE)
int alerts_queued;
@@ -924,9 +930,6 @@ struct window {
struct options *options;
- struct style style;
- struct style active_style;
-
u_int references;
TAILQ_HEAD(, winlink) winlinks;
@@ -958,6 +961,11 @@ TAILQ_HEAD(winlink_stack, winlink);
#define WINDOW_SIZE_SMALLEST 1
#define WINDOW_SIZE_MANUAL 2
+/* Pane border status option. */
+#define PANE_STATUS_OFF 0
+#define PANE_STATUS_TOP 1
+#define PANE_STATUS_BOTTOM 2
+
/* Layout direction. */
enum layout_type {
LAYOUT_LEFTRIGHT,
@@ -1326,6 +1334,7 @@ struct cmd_parse_input {
#define CMD_PARSE_QUIET 0x1
#define CMD_PARSE_PARSEONLY 0x2
#define CMD_PARSE_NOALIAS 0x4
+#define CMD_PARSE_VERBOSE 0x8
const char *file;
u_int line;
@@ -1491,7 +1500,7 @@ struct client {
#define CLIENT_REPEAT 0x20
#define CLIENT_SUSPENDED 0x40
#define CLIENT_ATTACHED 0x80
-/* 0x100 unused */
+#define CLIENT_EXITED 0x100
#define CLIENT_DEAD 0x200
#define CLIENT_REDRAWBORDERS 0x400
#define CLIENT_READONLY 0x800
@@ -1509,6 +1518,7 @@ struct client {
#define CLIENT_STATUSOFF 0x800000
#define CLIENT_REDRAWSTATUSALWAYS 0x1000000
#define CLIENT_REDRAWOVERLAY 0x2000000
+#define CLIENT_CONTROL_NOOUTPUT 0x4000000
#define CLIENT_ALLREDRAWFLAGS \
(CLIENT_REDRAWWINDOW| \
CLIENT_REDRAWSTATUS| \
@@ -1606,12 +1616,11 @@ enum options_table_type {
OPTIONS_TABLE_COMMAND
};
-enum options_table_scope {
- OPTIONS_TABLE_NONE,
- OPTIONS_TABLE_SERVER,
- OPTIONS_TABLE_SESSION,
- OPTIONS_TABLE_WINDOW
-};
+#define OPTIONS_TABLE_NONE 0
+#define OPTIONS_TABLE_SERVER 0x1
+#define OPTIONS_TABLE_SESSION 0x2
+#define OPTIONS_TABLE_WINDOW 0x4
+#define OPTIONS_TABLE_PANE 0x8
#define OPTIONS_TABLE_IS_ARRAY 0x1
#define OPTIONS_TABLE_IS_HOOK 0x2
@@ -1619,7 +1628,7 @@ enum options_table_scope {
struct options_table_entry {
const char *name;
enum options_table_type type;
- enum options_table_scope scope;
+ int scope;
int flags;
u_int minimum;
@@ -1781,6 +1790,7 @@ void notify_pane(const char *, struct window_pane *);
/* options.c */
struct options *options_create(struct options *);
void options_free(struct options *);
+void options_set_parent(struct options *, struct options *);
struct options_entry *options_first(struct options *);
struct options_entry *options_next(struct options_entry *);
struct options_entry *options_empty(struct options *,
@@ -1820,7 +1830,10 @@ 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 *);
-enum options_table_scope options_scope_from_flags(struct args *, int,
+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 **);
/* options-table.c */
@@ -2011,7 +2024,7 @@ extern const struct cmd_entry *cmd_table[];
/* cmd-attach-session.c */
enum cmd_retval cmd_attach_session(struct cmdq_item *, const char *, int, int,
- const char *, int);
+ int, const char *, int);
/* cmd-parse.c */
void cmd_parse_empty(struct cmd_parse_input *);
@@ -2038,6 +2051,7 @@ void cmdq_insert_after(struct cmdq_item *, struct cmdq_item *);
void 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 *);
@@ -2187,7 +2201,8 @@ int colour_join_rgb(u_char, u_char, u_char);
void colour_split_rgb(int, u_char *, u_char *, u_char *);
const char *colour_tostring(int);
int colour_fromstring(const char *s);
-u_char colour_256to16(u_char);
+int colour_256toRGB(int);
+int colour_256to16(int);
/* attributes.c */
const char *attributes_tostring(int);
@@ -2352,7 +2367,6 @@ struct window *window_find_by_id_str(const char *);
struct window *window_find_by_id(u_int);
void window_update_activity(struct window *);
struct window *window_create(u_int, u_int);
-void window_destroy(struct window *);
void window_pane_set_event(struct window_pane *);
struct window_pane *window_get_active_at(struct window *, u_int, u_int);
struct window_pane *window_find_string(struct window *, const char *);
@@ -2397,7 +2411,8 @@ void window_pane_key(struct window_pane *, struct client *,
struct session *, struct winlink *, key_code,
struct mouse_event *);
int window_pane_visible(struct window_pane *);
-u_int window_pane_search(struct window_pane *, const char *);
+u_int window_pane_search(struct window_pane *, const char *, int,
+ int);
const char *window_printable_flags(struct winlink *);
struct window_pane *window_pane_find_up(struct window_pane *);
struct window_pane *window_pane_find_down(struct window_pane *);
@@ -2425,7 +2440,7 @@ void layout_set_size(struct layout_cell *, u_int, u_int, u_int,
u_int);
void layout_make_leaf(struct layout_cell *, struct window_pane *);
void layout_make_node(struct layout_cell *, enum layout_type);
-void layout_fix_offsets(struct layout_cell *);
+void layout_fix_offsets(struct window *);
void layout_fix_panes(struct window *);
void layout_resize_adjust(struct window *, struct layout_cell *,
enum layout_type, int);
@@ -2634,4 +2649,7 @@ int style_is_default(struct style *);
struct winlink *spawn_window(struct spawn_context *, char **);
struct window_pane *spawn_pane(struct spawn_context *, char **);
+/* regsub.c */
+char *regsub(const char *, const char *, const char *, int);
+
#endif /* TMUX_H */
diff --git a/tty-term.c b/tty-term.c
index b3fc8e0d..eabadf6b 100644
--- a/tty-term.c
+++ b/tty-term.c
@@ -249,6 +249,7 @@ static const struct tty_term_code_entry tty_term_codes[] = {
[TTYC_SETAF] = { TTYCODE_STRING, "setaf" },
[TTYC_SETRGBB] = { TTYCODE_STRING, "setrgbb" },
[TTYC_SETRGBF] = { TTYCODE_STRING, "setrgbf" },
+ [TTYC_SETULC] = { TTYCODE_STRING, "Setulc" },
[TTYC_SE] = { TTYCODE_STRING, "Se" },
[TTYC_SGR0] = { TTYCODE_STRING, "sgr0" },
[TTYC_SITM] = { TTYCODE_STRING, "sitm" },
@@ -691,7 +692,7 @@ tty_term_describe(struct tty_term *term, enum tty_code_code code)
break;
case TTYCODE_STRING:
strnvis(out, term->codes[code].value.string, sizeof out,
- VIS_OCTAL|VIS_TAB|VIS_NL);
+ VIS_OCTAL|VIS_CSTYLE|VIS_TAB|VIS_NL);
xsnprintf(s, sizeof s, "%4u: %s: (string) %s",
code, tty_term_codes[code].name,
out);
diff --git a/tty.c b/tty.c
index 34403a1f..ab1da9fd 100644
--- a/tty.c
+++ b/tty.c
@@ -49,8 +49,11 @@ 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_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 *);
static void tty_region_pane(struct tty *, const struct tty_ctx *, u_int,
u_int);
@@ -527,6 +530,12 @@ tty_putc(struct tty *tty, u_char ch)
{
const char *acs;
+ if ((tty->term->flags & TERM_EARLYWRAP) &&
+ ch >= 0x20 && ch != 0x7f &&
+ tty->cy == tty->sy - 1 &&
+ tty->cx + 1 >= tty->sx)
+ return;
+
if (tty->cell.attr & GRID_ATTR_CHARSET) {
acs = tty_acs_get(tty, ch);
if (acs != NULL)
@@ -557,6 +566,11 @@ tty_putc(struct tty *tty, u_char ch)
void
tty_putn(struct tty *tty, const void *buf, size_t len, u_int width)
{
+ if ((tty->term->flags & TERM_EARLYWRAP) &&
+ tty->cy == tty->sy - 1 &&
+ tty->cx + len >= tty->sx)
+ len = tty->sx - tty->cx - 1;
+
tty_add(tty, buf, len);
if (tty->cx + width > tty->sx) {
tty->cx = (tty->cx + width) - tty->sx;
@@ -1049,17 +1063,17 @@ tty_clamp_area(struct tty *tty, const struct tty_ctx *ctx, u_int px, u_int py,
*y = ctx->yoff + py - ctx->oy;
*ry = ny;
} else if (yoff < ctx->oy && yoff + ny > ctx->oy + ctx->sy) {
- /* Both left and right not visible. */
+ /* Both top and bottom not visible. */
*j = ctx->oy;
*y = 0;
*ry = ctx->sy;
} else if (yoff < ctx->oy) {
- /* Left not visible. */
+ /* Top not visible. */
*j = ctx->oy - (ctx->yoff + py);
*y = 0;
*ry = ny - *j;
} else {
- /* Right not visible. */
+ /* Bottom not visible. */
*j = 0;
*y = (ctx->yoff + py) - ctx->oy;
*ry = ctx->sy - *y;
@@ -1203,7 +1217,7 @@ tty_draw_line(struct tty *tty, struct window_pane *wp, struct screen *s,
const struct grid_cell *gcp;
struct grid_line *gl;
u_int i, j, ux, sx, width;
- int flags, cleared = 0;
+ int flags, cleared = 0, wrapped = 0;
char buf[512];
size_t len;
u_int cellsize;
@@ -1260,8 +1274,10 @@ tty_draw_line(struct tty *tty, struct window_pane *wp, struct screen *s,
tty_putcode(tty, TTYC_EL1);
cleared = 1;
}
- } else
+ } else {
log_debug("%s: wrapped line %u", __func__, aty);
+ wrapped = 1;
+ }
memcpy(&last, &grid_default_cell, sizeof last);
len = 0;
@@ -1276,6 +1292,7 @@ tty_draw_line(struct tty *tty, struct window_pane *wp, struct screen *s,
gcp->attr != last.attr ||
gcp->fg != last.fg ||
gcp->bg != last.bg ||
+ gcp->us != last.us ||
ux + width + gcp->data.width > nx ||
(sizeof buf) - len < gcp->data.size)) {
tty_attributes(tty, &last, wp);
@@ -1284,13 +1301,15 @@ tty_draw_line(struct tty *tty, struct window_pane *wp, struct screen *s,
tty_clear_line(tty, wp, aty, atx + ux, width,
last.bg);
} else {
- tty_cursor(tty, atx + ux, aty);
+ if (!wrapped || atx != 0 || ux != 0)
+ tty_cursor(tty, atx + ux, aty);
tty_putn(tty, buf, len, width);
}
ux += width;
len = 0;
width = 0;
+ wrapped = 0;
}
if (gcp->flags & GRID_FLAG_SELECTED)
@@ -1324,7 +1343,8 @@ tty_draw_line(struct tty *tty, struct window_pane *wp, struct screen *s,
log_debug("%s: %zu cleared (end)", __func__, len);
tty_clear_line(tty, wp, aty, atx + ux, width, last.bg);
} else {
- tty_cursor(tty, atx + ux, aty);
+ if (!wrapped || atx != 0 || ux != 0)
+ tty_cursor(tty, atx + ux, aty);
tty_putn(tty, buf, len, width);
}
ux += width;
@@ -2121,10 +2141,11 @@ tty_attributes(struct tty *tty, const struct grid_cell *gc,
/* Ignore cell if it is the same as the last one. */
if (wp != NULL &&
(int)wp->id == tty->last_wp &&
- ~(wp->window->flags & WINDOW_STYLECHANGED) &&
+ ~(wp->flags & PANE_STYLECHANGED) &&
gc->attr == tty->last_cell.attr &&
gc->fg == tty->last_cell.fg &&
- gc->bg == tty->last_cell.bg)
+ 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);
@@ -2152,14 +2173,18 @@ 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);
- /* If any bits are being cleared, reset everything. */
- if (tc->attr & ~gc2.attr)
+ /*
+ * If any bits are being cleared or the underline colour is now default,
+ * reset everything.
+ */
+ if ((tc->attr & ~gc2.attr) || (tc->us != gc2.us && gc2.us == 0))
tty_reset(tty);
/*
* Set the colours. This may call tty_reset() (so it comes next) and
- * may add to (NOT remove) the desired attributes by changing new_attr.
+ * may add to (NOT remove) the desired attributes.
*/
tty_colours(tty, &gc2);
@@ -2212,7 +2237,7 @@ tty_colours(struct tty *tty, const struct grid_cell *gc)
int have_ax;
/* No changes? Nothing is necessary. */
- if (gc->fg == tc->fg && gc->bg == tc->bg)
+ if (gc->fg == tc->fg && gc->bg == tc->bg && gc->us == tc->us)
return;
/*
@@ -2260,6 +2285,10 @@ tty_colours(struct tty *tty, const struct grid_cell *gc)
*/
if (!COLOUR_DEFAULT(gc->bg) && gc->bg != tc->bg)
tty_colours_bg(tty, gc);
+
+ /* Set the underscore color. */
+ if (gc->us != tc->us)
+ tty_colours_us(tty, gc);
}
static void
@@ -2375,6 +2404,22 @@ 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)
+{
+ 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)
+ gc->us = c;
+ }
+
+ /* Underscore colour is set as RGB so convert a 256 colour to RGB. */
+ if (gc->us & COLOUR_FLAG_256)
+ gc->us = colour_256toRGB (gc->us);
+}
+
+static void
tty_colours_fg(struct tty *tty, const struct grid_cell *gc)
{
struct grid_cell *tc = &tty->cell;
@@ -2438,6 +2483,31 @@ save_bg:
tc->bg = gc->bg;
}
+static void
+tty_colours_us(struct tty *tty, const struct grid_cell *gc)
+{
+ struct grid_cell *tc = &tty->cell;
+ u_int c;
+ u_char r, g, b;
+
+ /* Must be an RGB colour - this should never happen. */
+ if (~gc->us & COLOUR_FLAG_RGB)
+ return;
+
+ /*
+ * Setulc follows the ncurses(3) one argument "direct colour"
+ * capability format. Calculate the colour value.
+ */
+ colour_split_rgb(gc->us, &r, &g, &b);
+ c = (65536 * r) + (256 * g) + b;
+
+ /* Write the colour. */
+ tty_putcode1(tty, TTYC_SETULC, c);
+
+ /* Save the new values in the terminal current cell. */
+ tc->us = gc->us;
+}
+
static int
tty_try_colour(struct tty *tty, int colour, const char *type)
{
@@ -2503,30 +2573,28 @@ fallback_256:
static void
tty_default_colours(struct grid_cell *gc, struct window_pane *wp)
{
- struct window *w = wp->window;
- struct options *oo = w->options;
- struct style *active, *pane, *window;
- int c;
-
- if (w->flags & WINDOW_STYLECHANGED) {
- w->flags &= ~WINDOW_STYLECHANGED;
- active = options_get_style(oo, "window-active-style");
- style_copy(&w->active_style, active);
- window = options_get_style(oo, "window-style");
- style_copy(&w->style, window);
+ struct options *oo = wp->options;
+ struct style *style, *active_style;
+ int c;
+
+ 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 = &w->active_style;
- window = &w->style;
+ active_style = &wp->cached_active_style;
+ style = &wp->cached_style;
}
- pane = &wp->style;
if (gc->fg == 8) {
- if (pane->gc.fg != 8)
- gc->fg = pane->gc.fg;
- else if (wp == w->active && active->gc.fg != 8)
- gc->fg = active->gc.fg;
+ if (wp == wp->window->active && active_style->gc.fg != 8)
+ gc->fg = active_style->gc.fg;
else
- gc->fg = window->gc.fg;
+ gc->fg = style->gc.fg;
if (gc->fg != 8) {
c = window_pane_get_palette(wp, gc->fg);
@@ -2536,12 +2604,10 @@ tty_default_colours(struct grid_cell *gc, struct window_pane *wp)
}
if (gc->bg == 8) {
- if (pane->gc.bg != 8)
- gc->bg = pane->gc.bg;
- else if (wp == w->active && active->gc.bg != 8)
- gc->bg = active->gc.bg;
+ if (wp == wp->window->active && active_style->gc.bg != 8)
+ gc->bg = active_style->gc.bg;
else
- gc->bg = window->gc.bg;
+ gc->bg = style->gc.bg;
if (gc->bg != 8) {
c = window_pane_get_palette(wp, gc->bg);
diff --git a/window-buffer.c b/window-buffer.c
index d65916b5..224dfedb 100644
--- a/window-buffer.c
+++ b/window-buffer.c
@@ -245,7 +245,7 @@ window_buffer_draw(__unused void *modedata, void *itemdata,
at = 0;
while (end != pdata + psize && *end != '\n') {
if ((sizeof line) - at > 5) {
- cp = vis(line + at, *end, VIS_TAB|VIS_OCTAL, 0);
+ cp = vis(line + at, *end, VIS_OCTAL|VIS_TAB, 0);
at = cp - line;
}
end++;
diff --git a/window-copy.c b/window-copy.c
index d81073bf..d868631c 100644
--- a/window-copy.c
+++ b/window-copy.c
@@ -577,6 +577,7 @@ 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;
struct screen_write_ctx ctx;
+ int search;
screen_resize(s, sx, sy, 1);
if (data->backing != &wp->base)
@@ -589,13 +590,15 @@ window_copy_resize(struct window_mode_entry *wme, u_int sx, u_int sy)
if (data->oy > screen_hsize(data->backing))
data->oy = screen_hsize(data->backing);
+ 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_stop(&ctx);
- if (data->searchmark != NULL)
+ if (search)
window_copy_search_marks(wme, NULL);
data->searchx = data->cx;
data->searchy = data->cy;
@@ -2700,7 +2703,7 @@ window_copy_append_selection(struct window_mode_entry *wme)
struct window_pane *wp = wme->wp;
char *buf;
struct paste_buffer *pb;
- const char *bufdata, *bufname;
+ const char *bufdata, *bufname = NULL;
size_t len, bufsize;
struct screen_write_ctx ctx;
@@ -3027,8 +3030,8 @@ window_copy_cursor_up(struct window_mode_entry *wme, int scroll_only)
if (data->lineflag == LINE_SEL_LEFT_RIGHT && oy == data->sely)
window_copy_other_end(wme);
- data->cx = data->lastcx;
if (scroll_only || data->cy == 0) {
+ data->cx = data->lastcx;
window_copy_scroll_down(wme, 1);
if (scroll_only) {
if (data->cy == screen_size_y(s) - 1)
@@ -3037,7 +3040,7 @@ window_copy_cursor_up(struct window_mode_entry *wme, int scroll_only)
window_copy_redraw_lines(wme, data->cy, 2);
}
} else {
- window_copy_update_cursor(wme, data->cx, data->cy - 1);
+ window_copy_update_cursor(wme, data->lastcx, data->cy - 1);
if (window_copy_update_selection(wme, 1)) {
if (data->cy == screen_size_y(s) - 1)
window_copy_redraw_lines(wme, data->cy, 1);
@@ -3077,13 +3080,13 @@ window_copy_cursor_down(struct window_mode_entry *wme, int scroll_only)
if (data->lineflag == LINE_SEL_RIGHT_LEFT && oy == data->endsely)
window_copy_other_end(wme);
- data->cx = data->lastcx;
if (scroll_only || data->cy == screen_size_y(s) - 1) {
+ data->cx = data->lastcx;
window_copy_scroll_up(wme, 1);
if (scroll_only && data->cy > 0)
window_copy_redraw_lines(wme, data->cy - 1, 2);
} else {
- window_copy_update_cursor(wme, data->cx, data->cy + 1);
+ window_copy_update_cursor(wme, data->lastcx, data->cy + 1);
if (window_copy_update_selection(wme, 1))
window_copy_redraw_lines(wme, data->cy - 1, 2);
}
diff --git a/window.c b/window.c
index 1b30c793..409f1df5 100644
--- a/window.c
+++ b/window.c
@@ -19,9 +19,11 @@
#include <sys/types.h>
#include <sys/ioctl.h>
+#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <fnmatch.h>
+#include <regex.h>
#include <signal.h>
#include <stdint.h>
#include <stdlib.h>
@@ -310,7 +312,7 @@ window_create(u_int sx, u_int sy)
w = xcalloc(1, sizeof *w);
w->name = NULL;
- w->flags = WINDOW_STYLECHANGED;
+ w->flags = 0;
TAILQ_INIT(&w->panes);
w->active = NULL;
@@ -334,7 +336,7 @@ window_create(u_int sx, u_int sy)
return (w);
}
-void
+static void
window_destroy(struct window *w)
{
log_debug("window @%u destroyed (%d references)", w->id, w->references);
@@ -408,6 +410,7 @@ window_set_name(struct window *w, const char *new_name)
void
window_resize(struct window *w, u_int sx, u_int sy)
{
+ log_debug("%s: @%u resize %ux%u", __func__, w->id, sx, sy);
w->sx = sx;
w->sy = sy;
}
@@ -447,31 +450,37 @@ 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 *sy;
+ struct style *sy1, *sy2;
+ int c1, c2;
if (wp == w->active)
return;
- /*
- * If window-style and window-active-style are the same, we don't need
- * to redraw panes when switching active panes.
- */
- sy = options_get_style(w->options, "window-active-style");
- if (style_equal(sy, options_get_style(w->options, "window-style")))
- return;
-
- /*
- * If the now active or inactive pane do not have a custom style or if
- * the palette is different, they need to be redrawn.
- */
- if (window_pane_get_palette(w->active, w->active->style.gc.fg) != -1 ||
- window_pane_get_palette(w->active, w->active->style.gc.bg) != -1 ||
- style_is_default(&w->active->style))
- w->active->flags |= PANE_REDRAW;
- if (window_pane_get_palette(wp, wp->style.gc.fg) != -1 ||
- window_pane_get_palette(wp, wp->style.gc.bg) != -1 ||
- style_is_default(&wp->style))
- wp->flags |= PANE_REDRAW;
+ for (;;) {
+ /*
+ * 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))
+ wp->flags |= PANE_REDRAW;
+ else {
+ c1 = window_pane_get_palette(wp, sy1->gc.fg);
+ c2 = window_pane_get_palette(wp, sy2->gc.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);
+ if (c1 != c2)
+ wp->flags |= PANE_REDRAW;
+ }
+ }
+ if (wp == w->active)
+ break;
+ wp = w->active;
+ }
}
struct window_pane *
@@ -775,6 +784,8 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit)
wp = xcalloc(1, sizeof *wp);
wp->window = w;
+ wp->options = options_create(w->options);
+ wp->flags = PANE_STYLECHANGED;
wp->id = next_window_pane_id++;
RB_INSERT(window_pane_tree, &all_window_panes, wp);
@@ -802,8 +813,8 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit)
wp->pipe_event = NULL;
wp->saved_grid = NULL;
-
- style_set(&wp->style, &grid_default_cell);
+ wp->saved_cx = UINT_MAX;
+ wp->saved_cy = UINT_MAX;
screen_init(&wp->base, sx, sy, hlimit);
wp->screen = &wp->base;
@@ -850,6 +861,7 @@ window_pane_destroy(struct window_pane *wp)
RB_REMOVE(window_pane_tree, &all_window_panes, wp);
+ options_free(wp->options);
free((void *)wp->cwd);
free(wp->shell);
cmd_free_argv(wp->argc, wp->argv);
@@ -913,6 +925,7 @@ window_pane_resize(struct window_pane *wp, u_int sx, u_int sy)
wp->sx = sx;
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);
wme = TAILQ_FIRST(&wp->modes);
@@ -935,7 +948,7 @@ window_pane_alternate_on(struct window_pane *wp, struct grid_cell *gc,
if (wp->saved_grid != NULL)
return;
- if (!options_get_number(wp->window->options, "alternate-screen"))
+ if (!options_get_number(wp->options, "alternate-screen"))
return;
sx = screen_size_x(s);
sy = screen_size_y(s);
@@ -963,9 +976,24 @@ window_pane_alternate_off(struct window_pane *wp, struct grid_cell *gc,
struct screen *s = &wp->base;
u_int sx, sy;
- if (wp->saved_grid == NULL)
+ if (!options_get_number(wp->options, "alternate-screen"))
return;
- if (!options_get_number(wp->window->options, "alternate-screen"))
+
+ /*
+ * 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);
@@ -977,17 +1005,8 @@ window_pane_alternate_off(struct window_pane *wp, struct grid_cell *gc,
if (sy > wp->saved_grid->sy)
screen_resize(s, sx, wp->saved_grid->sy, 1);
- /* Restore the grid, cursor position and cell. */
+ /* Restore the saved grid. */
grid_duplicate_lines(s->grid, screen_hsize(s), wp->saved_grid, 0, sy);
- if (cursor)
- s->cx = wp->saved_cx;
- if (s->cx > screen_size_x(s) - 1)
- s->cx = screen_size_x(s) - 1;
- if (cursor)
- s->cy = wp->saved_cy;
- if (s->cy > screen_size_y(s) - 1)
- s->cy = screen_size_y(s) - 1;
- memcpy(gc, &wp->saved_cell, sizeof *gc);
/*
* Turn history back on (so resize can use it) and then resize back to
@@ -1137,7 +1156,7 @@ window_pane_reset_mode(struct window_pane *wp)
} else {
log_debug("%s: next mode is %s", __func__, next->mode->name);
wp->screen = next->screen;
- if (next != NULL && next->mode->resize != NULL)
+ if (next->mode->resize != NULL)
next->mode->resize(next, wp->sx, wp->sy);
}
wp->flags |= (PANE_REDRAW|PANE_CHANGED);
@@ -1199,24 +1218,48 @@ window_pane_visible(struct window_pane *wp)
}
u_int
-window_pane_search(struct window_pane *wp, const char *searchstr)
+window_pane_search(struct window_pane *wp, const char *term, int regex,
+ int ignore)
{
struct screen *s = &wp->base;
- char *newsearchstr, *line;
+ regex_t r;
+ char *new = NULL, *line;
u_int i;
+ int flags = 0, found;
+ size_t n;
- xasprintf(&newsearchstr, "*%s*", searchstr);
+ if (!regex) {
+ if (ignore)
+ flags |= FNM_CASEFOLD;
+ xasprintf(&new, "*%s*", term);
+ } else {
+ if (ignore)
+ flags |= REG_ICASE;
+ if (regcomp(&r, term, flags|REG_EXTENDED) != 0)
+ return (0);
+ }
for (i = 0; i < screen_size_y(s); i++) {
line = grid_view_string_cells(s->grid, 0, i, screen_size_x(s));
- if (fnmatch(newsearchstr, line, 0) == 0) {
- free(line);
- break;
+ for (n = strlen(line); n > 0; n--) {
+ if (!isspace((u_char)line[n - 1]))
+ break;
+ line[n - 1] = '\0';
}
+ log_debug("%s: %s", __func__, line);
+ if (!regex)
+ found = (fnmatch(new, line, 0) == 0);
+ else
+ found = (regexec(&r, line, 0, NULL, 0) == 0);
free(line);
+ if (found)
+ break;
}
+ if (!regex)
+ free(new);
+ else
+ regfree(&r);
- free(newsearchstr);
if (i == screen_size_y(s))
return (0);
return (i + 1);
@@ -1248,25 +1291,35 @@ window_pane_choose_best(struct window_pane **list, u_int size)
struct window_pane *
window_pane_find_up(struct window_pane *wp)
{
+ struct window *w;
struct window_pane *next, *best, **list;
u_int edge, left, right, end, size;
int status, found;
if (wp == NULL)
return (NULL);
- status = options_get_number(wp->window->options, "pane-border-status");
+ w = wp->window;
+ status = options_get_number(w->options, "pane-border-status");
list = NULL;
size = 0;
edge = wp->yoff;
- if (edge == (status == 1 ? 1 : 0))
- edge = wp->window->sy + 1 - (status == 2 ? 1 : 0);
+ if (status == PANE_STATUS_TOP) {
+ if (edge == 1)
+ edge = w->sy + 1;
+ } else if (status == PANE_STATUS_BOTTOM) {
+ if (edge == 0)
+ edge = w->sy;
+ } else {
+ if (edge == 0)
+ edge = w->sy + 1;
+ }
left = wp->xoff;
right = wp->xoff + wp->sx;
- TAILQ_FOREACH(next, &wp->window->panes, entry) {
+ TAILQ_FOREACH(next, &w->panes, entry) {
if (next == wp)
continue;
if (next->yoff + next->sy + 1 != edge)
@@ -1295,25 +1348,35 @@ window_pane_find_up(struct window_pane *wp)
struct window_pane *
window_pane_find_down(struct window_pane *wp)
{
+ struct window *w;
struct window_pane *next, *best, **list;
u_int edge, left, right, end, size;
int status, found;
if (wp == NULL)
return (NULL);
- status = options_get_number(wp->window->options, "pane-border-status");
+ w = wp->window;
+ status = options_get_number(w->options, "pane-border-status");
list = NULL;
size = 0;
edge = wp->yoff + wp->sy + 1;
- if (edge >= wp->window->sy - (status == 2 ? 1 : 0))
- edge = (status == 1 ? 1 : 0);
+ if (status == PANE_STATUS_TOP) {
+ if (edge >= w->sy)
+ edge = 1;
+ } else if (status == PANE_STATUS_BOTTOM) {
+ if (edge >= w->sy - 1)
+ edge = 0;
+ } else {
+ if (edge >= w->sy)
+ edge = 0;
+ }
left = wp->xoff;
right = wp->xoff + wp->sx;
- TAILQ_FOREACH(next, &wp->window->panes, entry) {
+ TAILQ_FOREACH(next, &w->panes, entry) {
if (next == wp)
continue;
if (next->yoff != edge)
@@ -1342,24 +1405,26 @@ window_pane_find_down(struct window_pane *wp)
struct window_pane *
window_pane_find_left(struct window_pane *wp)
{
+ struct window *w;
struct window_pane *next, *best, **list;
u_int edge, top, bottom, end, size;
int found;
if (wp == NULL)
return (NULL);
+ w = wp->window;
list = NULL;
size = 0;
edge = wp->xoff;
if (edge == 0)
- edge = wp->window->sx + 1;
+ edge = w->sx + 1;
top = wp->yoff;
bottom = wp->yoff + wp->sy;
- TAILQ_FOREACH(next, &wp->window->panes, entry) {
+ TAILQ_FOREACH(next, &w->panes, entry) {
if (next == wp)
continue;
if (next->xoff + next->sx + 1 != edge)
@@ -1388,24 +1453,26 @@ window_pane_find_left(struct window_pane *wp)
struct window_pane *
window_pane_find_right(struct window_pane *wp)
{
+ struct window *w;
struct window_pane *next, *best, **list;
u_int edge, top, bottom, end, size;
int found;
if (wp == NULL)
return (NULL);
+ w = wp->window;
list = NULL;
size = 0;
edge = wp->xoff + wp->sx + 1;
- if (edge >= wp->window->sx)
+ if (edge >= w->sx)
edge = 0;
top = wp->yoff;
bottom = wp->yoff + wp->sy;
- TAILQ_FOREACH(next, &wp->window->panes, entry) {
+ TAILQ_FOREACH(next, &w->panes, entry) {
if (next == wp)
continue;
if (next->xoff != edge)
@@ -1487,7 +1554,7 @@ window_pane_input_callback(struct client *c, int closed, void *data)
c->stdin_callback = NULL;
server_client_unref(c);
- cdata->item->flags &= ~CMDQ_WAITING;
+ cmdq_continue(cdata->item);
free(cdata);
return;
diff --git a/xmalloc.c b/xmalloc.c
index 22ea3540..f249e397 100644
--- a/xmalloc.c
+++ b/xmalloc.c
@@ -111,7 +111,7 @@ xvasprintf(char **ret, const char *fmt, va_list ap)
i = vasprintf(ret, fmt, ap);
- if (i < 0 || *ret == NULL)
+ if (i == -1)
fatalx("xasprintf: %s", strerror(errno));
return i;