Merge branch 'master' into floating_panes

This commit is contained in:
Michael Grant
2026-03-04 13:16:52 +00:00
43 changed files with 980 additions and 437 deletions

2
.github/README.md vendored
View File

@@ -79,7 +79,7 @@ A small example configuration is in `example_tmux.conf`.
And a bash(1) completion file at: And a bash(1) completion file at:
https://github.com/scop/bash-completion/blob/main/completions/tmux https://github.com/scop/bash-completion/blob/main/completions-core/tmux.bash
For debugging, run tmux with `-v` or `-vv` to generate server and client log For debugging, run tmux with `-v` or `-vv` to generate server and client log
files in the current directory. files in the current directory.

View File

@@ -29,6 +29,7 @@ Ted Unangst <tedu@openbsd.org> tedu <tedu>
Theo de Raadt <deraadt@openbsd.org> Theo Deraadt <deraadt@openbsd.org> Theo de Raadt <deraadt@openbsd.org> Theo Deraadt <deraadt@openbsd.org>
Theo de Raadt <deraadt@openbsd.org> deraadt <deraadt> Theo de Raadt <deraadt@openbsd.org> deraadt <deraadt>
Thomas Adam <thomas@xteddy.org> Thomas <thomas@xteddy.org> Thomas Adam <thomas@xteddy.org> Thomas <thomas@xteddy.org>
Thomas Adam <thomas@xteddy.org> Thomas Adam <thomas.adam22@gmail.com>
Thomas Adam <thomas@xteddy.org> Thomas Adam <thomas.adam@smoothwall.net> Thomas Adam <thomas@xteddy.org> Thomas Adam <thomas.adam@smoothwall.net>
Thomas Adam <thomas@xteddy.org> n6tadam <n6tadam@xteddy.org> Thomas Adam <thomas@xteddy.org> n6tadam <n6tadam@xteddy.org>
Tim van der Molen <tim@openbsd.org> tim <tim> Tim van der Molen <tim@openbsd.org> tim <tim>

View File

@@ -106,6 +106,7 @@ dist_tmux_SOURCES = \
cmd-kill-window.c \ cmd-kill-window.c \
cmd-list-buffers.c \ cmd-list-buffers.c \
cmd-list-clients.c \ cmd-list-clients.c \
cmd-list-commands.c \
cmd-list-keys.c \ cmd-list-keys.c \
cmd-list-panes.c \ cmd-list-panes.c \
cmd-list-sessions.c \ cmd-list-sessions.c \

View File

@@ -98,6 +98,13 @@ cmd_choose_tree_exec(struct cmd *self, struct cmdq_item *item)
struct cmd_find_state *target = cmdq_get_target(item); struct cmd_find_state *target = cmdq_get_target(item);
struct window_pane *wp = target->wp; struct window_pane *wp = target->wp;
const struct window_mode *mode; const struct window_mode *mode;
enum sort_order order;
order = sort_order_from_string(args_get(args, 'O'));
if (order == SORT_END && args_has(args, 'O')) {
cmdq_error(item, "invalid sort order");
return (CMD_RETURN_ERROR);
}
if (cmd_get_entry(self) == &cmd_choose_buffer_entry) { if (cmd_get_entry(self) == &cmd_choose_buffer_entry) {
if (paste_is_empty()) if (paste_is_empty())

View File

@@ -92,6 +92,7 @@ cmd_confirm_before_exec(struct cmd *self, struct cmdq_item *item)
cdata->confirm_key = confirm_key[0]; cdata->confirm_key = confirm_key[0];
else { else {
cmdq_error(item, "invalid confirm key"); cmdq_error(item, "invalid confirm key");
cmd_list_free(cdata->cmdlist);
free(cdata); free(cdata);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }

View File

@@ -36,7 +36,7 @@ const struct cmd_entry cmd_copy_mode_entry = {
.source = { 's', CMD_FIND_PANE, 0 }, .source = { 's', CMD_FIND_PANE, 0 },
.target = { 't', CMD_FIND_PANE, 0 }, .target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK, .flags = CMD_AFTERHOOK|CMD_READONLY,
.exec = cmd_copy_mode_exec .exec = cmd_copy_mode_exec
}; };

View File

@@ -294,7 +294,7 @@ cmd_display_menu_exec(struct cmd *self, struct cmdq_item *item)
const char *border_style = args_get(args, 'S'); const char *border_style = args_get(args, 'S');
const char *selected_style = args_get(args, 'H'); const char *selected_style = args_get(args, 'H');
enum box_lines lines = BOX_LINES_DEFAULT; enum box_lines lines = BOX_LINES_DEFAULT;
char *title, *cause; char *title, *cause = NULL;
int flags = 0, starting_choice = 0; int flags = 0, starting_choice = 0;
u_int px, py, i, count = args_count(args); u_int px, py, i, count = args_count(args);
struct options *o = target->s->curw->window->options; struct options *o = target->s->curw->window->options;
@@ -312,8 +312,7 @@ cmd_display_menu_exec(struct cmd *self, struct cmdq_item *item)
&cause); &cause);
if (cause != NULL) { if (cause != NULL) {
cmdq_error(item, "starting choice %s", cause); cmdq_error(item, "starting choice %s", cause);
free(cause); goto fail;
return (CMD_RETURN_ERROR);
} }
} }
} }
@@ -334,8 +333,7 @@ cmd_display_menu_exec(struct cmd *self, struct cmdq_item *item)
if (count - i < 2) { if (count - i < 2) {
cmdq_error(item, "not enough arguments"); cmdq_error(item, "not enough arguments");
menu_free(menu); goto fail;
return (CMD_RETURN_ERROR);
} }
key = args_string(args, i++); key = args_string(args, i++);
@@ -347,17 +345,13 @@ cmd_display_menu_exec(struct cmd *self, struct cmdq_item *item)
} }
if (menu == NULL) { if (menu == NULL) {
cmdq_error(item, "invalid menu arguments"); cmdq_error(item, "invalid menu arguments");
return (CMD_RETURN_ERROR); goto fail;
}
if (menu->count == 0) {
menu_free(menu);
return (CMD_RETURN_NORMAL);
} }
if (menu->count == 0)
goto out;
if (!cmd_display_menu_get_pos(tc, item, args, &px, &py, menu->width + 4, if (!cmd_display_menu_get_pos(tc, item, args, &px, &py, menu->width + 4,
menu->count + 2)) { menu->count + 2))
menu_free(menu); goto out;
return (CMD_RETURN_NORMAL);
}
value = args_get(args, 'b'); value = args_get(args, 'b');
if (value != NULL) { if (value != NULL) {
@@ -366,8 +360,7 @@ cmd_display_menu_exec(struct cmd *self, struct cmdq_item *item)
&cause); &cause);
if (lines == -1) { if (lines == -1) {
cmdq_error(item, "menu-border-lines %s", cause); cmdq_error(item, "menu-border-lines %s", cause);
free(cause); goto fail;
return (CMD_RETURN_ERROR);
} }
} }
@@ -379,6 +372,15 @@ cmd_display_menu_exec(struct cmd *self, struct cmdq_item *item)
style, selected_style, border_style, target, NULL, NULL) != 0) style, selected_style, border_style, target, NULL, NULL) != 0)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
return (CMD_RETURN_WAIT); return (CMD_RETURN_WAIT);
out:
menu_free(menu);
return (CMD_RETURN_NORMAL);
fail:
free(cause);
menu_free(menu);
return (CMD_RETURN_ERROR);
} }
static enum cmd_retval static enum cmd_retval
@@ -393,7 +395,7 @@ cmd_display_popup_exec(struct cmd *self, struct cmdq_item *item)
const char *style = args_get(args, 's'); const char *style = args_get(args, 's');
const char *border_style = args_get(args, 'S'); const char *border_style = args_get(args, 'S');
char *cwd = NULL, *cause = NULL, **argv = NULL; char *cwd = NULL, *cause = NULL, **argv = NULL;
char *title; char *title = NULL;
int modify = popup_present(tc); int modify = popup_present(tc);
int flags = -1, argc = 0; int flags = -1, argc = 0;
enum box_lines lines = BOX_LINES_DEFAULT; enum box_lines lines = BOX_LINES_DEFAULT;
@@ -417,8 +419,7 @@ cmd_display_popup_exec(struct cmd *self, struct cmdq_item *item)
&cause); &cause);
if (cause != NULL) { if (cause != NULL) {
cmdq_error(item, "height %s", cause); cmdq_error(item, "height %s", cause);
free(cause); goto fail;
return (CMD_RETURN_ERROR);
} }
} }
@@ -428,8 +429,7 @@ cmd_display_popup_exec(struct cmd *self, struct cmdq_item *item)
&cause); &cause);
if (cause != NULL) { if (cause != NULL) {
cmdq_error(item, "width %s", cause); cmdq_error(item, "width %s", cause);
free(cause); goto fail;
return (CMD_RETURN_ERROR);
} }
} }
@@ -438,7 +438,7 @@ cmd_display_popup_exec(struct cmd *self, struct cmdq_item *item)
if (h > tty->sy) if (h > tty->sy)
h = tty->sy; h = tty->sy;
if (!cmd_display_menu_get_pos(tc, item, args, &px, &py, w, h)) if (!cmd_display_menu_get_pos(tc, item, args, &px, &py, w, h))
return (CMD_RETURN_NORMAL); goto out;
value = args_get(args, 'd'); value = args_get(args, 'd');
if (value != NULL) if (value != NULL)
@@ -478,8 +478,7 @@ cmd_display_popup_exec(struct cmd *self, struct cmdq_item *item)
&cause); &cause);
if (cause != NULL) { if (cause != NULL) {
cmdq_error(item, "popup-border-lines %s", cause); cmdq_error(item, "popup-border-lines %s", cause);
free(cause); goto fail;
return (CMD_RETURN_ERROR);
} }
} }
@@ -507,22 +506,29 @@ cmd_display_popup_exec(struct cmd *self, struct cmdq_item *item)
if (modify) { if (modify) {
popup_modify(tc, title, style, border_style, lines, flags); popup_modify(tc, title, style, border_style, lines, flags);
free(title); goto out;
return (CMD_RETURN_NORMAL);
} }
if (popup_display(flags, lines, item, px, py, w, h, env, shellcmd, argc, if (popup_display(flags, lines, item, px, py, w, h, env, shellcmd, argc,
argv, cwd, title, tc, s, style, border_style, NULL, NULL) != 0) { argv, cwd, title, tc, s, style, border_style, NULL, NULL) != 0)
cmd_free_argv(argc, argv); goto out;
if (env != NULL)
environ_free(env);
free(cwd);
free(title);
return (CMD_RETURN_NORMAL);
}
if (env != NULL)
environ_free(env); environ_free(env);
free(cwd); free(cwd);
free(title); free(title);
cmd_free_argv(argc, argv); cmd_free_argv(argc, argv);
return (CMD_RETURN_WAIT); return (CMD_RETURN_WAIT);
out:
cmd_free_argv(argc, argv);
environ_free(env);
free(cwd);
free(title);
return (CMD_RETURN_NORMAL);
fail:
free(cause);
cmd_free_argv(argc, argv);
environ_free(env);
free(cwd);
free(title);
return (CMD_RETURN_ERROR);
} }

View File

@@ -131,6 +131,7 @@ cmd_display_message_exec(struct cmd *self, struct cmdq_item *item)
if (args_has(args, 'a')) { if (args_has(args, 'a')) {
format_each(ft, cmd_display_message_each, item); format_each(ft, cmd_display_message_each, item);
format_free(ft);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
@@ -155,6 +156,5 @@ cmd_display_message_exec(struct cmd *self, struct cmdq_item *item)
free(msg); free(msg);
format_free(ft); format_free(ft);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@@ -60,6 +60,10 @@ cmd_list_buffers_exec(struct cmd *self, struct cmdq_item *item)
filter = args_get(args, 'f'); filter = args_get(args, 'f');
sort_crit.order = sort_order_from_string(args_get(args, 'O')); sort_crit.order = sort_order_from_string(args_get(args, 'O'));
if (sort_crit.order == SORT_END && args_has(args, 'O')) {
cmdq_error(item, "invalid sort order");
return (CMD_RETURN_ERROR);
}
sort_crit.reversed = args_has(args, 'r'); sort_crit.reversed = args_has(args, 'r');
l = sort_get_buffers(&n, &sort_crit); l = sort_get_buffers(&n, &sort_crit);

View File

@@ -74,6 +74,10 @@ cmd_list_clients_exec(struct cmd *self, struct cmdq_item *item)
filter = args_get(args, 'f'); filter = args_get(args, 'f');
sort_crit.order = sort_order_from_string(args_get(args, 'O')); sort_crit.order = sort_order_from_string(args_get(args, 'O'));
if (sort_crit.order == SORT_END && args_has(args, 'O')) {
cmdq_error(item, "invalid sort order");
return (CMD_RETURN_ERROR);
}
sort_crit.reversed = args_has(args, 'r'); sort_crit.reversed = args_has(args, 'r');
l = sort_get_clients(&n, &sort_crit); l = sort_get_clients(&n, &sort_crit);

107
cmd-list-commands.c Normal file
View File

@@ -0,0 +1,107 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
/*
* List all commands.
*/
#define LIST_COMMANDS_TEMPLATE \
"#{command_list_name}" \
"#{?command_list_alias, (#{command_list_alias}),} " \
"#{command_list_usage}"
static enum cmd_retval cmd_list_commands(struct cmd *, struct cmdq_item *);
const struct cmd_entry cmd_list_commands_entry = {
.name = "list-commands",
.alias = "lscm",
.args = { "F:", 0, 1, NULL },
.usage = "[-F format] [command]",
.flags = CMD_STARTSERVER|CMD_AFTERHOOK,
.exec = cmd_list_commands
};
static void
cmd_list_single_command(const struct cmd_entry *entry, struct format_tree *ft,
const char *template, struct cmdq_item *item)
{
const char *s;
char *line;
format_add(ft, "command_list_name", "%s", entry->name);
if (entry->alias != NULL)
s = entry->alias;
else
s = "";
format_add(ft, "command_list_alias", "%s", s);
if (entry->usage != NULL)
s = entry->usage;
else
s = "";
format_add(ft, "command_list_usage", "%s", s);
line = format_expand(ft, template);
if (*line != '\0')
cmdq_print(item, "%s", line);
free(line);
}
static enum cmd_retval
cmd_list_commands(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
const struct cmd_entry **entryp;
const struct cmd_entry *entry;
struct format_tree *ft;
const char *template, *command;
char *cause;
if ((template = args_get(args, 'F')) == NULL)
template = LIST_COMMANDS_TEMPLATE;
ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0);
format_defaults(ft, NULL, NULL, NULL, NULL);
command = args_string(args, 0);
if (command == NULL) {
for (entryp = cmd_table; *entryp != NULL; entryp++)
cmd_list_single_command(*entryp, ft, template, item);
} else {
entry = cmd_find(command, &cause);
if (entry != NULL)
cmd_list_single_command(entry, ft, template, item);
else {
cmdq_error(item, "%s", cause);
free(cause);
format_free(ft);
return (CMD_RETURN_ERROR);
}
}
format_free(ft);
return (CMD_RETURN_NORMAL);
}

View File

@@ -27,122 +27,140 @@
* List key bindings. * List key bindings.
*/ */
static enum cmd_retval cmd_list_keys_exec(struct cmd *, struct cmdq_item *); #define LIST_KEYS_TEMPLATE \
"#{?notes_only," \
"#{key_prefix} " \
"#{p|#{key_string_width}:key_string} " \
"#{?key_note,#{key_note},#{key_command}}" \
"," \
"bind-key #{?key_has_repeat,#{?key_repeat,-r, },} " \
"-T #{p|#{key_table_width}:key_table} " \
"#{p|#{key_string_width}:key_string} " \
"#{key_command}}"
static enum cmd_retval cmd_list_keys_commands(struct cmd *, static enum cmd_retval cmd_list_keys_exec(struct cmd *, struct cmdq_item *);
struct cmdq_item *);
const struct cmd_entry cmd_list_keys_entry = { const struct cmd_entry cmd_list_keys_entry = {
.name = "list-keys", .name = "list-keys",
.alias = "lsk", .alias = "lsk",
.args = { "1aNP:T:", 0, 1, NULL }, .args = { "1aF:NO:P:rT:", 0, 1, NULL },
.usage = "[-1aN] [-P prefix-string] [-T key-table] [key]", .usage = "[-1aNr] [-F format] [-O order] [-P prefix-string]"
"[-T key-table] [key]",
.flags = CMD_STARTSERVER|CMD_AFTERHOOK, .flags = CMD_STARTSERVER|CMD_AFTERHOOK,
.exec = cmd_list_keys_exec .exec = cmd_list_keys_exec
}; };
const struct cmd_entry cmd_list_commands_entry = { static char *
.name = "list-commands", cmd_list_keys_get_prefix(struct args *args)
.alias = "lscm", {
key_code prefix;
.args = { "F:", 0, 1, NULL }, if (args_has(args, 'P'))
.usage = "[-F format] [command]", return (xstrdup(args_get(args, 'P')));
.flags = CMD_STARTSERVER|CMD_AFTERHOOK, prefix = options_get_number(global_s_options, "prefix");
.exec = cmd_list_keys_exec if (prefix == KEYC_NONE)
}; return (xstrdup(""));
return (xstrdup(key_string_lookup_key(prefix, 0)));
}
static u_int static u_int
cmd_list_keys_get_width(const char *tablename, key_code only) cmd_list_keys_get_width(struct key_binding **l, u_int n)
{ {
struct key_table *table; u_int i, width, keywidth = 0;
struct key_binding *bd;
u_int width, keywidth = 0;
table = key_bindings_get_table(tablename, 0); for (i = 0; i < n; i++) {
if (table == NULL) width = utf8_cstrwidth(key_string_lookup_key(l[i]->key, 0));
return (0);
bd = key_bindings_first(table);
while (bd != NULL) {
if ((only != KEYC_UNKNOWN && bd->key != only) ||
KEYC_IS_MOUSE(bd->key) ||
bd->note == NULL ||
*bd->note == '\0') {
bd = key_bindings_next(table, bd);
continue;
}
width = utf8_cstrwidth(key_string_lookup_key(bd->key, 0));
if (width > keywidth) if (width > keywidth)
keywidth = width; keywidth = width;
bd = key_bindings_next(table, bd);
} }
return (keywidth); return (keywidth);
} }
static int static u_int
cmd_list_keys_print_notes(struct cmdq_item *item, struct args *args, cmd_list_keys_get_table_width(struct key_binding **l, u_int n)
const char *tablename, u_int keywidth, key_code only, const char *prefix)
{ {
struct client *tc = cmdq_get_target_client(item); u_int i, width, tablewidth = 0;
struct key_table *table;
struct key_binding *bd;
const char *key;
char *tmp, *note;
int found = 0;
table = key_bindings_get_table(tablename, 0); for (i = 0; i < n; i++) {
if (table == NULL) width = utf8_cstrwidth(l[i]->tablename);
return (0); if (width > tablewidth)
bd = key_bindings_first(table); tablewidth = width;
while (bd != NULL) { }
if ((only != KEYC_UNKNOWN && bd->key != only) || return (tablewidth);
KEYC_IS_MOUSE(bd->key) || }
((bd->note == NULL || *bd->note == '\0') &&
!args_has(args, 'a'))) { static struct key_binding **
bd = key_bindings_next(table, bd); cmd_get_root_and_prefix(u_int *n, struct sort_criteria *sort_crit)
{
const char *tables[] = { "prefix", "root" };
struct key_table *t;
struct key_binding **lt;
u_int i, ltsz, len = 0, offset = 0;
static struct key_binding **l = NULL;
static u_int lsz = 0;
for (i = 0; i < nitems(tables); i++) {
t = key_bindings_get_table(tables[i], 0);
lt = sort_get_key_bindings_table(t, &ltsz, sort_crit);
len += ltsz;
if (lsz <= len) {
lsz = len + 100;
l = xreallocarray(l, lsz, sizeof *l);
}
memcpy(l + offset, lt, ltsz * sizeof *l);
offset += ltsz;
}
*n = len;
return (l);
}
static void
cmd_filter_key_list(int filter_notes, int filter_key, key_code only,
struct key_binding **l, u_int *n)
{
key_code key;
u_int i, j = 0;
for (i = 0; i < *n; i++) {
key = l[i]->key & (KEYC_MASK_KEY|KEYC_MASK_MODIFIERS);
if (filter_key && only != key)
continue; continue;
if (filter_notes && l[i]->note == NULL)
continue;
l[j++] = l[i];
} }
found = 1; *n = j;
key = key_string_lookup_key(bd->key, 0);
if (bd->note == NULL || *bd->note == '\0')
note = cmd_list_print(bd->cmdlist,
CMD_LIST_PRINT_ESCAPED|CMD_LIST_PRINT_NO_GROUPS);
else
note = xstrdup(bd->note);
tmp = utf8_padcstr(key, keywidth + 1);
if (args_has(args, '1') && tc != NULL) {
status_message_set(tc, -1, 1, 0, 0, "%s%s%s", prefix,
tmp, note);
} else
cmdq_print(item, "%s%s%s", prefix, tmp, note);
free(tmp);
free(note);
if (args_has(args, '1'))
break;
bd = key_bindings_next(table, bd);
}
return (found);
} }
static char * static void
cmd_list_keys_get_prefix(struct args *args, key_code *prefix) cmd_format_add_key_binding(struct format_tree *ft,
const struct key_binding *bd, const char *prefix)
{ {
char *s; const char *s;
*prefix = options_get_number(global_s_options, "prefix"); if (bd->flags & KEY_BINDING_REPEAT)
if (!args_has(args, 'P')) { format_add(ft, "key_repeat", "1");
if (*prefix != KEYC_NONE)
xasprintf(&s, "%s ", key_string_lookup_key(*prefix, 0));
else else
s = xstrdup(""); format_add(ft, "key_repeat", "0");
} else
s = xstrdup(args_get(args, 'P')); if (bd->note != NULL)
return (s); format_add(ft, "key_note", "%s", bd->note);
else
format_add(ft, "key_note", "%s", "");
format_add(ft, "key_prefix", "%s", prefix);
format_add(ft, "key_table", "%s", bd->tablename);
s = key_string_lookup_key(bd->key, 0);
format_add(ft, "key_string", "%s", s);
s = cmd_list_print(bd->cmdlist,
CMD_LIST_PRINT_ESCAPED|CMD_LIST_PRINT_NO_GROUPS);
format_add(ft, "key_command", "%s", s);
} }
static enum cmd_retval static enum cmd_retval
@@ -150,16 +168,16 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = cmd_get_args(self);
struct client *tc = cmdq_get_target_client(item); struct client *tc = cmdq_get_target_client(item);
struct key_table *table; struct format_tree *ft;
struct key_binding *bd; struct key_table *table = NULL;
const char *tablename, *r, *keystr; struct key_binding **l;
char *key, *cp, *tmp, *start, *empty; key_code only = KEYC_UNKNOWN;
key_code prefix, only = KEYC_UNKNOWN; const char *template, *tablename, *keystr;
int repeat, width, tablewidth, keywidth, found = 0; char *line;
size_t tmpsize, tmpused, cplen; char *prefix = NULL;
u_int i, n;
if (cmd_get_entry(self) == &cmd_list_commands_entry) int single, notes_only, filter_notes, filter_key;
return (cmd_list_keys_commands(self, item)); struct sort_criteria sort_crit;
if ((keystr = args_string(args, 0)) != NULL) { if ((keystr = args_string(args, 0)) != NULL) {
only = key_string_lookup_string(keystr); only = key_string_lookup_string(keystr);
@@ -170,219 +188,64 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
only &= (KEYC_MASK_KEY|KEYC_MASK_MODIFIERS); only &= (KEYC_MASK_KEY|KEYC_MASK_MODIFIERS);
} }
tablename = args_get(args, 'T'); sort_crit.order = sort_order_from_string(args_get(args, 'O'));
if (tablename != NULL && key_bindings_get_table(tablename, 0) == NULL) { if (sort_crit.order == SORT_END && args_has(args, 'O')) {
cmdq_error(item, "invalid sort order");
return (CMD_RETURN_ERROR);
}
sort_crit.reversed = args_has(args, 'r');
prefix = cmd_list_keys_get_prefix(args);
single = args_has(args, '1');
notes_only = args_has(args, 'N');
if ((tablename = args_get(args, 'T')) != NULL) {
table = key_bindings_get_table(tablename, 0);
if (table == NULL) {
cmdq_error(item, "table %s doesn't exist", tablename); cmdq_error(item, "table %s doesn't exist", tablename);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (args_has(args, 'N')) {
if (tablename == NULL) {
start = cmd_list_keys_get_prefix(args, &prefix);
keywidth = cmd_list_keys_get_width("root", only);
if (prefix != KEYC_NONE) {
width = cmd_list_keys_get_width("prefix", only);
if (width == 0)
prefix = KEYC_NONE;
else if (width > keywidth)
keywidth = width;
} }
empty = utf8_padcstr("", utf8_cstrwidth(start));
found = cmd_list_keys_print_notes(item, args, "root", if ((template = args_get(args, 'F')) == NULL)
keywidth, only, empty); template = LIST_KEYS_TEMPLATE;
if (prefix != KEYC_NONE) {
if (cmd_list_keys_print_notes(item, args, if (table)
"prefix", keywidth, only, start)) l = sort_get_key_bindings_table(table, &n, &sort_crit);
found = 1; else if (notes_only)
} l = cmd_get_root_and_prefix(&n, &sort_crit);
free(empty);
} else {
if (args_has(args, 'P'))
start = xstrdup(args_get(args, 'P'));
else else
start = xstrdup(""); l = sort_get_key_bindings(&n, &sort_crit);
keywidth = cmd_list_keys_get_width(tablename, only);
found = cmd_list_keys_print_notes(item, args, tablename,
keywidth, only, start);
} filter_notes = notes_only && !args_has(args, 'a');
free(start); filter_key = only != KEYC_UNKNOWN;
goto out; if (filter_notes || filter_key)
} cmd_filter_key_list(filter_notes, filter_key, only, l, &n);
if (single)
repeat = 0; n = 1;
tablewidth = keywidth = 0;
table = key_bindings_first_table();
while (table != NULL) {
if (tablename != NULL && strcmp(table->name, tablename) != 0) {
table = key_bindings_next_table(table);
continue;
}
bd = key_bindings_first(table);
while (bd != NULL) {
if (only != KEYC_UNKNOWN && bd->key != only) {
bd = key_bindings_next(table, bd);
continue;
}
key = args_escape(key_string_lookup_key(bd->key, 0));
if (bd->flags & KEY_BINDING_REPEAT)
repeat = 1;
width = utf8_cstrwidth(table->name);
if (width > tablewidth)
tablewidth = width;
width = utf8_cstrwidth(key);
if (width > keywidth)
keywidth = width;
free(key);
bd = key_bindings_next(table, bd);
}
table = key_bindings_next_table(table);
}
tmpsize = 256;
tmp = xmalloc(tmpsize);
table = key_bindings_first_table();
while (table != NULL) {
if (tablename != NULL && strcmp(table->name, tablename) != 0) {
table = key_bindings_next_table(table);
continue;
}
bd = key_bindings_first(table);
while (bd != NULL) {
if (only != KEYC_UNKNOWN && bd->key != only) {
bd = key_bindings_next(table, bd);
continue;
}
found = 1;
key = args_escape(key_string_lookup_key(bd->key, 0));
if (!repeat)
r = "";
else if (bd->flags & KEY_BINDING_REPEAT)
r = "-r ";
else
r = " ";
tmpused = xsnprintf(tmp, tmpsize, "%s-T ", r);
cp = utf8_padcstr(table->name, tablewidth);
cplen = strlen(cp) + 1;
while (tmpused + cplen + 1 >= tmpsize) {
tmpsize *= 2;
tmp = xrealloc(tmp, tmpsize);
}
strlcat(tmp, cp, tmpsize);
tmpused = strlcat(tmp, " ", tmpsize);
free(cp);
cp = utf8_padcstr(key, keywidth);
cplen = strlen(cp) + 1;
while (tmpused + cplen + 1 >= tmpsize) {
tmpsize *= 2;
tmp = xrealloc(tmp, tmpsize);
}
strlcat(tmp, cp, tmpsize);
tmpused = strlcat(tmp, " ", tmpsize);
free(cp);
cp = cmd_list_print(bd->cmdlist,
CMD_LIST_PRINT_ESCAPED|CMD_LIST_PRINT_NO_GROUPS);
cplen = strlen(cp);
while (tmpused + cplen + 1 >= tmpsize) {
tmpsize *= 2;
tmp = xrealloc(tmp, tmpsize);
}
strlcat(tmp, cp, tmpsize);
free(cp);
if (args_has(args, '1') && tc != NULL) {
status_message_set(tc, -1, 1, 0, 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);
}
free(tmp);
out:
if (only != KEYC_UNKNOWN && !found) {
cmdq_error(item, "unknown key: %s", args_string(args, 0));
return (CMD_RETURN_ERROR);
}
return (CMD_RETURN_NORMAL);
}
static void
cmd_list_single_command(const struct cmd_entry *entry, struct format_tree *ft,
const char *template, struct cmdq_item *item)
{
const char *s;
char *line;
format_add(ft, "command_list_name", "%s", entry->name);
if (entry->alias != NULL)
s = entry->alias;
else
s = "";
format_add(ft, "command_list_alias", "%s", s);
if (entry->usage != NULL)
s = entry->usage;
else
s = "";
format_add(ft, "command_list_usage", "%s", s);
line = format_expand(ft, template);
if (*line != '\0')
cmdq_print(item, "%s", line);
free(line);
}
static enum cmd_retval
cmd_list_keys_commands(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
const struct cmd_entry **entryp;
const struct cmd_entry *entry;
struct format_tree *ft;
const char *template, *command;
char *cause;
if ((template = args_get(args, 'F')) == NULL) {
template = "#{command_list_name}"
"#{?command_list_alias, (#{command_list_alias}),} "
"#{command_list_usage}";
}
ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0); ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0);
format_defaults(ft, NULL, NULL, NULL, NULL); format_defaults(ft, NULL, NULL, NULL, NULL);
format_add(ft, "notes_only", "%d", notes_only);
format_add(ft, "key_has_repeat", "%d", key_bindings_has_repeat(l, n));
format_add(ft, "key_string_width", "%u", cmd_list_keys_get_width(l, n));
format_add(ft, "key_table_width", "%u",
cmd_list_keys_get_table_width(l, n));
for (i = 0; i < n; i++) {
cmd_format_add_key_binding(ft, l[i], prefix);
command = args_string(args, 0); line = format_expand(ft, template);
if (command == NULL) { if ((single && tc != NULL) || n == 1)
for (entryp = cmd_table; *entryp != NULL; entryp++) status_message_set(tc, -1, 1, 0, 0, "%s", line);
cmd_list_single_command(*entryp, ft, template, item); else if (*line != '\0')
} else { cmdq_print(item, "%s", line);
entry = cmd_find(command, &cause); free(line);
if (entry != NULL)
cmd_list_single_command(entry, ft, template, item);
else {
cmdq_error(item, "%s", cause);
free(cause);
format_free(ft);
return (CMD_RETURN_ERROR);
}
}
if (single)
break;
}
format_free(ft); format_free(ft);
free(prefix);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@@ -55,6 +55,13 @@ cmd_list_panes_exec(struct cmd *self, struct cmdq_item *item)
struct cmd_find_state *target = cmdq_get_target(item); struct cmd_find_state *target = cmdq_get_target(item);
struct session *s = target->s; struct session *s = target->s;
struct winlink *wl = target->wl; struct winlink *wl = target->wl;
enum sort_order order;
order = sort_order_from_string(args_get(args, 'O'));
if (order == SORT_END && args_has(args, 'O')) {
cmdq_error(item, "invalid sort order");
return (CMD_RETURN_ERROR);
}
if (args_has(args, 'a')) if (args_has(args, 'a'))
cmd_list_panes_server(self, item); cmd_list_panes_server(self, item);

View File

@@ -66,6 +66,10 @@ cmd_list_sessions_exec(struct cmd *self, struct cmdq_item *item)
filter = args_get(args, 'f'); filter = args_get(args, 'f');
sort_crit.order = sort_order_from_string(args_get(args, 'O')); sort_crit.order = sort_order_from_string(args_get(args, 'O'));
if (sort_crit.order == SORT_END && args_has(args, 'O')) {
cmdq_error(item, "invalid sort order");
return (CMD_RETURN_ERROR);
}
sort_crit.reversed = args_has(args, 'r'); sort_crit.reversed = args_has(args, 'r');
l = sort_get_sessions(&n, &sort_crit); l = sort_get_sessions(&n, &sort_crit);

View File

@@ -73,6 +73,10 @@ cmd_list_windows_exec(struct cmd *self, struct cmdq_item *item)
filter = args_get(args, 'f'); filter = args_get(args, 'f');
sort_crit.order = sort_order_from_string(args_get(args, 'O')); sort_crit.order = sort_order_from_string(args_get(args, 'O'));
if (sort_crit.order == SORT_END && args_has(args, 'O')) {
cmdq_error(item, "invalid sort order");
return (CMD_RETURN_ERROR);
}
sort_crit.reversed = args_has(args, 'r'); sort_crit.reversed = args_has(args, 'r');
if (args_has(args, 'a')) { if (args_has(args, 'a')) {

View File

@@ -117,8 +117,9 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
as = target->s; as = target->s;
if (as != NULL) { if (as != NULL) {
retval = cmd_attach_session(item, as->name, retval = cmd_attach_session(item, as->name,
args_has(args, 'D'), args_has(args, 'X'), 0, NULL, args_has(args, 'D'), args_has(args, 'X'), 0,
args_has(args, 'E'), args_get(args, 'f')); args_get(args, 'c'), args_has(args, 'E'),
args_get(args, 'f'));
free(newname); free(newname);
return (retval); return (retval);
} }

View File

@@ -33,8 +33,8 @@ const struct cmd_entry cmd_paste_buffer_entry = {
.name = "paste-buffer", .name = "paste-buffer",
.alias = "pasteb", .alias = "pasteb",
.args = { "db:prs:t:", 0, 0, NULL }, .args = { "db:prSs:t:", 0, 0, NULL },
.usage = "[-dpr] [-s separator] " CMD_BUFFER_USAGE " " .usage = "[-dprS] [-s separator] " CMD_BUFFER_USAGE " "
CMD_TARGET_PANE_USAGE, CMD_TARGET_PANE_USAGE,
.target = { 't', CMD_FIND_PANE, 0 }, .target = { 't', CMD_FIND_PANE, 0 },
@@ -43,6 +43,17 @@ const struct cmd_entry cmd_paste_buffer_entry = {
.exec = cmd_paste_buffer_exec .exec = cmd_paste_buffer_exec
}; };
static void
cmd_paste_buffer_paste(struct window_pane *wp, const char *buf, size_t len)
{
char *cp;
size_t n;
n = utf8_stravisx(&cp, buf, len, VIS_SAFE|VIS_NOSLASH);
bufferevent_write(wp->event, cp, n);
free(cp);
}
static enum cmd_retval static enum cmd_retval
cmd_paste_buffer_exec(struct cmd *self, struct cmdq_item *item) cmd_paste_buffer_exec(struct cmd *self, struct cmdq_item *item)
{ {
@@ -51,7 +62,7 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmdq_item *item)
struct window_pane *wp = target->wp; struct window_pane *wp = target->wp;
struct paste_buffer *pb; struct paste_buffer *pb;
const char *sepstr, *bufname, *bufdata, *bufend, *line; const char *sepstr, *bufname, *bufdata, *bufend, *line;
size_t seplen, bufsize; size_t seplen, bufsize, len;
int bracket = args_has(args, 'p'); int bracket = args_has(args, 'p');
if (window_pane_exited(wp)) { if (window_pane_exited(wp)) {
@@ -93,14 +104,22 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmdq_item *item)
line = memchr(bufdata, '\n', bufend - bufdata); line = memchr(bufdata, '\n', bufend - bufdata);
if (line == NULL) if (line == NULL)
break; break;
len = line - bufdata;
bufferevent_write(wp->event, bufdata, line - bufdata); if (args_has(args, 'S'))
bufferevent_write(wp->event, bufdata, len);
else
cmd_paste_buffer_paste(wp, bufdata, len);
bufferevent_write(wp->event, sepstr, seplen); bufferevent_write(wp->event, sepstr, seplen);
bufdata = line + 1; bufdata = line + 1;
} }
if (bufdata != bufend) if (bufdata != bufend) {
bufferevent_write(wp->event, bufdata, bufend - bufdata); len = bufend - bufdata;
if (args_has(args, 'S'))
bufferevent_write(wp->event, bufdata, len);
else
cmd_paste_buffer_paste(wp, bufdata, len);
}
if (bracket && (wp->screen->mode & MODE_BRACKETPASTE)) if (bracket && (wp->screen->mode & MODE_BRACKETPASTE))
bufferevent_write(wp->event, "\033[201~", 6); bufferevent_write(wp->event, "\033[201~", 6);

View File

@@ -39,7 +39,8 @@ const struct cmd_entry cmd_send_keys_entry = {
.target = { 't', CMD_FIND_PANE, 0 }, .target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK|CMD_CLIENT_CFLAG|CMD_CLIENT_CANFAIL, .flags = CMD_AFTERHOOK|CMD_CLIENT_CFLAG|CMD_CLIENT_CANFAIL|
CMD_READONLY,
.exec = cmd_send_keys_exec .exec = cmd_send_keys_exec
}; };
@@ -167,6 +168,11 @@ cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
u_int count = args_count(args); u_int count = args_count(args);
char *cause = NULL; char *cause = NULL;
if (tc != NULL && tc->flags & CLIENT_READONLY && !args_has(args, 'X')) {
cmdq_error(item, "client is read-only");
return (CMD_RETURN_ERROR);
}
if (args_has(args, 'N')) { if (args_has(args, 'N')) {
np = args_strtonum_and_expand(args, 'N', 1, UINT_MAX, item, np = args_strtonum_and_expand(args, 'N', 1, UINT_MAX, item,
&cause); &cause);

View File

@@ -90,6 +90,7 @@ cmd_server_access_exec(struct cmd *self, struct cmdq_item *item)
pw = getpwnam(name); pw = getpwnam(name);
if (pw == NULL) { if (pw == NULL) {
cmdq_error(item, "unknown user: %s", name); cmdq_error(item, "unknown user: %s", name);
free(name);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
free(name); free(name);

View File

@@ -60,6 +60,9 @@ cmd_show_prompt_history_exec(struct cmd *self, struct cmdq_item *item)
if (cmd_get_entry(self) == &cmd_clear_prompt_history_entry) { if (cmd_get_entry(self) == &cmd_clear_prompt_history_entry) {
if (typestr == NULL) { if (typestr == NULL) {
for (tidx = 0; tidx < PROMPT_NTYPES; tidx++) { for (tidx = 0; tidx < PROMPT_NTYPES; tidx++) {
for (hidx = 0; hidx < status_prompt_hsize[tidx];
hidx++)
free(status_prompt_hlist[tidx][hidx]);
free(status_prompt_hlist[tidx]); free(status_prompt_hlist[tidx]);
status_prompt_hlist[tidx] = NULL; status_prompt_hlist[tidx] = NULL;
status_prompt_hsize[tidx] = 0; status_prompt_hsize[tidx] = 0;
@@ -70,6 +73,8 @@ cmd_show_prompt_history_exec(struct cmd *self, struct cmdq_item *item)
cmdq_error(item, "invalid type: %s", typestr); cmdq_error(item, "invalid type: %s", typestr);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
for (hidx = 0; hidx < status_prompt_hsize[type]; hidx++)
free(status_prompt_hlist[type][hidx]);
free(status_prompt_hlist[type]); free(status_prompt_hlist[type]);
status_prompt_hlist[type] = NULL; status_prompt_hlist[type] = NULL;
status_prompt_hsize[type] = 0; status_prompt_hsize[type] = 0;

View File

@@ -97,6 +97,10 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
} }
sort_crit.order = sort_order_from_string(args_get(args, 'O')); sort_crit.order = sort_order_from_string(args_get(args, 'O'));
if (sort_crit.order == SORT_END && args_has(args, 'O')) {
cmdq_error(item, "invalid sort order");
return (CMD_RETURN_ERROR);
}
sort_crit.reversed = args_has(args, 'r'); sort_crit.reversed = args_has(args, 'r');
if (args_has(args, 'n')) { if (args_has(args, 'n')) {

View File

@@ -388,7 +388,7 @@ int clock_gettime(int, struct timespec *);
/* base64.c */ /* base64.c */
#undef b64_ntop #undef b64_ntop
#undef b64_pton #undef b64_pton
int b64_ntop(const char *, size_t, char *, size_t); int b64_ntop(const u_char *, size_t, char *, size_t);
int b64_pton(const char *, u_char *, size_t); int b64_pton(const char *, u_char *, size_t);
#endif #endif

View File

@@ -1,4 +1,4 @@
/* $OpenBSD: base64.c,v 1.8 2015/01/16 16:48:51 deraadt Exp $ */ /* $OpenBSD: base64.c,v 1.15 2021/10/25 14:41:09 jca Exp $ */
/* /*
* Copyright (c) 1996 by Internet Software Consortium. * Copyright (c) 1996 by Internet Software Consortium.
@@ -46,15 +46,15 @@
#include <sys/socket.h> #include <sys/socket.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <arpa/nameser.h>
#include <ctype.h> #include <ctype.h>
#include <resolv.h> #include <resolv.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "compat.h"
static const char Base64[] = static const char Base64[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static const char Pad64 = '='; static const char Pad64 = '=';
@@ -123,15 +123,12 @@ static const char Pad64 = '=';
*/ */
int int
b64_ntop(src, srclength, target, targsize) b64_ntop(unsigned char const *src, size_t srclength, char *target,
u_char const *src; size_t targsize)
size_t srclength;
char *target;
size_t targsize;
{ {
size_t datalength = 0; size_t datalength = 0;
u_char input[3]; unsigned char input[3];
u_char output[4]; unsigned char output[4];
int i; int i;
while (2 < srclength) { while (2 < srclength) {
@@ -187,13 +184,10 @@ b64_ntop(src, srclength, target, targsize)
*/ */
int int
b64_pton(src, target, targsize) b64_pton(char const *src, unsigned char *target, size_t targsize)
char const *src;
u_char *target;
size_t targsize;
{ {
int tarindex, state, ch; int tarindex, state, ch;
u_char nextbyte; unsigned char nextbyte;
char *pos; char *pos;
state = 0; state = 0;

View File

@@ -57,6 +57,9 @@ environ_free(struct environ *env)
{ {
struct environ_entry *envent, *envent1; struct environ_entry *envent, *envent1;
if (env == NULL)
return;
RB_FOREACH_SAFE(envent, environ, env, envent1) { RB_FOREACH_SAFE(envent, environ, env, envent1) {
RB_REMOVE(environ, env, envent); RB_REMOVE(environ, env, envent);
free(envent->name); free(envent->name);

1
file.c
View File

@@ -55,6 +55,7 @@ file_get_path(struct client *c, const char *file)
if (*path == '/') if (*path == '/')
return (path); return (path);
xasprintf(&full_path, "%s/%s", server_client_get_cwd(c, NULL), path); xasprintf(&full_path, "%s/%s", server_client_get_cwd(c, NULL), path);
free(path);
return (full_path); return (full_path);
} }

View File

@@ -4447,6 +4447,9 @@ format_loop_sessions(struct format_expand_state *es, const char *fmt)
free(expanded); free(expanded);
} }
free(active);
free(all);
return (value); return (value);
} }

View File

@@ -44,7 +44,7 @@ LLVMFuzzerTestOneInput(const u_char *data, size_t size)
w = window_create(PANE_WIDTH, PANE_HEIGHT, 0, 0); w = window_create(PANE_WIDTH, PANE_HEIGHT, 0, 0);
wp = window_add_pane(w, NULL, 0, 0); wp = window_add_pane(w, NULL, 0, 0);
bufferevent_pair_new(libevent, BEV_OPT_CLOSE_ON_FREE, vpty); bufferevent_pair_new(libevent, BEV_OPT_CLOSE_ON_FREE, vpty);
wp->ictx = input_init(wp, vpty[0], NULL); wp->ictx = input_init(wp, vpty[0], NULL, NULL);
window_add_ref(w, __func__); window_add_ref(w, __func__);
wp->fd = open("/dev/null", O_WRONLY); wp->fd = open("/dev/null", O_WRONLY);

16
grid.c
View File

@@ -209,12 +209,14 @@ grid_clear_cell(struct grid *gd, u_int px, u_int py, u_int bg)
int had_extd = (gce->flags & GRID_FLAG_EXTENDED); int had_extd = (gce->flags & GRID_FLAG_EXTENDED);
memcpy(gce, &grid_cleared_entry, sizeof *gce); memcpy(gce, &grid_cleared_entry, sizeof *gce);
if (bg != 8) {
if (bg & COLOUR_FLAG_RGB) {
if (had_extd && old_offset < gl->extdsize) { if (had_extd && old_offset < gl->extdsize) {
gce->flags |= GRID_FLAG_EXTENDED; gce->flags |= GRID_FLAG_EXTENDED;
gce->offset = old_offset; gce->offset = old_offset;
} else gee = grid_extended_cell(gl, gce, &grid_cleared_cell);
if (bg != 8)
gee->bg = bg;
} else if (bg != 8) {
if (bg & COLOUR_FLAG_RGB) {
grid_get_extended_cell(gl, gce, gce->flags); grid_get_extended_cell(gl, gce, gce->flags);
gee = grid_extended_cell(gl, gce, &grid_cleared_cell); gee = grid_extended_cell(gl, gce, &grid_cleared_cell);
gee->bg = bg; gee->bg = bg;
@@ -493,7 +495,7 @@ static void
grid_expand_line(struct grid *gd, u_int py, u_int sx, u_int bg) grid_expand_line(struct grid *gd, u_int py, u_int sx, u_int bg)
{ {
struct grid_line *gl; struct grid_line *gl;
u_int xx; u_int xx, old_cellsize;
gl = &gd->linedata[py]; gl = &gd->linedata[py];
if (sx <= gl->cellsize) if (sx <= gl->cellsize)
@@ -506,8 +508,10 @@ grid_expand_line(struct grid *gd, u_int py, u_int sx, u_int bg)
else if (gd->sx > sx) else if (gd->sx > sx)
sx = gd->sx; sx = gd->sx;
gl->celldata = xreallocarray(gl->celldata, sx, sizeof *gl->celldata); old_cellsize = gl->cellsize;
for (xx = gl->cellsize; xx < sx; xx++) gl->celldata = xrecallocarray(gl->celldata, old_cellsize, sx,
sizeof *gl->celldata);
for (xx = old_cellsize; xx < sx; xx++)
grid_clear_cell(gd, xx, py, bg); grid_clear_cell(gd, xx, py, bg);
gl->cellsize = sx; gl->cellsize = sx;
} }

56
input.c
View File

@@ -1139,11 +1139,9 @@ input_get(struct input_ctx *ictx, u_int validx, int minval, int defval)
static void static void
input_send_reply(struct input_ctx *ictx, const char *reply) input_send_reply(struct input_ctx *ictx, const char *reply)
{ {
struct bufferevent *bev = ictx->event; if (ictx->event != NULL) {
if (bev != NULL) {
log_debug("%s: %s", __func__, reply); log_debug("%s: %s", __func__, reply);
bufferevent_write(bev, reply, strlen(reply)); bufferevent_write(ictx->event, reply, strlen(reply));
} }
} }
@@ -1627,10 +1625,6 @@ input_csi_dispatch(struct input_ctx *ictx)
} }
input_reply(ictx, 1, "\033[?12;%d$y", n); input_reply(ictx, 1, "\033[?12;%d$y", n);
break; break;
case 2004: /* bracketed paste */
n = (s->mode & MODE_BRACKETPASTE) ? 1 : 2;
input_reply(ictx, 1, "\033[?2004;%d$y", n);
break;
case 1004: /* focus reporting */ case 1004: /* focus reporting */
n = (s->mode & MODE_FOCUSON) ? 1 : 2; n = (s->mode & MODE_FOCUSON) ? 1 : 2;
input_reply(ictx, 1, "\033[?1004;%d$y", n); input_reply(ictx, 1, "\033[?1004;%d$y", n);
@@ -1639,6 +1633,14 @@ input_csi_dispatch(struct input_ctx *ictx)
n = (s->mode & MODE_MOUSE_SGR) ? 1 : 2; n = (s->mode & MODE_MOUSE_SGR) ? 1 : 2;
input_reply(ictx, 1, "\033[?1006;%d$y", n); input_reply(ictx, 1, "\033[?1006;%d$y", n);
break; break;
case 2004: /* bracketed paste */
n = (s->mode & MODE_BRACKETPASTE) ? 1 : 2;
input_reply(ictx, 1, "\033[?2004;%d$y", n);
break;
case 2026: /* synchronized output */
n = (s->mode & MODE_SYNC) ? 1 : 2;
input_reply(ictx, 1, "\033[?2026;%d$y", n);
break;
case 2031: case 2031:
input_reply(ictx, 1, "\033[?2031;2$y"); input_reply(ictx, 1, "\033[?2031;2$y");
break; break;
@@ -3089,8 +3091,9 @@ input_osc_133(struct input_ctx *ictx, const char *p)
/* Handle OSC 52 reply. */ /* Handle OSC 52 reply. */
static void static void
input_osc_52_reply(struct input_ctx *ictx) input_osc_52_reply(struct input_ctx *ictx, char clip)
{ {
struct bufferevent *ev = ictx->event;
struct paste_buffer *pb; struct paste_buffer *pb;
int state; int state;
const char *buf; const char *buf;
@@ -3104,9 +3107,9 @@ input_osc_52_reply(struct input_ctx *ictx)
return; return;
buf = paste_buffer_data(pb, &len); buf = paste_buffer_data(pb, &len);
if (ictx->input_end == INPUT_END_BEL) if (ictx->input_end == INPUT_END_BEL)
input_reply_clipboard(ictx->event, buf, len, "\007"); input_reply_clipboard(ev, buf, len, "\007", clip);
else else
input_reply_clipboard(ictx->event, buf, len, "\033\\"); input_reply_clipboard(ev, buf, len, "\033\\", clip);
return; return;
} }
input_add_request(ictx, INPUT_REQUEST_CLIPBOARD, ictx->input_end); input_add_request(ictx, INPUT_REQUEST_CLIPBOARD, ictx->input_end);
@@ -3119,7 +3122,7 @@ input_osc_52_reply(struct input_ctx *ictx)
*/ */
static int static int
input_osc_52_parse(struct input_ctx *ictx, const char *p, u_char **out, input_osc_52_parse(struct input_ctx *ictx, const char *p, u_char **out,
int *outlen, char *flags) int *outlen, char *clip)
{ {
char *end; char *end;
size_t len; size_t len;
@@ -3137,13 +3140,13 @@ input_osc_52_parse(struct input_ctx *ictx, const char *p, u_char **out,
log_debug("%s: %s", __func__, end); log_debug("%s: %s", __func__, end);
for (i = 0; p + i != end; i++) { for (i = 0; p + i != end; i++) {
if (strchr(allow, p[i]) != NULL && strchr(flags, p[i]) == NULL) if (strchr(allow, p[i]) != NULL && strchr(clip, p[i]) == NULL)
flags[j++] = p[i]; clip[j++] = p[i];
} }
log_debug("%s: %.*s %s", __func__, (int)(end - p - 1), p, flags); log_debug("%s: %.*s %s", __func__, (int)(end - p - 1), p, clip);
if (strcmp(end, "?") == 0) { if (strcmp(end, "?") == 0) {
input_osc_52_reply(ictx); input_osc_52_reply(ictx, *clip);
return (0); return (0);
} }
@@ -3169,9 +3172,9 @@ input_osc_52(struct input_ctx *ictx, const char *p)
struct screen_write_ctx ctx; struct screen_write_ctx ctx;
u_char *out; u_char *out;
int outlen; int outlen;
char flags[sizeof "cpqs01234567"] = ""; char clip[sizeof "cpqs01234567"] = "";
if (!input_osc_52_parse(ictx, p, &out, &outlen, flags)) if (!input_osc_52_parse(ictx, p, &out, &outlen, clip))
return; return;
if (wp == NULL) { if (wp == NULL) {
@@ -3180,17 +3183,16 @@ input_osc_52(struct input_ctx *ictx, const char *p)
free(out); free(out);
return; return;
} }
tty_set_selection(&ictx->c->tty, flags, out, outlen); tty_set_selection(&ictx->c->tty, clip, out, outlen);
paste_add(NULL, out, outlen); paste_add(NULL, out, outlen);
} else { } else {
/* Normal window. */ /* Normal window. */
screen_write_start_pane(&ctx, wp, NULL); screen_write_start_pane(&ctx, wp, NULL);
screen_write_setselection(&ctx, flags, out, outlen); screen_write_setselection(&ctx, clip, out, outlen);
screen_write_stop(&ctx); screen_write_stop(&ctx);
notify_pane("pane-set-clipboard", wp); notify_pane("pane-set-clipboard", wp);
paste_add(NULL, out, outlen); paste_add(NULL, out, outlen);
} }
free(out);
} }
/* Handle the OSC 104 sequence for unsetting (multiple) palette entries. */ /* Handle the OSC 104 sequence for unsetting (multiple) palette entries. */
@@ -3233,7 +3235,7 @@ input_osc_104(struct input_ctx *ictx, const char *p)
/* Send a clipboard reply. */ /* Send a clipboard reply. */
void void
input_reply_clipboard(struct bufferevent *bev, const char *buf, size_t len, input_reply_clipboard(struct bufferevent *bev, const char *buf, size_t len,
const char *end) const char *end, char clip)
{ {
char *out = NULL; char *out = NULL;
int outlen = 0; int outlen = 0;
@@ -3249,7 +3251,10 @@ input_reply_clipboard(struct bufferevent *bev, const char *buf, size_t len,
} }
} }
bufferevent_write(bev, "\033]52;;", 6); bufferevent_write(bev, "\033]52;", 5);
if (clip != 0)
bufferevent_write(bev, &clip, 1);
bufferevent_write(bev, ";", 1);
if (outlen != 0) if (outlen != 0)
bufferevent_write(bev, out, outlen); bufferevent_write(bev, out, outlen);
bufferevent_write(bev, end, strlen(end)); bufferevent_write(bev, end, strlen(end));
@@ -3391,6 +3396,7 @@ static void
input_request_clipboard_reply(struct input_request *ir, void *data) input_request_clipboard_reply(struct input_request *ir, void *data)
{ {
struct input_ctx *ictx = ir->ictx; struct input_ctx *ictx = ir->ictx;
struct bufferevent *ev = ictx->event;
struct input_request_clipboard_data *cd = data; struct input_request_clipboard_data *cd = data;
int state; int state;
char *copy; char *copy;
@@ -3405,9 +3411,9 @@ input_request_clipboard_reply(struct input_request *ir, void *data)
} }
if (ir->idx == INPUT_END_BEL) if (ir->idx == INPUT_END_BEL)
input_reply_clipboard(ictx->event, cd->buf, cd->len, "\007"); input_reply_clipboard(ev, cd->buf, cd->len, "\007", cd->clip);
else else
input_reply_clipboard(ictx->event, cd->buf, cd->len, "\033\\"); input_reply_clipboard(ev, cd->buf, cd->len, "\033\\", cd->clip);
} }
/* Handle a reply to a request. */ /* Handle a reply to a request. */

View File

@@ -215,6 +215,7 @@ key_bindings_add(const char *name, key_code key, const char *note, int repeat,
bd = xcalloc(1, sizeof *bd); bd = xcalloc(1, sizeof *bd);
bd->key = (key & ~KEYC_MASK_FLAGS); bd->key = (key & ~KEYC_MASK_FLAGS);
bd->tablename = table->name;
if (note != NULL) if (note != NULL)
bd->note = xstrdup(note); bd->note = xstrdup(note);
RB_INSERT(key_bindings, &table->key_bindings, bd); RB_INSERT(key_bindings, &table->key_bindings, bd);
@@ -695,6 +696,7 @@ key_bindings_dispatch(struct key_binding *bd, struct cmdq_item *item,
readonly = 1; readonly = 1;
else else
readonly = cmd_list_all_have(bd->cmdlist, CMD_READONLY); readonly = cmd_list_all_have(bd->cmdlist, CMD_READONLY);
if (!readonly) if (!readonly)
new_item = cmdq_get_callback(key_bindings_read_only, NULL); new_item = cmdq_get_callback(key_bindings_read_only, NULL);
else { else {
@@ -710,3 +712,15 @@ key_bindings_dispatch(struct key_binding *bd, struct cmdq_item *item,
new_item = cmdq_append(c, new_item); new_item = cmdq_append(c, new_item);
return (new_item); return (new_item);
} }
int
key_bindings_has_repeat(struct key_binding **l, u_int n)
{
u_int i;
for (i = 0; i < n; i++) {
if (l[i]->flags & KEY_BINDING_REPEAT)
return (1);
}
return (0);
}

4
menu.c
View File

@@ -90,6 +90,7 @@ menu_add_item(struct menu *menu, const struct menu_item *item,
else else
s = format_single(qitem, item->name, c, NULL, NULL, NULL); s = format_single(qitem, item->name, c, NULL, NULL, NULL);
if (*s == '\0') { /* no item if empty after format expanded */ if (*s == '\0') { /* no item if empty after format expanded */
free(s);
menu->count--; menu->count--;
return; return;
} }
@@ -161,6 +162,9 @@ menu_free(struct menu *menu)
{ {
u_int i; u_int i;
if (menu == NULL)
return;
for (i = 0; i < menu->count; i++) { for (i = 0; i < menu->count; i++) {
free((void *)menu->items[i].name); free((void *)menu->items[i].name);
free((void *)menu->items[i].command); free((void *)menu->items[i].command);

82
regress/decrqm-sync.sh Normal file
View File

@@ -0,0 +1,82 @@
#!/bin/sh
# Test DECRPM response for mode 2026 (synchronized output).
#
# DECRQM (ESC[?2026$p) should elicit DECRPM (ESC[?2026;Ps$y) where
# Ps=1 when MODE_SYNC is active, Ps=2 when reset.
PATH=/bin:/usr/bin
TERM=screen
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
TMUX="$TEST_TMUX -Ltest"
$TMUX kill-server 2>/dev/null
sleep 1
TMP=$(mktemp)
TMP2=$(mktemp)
trap "rm -f $TMP $TMP2; $TMUX kill-server 2>/dev/null" 0 1 15
$TMUX -f/dev/null new -d -x80 -y24 || exit 1
sleep 1
# Keep the session alive regardless of pane exits.
$TMUX set -g remain-on-exit on
exit_status=0
# query_decrpm <outfile> [setup_seq]
# Spawn a pane that optionally sends setup_seq, then sends DECRQM for
# mode 2026 and captures the response into outfile in cat -v form.
query_decrpm () {
_outfile=$1
_setup=$2
$TMUX respawnw -k -t:0 -- sh -c "
exec 2>/dev/null
stty raw -echo
${_setup:+printf '$_setup'; sleep 0.2}
printf '\033[?2026\$p'
dd bs=1 count=11 2>/dev/null | cat -v > $_outfile
sleep 0.2
" || exit 1
sleep 2
}
# ------------------------------------------------------------------
# Test 1: mode 2026 should be reset by default (Ps=2)
# ------------------------------------------------------------------
query_decrpm "$TMP"
actual=$(cat "$TMP")
expected='^[[?2026;2$y'
if [ "$actual" = "$expected" ]; then
if [ -n "$VERBOSE" ]; then
echo "[PASS] DECRQM 2026 (default/reset) -> $actual"
fi
else
echo "[FAIL] DECRQM 2026 (default/reset): expected '$expected', got '$actual'"
exit_status=1
fi
# ------------------------------------------------------------------
# Test 2: set mode 2026 (SM ?2026), then query (expect Ps=1)
# ------------------------------------------------------------------
query_decrpm "$TMP2" '\033[?2026h'
actual=$(cat "$TMP2")
expected='^[[?2026;1$y'
if [ "$actual" = "$expected" ]; then
if [ -n "$VERBOSE" ]; then
echo "[PASS] DECRQM 2026 (set) -> $actual"
fi
else
echo "[FAIL] DECRQM 2026 (set): expected '$expected', got '$actual'"
exit_status=1
fi
$TMUX kill-server 2>/dev/null
exit $exit_status

70
regress/session-group-resize.sh Executable file
View File

@@ -0,0 +1,70 @@
#!/bin/sh
# Test that window-size=latest resizes windows correctly when switching
# windows in session groups. When a client switches to a window, it should
# resize immediately to match that client's size.
#
# Tests both switch-client and select-window, which use different code paths.
PATH=/bin:/usr/bin
TERM=screen
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
TMUX="$TEST_TMUX -Ltest"
$TMUX kill-server 2>/dev/null
TMP1=$(mktemp)
TMP2=$(mktemp)
TMP3=$(mktemp)
trap "rm -f $TMP1 $TMP2 $TMP3" 0 1 15
# Create a session with two windows, staying on window 0.
$TMUX -f/dev/null new -d -s test -x 20 -y 6 || exit 1
$TMUX neww -t test || exit 1
$TMUX selectw -t test:0 || exit 1
# Attach a small 20x6 client in control-mode and have it select window 1. This makes
# the small client the "latest" for window 1. The sleep keeps stdin open so the
# control client stays attached.
(echo "refresh-client -C 20,6"; echo "selectw -t :1"; sleep 5) |
$TMUX -f/dev/null -C attach -t test >$TMP1 2>&1 &
# Wait for small client to be on window 1.
n=0
while [ $n -lt 20 ]; do
$TMUX lsc -F '#{client_name} #{window_index}' 2>/dev/null | grep -q " 1$" && break
sleep 0.1
n=$((n + 1))
done
# Create a grouped session with a larger 30x10 client, also in control mode. It
# starts on window 0 (inherited), then switches to window 1 with
# `switch-client`.
(echo "refresh-client -C 30,10"; echo "switch-client -t :=1"; sleep 5) |
$TMUX -f/dev/null -C new -t test -x 30 -y 10 >$TMP2 2>&1 &
# Wait briefly for the switch-client command to execute, then check.
# The resize should happen immediately (within 0.2s).
sleep 0.2
OUT1=$($TMUX display -t test:1 -p '#{window_width}x#{window_height}' 2>/dev/null)
# Also test selectw (select-window) which uses a different code path.
# Create a third grouped session with a 25x8 client, switch to window 1
# using selectw instead of switch-client.
(echo "refresh-client -C 25,8"; echo "selectw -t :1"; sleep 5) |
$TMUX -f/dev/null -C new -t test -x 25 -y 8 >$TMP3 2>&1 &
sleep 0.2
OUT2=$($TMUX display -t test:1 -p '#{window_width}x#{window_height}' 2>/dev/null)
# Clean up - kill server (terminates clients). Don't wait for background
# sleeps; they'll be orphaned but harmless.
$TMUX kill-server 2>/dev/null
# Window 1 should have resized to 30x10 (the second client's size).
[ "$OUT1" = "30x10" ] || { echo "switch-client resize failed: $OUT1"; exit 1; }
# Window 1 should have resized to 25x8 (the third client's size).
[ "$OUT2" = "25x8" ] || { echo "selectw resize failed: $OUT2"; exit 1; }
exit 0

View File

@@ -2510,14 +2510,14 @@ screen_write_overwrite(struct screen_write_ctx *ctx, struct grid_cell *gc,
/* Set external clipboard. */ /* Set external clipboard. */
void void
screen_write_setselection(struct screen_write_ctx *ctx, const char *flags, screen_write_setselection(struct screen_write_ctx *ctx, const char *clip,
u_char *str, u_int len) u_char *str, u_int len)
{ {
struct tty_ctx ttyctx; struct tty_ctx ttyctx;
screen_write_initctx(ctx, &ttyctx, 0); screen_write_initctx(ctx, &ttyctx, 0);
ttyctx.ptr = str; ttyctx.ptr = str;
ttyctx.ptr2 = (void *)flags; ttyctx.ptr2 = (void *)clip;
ttyctx.num = len; ttyctx.num = len;
tty_write(tty_cmd_setselection, &ttyctx); tty_write(tty_cmd_setselection, &ttyctx);

View File

@@ -96,7 +96,9 @@ server_redraw_window(struct window *w)
struct client *c; struct client *c;
TAILQ_FOREACH(c, &clients, entry) { TAILQ_FOREACH(c, &clients, entry) {
if (c->session != NULL && c->session->curw->window == w) if (c->session != NULL &&
c->session->curw != NULL &&
c->session->curw->window == w)
server_redraw_client(c); server_redraw_client(c);
} }
} }
@@ -107,7 +109,9 @@ server_redraw_window_borders(struct window *w)
struct client *c; struct client *c;
TAILQ_FOREACH(c, &clients, entry) { TAILQ_FOREACH(c, &clients, entry) {
if (c->session != NULL && c->session->curw->window == w) if (c->session != NULL &&
c->session->curw != NULL &&
c->session->curw->window == w)
c->flags |= CLIENT_REDRAWBORDERS; c->flags |= CLIENT_REDRAWBORDERS;
} }
} }

101
sort.c
View File

@@ -72,6 +72,7 @@ sort_buffer_cmp(const void *a0, const void *b0)
break; break;
case SORT_ACTIVITY: case SORT_ACTIVITY:
case SORT_INDEX: case SORT_INDEX:
case SORT_MODIFIER:
case SORT_ORDER: case SORT_ORDER:
case SORT_END: case SORT_END:
break; break;
@@ -117,6 +118,7 @@ sort_client_cmp(const void *a0, const void *b0)
result = 1; result = 1;
break; break;
case SORT_INDEX: case SORT_INDEX:
case SORT_MODIFIER:
case SORT_ORDER: case SORT_ORDER:
case SORT_END: case SORT_END:
break; break;
@@ -167,6 +169,7 @@ sort_session_cmp(const void *a0, const void *b0)
case SORT_NAME: case SORT_NAME:
result = strcmp(sa->name, sb->name); result = strcmp(sa->name, sb->name);
break; break;
case SORT_MODIFIER:
case SORT_ORDER: case SORT_ORDER:
case SORT_SIZE: case SORT_SIZE:
case SORT_END: case SORT_END:
@@ -208,6 +211,7 @@ sort_pane_cmp(const void *a0, const void *b0)
case SORT_NAME: case SORT_NAME:
result = strcmp(a->screen->title, b->screen->title); result = strcmp(a->screen->title, b->screen->title);
break; break;
case SORT_MODIFIER:
case SORT_ORDER: case SORT_ORDER:
case SORT_END: case SORT_END:
break; break;
@@ -263,6 +267,7 @@ sort_winlink_cmp(const void *a0, const void *b0)
case SORT_SIZE: case SORT_SIZE:
result = wa->sx * wa->sy - wb->sx * wb->sy; result = wa->sx * wa->sy - wb->sx * wb->sy;
break; break;
case SORT_MODIFIER:
case SORT_ORDER: case SORT_ORDER:
case SORT_END: case SORT_END:
break; break;
@@ -276,6 +281,41 @@ sort_winlink_cmp(const void *a0, const void *b0)
return (result); return (result);
} }
static int
sort_key_binding_cmp(const void *a0, const void *b0)
{
struct sort_criteria *sort_crit = sort_criteria;
const struct key_binding *a = *(struct key_binding **)a0;
const struct key_binding *b = *(struct key_binding **)b0;
int result = 0;
switch (sort_crit->order) {
case SORT_INDEX:
result = a->key - b->key;
break;
case SORT_MODIFIER:
result = (a->key & KEYC_MASK_MODIFIERS) -
(b->key & KEYC_MASK_MODIFIERS);
break;
case SORT_NAME:
result = strcasecmp(a->tablename, b->tablename) == 0;
break;
case SORT_ACTIVITY:
case SORT_CREATION:
case SORT_ORDER:
case SORT_SIZE:
case SORT_END:
break;
}
if (result == 0)
result = strcasecmp(a->tablename, b->tablename) == 0;
if (sort_crit->reversed)
result = -result;
return (result);
}
void void
sort_next_order(struct sort_criteria *sort_crit) sort_next_order(struct sort_criteria *sort_crit)
{ {
@@ -306,8 +346,11 @@ sort_order_from_string(const char* order)
return (SORT_ACTIVITY); return (SORT_ACTIVITY);
if (strcasecmp(order, "creation") == 0) if (strcasecmp(order, "creation") == 0)
return (SORT_CREATION); return (SORT_CREATION);
if (strcasecmp(order, "index") == 0) if (strcasecmp(order, "index") == 0 ||
strcasecmp(order, "key") == 0)
return (SORT_INDEX); return (SORT_INDEX);
if (strcasecmp(order, "modifier") == 0)
return (SORT_MODIFIER);
if (strcasecmp(order, "name") == 0 || if (strcasecmp(order, "name") == 0 ||
strcasecmp(order, "title") == 0) strcasecmp(order, "title") == 0)
return (SORT_NAME); return (SORT_NAME);
@@ -328,6 +371,8 @@ sort_order_to_string(enum sort_order order)
return "creation"; return "creation";
if (order == SORT_INDEX) if (order == SORT_INDEX)
return "index"; return "index";
if (order == SORT_MODIFIER)
return "modifier";
if (order == SORT_NAME) if (order == SORT_NAME)
return "name"; return "name";
if (order == SORT_ORDER) if (order == SORT_ORDER)
@@ -548,3 +593,57 @@ sort_get_winlinks_session(struct session *s, u_int *n,
return (l); return (l);
} }
struct key_binding **
sort_get_key_bindings(u_int *n, struct sort_criteria *sort_crit)
{
struct key_table *table;
struct key_binding *bd;
u_int i = 0;
static struct key_binding **l = NULL;
static u_int lsz = 0;
table = key_bindings_first_table();
while (table != NULL) {
bd = key_bindings_first(table);
while (bd != NULL) {
if (lsz <= i) {
lsz += 100;
l = xreallocarray(l, lsz, sizeof *l);
}
l[i++] = bd;
bd = key_bindings_next(table, bd);
}
table = key_bindings_next_table(table);
}
sort_qsort(l, i, sizeof *l, sort_key_binding_cmp, sort_crit);
*n = i;
return (l);
}
struct key_binding **
sort_get_key_bindings_table(struct key_table *table, u_int *n,
struct sort_criteria *sort_crit)
{
struct key_binding *bd;
u_int i = 0;
static struct key_binding **l = NULL;
static u_int lsz = 0;
bd = key_bindings_first(table);
while (bd != NULL) {
if (lsz <= i) {
lsz += 100;
l = xreallocarray(l, lsz, sizeof *l);
}
l[i++] = bd;
bd = key_bindings_next(table, bd);
}
sort_qsort(l, i, sizeof *l, sort_key_binding_cmp, sort_crit);
*n = i;
return (l);
}

View File

@@ -1890,7 +1890,7 @@ status_prompt_complete_window_menu(struct client *c, struct session *s,
struct winlink *wl; struct winlink *wl;
char **list = NULL, *tmp; char **list = NULL, *tmp;
u_int lines = status_line_size(c), height; u_int lines = status_line_size(c), height;
u_int py, size = 0; u_int py, size = 0, i;
if (c->tty.sy - lines < 3) if (c->tty.sy - lines < 3)
return (NULL); return (NULL);
@@ -1969,6 +1969,9 @@ status_prompt_complete_window_menu(struct client *c, struct session *s,
BOX_LINES_DEFAULT, NULL, NULL, NULL, NULL, BOX_LINES_DEFAULT, NULL, NULL, NULL, NULL,
status_prompt_menu_callback, spm) != 0) { status_prompt_menu_callback, spm) != 0) {
menu_free(menu); menu_free(menu);
for (i = 0; i < size; i++)
free(list[i]);
free(list);
free(spm); free(spm);
return (NULL); return (NULL);
} }

65
tmux.1
View File

@@ -2247,6 +2247,18 @@ Same as
.Ic scroll-down .Ic scroll-down
but also exit copy mode if the cursor reaches the bottom. but also exit copy mode if the cursor reaches the bottom.
.It Xo .It Xo
.Ic scroll-exit-on
.Xc
Turn on exiting copy mode when scrolling to the end of the buffer.
.It Xo
.Ic scroll-exit-off
.Xc
Turn off exiting copy mode when scrolling to the end of the buffer.
.It Xo
.Ic scroll-exit-toggle
.Xc
Toggle exiting copy mode when scrolling to the end of the buffer.
.It Xo
.Ic scroll-middle .Ic scroll-middle
(vi: z) (vi: z)
.Xc .Xc
@@ -3827,24 +3839,45 @@ To view the default bindings and possible commands, see the
command. command.
.Tg lsk .Tg lsk
.It Xo Ic list-keys .It Xo Ic list-keys
.Op Fl 1aN .Op Fl 1aNr
.Op Fl F Ar format
.Op Fl O Ar sort-order
.Op Fl P Ar prefix-string .Op Fl P Ar prefix-string
.Op Fl T Ar key-table .Op Fl T Ar key-table
.Op Ar key .Op Ar key
.Xc .Xc
.D1 Pq alias: Ic lsk .D1 Pq alias: Ic lsk
List key bindings. List key bindings.
There are two forms: the default lists keys as .Fl F
specifies the format of each line.
See the
.Sx FORMATS
section.
.Fl T
specifies a
.Ar key-table
to list from.
.Fl 1
lists only the first matching key.
.Fl O
specifies the sort order: one of
.Ql key ,
.Ql modifier ,
.Ql name
(table name).
.Fl r
reverses the sort order.
.Pp
If no
.Ar format
is given, there are two forms: the default lists keys as
.Ic bind-key .Ic bind-key
commands; commands;
.Fl N .Fl N
lists only keys with attached notes and shows only the key and note for each lists only keys with attached notes and shows only the key and note for each
key. key.
.Pp .Pp
With the default form, all key tables are listed by default. With the default form, all key tables are listed unless specified otherwise.
.Fl T
lists only keys in
.Ar key-table .
.Pp .Pp
With the With the
.Fl N .Fl N
@@ -3857,9 +3890,7 @@ key tables are listed by default;
also lists only keys in also lists only keys in
.Ar key-table . .Ar key-table .
.Fl P .Fl P
specifies a prefix to print before each key and specifies a prefix to print before each key.
.Fl 1
lists only the first matching key.
.Fl a .Fl a
lists the command for keys that do not have a note rather than skipping them. lists the command for keys that do not have a note rather than skipping them.
.Tg send .Tg send
@@ -6236,6 +6267,15 @@ The following variables are available, where appropriate:
.It Li "host" Ta "#H" Ta "Hostname of local host" .It Li "host" Ta "#H" Ta "Hostname of local host"
.It Li "host_short" Ta "#h" Ta "Hostname of local host (no domain name)" .It Li "host_short" Ta "#h" Ta "Hostname of local host (no domain name)"
.It Li "insert_flag" Ta "" Ta "Pane insert flag" .It Li "insert_flag" Ta "" Ta "Pane insert flag"
.It Li "key_string" Ta "" Ta "String representation of the key binding"
.It Li "key_repeat" Ta "" Ta "1 if key binding is repeatable"
.It Li "key_note" Ta "" Ta "Note of the key binding"
.It Li "key_prefix" Ta "" Ta "Global key prefix"
.It Li "key_table" Ta "" Ta "Table name of the key binding"
.It Li "key_command" Ta "" Ta "Command of the key binding"
.It Li "key_has_repeat" Ta "" Ta "1 if list contain a repeatable key"
.It Li "key_string_width" Ta "" Ta "Maximum key_string width in list"
.It Li "key_table_width" Ta "" Ta "Maximum key_table width in list"
.It Li "keypad_cursor_flag" Ta "" Ta "Pane keypad cursor flag" .It Li "keypad_cursor_flag" Ta "" Ta "Pane keypad cursor flag"
.It Li "keypad_flag" Ta "" Ta "Pane keypad flag" .It Li "keypad_flag" Ta "" Ta "Pane keypad flag"
.It Li "last_window_index" Ta "" Ta "Index of last window in session" .It Li "last_window_index" Ta "" Ta "Index of last window in session"
@@ -7411,7 +7451,7 @@ is
the contents are read from stdin. the contents are read from stdin.
.Tg pasteb .Tg pasteb
.It Xo Ic paste-buffer .It Xo Ic paste-buffer
.Op Fl dpr .Op Fl dprS
.Op Fl b Ar buffer-name .Op Fl b Ar buffer-name
.Op Fl s Ar separator .Op Fl s Ar separator
.Op Fl t Ar target-pane .Op Fl t Ar target-pane
@@ -7419,9 +7459,14 @@ the contents are read from stdin.
.D1 Pq alias: Ic pasteb .D1 Pq alias: Ic pasteb
Insert the contents of a paste buffer into the specified pane. Insert the contents of a paste buffer into the specified pane.
If not specified, paste into the current one. If not specified, paste into the current one.
By default, control characters are sanitized with
.Xr vis 3 ;
.Fl S
disables this.
With With
.Fl d , .Fl d ,
also delete the paste buffer. also delete the paste buffer.
.Pp
When output, any linefeed (LF) characters in the paste buffer are replaced with When output, any linefeed (LF) characters in the paste buffer are replaced with
a separator, by default carriage return (CR). a separator, by default carriage return (CR).
A custom separator may be specified using the A custom separator may be specified using the

16
tmux.h
View File

@@ -1146,6 +1146,7 @@ struct input_request_palette_data {
struct input_request_clipboard_data { struct input_request_clipboard_data {
char *buf; char *buf;
size_t len; size_t len;
char clip;
}; };
/* Request sent to client on behalf of pane. */ /* Request sent to client on behalf of pane. */
@@ -2157,6 +2158,7 @@ struct key_binding {
key_code key; key_code key;
struct cmd_list *cmdlist; struct cmd_list *cmdlist;
const char *note; const char *note;
const char *tablename;
int flags; int flags;
#define KEY_BINDING_REPEAT 0x1 #define KEY_BINDING_REPEAT 0x1
@@ -2296,6 +2298,7 @@ enum sort_order {
SORT_ACTIVITY, SORT_ACTIVITY,
SORT_CREATION, SORT_CREATION,
SORT_INDEX, SORT_INDEX,
SORT_MODIFIER,
SORT_NAME, SORT_NAME,
SORT_ORDER, SORT_ORDER,
SORT_SIZE, SORT_SIZE,
@@ -2394,6 +2397,10 @@ struct window_pane **sort_get_panes_window(struct window *, u_int *,
struct winlink **sort_get_winlinks(u_int *, struct sort_criteria *); struct winlink **sort_get_winlinks(u_int *, struct sort_criteria *);
struct winlink **sort_get_winlinks_session(struct session *, u_int *, struct winlink **sort_get_winlinks_session(struct session *, u_int *,
struct sort_criteria *); struct sort_criteria *);
struct key_binding **sort_get_key_bindings(u_int *,
struct sort_criteria *);
struct key_binding **sort_get_key_bindings_table(struct key_table *,
u_int *, struct sort_criteria *);
/* format.c */ /* format.c */
#define FORMAT_STATUS 0x1 #define FORMAT_STATUS 0x1
@@ -2906,6 +2913,7 @@ void key_bindings_reset(const char *, key_code);
void key_bindings_remove_table(const char *); void key_bindings_remove_table(const char *);
void key_bindings_reset_table(const char *); void key_bindings_reset_table(const char *);
void key_bindings_init(void); void key_bindings_init(void);
int key_bindings_has_repeat(struct key_binding **, u_int);
struct cmdq_item *key_bindings_dispatch(struct key_binding *, struct cmdq_item *key_bindings_dispatch(struct key_binding *,
struct cmdq_item *, struct client *, struct key_event *, struct cmdq_item *, struct client *, struct key_event *,
struct cmd_find_state *); struct cmd_find_state *);
@@ -3079,7 +3087,7 @@ void input_parse_buffer(struct window_pane *, u_char *, size_t);
void input_parse_screen(struct input_ctx *, struct screen *, void input_parse_screen(struct input_ctx *, struct screen *,
screen_write_init_ctx_cb, void *, u_char *, size_t); screen_write_init_ctx_cb, void *, u_char *, size_t);
void input_reply_clipboard(struct bufferevent *, const char *, size_t, void input_reply_clipboard(struct bufferevent *, const char *, size_t,
const char *); const char *, char);
void input_set_buffer_size(size_t); void input_set_buffer_size(size_t);
void input_request_reply(struct client *, enum input_request_type, void *); void input_request_reply(struct client *, enum input_request_type, void *);
void input_cancel_requests(struct client *); void input_cancel_requests(struct client *);
@@ -3637,9 +3645,9 @@ void utf8_copy(struct utf8_data *, const struct utf8_data *);
enum utf8_state utf8_open(struct utf8_data *, u_char); enum utf8_state utf8_open(struct utf8_data *, u_char);
enum utf8_state utf8_append(struct utf8_data *, u_char); enum utf8_state utf8_append(struct utf8_data *, u_char);
int utf8_isvalid(const char *); int utf8_isvalid(const char *);
int utf8_strvis(char *, const char *, size_t, int); size_t utf8_strvis(char *, const char *, size_t, int);
int utf8_stravis(char **, const char *, int); size_t utf8_stravis(char **, const char *, int);
int utf8_stravisx(char **, const char *, size_t, int); size_t utf8_stravisx(char **, const char *, size_t, int);
char *utf8_sanitize(const char *); char *utf8_sanitize(const char *);
size_t utf8_strlen(const struct utf8_data *); size_t utf8_strlen(const struct utf8_data *);
u_int utf8_strwidth(const struct utf8_data *, ssize_t); u_int utf8_strwidth(const struct utf8_data *, ssize_t);

View File

@@ -1310,7 +1310,7 @@ tty_keys_clipboard(struct tty *tty, const char *buf, size_t len, size_t *size)
{ {
struct client *c = tty->client; struct client *c = tty->client;
size_t end, terminator = 0, needed; size_t end, terminator = 0, needed;
char *copy, *out; char *copy, *out, clip = 0;
int outlen; int outlen;
struct input_request_clipboard_data cd; struct input_request_clipboard_data cd;
@@ -1360,7 +1360,14 @@ tty_keys_clipboard(struct tty *tty, const char *buf, size_t len, size_t *size)
/* Adjust end so that it points to the start of the terminator. */ /* Adjust end so that it points to the start of the terminator. */
end -= terminator - 1; end -= terminator - 1;
/* Get the second argument. */ /*
* Save which clipboard was used from the second argument. If more than
* one is specified (should not happen), ignore the argument.
*/
if (end >= 2 && buf[0] != ';' && buf[1] == ';')
clip = buf[0];
/* Skip the second argument. */
while (end != 0 && *buf != ';') { while (end != 0 && *buf != ';') {
buf++; buf++;
end--; end--;
@@ -1382,7 +1389,7 @@ tty_keys_clipboard(struct tty *tty, const char *buf, size_t len, size_t *size)
return (0); return (0);
} }
out = xmalloc(needed); out = xmalloc(needed);
if ((outlen = b64_pton(copy, out, len)) == -1) { if ((outlen = b64_pton(copy, out, needed)) == -1) {
free(out); free(out);
free(copy); free(copy);
return (0); return (0);
@@ -1393,6 +1400,7 @@ tty_keys_clipboard(struct tty *tty, const char *buf, size_t len, size_t *size)
/* Set reply if any. */ /* Set reply if any. */
cd.buf = out; cd.buf = out;
cd.len = outlen; cd.len = outlen;
cd.clip = clip;
input_request_reply(c, INPUT_REQUEST_CLIPBOARD, &cd); input_request_reply(c, INPUT_REQUEST_CLIPBOARD, &cd);
/* Create a buffer if requested. */ /* Create a buffer if requested. */

4
tty.c
View File

@@ -2135,7 +2135,7 @@ tty_cmd_setselection(struct tty *tty, const struct tty_ctx *ctx)
} }
void void
tty_set_selection(struct tty *tty, const char *flags, const char *buf, tty_set_selection(struct tty *tty, const char *clip, const char *buf,
size_t len) size_t len)
{ {
char *encoded; char *encoded;
@@ -2151,7 +2151,7 @@ tty_set_selection(struct tty *tty, const char *flags, const char *buf,
b64_ntop(buf, len, encoded, size); b64_ntop(buf, len, encoded, size);
tty->flags |= TTY_NOBLOCK; tty->flags |= TTY_NOBLOCK;
tty_putcode_ss(tty, TTYC_MS, flags, encoded); tty_putcode_ss(tty, TTYC_MS, clip, encoded);
free(encoded); free(encoded);
} }

10
utf8.c
View File

@@ -652,7 +652,7 @@ utf8_append(struct utf8_data *ud, u_char ch)
* bytes available for each character from src (for \abc or UTF-8) plus space * bytes available for each character from src (for \abc or UTF-8) plus space
* for \0. * for \0.
*/ */
int size_t
utf8_strvis(char *dst, const char *src, size_t len, int flag) utf8_strvis(char *dst, const char *src, size_t len, int flag)
{ {
struct utf8_data ud; struct utf8_data ud;
@@ -690,11 +690,11 @@ utf8_strvis(char *dst, const char *src, size_t len, int flag)
} }
/* Same as utf8_strvis but allocate the buffer. */ /* Same as utf8_strvis but allocate the buffer. */
int size_t
utf8_stravis(char **dst, const char *src, int flag) utf8_stravis(char **dst, const char *src, int flag)
{ {
char *buf; char *buf;
int len; size_t len;
buf = xreallocarray(NULL, 4, strlen(src) + 1); buf = xreallocarray(NULL, 4, strlen(src) + 1);
len = utf8_strvis(buf, src, strlen(src), flag); len = utf8_strvis(buf, src, strlen(src), flag);
@@ -704,11 +704,11 @@ utf8_stravis(char **dst, const char *src, int flag)
} }
/* Same as utf8_strvis but allocate the buffer. */ /* Same as utf8_strvis but allocate the buffer. */
int size_t
utf8_stravisx(char **dst, const char *src, size_t srclen, int flag) utf8_stravisx(char **dst, const char *src, size_t srclen, int flag)
{ {
char *buf; char *buf;
int len; size_t len;
buf = xreallocarray(NULL, 4, srclen + 1); buf = xreallocarray(NULL, 4, srclen + 1);
len = utf8_strvis(buf, src, srclen, flag); len = utf8_strvis(buf, src, srclen, flag);

View File

@@ -2127,6 +2127,36 @@ window_copy_cmd_rectangle_toggle(struct window_copy_cmd_state *cs)
return (WINDOW_COPY_CMD_NOTHING); return (WINDOW_COPY_CMD_NOTHING);
} }
static enum window_copy_cmd_action
window_copy_cmd_scroll_exit_on(struct window_copy_cmd_state *cs)
{
struct window_copy_mode_data *data = cs->wme->data;
data->scroll_exit = 1;
return (WINDOW_COPY_CMD_NOTHING);
}
static enum window_copy_cmd_action
window_copy_cmd_scroll_exit_off(struct window_copy_cmd_state *cs)
{
struct window_copy_mode_data *data = cs->wme->data;
data->scroll_exit = 0;
return (WINDOW_COPY_CMD_NOTHING);
}
static enum window_copy_cmd_action
window_copy_cmd_scroll_exit_toggle(struct window_copy_cmd_state *cs)
{
struct window_copy_mode_data *data = cs->wme->data;
data->scroll_exit = !data->scroll_exit;
return (WINDOW_COPY_CMD_NOTHING);
}
static enum window_copy_cmd_action static enum window_copy_cmd_action
window_copy_cmd_scroll_down(struct window_copy_cmd_state *cs) window_copy_cmd_scroll_down(struct window_copy_cmd_state *cs)
{ {
@@ -2702,16 +2732,20 @@ window_copy_cmd_refresh_from_pane(struct window_copy_cmd_state *cs)
struct window_mode_entry *wme = cs->wme; struct window_mode_entry *wme = cs->wme;
struct window_pane *wp = wme->swp; struct window_pane *wp = wme->swp;
struct window_copy_mode_data *data = wme->data; struct window_copy_mode_data *data = wme->data;
u_int oy_from_top;
if (data->viewmode) if (data->viewmode)
return (WINDOW_COPY_CMD_NOTHING); return (WINDOW_COPY_CMD_NOTHING);
oy_from_top = screen_hsize(data->backing) - data->oy;
screen_free(data->backing); screen_free(data->backing);
free(data->backing); free(data->backing);
data->backing = window_copy_clone_screen(&wp->base, &data->screen, NULL, data->backing = window_copy_clone_screen(&wp->base, &data->screen, NULL,
NULL, wme->swp != wme->wp); NULL, wme->swp != wme->wp);
if (data->oy > screen_hsize(data->backing)) { if (oy_from_top <= screen_hsize(data->backing))
data->oy = screen_hsize(data->backing) - oy_from_top;
else {
data->cy = 0; data->cy = 0;
data->oy = screen_hsize(data->backing); data->oy = screen_hsize(data->backing);
} }
@@ -2725,451 +2759,559 @@ static const struct {
u_int minargs; u_int minargs;
u_int maxargs; u_int maxargs;
struct args_parse args; struct args_parse args;
#define WINDOW_COPY_CMD_FLAG_READONLY 0x1
int flags;
enum window_copy_cmd_clear clear; enum window_copy_cmd_clear clear;
enum window_copy_cmd_action (*f)(struct window_copy_cmd_state *); enum window_copy_cmd_action (*f)(struct window_copy_cmd_state *);
} window_copy_cmd_table[] = { } window_copy_cmd_table[] = {
{ .command = "append-selection", { .command = "append-selection",
.args = { "", 0, 0, NULL }, .args = { "", 0, 0, NULL },
.flags = 0,
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS, .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
.f = window_copy_cmd_append_selection .f = window_copy_cmd_append_selection
}, },
{ .command = "append-selection-and-cancel", { .command = "append-selection-and-cancel",
.args = { "", 0, 0, NULL }, .args = { "", 0, 0, NULL },
.flags = 0,
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS, .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
.f = window_copy_cmd_append_selection_and_cancel .f = window_copy_cmd_append_selection_and_cancel
}, },
{ .command = "back-to-indentation", { .command = "back-to-indentation",
.args = { "", 0, 0, NULL }, .args = { "", 0, 0, NULL },
.flags = WINDOW_COPY_CMD_FLAG_READONLY,
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS, .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
.f = window_copy_cmd_back_to_indentation .f = window_copy_cmd_back_to_indentation
}, },
{ .command = "begin-selection", { .command = "begin-selection",
.args = { "", 0, 0, NULL }, .args = { "", 0, 0, NULL },
.flags = 0,
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS, .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
.f = window_copy_cmd_begin_selection .f = window_copy_cmd_begin_selection
}, },
{ .command = "bottom-line", { .command = "bottom-line",
.args = { "", 0, 0, NULL }, .args = { "", 0, 0, NULL },
.flags = WINDOW_COPY_CMD_FLAG_READONLY,
.clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY, .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
.f = window_copy_cmd_bottom_line .f = window_copy_cmd_bottom_line
}, },
{ .command = "cancel", { .command = "cancel",
.args = { "", 0, 0, NULL }, .args = { "", 0, 0, NULL },
.flags = WINDOW_COPY_CMD_FLAG_READONLY,
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS, .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
.f = window_copy_cmd_cancel .f = window_copy_cmd_cancel
}, },
{ .command = "clear-selection", { .command = "clear-selection",
.args = { "", 0, 0, NULL }, .args = { "", 0, 0, NULL },
.flags = 0,
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS, .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
.f = window_copy_cmd_clear_selection .f = window_copy_cmd_clear_selection
}, },
{ .command = "copy-end-of-line", { .command = "copy-end-of-line",
.args = { "CP", 0, 1, NULL }, .args = { "CP", 0, 1, NULL },
.flags = 0,
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS, .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
.f = window_copy_cmd_copy_end_of_line .f = window_copy_cmd_copy_end_of_line
}, },
{ .command = "copy-end-of-line-and-cancel", { .command = "copy-end-of-line-and-cancel",
.args = { "CP", 0, 1, NULL }, .args = { "CP", 0, 1, NULL },
.flags = 0,
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS, .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
.f = window_copy_cmd_copy_end_of_line_and_cancel .f = window_copy_cmd_copy_end_of_line_and_cancel
}, },
{ .command = "copy-pipe-end-of-line", { .command = "copy-pipe-end-of-line",
.args = { "CP", 0, 2, NULL }, .args = { "CP", 0, 2, NULL },
.flags = 0,
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS, .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
.f = window_copy_cmd_copy_pipe_end_of_line .f = window_copy_cmd_copy_pipe_end_of_line
}, },
{ .command = "copy-pipe-end-of-line-and-cancel", { .command = "copy-pipe-end-of-line-and-cancel",
.args = { "CP", 0, 2, NULL }, .args = { "CP", 0, 2, NULL },
.flags = 0,
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS, .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
.f = window_copy_cmd_copy_pipe_end_of_line_and_cancel .f = window_copy_cmd_copy_pipe_end_of_line_and_cancel
}, },
{ .command = "copy-line", { .command = "copy-line",
.args = { "CP", 0, 1, NULL }, .args = { "CP", 0, 1, NULL },
.flags = 0,
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS, .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
.f = window_copy_cmd_copy_line .f = window_copy_cmd_copy_line
}, },
{ .command = "copy-line-and-cancel", { .command = "copy-line-and-cancel",
.args = { "CP", 0, 1, NULL }, .args = { "CP", 0, 1, NULL },
.flags = 0,
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS, .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
.f = window_copy_cmd_copy_line_and_cancel .f = window_copy_cmd_copy_line_and_cancel
}, },
{ .command = "copy-pipe-line", { .command = "copy-pipe-line",
.args = { "CP", 0, 2, NULL }, .args = { "CP", 0, 2, NULL },
.flags = 0,
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS, .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
.f = window_copy_cmd_copy_pipe_line .f = window_copy_cmd_copy_pipe_line
}, },
{ .command = "copy-pipe-line-and-cancel", { .command = "copy-pipe-line-and-cancel",
.args = { "CP", 0, 2, NULL }, .args = { "CP", 0, 2, NULL },
.flags = 0,
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS, .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
.f = window_copy_cmd_copy_pipe_line_and_cancel .f = window_copy_cmd_copy_pipe_line_and_cancel
}, },
{ .command = "copy-pipe-no-clear", { .command = "copy-pipe-no-clear",
.args = { "CP", 0, 2, NULL }, .args = { "CP", 0, 2, NULL },
.flags = 0,
.clear = WINDOW_COPY_CMD_CLEAR_NEVER, .clear = WINDOW_COPY_CMD_CLEAR_NEVER,
.f = window_copy_cmd_copy_pipe_no_clear .f = window_copy_cmd_copy_pipe_no_clear
}, },
{ .command = "copy-pipe", { .command = "copy-pipe",
.args = { "CP", 0, 2, NULL }, .args = { "CP", 0, 2, NULL },
.flags = 0,
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS, .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
.f = window_copy_cmd_copy_pipe .f = window_copy_cmd_copy_pipe
}, },
{ .command = "copy-pipe-and-cancel", { .command = "copy-pipe-and-cancel",
.args = { "CP", 0, 2, NULL }, .args = { "CP", 0, 2, NULL },
.flags = 0,
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS, .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
.f = window_copy_cmd_copy_pipe_and_cancel .f = window_copy_cmd_copy_pipe_and_cancel
}, },
{ .command = "copy-selection-no-clear", { .command = "copy-selection-no-clear",
.args = { "CP", 0, 1, NULL }, .args = { "CP", 0, 1, NULL },
.flags = 0,
.clear = WINDOW_COPY_CMD_CLEAR_NEVER, .clear = WINDOW_COPY_CMD_CLEAR_NEVER,
.f = window_copy_cmd_copy_selection_no_clear .f = window_copy_cmd_copy_selection_no_clear
}, },
{ .command = "copy-selection", { .command = "copy-selection",
.args = { "CP", 0, 1, NULL }, .args = { "CP", 0, 1, NULL },
.flags = 0,
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS, .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
.f = window_copy_cmd_copy_selection .f = window_copy_cmd_copy_selection
}, },
{ .command = "copy-selection-and-cancel", { .command = "copy-selection-and-cancel",
.args = { "CP", 0, 1, NULL }, .args = { "CP", 0, 1, NULL },
.flags = 0,
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS, .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
.f = window_copy_cmd_copy_selection_and_cancel .f = window_copy_cmd_copy_selection_and_cancel
}, },
{ .command = "cursor-down", { .command = "cursor-down",
.args = { "", 0, 0, NULL }, .args = { "", 0, 0, NULL },
.flags = WINDOW_COPY_CMD_FLAG_READONLY,
.clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY, .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
.f = window_copy_cmd_cursor_down .f = window_copy_cmd_cursor_down
}, },
{ .command = "cursor-down-and-cancel", { .command = "cursor-down-and-cancel",
.args = { "", 0, 0, NULL }, .args = { "", 0, 0, NULL },
.flags = WINDOW_COPY_CMD_FLAG_READONLY,
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS, .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
.f = window_copy_cmd_cursor_down_and_cancel .f = window_copy_cmd_cursor_down_and_cancel
}, },
{ .command = "cursor-left", { .command = "cursor-left",
.args = { "", 0, 0, NULL }, .args = { "", 0, 0, NULL },
.flags = WINDOW_COPY_CMD_FLAG_READONLY,
.clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY, .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
.f = window_copy_cmd_cursor_left .f = window_copy_cmd_cursor_left
}, },
{ .command = "cursor-right", { .command = "cursor-right",
.args = { "", 0, 0, NULL }, .args = { "", 0, 0, NULL },
.flags = WINDOW_COPY_CMD_FLAG_READONLY,
.clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY, .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
.f = window_copy_cmd_cursor_right .f = window_copy_cmd_cursor_right
}, },
{ .command = "cursor-up", { .command = "cursor-up",
.args = { "", 0, 0, NULL }, .args = { "", 0, 0, NULL },
.flags = WINDOW_COPY_CMD_FLAG_READONLY,
.clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY, .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
.f = window_copy_cmd_cursor_up .f = window_copy_cmd_cursor_up
}, },
{ .command = "cursor-centre-vertical", { .command = "cursor-centre-vertical",
.args = { "", 0, 0, NULL }, .args = { "", 0, 0, NULL },
.flags = WINDOW_COPY_CMD_FLAG_READONLY,
.clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY, .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
.f = window_copy_cmd_centre_vertical, .f = window_copy_cmd_centre_vertical,
}, },
{ .command = "cursor-centre-horizontal", { .command = "cursor-centre-horizontal",
.args = { "", 0, 0, NULL }, .args = { "", 0, 0, NULL },
.flags = WINDOW_COPY_CMD_FLAG_READONLY,
.clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY, .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
.f = window_copy_cmd_centre_horizontal, .f = window_copy_cmd_centre_horizontal,
}, },
{ .command = "end-of-line", { .command = "end-of-line",
.args = { "", 0, 0, NULL }, .args = { "", 0, 0, NULL },
.flags = WINDOW_COPY_CMD_FLAG_READONLY,
.clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY, .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
.f = window_copy_cmd_end_of_line .f = window_copy_cmd_end_of_line
}, },
{ .command = "goto-line", { .command = "goto-line",
.args = { "", 1, 1, NULL }, .args = { "", 1, 1, NULL },
.flags = WINDOW_COPY_CMD_FLAG_READONLY,
.clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY, .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
.f = window_copy_cmd_goto_line .f = window_copy_cmd_goto_line
}, },
{ .command = "halfpage-down", { .command = "halfpage-down",
.args = { "", 0, 0, NULL }, .args = { "", 0, 0, NULL },
.flags = WINDOW_COPY_CMD_FLAG_READONLY,
.clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY, .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
.f = window_copy_cmd_halfpage_down .f = window_copy_cmd_halfpage_down
}, },
{ .command = "halfpage-down-and-cancel", { .command = "halfpage-down-and-cancel",
.args = { "", 0, 0, NULL }, .args = { "", 0, 0, NULL },
.flags = WINDOW_COPY_CMD_FLAG_READONLY,
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS, .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
.f = window_copy_cmd_halfpage_down_and_cancel .f = window_copy_cmd_halfpage_down_and_cancel
}, },
{ .command = "halfpage-up", { .command = "halfpage-up",
.args = { "", 0, 0, NULL }, .args = { "", 0, 0, NULL },
.flags = WINDOW_COPY_CMD_FLAG_READONLY,
.clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY, .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
.f = window_copy_cmd_halfpage_up .f = window_copy_cmd_halfpage_up
}, },
{ .command = "history-bottom", { .command = "history-bottom",
.args = { "", 0, 0, NULL }, .args = { "", 0, 0, NULL },
.flags = WINDOW_COPY_CMD_FLAG_READONLY,
.clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY, .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
.f = window_copy_cmd_history_bottom .f = window_copy_cmd_history_bottom
}, },
{ .command = "history-top", { .command = "history-top",
.args = { "", 0, 0, NULL }, .args = { "", 0, 0, NULL },
.flags = WINDOW_COPY_CMD_FLAG_READONLY,
.clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY, .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
.f = window_copy_cmd_history_top .f = window_copy_cmd_history_top
}, },
{ .command = "jump-again", { .command = "jump-again",
.args = { "", 0, 0, NULL }, .args = { "", 0, 0, NULL },
.flags = 0,
.clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY, .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
.f = window_copy_cmd_jump_again .f = window_copy_cmd_jump_again
}, },
{ .command = "jump-backward", { .command = "jump-backward",
.args = { "", 1, 1, NULL }, .args = { "", 1, 1, NULL },
.flags = 0,
.clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY, .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
.f = window_copy_cmd_jump_backward .f = window_copy_cmd_jump_backward
}, },
{ .command = "jump-forward", { .command = "jump-forward",
.args = { "", 1, 1, NULL }, .args = { "", 1, 1, NULL },
.flags = 0,
.clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY, .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
.f = window_copy_cmd_jump_forward .f = window_copy_cmd_jump_forward
}, },
{ .command = "jump-reverse", { .command = "jump-reverse",
.args = { "", 0, 0, NULL }, .args = { "", 0, 0, NULL },
.flags = 0,
.clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY, .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
.f = window_copy_cmd_jump_reverse .f = window_copy_cmd_jump_reverse
}, },
{ .command = "jump-to-backward", { .command = "jump-to-backward",
.args = { "", 1, 1, NULL }, .args = { "", 1, 1, NULL },
.flags = 0,
.clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY, .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
.f = window_copy_cmd_jump_to_backward .f = window_copy_cmd_jump_to_backward
}, },
{ .command = "jump-to-forward", { .command = "jump-to-forward",
.args = { "", 1, 1, NULL }, .args = { "", 1, 1, NULL },
.flags = 0,
.clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY, .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
.f = window_copy_cmd_jump_to_forward .f = window_copy_cmd_jump_to_forward
}, },
{ .command = "jump-to-mark", { .command = "jump-to-mark",
.args = { "", 0, 0, NULL }, .args = { "", 0, 0, NULL },
.flags = WINDOW_COPY_CMD_FLAG_READONLY,
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS, .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
.f = window_copy_cmd_jump_to_mark .f = window_copy_cmd_jump_to_mark
}, },
{ .command = "next-prompt", { .command = "next-prompt",
.args = { "o", 0, 0, NULL }, .args = { "o", 0, 0, NULL },
.flags = WINDOW_COPY_CMD_FLAG_READONLY,
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS, .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
.f = window_copy_cmd_next_prompt .f = window_copy_cmd_next_prompt
}, },
{ .command = "previous-prompt", { .command = "previous-prompt",
.args = { "o", 0, 0, NULL }, .args = { "o", 0, 0, NULL },
.flags = WINDOW_COPY_CMD_FLAG_READONLY,
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS, .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
.f = window_copy_cmd_previous_prompt .f = window_copy_cmd_previous_prompt
}, },
{ .command = "middle-line", { .command = "middle-line",
.args = { "", 0, 0, NULL }, .args = { "", 0, 0, NULL },
.flags = WINDOW_COPY_CMD_FLAG_READONLY,
.clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY, .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
.f = window_copy_cmd_middle_line .f = window_copy_cmd_middle_line
}, },
{ .command = "next-matching-bracket", { .command = "next-matching-bracket",
.args = { "", 0, 0, NULL }, .args = { "", 0, 0, NULL },
.flags = WINDOW_COPY_CMD_FLAG_READONLY,
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS, .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
.f = window_copy_cmd_next_matching_bracket .f = window_copy_cmd_next_matching_bracket
}, },
{ .command = "next-paragraph", { .command = "next-paragraph",
.args = { "", 0, 0, NULL }, .args = { "", 0, 0, NULL },
.flags = WINDOW_COPY_CMD_FLAG_READONLY,
.clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY, .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
.f = window_copy_cmd_next_paragraph .f = window_copy_cmd_next_paragraph
}, },
{ .command = "next-space", { .command = "next-space",
.args = { "", 0, 0, NULL }, .args = { "", 0, 0, NULL },
.flags = WINDOW_COPY_CMD_FLAG_READONLY,
.clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY, .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
.f = window_copy_cmd_next_space .f = window_copy_cmd_next_space
}, },
{ .command = "next-space-end", { .command = "next-space-end",
.args = { "", 0, 0, NULL }, .args = { "", 0, 0, NULL },
.flags = WINDOW_COPY_CMD_FLAG_READONLY,
.clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY, .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
.f = window_copy_cmd_next_space_end .f = window_copy_cmd_next_space_end
}, },
{ .command = "next-word", { .command = "next-word",
.args = { "", 0, 0, NULL }, .args = { "", 0, 0, NULL },
.flags = WINDOW_COPY_CMD_FLAG_READONLY,
.clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY, .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
.f = window_copy_cmd_next_word .f = window_copy_cmd_next_word
}, },
{ .command = "next-word-end", { .command = "next-word-end",
.args = { "", 0, 0, NULL }, .args = { "", 0, 0, NULL },
.flags = WINDOW_COPY_CMD_FLAG_READONLY,
.clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY, .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
.f = window_copy_cmd_next_word_end .f = window_copy_cmd_next_word_end
}, },
{ .command = "other-end", { .command = "other-end",
.args = { "", 0, 0, NULL }, .args = { "", 0, 0, NULL },
.flags = 0,
.clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY, .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
.f = window_copy_cmd_other_end .f = window_copy_cmd_other_end
}, },
{ .command = "page-down", { .command = "page-down",
.args = { "", 0, 0, NULL }, .args = { "", 0, 0, NULL },
.flags = WINDOW_COPY_CMD_FLAG_READONLY,
.clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY, .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
.f = window_copy_cmd_page_down .f = window_copy_cmd_page_down
}, },
{ .command = "page-down-and-cancel", { .command = "page-down-and-cancel",
.args = { "", 0, 0, NULL }, .args = { "", 0, 0, NULL },
.flags = WINDOW_COPY_CMD_FLAG_READONLY,
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS, .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
.f = window_copy_cmd_page_down_and_cancel .f = window_copy_cmd_page_down_and_cancel
}, },
{ .command = "page-up", { .command = "page-up",
.args = { "", 0, 0, NULL }, .args = { "", 0, 0, NULL },
.flags = WINDOW_COPY_CMD_FLAG_READONLY,
.clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY, .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
.f = window_copy_cmd_page_up .f = window_copy_cmd_page_up
}, },
{ .command = "pipe-no-clear", { .command = "pipe-no-clear",
.args = { "", 0, 1, NULL }, .args = { "", 0, 1, NULL },
.flags = 0,
.clear = WINDOW_COPY_CMD_CLEAR_NEVER, .clear = WINDOW_COPY_CMD_CLEAR_NEVER,
.f = window_copy_cmd_pipe_no_clear .f = window_copy_cmd_pipe_no_clear
}, },
{ .command = "pipe", { .command = "pipe",
.args = { "", 0, 1, NULL }, .args = { "", 0, 1, NULL },
.flags = 0,
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS, .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
.f = window_copy_cmd_pipe .f = window_copy_cmd_pipe
}, },
{ .command = "pipe-and-cancel", { .command = "pipe-and-cancel",
.args = { "", 0, 1, NULL }, .args = { "", 0, 1, NULL },
.flags = 0,
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS, .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
.f = window_copy_cmd_pipe_and_cancel .f = window_copy_cmd_pipe_and_cancel
}, },
{ .command = "previous-matching-bracket", { .command = "previous-matching-bracket",
.args = { "", 0, 0, NULL }, .args = { "", 0, 0, NULL },
.flags = WINDOW_COPY_CMD_FLAG_READONLY,
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS, .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
.f = window_copy_cmd_previous_matching_bracket .f = window_copy_cmd_previous_matching_bracket
}, },
{ .command = "previous-paragraph", { .command = "previous-paragraph",
.args = { "", 0, 0, NULL }, .args = { "", 0, 0, NULL },
.flags = WINDOW_COPY_CMD_FLAG_READONLY,
.clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY, .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
.f = window_copy_cmd_previous_paragraph .f = window_copy_cmd_previous_paragraph
}, },
{ .command = "previous-space", { .command = "previous-space",
.args = { "", 0, 0, NULL }, .args = { "", 0, 0, NULL },
.flags = WINDOW_COPY_CMD_FLAG_READONLY,
.clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY, .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
.f = window_copy_cmd_previous_space .f = window_copy_cmd_previous_space
}, },
{ .command = "previous-word", { .command = "previous-word",
.args = { "", 0, 0, NULL }, .args = { "", 0, 0, NULL },
.flags = WINDOW_COPY_CMD_FLAG_READONLY,
.clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY, .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
.f = window_copy_cmd_previous_word .f = window_copy_cmd_previous_word
}, },
{ .command = "rectangle-on", { .command = "rectangle-on",
.args = { "", 0, 0, NULL }, .args = { "", 0, 0, NULL },
.flags = 0,
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS, .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
.f = window_copy_cmd_rectangle_on .f = window_copy_cmd_rectangle_on
}, },
{ .command = "rectangle-off", { .command = "rectangle-off",
.args = { "", 0, 0, NULL }, .args = { "", 0, 0, NULL },
.flags = 0,
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS, .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
.f = window_copy_cmd_rectangle_off .f = window_copy_cmd_rectangle_off
}, },
{ .command = "rectangle-toggle", { .command = "rectangle-toggle",
.args = { "", 0, 0, NULL }, .args = { "", 0, 0, NULL },
.flags = 0,
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS, .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
.f = window_copy_cmd_rectangle_toggle .f = window_copy_cmd_rectangle_toggle
}, },
{ .command = "refresh-from-pane", { .command = "refresh-from-pane",
.args = { "", 0, 0, NULL }, .args = { "", 0, 0, NULL },
.flags = WINDOW_COPY_CMD_FLAG_READONLY,
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS, .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
.f = window_copy_cmd_refresh_from_pane .f = window_copy_cmd_refresh_from_pane
}, },
{ .command = "scroll-bottom", { .command = "scroll-bottom",
.args = { "", 0, 0, NULL }, .args = { "", 0, 0, NULL },
.flags = WINDOW_COPY_CMD_FLAG_READONLY,
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS, .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
.f = window_copy_cmd_scroll_bottom .f = window_copy_cmd_scroll_bottom
}, },
{ .command = "scroll-down", { .command = "scroll-down",
.args = { "", 0, 0, NULL }, .args = { "", 0, 0, NULL },
.flags = WINDOW_COPY_CMD_FLAG_READONLY,
.clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY, .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
.f = window_copy_cmd_scroll_down .f = window_copy_cmd_scroll_down
}, },
{ .command = "scroll-down-and-cancel", { .command = "scroll-down-and-cancel",
.args = { "", 0, 0, NULL }, .args = { "", 0, 0, NULL },
.flags = WINDOW_COPY_CMD_FLAG_READONLY,
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS, .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
.f = window_copy_cmd_scroll_down_and_cancel .f = window_copy_cmd_scroll_down_and_cancel
}, },
{ .command = "scroll-exit-on",
.args = { "", 0, 0, NULL },
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
.f = window_copy_cmd_scroll_exit_on
},
{ .command = "scroll-exit-off",
.args = { "", 0, 0, NULL },
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
.f = window_copy_cmd_scroll_exit_off
},
{ .command = "scroll-exit-toggle",
.args = { "", 0, 0, NULL },
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
.f = window_copy_cmd_scroll_exit_toggle
},
{ .command = "scroll-middle", { .command = "scroll-middle",
.args = { "", 0, 0, NULL }, .args = { "", 0, 0, NULL },
.flags = WINDOW_COPY_CMD_FLAG_READONLY,
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS, .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
.f = window_copy_cmd_scroll_middle .f = window_copy_cmd_scroll_middle
}, },
{ .command = "scroll-to-mouse", { .command = "scroll-to-mouse",
.args = { "e", 0, 0, NULL }, .args = { "e", 0, 0, NULL },
.flags = WINDOW_COPY_CMD_FLAG_READONLY,
.clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY, .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
.f = window_copy_cmd_scroll_to_mouse .f = window_copy_cmd_scroll_to_mouse
}, },
{ .command = "scroll-top", { .command = "scroll-top",
.args = { "", 0, 0, NULL }, .args = { "", 0, 0, NULL },
.flags = WINDOW_COPY_CMD_FLAG_READONLY,
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS, .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
.f = window_copy_cmd_scroll_top .f = window_copy_cmd_scroll_top
}, },
{ .command = "scroll-up", { .command = "scroll-up",
.args = { "", 0, 0, NULL }, .args = { "", 0, 0, NULL },
.flags = WINDOW_COPY_CMD_FLAG_READONLY,
.clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY, .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
.f = window_copy_cmd_scroll_up .f = window_copy_cmd_scroll_up
}, },
{ .command = "search-again", { .command = "search-again",
.args = { "", 0, 0, NULL }, .args = { "", 0, 0, NULL },
.flags = 0,
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS, .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
.f = window_copy_cmd_search_again .f = window_copy_cmd_search_again
}, },
{ .command = "search-backward", { .command = "search-backward",
.args = { "", 0, 1, NULL }, .args = { "", 0, 1, NULL },
.flags = 0,
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS, .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
.f = window_copy_cmd_search_backward .f = window_copy_cmd_search_backward
}, },
{ .command = "search-backward-text", { .command = "search-backward-text",
.args = { "", 0, 1, NULL }, .args = { "", 0, 1, NULL },
.flags = 0,
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS, .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
.f = window_copy_cmd_search_backward_text .f = window_copy_cmd_search_backward_text
}, },
{ .command = "search-backward-incremental", { .command = "search-backward-incremental",
.args = { "", 1, 1, NULL }, .args = { "", 1, 1, NULL },
.flags = 0,
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS, .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
.f = window_copy_cmd_search_backward_incremental .f = window_copy_cmd_search_backward_incremental
}, },
{ .command = "search-forward", { .command = "search-forward",
.args = { "", 0, 1, NULL }, .args = { "", 0, 1, NULL },
.flags = 0,
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS, .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
.f = window_copy_cmd_search_forward .f = window_copy_cmd_search_forward
}, },
{ .command = "search-forward-text", { .command = "search-forward-text",
.args = { "", 0, 1, NULL }, .args = { "", 0, 1, NULL },
.flags = 0,
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS, .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
.f = window_copy_cmd_search_forward_text .f = window_copy_cmd_search_forward_text
}, },
{ .command = "search-forward-incremental", { .command = "search-forward-incremental",
.args = { "", 1, 1, NULL }, .args = { "", 1, 1, NULL },
.flags = 0,
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS, .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
.f = window_copy_cmd_search_forward_incremental .f = window_copy_cmd_search_forward_incremental
}, },
{ .command = "search-reverse", { .command = "search-reverse",
.args = { "", 0, 0, NULL }, .args = { "", 0, 0, NULL },
.flags = 0,
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS, .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
.f = window_copy_cmd_search_reverse .f = window_copy_cmd_search_reverse
}, },
{ .command = "select-line", { .command = "select-line",
.args = { "", 0, 0, NULL }, .args = { "", 0, 0, NULL },
.flags = 0,
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS, .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
.f = window_copy_cmd_select_line .f = window_copy_cmd_select_line
}, },
{ .command = "select-word", { .command = "select-word",
.args = { "", 0, 0, NULL }, .args = { "", 0, 0, NULL },
.flags = 0,
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS, .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
.f = window_copy_cmd_select_word .f = window_copy_cmd_select_word
}, },
{ .command = "selection-mode", { .command = "selection-mode",
.args = { "", 0, 1, NULL }, .args = { "", 0, 1, NULL },
.flags = 0,
.clear = 0, .clear = 0,
.f = window_copy_cmd_selection_mode .f = window_copy_cmd_selection_mode
}, },
{ .command = "set-mark", { .command = "set-mark",
.args = { "", 0, 0, NULL }, .args = { "", 0, 0, NULL },
.flags = WINDOW_COPY_CMD_FLAG_READONLY,
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS, .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
.f = window_copy_cmd_set_mark .f = window_copy_cmd_set_mark
}, },
{ .command = "start-of-line", { .command = "start-of-line",
.args = { "", 0, 0, NULL }, .args = { "", 0, 0, NULL },
.flags = WINDOW_COPY_CMD_FLAG_READONLY,
.clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY, .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
.f = window_copy_cmd_start_of_line .f = window_copy_cmd_start_of_line
}, },
{ .command = "stop-selection", { .command = "stop-selection",
.args = { "", 0, 0, NULL }, .args = { "", 0, 0, NULL },
.flags = 0,
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS, .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
.f = window_copy_cmd_stop_selection .f = window_copy_cmd_stop_selection
}, },
{ .command = "toggle-position", { .command = "toggle-position",
.args = { "", 0, 0, NULL }, .args = { "", 0, 0, NULL },
.flags = WINDOW_COPY_CMD_FLAG_READONLY,
.clear = WINDOW_COPY_CMD_CLEAR_NEVER, .clear = WINDOW_COPY_CMD_CLEAR_NEVER,
.f = window_copy_cmd_toggle_position .f = window_copy_cmd_toggle_position
}, },
{ .command = "top-line", { .command = "top-line",
.args = { "", 0, 0, NULL }, .args = { "", 0, 0, NULL },
.flags = WINDOW_COPY_CMD_FLAG_READONLY,
.clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY, .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
.f = window_copy_cmd_top_line .f = window_copy_cmd_top_line
} }
@@ -3209,6 +3351,14 @@ window_copy_command(struct window_mode_entry *wme, struct client *c,
action = WINDOW_COPY_CMD_NOTHING; action = WINDOW_COPY_CMD_NOTHING;
for (i = 0; i < nitems(window_copy_cmd_table); i++) { for (i = 0; i < nitems(window_copy_cmd_table); i++) {
if (strcmp(window_copy_cmd_table[i].command, command) == 0) { if (strcmp(window_copy_cmd_table[i].command, command) == 0) {
if (c->flags & CLIENT_READONLY &&
(~window_copy_cmd_table[i].flags &
WINDOW_COPY_CMD_FLAG_READONLY)) {
status_message_set(c, -1, 1, 0, 0,
"client is read-only");
return;
}
cs.wargs = args_parse(&window_copy_cmd_table[i].args, cs.wargs = args_parse(&window_copy_cmd_table[i].args,
args_values(args), count, &error); args_values(args), count, &error);