aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosh Rahm <rahm@google.com>2023-01-27 23:04:47 +0000
committerJosh Rahm <rahm@google.com>2023-01-27 23:04:47 +0000
commite64dc03ff7b867826c7fc76d6fff210ad3382e33 (patch)
tree9cf71b02a7ee8f6d39ae1207201dc0745bdb8be5
parentfb15fd116097b98c1b839cfdc76a7d84e206e6d5 (diff)
parentf5af3cfb211c12897b15e3b5a3b29c4bbb0493a8 (diff)
downloadrtmux-e64dc03ff7b867826c7fc76d6fff210ad3382e33.tar.gz
rtmux-e64dc03ff7b867826c7fc76d6fff210ad3382e33.tar.bz2
rtmux-e64dc03ff7b867826c7fc76d6fff210ad3382e33.zip
Merge remote-tracking branch 'upstream/master' into rahm
-rw-r--r--arguments.c213
-rw-r--r--client.c9
-rw-r--r--cmd-break-pane.c1
-rw-r--r--cmd-capture-pane.c18
-rw-r--r--cmd-display-menu.c29
-rw-r--r--cmd-display-message.c10
-rw-r--r--cmd-find-window.c4
-rw-r--r--cmd-find.c10
-rw-r--r--cmd-join-pane.c1
-rw-r--r--cmd-list-keys.c11
-rw-r--r--cmd-parse.y3
-rw-r--r--cmd-queue.c96
-rw-r--r--cmd-save-buffer.c13
-rw-r--r--cmd-send-keys.c37
-rw-r--r--cmd-swap-pane.c2
-rw-r--r--colour.c42
-rw-r--r--compat.h1
-rw-r--r--compat/getpeereid.c5
-rw-r--r--compat/systemd.c10
-rw-r--r--configure.ac6
-rw-r--r--control-notify.c26
-rw-r--r--control.c4
-rw-r--r--environ.c15
-rw-r--r--file.c48
-rw-r--r--format.c30
-rw-r--r--grid-view.c2
-rw-r--r--grid.c88
-rw-r--r--input-keys.c26
-rw-r--r--input.c143
-rw-r--r--key-bindings.c5
-rw-r--r--key-string.c4
-rw-r--r--menu.c120
-rw-r--r--mode-tree.c4
-rw-r--r--notify.c37
-rw-r--r--options-table.c23
-rw-r--r--paste.c11
-rw-r--r--popup.c2
-rw-r--r--regress/conf/2eae5d47049c1f6d0bef3db4e171aed7.conf2
-rw-r--r--regress/conf/a46e6e84cd1071105aa807256dbc158d.conf2
-rw-r--r--regress/conf/ad21dbb0893240563ddfdd954b9903a1.conf2
-rw-r--r--regress/conf/b9f0ce1976ec62ec60dc5da7dd92c160.conf6
-rw-r--r--regress/conf/e2661d67d0d45a8647fb95de76ec8174.conf2
-rw-r--r--regress/input-keys.sh299
-rw-r--r--regress/tty-keys.sh361
-rw-r--r--screen-write.c27
-rw-r--r--server-client.c28
-rw-r--r--session.c9
-rw-r--r--spawn.c2
-rw-r--r--status.c41
-rw-r--r--tmux-protocol.h7
-rw-r--r--tmux.1113
-rw-r--r--tmux.c2
-rw-r--r--tmux.h100
-rw-r--r--tty-features.c64
-rw-r--r--tty-keys.c218
-rw-r--r--tty-term.c5
-rw-r--r--tty.c57
-rw-r--r--utf8.c11
-rw-r--r--window-buffer.c7
-rw-r--r--window-copy.c78
-rw-r--r--window.c22
61 files changed, 2083 insertions, 491 deletions
diff --git a/arguments.c b/arguments.c
index 46777f7f..9a3115dc 100644
--- a/arguments.c
+++ b/arguments.c
@@ -37,6 +37,10 @@ struct args_entry {
u_char flag;
struct args_values values;
u_int count;
+
+ int flags;
+#define ARGS_ENTRY_OPTIONAL_VALUE 0x1
+
RB_ENTRY(args_entry) entry;
};
@@ -122,6 +126,99 @@ args_create(void)
return (args);
}
+/* Parse a single flag. */
+static int
+args_parse_flag_argument(struct args_value *values, u_int count, char **cause,
+ struct args *args, u_int *i, const char *string, int flag,
+ int optional_argument)
+{
+ struct args_value *argument, *new;
+ const char *s;
+
+ new = xcalloc(1, sizeof *new);
+ if (*string != '\0') {
+ new->type = ARGS_STRING;
+ new->string = xstrdup(string);
+ goto out;
+ }
+
+ if (*i == count)
+ argument = NULL;
+ else {
+ argument = &values[*i];
+ if (argument->type != ARGS_STRING) {
+ xasprintf(cause, "-%c argument must be a string", flag);
+ return (-1);
+ }
+ }
+ if (argument == NULL) {
+ if (optional_argument) {
+ log_debug("%s: -%c (optional)", __func__, flag);
+ args_set(args, flag, NULL, ARGS_ENTRY_OPTIONAL_VALUE);
+ return (0); /* either - or end */
+ }
+ xasprintf(cause, "-%c expects an argument", flag);
+ return (-1);
+ }
+ args_copy_value(new, argument);
+ (*i)++;
+
+out:
+ s = args_value_as_string(new);
+ log_debug("%s: -%c = %s", __func__, flag, s);
+ args_set(args, flag, new, 0);
+ return (0);
+}
+
+/* Parse flags argument. */
+static int
+args_parse_flags(const struct args_parse *parse, struct args_value *values,
+ u_int count, char **cause, struct args *args, int *i)
+{
+ struct args_value *value;
+ u_char flag;
+ const char *found, *string;
+ int optional_argument;
+
+ value = &values[*i];
+ if (value->type != ARGS_STRING)
+ return (1);
+
+ string = value->string;
+ log_debug("%s: next %s", __func__, string);
+ if (*string++ != '-' || *string == '\0')
+ return (1);
+ (*i)++;
+ if (string[0] == '-' && string[1] == '\0')
+ return (1);
+
+ for (;;) {
+ flag = *string++;
+ if (flag == '\0')
+ return (0);
+ if (flag == '?')
+ return (-1);
+ if (!isalnum(flag)) {
+ xasprintf(cause, "invalid flag -%c", flag);
+ return (-1);
+ }
+
+ found = strchr(parse->template, flag);
+ if (found == NULL) {
+ xasprintf(cause, "unknown flag -%c", flag);
+ return (-1);
+ }
+ if (found[1] != ':') {
+ log_debug("%s: -%c", __func__, flag);
+ args_set(args, flag, NULL, 0);
+ continue;
+ }
+ optional_argument = (found[2] == ':');
+ return (args_parse_flag_argument(values, count, cause, args, i,
+ string, flag, optional_argument));
+ }
+}
+
/* Parse arguments into a new argument set. */
struct args *
args_parse(const struct args_parse *parse, struct args_value *values,
@@ -131,86 +228,21 @@ args_parse(const struct args_parse *parse, struct args_value *values,
u_int i;
enum args_parse_type type;
struct args_value *value, *new;
- u_char flag;
- const char *found, *string, *s;
- int optional_argument;
+ const char *s;
+ int stop;
if (count == 0)
return (args_create());
args = args_create();
for (i = 1; i < count; /* nothing */) {
- value = &values[i];
- if (value->type != ARGS_STRING)
- break;
-
- string = value->string;
- if (*string++ != '-' || *string == '\0')
- break;
- i++;
- if (string[0] == '-' && string[1] == '\0')
- break;
-
- for (;;) {
- flag = *string++;
- if (flag == '\0')
- break;
- if (flag == '?') {
- args_free(args);
- return (NULL);
- }
- if (!isalnum(flag)) {
- xasprintf(cause, "invalid flag -%c", flag);
- args_free(args);
- return (NULL);
- }
- found = strchr(parse->template, flag);
- if (found == NULL) {
- xasprintf(cause, "unknown flag -%c", flag);
- args_free(args);
- return (NULL);
- }
- if (*++found != ':') {
- log_debug("%s: -%c", __func__, flag);
- args_set(args, flag, NULL);
- continue;
- }
- if (*found == ':') {
- optional_argument = 1;
- found++;
- }
- new = xcalloc(1, sizeof *new);
- if (*string != '\0') {
- new->type = ARGS_STRING;
- new->string = xstrdup(string);
- } else {
- if (i == count) {
- if (optional_argument) {
- log_debug("%s: -%c", __func__,
- flag);
- args_set(args, flag, NULL);
- continue;
- }
- xasprintf(cause,
- "-%c expects an argument",
- flag);
- args_free(args);
- return (NULL);
- }
- if (values[i].type != ARGS_STRING) {
- xasprintf(cause,
- "-%c argument must be a string",
- flag);
- args_free(args);
- return (NULL);
- }
- args_copy_value(new, &values[i++]);
- }
- s = args_value_as_string(new);
- log_debug("%s: -%c = %s", __func__, flag, s);
- args_set(args, flag, new);
- break;
+ stop = args_parse_flags(parse, values, count, cause, args, &i);
+ if (stop == -1) {
+ args_free(args);
+ return (NULL);
}
+ if (stop == 1)
+ break;
}
log_debug("%s: flags end at %u of %u", __func__, i, count);
if (i != count) {
@@ -323,13 +355,13 @@ args_copy(struct args *args, int argc, char **argv)
RB_FOREACH(entry, args_tree, &args->tree) {
if (TAILQ_EMPTY(&entry->values)) {
for (i = 0; i < entry->count; i++)
- args_set(new_args, entry->flag, NULL);
+ args_set(new_args, entry->flag, NULL, 0);
continue;
}
TAILQ_FOREACH(value, &entry->values, entry) {
new_value = xcalloc(1, sizeof *new_value);
args_copy_copy_value(new_value, value, argc, argv);
- args_set(new_args, entry->flag, new_value);
+ args_set(new_args, entry->flag, new_value, 0);
}
}
if (args->count == 0)
@@ -487,6 +519,7 @@ args_print(struct args *args)
char *buf;
u_int i, j;
struct args_entry *entry;
+ struct args_entry *last = NULL;
struct args_value *value;
len = 1;
@@ -494,6 +527,8 @@ args_print(struct args *args)
/* Process the flags first. */
RB_FOREACH(entry, args_tree, &args->tree) {
+ if (entry->flags & ARGS_ENTRY_OPTIONAL_VALUE)
+ continue;
if (!TAILQ_EMPTY(&entry->values))
continue;
@@ -505,6 +540,16 @@ args_print(struct args *args)
/* Then the flags with arguments. */
RB_FOREACH(entry, args_tree, &args->tree) {
+ if (entry->flags & ARGS_ENTRY_OPTIONAL_VALUE) {
+ if (*buf != '\0')
+ args_print_add(&buf, &len, " -%c", entry->flag);
+ else
+ args_print_add(&buf, &len, "-%c", entry->flag);
+ last = entry;
+ continue;
+ }
+ if (TAILQ_EMPTY(&entry->values))
+ continue;
TAILQ_FOREACH(value, &entry->values, entry) {
if (*buf != '\0')
args_print_add(&buf, &len, " -%c", entry->flag);
@@ -512,7 +557,10 @@ args_print(struct args *args)
args_print_add(&buf, &len, "-%c", entry->flag);
args_print_add_value(&buf, &len, value);
}
+ last = entry;
}
+ if (last && (last->flags & ARGS_ENTRY_OPTIONAL_VALUE))
+ args_print_add(&buf, &len, " --");
/* And finally the argument vector. */
for (i = 0; i < args->count; i++)
@@ -582,7 +630,7 @@ args_has(struct args *args, u_char flag)
/* Set argument value in the arguments tree. */
void
-args_set(struct args *args, u_char flag, struct args_value *value)
+args_set(struct args *args, u_char flag, struct args_value *value, int flags)
{
struct args_entry *entry;
@@ -591,6 +639,7 @@ args_set(struct args *args, u_char flag, struct args_value *value)
entry = xcalloc(1, sizeof *entry);
entry->flag = flag;
entry->count = 1;
+ entry->flags = flags;
TAILQ_INIT(&entry->values);
RB_INSERT(args_tree, &args->tree, entry);
} else
@@ -895,6 +944,10 @@ args_percentage(struct args *args, u_char flag, long long minval,
*cause = xstrdup("missing");
return (0);
}
+ if (TAILQ_EMPTY(&entry->values)) {
+ *cause = xstrdup("empty");
+ return (0);
+ }
value = TAILQ_LAST(&entry->values, args_values)->string;
return (args_string_percentage(value, minval, maxval, curval, cause));
}
@@ -909,6 +962,10 @@ args_string_percentage(const char *value, long long minval, long long maxval,
size_t valuelen = strlen(value);
char *copy;
+ if (valuelen == 0) {
+ *cause = xstrdup("empty");
+ return (0);
+ }
if (value[valuelen - 1] == '%') {
copy = xstrdup(value);
copy[valuelen - 1] = '\0';
@@ -955,6 +1012,10 @@ args_percentage_and_expand(struct args *args, u_char flag, long long minval,
*cause = xstrdup("missing");
return (0);
}
+ if (TAILQ_EMPTY(&entry->values)) {
+ *cause = xstrdup("empty");
+ return (0);
+ }
value = TAILQ_LAST(&entry->values, args_values)->string;
return (args_string_percentage_and_expand(value, minval, maxval, curval,
item, cause));
diff --git a/client.c b/client.c
index df6cee94..374c1146 100644
--- a/client.c
+++ b/client.c
@@ -284,6 +284,12 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags,
log_debug("flags are %#llx", (unsigned long long)client_flags);
/* Initialize the client socket and start the server. */
+#ifdef HAVE_SYSTEMD
+ if (systemd_activated()) {
+ /* socket-based activation, do not even try to be a client. */
+ fd = server_start(client_proc, flags, base, 0, NULL);
+ } else
+#endif
fd = client_connect(base, socket_path, client_flags);
if (fd == -1) {
if (errno == ECONNREFUSED) {
@@ -694,6 +700,9 @@ client_dispatch_wait(struct imsg *imsg)
!(client_flags & CLIENT_CONTROL), client_file_check_cb,
NULL);
break;
+ case MSG_READ_CANCEL:
+ file_read_cancel(&client_files, imsg);
+ break;
case MSG_WRITE_OPEN:
file_write_open(&client_files, client_peer, imsg, 1,
!(client_flags & CLIENT_CONTROL), client_file_check_cb,
diff --git a/cmd-break-pane.c b/cmd-break-pane.c
index 4f38d4bd..9c4b1508 100644
--- a/cmd-break-pane.c
+++ b/cmd-break-pane.c
@@ -115,6 +115,7 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
layout_init(w, wp);
wp->flags |= PANE_CHANGED;
+ colour_palette_from_option(&wp->palette, wp->options);
if (idx == -1)
idx = -1 - options_get_number(dst_s->options, "base-index");
diff --git a/cmd-capture-pane.c b/cmd-capture-pane.c
index 422f87d6..57e9716d 100644
--- a/cmd-capture-pane.c
+++ b/cmd-capture-pane.c
@@ -40,7 +40,7 @@ const struct cmd_entry cmd_capture_pane_entry = {
.alias = "capturep",
.args = { "ab:CeE:JNpPqS:t:", 0, 0, NULL },
- .usage = "[-aCeJNpPq] " CMD_BUFFER_USAGE " [-E end-line] "
+ .usage = "[-aCeJNpPqT] " CMD_BUFFER_USAGE " [-E end-line] "
"[-S start-line] " CMD_TARGET_PANE_USAGE,
.target = { 't', CMD_FIND_PANE, 0 },
@@ -110,7 +110,7 @@ cmd_capture_pane_history(struct args *args, struct cmdq_item *item,
struct grid *gd;
const struct grid_line *gl;
struct grid_cell *gc = NULL;
- int n, with_codes, escape_c0, join_lines, no_trim;
+ int n, join_lines, flags = 0;
u_int i, sx, top, bottom, tmp;
char *cause, *buf, *line;
const char *Sflag, *Eflag;
@@ -169,15 +169,19 @@ cmd_capture_pane_history(struct args *args, struct cmdq_item *item,
top = tmp;
}
- with_codes = args_has(args, 'e');
- escape_c0 = args_has(args, 'C');
join_lines = args_has(args, 'J');
- no_trim = args_has(args, 'N');
+ if (args_has(args, 'e'))
+ flags |= GRID_STRING_WITH_SEQUENCES;
+ if (args_has(args, 'C'))
+ flags |= GRID_STRING_ESCAPE_SEQUENCES;
+ if (!join_lines && !args_has(args, 'T'))
+ flags |= GRID_STRING_EMPTY_CELLS;
+ if (!join_lines && !args_has(args, 'N'))
+ flags |= GRID_STRING_TRIM_SPACES;
buf = NULL;
for (i = top; i <= bottom; i++) {
- line = grid_string_cells(gd, 0, i, sx, &gc, with_codes,
- escape_c0, !join_lines && !no_trim, wp->screen);
+ line = grid_string_cells(gd, 0, i, sx, &gc, flags, wp->screen);
linelen = strlen(line);
buf = cmd_capture_pane_append(buf, len, line, linelen);
diff --git a/cmd-display-menu.c b/cmd-display-menu.c
index e6a503b1..22cc5d9f 100644
--- a/cmd-display-menu.c
+++ b/cmd-display-menu.c
@@ -38,9 +38,10 @@ const struct cmd_entry cmd_display_menu_entry = {
.name = "display-menu",
.alias = "menu",
- .args = { "c:t:OT:x:y:", 1, -1, cmd_display_menu_args_parse },
- .usage = "[-O] [-c target-client] " CMD_TARGET_PANE_USAGE " [-T title] "
- "[-x position] [-y position] name key command ...",
+ .args = { "c:t:S:OT:x:y:", 1, -1, cmd_display_menu_args_parse },
+ .usage = "[-O] [-c target-client] [-S starting-choice] "
+ CMD_TARGET_PANE_USAGE " [-T title] [-x position] "
+ "[-y position] name key command ...",
.target = { 't', CMD_FIND_PANE, 0 },
@@ -287,13 +288,27 @@ cmd_display_menu_exec(struct cmd *self, struct cmdq_item *item)
struct menu *menu = NULL;
struct menu_item menu_item;
const char *key, *name;
- char *title;
- int flags = 0;
+ char *title, *cause;
+ int flags = 0, starting_choice = 0;
u_int px, py, i, count = args_count(args);
if (tc->overlay_draw != NULL)
return (CMD_RETURN_NORMAL);
+ if (args_has(args, 'S')) {
+ if (strcmp(args_get(args, 'S'), "-") == 0)
+ starting_choice = -1;
+ else {
+ starting_choice = args_strtonum(args, 'S', 0, UINT_MAX,
+ &cause);
+ if (cause != NULL) {
+ cmdq_error(item, "starting choice %s", cause);
+ free(cause);
+ return (CMD_RETURN_ERROR);
+ }
+ }
+ }
+
if (args_has(args, 'T'))
title = format_single_from_target(item, args_get(args, 'T'));
else
@@ -340,8 +355,8 @@ cmd_display_menu_exec(struct cmd *self, struct cmdq_item *item)
flags |= MENU_STAYOPEN;
if (!event->m.valid)
flags |= MENU_NOMOUSE;
- if (menu_display(menu, flags, item, px, py, tc, target, NULL,
- NULL) != 0)
+ if (menu_display(menu, flags, starting_choice, item, px, py, tc, target,
+ NULL, NULL) != 0)
return (CMD_RETURN_NORMAL);
return (CMD_RETURN_WAIT);
}
diff --git a/cmd-display-message.c b/cmd-display-message.c
index 7828f694..f5e91020 100644
--- a/cmd-display-message.c
+++ b/cmd-display-message.c
@@ -39,8 +39,8 @@ const struct cmd_entry cmd_display_message_entry = {
.name = "display-message",
.alias = "display",
- .args = { "ac:d:INpt:F:v", 0, 1, NULL },
- .usage = "[-aINpv] [-c target-client] [-d delay] [-F format] "
+ .args = { "ac:d:lINpt:F:v", 0, 1, NULL },
+ .usage = "[-aIlNpv] [-c target-client] [-d delay] [-F format] "
CMD_TARGET_PANE_USAGE " [message]",
.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
@@ -132,7 +132,11 @@ cmd_display_message_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_NORMAL);
}
- msg = format_expand_time(ft, template);
+ if (args_has(args, 'l'))
+ msg = xstrdup(template);
+ else
+ msg = format_expand_time(ft, template);
+
if (cmdq_get_client(item) == NULL)
cmdq_error(item, "%s", msg);
else if (args_has(args, 'p'))
diff --git a/cmd-find-window.c b/cmd-find-window.c
index 6e07537c..cb9afacb 100644
--- a/cmd-find-window.c
+++ b/cmd-find-window.c
@@ -103,8 +103,8 @@ cmd_find_window_exec(struct cmd *self, struct cmdq_item *item)
new_args = args_create();
if (args_has(args, 'Z'))
- args_set(new_args, 'Z', NULL);
- args_set(new_args, 'f', filter);
+ args_set(new_args, 'Z', NULL, 0);
+ args_set(new_args, 'f', filter, 0);
window_pane_set_mode(wp, NULL, &window_tree_mode, target, new_args);
args_free(new_args);
diff --git a/cmd-find.c b/cmd-find.c
index e98090d2..154cadac 100644
--- a/cmd-find.c
+++ b/cmd-find.c
@@ -587,22 +587,22 @@ cmd_find_get_pane_with_window(struct cmd_find_state *fs, const char *pane)
return (-1);
return (0);
} else if (strcmp(pane, "{up-of}") == 0) {
- fs->wp = window_pane_find_up(fs->current->wp);
+ fs->wp = window_pane_find_up(fs->w->active);
if (fs->wp == NULL)
return (-1);
return (0);
} else if (strcmp(pane, "{down-of}") == 0) {
- fs->wp = window_pane_find_down(fs->current->wp);
+ fs->wp = window_pane_find_down(fs->w->active);
if (fs->wp == NULL)
return (-1);
return (0);
} else if (strcmp(pane, "{left-of}") == 0) {
- fs->wp = window_pane_find_left(fs->current->wp);
+ fs->wp = window_pane_find_left(fs->w->active);
if (fs->wp == NULL)
return (-1);
return (0);
} else if (strcmp(pane, "{right-of}") == 0) {
- fs->wp = window_pane_find_right(fs->current->wp);
+ fs->wp = window_pane_find_right(fs->w->active);
if (fs->wp == NULL)
return (-1);
return (0);
@@ -614,7 +614,7 @@ cmd_find_get_pane_with_window(struct cmd_find_state *fs, const char *pane)
n = strtonum(pane + 1, 1, INT_MAX, NULL);
else
n = 1;
- wp = fs->current->wp;
+ wp = fs->w->active;
if (pane[0] == '+')
fs->wp = window_pane_next_by_number(fs->w, wp, n);
else
diff --git a/cmd-join-pane.c b/cmd-join-pane.c
index e82b4cde..da1ba9ae 100644
--- a/cmd-join-pane.c
+++ b/cmd-join-pane.c
@@ -155,6 +155,7 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
else
TAILQ_INSERT_AFTER(&dst_w->panes, dst_wp, src_wp, entry);
layout_assign_pane(lc, src_wp, 0);
+ colour_palette_from_option(&src_wp->palette, src_wp->options);
recalculate_sizes();
diff --git a/cmd-list-keys.c b/cmd-list-keys.c
index ae9f995c..395b147c 100644
--- a/cmd-list-keys.c
+++ b/cmd-list-keys.c
@@ -148,6 +148,7 @@ static enum cmd_retval
cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
+ struct client *tc = cmdq_get_target_client(item);
struct key_table *table;
struct key_binding *bd;
const char *tablename, *r, *keystr;
@@ -296,9 +297,15 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
strlcat(tmp, cp, tmpsize);
free(cp);
- cmdq_print(item, "bind-key %s", tmp);
-
+ if (args_has(args, '1') && tc != NULL) {
+ status_message_set(tc, -1, 1, 0, "bind-key %s",
+ tmp);
+ } else
+ cmdq_print(item, "bind-key %s", tmp);
free(key);
+
+ if (args_has(args, '1'))
+ break;
bd = key_bindings_next(table, bd);
}
table = key_bindings_next_table(table);
diff --git a/cmd-parse.y b/cmd-parse.y
index 1d692770..cdf026f3 100644
--- a/cmd-parse.y
+++ b/cmd-parse.y
@@ -1086,7 +1086,8 @@ cmd_parse_from_arguments(struct args_value *values, u_int count,
arg->type = CMD_PARSE_STRING;
arg->string = copy;
TAILQ_INSERT_TAIL(&cmd->arguments, arg, entry);
- }
+ } else
+ free(copy);
} else if (values[i].type == ARGS_COMMANDS) {
arg = xcalloc(1, sizeof *arg);
arg->type = CMD_PARSE_PARSED_COMMANDS;
diff --git a/cmd-queue.c b/cmd-queue.c
index 8325e2e8..78b379de 100644
--- a/cmd-queue.c
+++ b/cmd-queue.c
@@ -823,43 +823,89 @@ cmdq_guard(struct cmdq_item *item, const char *guard, int flags)
/* Show message from command. */
void
-cmdq_print(struct cmdq_item *item, const char *fmt, ...)
+cmdq_print_data(struct cmdq_item *item, int parse, struct evbuffer *evb)
{
struct client *c = item->client;
+ void *data = EVBUFFER_DATA(evb);
+ size_t size = EVBUFFER_LE