aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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 ch