aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicholas Marriott <nicholas.marriott@gmail.com>2021-04-13 06:25:59 +0100
committerNicholas Marriott <nicholas.marriott@gmail.com>2021-04-13 06:25:59 +0100
commitc2048c5c65aea99f2b79290b87635cb1d90863a6 (patch)
tree8aafdf588893ccdd65c8db53f5188f83f020675b
parent46cbbe3d4566885b8ad4235598389936f63c2c01 (diff)
parentbedf2bd4372c60a525c22e6309f329cfd0bd07bc (diff)
downloadrtmux-c2048c5c65aea99f2b79290b87635cb1d90863a6.tar.gz
rtmux-c2048c5c65aea99f2b79290b87635cb1d90863a6.tar.bz2
rtmux-c2048c5c65aea99f2b79290b87635cb1d90863a6.zip
Merge branch 'master' into 3.2-rc
-rw-r--r--alerts.c9
-rw-r--r--cfg.c20
-rw-r--r--cmd-choose-tree.c18
-rw-r--r--cmd-display-message.c22
-rw-r--r--cmd-list-keys.c7
-rw-r--r--cmd-queue.c4
-rw-r--r--cmd-run-shell.c9
-rw-r--r--control-notify.c11
-rw-r--r--format.c34
-rw-r--r--grid-reader.c28
-rw-r--r--input-keys.c26
-rw-r--r--key-string.c17
-rw-r--r--log.c13
-rw-r--r--mode-tree.c70
-rw-r--r--notify.c2
-rw-r--r--screen.c4
-rw-r--r--server-client.c12
-rw-r--r--status.c7
-rw-r--r--tmux.145
-rw-r--r--tmux.h10
-rw-r--r--tty-keys.c61
-rw-r--r--tty.c38
-rw-r--r--window-buffer.c59
-rw-r--r--window-client.c43
-rw-r--r--window-copy.c257
-rw-r--r--window-customize.c8
-rw-r--r--window-tree.c52
27 files changed, 667 insertions, 219 deletions
diff --git a/alerts.c b/alerts.c
index 4cc5c3eb..d3c5df05 100644
--- a/alerts.c
+++ b/alerts.c
@@ -314,10 +314,11 @@ alerts_set_message(struct winlink *wl, const char *type, const char *option)
tty_putcode(&c->tty, TTYC_BEL);
if (visual == VISUAL_OFF)
continue;
- if (c->session->curw == wl)
- status_message_set(c, -1, 1, "%s in current window", type);
- else {
- status_message_set(c, -1, 1, "%s in window %d", type,
+ if (c->session->curw == wl) {
+ status_message_set(c, -1, 1, 0, "%s in current window",
+ type);
+ } else {
+ status_message_set(c, -1, 1, 0, "%s in window %d", type,
wl->idx);
}
}
diff --git a/cfg.c b/cfg.c
index 3ef46e66..8ec5a95b 100644
--- a/cfg.c
+++ b/cfg.c
@@ -102,6 +102,7 @@ load_cfg(const char *path, struct client *c, struct cmdq_item *item, int flags,
struct cmd_parse_input pi;
struct cmd_parse_result *pr;
struct cmdq_item *new_item0;
+ struct cmdq_state *state;
if (new_item != NULL)
*new_item = NULL;
@@ -135,12 +136,19 @@ load_cfg(const char *path, struct client *c, struct cmdq_item *item, int flags,
return (0);
}
- new_item0 = cmdq_get_command(pr->cmdlist, NULL);
+ if (item != NULL)
+ state = cmdq_copy_state(cmdq_get_state(item));
+ else
+ state = cmdq_new_state(NULL, NULL, 0);
+ cmdq_add_format(state, "current_file", "%s", pi.file);
+
+ new_item0 = cmdq_get_command(pr->cmdlist, state);
if (item != NULL)
new_item0 = cmdq_insert_after(item, new_item0);
else
new_item0 = cmdq_append(NULL, new_item0);
cmd_list_free(pr->cmdlist);
+ cmdq_free_state(state);
if (new_item != NULL)
*new_item = new_item0;
@@ -155,6 +163,7 @@ load_cfg_from_buffer(const void *buf, size_t len, const char *path,
struct cmd_parse_input pi;
struct cmd_parse_result *pr;
struct cmdq_item *new_item0;
+ struct cmdq_state *state;
if (new_item != NULL)
*new_item = NULL;
@@ -181,12 +190,19 @@ load_cfg_from_buffer(const void *buf, size_t len, const char *path,
return (0);
}
- new_item0 = cmdq_get_command(pr->cmdlist, NULL);
+ if (item != NULL)
+ state = cmdq_copy_state(cmdq_get_state(item));
+ else
+ state = cmdq_new_state(NULL, NULL, 0);
+ cmdq_add_format(state, "current_file", "%s", pi.file);
+
+ new_item0 = cmdq_get_command(pr->cmdlist, state);
if (item != NULL)
new_item0 = cmdq_insert_after(item, new_item0);
else
new_item0 = cmdq_append(NULL, new_item0);
cmd_list_free(pr->cmdlist);
+ cmdq_free_state(state);
if (new_item != NULL)
*new_item = new_item0;
diff --git a/cmd-choose-tree.c b/cmd-choose-tree.c
index a58469ac..81209ee3 100644
--- a/cmd-choose-tree.c
+++ b/cmd-choose-tree.c
@@ -30,9 +30,9 @@ const struct cmd_entry cmd_choose_tree_entry = {
.name = "choose-tree",
.alias = NULL,
- .args = { "F:Gf:NO:rst:wZ", 0, 1 },
- .usage = "[-GNrswZ] [-F format] [-f filter] [-O sort-order] "
- CMD_TARGET_PANE_USAGE " [template]",
+ .args = { "F:f:GK:NO:rst:wZ", 0, 1 },
+ .usage = "[-GNrswZ] [-F format] [-f filter] [-K key-format] "
+ "[-O sort-order] " CMD_TARGET_PANE_USAGE " [template]",
.target = { 't', CMD_FIND_PANE, 0 },
@@ -44,9 +44,9 @@ const struct cmd_entry cmd_choose_client_entry = {
.name = "choose-client",
.alias = NULL,
- .args = { "F:f:NO:rt:Z", 0, 1 },
- .usage = "[-NrZ] [-F format] [-f filter] [-O sort-order] "
- CMD_TARGET_PANE_USAGE " [template]",
+ .args = { "F:f:K:NO:rt:Z", 0, 1 },
+ .usage = "[-NrZ] [-F format] [-f filter] [-K key-format] "
+ "[-O sort-order] " CMD_TARGET_PANE_USAGE " [template]",
.target = { 't', CMD_FIND_PANE, 0 },
@@ -58,9 +58,9 @@ const struct cmd_entry cmd_choose_buffer_entry = {
.name = "choose-buffer",
.alias = NULL,
- .args = { "F:f:NO:rt:Z", 0, 1 },
- .usage = "[-NrZ] [-F format] [-f filter] [-O sort-order] "
- CMD_TARGET_PANE_USAGE " [template]",
+ .args = { "F:f:K:NO:rt:Z", 0, 1 },
+ .usage = "[-NrZ] [-F format] [-f filter] [-K key-format] "
+ "[-O sort-order] " CMD_TARGET_PANE_USAGE " [template]",
.target = { 't', CMD_FIND_PANE, 0 },
diff --git a/cmd-display-message.c b/cmd-display-message.c
index fc9c4851..0522d37f 100644
--- a/cmd-display-message.c
+++ b/cmd-display-message.c
@@ -39,11 +39,11 @@ const struct cmd_entry cmd_display_message_entry = {
.name = "display-message",
.alias = "display",
- .args = { "acd:Ipt:F:v", 0, 1 },
- .usage = "[-aIpv] [-c target-client] [-d delay] [-F format] "
+ .args = { "acd:INpt:F:v", 0, 1 },
+ .usage = "[-aINpv] [-c target-client] [-d delay] [-F format] "
CMD_TARGET_PANE_USAGE " [message]",
- .target = { 't', CMD_FIND_PANE, 0 },
+ .target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
.flags = CMD_AFTERHOOK|CMD_CLIENT_CFLAG|CMD_CLIENT_CANFAIL,
.exec = cmd_display_message_exec
@@ -73,6 +73,8 @@ cmd_display_message_exec(struct cmd *self, struct cmdq_item *item)
int flags;
if (args_has(args, 'I')) {
+ if (wp == NULL)
+ return (CMD_RETURN_NORMAL);
if (window_pane_start_input(wp, item, &cause) != 0) {
cmdq_error(item, "%s", cause);
free(cause);
@@ -109,8 +111,10 @@ cmd_display_message_exec(struct cmd *self, struct cmdq_item *item)
*/
if (tc != NULL && tc->session == s)
c = tc;
- else
+ else if (s != NULL)
c = cmd_find_best_client(s);
+ else
+ c = NULL;
if (args_has(args, 'v'))
flags = FORMAT_VERBOSE;
else
@@ -124,10 +128,14 @@ cmd_display_message_exec(struct cmd *self, struct cmdq_item *item)
}
msg = format_expand_time(ft, template);
- if (args_has(args, 'p'))
+ if (cmdq_get_client(item) == NULL)
+ cmdq_error(item, "%s", msg);
+ else if (args_has(args, 'p'))
cmdq_print(item, "%s", msg);
- else if (tc != NULL)
- status_message_set(tc, delay, 0, "%s", msg);
+ else if (tc != NULL) {
+ status_message_set(tc, delay, 0, args_has(args, 'N'), "%s",
+ msg);
+ }
free(msg);
format_free(ft);
diff --git a/cmd-list-keys.c b/cmd-list-keys.c
index dd82e57e..ca4bf752 100644
--- a/cmd-list-keys.c
+++ b/cmd-list-keys.c
@@ -113,9 +113,10 @@ cmd_list_keys_print_notes(struct cmdq_item *item, struct args *args,
else
note = xstrdup(bd->note);
tmp = utf8_padcstr(key, keywidth + 1);
- if (args_has(args, '1') && tc != NULL)
- status_message_set(tc, -1, 1, "%s%s%s", prefix, tmp, note);
- else
+ if (args_has(args, '1') && tc != NULL) {
+ status_message_set(tc, -1, 1, 0, "%s%s%s", prefix, tmp,
+ note);
+ } else
cmdq_print(item, "%s%s%s", prefix, tmp, note);
free(tmp);
free(note);
diff --git a/cmd-queue.c b/cmd-queue.c
index 05f439f5..54163919 100644
--- a/cmd-queue.c
+++ b/cmd-queue.c
@@ -276,7 +276,7 @@ cmdq_merge_formats(struct cmdq_item *item, struct format_tree *ft)
const struct cmd_entry *entry;
if (item->cmd != NULL) {
- entry = cmd_get_entry (item->cmd);
+ entry = cmd_get_entry(item->cmd);
format_add(ft, "command", "%s", entry->name);
}
if (item->state->formats != NULL)
@@ -862,7 +862,7 @@ cmdq_error(struct cmdq_item *item, const char *fmt, ...)
c->retval = 1;
} else {
*msg = toupper((u_char) *msg);
- status_message_set(c, -1, 1, "%s", msg);
+ status_message_set(c, -1, 1, 0, "%s", msg);
}
free(msg);
diff --git a/cmd-run-shell.c b/cmd-run-shell.c
index 4f30d05d..56d5f723 100644
--- a/cmd-run-shell.c
+++ b/cmd-run-shell.c
@@ -20,6 +20,7 @@
#include <sys/types.h>
#include <sys/wait.h>
+#include <ctype.h>
#include <stdlib.h>
#include <string.h>
@@ -190,8 +191,12 @@ cmd_run_shell_timer(__unused int fd, __unused short events, void* arg)
&error);
}
if (status == CMD_PARSE_ERROR) {
- cmdq_error(cdata->item, "%s", error);
- free(error);
+ if (cdata->item == NULL) {
+ *error = toupper((u_char)*error);
+ status_message_set(c, -1, 1, 0, "%s", error);
+ } else
+ cmdq_error(cdata->item, "%s", error);
+ free(error);
}
}
diff --git a/control-notify.c b/control-notify.c
index cc706ac2..6ff0e436 100644
--- a/control-notify.c
+++ b/control-notify.c
@@ -172,6 +172,17 @@ control_notify_client_session_changed(struct client *cc)
}
void
+control_notify_client_detached(struct client *cc)
+{
+ struct client *c;
+
+ TAILQ_FOREACH(c, &clients, entry) {
+ if (CONTROL_SHOULD_NOTIFY_CLIENT(c))
+ control_write(c, "%%client-detached %s", cc->name);
+ }
+}
+
+void
control_notify_session_renamed(struct session *s)
{
struct client *c;
diff --git a/format.c b/format.c
index 0e8ea8f3..5a12502e 100644
--- a/format.c
+++ b/format.c
@@ -100,6 +100,7 @@ format_job_cmp(struct format_job *fj1, struct format_job *fj2)
#define FORMAT_QUOTE_STYLE 0x2000
#define FORMAT_WINDOW_NAME 0x4000
#define FORMAT_SESSION_NAME 0x8000
+#define FORMAT_CHARACTER 0x10000
/* Limit on recursion. */
#define FORMAT_LOOP_LIMIT 10
@@ -3522,7 +3523,7 @@ format_build_modifiers(struct format_expand_state *es, const char **s,
/*
* Modifiers are a ; separated list of the forms:
- * l,m,C,b,d,n,t,w,q,E,T,S,W,P,<,>
+ * l,m,C,a,b,d,n,t,w,q,E,T,S,W,P,<,>
* =a
* =/a
* =/a/
@@ -3539,7 +3540,7 @@ format_build_modifiers(struct format_expand_state *es, const char **s,
cp++;
/* Check single character modifiers with no arguments. */
- if (strchr("lbdnwETSWP<>", cp[0]) != NULL &&
+ if (strchr("labdnwETSWP<>", cp[0]) != NULL &&
format_is_end(cp[1])) {
format_add_modifier(&list, count, cp, 1, NULL, 0);
cp++;
@@ -3956,7 +3957,7 @@ format_replace_expression(struct format_modifier *mexp,
mright = (long long)mright;
}
format_log(es, "expression left side is: %.*f", prec, mleft);
- format_log(es, "expression right side is: %.*f", prec, mright);
+ format_log(es, "expression right side is: %.*f", prec, mright);
switch (operator) {
case ADD:
@@ -4016,10 +4017,10 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
{
struct format_tree *ft = es->ft;
struct window_pane *wp = ft->wp;
- const char *errptr, *copy, *cp, *marker = NULL;
+ const char *errstr, *copy, *cp, *marker = NULL;
const char *time_format = NULL;
char *copy0, *condition, *found, *new;
- char *value, *left, *right;
+ char *value, *left, *right, c;
size_t valuelen;
int modifiers = 0, limit = 0, width = 0;
int j;
@@ -4063,8 +4064,8 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
if (fm->argc < 1)
break;
limit = strtonum(fm->argv[0], INT_MIN, INT_MAX,
- &errptr);
- if (errptr != NULL)
+ &errstr);
+ if (errstr != NULL)
limit = 0;
if (fm->argc >= 2 && fm->argv[1] != NULL)
marker = fm->argv[1];
@@ -4073,8 +4074,8 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
if (fm->argc < 1)
break;
width = strtonum(fm->argv[0], INT_MIN, INT_MAX,
- &errptr);
- if (errptr != NULL)
+ &errstr);
+ if (errstr != NULL)
width = 0;
break;
case 'w':
@@ -4088,6 +4089,9 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
case 'l':
modifiers |= FORMAT_LITERAL;
break;
+ case 'a':
+ modifiers |= FORMAT_CHARACTER;
+ break;
case 'b':
modifiers |= FORMAT_BASENAME;
break;
@@ -4154,6 +4158,18 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
goto done;
}
+ /* Is this a character? */
+ if (modifiers & FORMAT_CHARACTER) {
+ new = format_expand1(es, copy);
+ c = strtonum(new, 32, 126, &errstr);
+ if (errstr != NULL)
+ value = xstrdup("");
+ else
+ xasprintf(&value, "%c", c);
+ free (new);
+ goto done;
+ }
+
/* Is this a loop, comparison or condition? */
if (modifiers & FORMAT_SESSIONS) {
value = format_loop_sessions(es, copy);
diff --git a/grid-reader.c b/grid-reader.c
index ae2f4d2b..89fe90fb 100644
--- a/grid-reader.c
+++ b/grid-reader.c
@@ -71,7 +71,7 @@ grid_reader_cursor_right(struct grid_reader *gr, int wrap, int all)
/* Move cursor back one position. */
void
-grid_reader_cursor_left(struct grid_reader *gr)
+grid_reader_cursor_left(struct grid_reader *gr, int wrap)
{
struct grid_cell gc;
@@ -81,7 +81,9 @@ grid_reader_cursor_left(struct grid_reader *gr)
break;
gr->cx--;
}
- if (gr->cx == 0 && gr->cy > 0) {
+ if (gr->cx == 0 && gr->cy > 0 &&
+ (wrap ||
+ grid_get_line(gr->gd, gr->cy - 1)->flags & GRID_LINE_WRAPPED)) {
grid_reader_cursor_up(gr);
grid_reader_cursor_end_of_line(gr, 0, 0);
} else if (gr->cx > 0)
@@ -363,3 +365,25 @@ grid_reader_cursor_jump_back(struct grid_reader *gr, const struct utf8_data *jc)
}
return 0;
}
+
+/* Jump back to the first non-blank character of the line. */
+void
+grid_reader_cursor_back_to_indentation(struct grid_reader *gr)
+{
+ struct grid_cell gc;
+ u_int px, py, xx, yy;
+
+ yy = gr->gd->hsize + gr->gd->sy - 1;
+ grid_reader_cursor_start_of_line(gr, 1);
+
+ for (py = gr->cy; py <= yy; py++) {
+ xx = grid_line_length(gr->gd, py);
+ for (px = 0; px < xx; px++) {
+ grid_get_cell(gr->gd, px, py, &gc);
+ if (gc.data.size != 1 || *gc.data.data != ' ')
+ break;
+ }
+ if (~grid_get_line(gr->gd, py)->flags & GRID_LINE_WRAPPED)
+ break;
+ }
+}
diff --git a/input-keys.c b/input-keys.c
index 39a72cdc..a3252855 100644
--- a/input-keys.c
+++ b/input-keys.c
@@ -428,6 +428,14 @@ input_key_pane(struct window_pane *wp, key_code key, struct mouse_event *m)
return (input_key(wp->screen, wp->event, key));
}
+static void
+input_key_write(const char *from, struct bufferevent *bev, const char *data,
+ size_t size)
+{
+ log_debug("%s: %.*s", from, (int)size, data);
+ bufferevent_write(bev, data, size);
+}
+
/* Translate a key code into an output key sequence. */
int
input_key(struct screen *s, struct bufferevent *bev, key_code key)
@@ -444,7 +452,7 @@ input_key(struct screen *s, struct bufferevent *bev, key_code key)
/* Literal keys go as themselves (can't be more than eight bits). */
if (key & KEYC_LITERAL) {
ud.data[0] = (u_char)key;
- bufferevent_write(bev, &ud.data[0], 1);
+ input_key_write(__func__, bev, &ud.data[0], 1);
return (0);
}
@@ -463,16 +471,16 @@ input_key(struct screen *s, struct bufferevent *bev, key_code key)
justkey = (key & ~(KEYC_META|KEYC_IMPLIED_META));
if (justkey <= 0x7f) {
if (key & KEYC_META)
- bufferevent_write(bev, "\033", 1);
+ input_key_write(__func__, bev, "\033", 1);
ud.data[0] = justkey;
- bufferevent_write(bev, &ud.data[0], 1);
+ input_key_write(__func__, bev, &ud.data[0], 1);
return (0);
}
if (justkey > 0x7f && justkey < KEYC_BASE) {
if (key & KEYC_META)
- bufferevent_write(bev, "\033", 1);
+ input_key_write(__func__, bev, "\033", 1);
utf8_to_data(justkey, &ud);
- bufferevent_write(bev, ud.data, ud.size);
+ input_key_write(__func__, bev, ud.data, ud.size);
return (0);
}
@@ -494,8 +502,8 @@ input_key(struct screen *s, struct bufferevent *bev, key_code key)
if (ike != NULL) {
log_debug("found key 0x%llx: \"%s\"", key, ike->data);
if ((key & KEYC_META) && (~key & KEYC_IMPLIED_META))
- bufferevent_write(bev, "\033", 1);
- bufferevent_write(bev, ike->data, strlen(ike->data));
+ input_key_write(__func__, bev, "\033", 1);
+ input_key_write(__func__, bev, ike->data, strlen(ike->data));
return (0);
}
@@ -560,7 +568,7 @@ input_key(struct screen *s, struct bufferevent *bev, key_code key)
goto missing;
}
xsnprintf(tmp, sizeof tmp, "\033[%llu;%cu", outkey, modifier);
- bufferevent_write(bev, tmp, strlen(tmp));
+ input_key_write(__func__, bev, tmp, strlen(tmp));
return (0);
missing:
@@ -656,5 +664,5 @@ input_key_mouse(struct window_pane *wp, struct mouse_event *m)
if (!input_key_get_mouse(s, m, x, y, &buf, &len))
return;
log_debug("writing mouse %.*s to %%%u", (int)len, buf, wp->id);
- bufferevent_write(wp->event, buf, len);
+ input_key_write(__func__, wp->event, buf, len);
}
diff --git a/key-string.c b/key-string.c
index 194fdef2..8d60f132 100644
--- a/key-string.c
+++ b/key-string.c
@@ -45,9 +45,9 @@ static const struct {
{ "F11", KEYC_F11|KEYC_IMPLIED_META },
{ "F12", KEYC_F12|KEYC_IMPLIED_META },
{ "IC", KEYC_IC|KEYC_IMPLIED_META },
- { "Insert", KEYC_IC|KEYC_IMPLIED_META },
+ { "Insert", KEYC_IC|KEYC_IMPLIED_META },
{ "DC", KEYC_DC|KEYC_IMPLIED_META },
- { "Delete", KEYC_DC|KEYC_IMPLIED_META },
+ { "Delete", KEYC_DC|KEYC_IMPLIED_META },
{ "Home", KEYC_HOME|KEYC_IMPLIED_META },
{ "End", KEYC_END|KEYC_IMPLIED_META },
{ "NPage", KEYC_NPAGE|KEYC_IMPLIED_META },
@@ -70,7 +70,7 @@ static const struct {
{ "Right", KEYC_RIGHT|KEYC_CURSOR|KEYC_IMPLIED_META },
/* Numeric keypad. */
- { "KP/", KEYC_KP_SLASH|KEYC_KEYPAD },
+ { "KP/", KEYC_KP_SLASH|KEYC_KEYPAD },
{ "KP*", KEYC_KP_STAR|KEYC_KEYPAD },
{ "KP-", KEYC_KP_MINUS|KEYC_KEYPAD },
{ "KP7", KEYC_KP_SEVEN|KEYC_KEYPAD },
@@ -164,7 +164,7 @@ key_string_get_modifiers(const char **string)
key_code
key_string_lookup_string(const char *string)
{
- static const char *other = "!#()+,-.0123456789:;<=>'\r\t";
+ static const char *other = "!#()+,-.0123456789:;<=>'\r\t\177";
key_code key, modifiers;
u_int u, i;
struct utf8_data ud, *udp;
@@ -181,8 +181,8 @@ key_string_lookup_string(const char *string)
/* Is this a hexadecimal value? */
if (string[0] == '0' && string[1] == 'x') {
- if (sscanf(string + 2, "%x", &u) != 1)
- return (KEYC_UNKNOWN);
+ if (sscanf(string + 2, "%x", &u) != 1)
+ return (KEYC_UNKNOWN);
mlen = wctomb(m, u);
if (mlen <= 0 || mlen > MB_LEN_MAX)
return (KEYC_UNKNOWN);
@@ -238,11 +238,12 @@ key_string_lookup_string(const char *string)
}
/* Convert the standard control keys. */
- if (key < KEYC_BASE && (modifiers & KEYC_CTRL) && !strchr(other, key)) {
+ if (key < KEYC_BASE && (modifiers & KEYC_CTRL) &&
+ strchr(other, key) == NULL) {
if (key >= 97 && key <= 122)
key -= 96;
else if (key >= 64 && key <= 95)
- key -= 64;
+ key -= 64;
else if (key == 32)
key = 0;
else if (key == 63)
diff --git a/log.c b/log.c
index f87cab92..26569974 100644
--- a/log.c
+++ b/log.c
@@ -110,15 +110,16 @@ log_vwrite(const char *msg, va_list ap)
return;
if (vasprintf(&fmt, msg, ap) == -1)
- exit(1);
- if (stravis(&out, fmt, VIS_OCTAL|VIS_CSTYLE|VIS_TAB|VIS_NL) == -1)
- exit(1);
+ return;
+ if (stravis(&out, fmt, VIS_OCTAL|VIS_CSTYLE|VIS_TAB|VIS_NL) == -1) {
+ free(fmt);
+ return;
+ }
gettimeofday(&tv, NULL);
if (fprintf(log_file, "%lld.%06d %s\n", (long long)tv.tv_sec,
- (int)tv.tv_usec, out) == -1)
- exit(1);
- fflush(log_file);
+ (int)tv.tv_usec, out) != -1)
+ fflush(log_file);
free(out);
free(fmt);
diff --git a/mode-tree.c b/mode-tree.c
index a47c0c06..ca7f33a4 100644
--- a/mode-tree.c
+++ b/mode-tree.c
@@ -46,6 +46,7 @@ struct mode_tree_data {
mode_tree_search_cb searchcb;
mode_tree_menu_cb menucb;
mode_tree_height_cb heightcb;
+ mode_tree_key_cb keycb;
struct mode_tree_list children;
struct mode_tree_list saved;
@@ -74,6 +75,10 @@ struct mode_tree_item {
void *itemdata;
u_int line;
+ key_code key;
+ const char *keystr;
+ size_t keylen;
+
uint64_t tag;
const char *name;
const char *text;
@@ -135,6 +140,7 @@ mode_tree_free_item(struct mode_tree_item *mti)
free((void *)mti->name);
free((void *)mti->text);
+ free((void *)mti->keystr);
free(mti);
}
@@ -193,6 +199,26 @@ mode_tree_build_lines(struct mode_tree_data *mtd,
flat = 0;
if (mti->expanded)
mode_tree_build_lines(mtd, &mti->children, depth + 1);
+
+ if (mtd->keycb != NULL) {
+ mti->key = mtd->keycb(mtd->modedata, mti->itemdata,
+ mti->line);
+ if (mti->key == KEYC_UNKNOWN)
+ mti->key = KEYC_NONE;
+ } else if (mti->line < 10)
+ mti->key = '0' + mti->line;
+ else if (mti->line < 36)
+ mti->key = KEYC_META|('a' + mti->line - 10);
+ else
+ mti->key = KEYC_NONE;
+ if (mti->key != KEYC_NONE) {
+ mti->keystr = xstrdup(key_string_lookup_key(mti->key,
+ 0));
+ mti->keylen = strlen(mti->keystr);
+ } else {
+ mti->keystr = NULL;
+ mti->keylen = 0;
+ }
}
TAILQ_FOREACH(mti, mtl, entry) {
for (i = 0; i < mtd->line_size; i++) {
@@ -363,7 +389,7 @@ struct mode_tree_data *
mode_tree_start(struct window_pane *wp, struct args *args,
mode_tree_build_cb buildcb, mode_tree_draw_cb drawcb,
mode_tree_search_cb searchcb, mode_tree_menu_cb menucb,
- mode_tree_height_cb heightcb, void *modedata,
+ mode_tree_height_cb heightcb, mode_tree_key_cb keycb, void *modedata,
const struct menu_item *menu, const char **sort_list, u_int sort_size,
struct screen **s)
{
@@ -402,6 +428,7 @@ mode_tree_start(struct window_pane *wp, struct args *args,
mtd->searchcb = searchcb;
mtd->menucb = menucb;
mtd->heightcb = heightcb;
+ mtd->keycb = keycb;
TAILQ_INIT(&mtd->children);
@@ -596,10 +623,10 @@ mode_tree_draw(struct mode_tree_data *mtd)
struct screen_write_ctx ctx;
struct grid_cell gc0, gc;
u_int w, h, i, j, sy, box_x, box_y, width;
- char *text, *start, key[7];
+ char *text, *start, *key;
const char *tag, *symbol;
size_t size, n;
- int keylen;
+ int keylen, pad;
if (mtd->line_size == 0)
return;
@@ -614,28 +641,30 @@ mode_tree_draw(struct mode_tree_data *mtd)
screen_write_start(&ctx, s);
screen_write_clearscreen(&ctx, 8);
- if (mtd->line_size > 10)
- keylen = 6;
- else
- keylen = 4;
+ keylen = 0;
+ for (i = 0; i < mtd->line_size; i++) {
+ mti = mtd->line_list[i].item;
+ if (mti->key == KEYC_NONE)
+ continue;
+ if ((int)mti->keylen + 3 > keylen)
+ keylen = mti->keylen + 3;
+ }
for (i = 0; i < mtd->line_size; i++) {
if (i < mtd->offset)
continue;
if (i > mtd->offset + h - 1)
break;
-
line = &mtd->line_list[i];
mti = line->item;
screen_write_cursormove(&ctx, 0, i - mtd->offset, 0);
- if (i < 10)
- snprintf(key, sizeof key, "(%c) ", '0' + i);
- else if (i < 36)
- snprintf(key, sizeof key, "(M-%c)", 'a' + (i - 10));
+ pad = keylen - 2 - mti->keylen;
+ if (mti->key != KEYC_NONE)
+ xasprintf(&key, "(%s)%*s", mti->keystr, pad, "");
else
- *key = '\0';
+ key = xstrdup("");
if (line->flat)
symbol = "";
@@ -698,6 +727,7 @@ mode_tree_draw(struct mode_tree_data *mtd)
}
}
free(text);
+ free(key);
if (mti->tagged) {
gc.attr ^= GRID_ATTR_BRIGHT;
@@ -951,7 +981,6 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key,
struct mode_tree_item *current, *parent, *mti;
u_int i, x, y;
int choice;
- key_code tmp;
if (KEYC_IS_MOUSE(*key) && m != NULL) {
if (cmd_mouse_at(mtd->wp, m, &x, &y, 0) != 0) {
@@ -993,12 +1022,11 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key,
current = line->item;
choice = -1;
- if (*key >= '0' && *key <= '9')
- choice = (*key) - '0';
- else if (((*key) & KEYC_MASK_MODIFIERS) == KEYC_META) {
- tmp = (*key) & KEYC_MASK_KEY;
- if (tmp >= 'a' && tmp <= 'z')
- choice = 10 + (tmp - 'a');
+ for (i = 0; i < mtd->line_size; i++) {
+ if (*key == mtd->line_list[i].item->key) {
+ choice = i;
+ break;
+ }
}
if (choice != -1) {
if ((u_int)choice > mtd->line_size - 1) {
@@ -1176,7 +1204,7 @@ mode_tree_run_command(struct client *c, struct cmd_find_state *fs,
if (status == CMD_PARSE_ERROR) {
if (c != NULL) {
*error = toupper((u_char)*error);
- status_message_set(c, -1, 1, "%s", error);
+ status_message_set(c, -1, 1, 0, "%s", error);
}
free(error);
}
diff --git a/notify.c b/notify.c
index f7440cad..4b9b1eaa 100644
--- a/notify.c
+++ b/notify.c
@@ -125,6 +125,8 @@ notify_callback(struct cmdq_item *item, void *data)
control_notify_window_renamed(ne->window);
if (strcmp(ne->name, "client-session-changed") == 0)
control_notify_client_session_changed(ne->client);
+ if (strcmp(ne->name, "client-detached") == 0)
+ control_notify_client_detached(ne->client);
if (strcmp(ne->name, "session-renamed") == 0)
control_notify_session_renamed(ne->session);
if (strcmp(ne->name, "session-created") == 0)
diff --git a/screen.c b/screen.c
index db2590cc..2b9d70de 100644
--- a/screen.c
+++ b/screen.c
@@ -153,8 +153,10 @@ screen_reset_tabs(struct screen *s)
void
screen_set_cursor_style(struct screen *s, u_int style)
{
- if (style <= 6)
+ if (style <= 6) {
s->cstyle = style;
+ s->mode &= ~MODE_BLINKING;
+ }
}
/* Set screen cursor colour. */
diff --git a/server-client.c b/server-client.c
index 96e1b584..d3ffd682 100644
--- a/server-client.c
+++ b/server-client.c
@@ -296,6 +296,9 @@ server_client_lost(struct client *c)
TAILQ_REMOVE(&clients, c, entry);
log_debug("lost client %p", c);
+ if (c->flags & CLIENT_ATTACHED)
+ notify_client("client-detached", c);
+
if (c->flags & CLIENT_CONTROL)
control_stop(c);
if (c->flags & CLIENT_TERMINAL)
@@ -1305,7 +1308,11 @@ server_client_handle_key(struct client *c, struct key_event *event)
* immediately rather than queued.
*/
if (~c->flags & CLIENT_READONLY) {
- status_message_clear(c);
+ if (c->message_string != NULL) {
+ if (c->message_ignore_keys)
+ return (0);
+ status_message_clear(c);
+ }
if (c->overlay_key != NULL) {
switch (c->overlay_key(c, event)) {
case 0:
@@ -1766,9 +1773,6 @@ server_client_check_exit(struct client *c)
if (EVBUFFER_LENGTH(cf->buffer) != 0)
return;
}
-
- if (c->flags & CLIENT_ATTACHED)
- notify_client("client-detached", c);
c->flags |= CLIENT_EXITED;
switch (c->exit_type) {
diff --git a/status.c b/status.c
index 154d9452..f9786f4b 100644
--- a/status.c
+++ b/status.c
@@ -424,7 +424,7 @@ status_redraw(struct client *c)
/* Set a status line message. */
void
status_message_set(struct client *c, int delay, int ignore_styles,
- const char *fmt, ...)
+ int ignore_keys, const char *fmt, ...)
{
struct timeval tv;
va_list ap;
@@ -433,7 +433,6 @@ status_message_set(struct client *c, int delay, int ignore_styles,
status_push_screen(c);
va_start(ap, fmt);
- c->message_ignore_styles = ignore_styles;
xvasprintf(&c->message_string, fmt, ap);
va_end(ap);
@@ -456,6 +455,10 @@ status_message_set(struct client *c, int delay, int ignore_styles,
evtimer_add(&c->message_timer, &tv);
}
+ if (delay != 0)
+ c->message_ignore_keys = ignore_keys;
+ c->message_ignore_styles = ignore_styles;
+
c->tty.flags |= (TTY_NOCURSOR|TTY_FREEZE);
c->flags |= CLIENT_REDRAWSTATUS;
}
diff --git a/tmux.1 b/tmux.1
index c79950ce..2343ab89 100644
--- a/tmux.1
+++ b/tmux.1
@@ -1985,12 +1985,17 @@ The default is to capture only the visible contents of the pane.
.Op Fl NrZ
.Op Fl F Ar format
.Op Fl f Ar filter
+.Op Fl K Ar key-format
.Op Fl O Ar sort-order
.Op Fl t Ar target-pane
.Op Ar template
.Xc
Put a pane into client mode, allowing a client to be selected interactively from
a list.
+Each client is shown on one line.
+A shortcut key is shown on the left in brackets allowing for immediate choice,
+or the list may be navigated and an item chosen or otherwise manipulated using
+the keys below.
.Fl Z
zooms the pane.
The following keys may be used in client mode:
@@ -2040,7 +2045,9 @@ specifies an initial filter: the filter is a format - if it evaluates to zero,
the item in the list is not shown, otherwise it is shown.
If a filter would lead to an empty list, it is ignored.
.Fl F
-specifies the format for each item in the list.
+specifies the format for each item in the list and
+.Fl K
+a format for each shortcut key; both are evaluated once for each line.
.Fl N
starts without the preview.
This command works only if at least one client is attached.
@@ -2049,12 +2056,17 @@ This command works only if at least one client is attached.
.Op Fl GNrswZ
.Op Fl F Ar format
.Op Fl f Ar filter
+.Op Fl K Ar key-format
.Op Fl O Ar sort-order
.Op Fl t Ar target-pane
.Op Ar template
.Xc
Put a pane into tree mode, where a session, window or pane may be chosen
-interactively from a list.
+interactively from a tree.
+Each session, window or pane is shown on one line.
+A shortcut key is shown on the left in brackets allowing for immediate choice,
+or the tree may be navigated and an item chosen or otherwise manipulated using
+the keys below.
.Fl s
starts with sessions collapsed and
.Fl w
@@ -2113,7 +2125,9 @@ specifies an initial filter: the filter is a format - if it evaluates to zero,
the item in the list is not shown, otherwise it is shown.
If a filter would lead to an empty list, it is ignored.
.Fl F
-specifies the format for each item in the tree.
+specifies the format for each item in the tree and
+.Fl K
+a format for each shortcut key; both are evaluated once for each line.
.Fl N
starts without the preview.
.Fl G
@@ -3149,8 +3163,8 @@ The appearance and behaviour of
may be modified by changing the value of various options.
There are four types of option:
.Em server options ,
-.Em session options
-.Em window options
+.Em session options ,
+.Em window options ,
and
.Em pane options .
.Pp
@@ -4663,6 +4677,11 @@ For example,
multiplies 5.5 by 3 for a result with four decimal places and
.Ql #{e|%%:7,3}
returns the modulus of 7 and 3.
+.Ql a
+replaces a numeric argument by its ASCII equivalent, so
+.Ql #{a:98}
+results in
+.Ql b .
.Pp
A limit may be placed on the length of the resultant string by prefixing it
by an
@@ -4859,6 +4878,7 @@ The following variables are available, where appropriate:
.It Li "copy_cursor_word" Ta "" Ta "Word under cursor in copy mode"
.It Li "copy_cursor_x" Ta "" Ta "Cursor X position in copy mode"
.It Li "copy_cursor_y" Ta "" Ta "Cursor Y position in copy mode"
+.It Li "current_file" Ta "" Ta "Current configuration file"
.It Li "cursor_character" Ta "" Ta "Character at cursor in pane"
.It Li "cursor_flag" Ta "" Ta "Pane cursor flag"
.It Li "cursor_x" Ta "" Ta "Cursor X position in pane"
@@ -5545,7 +5565,7 @@ The following keys are also available:
.It Li "q" Ta "Exit menu"
.El
.It Xo Ic display-message
-.Op Fl aIpv
+.Op Fl aINpv
.Op Fl c Ar target-client
.Op Fl d Ar delay
.Op Fl t Ar target-pane
@@ -5565,6 +5585,8 @@ If
is not given, the
.Ic message-time
option is used; a delay of zero waits for a key press.
+.Ql N
+ignores key presses and closes only after the delay expires.
The format of
.Ar message
is described in the
@@ -5680,12 +5702,17 @@ The buffer commands are as follows:
.Op Fl NZr
.Op Fl F Ar format
.Op Fl f Ar filter
+.Op Fl K Ar key-format
.Op Fl O Ar sort-order
.Op Fl t Ar target-pane
.Op Ar template
.Xc
Put a pane into buffer mode, where a buffer may be chosen interactively from
a list.
+Each buffer is shown on one line.
+A shortcut key is shown on the left in brackets allowing for immediate choice,
+or the list may be navigated and an item chosen or otherwise manipulated using
+the keys below.
.Fl Z
zooms the pane.
The following keys may be used in buffer mode:
@@ -5733,7 +5760,9 @@ specifies an initial filter: the filter is a format - if it evaluates to zero,
the item in the list is not shown, otherwise it is shown.
If a filter would lead to an empty list, it is ignored.
.Fl F
-specifies the format for each item in the list.
+specifies the format for each item in the list and
+.Fl K
+a format for each shortcut key; both are evaluated once for each line.
.Fl N
starts without the preview.
This command works only if at least one client is attached.
@@ -6107,6 +6136,8 @@ A notification will never occur inside an output block.
.Pp
The following notifications are defined:
.Bl -tag -width Ds
+.It Ic %client-detached Ar client
+The client has detached.
.It Ic %client-session-changed Ar client session-id name
The client is now attached to the session with ID
.Ar session-id ,
diff --git a/tmux.h b/tmux.h
index ca71559f..6be5b302 100644
--- a/tmux.h
+++ b/tmux.h
@@ -1688,6 +1688,7 @@ struct client {
uint64_t redraw_panes;
+ int message_ignore_keys;
int message_ignore_styles;
char *message_string;
struct event message_timer;
@@ -2491,7 +2492,7 @@ struct style_range *status_get_range(struct client *, u_int, u_int);
void status_init(struct client *);
void status_free(struct client *);
int status_redraw(struct client *);
-void status_message_set(struct client *, int, int, const char *, ...);
+void status_message_set(struct client *, int, int, int, const char *, ...);
void status_message_clear(struct client *);
int status_message_redraw(struct client *);
void status_prompt_set(struct client *, struct cmd_find_state *,
@@ -2584,7 +2585,7 @@ void grid_reader_get_cursor(struct grid_reader *, u_int *, u_int *);
u_int grid_reader_line_length(struct grid_reader *);
int grid_reader_in_set(struct grid_reader *, const char *);
void grid_reader_cursor_right(struct grid_reader *, int, int);
-void grid_reader_cursor_left(struct grid_reader *);
+void grid_reader_cursor_left(struct grid_reader *, int);
void grid_reader_cursor_down(struct grid_reader *);
void grid_reader_cursor_up(struct grid_reader *);
void grid_reader_cursor_start_of_line(struct grid_reader *, int);
@@ -2597,6 +2598,7 @@ int grid_reader_cursor_jump(struct grid_reader *,
const struct utf8_data *);
int grid_reader_cursor_jump_back(struct grid_reader *,
const struct utf8_data *);
+void grid_reader_cursor_back_to_indentation(struct grid_reader *);
/* grid-view.c */
void grid_view_get_cell(struct grid *, u_int, u_int, struct grid_cell *);
@@ -2855,6 +2857,7 @@ typedef void (*mode_tree_draw_cb)(void *, void *, struct screen_write_ctx *,
typedef int (*mode_tree_search_cb)(void *, void *, const char *);
typedef void (*mode_tree_menu_cb)(void *, struct client *, key_code);
typedef u_int (*mode_tree_height_cb)(void *, u_int);
+typedef key_code (*mode_tree_key_cb)(void *, void *, u_int);
typedef void (*mode_tree_each_cb)(void *, void *, struct client *, key_code);
u_int mode_tree_count_tagged(struct mode_tree_data *);
void *mode_tree_get_current(struct mode_tree_data *);
@@ -2869,7 +2872,7 @@ void mode_tree_up(struct mode_tree_data *, int);
void mode_tree_down(struct mode_tree_data *, int);
struct mode_tree_data *mode_tree_start(struct window_pane *, struct args *,
mode_tree_build_cb, mode_tree_draw_cb, mode_tree_search_cb,
- mode_tree_menu_cb, mode_tree_height_cb, void *,
+ mode_tree_menu_cb, mode_tree_height_cb, mode_tree_key_cb, void *,
const struct menu_item *, const char **, u_int, struct screen **);
void mode_tree_zoom(struct mode_tree_data *, struct args *);
void mode_tree_build(struct mode_tree_data *);
@@ -2946,6 +2949,7 @@ void control_notify_window_unlinked(struct session *, struct window *);
void control_notify_window_linked(struct session *, struct window *);
void control_notify_window_renamed(struct window *);
void control_notify_client_session_changed(struct client *);
+void control_notify_client_detached(struct client *);
void control_notify_session_renamed(struct session *);
void control_notify_session_created(struct session *);
void control_notify_session_closed(struct session *);
diff --git a/tty-keys.c b/tty-keys.c
index 59426772..e88ff227 100644
--- a/tty-keys.c
+++ b/tty-keys.c
@@ -61,7 +61,7 @@ static int tty_keys_extended_device_attributes(struct tty *, const char *,
/* Default raw keys. */
struct tty_default_key_raw {
const char *string;
- key_code key;
+ key_code key;
};
static const struct tty_default_key_raw tty_default_raw_keys[] = {
/* Application escape. */
@@ -262,7 +262,7 @@ static const key_code tty_default_xterm_modifiers[] = {
*/
struct tty_default_key_code {
enum tty_code_code code;
- key_code key;
+ key_code key;
};
static const struct tty_default_key_code tty_default_code_keys[] = {
/* Function keys. */
@@ -420,7 +420,7 @@ tty_keys_add(struct tty *tty, const char *s, key_code key)
{
struct tty_key *tk;
size_t size;
- const char *keystr;
+ const char *keystr;
keystr = key_string_lookup_key(key, 1);
if ((tk = tty_keys_find(tty, s, strlen(s), &size)) == NULL) {
@@ -477,7 +477,7 @@ tty_keys_build(struct tty *tty)
const struct tty_default_key_raw *tdkr;
const struct tty_default_key_xterm *tdkx;
const struct tty_default_key_code *tdkc;
- u_int i, j;
+ u_int i, j;
const char *s;
struct options_entry *o;
struct options_array_item *a;
@@ -869,6 +869,9 @@ tty_keys_extended_key(struct tty *tty, const char *buf, size_t len,
size_t end;
u_int number, modifiers;
char tmp[64];
+ cc_t bspace;
+ key_code nkey;
+ key_code onlykey;
*size = 0;
@@ -911,38 +914,68 @@ tty_keys_extended_key(struct tty *tty, const char *buf, size_t len,
}
*size = end + 1;
- /* Store the key and modifiers. */
- *key = number;
+ /* Store the key. */
+ bspace = tty->tio.c_cc[VERASE];
+ if (bspace != _POSIX_VDISABLE && number == bspace)
+ nkey = KEYC_BSPACE;
+ else
+ nkey = number;
+
+ /* Update the modifiers. */
switch (modifiers) {
case 2:
- (*key) |= KEYC_SHIFT;
+ nkey |= KEYC_SHIFT;
break;
case 3:
- (*key) |= (KEYC_META|KEYC_IMPLIED_META);
+ nkey |= (KEYC_META|KEYC_IMPLIED_META);
break;
case 4:
- (*key) |= (KEYC_SHIFT|KEYC_META|KEYC_IMPLIED_META);
+ nkey |= (KEYC_SHIFT|KEYC_META|KEYC_IMPLIED_META);
break;
case 5:
- (*key) |= KEYC_CTRL;
+ nkey |= KEYC_CTRL;
break;
case 6:
- (*key) |= (KEYC_SHIFT|KEYC_CTRL);
+ nkey |= (KEYC_SHIFT|KEYC_CTRL);
break;
case 7:
- (*key) |= (KEYC_META|KEYC_CTRL);
+ nkey |= (KEYC_META|KEYC_CTRL);
break;
case 8:
- (*key) |= (KEYC_SHIFT|KEYC_META|KEYC_IMPLIED_META|KEYC_CTRL);
+ nkey |= (KEYC_SHIFT|KEYC_META|KEYC_IMPLIED_META|KEYC_CTRL);
break;
default:
*key = KEYC_NONE;
break;
}
+
+ /*
+ * Don't allow both KEYC_CTRL and as an implied modifier. Also convert
+ * C-X into C-x and so on.
+ */
+ if (nkey & KEYC_CTRL){
+ onlykey = (nkey & KEYC_MASK_KEY);
+ if (onlykey < 32)
+ onlykey = (nkey & ~KEYC_CTRL);
+ else {
+ if (onlykey >= 97 && onlykey <= 122)
+ onlykey -= 96;
+ else if (onlykey >= 64 && onlykey <= 95)
+ onlykey -= 64;
+ else if (onlykey == 32)
+ onlykey = 0;
+ else if (onlykey == 63)
+ onlykey = 127;
+ onlykey |= ((nkey & KEYC_MASK_MODIFIERS) & ~KEYC_CTRL);
+ }
+ nkey = onlykey;
+ }
+
if (log_get_level() != 0) {
log_debug("%s: extended key %.*s is %llx (%s)", c->name,
- (int)*size, buf, *key, key_string_lookup_key(*key, 1));
+ (int)*size, buf, nkey, key_string_lookup_key(nkey, 1));
}
+ *key = nkey;
return (0);
}
diff --git a/tty.c b/tty.c
index 399bbae8..e8a8cbaa 100644
--- a/tty.c
+++ b/tty.c
@@ -670,19 +670,10 @@ tty_update_mode(struct tty *tty, int mode, struct screen *s)
if (changed != 0)
log_debug("%s: update mode %x to %x", c->name, tty->mode, mode);
- if (changed & MODE_BLINKING) {
- if (tty_term_has(tty->term, TTYC_CVVIS))
- tty_putcode(tty, TTYC_CVVIS);
- else
- tty_putcode(tty, TTYC_CNORM);
- changed |= MODE_CURSOR;
- }
- if (changed & MODE_CURSOR) {
- if (mode & MODE_CURSOR)
- tty_putcode(tty, TTYC_CNORM);
- else
- tty_putcode(tty, TTYC_CIVIS);
- }
+ /*
+ * The cursor blinking flag can be reset by setting the cursor style, so
+ * set the style first.
+ */
if (s != NULL && tty->cstyle != s->cstyle) {
if (tty_term_has(tty->term, TTYC_SS)) {
if (s->cstyle == 0 && tty_term_has(tty->term, TTYC_SE))
@@ -691,7 +682,28 @@ tty_update_mode(struct tty *tty, int mode, struct screen *s)
tty_putcode1(tty, TTYC_SS, s->cstyle);
}
tty->cstyle = s->cstyle;
+ changed |= (MODE_CURSOR|MODE_BLINKING);
}
+
+ /*
+ * Cursor invisible (RM ?25) overrides cursor blinking (SM ?12 or RM
+ * 34), and we need to be careful not send cnorm after cvvis since it
+ * can undo it.
+ */
+ if (changed & (MODE_CURSOR|MODE_BLINKING)) {
+ log_debug("%s: cursor %s, %sblinking", __func__,
+ (mode & MODE_CURSOR) ? "on" : "off",
+ (mode & MODE_BLINKING) ? "" : "not ");
+ if (~mode & MODE_CURSOR)
+ tty_putcode(tty, TTYC_CIVIS);
+ else if (mode & MODE_BLINKING) {
+ tty_putcode(tty, TTYC_CNORM);
+ if (tty_term_has(tty->term, TTYC_CVVIS))
+ tty_putcode(tty, TTYC_CVVIS);
+ } else
+ tty_putcode(tty, TTYC_CNORM);
+ }
+
if ((changed & ALL_MOUSE_MODES) &&
tty_term_has(tty->term, TTYC_KMOUS)) {
/*
diff --git a/window-buffer.c b/window-buffer.c
index acdcb525..8d93558a 100644
--- a/window-buffer.c
+++ b/window-buffer.c
@@ -41,6 +41,17 @@ static void window_buffer_key(struct window_mode_entry *,
#define WINDOW_BUFFER_DEFAULT_FORMAT \
"#{t/p:buffer_created}: #{buffer_sample}"
+#define WINDOW_BUFFER_DEFAULT_KEY_FORMAT \
+ "#{?#{e|<:#{line},10}," \
+ "#{line}" \
+ "," \
+ "#{?#{e|<:#{line},36}," \
+ "M-#{a:#{e|+:97,#{e|-:#{line},10}}}" \
+ "," \
+ "" \
+ "}" \
+ "}"
+
static const struct menu_item window_buffer_menu_items[] = {
{ "Paste", 'p', NULL },
{ "Paste Tagged", 'P', NULL },
@@ -93,6 +104,7 @@ struct window_buffer_modedata {
struct mode_tree_data *data;
char *command;
char *format;
+ char *key_format;
struct window_buffer_itemdata **item_list;
u_int item_size;
@@ -232,7 +244,8 @@ window_buffer_draw(__unused void *modedata, void *itemdata,
while (end != pdata + psize && *end != '\n')
end++;
buf = xreallocarray(buf, 4, end - start + 1);
- utf8_strvis(buf, start, end - start, VIS_OCTAL|VIS_CSTYLE|VIS_TAB);
+ utf8_strvis(buf, start, end - start,
+ VIS_OCTAL|VIS_CSTYLE|VIS_TAB);
if (*buf != '\0') {
screen_write_cursormove(ctx, cx, cy + i, 0);
screen_write_nputs(ctx, sx, &grid_default_cell, "%s",
@@ -275,6 +288,41 @@ window_buffer_menu(void *modedata, struct client *c, key_code key)
window_buffer_key(wme, c, NULL, NULL, key, NULL);
}
+static key_code
+window_buffer_get_key(void *modedata, void *itemdata, u_int line)
+{
+ struct window_buffer_modedata *data = modedata;
+ struct window_buffer_itemdata *item = itemdata;
+ struct format_tree *ft;
+ struct session *s;
+ struct winlink *wl;
+ struct window_pane *wp;
+ struct paste_buffer *pb;
+ char *expanded;
+ key_code key;
+
+ if (cmd_find_valid_state(&data->fs)) {
+ s = data->fs.s;
+ wl = data->fs.wl;
+ wp = data->fs.wp;
+ }
+ pb = paste_get_name(item->name);
+ if (pb == NULL)
+ return KEYC_NONE;
+
+ ft = format_create(NULL, NULL, FORMAT_NONE, 0);
+ format_defaults(ft, NULL, NULL, 0, NULL);
+ format_defaults(ft, NULL, s, wl, wp);
+ format_defaults_paste_buffer(ft, pb);
+ format_add(ft, "line", "%u", line);
+
+ expanded = format_expand(ft, data->key_format);
+ key = key_string_lookup_string(expanded);
+ free(expanded);
+ format_free(ft);
+ return key;
+}
+
static struct screen *
window_buffer_init(struct window_mode_entry *wme, struct cmd_find_state *fs,
struct args *args)
@@ -291,6 +339,10 @@ window_buffer_init(struct window_mode_entry *wme, struct cmd_find_state *fs,
data->format = xstrdup(WINDOW_BUFFER_DEFAULT_FORMAT);
else
data->format = xstrdup(args_get(args, 'F'));
+ if (args == NULL || !args_has(args, 'K'))
+ data->key_format = xstrdup(WINDOW_BUFFER_DEFAULT_KEY_FORMAT);
+ else
+ data->key_format = xstrdup(args_get(args, 'K'));
if (args == NULL || args->argc == 0)
data->command = xstrdup(WINDOW_BUFFER_DEFAULT_COMMAND);
else
@@ -298,8 +350,8 @@ window_buffer_init(struct window_mode_entry *wme, struct cmd_find_state *fs,
data->data = mode_tree_start(wp, args, window_buffer_build,
window_buffer_draw, window_buffer_search, window_buffer_menu, NULL,
- data, window_buffer_menu_items, window_buffer_sort_list,
- nitems(window_buffer_sort_list), &s);
+ window_buffer_get_key, data, window_buffer_menu_items,
+ window_buffer_sort_list, nitems(window_buffer_sort_list), &s);
mode_tree_zoom(data->data, args);
mode_tree_build(data->data);
@@ -324,6 +376,7 @@ window_buffer_free(struct window_mode_entry *wme)
free(data->item_list);
free(data->format);
+ free(data->key_format);
free(data->command);
free(data);
diff --git a/window-client.c b/window-client.c
index ec3c646a..db7c6dcc 100644
--- a/window-client.c
+++ b/window-client.c
@@ -40,6 +40,17 @@ static void window_client_key(struct window_mode_entry *,
#define WINDOW_CLIENT_DEFAULT_FORMAT \
"#{t/p:client_activity}: session #{session_name}"
+#define WINDOW_CLIENT_DEFAULT_KEY_FORMAT \
+ "#{?#{e|<:#{line},10}," \
+ "#{line}" \
+ "," \
+ "#{?#{e|<:#{line},36}," \
+ "M-#{a:#{e|+:97,#{e|-:#{line},10}}}" \
+ "," \
+ "" \
+ "}" \
+ "}"
+
static const struct menu_item window_client_menu_items[] = {
{ "Detach", 'd', NULL },
{ "Detach Tagged", 'D', NULL },
@@ -87,6 +98,7 @@ struct window_client_modedata {
struct mode_tree_data *data;
char *format;
+ char *key_format;
char *command;
struct window_client_itemdata **item_list;
@@ -252,6 +264,26 @@ window_client_menu(void *modedata, struct client *c, key_code key)
window_client_key(wme, c, NULL, NULL, key, NULL);
}
+static key_code
+window_client_get_key(void *modedata, void *itemdata, u_int line)
+{
+ struct window_client_modedata *data = modedata;
+ struct window_client_itemdata *item = itemdata;
+ struct format_tree *ft;
+ char *expanded;
+ key_code key;
+
+ ft = format_create(NULL, NULL, FORMAT_NONE, 0);
+ format_defaults(ft, item->c, NULL, 0, NULL);
+ format_add(ft, "line", "%u", line);
+
+ expanded = format_expand(ft, data->key_format);
+ key = key_string_lookup_string(expanded);
+ free(expanded);
+ format_free(ft);
+ return key;
+}
+
static struct screen *
window_client_init(struct window_mode_entry *wme,
__unused struct cmd_find_state *fs, struct args *args)
@@ -267,15 +299,19 @@ window_client_init(struct window_mode_entry *wme,
data->format = xstrdup(WINDOW_CLIENT_DEFAULT_FORMAT);
else
data->format = xstrdup(args_get(args, 'F'));
+ if (args == NULL || !args_has(args, 'K'))
+ data->key_format = xstrdup(WINDOW_CLIENT_DEFAULT_KEY_FORMAT);
+ else
+ data->key_format = xstrdup(args_get(args, 'K'));
if (args == NULL || args->argc == 0)
data->command = xstrdup(WINDOW_CLIENT_DEFAULT_COMMAND);
else
data->command = xstrdup(args->argv[0]);
data->data = mode_tree_start(wp, args, window_client_build,
- window_client_draw, NULL, window_client_menu, NULL, data,
- window_client_menu_items, window_client_sort_list,
- nitems(window_client_sort_list), &s);
+ window_client_draw, NULL, window_client_menu, NULL,
+ window_client_get_key, data, window_client_menu_items,
+ window_client_sort_list, nitems(window_client_sort_list), &s);
mode_tree_zoom(data->data, args);
mode_tree_build(data->data);
@@ -300,6 +336,7 @@ window_client_free(struct window_mode_entry *wme)
free(data->item_list);
free(data->format);
+ free(data->key_format);
free(data->command);
free(data);
diff --git a/window-copy.c b/window-copy.c
index 3fc7ad3e..423cce8f 100644
--- a/window-copy.c
+++ b/window-copy.c
@@ -64,6 +64,8 @@ static int window_copy_search_rl(struct grid *, struct grid *, u_int *,
static int window_copy_last_regex(struct grid *, u_int, u_int, u_int,
u_int, u_int *, u_int *, const char *, const regex_t *,
int);
+static int window_copy_search_mark_at(struct window_copy_mode_data *,
+ u_int, u_int, u_int *);
static char *window_copy_stringify(struct grid *, u_int, u_int, u_int,
char *, u_int *);
static void window_copy_cstrtocellpos(struct grid *, u_int, u_int *,
@@ -71,16 +73,15 @@ static void window_copy_cstrtocellpos(struct grid *, u_int, u_int *,
static int window_copy_search_marks(struct window_mode_entry *,
struct screen *, int, int);
static void window_copy_clear_marks(struct window_mode_entry *);
-static void window_copy_move_left(struct screen *, u_int *, u_int *, int);
static int window_copy_is_lowercase(const char *);
static void window_copy_search_back_overlap(struct grid *, regex_t *,
u_int *, u_int *, u_int *, u_int);
static int window_copy_search_jump(struct window_mode_entry *,
struct grid *, struct grid *, u_int, u_int, u_int, int, int,
- int, int, u_int *);
-static int window_copy_search(struct window_mode_entry *, int, int, int);
-static int window_copy_search_up(struct window_mode_entry *, int, int);
-static int window_copy_search_down(struct window_mode_entry *, int, int);
+ int, int);
+static int window_copy_search(struct window_mode_entry *, int, int);
+static int window_copy_search_up(struct window_mode_entry *, int);
+static int window_copy_search_down(struct window_mode_entry *, int);
static void window_copy_goto_line(struct window_mode_entry *, const char *);
static void window_copy_update_cursor(struct window_mode_entry *, u_int,
u_int);
@@ -275,6 +276,7 @@ struct window_copy_mode_data {
int showmark;
int searchtype;
+ int searchdirection;
int searchregex;
char *searchstr;
u_char *searchmark;
@@ -1718,10 +1720,10 @@ window_copy_cmd_search_again(struct window_copy_cmd_state *cs)
if (data->searchtype == WINDOW_COPY_SEARCHUP) {
for (; np != 0; np--)
- window_copy_search_up(wme, data->searchregex, 1);
+ window_copy_search_up(wme, data->searchregex);
} else if (data->searchtype == WINDOW_COPY_SEARCHDOWN) {
for (; np != 0; np--)
- window_copy_search_down(wme, data->searchregex, 1);
+ window_copy_search_down(wme, data->searchregex);
}
return (WINDOW_COPY_CMD_NOTHING);
}
@@ -1735,10 +1737,10 @@ window_copy_cmd_search_reverse(struct window_copy_cmd_state *cs)
if (data->searchtype == WINDOW_COPY_SEARCHUP) {
for (; np != 0; np--)
- window_copy_search_down(wme, data->searchregex, 1);
+ window_copy_search_down(wme, data->searchregex);
} else if (data->searchtype == WINDOW_COPY_SEARCHDOWN) {
for (; np != 0; np--)
- window_copy_search_up(wme, data->searchregex, 1);
+ window_copy_search_up(wme, data->searchregex);
}
return (WINDOW_COPY_CMD_NOTHING);
}
@@ -2042,7 +2044,7 @@ window_copy_cmd_search_backward(struct window_copy_cmd_state *cs)
data->searchregex = 1;
data->timeout = 0;
for (; np != 0; np--)
- window_copy_search_up(wme, 1, 0);
+ window_copy_search_up(wme, 1);
}
return (WINDOW_COPY_CMD_NOTHING);
}
@@ -2062,7 +2064,7 @@ window_copy_cmd_search_backward_text(struct window_copy_cmd_state *cs)
data->searchregex = 0;
data->timeout = 0;
for (; np != 0; np--)
- window_copy_search_up(wme, 0, 0);
+ window_copy_search_up(wme, 0);
}
return (WINDOW_COPY_CMD_NOTHING);
}
@@ -2082,7 +2084,7 @@ window_copy_cmd_search_forward(struct window_copy_cmd_state *cs)
data->searchregex = 1;
data->timeout = 0;
for (; np != 0; np--)
- window_copy_search_down(wme, 1, 0);
+ window_copy_search_down(wme, 1);
}
return (WINDOW_COPY_CMD_NOTHING);
}
@@ -2102,7 +2104,7 @@ window_copy_cmd_search_forward_text(struct window_copy_cmd_state *cs)
data->searchregex = 0;
data->timeout = 0;
for (; np != 0; np--)
- window_copy_search_down(wme, 0, 0);
+ window_copy_search_down(wme, 0);
}
return (WINDOW_COPY_CMD_NOTHING);
}
@@ -2143,7 +2145,7 @@ window_copy_cmd_search_backward_incremental(struct window_copy_cmd_state *cs)
data->searchregex = 0;
free(data->searchstr);
data->searchstr = xstrdup(argument);
- if (!window_copy_search_up(wme, 0, 1)) {
+ if (!window_copy_search_up(wme, 0)) {
window_copy_clear_marks(wme);
return (WINDOW_COPY_CMD_REDRAW);
}
@@ -2153,7 +2155,7 @@ window_copy_cmd_search_backward_incremental(struct window_copy_cmd_state *cs)
data->searchregex = 0;
free(data->searchstr);
data->searchstr = xstrdup(argument);
- if (!window_copy_search_down(wme, 0, 0)) {
+ if (!window_copy_search_down(wme, 0)) {
window_copy_clear_marks(wme);
return (WINDOW_COPY_CMD_REDRAW);
}
@@ -2198,7 +2200,7 @@ window_copy_cmd_search_forward_incremental(struct window_copy_cmd_state *cs)
data->searchregex = 0;
free(data->searchstr);
data->searchstr = xstrdup(argument);
- if (!window_copy_search_down(wme, 0, 1)) {
+ if (!window_copy_search_down(wme, 0)) {
window_copy_clear_marks(wme);
return (WINDOW_COPY_CMD_REDRAW);
}
@@ -2208,7 +2210,7 @@ window_copy_cmd_search_forward_incremental(struct window_copy_cmd_state *cs)
data->searchregex = 0;
free(data->searchstr);
data->searchstr = xstrdup(argument);
- if (!window_copy_search_up(wme, 0, 1)) {
+ if (!window_copy_search_up(wme, 0)) {
window_copy_clear_marks(wme);
return (WINDOW_COPY_CMD_REDRAW);
}
@@ -2917,6 +2919,23 @@ window_copy_move_left(struct screen *s, u_int *fx, u_int *fy, int wrapflag)
*fx = *fx - 1;
}
+static void
+window_copy_move_right(struct screen *s, u_int *fx, u_int *fy, int wrapflag)
+{
+ if (*fx == screen_size_x(s) - 1) { /* right */
+ if (*fy == screen_hsize(s) + screen_size_y(s) - 1) { /* bottom */
+ if (wrapflag) {
+ *fx = 0;
+ *fy = 0;
+ }
+ return;
+ }
+ *fx = 0;
+ *fy = *fy + 1;
+ } else
+ *fx = *fx + 1;
+}
+
static int
window_copy_is_lowercase(const char *ptr)
{
@@ -2979,7 +2998,7 @@ window_copy_search_back_overlap(struct grid *gd, regex_t *preg, u_int *ppx,
static int
window_copy_search_jump(struct window_mode_entry *wme, struct grid *gd,
struct grid *sgd, u_int fx, u_int fy, u_int endline, int cis, int wrap,
- int direction, int regex, u_int *foundlen)
+ int direction, int regex)
{
u_int i, px, sx, ssize = 1;
int found = 0, cflags = REG_EXTENDED;
@@ -3004,20 +3023,15 @@ window_copy_search_jump(struct window_mode_entry *wme, struct grid *gd,
if (regex) {
found = window_copy_search_lr_regex(gd,
&px, &sx, i, fx, gd->sx, &reg);
- if (found)
- *foundlen = sx;
} else {
found = window_copy_search_lr(gd, sgd,
&px, i, fx, gd->sx, cis);
- if (found)
- *foundlen = sgd->sx;
}
if (found)
break;
fx = 0;
}
} else {
- *foundlen = 0;
for (i = fy + 1; endline < i; i--) {
if (regex) {
found = window_copy_search_rl_regex(gd,
@@ -3048,18 +3062,40 @@ window_copy_search_jump(struct window_mode_entry *wme, struct grid *gd,
return (window_copy_search_jump(wme, gd, sgd,
direction ? 0 : gd->sx - 1,
direction ? 0 : gd->hsize + gd->sy - 1, fy, cis, 0,
- direction, regex, foundlen));
+ direction, regex));
}
return (0);
}
+static void
+window_copy_move_after_search_mark(struct window_copy_mode_data *data,
+ u_int *fx, u_int *fy, int wrapflag)
+{
+ struct screen *s = data->backing;
+ u_int at, start;
+
+ if (window_copy_search_mark_at(data, *fx, *fy, &start) == 0 &&
+ data->searchmark[start] != 0) {
+ while (window_copy_search_mark_at(data, *fx, *fy, &at) == 0) {
+ if (data->searchmark[at] != data->searchmark[start])
+ break;
+ /* Stop if not wrapping and at the end of the grid. */
+ if (!wrapflag &&
+ *fx == screen_size_x(s) - 1 &&
+ *fy == screen_hsize(s) + screen_size_y(s) - 1)
+ break;
+
+ window_copy_move_right(s, fx, fy, wrapflag);
+ }
+ }
+}
+
/*
* Search in for text searchstr. If direction is 0 then search up, otherwise
* down.
*/
static int
-window_copy_search(struct window_mode_entry *wme, int direction, int regex,
- int again)
+window_copy_search(struct window_mode_entry *wme, int direction, int regex)
{
struct window_pane *wp = wme->wp;
struct window_copy_mode_data *data = wme->data;
@@ -3067,12 +3103,15 @@ window_copy_search(struct window_mode_entry *wme, int direction, int regex,
struct screen_write_ctx ctx;
struct grid *gd = s->grid;
const char *str = data->searchstr;
- u_int fx, fy, endline, i, foundlen;
- int wrapflag, cis, found, visible_only;
+ u_int at, endline, fx, fy, start;
+ int cis, found, keys, visible_only;
+ int wrapflag;
if (regex && str[strcspn(str, "^$*+()?[].\\")] == '\0')
regex = 0;
+ data->searchdirection = direction;
+
if (data->timeout)
return (0);
@@ -3097,27 +3136,94 @@ window_copy_search(struct window_mode_entry *wme, int direction, int regex,
wrapflag = options_get_number(wp->window->options, "wrap-search");
cis = window_copy_is_lowercase(str);
- if (direction)
+ keys = options_get_number(wp->window->options, "mode-keys");
+
+ if (direction) {
+ /*
+ * Behave according to mode-keys. If it is emacs, search forward
+ * leaves the cursor after the match. If it is vi, the cursor
+ * remains at the beginning of the match, regardless of
+ * direction, which means that we need to start the next search
+ * after the term the cursor is currently on when searching
+ * forward.
+ */
+ if (keys == MODEKEY_VI) {
+ if (data->searchmark != NULL)
+ window_copy_move_after_search_mark(data, &fx,
+ &fy, wrapflag);
+ else {
+ /*
+ * When there are no search marks, start the
+ * search after the current cursor position.
+ */
+ window_copy_move_right(s, &fx, &fy, wrapflag);
+ }
+ }
endline = gd->hsize + gd->sy - 1;
+ }
else {
- if (again)
- window_copy_move_left(s, &fx, &fy, wrapflag);
+ window_copy_move_left(s, &fx, &fy, wrapflag);
endline = 0;
}
found = window_copy_search_jump(wme, gd, ss.grid, fx, fy, endline, cis,
- wrapflag, direction, regex, &foundlen);
+ wrapflag, direction, regex);
if (found) {
window_copy_search_marks(wme, &ss, regex, visible_only);
- if (foundlen != 0) {
- /* Adjust for wrapped lines eating one right. */
- i = data->cx + foundlen;
- while (i > gd->sx - 1) {
- i -= gd->sx;
- window_copy_cursor_right(wme, 1);
+ fx = data->cx;
+ fy = screen_hsize(data->backing) - data->oy + data->cy;
+
+ /*
+ * When searching forward, if the cursor is not at the beginning
+ * of the mark, search again.
+ */
+ if (direction &&
+ window_copy_search_mark_at(data, fx, fy, &at) == 0 &&
+ at > 0 &&
+ data->searchmark[at] == data->searchmark[at - 1]) {
+ window_copy_move_after_search_mark(data, &fx, &fy,
+ wrapflag);
+ window_copy_search_jump(wme, gd, ss.grid, fx,
+ fy, endline, cis, wrapflag, direction,
+ regex);
+ fx = data->cx;
+ fy = screen_hsize(data->backing) - data->oy + data->cy;
+ }
+
+ if (direction) {
+ /*
+ * When in Emacs mode, position the cursor just after
+ * the mark.
+ */
+ if (keys == MODEKEY_EMACS) {
+ window_copy_move_after_search_mark(data, &fx,
+ &fy, wrapflag);
+ data->cx = fx;
+ data->cy = fy - screen_hsize(data->backing) +
+ data-> oy;
+ }
+ }
+ else {
+ /*
+ * When searching backward, position the cursor at the
+ * beginning of the mark.
+ */
+ if (window_copy_search_mark_at(data, fx, fy,
+ &start) == 0) {
+ while (window_copy_search_mark_at(data, fx, fy,
+ &at) == 0 &&
+ data->searchmark[at] ==
+ data->searchmark[start]) {
+ data->cx = fx;
+ data->cy = fy -
+ screen_hsize(data->backing) +
+ data-> oy;
+ if (at == 0)
+ break;
+
+ window_copy_move_left(s, &fx, &fy, 0);
+ }
}
- for (i = 0; i < foundlen; i++)
- window_copy_cursor_right(wme, 1);
}
}
window_copy_redraw_screen(wme);
@@ -3302,15 +3408,15 @@ window_copy_clear_marks(struct window_mode_entry *wme)
}
static int
-window_copy_search_up(struct window_mode_entry *wme, int regex, int again)
+window_copy_search_up(struct window_mode_entry *wme, int regex)
{
- return (window_copy_search(wme, 0, regex, again));
+ return (window_copy_search(wme, 0, regex));
}
static int
-window_copy_search_down(struct window_mode_entry *wme, int regex, int again)
+window_copy_search_down(struct window_mode_entry *wme, int regex)
{
- return (window_copy_search(wme, 1, regex, again));
+ return (window_copy_search(wme, 1, regex));
}
static void
@@ -3396,9 +3502,11 @@ window_copy_update_style(struct window_mode_entry *wme, u_int fx, u_int fy,
struct grid_cell *gc, const struct grid_cell *mgc,
const struct grid_cell *cgc, const struct grid_cell *mkgc)
{
+ struct window_pane *wp = wme->wp;
struct window_copy_mode_data *data = wme->data;
u_int mark, start, end, cy, cursor, current;
int inv = 0, found = 0;
+ int keys;
if (data->showmark && fy == data->my) {
gc->attr = mkgc->attr;
@@ -3425,13 +3533,16 @@ window_copy_update_style(struct window_mode_entry *wme, u_int fx, u_int fy,
cy = screen_hsize(data->backing) - data->oy + data->cy;
if (window_copy_search_mark_at(data, data->cx, cy, &cursor) == 0) {
- if (data->searchmark[cursor] == mark)
- found = 1;
- else if (cursor != 0) {
- cursor--;
- if (data->searchmark[cursor] == mark)
+ keys = options_get_number(wp->window->options, "mode-keys");
+ if (cursor != 0 &&
+ keys == MODEKEY_EMACS &&
+ data->searchdirection) {
+ if (data->searchmark[cursor - 1] == mark) {
+ cursor--;
found = 1;
- }
+ }
+ } else if (data->searchmark[cursor] == mark)
+ found = 1;
if (found) {
window_copy_match_start_end(data, cursor, &start, &end);
if (current >= start && current <= end) {
@@ -4180,23 +4291,19 @@ static void
window_copy_cursor_back_to_indentation(struct window_mode_entry *wme)
{
struct window_copy_mode_data *data = wme->data;
- u_int px, py, xx;
- struct grid_cell gc;
-
- px = 0;
- py = screen_hsize(data->backing) + data->cy - data->oy;
- xx = window_copy_find_length(wme, py);
+ struct screen *back_s = data->backing;
+ struct grid_reader gr;
+ u_int px, py, oldy, hsize;
- while (px < xx) {
- grid_get_cell(data->backing->grid, px, py, &gc);
- if (gc.data.size != 1 || *gc.data.data != ' ')
- break;
- px++;
- }
+ px = data->cx;
+ hsize = screen_hsize(back_s);
+ py = hsize + data->cy - data->oy;
+ oldy = data->cy;
- window_copy_update_cursor(wme, px, data->cy);
- if (window_copy_update_selection(wme, 1, 0))
- window_copy_redraw_lines(wme, data->cy, 1);
+ grid_reader_start(&gr, back_s->grid, px, py);
+ grid_reader_cursor_back_to_indentation(&gr);
+ grid_reader_get_cursor(&gr, &px, &py);
+ window_copy_acquire_cursor_up(wme, hsize, data->oy, oldy, px, py);
}
static void
@@ -4287,7 +4394,7 @@ window_copy_cursor_left(struct window_mode_entry *wme)
oldy = data->cy;
grid_reader_start(&gr, back_s->grid, px, py);
- grid_reader_cursor_left(&gr);
+ grid_reader_cursor_left(&gr, 1);
grid_reader_get_cursor(&gr, &px, &py);
window_copy_acquire_cursor_up(wme, hsize, data->oy, oldy, px, py);
}
@@ -4472,10 +4579,8 @@ window_copy_cursor_jump_back(struct window_mode_entry *wme)
py = hsize + data->cy - data->oy;
oldy = data->cy;
- if (px > 0)
- px--;
-
grid_reader_start(&gr, back_s->grid, px, py);
+ grid_reader_cursor_left(&gr, 0);
if (grid_reader_cursor_jump_back(&gr, data->jumpchar)) {
grid_reader_get_cursor(&gr, &px, &py);
window_copy_acquire_cursor_up(wme, hsize, data->oy, oldy, px,
@@ -4498,7 +4603,7 @@ window_copy_cursor_jump_to(struct window_mode_entry *wme)
grid_reader_start(&gr, back_s->grid, px, py);
if (grid_reader_cursor_jump(&gr, data->jumpchar)) {
- grid_reader_cursor_left(&gr);
+ grid_reader_cursor_left(&gr, 1);
grid_reader_get_cursor(&gr, &px, &py);
window_copy_acquire_cursor_down(wme, hsize,
screen_size_y(back_s), data->oy, oldy, px, py, 0);
@@ -4518,13 +4623,9 @@ window_copy_cursor_jump_to_back(struct window_mode_entry *wme)
py = hsize + data->cy - data->oy;
oldy = data->cy;
- if (px > 0)
- px--;
-
- if (px > 0)
- px--;
-
grid_reader_start(&gr, back_s->grid, px, py);
+ grid_reader_cursor_left(&gr, 0);
+ grid_reader_cursor_left(&gr, 0);
if (grid_reader_cursor_jump_back(&gr, data->jumpchar)) {
grid_reader_cursor_right(&gr, 1, 0);
grid_reader_get_cursor(&gr, &px, &py);
@@ -4577,7 +4678,7 @@ window_copy_cursor_next_word_end_pos(struct window_mode_entry *wme,
grid_reader_cursor_right(&gr, 0, 0);
grid_reader_cursor_next_word_end(&gr, separators);
if (keys == MODEKEY_VI)
- grid_reader_cursor_left(&gr);
+ grid_reader_cursor_left(&gr, 1);
grid_reader_get_cursor(&gr, &px, &py);
*ppx = px;
*ppy = py;
@@ -4607,7 +4708,7 @@ window_copy_cursor_next_word_end(struct window_mode_entry *wme,
grid_reader_cursor_right(&gr, 0, 0);
grid_reader_cursor_next_word_end(&gr, separators);
if (keys == MODEKEY_VI)
- grid_reader_cursor_left(&gr);
+ grid_reader_cursor_left(&gr, 1);
grid_reader_get_cursor(&gr, &px, &py);
window_copy_acquire_cursor_down(wme, hsize, screen_size_y(back_s),
data->oy, oldy, px, py, no_reset);
diff --git a/window-customize.c b/window-customize.c
index a1f191b5..34a13f73 100644
--- a/window-customize.c
+++ b/window-customize.c
@@ -890,8 +890,8 @@ window_customize_init(struct window_mode_entry *wme, struct cmd_find_state *fs,
data->data = mode_tree_start(wp, args, window_customize_build,
window_customize_draw, NULL, window_customize_menu,
- window_customize_height, data, window_customize_menu_items, NULL, 0,
- &s);
+ window_customize_height, NULL, data, window_customize_menu_items,
+ NULL, 0, &s);
mode_tree_zoom(data->data, args);
mode_tree_build(data->data);
@@ -999,7 +999,7 @@ window_customize_set_option_callback(struct client *c, void *itemdata,
fail:
*cause = toupper((u_char)*cause);
- status_message_set(c, -1, 1, "%s", cause);
+ status_message_set(c, -1, 1, 0, "%s", cause);
free(cause);
return (0);
}
@@ -1205,7 +1205,7 @@ window_customize_set_command_callback(struct client *c, void *itemdata,
fail:
*error = toupper((u_char)*error);
- status_message_set(c, -1, 1, "%s", error);
+ status_message_set(c, -1, 1, 0, "%s", error);
free(error);
return (0);
}
diff --git a/window-tree.c b/window-tree.c
index cc822ac3..33af0413 100644
--- a/window-tree.c
+++ b/window-tree.c
@@ -56,6 +56,17 @@ static void window_tree_key(struct window_mode_entry *,
"}" \
"}"
+#define WINDOW_TREE_DEFAULT_KEY_FORMAT \
+ "#{?#{e|<:#{line},10}," \
+ "#{line}" \
+ "," \
+ "#{?#{e|<:#{line},36}," \
+ "M-#{a:#{e|+:97,#{e|-:#{line},10}}}" \
+ "," \
+ "" \
+ "}" \
+ "}"
+
static const struct menu_item window_tree_menu_items[] = {
{ "Select", '\r', NULL },
{ "Expand", KEYC_RIGHT, NULL },
@@ -117,6 +128,7 @@ struct window_tree_modedata {
struct mode_tree_data *data;
char *format;
+ char *key_format;
char *command;
int squash_groups;
@@ -856,6 +868,35 @@ window_tree_menu(void *modedata, struct client *c, key_code key)
window_tree_key(wme, c, NULL, NULL, key, NULL);
}
+static key_code
+window_tree_get_key(void *modedata, void *itemdata, u_int line)
+{
+ struct window_tree_modedata *data = modedata;
+ struct window_tree_itemdata *item = itemdata;
+ struct format_tree *ft;
+ struct session *s;
+ struct winlink *wl;
+ struct window_pane *wp;
+ char *expanded;
+ key_code key;
+
+ ft = format_create(NULL, NULL, FORMAT_NONE, 0);
+ window_tree_pull_item(item, &s, &wl, &wp);
+ if (item->type == WINDOW_TREE_SESSION)
+ format_defaults(ft, NULL, s, NULL, NULL);
+ else if (item->type == WINDOW_TREE_WINDOW)
+ format_defaults(ft, NULL, s, wl, NULL);
+ else
+ format_defaults(ft, NULL, s, wl, wp);
+ format_add(ft, "line", "%u", line);
+
+ expanded = format_expand(ft, data->key_format);
+ key = key_string_lookup_string(expanded);
+ free(expanded);
+ format_free(ft);
+ return key;
+}
+
static struct screen *
window_tree_init(struct window_mode_entry *wme, struct cmd_find_state *fs,
struct args *args)
@@ -880,6 +921,10 @@ window_tree_init(struct window_mode_entry *wme, struct cmd_find_state *fs,
data->format = xstrdup(WINDOW_TREE_DEFAULT_FORMAT);
else
data->format = xstrdup(args_get(args, 'F'));
+ if (args == NULL || !args_has(args, 'K'))
+ data->key_format = xstrdup(WINDOW_TREE_DEFAULT_KEY_FORMAT);
+ else
+ data->key_format = xstrdup(args_get(args, 'K'));
if (args == NULL || args->argc == 0)
data->command = xstrdup(WINDOW_TREE_DEFAULT_COMMAND);
else
@@ -887,9 +932,9 @@ window_tree_init(struct window_mode_entry *wme, struct cmd_find_state *fs,
data->squash_groups = !args_has(args, 'G');
data->data = mode_tree_start(wp, args, window_tree_build,
- window_tree_draw, window_tree_search, window_tree_menu, NULL, data,
- window_tree_menu_items, window_tree_sort_list,
- nitems(window_tree_sort_list), &s);
+ window_tree_draw, window_tree_search, window_tree_menu, NULL,
+ window_tree_get_key, data, window_tree_menu_items,
+ window_tree_sort_list, nitems(window_tree_sort_list), &s);
mode_tree_zoom(data->data, args);
mode_tree_build(data->data);
@@ -913,6 +958,7 @@ window_tree_destroy(struct window_tree_modedata *data)
free(data->item_list);
free(data->format);
+ free(data->key_format);
free(data->command);
free(data);