summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortopcat001 <anindya49@hotmail.com>2023-07-22 17:29:10 -0700
committertopcat001 <anindya49@hotmail.com>2023-07-22 17:29:10 -0700
commit14b8b524523a7d5a4e42f7dfa346905c604c91e2 (patch)
tree6422472dfa2f535912f1407bba5f3a848e7a3188
parent4baf76422fadb216bf27b47645b52da3379e7dea (diff)
parentfda393773485c7c9236e4cf0c18668ab809d2574 (diff)
Merge branch 'master' into sixel
-rw-r--r--arguments.c2
-rw-r--r--client.c20
-rw-r--r--cmd-find.c2
-rw-r--r--cmd-resize-window.c3
-rw-r--r--cmd-select-pane.c6
-rw-r--r--cmd-swap-pane.c6
-rw-r--r--configure.ac4
-rw-r--r--format.c8
-rw-r--r--grid.c13
-rw-r--r--hyperlinks.c2
-rw-r--r--input.c32
-rw-r--r--notify.c4
-rw-r--r--popup.c2
-rw-r--r--regsub.c4
-rw-r--r--screen-write.c4
-rw-r--r--screen.c2
-rw-r--r--session.c5
-rw-r--r--spawn.c3
-rw-r--r--style.c15
-rw-r--r--tmux.1357
-rw-r--r--tmux.h13
-rw-r--r--tty-keys.c2
-rw-r--r--tty-term.c4
-rw-r--r--tty.c17
-rw-r--r--utf8.c4
-rw-r--r--window-copy.c73
-rw-r--r--window-tree.c4
-rw-r--r--window.c56
28 files changed, 512 insertions, 155 deletions
diff --git a/arguments.c b/arguments.c
index 387790ac..f3152ddf 100644
--- a/arguments.c
+++ b/arguments.c
@@ -189,7 +189,7 @@ out:
/* Parse flags argument. */
static int
args_parse_flags(const struct args_parse *parse, struct args_value *values,
- u_int count, char **cause, struct args *args, int *i)
+ u_int count, char **cause, struct args *args, u_int *i)
{
struct args_value *value;
u_char flag;
diff --git a/client.c b/client.c
index 374c1146..9cd5ad85 100644
--- a/client.c
+++ b/client.c
@@ -245,9 +245,6 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags,
u_int ncaps = 0;
struct args_value *values;
- /* Ignore SIGCHLD now or daemon() in the server will leave a zombie. */
- signal(SIGCHLD, SIG_IGN);
-
/* Set up the initial command. */
if (shell_command != NULL) {
msg = MSG_SHELL;
@@ -533,11 +530,22 @@ client_signal(int sig)
{
struct sigaction sigact;
int status;
+ pid_t pid;
log_debug("%s: %s", __func__, strsignal(sig));
- if (sig == SIGCHLD)
- waitpid(WAIT_ANY, &status, WNOHANG);
- else if (!client_attached) {
+ if (sig == SIGCHLD) {
+ for (;;) {
+ pid = waitpid(WAIT_ANY, &status, WNOHANG);
+ if (pid == 0)
+ break;
+ if (pid == -1) {
+ if (errno == ECHILD)
+ break;
+ log_debug("waitpid failed: %s",
+ strerror(errno));
+ }
+ }
+ } else if (!client_attached) {
if (sig == SIGTERM || sig == SIGHUP)
proc_exit(client_proc);
} else {
diff --git a/cmd-find.c b/cmd-find.c
index 154cadac..8a3499a1 100644
--- a/cmd-find.c
+++ b/cmd-find.c
@@ -582,7 +582,7 @@ cmd_find_get_pane_with_window(struct cmd_find_state *fs, const char *pane)
/* Try special characters. */
if (strcmp(pane, "!") == 0) {
- fs->wp = fs->w->last;
+ fs->wp = TAILQ_FIRST(&fs->w->last_panes);
if (fs->wp == NULL)
return (-1);
return (0);
diff --git a/cmd-resize-window.c b/cmd-resize-window.c
index ad739165..c420451c 100644
--- a/cmd-resize-window.c
+++ b/cmd-resize-window.c
@@ -53,8 +53,7 @@ cmd_resize_window_exec(struct cmd *self, struct cmdq_item *item)
struct session *s = target->s;
const char *errstr;
char *cause;
- u_int adjust, sx, sy;
- int xpixel = -1, ypixel = -1;
+ u_int adjust, sx, sy, xpixel = 0, ypixel = 0;
if (args_count(args) == 0)
adjust = 1;
diff --git a/cmd-select-pane.c b/cmd-select-pane.c
index ae21d4ce..135729f5 100644
--- a/cmd-select-pane.c
+++ b/cmd-select-pane.c
@@ -98,7 +98,11 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
struct options_entry *o;
if (entry == &cmd_last_pane_entry || args_has(args, 'l')) {
- lastwp = w->last;
+ /*
+ * Check for no last pane found in case the other pane was
+ * spawned without being visited (for example split-window -d).
+ */
+ lastwp = TAILQ_FIRST(&w->last_panes);
if (lastwp == NULL && window_count_panes(w) == 2) {
lastwp = TAILQ_PREV(w->active, window_panes, entry);
if (lastwp == NULL)
diff --git a/cmd-swap-pane.c b/cmd-swap-pane.c
index 80c20c80..6931bd16 100644
--- a/cmd-swap-pane.c
+++ b/cmd-swap-pane.c
@@ -128,10 +128,8 @@ cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item)
window_set_active_pane(dst_w, src_wp, 1);
}
if (src_w != dst_w) {
- if (src_w->last == src_wp)
- src_w->last = NULL;
- if (dst_w->last == dst_wp)
- dst_w->last = NULL;
+ window_pane_stack_remove(&src_w->last_panes, src_wp);
+ window_pane_stack_remove(&dst_w->last_panes, dst_wp);
colour_palette_from_option(&src_wp->palette, src_wp->options);
colour_palette_from_option(&dst_wp->palette, dst_wp->options);
}
diff --git a/configure.ac b/configure.ac
index 4d85624d..ca9b9473 100644
--- a/configure.ac
+++ b/configure.ac
@@ -315,7 +315,7 @@ fi
if test "x$found_ncurses" = xno; then
AC_SEARCH_LIBS(
setupterm,
- [tinfo ncurses ncursesw],
+ [tinfo terminfo ncurses ncursesw],
found_ncurses=yes,
found_ncurses=no
)
@@ -461,7 +461,7 @@ AM_CONDITIONAL(ENABLE_SIXEL, [test "x$enable_sixel" = xyes])
# Check for b64_ntop. If we have b64_ntop, we assume b64_pton as well.
AC_MSG_CHECKING(for b64_ntop)
- AC_LINK_IFELSE([AC_LANG_PROGRAM(
+AC_LINK_IFELSE([AC_LANG_PROGRAM(
[
#include <sys/types.h>
#include <netinet/in.h>
diff --git a/format.c b/format.c
index f69330b2..b20e90a8 100644
--- a/format.c
+++ b/format.c
@@ -1902,7 +1902,7 @@ static void *
format_cb_pane_last(struct format_tree *ft)
{
if (ft->wp != NULL) {
- if (ft->wp == ft->wp->window->last)
+ if (ft->wp == TAILQ_FIRST(&ft->wp->window->last_panes))
return (xstrdup("1"));
return (xstrdup("0"));
}
@@ -3664,7 +3664,9 @@ format_skip(const char *s, const char *end)
for (; *s != '\0'; s++) {
if (*s == '#' && s[1] == '{')
brackets++;
- if (*s == '#' && strchr(",#{}:", s[1]) != NULL) {
+ if (*s == '#' &&
+ s[1] != '\0' &&
+ strchr(",#{}:", s[1]) != NULL) {
s++;
continue;
}
@@ -3813,7 +3815,7 @@ format_build_modifiers(struct format_expand_state *es, const char **s,
argc = 0;
/* Single argument with no wrapper character. */
- if (!ispunct(cp[1]) || cp[1] == '-') {
+ if (!ispunct((u_char)cp[1]) || cp[1] == '-') {
end = format_skip(cp + 1, ":;");
if (end == NULL)
break;
diff --git a/grid.c b/grid.c
index 3afbfb6a..edada819 100644
--- a/grid.c
+++ b/grid.c
@@ -37,7 +37,7 @@
/* Default grid cell data. */
const struct grid_cell grid_default_cell = {
- { { ' ' }, 0, 1, 1 }, 0, 0, 8, 8, 0, 0
+ { { ' ' }, 0, 1, 1 }, 0, 0, 8, 8, 8, 0
};
/*
@@ -45,12 +45,12 @@ const struct grid_cell grid_default_cell = {
* appears in the grid - because of this, they are always extended cells.
*/
static const struct grid_cell grid_padding_cell = {
- { { '!' }, 0, 0, 0 }, 0, GRID_FLAG_PADDING, 8, 8, 0, 0
+ { { '!' }, 0, 0, 0 }, 0, GRID_FLAG_PADDING, 8, 8, 8, 0
};
/* Cleared grid cell data. */
static const struct grid_cell grid_cleared_cell = {
- { { ' ' }, 0, 1, 1 }, 0, GRID_FLAG_CLEARED, 8, 8, 0, 0
+ { { ' ' }, 0, 1, 1 }, 0, GRID_FLAG_CLEARED, 8, 8, 8, 0
};
static const struct grid_cell_entry grid_cleared_entry = {
{ .data = { 0, 8, 8, ' ' } }, GRID_FLAG_CLEARED
@@ -528,7 +528,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;
+ gc->us = 8;
utf8_set(&gc->data, gce->data.data);
gc->link = 0;
}
@@ -956,7 +956,7 @@ grid_string_cells_code(const struct grid_cell *lastgc,
for (i = 0; i < nitems(attrs); i++) {
if (((~attr & attrs[i].mask) &&
(lastattr & attrs[i].mask)) ||
- (lastgc->us != 0 && gc->us == 0)) {
+ (lastgc->us != 8 && gc->us == 8)) {
s[n++] = 0;
lastattr &= GRID_ATTR_CHARSET;
break;
@@ -1044,7 +1044,8 @@ grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx,
const char *data;
char *buf, code[8192];
size_t len, off, size, codelen;
- u_int xx, has_link = 0, end;
+ u_int xx, end;
+ int has_link = 0;
const struct grid_line *gl;
if (lastgc != NULL && *lastgc == NULL) {
diff --git a/hyperlinks.c b/hyperlinks.c
index cde500c0..70c2f4e3 100644
--- a/hyperlinks.c
+++ b/hyperlinks.c
@@ -42,7 +42,7 @@
#define MAX_HYPERLINKS 5000
-static uint64_t hyperlinks_next_external_id = 1;
+static long long hyperlinks_next_external_id = 1;
static u_int global_hyperlinks_count;
struct hyperlinks_uri {
diff --git a/input.c b/input.c
index d32dfd67..324e58f5 100644
--- a/input.c
+++ b/input.c
@@ -144,6 +144,7 @@ static void input_osc_104(struct input_ctx *, const char *);
static void input_osc_110(struct input_ctx *, const char *);
static void input_osc_111(struct input_ctx *, const char *);
static void input_osc_112(struct input_ctx *, const char *);
+static void input_osc_133(struct input_ctx *, const char *);
/* Transition entry/exit handlers. */
static void input_clear(struct input_ctx *);
@@ -2069,7 +2070,7 @@ static void
input_csi_dispatch_sgr(struct input_ctx *ictx)
{
struct grid_cell *gc = &ictx->cell.cell;
- u_int i;
+ u_int i, link;
int n;
if (ictx->param_list_len == 0) {
@@ -2101,7 +2102,9 @@ input_csi_dispatch_sgr(struct input_ctx *ictx)
switch (n) {
case 0:
+ link = gc->link;
memcpy(gc, &grid_default_cell, sizeof *gc);
+ gc->link = link;
break;
case 1:
gc->attr |= GRID_ATTR_BRIGHT;
@@ -2187,7 +2190,7 @@ input_csi_dispatch_sgr(struct input_ctx *ictx)
gc->attr &= ~GRID_ATTR_OVERLINE;
break;
case 59:
- gc->us = 0;
+ gc->us = 8;
break;
case 90:
case 91:
@@ -2363,6 +2366,9 @@ input_exit_osc(struct input_ctx *ictx)
case 112:
input_osc_112(ictx, p);
break;
+ case 133:
+ input_osc_133(ictx, p);
+ break;
default:
log_debug("%s: unknown '%u'", __func__, option);
break;
@@ -2752,6 +2758,24 @@ input_osc_112(struct input_ctx *ictx, const char *p)
screen_set_cursor_colour(ictx->ctx.s, -1);
}
+/* Handle the OSC 133 sequence. */
+static void
+input_osc_133(struct input_ctx *ictx, const char *p)
+{
+ struct grid *gd = ictx->ctx.s->grid;
+ u_int line = ictx->ctx.s->cy + gd->hsize;
+ struct grid_line *gl;
+
+ if (line > gd->hsize + gd->sy - 1)
+ return;
+ gl = grid_get_line(gd, line);
+
+ switch (*p) {
+ case 'A':
+ gl->flags |= GRID_LINE_START_PROMPT;
+ break;
+ }
+}
/* Handle the OSC 52 sequence for setting the clipboard. */
static void
@@ -2858,9 +2882,11 @@ input_reply_clipboard(struct bufferevent *bev, const char *buf, size_t len,
const char *end)
{
char *out = NULL;
- size_t outlen = 0;
+ int outlen = 0;
if (buf != NULL && len != 0) {
+ if (len >= ((size_t)INT_MAX * 3 / 4) - 1)
+ return;
outlen = 4 * ((len + 2) / 3) + 1;
out = xmalloc(outlen);
if ((outlen = b64_ntop(buf, len, out, outlen)) == -1) {
diff --git a/notify.c b/notify.c
index 97919487..d42e2b9d 100644
--- a/notify.c
+++ b/notify.c
@@ -193,7 +193,7 @@ notify_add(const char *name, struct cmd_find_state *fs, struct client *c,
ne->client = c;
ne->session = s;
ne->window = w;
- ne->pane = (wp != NULL ? wp->id : -1);
+ ne->pane = (wp != NULL ? (int)wp->id : -1);
ne->pbname = (pbname != NULL ? xstrdup(pbname) : NULL);
ne->formats = format_create(NULL, NULL, 0, FORMAT_NOJOBS);
@@ -240,7 +240,7 @@ notify_hook(struct cmdq_item *item, const char *name)
ne.client = cmdq_get_client(item);
ne.session = target->s;
ne.window = target->w;
- ne.pane = (target->wp != NULL ? target->wp->id : -1);
+ ne.pane = (target->wp != NULL ? (int)target->wp->id : -1);
ne.formats = format_create(NULL, NULL, 0, FORMAT_NOJOBS);
format_add(ne.formats, "hook", "%s", name);
diff --git a/popup.c b/popup.c
index dc37f002..5686ad17 100644
--- a/popup.c
+++ b/popup.c
@@ -787,6 +787,8 @@ popup_editor(struct client *c, const char *buf, size_t len,
if (fd == -1)
return (-1);
f = fdopen(fd, "w");
+ if (f == NULL)
+ return (-1);
if (fwrite(buf, len, 1, f) != 1) {
fclose(f);
return (-1);
diff --git a/regsub.c b/regsub.c
index 4039b9be..61a9c324 100644
--- a/regsub.c
+++ b/regsub.c
@@ -24,7 +24,7 @@
#include "tmux.h"
static void
-regsub_copy(char **buf, size_t *len, const char *text, size_t start, size_t end)
+regsub_copy(char **buf, ssize_t *len, const char *text, size_t start, size_t end)
{
size_t add = end - start;
@@ -34,7 +34,7 @@ regsub_copy(char **buf, size_t *len, const char *text, size_t start, size_t end)
}
static void
-regsub_expand(char **buf, size_t *len, const char *with, const char *text,
+regsub_expand(char **buf, ssize_t *len, const char *with, const char *text,
regmatch_t *m, u_int n)
{
const char *cp;
diff --git a/screen-write.c b/screen-write.c
index 91750d93..02261a32 100644
--- a/screen-write.c
+++ b/screen-write.c
@@ -326,7 +326,9 @@ screen_write_reset(struct screen_write_ctx *ctx)
screen_reset_tabs(s);
screen_write_scrollregion(ctx, 0, screen_size_y(s) - 1);
- s->mode = MODE_CURSOR | MODE_WRAP;
+ s->mode = MODE_CURSOR|MODE_WRAP;
+ if (options_get_number(global_options, "extended-keys") == 2)
+ s->mode |= MODE_KEXTENDED;
screen_write_clearscreen(ctx, 8);
screen_write_set_cursor(ctx, 0, 0);
diff --git a/screen.c b/screen.c
index a51b17bd..a7c6195b 100644
--- a/screen.c
+++ b/screen.c
@@ -642,7 +642,7 @@ screen_alternate_off(struct screen *s, struct grid_cell *gc, int cursor)
* before copying back.
*/
if (s->saved_grid != NULL)
- screen_resize(s, s->saved_grid->sx, s->saved_grid->sy, 1);
+ screen_resize(s, s->saved_grid->sx, s->saved_grid->sy, 0);
/*
* Restore the cursor position and cell. This happens even if not
diff --git a/session.c b/session.c
index 71435cdf..8432b6ae 100644
--- a/session.c
+++ b/session.c
@@ -737,9 +737,12 @@ session_renumber_windows(struct session *s)
memcpy(&old_lastw, &s->lastw, sizeof old_lastw);
TAILQ_INIT(&s->lastw);
TAILQ_FOREACH(wl, &old_lastw, sentry) {
+ wl->flags &= ~WINLINK_VISITED;
wl_new = winlink_find_by_window(&s->windows, wl->window);
- if (wl_new != NULL)
+ if (wl_new != NULL) {
TAILQ_INSERT_TAIL(&s->lastw, wl_new, sentry);
+ wl_new->flags |= WINLINK_VISITED;
+ }
}
/* Set the current window. */
diff --git a/spawn.c b/spawn.c
index 10604028..d321dba4 100644
--- a/spawn.c
+++ b/spawn.c
@@ -113,6 +113,7 @@ spawn_window(struct spawn_context *sc, char **cause)
window_pane_resize(sc->wp0, w->sx, w->sy);
layout_init(w, sc->wp0);
+ w->active = NULL;
window_set_active_pane(w, sc->wp0, 0);
}
@@ -428,8 +429,8 @@ spawn_pane(struct spawn_context *sc, char **cause)
_exit(1);
/* Clean up file descriptors and signals and update the environment. */
- closefrom(STDERR_FILENO + 1);
proc_clear_signals(server_proc, 1);
+ closefrom(STDERR_FILENO + 1);
sigprocmask(SIG_SETMASK, &oldset, NULL);
log_close();
environ_push(child);
diff --git a/style.c b/style.c
index 8407dc68..3d9d317d 100644
--- a/style.c
+++ b/style.c
@@ -77,6 +77,7 @@ style_parse(struct style *sy, const struct grid_cell *base, const char *in)
if (strcasecmp(tmp, "default") == 0) {
sy->gc.fg = base->fg;
sy->gc.bg = base->bg;
+ sy->gc.us = base->us;
sy->gc.attr = base->attr;
sy->gc.flags = base->flags;
} else if (strcasecmp(tmp, "ignore") == 0)
@@ -162,6 +163,13 @@ style_parse(struct style *sy, const struct grid_cell *base, const char *in)
sy->gc.bg = base->bg;
} else
goto error;
+ } else if (end > 3 && strncasecmp(tmp, "us=", 3) == 0) {
+ if ((value = colour_fromstring(tmp + 3)) == -1)
+ goto error;
+ if (value != 8)
+ sy->gc.us = value;
+ else
+ sy->gc.us = base->us;
} else if (strcasecmp(tmp, "none") == 0)
sy->gc.attr = 0;
else if (end > 2 && strncasecmp(tmp, "no", 2) == 0) {
@@ -258,6 +266,11 @@ style_tostring(struct style *sy)
colour_tostring(gc->bg));
comma = ",";
}
+ if (gc->us != 8) {
+ off += xsnprintf(s + off, sizeof s - off, "%sus=%s", comma,
+ colour_tostring(gc->us));
+ comma = ",";
+ }
if (gc->attr != 0) {
xsnprintf(s + off, sizeof s - off, "%s%s", comma,
attributes_tostring(gc->attr));
@@ -287,6 +300,8 @@ style_add(struct grid_cell *gc, struct options *oo, const char *name,
gc->fg = sy->gc.fg;
if (sy->gc.bg != 8)
gc->bg = sy->gc.bg;
+ if (sy->gc.us != 8)
+ gc->us = sy->gc.us;
gc->attr |= sy->gc.attr;
if (ft0 != NULL)
diff --git a/tmux.1 b/tmux.1
index 7bf2bc4d..7b53740c 100644
--- a/tmux.1
+++ b/tmux.1
@@ -1745,91 +1745,266 @@ Key tables may be viewed with the
command.
.Pp
The following commands are supported in copy mode:
-.Bl -column "CommandXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" "viXXXXXXXXXX" "emacs" -offset indent
-.It Sy "Command" Ta Sy "vi" Ta Sy "emacs"
-.It Li "append-selection" Ta "" Ta ""
-.It Li "append-selection-and-cancel" Ta "A" Ta ""
-.It Li "back-to-indentation" Ta "^" Ta "M-m"
-.It Li "begin-selection" Ta "Space" Ta "C-Space"
-.It Li "bottom-line" Ta "L" Ta ""
-.It Li "cancel" Ta "q" Ta "Escape"
-.It Li "clear-selection" Ta "Escape" Ta "C-g"
-.It Li "copy-end-of-line [<prefix>]" Ta "" Ta ""
-.It Li "copy-end-of-line-and-cancel [<prefix>]" Ta "" Ta ""
-.It Li "copy-pipe-end-of-line [<command>] [<prefix>]" Ta "" Ta ""
-.It Li "copy-pipe-end-of-line-and-cancel [<command>] [<prefix>]" Ta "D" Ta "C-k"
-.It Li "copy-line [<prefix>]" Ta "" Ta ""
-.It Li "copy-line-and-cancel [<prefix>]" Ta "" Ta ""
-.It Li "copy-pipe-line [<command>] [<prefix>]" Ta "" Ta ""
-.It Li "copy-pipe-line-and-cancel [<command>] [<prefix>]" Ta "" Ta ""
-.It Li "copy-pipe [<command>] [<prefix>]" Ta "" Ta ""
-.It Li "copy-pipe-no-clear [<command>] [<prefix>]" Ta "" Ta ""
-.It Li "copy-pipe-and-cancel [<command>] [<prefix>]" Ta "" Ta ""
-.It Li "copy-selection [<prefix>]" Ta "" Ta ""
-.It Li "copy-selection-no-clear [<prefix>]" Ta "" Ta ""
-.It Li "copy-selection-and-cancel [<prefix>]" Ta "Enter" Ta "M-w"
-.It Li "cursor-down" Ta "j" Ta "Down"
-.It Li "cursor-down-and-cancel" Ta "" Ta ""
-.It Li "cursor-left" Ta "h" Ta "Left"
-.It Li "cursor-right" Ta "l" Ta "Right"
-.It Li "cursor-up" Ta "k" Ta "Up"
-.It Li "end-of-line" Ta "$" Ta "C-e"
-.It Li "goto-line <line>" Ta ":" Ta "g"
-.It Li "halfpage-down" Ta "C-d" Ta "M-Down"
-.It Li "halfpage-down-and-cancel" Ta "" Ta ""
-.It Li "halfpage-up" Ta "C-u" Ta "M-Up"
-.It Li "history-bottom" Ta "G" Ta "M->"
-.It Li "history-top" Ta "g" Ta "M-<"
-.It Li "jump-again" Ta ";" Ta ";"
-.It Li "jump-backward <to>" Ta "F" Ta "F"
-.It Li "jump-forward <to>" Ta "f" Ta "f"
-.It Li "jump-reverse" Ta "," Ta ","
-.It Li "jump-to-backward <to>" Ta "T" Ta ""
-.It Li "jump-to-forward <to>" Ta "t" Ta ""
-.It Li "jump-to-mark" Ta "M-x" Ta "M-x"
-.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 ""
-.It Li "next-word" Ta "w" Ta ""
-.It Li "next-word-end" Ta "e" Ta "M-f"
-.It Li "other-end" Ta "o" Ta ""
-.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 "pipe [<command>] [<prefix>]" Ta "" Ta ""
-.It Li "pipe-no-clear [<command>] [<prefix>]" Ta "" Ta ""
-.It Li "pipe-and-cancel [<command>] [<prefix>]" Ta "" Ta ""
-.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"
-.It Li "rectangle-on" Ta "" Ta ""
-.It Li "rectangle-off" Ta "" Ta ""
-.It Li "rectangle-toggle" Ta "v" Ta "R"
-.It Li "refresh-from-pane" Ta "r" Ta "r"
-.It Li "scroll-down" Ta "C-e" Ta "C-Down"
-.It Li "scroll-down-and-cancel" Ta "" Ta ""
-.It Li "scroll-up" Ta "C-y" Ta "C-Up"
-.It Li "search-again" Ta "n" Ta "n"
-.It Li "search-backward <for>" Ta "?" Ta ""
-.It Li "search-backward-incremental <for>" Ta "" Ta "C-r"
-.It Li "search-backward-text <for>" Ta "" Ta ""
-.It Li "search-forward <for>" Ta "/" Ta ""
-.It Li "search-forward-incremental <for>" Ta "" Ta "C-s"
-.It Li "search-forward-text <for>" Ta "" Ta ""
-.It Li "scroll-bottom" Ta "" Ta ""
-.It Li "scroll-middle" Ta "z" Ta ""
-.It Li "scroll-top" Ta "" Ta ""
-.It Li "search-reverse" Ta "N" Ta "N"
-.It Li "select-line" Ta "V" Ta ""
-.It Li "select-word" Ta "" Ta ""
-.It Li "set-mark" Ta "X" Ta "X"
-.It Li "start-of-line" Ta "0" Ta "C-a"
-.It Li "stop-selection" Ta "" Ta ""
-.It Li "toggle-position" Ta "P" Ta "P"
-.It Li "top-line" Ta "H" Ta "M-R"
+.Bl -tag -width Ds
+.It Xo
+.Ic append-selection
+.Xc
+Append the selection to the top paste buffer.
+.It Xo
+.Ic append-selection-and-cancel
+(vi: A)
+.Xc
+Append the selection to the top paste buffer and exit copy mode.
+.It Xo
+.Ic back-to-indentation
+(vi: ^)
+(emacs: M-m)
+.Xc
+Move the cursor back to the indentation.
+.It Xo
+.Ic begin-selection
+(vi: Space)
+(emacs: C-Space)
+.Xc
+Begin selection.
+.It Xo
+.Ic bottom-line
+(vi: L)
+.Xc
+Move to the bottom line.
+.It Xo
+.Ic cancel
+(vi: q)
+(emacs: Escape)
+.Xc
+Exit copy mode.
+.It Xo
+.Ic clear-selection
+(vi: Escape)
+(emacs: C-g)
+.Xc
+Clear the current selection.
+.It Xo
+.Ic copy-end-of-line [<prefix>]
+.Xc
+Copy from the cursor position to the end of the line.
+.Ar prefix
+is used to name the new paste buffer.
+.It Xo
+.Ic copy-end-of-line-and-cancel [<prefix>]
+.Xc
+Copy from the cursor position and exit copy mode.
+.It Xo
+.Ic copy-line [<prefix>]
+.Xc
+Copy the entire line.
+.It Xo
+.Ic copy-line-and-cancel [<prefix>]
+.Xc
+Copy the entire line and exit copy mode.
+.It Xo
+.Ic copy-selection [<prefix>]
+.Xc
+Copies the current selection.
+.It Xo
+.Ic copy-selection-and-cancel [<prefix>]
+(vi: Enter)
+(emacs: M-w)
+.Xc
+Copy the current selection and exit copy mode.
+.It Xo
+.Ic cursor-down
+(vi: j)
+(emacs: Down)
+.Xc
+Move the cursor down.
+.It Xo
+.Ic cursor-left
+(vi: h)
+(emacs: Left)
+.Xc
+Move the cursor left.
+.It Xo
+.Ic cursor-right
+(vi: l)
+(emacs: Right)
+.Xc
+Move the cursor right.
+.It Xo
+.Ic cursor-up
+(vi: k)
+(emacs: Up)
+.Xc
+Move the cursor up.
+.It Xo
+.Ic end-of-line
+(vi: $)
+(emacs: C-e)
+.Xc
+Move the cursor to the end of the line.
+.It Xo
+.Ic goto-line <line>
+(vi: :)
+(emacs: g)
+.Xc
+Move the cursor to a specific line.
+.It Xo
+.Ic history-bottom
+(vi: G)
+(emacs: M->)
+.Xc
+Scroll to the bottom of the history.
+.It Xo
+.Ic history-top
+(vi: g)
+(emacs: M-<)
+.Xc
+Scroll to the top of the history.
+.It Xo
+.Ic jump-again
+(vi: ;)
+(emacs: ;)
+.Xc
+Repeat the last jump.
+.It Xo
+.Ic jump-backward <to>
+(vi: F)
+(emacs: F)
+.Xc
+Jump backwards to the specified text.
+.It Xo
+.Ic jump-forward <to>
+(vi: f)
+(emacs: f)
+.Xc
+Jump forward to the specified text.
+.It Xo
+.Ic jump-to-mark
+(vi: M-x)
+(emacs: M-x)
+.Xc
+Jump to the last mark.
+.It Xo
+.Ic middle-line
+(vi: M)
+(emacs: M-r)
+.Xc
+Move to the middle line.
+.It Xo
+.Ic next-matching-bracket
+(vi: %)
+(emacs: M-C-f)
+.Xc
+Move to the next matching bracket.
+.It Xo
+.Ic next-paragraph
+(vi: })
+(emacs: M-})
+.Xc
+Move to the next paragraph.
+.It Xo
+.Ic next-prompt
+.Xc
+Move to the next prompt.
+.It Xo
+.Ic next-word
+(vi: w)
+.Xc
+Move to the next word.
+.It Xo
+.Ic page-down
+(vi: C-f)
+(emacs: PageDown)
+.Xc
+Scroll down by one page.
+.It Xo
+.Ic page-up
+(vi: C-b)
+(emacs: PageUp)
+.Xc
+Scroll up by one page.
+.It Xo
+.Ic previous-matching-bracket
+(emacs: M-C-b)
+.Xc
+Move to the previous matching bracket.
+.It Xo
+.Ic previous-paragraph
+(vi: {)
+(emacs: M-{)
+.Xc
+Move to the previous paragraph.
+.It Xo
+.Ic previous-prompt
+.Xc
+Move to the previous prompt.
+.It Xo
+.Ic previous-word
+(vi: b)
+(emacs: M-b)
+.Xc
+Move to the previous word.
+.It Xo
+.Ic rectangle-toggle
+(vi: v)
+(emacs: R)
+.Xc
+Toggle rectangle selection mode.
+.It Xo
+.Ic refresh-from-pane
+(vi: r)
+(emacs: r)
+.Xc
+Refresh the content from the pane.
+.It Xo
+.Ic search-again
+(vi: n)
+(emacs: n)
+.Xc
+Repeat the last search.
+.It Xo
+.Ic search-backward <for>
+(vi: ?)
+.Xc
+Search backwards for the specified text.
+.It Xo
+.Ic search-forward <for>
+(vi: /)
+.Xc
+Search forward for the specified text.
+.It Xo
+.Ic select-line
+(vi: V)
+.Xc
+Select the current line.
+.It Xo
+.Ic select-word
+.Xc
+Select the current word.
+.It Xo
+.Ic start-of-line
+(vi: 0)
+(emacs: C-a)
+.Xc
+Move the cursor to the start of the line.
+.It Xo
+.Ic top-line
+(vi: H)
+(emacs: M-R)
+.Xc
+Move to the top line.
+.It Xo
+.Ic next-prompt
+(vi: C-n)
+(emacs: C-n)
+.Xc
+Move to the next prompt.
+.It Xo
+.Ic previous-prompt
+(vi: C-p)
+(emacs: C-p)
+.Xc
+Move to the previous prompt.
.El
.Pp
The search commands come in several varieties:
@@ -1852,6 +2027,16 @@ repeats the last search and
does the same but reverses the direction (forward becomes backward and backward
becomes forward).
.Pp
+The
+.Ql next-prompt
+and
+.Ql previous-prompt
+move between shell prompts, but require the shell to emit an escape sequence
+(\e033]133;A\e033\e\e) to tell
+.Nm
+where the prompts are located; if the shell does not do this, these commands
+will do nothing.
+.Pp
Copy commands may take an optional buffer prefix argument which is used
to generate the buffer name (the default is
.Ql buffer
@@ -5387,6 +5572,8 @@ for the terminal default colour; or a hexadecimal RGB string such as
.Ql #ffffff .
.It Ic bg=colour
Set the background colour.
+.It Ic us=colour
+Set the underscore colour.
.It Ic none
Set no attributes (turn off any active attributes).
.It Xo Ic acs ,
diff --git a/tmux.h b/tmux.h
index 602bbd89..c22aa2d6 100644
--- a/tmux.h
+++ b/tmux.h
@@ -680,6 +680,7 @@ struct colour_palette {
#define GRID_LINE_WRAPPED 0x1
#define GRID_LINE_EXTENDED 0x2
#define GRID_LINE_DEAD 0x4
+#define GRID_LINE_START_PROMPT 0x8
/* Grid string flags. */
#define GRID_STRING_WITH_SEQUENCES 0x1
@@ -1068,7 +1069,7 @@ struct window_pane {
#define PANE_REDRAW 0x1
#define PANE_DROP 0x2
#define PANE_FOCUSED 0x4
-/* 0x8 unused */
+#define PANE_VISITED 0x8
/* 0x10 unused */
/* 0x20 unused */
#define PANE_INPUTOFF 0x40
@@ -1123,7 +1124,8 @@ struct window_pane {
int border_gc_set;
struct grid_cell border_gc;
- TAILQ_ENTRY(window_pane)