mirror of
https://github.com/tmux/tmux.git
synced 2025-01-09 09:38:48 +00:00
Merge branch 'master' into sixel
This commit is contained in:
commit
64368a1a63
223
arguments.c
223
arguments.c
@ -37,6 +37,10 @@ struct args_entry {
|
|||||||
u_char flag;
|
u_char flag;
|
||||||
struct args_values values;
|
struct args_values values;
|
||||||
u_int count;
|
u_int count;
|
||||||
|
|
||||||
|
int flags;
|
||||||
|
#define ARGS_ENTRY_OPTIONAL_VALUE 0x1
|
||||||
|
|
||||||
RB_ENTRY(args_entry) entry;
|
RB_ENTRY(args_entry) entry;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -94,6 +98,22 @@ args_copy_value(struct args_value *to, struct args_value *from)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Type to string. */
|
||||||
|
static const char *
|
||||||
|
args_type_to_string (enum args_type type)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case ARGS_NONE:
|
||||||
|
return "NONE";
|
||||||
|
case ARGS_STRING:
|
||||||
|
return "STRING";
|
||||||
|
case ARGS_COMMANDS:
|
||||||
|
return "COMMANDS";
|
||||||
|
}
|
||||||
|
return "INVALID";
|
||||||
|
}
|
||||||
|
|
||||||
/* Get value as string. */
|
/* Get value as string. */
|
||||||
static const char *
|
static const char *
|
||||||
args_value_as_string(struct args_value *value)
|
args_value_as_string(struct args_value *value)
|
||||||
@ -122,6 +142,99 @@ args_create(void)
|
|||||||
return (args);
|
return (args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Parse a single flag. */
|
||||||
|
static int
|
||||||
|
args_parse_flag_argument(struct args_value *values, u_int count, char **cause,
|
||||||
|
struct args *args, u_int *i, const char *string, int flag,
|
||||||
|
int optional_argument)
|
||||||
|
{
|
||||||
|
struct args_value *argument, *new;
|
||||||
|
const char *s;
|
||||||
|
|
||||||
|
new = xcalloc(1, sizeof *new);
|
||||||
|
if (*string != '\0') {
|
||||||
|
new->type = ARGS_STRING;
|
||||||
|
new->string = xstrdup(string);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*i == count)
|
||||||
|
argument = NULL;
|
||||||
|
else {
|
||||||
|
argument = &values[*i];
|
||||||
|
if (argument->type != ARGS_STRING) {
|
||||||
|
xasprintf(cause, "-%c argument must be a string", flag);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (argument == NULL) {
|
||||||
|
if (optional_argument) {
|
||||||
|
log_debug("%s: -%c (optional)", __func__, flag);
|
||||||
|
args_set(args, flag, NULL, ARGS_ENTRY_OPTIONAL_VALUE);
|
||||||
|
return (0); /* either - or end */
|
||||||
|
}
|
||||||
|
xasprintf(cause, "-%c expects an argument", flag);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
args_copy_value(new, argument);
|
||||||
|
(*i)++;
|
||||||
|
|
||||||
|
out:
|
||||||
|
s = args_value_as_string(new);
|
||||||
|
log_debug("%s: -%c = %s", __func__, flag, s);
|
||||||
|
args_set(args, flag, new, 0);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse flags argument. */
|
||||||
|
static int
|
||||||
|
args_parse_flags(const struct args_parse *parse, struct args_value *values,
|
||||||
|
u_int count, char **cause, struct args *args, int *i)
|
||||||
|
{
|
||||||
|
struct args_value *value;
|
||||||
|
u_char flag;
|
||||||
|
const char *found, *string;
|
||||||
|
int optional_argument;
|
||||||
|
|
||||||
|
value = &values[*i];
|
||||||
|
if (value->type != ARGS_STRING)
|
||||||
|
return (1);
|
||||||
|
|
||||||
|
string = value->string;
|
||||||
|
log_debug("%s: next %s", __func__, string);
|
||||||
|
if (*string++ != '-' || *string == '\0')
|
||||||
|
return (1);
|
||||||
|
(*i)++;
|
||||||
|
if (string[0] == '-' && string[1] == '\0')
|
||||||
|
return (1);
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
flag = *string++;
|
||||||
|
if (flag == '\0')
|
||||||
|
return (0);
|
||||||
|
if (flag == '?')
|
||||||
|
return (-1);
|
||||||
|
if (!isalnum(flag)) {
|
||||||
|
xasprintf(cause, "invalid flag -%c", flag);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
found = strchr(parse->template, flag);
|
||||||
|
if (found == NULL) {
|
||||||
|
xasprintf(cause, "unknown flag -%c", flag);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
if (found[1] != ':') {
|
||||||
|
log_debug("%s: -%c", __func__, flag);
|
||||||
|
args_set(args, flag, NULL, 0);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
optional_argument = (found[2] == ':');
|
||||||
|
return (args_parse_flag_argument(values, count, cause, args, i,
|
||||||
|
string, flag, optional_argument));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Parse arguments into a new argument set. */
|
/* Parse arguments into a new argument set. */
|
||||||
struct args *
|
struct args *
|
||||||
args_parse(const struct args_parse *parse, struct args_value *values,
|
args_parse(const struct args_parse *parse, struct args_value *values,
|
||||||
@ -131,86 +244,21 @@ args_parse(const struct args_parse *parse, struct args_value *values,
|
|||||||
u_int i;
|
u_int i;
|
||||||
enum args_parse_type type;
|
enum args_parse_type type;
|
||||||
struct args_value *value, *new;
|
struct args_value *value, *new;
|
||||||
u_char flag;
|
const char *s;
|
||||||
const char *found, *string, *s;
|
int stop;
|
||||||
int optional_argument;
|
|
||||||
|
|
||||||
if (count == 0)
|
if (count == 0)
|
||||||
return (args_create());
|
return (args_create());
|
||||||
|
|
||||||
args = args_create();
|
args = args_create();
|
||||||
for (i = 1; i < count; /* nothing */) {
|
for (i = 1; i < count; /* nothing */) {
|
||||||
value = &values[i];
|
stop = args_parse_flags(parse, values, count, cause, args, &i);
|
||||||
if (value->type != ARGS_STRING)
|
if (stop == -1) {
|
||||||
break;
|
args_free(args);
|
||||||
|
return (NULL);
|
||||||
string = value->string;
|
|
||||||
if (*string++ != '-' || *string == '\0')
|
|
||||||
break;
|
|
||||||
i++;
|
|
||||||
if (string[0] == '-' && string[1] == '\0')
|
|
||||||
break;
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
flag = *string++;
|
|
||||||
if (flag == '\0')
|
|
||||||
break;
|
|
||||||
if (flag == '?') {
|
|
||||||
args_free(args);
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
if (!isalnum(flag)) {
|
|
||||||
xasprintf(cause, "invalid flag -%c", flag);
|
|
||||||
args_free(args);
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
found = strchr(parse->template, flag);
|
|
||||||
if (found == NULL) {
|
|
||||||
xasprintf(cause, "unknown flag -%c", flag);
|
|
||||||
args_free(args);
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
if (*++found != ':') {
|
|
||||||
log_debug("%s: -%c", __func__, flag);
|
|
||||||
args_set(args, flag, NULL);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (*found == ':') {
|
|
||||||
optional_argument = 1;
|
|
||||||
found++;
|
|
||||||
}
|
|
||||||
new = xcalloc(1, sizeof *new);
|
|
||||||
if (*string != '\0') {
|
|
||||||
new->type = ARGS_STRING;
|
|
||||||
new->string = xstrdup(string);
|
|
||||||
} else {
|
|
||||||
if (i == count) {
|
|
||||||
if (optional_argument) {
|
|
||||||
log_debug("%s: -%c", __func__,
|
|
||||||
flag);
|
|
||||||
args_set(args, flag, NULL);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
xasprintf(cause,
|
|
||||||
"-%c expects an argument",
|
|
||||||
flag);
|
|
||||||
args_free(args);
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
if (values[i].type != ARGS_STRING) {
|
|
||||||
xasprintf(cause,
|
|
||||||
"-%c argument must be a string",
|
|
||||||
flag);
|
|
||||||
args_free(args);
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
args_copy_value(new, &values[i++]);
|
|
||||||
}
|
|
||||||
s = args_value_as_string(new);
|
|
||||||
log_debug("%s: -%c = %s", __func__, flag, s);
|
|
||||||
args_set(args, flag, new);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
if (stop == 1)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
log_debug("%s: flags end at %u of %u", __func__, i, count);
|
log_debug("%s: flags end at %u of %u", __func__, i, count);
|
||||||
if (i != count) {
|
if (i != count) {
|
||||||
@ -218,8 +266,8 @@ args_parse(const struct args_parse *parse, struct args_value *values,
|
|||||||
value = &values[i];
|
value = &values[i];
|
||||||
|
|
||||||
s = args_value_as_string(value);
|
s = args_value_as_string(value);
|
||||||
log_debug("%s: %u = %s (type %d)", __func__, i, s,
|
log_debug("%s: %u = %s (type %s)", __func__, i, s,
|
||||||
value->type);
|
args_type_to_string (value->type));
|
||||||
|
|
||||||
if (parse->cb != NULL) {
|
if (parse->cb != NULL) {
|
||||||
type = parse->cb(args, args->count, cause);
|
type = parse->cb(args, args->count, cause);
|
||||||
@ -323,13 +371,13 @@ args_copy(struct args *args, int argc, char **argv)
|
|||||||
RB_FOREACH(entry, args_tree, &args->tree) {
|
RB_FOREACH(entry, args_tree, &args->tree) {
|
||||||
if (TAILQ_EMPTY(&entry->values)) {
|
if (TAILQ_EMPTY(&entry->values)) {
|
||||||
for (i = 0; i < entry->count; i++)
|
for (i = 0; i < entry->count; i++)
|
||||||
args_set(new_args, entry->flag, NULL);
|
args_set(new_args, entry->flag, NULL, 0);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
TAILQ_FOREACH(value, &entry->values, entry) {
|
TAILQ_FOREACH(value, &entry->values, entry) {
|
||||||
new_value = xcalloc(1, sizeof *new_value);
|
new_value = xcalloc(1, sizeof *new_value);
|
||||||
args_copy_copy_value(new_value, value, argc, argv);
|
args_copy_copy_value(new_value, value, argc, argv);
|
||||||
args_set(new_args, entry->flag, new_value);
|
args_set(new_args, entry->flag, new_value, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (args->count == 0)
|
if (args->count == 0)
|
||||||
@ -487,6 +535,7 @@ args_print(struct args *args)
|
|||||||
char *buf;
|
char *buf;
|
||||||
u_int i, j;
|
u_int i, j;
|
||||||
struct args_entry *entry;
|
struct args_entry *entry;
|
||||||
|
struct args_entry *last = NULL;
|
||||||
struct args_value *value;
|
struct args_value *value;
|
||||||
|
|
||||||
len = 1;
|
len = 1;
|
||||||
@ -494,6 +543,8 @@ args_print(struct args *args)
|
|||||||
|
|
||||||
/* Process the flags first. */
|
/* Process the flags first. */
|
||||||
RB_FOREACH(entry, args_tree, &args->tree) {
|
RB_FOREACH(entry, args_tree, &args->tree) {
|
||||||
|
if (entry->flags & ARGS_ENTRY_OPTIONAL_VALUE)
|
||||||
|
continue;
|
||||||
if (!TAILQ_EMPTY(&entry->values))
|
if (!TAILQ_EMPTY(&entry->values))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -505,6 +556,16 @@ args_print(struct args *args)
|
|||||||
|
|
||||||
/* Then the flags with arguments. */
|
/* Then the flags with arguments. */
|
||||||
RB_FOREACH(entry, args_tree, &args->tree) {
|
RB_FOREACH(entry, args_tree, &args->tree) {
|
||||||
|
if (entry->flags & ARGS_ENTRY_OPTIONAL_VALUE) {
|
||||||
|
if (*buf != '\0')
|
||||||
|
args_print_add(&buf, &len, " -%c", entry->flag);
|
||||||
|
else
|
||||||
|
args_print_add(&buf, &len, "-%c", entry->flag);
|
||||||
|
last = entry;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (TAILQ_EMPTY(&entry->values))
|
||||||
|
continue;
|
||||||
TAILQ_FOREACH(value, &entry->values, entry) {
|
TAILQ_FOREACH(value, &entry->values, entry) {
|
||||||
if (*buf != '\0')
|
if (*buf != '\0')
|
||||||
args_print_add(&buf, &len, " -%c", entry->flag);
|
args_print_add(&buf, &len, " -%c", entry->flag);
|
||||||
@ -512,7 +573,10 @@ args_print(struct args *args)
|
|||||||
args_print_add(&buf, &len, "-%c", entry->flag);
|
args_print_add(&buf, &len, "-%c", entry->flag);
|
||||||
args_print_add_value(&buf, &len, value);
|
args_print_add_value(&buf, &len, value);
|
||||||
}
|
}
|
||||||
|
last = entry;
|
||||||
}
|
}
|
||||||
|
if (last && (last->flags & ARGS_ENTRY_OPTIONAL_VALUE))
|
||||||
|
args_print_add(&buf, &len, " --");
|
||||||
|
|
||||||
/* And finally the argument vector. */
|
/* And finally the argument vector. */
|
||||||
for (i = 0; i < args->count; i++)
|
for (i = 0; i < args->count; i++)
|
||||||
@ -582,7 +646,7 @@ args_has(struct args *args, u_char flag)
|
|||||||
|
|
||||||
/* Set argument value in the arguments tree. */
|
/* Set argument value in the arguments tree. */
|
||||||
void
|
void
|
||||||
args_set(struct args *args, u_char flag, struct args_value *value)
|
args_set(struct args *args, u_char flag, struct args_value *value, int flags)
|
||||||
{
|
{
|
||||||
struct args_entry *entry;
|
struct args_entry *entry;
|
||||||
|
|
||||||
@ -591,6 +655,7 @@ args_set(struct args *args, u_char flag, struct args_value *value)
|
|||||||
entry = xcalloc(1, sizeof *entry);
|
entry = xcalloc(1, sizeof *entry);
|
||||||
entry->flag = flag;
|
entry->flag = flag;
|
||||||
entry->count = 1;
|
entry->count = 1;
|
||||||
|
entry->flags = flags;
|
||||||
TAILQ_INIT(&entry->values);
|
TAILQ_INIT(&entry->values);
|
||||||
RB_INSERT(args_tree, &args->tree, entry);
|
RB_INSERT(args_tree, &args->tree, entry);
|
||||||
} else
|
} else
|
||||||
@ -747,6 +812,8 @@ args_make_commands(struct args_command_state *state, int argc, char **argv,
|
|||||||
}
|
}
|
||||||
|
|
||||||
cmd = xstrdup(state->cmd);
|
cmd = xstrdup(state->cmd);
|
||||||
|
log_debug("%s: %s", __func__, cmd);
|
||||||
|
cmd_log_argv(argc, argv, __func__);
|
||||||
for (i = 0; i < argc; i++) {
|
for (i = 0; i < argc; i++) {
|
||||||
new_cmd = cmd_template_replace(cmd, argv[i], i + 1);
|
new_cmd = cmd_template_replace(cmd, argv[i], i + 1);
|
||||||
log_debug("%s: %%%u %s: %s", __func__, i + 1, argv[i], new_cmd);
|
log_debug("%s: %%%u %s: %s", __func__, i + 1, argv[i], new_cmd);
|
||||||
|
3
client.c
3
client.c
@ -700,6 +700,9 @@ client_dispatch_wait(struct imsg *imsg)
|
|||||||
!(client_flags & CLIENT_CONTROL), client_file_check_cb,
|
!(client_flags & CLIENT_CONTROL), client_file_check_cb,
|
||||||
NULL);
|
NULL);
|
||||||
break;
|
break;
|
||||||
|
case MSG_READ_CANCEL:
|
||||||
|
file_read_cancel(&client_files, imsg);
|
||||||
|
break;
|
||||||
case MSG_WRITE_OPEN:
|
case MSG_WRITE_OPEN:
|
||||||
file_write_open(&client_files, client_peer, imsg, 1,
|
file_write_open(&client_files, client_peer, imsg, 1,
|
||||||
!(client_flags & CLIENT_CONTROL), client_file_check_cb,
|
!(client_flags & CLIENT_CONTROL), client_file_check_cb,
|
||||||
|
@ -115,6 +115,7 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
|
|
||||||
layout_init(w, wp);
|
layout_init(w, wp);
|
||||||
wp->flags |= PANE_CHANGED;
|
wp->flags |= PANE_CHANGED;
|
||||||
|
colour_palette_from_option(&wp->palette, wp->options);
|
||||||
|
|
||||||
if (idx == -1)
|
if (idx == -1)
|
||||||
idx = -1 - options_get_number(dst_s->options, "base-index");
|
idx = -1 - options_get_number(dst_s->options, "base-index");
|
||||||
|
@ -179,10 +179,10 @@ cmd_command_prompt_callback(struct client *c, void *data, const char *s,
|
|||||||
|
|
||||||
if (s == NULL)
|
if (s == NULL)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (done) {
|
if (done) {
|
||||||
if (cdata->flags & PROMPT_INCREMENTAL)
|
if (cdata->flags & PROMPT_INCREMENTAL)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
cmd_append_argv(&cdata->argc, &cdata->argv, s);
|
cmd_append_argv(&cdata->argc, &cdata->argv, s);
|
||||||
if (++cdata->current != cdata->count) {
|
if (++cdata->current != cdata->count) {
|
||||||
prompt = &cdata->prompts[cdata->current];
|
prompt = &cdata->prompts[cdata->current];
|
||||||
@ -193,8 +193,11 @@ cmd_command_prompt_callback(struct client *c, void *data, const char *s,
|
|||||||
|
|
||||||
argc = cdata->argc;
|
argc = cdata->argc;
|
||||||
argv = cmd_copy_argv(cdata->argc, cdata->argv);
|
argv = cmd_copy_argv(cdata->argc, cdata->argv);
|
||||||
cmd_append_argv(&argc, &argv, s);
|
if (!done)
|
||||||
|
cmd_append_argv(&argc, &argv, s);
|
||||||
|
|
||||||
if (done) {
|
if (done) {
|
||||||
|
cmd_free_argv(cdata->argc, cdata->argv);
|
||||||
cdata->argc = argc;
|
cdata->argc = argc;
|
||||||
cdata->argv = cmd_copy_argv(argc, argv);
|
cdata->argv = cmd_copy_argv(argc, argv);
|
||||||
}
|
}
|
||||||
|
@ -38,9 +38,10 @@ const struct cmd_entry cmd_display_menu_entry = {
|
|||||||
.name = "display-menu",
|
.name = "display-menu",
|
||||||
.alias = "menu",
|
.alias = "menu",
|
||||||
|
|
||||||
.args = { "c:t:OT:x:y:", 1, -1, cmd_display_menu_args_parse },
|
.args = { "c:t:S:OT:x:y:", 1, -1, cmd_display_menu_args_parse },
|
||||||
.usage = "[-O] [-c target-client] " CMD_TARGET_PANE_USAGE " [-T title] "
|
.usage = "[-O] [-c target-client] [-S starting-choice] "
|
||||||
"[-x position] [-y position] name key command ...",
|
CMD_TARGET_PANE_USAGE " [-T title] [-x position] "
|
||||||
|
"[-y position] name key command ...",
|
||||||
|
|
||||||
.target = { 't', CMD_FIND_PANE, 0 },
|
.target = { 't', CMD_FIND_PANE, 0 },
|
||||||
|
|
||||||
@ -274,6 +275,7 @@ cmd_display_menu_get_position(struct client *tc, struct cmdq_item *item,
|
|||||||
log_debug("%s: -y: %s = %s = %u (-h %u)", __func__, yp, p, *py, h);
|
log_debug("%s: -y: %s = %s = %u (-h %u)", __func__, yp, p, *py, h);
|
||||||
free(p);
|
free(p);
|
||||||
|
|
||||||
|
format_free(ft);
|
||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -287,13 +289,27 @@ cmd_display_menu_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
struct menu *menu = NULL;
|
struct menu *menu = NULL;
|
||||||
struct menu_item menu_item;
|
struct menu_item menu_item;
|
||||||
const char *key, *name;
|
const char *key, *name;
|
||||||
char *title;
|
char *title, *cause;
|
||||||
int flags = 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);
|
||||||
|
|
||||||
if (tc->overlay_draw != NULL)
|
if (tc->overlay_draw != NULL)
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
|
|
||||||
|
if (args_has(args, 'S')) {
|
||||||
|
if (strcmp(args_get(args, 'S'), "-") == 0)
|
||||||
|
starting_choice = -1;
|
||||||
|
else {
|
||||||
|
starting_choice = args_strtonum(args, 'S', 0, UINT_MAX,
|
||||||
|
&cause);
|
||||||
|
if (cause != NULL) {
|
||||||
|
cmdq_error(item, "starting choice %s", cause);
|
||||||
|
free(cause);
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (args_has(args, 'T'))
|
if (args_has(args, 'T'))
|
||||||
title = format_single_from_target(item, args_get(args, 'T'));
|
title = format_single_from_target(item, args_get(args, 'T'));
|
||||||
else
|
else
|
||||||
@ -340,8 +356,8 @@ cmd_display_menu_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
flags |= MENU_STAYOPEN;
|
flags |= MENU_STAYOPEN;
|
||||||
if (!event->m.valid)
|
if (!event->m.valid)
|
||||||
flags |= MENU_NOMOUSE;
|
flags |= MENU_NOMOUSE;
|
||||||
if (menu_display(menu, flags, item, px, py, tc, target, NULL,
|
if (menu_display(menu, flags, starting_choice, item, px, py, tc, target,
|
||||||
NULL) != 0)
|
NULL, NULL) != 0)
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
return (CMD_RETURN_WAIT);
|
return (CMD_RETURN_WAIT);
|
||||||
}
|
}
|
||||||
@ -454,11 +470,13 @@ cmd_display_popup_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
cmd_free_argv(argc, argv);
|
cmd_free_argv(argc, argv);
|
||||||
if (env != NULL)
|
if (env != NULL)
|
||||||
environ_free(env);
|
environ_free(env);
|
||||||
|
free(cwd);
|
||||||
free(title);
|
free(title);
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
}
|
}
|
||||||
if (env != NULL)
|
if (env != NULL)
|
||||||
environ_free(env);
|
environ_free(env);
|
||||||
|
free(cwd);
|
||||||
free(title);
|
free(title);
|
||||||
cmd_free_argv(argc, argv);
|
cmd_free_argv(argc, argv);
|
||||||
return (CMD_RETURN_WAIT);
|
return (CMD_RETURN_WAIT);
|
||||||
|
@ -68,9 +68,10 @@ cmd_display_message_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
struct window_pane *wp = target->wp;
|
struct window_pane *wp = target->wp;
|
||||||
const char *template;
|
const char *template;
|
||||||
char *msg, *cause;
|
char *msg, *cause;
|
||||||
int delay = -1, flags;
|
int delay = -1, flags, Nflag = args_has(args, 'N');
|
||||||
struct format_tree *ft;
|
struct format_tree *ft;
|
||||||
u_int count = args_count(args);
|
u_int count = args_count(args);
|
||||||
|
struct evbuffer *evb;
|
||||||
|
|
||||||
if (args_has(args, 'I')) {
|
if (args_has(args, 'I')) {
|
||||||
if (wp == NULL)
|
if (wp == NULL)
|
||||||
@ -141,10 +142,15 @@ cmd_display_message_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
cmdq_error(item, "%s", msg);
|
cmdq_error(item, "%s", msg);
|
||||||
else if (args_has(args, 'p'))
|
else if (args_has(args, 'p'))
|
||||||
cmdq_print(item, "%s", msg);
|
cmdq_print(item, "%s", msg);
|
||||||
else if (tc != NULL) {
|
else if (tc != NULL && (tc->flags & CLIENT_CONTROL)) {
|
||||||
status_message_set(tc, delay, 0, args_has(args, 'N'), "%s",
|
evb = evbuffer_new();
|
||||||
msg);
|
if (evb == NULL)
|
||||||
}
|
fatalx("out of memory");
|
||||||
|
evbuffer_add_printf(evb, "%%message %s", msg);
|
||||||
|
server_client_print(tc, 0, evb);
|
||||||
|
evbuffer_free(evb);
|
||||||
|
} else if (tc != NULL)
|
||||||
|
status_message_set(tc, delay, 0, Nflag, "%s", msg);
|
||||||
free(msg);
|
free(msg);
|
||||||
|
|
||||||
format_free(ft);
|
format_free(ft);
|
||||||
|
@ -103,8 +103,8 @@ cmd_find_window_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
|
|
||||||
new_args = args_create();
|
new_args = args_create();
|
||||||
if (args_has(args, 'Z'))
|
if (args_has(args, 'Z'))
|
||||||
args_set(new_args, 'Z', NULL);
|
args_set(new_args, 'Z', NULL, 0);
|
||||||
args_set(new_args, 'f', filter);
|
args_set(new_args, 'f', filter, 0);
|
||||||
|
|
||||||
window_pane_set_mode(wp, NULL, &window_tree_mode, target, new_args);
|
window_pane_set_mode(wp, NULL, &window_tree_mode, target, new_args);
|
||||||
args_free(new_args);
|
args_free(new_args);
|
||||||
|
@ -155,6 +155,7 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
else
|
else
|
||||||
TAILQ_INSERT_AFTER(&dst_w->panes, dst_wp, src_wp, entry);
|
TAILQ_INSERT_AFTER(&dst_w->panes, dst_wp, src_wp, entry);
|
||||||
layout_assign_pane(lc, src_wp, 0);
|
layout_assign_pane(lc, src_wp, 0);
|
||||||
|
colour_palette_from_option(&src_wp->palette, src_wp->options);
|
||||||
|
|
||||||
recalculate_sizes();
|
recalculate_sizes();
|
||||||
|
|
||||||
|
@ -41,8 +41,8 @@ const struct cmd_entry cmd_list_clients_entry = {
|
|||||||
.name = "list-clients",
|
.name = "list-clients",
|
||||||
.alias = "lsc",
|
.alias = "lsc",
|
||||||
|
|
||||||
.args = { "F:t:", 0, 0, NULL },
|
.args = { "F:f:t:", 0, 0, NULL },
|
||||||
.usage = "[-F format] " CMD_TARGET_SESSION_USAGE,
|
.usage = "[-F format] [-f filter] " CMD_TARGET_SESSION_USAGE,
|
||||||
|
|
||||||
.target = { 't', CMD_FIND_SESSION, 0 },
|
.target = { 't', CMD_FIND_SESSION, 0 },
|
||||||
|
|
||||||
@ -58,9 +58,10 @@ cmd_list_clients_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
struct client *c;
|
struct client *c;
|
||||||
struct session *s;
|
struct session *s;
|
||||||
struct format_tree *ft;
|
struct format_tree *ft;
|
||||||
const char *template;
|
const char *template, *filter;
|
||||||
u_int idx;
|
u_int idx;
|
||||||
char *line;
|
char *line, *expanded;
|
||||||
|
int flag;
|
||||||
|
|
||||||
if (args_has(args, 't'))
|
if (args_has(args, 't'))
|
||||||
s = target->s;
|
s = target->s;
|
||||||
@ -69,6 +70,7 @@ cmd_list_clients_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
|
|
||||||
if ((template = args_get(args, 'F')) == NULL)
|
if ((template = args_get(args, 'F')) == NULL)
|
||||||
template = LIST_CLIENTS_TEMPLATE;
|
template = LIST_CLIENTS_TEMPLATE;
|
||||||
|
filter = args_get(args, 'f');
|
||||||
|
|
||||||
idx = 0;
|
idx = 0;
|
||||||
TAILQ_FOREACH(c, &clients, entry) {
|
TAILQ_FOREACH(c, &clients, entry) {
|
||||||
@ -79,9 +81,17 @@ cmd_list_clients_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
format_add(ft, "line", "%u", idx);
|
format_add(ft, "line", "%u", idx);
|
||||||
format_defaults(ft, c, NULL, NULL, NULL);
|
format_defaults(ft, c, NULL, NULL, NULL);
|
||||||
|
|
||||||
line = format_expand(ft, template);
|
if (filter != NULL) {
|
||||||
cmdq_print(item, "%s", line);
|
expanded = format_expand(ft, filter);
|
||||||
free(line);
|
flag = format_true(expanded);
|
||||||
|
free(expanded);
|
||||||
|
} else
|
||||||
|
flag = 1;
|
||||||
|
if (flag) {
|
||||||
|
line = format_expand(ft, template);
|
||||||
|
cmdq_print(item, "%s", line);
|
||||||
|
free(line);
|
||||||
|
}
|
||||||
|
|
||||||
format_free(ft);
|
format_free(ft);
|
||||||
|
|
||||||
|
@ -148,6 +148,7 @@ static enum cmd_retval
|
|||||||
cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
|
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 key_table *table;
|
struct key_table *table;
|
||||||
struct key_binding *bd;
|
struct key_binding *bd;
|
||||||
const char *tablename, *r, *keystr;
|
const char *tablename, *r, *keystr;
|
||||||
@ -296,9 +297,15 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
strlcat(tmp, cp, tmpsize);
|
strlcat(tmp, cp, tmpsize);
|
||||||
free(cp);
|
free(cp);
|
||||||
|
|
||||||
cmdq_print(item, "bind-key %s", tmp);
|
if (args_has(args, '1') && tc != NULL) {
|
||||||
|
status_message_set(tc, -1, 1, 0, "bind-key %s",
|
||||||
|
tmp);
|
||||||
|
} else
|
||||||
|
cmdq_print(item, "bind-key %s", tmp);
|
||||||
free(key);
|
free(key);
|
||||||
|
|
||||||
|
if (args_has(args, '1'))
|
||||||
|
break;
|
||||||
bd = key_bindings_next(table, bd);
|
bd = key_bindings_next(table, bd);
|
||||||
}
|
}
|
||||||
table = key_bindings_next_table(table);
|
table = key_bindings_next_table(table);
|
||||||
|
17
cmd-parse.y
17
cmd-parse.y
@ -1615,13 +1615,24 @@ yylex_token(int ch)
|
|||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
/* EOF or \n are always the end of the token. */
|
/* EOF or \n are always the end of the token. */
|
||||||
if (ch == EOF || (state == NONE && ch == '\n'))
|
if (ch == EOF) {
|
||||||
|
log_debug("%s: end at EOF", __func__);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
if (state == NONE && ch == '\n') {
|
||||||
|
log_debug("%s: end at EOL", __func__);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* Whitespace or ; or } ends a token unless inside quotes. */
|
/* Whitespace or ; or } ends a token unless inside quotes. */
|
||||||
if ((ch == ' ' || ch == '\t' || ch == ';' || ch == '}') &&
|
if (state == NONE && (ch == ' ' || ch == '\t')) {
|
||||||
state == NONE)
|
log_debug("%s: end at WS", __func__);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
if (state == NONE && (ch == ';' || ch == '}')) {
|
||||||
|
log_debug("%s: end at %c", __func__, ch);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Spaces and comments inside quotes after \n are removed but
|
* Spaces and comments inside quotes after \n are removed but
|
||||||
|
47
cmd-queue.c
47
cmd-queue.c
@ -821,45 +821,30 @@ cmdq_guard(struct cmdq_item *item, const char *guard, int flags)
|
|||||||
control_write(c, "%%%s %ld %u %d", guard, t, number, flags);
|
control_write(c, "%%%s %ld %u %d", guard, t, number, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Show message from command. */
|
||||||
|
void
|
||||||
|
cmdq_print_data(struct cmdq_item *item, int parse, struct evbuffer *evb)
|
||||||
|
{
|
||||||
|
server_client_print(item->client, parse, evb);
|
||||||
|
}
|
||||||
|
|
||||||
/* Show message from command. */
|
/* Show message from command. */
|
||||||
void
|
void
|
||||||
cmdq_print(struct cmdq_item *item, const char *fmt, ...)
|
cmdq_print(struct cmdq_item *item, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
struct client *c = item->client;
|
va_list ap;
|
||||||
struct window_pane *wp;
|
struct evbuffer *evb;
|
||||||
struct window_mode_entry *wme;
|
|
||||||
va_list ap;
|
evb = evbuffer_new();
|
||||||
char *tmp, *msg;
|
if (evb == NULL)
|
||||||
|
fatalx("out of memory");
|
||||||
|
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
xvasprintf(&msg, fmt, ap);
|
evbuffer_add_vprintf(evb, fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
log_debug("%s: %s", __func__, msg);
|
cmdq_print_data(item, 0, evb);
|
||||||
|
evbuffer_free(evb);
|
||||||
if (c == NULL)
|
|
||||||
/* nothing */;
|
|
||||||
else if (c->session == NULL || (c->flags & CLIENT_CONTROL)) {
|
|
||||||
if (~c->flags & CLIENT_UTF8) {
|
|
||||||
tmp = msg;
|
|
||||||
msg = utf8_sanitize(tmp);
|
|
||||||
free(tmp);
|
|
||||||
}
|
|
||||||
if (c->flags & CLIENT_CONTROL)
|
|
||||||
control_write(c, "%s", msg);
|
|
||||||
else
|
|
||||||
file_print(c, "%s\n", msg);
|
|
||||||
} else {
|
|
||||||
wp = server_client_get_pane(c);
|
|
||||||
wme = TAILQ_FIRST(&wp->modes);
|
|
||||||
if (wme == NULL || wme->mode != &window_view_mode) {
|
|
||||||
window_pane_set_mode(wp, NULL, &window_view_mode, NULL,
|
|
||||||
NULL);
|
|
||||||
}
|
|
||||||
window_copy_add(wp, 0, "%s", msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(msg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Show error from command. */
|
/* Show error from command. */
|
||||||
|
@ -78,7 +78,8 @@ cmd_save_buffer_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
int flags;
|
int flags;
|
||||||
const char *bufname = args_get(args, 'b'), *bufdata;
|
const char *bufname = args_get(args, 'b'), *bufdata;
|
||||||
size_t bufsize;
|
size_t bufsize;
|
||||||
char *path, *tmp;
|
char *path;
|
||||||
|
struct evbuffer *evb;
|
||||||
|
|
||||||
if (bufname == NULL) {
|
if (bufname == NULL) {
|
||||||
if ((pb = paste_get_top(NULL)) == NULL) {
|
if ((pb = paste_get_top(NULL)) == NULL) {
|
||||||
@ -96,10 +97,12 @@ cmd_save_buffer_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
|
|
||||||
if (cmd_get_entry(self) == &cmd_show_buffer_entry) {
|
if (cmd_get_entry(self) == &cmd_show_buffer_entry) {
|
||||||
if (c->session != NULL || (c->flags & CLIENT_CONTROL)) {
|
if (c->session != NULL || (c->flags & CLIENT_CONTROL)) {
|
||||||
utf8_stravisx(&tmp, bufdata, bufsize,
|
evb = evbuffer_new();
|
||||||
VIS_OCTAL|VIS_CSTYLE|VIS_TAB);
|
if (evb == NULL)
|
||||||
cmdq_print(item, "%s", tmp);
|
fatalx("out of memory");
|
||||||
free(tmp);
|
evbuffer_add(evb, bufdata, bufsize);
|
||||||
|
cmdq_print_data(item, 1, evb);
|
||||||
|
evbuffer_free(evb);
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
}
|
}
|
||||||
path = xstrdup("-");
|
path = xstrdup("-");
|
||||||
|
@ -33,13 +33,13 @@ const struct cmd_entry cmd_send_keys_entry = {
|
|||||||
.name = "send-keys",
|
.name = "send-keys",
|
||||||
.alias = "send",
|
.alias = "send",
|
||||||
|
|
||||||
.args = { "FHlMN:Rt:X", 0, -1, NULL },
|
.args = { "c:FHKlMN:Rt:X", 0, -1, NULL },
|
||||||
.usage = "[-FHlMRX] [-N repeat-count] " CMD_TARGET_PANE_USAGE
|
.usage = "[-FHKlMRX] [-c target-client] [-N repeat-count] "
|
||||||
" key ...",
|
CMD_TARGET_PANE_USAGE " key ...",
|
||||||
|
|
||||||
.target = { 't', CMD_FIND_PANE, 0 },
|
.target = { 't', CMD_FIND_PANE, 0 },
|
||||||
|
|
||||||
.flags = CMD_AFTERHOOK,
|
.flags = CMD_AFTERHOOK|CMD_CLIENT_CFLAG|CMD_CLIENT_CANFAIL,
|
||||||
.exec = cmd_send_keys_exec
|
.exec = cmd_send_keys_exec
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -58,7 +58,7 @@ const struct cmd_entry cmd_send_prefix_entry = {
|
|||||||
|
|
||||||
static struct cmdq_item *
|
static struct cmdq_item *
|
||||||
cmd_send_keys_inject_key(struct cmdq_item *item, struct cmdq_item *after,
|
cmd_send_keys_inject_key(struct cmdq_item *item, struct cmdq_item *after,
|
||||||
key_code key)
|
struct args *args, key_code key)
|
||||||
{
|
{
|
||||||
struct cmd_find_state *target = cmdq_get_target(item);
|
struct cmd_find_state *target = cmdq_get_target(item);
|
||||||
struct client *tc = cmdq_get_target_client(item);
|
struct client *tc = cmdq_get_target_client(item);
|
||||||
@ -66,8 +66,20 @@ cmd_send_keys_inject_key(struct cmdq_item *item, struct cmdq_item *after,
|
|||||||
struct winlink *wl = target->wl;
|
struct winlink *wl = target->wl;
|
||||||
struct window_pane *wp = target->wp;
|
struct window_pane *wp = target->wp;
|
||||||
struct window_mode_entry *wme;
|
struct window_mode_entry *wme;
|
||||||
struct key_table *table;
|
struct key_table *table = NULL;
|
||||||
struct key_binding *bd;
|
struct key_binding *bd;
|
||||||
|
struct key_event *event;
|
||||||
|
|
||||||
|
if (args_has(args, 'K')) {
|
||||||
|
if (tc == NULL)
|
||||||
|
return (item);
|
||||||
|
event = xmalloc(sizeof *event);
|
||||||
|
event->key = key|KEYC_SENT;
|
||||||
|
memset(&event->m, 0, sizeof event->m);
|
||||||
|
if (server_client_handle_key(tc, event) == 0)
|
||||||
|
free(event);
|
||||||
|
return (item);
|
||||||
|
}
|
||||||
|
|
||||||
wme = TAILQ_FIRST(&wp->modes);
|
wme = TAILQ_FIRST(&wp->modes);
|
||||||
if (wme == NULL || wme->mode->key_table == NULL) {
|
if (wme == NULL || wme->mode->key_table == NULL) {
|
||||||
@ -102,14 +114,16 @@ cmd_send_keys_inject_string(struct cmdq_item *item, struct cmdq_item *after,
|
|||||||
n = strtol(s, &endptr, 16);
|
n = strtol(s, &endptr, 16);
|
||||||
if (*s =='\0' || n < 0 || n > 0xff || *endptr != '\0')
|
if (*s =='\0' || n < 0 || n > 0xff || *endptr != '\0')
|
||||||
return (item);
|
return (item);
|
||||||
return (cmd_send_keys_inject_key(item, after, KEYC_LITERAL|n));
|
return (cmd_send_keys_inject_key(item, after, args,
|
||||||
|
KEYC_LITERAL|n));
|
||||||
}
|
}
|
||||||
|
|
||||||
literal = args_has(args, 'l');
|
literal = args_has(args, 'l');
|
||||||
if (!literal) {
|
if (!literal) {
|
||||||
key = key_string_lookup_string(s);
|
key = key_string_lookup_string(s);
|
||||||
if (key != KEYC_NONE && key != KEYC_UNKNOWN) {
|
if (key != KEYC_NONE && key != KEYC_UNKNOWN) {
|
||||||
after = cmd_send_keys_inject_key(item, after, key);
|
after = cmd_send_keys_inject_key(item, after, args,
|
||||||
|
key);
|
||||||
if (after != NULL)
|
if (after != NULL)
|
||||||
return (after);
|
return (after);
|
||||||
}
|
}
|
||||||
@ -125,7 +139,8 @@ cmd_send_keys_inject_string(struct cmdq_item *item, struct cmdq_item *after,
|
|||||||
continue;
|
continue;
|
||||||
key = uc;
|
key = uc;
|
||||||
}
|
}
|
||||||
after = cmd_send_keys_inject_key(item, after, key);
|
after = cmd_send_keys_inject_key(item, after, args,
|
||||||
|
key);
|
||||||
}
|
}
|
||||||
free(ud);
|
free(ud);
|
||||||
}
|
}
|
||||||
@ -193,7 +208,7 @@ cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
key = options_get_number(s->options, "prefix2");
|
key = options_get_number(s->options, "prefix2");
|
||||||
else
|
else
|
||||||
key = options_get_number(s->options, "prefix");
|
key = options_get_number(s->options, "prefix");
|
||||||
cmd_send_keys_inject_key(item, item, key);
|
cmd_send_keys_inject_key(item, item, args, key);
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -207,7 +222,7 @@ cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
if (args_has(args, 'N') || args_has(args, 'R'))
|
if (args_has(args, 'N') || args_has(args, 'R'))
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
for (; np != 0; np--)
|
for (; np != 0; np--)
|
||||||
cmd_send_keys_inject_key(item, NULL, event->key);
|
cmd_send_keys_inject_key(item, NULL, args, event->key);
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,6 +132,8 @@ cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
src_w->last = NULL;
|
src_w->last = NULL;
|
||||||
if (dst_w->last == dst_wp)
|
if (dst_w->last == dst_wp)
|
||||||
dst_w->last = NULL;
|
dst_w->last = NULL;
|
||||||
|
colour_palette_from_option(&src_wp->palette, src_wp->options);
|
||||||
|
colour_palette_from_option(&dst_wp->palette, dst_wp->options);
|
||||||
}
|
}
|
||||||
server_redraw_window(src_w);
|
server_redraw_window(src_w);
|
||||||
server_redraw_window(dst_w);
|
server_redraw_window(dst_w);
|
||||||
|
42
colour.c
42
colour.c
@ -960,6 +960,47 @@ colour_byname(const char *name)
|
|||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Parse colour from an X11 string. */
|
||||||
|
int
|
||||||
|
colour_parseX11(const char *p)
|
||||||
|
{
|
||||||
|
double c, m, y, k = 0;
|
||||||
|
u_int r, g, b;
|
||||||
|
size_t len = strlen(p);
|
||||||
|
int colour = -1;
|
||||||
|
char *copy;
|
||||||
|
|
||||||
|
if ((len == 12 && sscanf(p, "rgb:%02x/%02x/%02x", &r, &g, &b) == 3) ||
|
||||||
|
(len == 7 && sscanf(p, "#%02x%02x%02x", &r, &g, &b) == 3) ||
|
||||||
|
sscanf(p, "%d,%d,%d", &r, &g, &b) == 3)
|
||||||
|
colour = colour_join_rgb(r, g, b);
|
||||||
|
else if ((len == 18 &&
|
||||||
|
sscanf(p, "rgb:%04x/%04x/%04x", &r, &g, &b) == 3) ||
|
||||||
|
(len == 13 && sscanf(p, "#%04x%04x%04x", &r, &g, &b) == 3))
|
||||||
|
colour = colour_join_rgb(r >> 8, g >> 8, b >> 8);
|
||||||
|
else if ((sscanf(p, "cmyk:%lf/%lf/%lf/%lf", &c, &m, &y, &k) == 4 ||
|
||||||
|
sscanf(p, "cmy:%lf/%lf/%lf", &c, &m, &y) == 3) &&
|
||||||
|
c >= 0 && c <= 1 && m >= 0 && m <= 1 &&
|
||||||
|
y >= 0 && y <= 1 && k >= 0 && k <= 1) {
|
||||||
|
colour = colour_join_rgb(
|
||||||
|
(1 - c) * (1 - k) * 255,
|
||||||
|
(1 - m) * (1 - k) * 255,
|
||||||
|
(1 - y) * (1 - k) * 255);
|
||||||
|
} else {
|
||||||
|
while (len != 0 && *p == ' ') {
|
||||||
|
p++;
|
||||||
|
len--;
|
||||||
|
}
|
||||||
|
while (len != 0 && p[len - 1] == ' ')
|
||||||
|
len--;
|
||||||
|
copy = xstrndup(p, len);
|
||||||
|
colour = colour_byname(copy);
|
||||||
|
free(copy);
|
||||||
|
}
|
||||||
|
log_debug("%s: %s = %s", __func__, p, colour_tostring(colour));
|
||||||
|
return (colour);
|
||||||
|
}
|
||||||
|
|
||||||
/* Initialize palette. */
|
/* Initialize palette. */
|
||||||
void
|
void
|
||||||
colour_palette_init(struct colour_palette *p)
|
colour_palette_init(struct colour_palette *p)
|
||||||
@ -1069,5 +1110,4 @@ colour_palette_from_option(struct colour_palette *p, struct options *oo)
|
|||||||
}
|
}
|
||||||
a = options_array_next(a);
|
a = options_array_next(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
44
file.c
44
file.c
@ -149,7 +149,8 @@ file_fire_done_cb(__unused int fd, __unused short events, void *arg)
|
|||||||
struct client_file *cf = arg;
|
struct client_file *cf = arg;
|
||||||
struct client *c = cf->c;
|
struct client *c = cf->c;
|
||||||
|
|
||||||
if (cf->cb != NULL && (c == NULL || (~c->flags & CLIENT_DEAD)))
|
if (cf->cb != NULL &&
|
||||||
|
(cf->closed || c == NULL || (~c->flags & CLIENT_DEAD)))
|
||||||
cf->cb(c, cf->path, cf->error, 1, cf->buffer, cf->data);
|
cf->cb(c, cf->path, cf->error, 1, cf->buffer, cf->data);
|
||||||
file_free(cf);
|
file_free(cf);
|
||||||
}
|
}
|
||||||
@ -352,7 +353,7 @@ done:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Read a file. */
|
/* Read a file. */
|
||||||
void
|
struct client_file *
|
||||||
file_read(struct client *c, const char *path, client_file_cb cb, void *cbdata)
|
file_read(struct client *c, const char *path, client_file_cb cb, void *cbdata)
|
||||||
{
|
{
|
||||||
struct client_file *cf;
|
struct client_file *cf;
|
||||||
@ -420,10 +421,27 @@ skip:
|
|||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
free(msg);
|
free(msg);
|
||||||
return;
|
return cf;
|
||||||
|
|
||||||
done:
|
done:
|
||||||
file_fire_done(cf);
|
file_fire_done(cf);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Cancel a file read. */
|
||||||
|
void
|
||||||
|
file_cancel(struct client_file *cf)
|
||||||
|
{
|
||||||
|
struct msg_read_cancel msg;
|
||||||
|
|
||||||
|
log_debug("read cancel file %d", cf->stream);
|
||||||
|
|
||||||
|
if (cf->closed)
|
||||||
|
return;
|
||||||
|
cf->closed = 1;
|
||||||
|
|
||||||
|
msg.stream = cf->stream;
|
||||||
|
proc_send(cf->peer, MSG_READ_CANCEL, -1, &msg, sizeof msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Push event, fired if there is more writing to be done. */
|
/* Push event, fired if there is more writing to be done. */
|
||||||
@ -757,6 +775,24 @@ reply:
|
|||||||
proc_send(peer, MSG_READ_DONE, -1, &reply, sizeof reply);
|
proc_send(peer, MSG_READ_DONE, -1, &reply, sizeof reply);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Handle a read cancel message (client). */
|
||||||
|
void
|
||||||
|
file_read_cancel(struct client_files *files, struct imsg *imsg)
|
||||||
|
{
|
||||||
|
struct msg_read_cancel *msg = imsg->data;
|
||||||
|
size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE;
|
||||||
|
struct client_file find, *cf;
|
||||||
|
|
||||||
|
if (msglen != sizeof *msg)
|
||||||
|
fatalx("bad MSG_READ_CANCEL size");
|
||||||
|
find.stream = msg->stream;
|
||||||
|
if ((cf = RB_FIND(client_files, files, &find)) == NULL)
|
||||||
|
fatalx("unknown stream number");
|
||||||
|
log_debug("cancel file %d", cf->stream);
|
||||||
|
|
||||||
|
file_read_error_callback(NULL, 0, cf);
|
||||||
|
}
|
||||||
|
|
||||||
/* Handle a write ready message (server). */
|
/* Handle a write ready message (server). */
|
||||||
void
|
void
|
||||||
file_write_ready(struct client_files *files, struct imsg *imsg)
|
file_write_ready(struct client_files *files, struct imsg *imsg)
|
||||||
@ -794,7 +830,7 @@ file_read_data(struct client_files *files, struct imsg *imsg)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
log_debug("file %d read %zu bytes", cf->stream, bsize);
|
log_debug("file %d read %zu bytes", cf->stream, bsize);
|
||||||
if (cf->error == 0) {
|
if (cf->error == 0 && !cf->closed) {
|
||||||
if (evbuffer_add(cf->buffer, bdata, bsize) != 0) {
|
if (evbuffer_add(cf->buffer, bdata, bsize) != 0) {
|
||||||
cf->error = ENOMEM;
|
cf->error = ENOMEM;
|
||||||
file_fire_done(cf);
|
file_fire_done(cf);
|
||||||
|
44
format.c
44
format.c
@ -103,6 +103,7 @@ format_job_cmp(struct format_job *fj1, struct format_job *fj2)
|
|||||||
#define FORMAT_SESSION_NAME 0x8000
|
#define FORMAT_SESSION_NAME 0x8000
|
||||||
#define FORMAT_CHARACTER 0x10000
|
#define FORMAT_CHARACTER 0x10000
|
||||||
#define FORMAT_COLOUR 0x20000
|
#define FORMAT_COLOUR 0x20000
|
||||||
|
#define FORMAT_CLIENTS 0x40000
|
||||||
|
|
||||||
/* Limit on recursion. */
|
/* Limit on recursion. */
|
||||||
#define FORMAT_LOOP_LIMIT 100
|
#define FORMAT_LOOP_LIMIT 100
|
||||||
@ -3747,7 +3748,7 @@ format_build_modifiers(struct format_expand_state *es, const char **s,
|
|||||||
cp++;
|
cp++;
|
||||||
|
|
||||||
/* Check single character modifiers with no arguments. */
|
/* Check single character modifiers with no arguments. */
|
||||||
if (strchr("labcdnwETSWP<>", cp[0]) != NULL &&
|
if (strchr("labcdnwETSWPL<>", cp[0]) != NULL &&
|
||||||
format_is_end(cp[1])) {
|
format_is_end(cp[1])) {
|
||||||
format_add_modifier(&list, count, cp, 1, NULL, 0);
|
format_add_modifier(&list, count, cp, 1, NULL, 0);
|
||||||
cp++;
|
cp++;
|
||||||
@ -4075,6 +4076,40 @@ format_loop_panes(struct format_expand_state *es, const char *fmt)
|
|||||||
return (value);
|
return (value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Loop over clients. */
|
||||||
|
static char *
|
||||||
|
format_loop_clients(struct format_expand_state *es, const char *fmt)
|
||||||
|
{
|
||||||
|
struct format_tree *ft = es->ft;
|
||||||
|
struct client *c = ft->client;
|
||||||
|
struct cmdq_item *item = ft->item;
|
||||||
|
struct format_tree *nft;
|
||||||
|
struct format_expand_state next;
|
||||||
|
char *expanded, *value;
|
||||||
|
size_t valuelen;
|
||||||
|
|
||||||
|
value = xcalloc(1, 1);
|
||||||
|
valuelen = 1;
|
||||||
|
|
||||||
|
TAILQ_FOREACH(c, &clients, entry) {
|
||||||
|
format_log(es, "client loop: %s", c->name);
|
||||||
|
nft = format_create(c, item, 0, ft->flags);
|
||||||
|
format_defaults(nft, c, ft->s, ft->wl, ft->wp);
|
||||||
|
format_copy_state(&next, es, 0);
|
||||||
|
next.ft = nft;
|
||||||
|
expanded = format_expand1(&next, fmt);
|
||||||
|
format_free(nft);
|
||||||
|
|
||||||
|
valuelen += strlen(expanded);
|
||||||
|
value = xrealloc(value, valuelen);
|
||||||
|
|
||||||
|
strlcat(value, expanded, valuelen);
|
||||||
|
free(expanded);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (value);
|
||||||
|
}
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
format_replace_expression(struct format_modifier *mexp,
|
format_replace_expression(struct format_modifier *mexp,
|
||||||
struct format_expand_state *es, const char *copy)
|
struct format_expand_state *es, const char *copy)
|
||||||
@ -4349,6 +4384,9 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
|
|||||||
case 'P':
|
case 'P':
|
||||||
modifiers |= FORMAT_PANES;
|
modifiers |= FORMAT_PANES;
|
||||||
break;
|
break;
|
||||||
|
case 'L':
|
||||||
|
modifiers |= FORMAT_CLIENTS;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} else if (fm->size == 2) {
|
} else if (fm->size == 2) {
|
||||||
if (strcmp(fm->modifier, "||") == 0 ||
|
if (strcmp(fm->modifier, "||") == 0 ||
|
||||||
@ -4405,6 +4443,10 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
|
|||||||
value = format_loop_panes(es, copy);
|
value = format_loop_panes(es, copy);
|
||||||
if (value == NULL)
|
if (value == NULL)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
} else if (modifiers & FORMAT_CLIENTS) {
|
||||||
|
value = format_loop_clients(es, copy);
|
||||||
|
if (value == NULL)
|
||||||
|
goto fail;
|
||||||
} else if (modifiers & FORMAT_WINDOW_NAME) {
|
} else if (modifiers & FORMAT_WINDOW_NAME) {
|
||||||
value = format_window_name(es, copy);
|
value = format_window_name(es, copy);
|
||||||
if (value == NULL)
|
if (value == NULL)
|
||||||
|
@ -496,6 +496,9 @@ input_key(struct screen *s, struct bufferevent *bev, key_code key)
|
|||||||
ike = input_key_get(key & ~KEYC_EXTENDED);
|
ike = input_key_get(key & ~KEYC_EXTENDED);
|
||||||
if (ike != NULL) {
|
if (ike != NULL) {
|
||||||
log_debug("found key 0x%llx: \"%s\"", key, ike->data);
|
log_debug("found key 0x%llx: \"%s\"", key, ike->data);
|
||||||
|
if ((key == KEYC_PASTE_START || key == KEYC_PASTE_END) &&
|
||||||
|
(~s->mode & MODE_BRACKETPASTE))
|
||||||
|
return (0);
|
||||||
if ((key & KEYC_META) && (~key & KEYC_IMPLIED_META))
|
if ((key & KEYC_META) && (~key & KEYC_IMPLIED_META))
|
||||||
input_key_write(__func__, bev, "\033", 1);
|
input_key_write(__func__, bev, "\033", 1);
|
||||||
input_key_write(__func__, bev, ike->data, strlen(ike->data));
|
input_key_write(__func__, bev, ike->data, strlen(ike->data));
|
||||||
|
115
input.c
115
input.c
@ -1086,6 +1086,7 @@ input_reply(struct input_ctx *ictx, const char *fmt, ...)
|
|||||||
xvasprintf(&reply, fmt, ap);
|
xvasprintf(&reply, fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
|
log_debug("%s: %s", __func__, reply);
|
||||||
bufferevent_write(bev, reply, strlen(reply));
|
bufferevent_write(bev, reply, strlen(reply));
|
||||||
free(reply);
|
free(reply);
|
||||||
}
|
}
|
||||||
@ -2466,47 +2467,6 @@ input_top_bit_set(struct input_ctx *ictx)
|
|||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Parse colour from OSC. */
|
|
||||||
static int
|
|
||||||
input_osc_parse_colour(const char *p)
|
|
||||||
{
|
|
||||||
double c, m, y, k = 0;
|
|
||||||
u_int r, g, b;
|
|
||||||
size_t len = strlen(p);
|
|
||||||
int colour = -1;
|
|
||||||
char *copy;
|
|
||||||
|
|
||||||
if ((len == 12 && sscanf(p, "rgb:%02x/%02x/%02x", &r, &g, &b) == 3) ||
|
|
||||||
(len == 7 && sscanf(p, "#%02x%02x%02x", &r, &g, &b) == 3) ||
|
|
||||||
sscanf(p, "%d,%d,%d", &r, &g, &b) == 3)
|
|
||||||
colour = colour_join_rgb(r, g, b);
|
|
||||||
else if ((len == 18 &&
|
|
||||||
sscanf(p, "rgb:%04x/%04x/%04x", &r, &g, &b) == 3) ||
|
|
||||||
(len == 13 && sscanf(p, "#%04x%04x%04x", &r, &g, &b) == 3))
|
|
||||||
colour = colour_join_rgb(r >> 8, g >> 8, b >> 8);
|
|
||||||
else if ((sscanf(p, "cmyk:%lf/%lf/%lf/%lf", &c, &m, &y, &k) == 4 ||
|
|
||||||
sscanf(p, "cmy:%lf/%lf/%lf", &c, &m, &y) == 3) &&
|
|
||||||
c >= 0 && c <= 1 && m >= 0 && m <= 1 &&
|
|
||||||
y >= 0 && y <= 1 && k >= 0 && k <= 1) {
|
|
||||||
colour = colour_join_rgb(
|
|
||||||
(1 - c) * (1 - k) * 255,
|
|
||||||
(1 - m) * (1 - k) * 255,
|
|
||||||
(1 - y) * (1 - k) * 255);
|
|
||||||
} else {
|
|
||||||
while (len != 0 && *p == ' ') {
|
|
||||||
p++;
|
|
||||||
len--;
|
|
||||||
}
|
|
||||||
while (len != 0 && p[len - 1] == ' ')
|
|
||||||
len--;
|
|
||||||
copy = xstrndup(p, len);
|
|
||||||
colour = colour_byname(copy);
|
|
||||||
free(copy);
|
|
||||||
}
|
|
||||||
log_debug("%s: %s = %s", __func__, p, colour_tostring(colour));
|
|
||||||
return (colour);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Reply to a colour request. */
|
/* Reply to a colour request. */
|
||||||
static void
|
static void
|
||||||
input_osc_colour_reply(struct input_ctx *ictx, u_int n, int c)
|
input_osc_colour_reply(struct input_ctx *ictx, u_int n, int c)
|
||||||
@ -2555,7 +2515,7 @@ input_osc_4(struct input_ctx *ictx, const char *p)
|
|||||||
input_osc_colour_reply(ictx, 4, c);
|
input_osc_colour_reply(ictx, 4, c);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ((c = input_osc_parse_colour(s)) == -1) {
|
if ((c = colour_parseX11(s)) == -1) {
|
||||||
s = next;
|
s = next;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -2611,6 +2571,47 @@ bad:
|
|||||||
free(id);
|
free(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get a client with a foreground for the pane. There isn't much to choose
|
||||||
|
* between them so just use the first.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
input_get_fg_client(struct window_pane *wp)
|
||||||
|
{
|
||||||
|
struct window *w = wp->window;
|
||||||
|
struct client *loop;
|
||||||
|
|
||||||
|
TAILQ_FOREACH(loop, &clients, entry) {
|
||||||
|
if (loop->flags & CLIENT_UNATTACHEDFLAGS)
|
||||||
|
continue;
|
||||||
|
if (loop->session == NULL || !session_has(loop->session, w))
|
||||||
|
continue;
|
||||||
|
if (loop->tty.fg == -1)
|
||||||
|
continue;
|
||||||
|
return (loop->tty.fg);
|
||||||
|
}
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get a client with a background for the pane. */
|
||||||
|
static int
|
||||||
|
input_get_bg_client(struct window_pane *wp)
|
||||||
|
{
|
||||||
|
struct window *w = wp->window;
|
||||||
|
struct client *loop;
|
||||||
|
|
||||||
|
TAILQ_FOREACH(loop, &clients, entry) {
|
||||||
|
if (loop->flags & CLIENT_UNATTACHEDFLAGS)
|
||||||
|
continue;
|
||||||
|
if (loop->session == NULL || !session_has(loop->session, w))
|
||||||
|
continue;
|
||||||
|
if (loop->tty.bg == -1)
|
||||||
|
continue;
|
||||||
|
return (loop->tty.bg);
|
||||||
|
}
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
/* Handle the OSC 10 sequence for setting and querying foreground colour. */
|
/* Handle the OSC 10 sequence for setting and querying foreground colour. */
|
||||||
static void
|
static void
|
||||||
input_osc_10(struct input_ctx *ictx, const char *p)
|
input_osc_10(struct input_ctx *ictx, const char *p)
|
||||||
@ -2620,14 +2621,18 @@ input_osc_10(struct input_ctx *ictx, const char *p)
|
|||||||
int c;
|
int c;
|
||||||
|
|
||||||
if (strcmp(p, "?") == 0) {
|
if (strcmp(p, "?") == 0) {
|
||||||
if (wp != NULL) {
|
if (wp == NULL)
|
||||||
tty_default_colours(&defaults, wp);
|
return;
|
||||||
input_osc_colour_reply(ictx, 10, defaults.fg);
|
tty_default_colours(&defaults, wp);
|
||||||
}
|
if (COLOUR_DEFAULT(defaults.fg))
|
||||||
|
c = input_get_fg_client(wp);
|
||||||
|
else
|
||||||
|
c = defaults.fg;
|
||||||
|
input_osc_colour_reply(ictx, 10, c);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((c = input_osc_parse_colour(p)) == -1) {
|
if ((c = colour_parseX11(p)) == -1) {
|
||||||
log_debug("bad OSC 10: %s", p);
|
log_debug("bad OSC 10: %s", p);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -2664,14 +2669,18 @@ input_osc_11(struct input_ctx *ictx, const char *p)
|
|||||||
int c;
|
int c;
|
||||||
|
|
||||||
if (strcmp(p, "?") == 0) {
|
if (strcmp(p, "?") == 0) {
|
||||||
if (wp != NULL) {
|
if (wp == NULL)
|
||||||
tty_default_colours(&defaults, wp);
|
return;
|
||||||
input_osc_colour_reply(ictx, 11, defaults.bg);
|
tty_default_colours(&defaults, wp);
|
||||||
}
|
if (COLOUR_DEFAULT(defaults.bg))
|
||||||
|
c = input_get_bg_client(wp);
|
||||||
|
else
|
||||||
|
c = defaults.bg;
|
||||||
|
input_osc_colour_reply(ictx, 11, c);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((c = input_osc_parse_colour(p)) == -1) {
|
if ((c = colour_parseX11(p)) == -1) {
|
||||||
log_debug("bad OSC 11: %s", p);
|
log_debug("bad OSC 11: %s", p);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -2716,7 +2725,7 @@ input_osc_12(struct input_ctx *ictx, const char *p)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((c = input_osc_parse_colour(p)) == -1) {
|
if ((c = colour_parseX11(p)) == -1) {
|
||||||
log_debug("bad OSC 12: %s", p);
|
log_debug("bad OSC 12: %s", p);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -377,7 +377,7 @@ key_bindings_init(void)
|
|||||||
"bind -N 'Move to the previously active pane' \\; { last-pane }",
|
"bind -N 'Move to the previously active pane' \\; { last-pane }",
|
||||||
"bind -N 'Choose a paste buffer from a list' = { choose-buffer -Z }",
|
"bind -N 'Choose a paste buffer from a list' = { choose-buffer -Z }",
|
||||||
"bind -N 'List key bindings' ? { list-keys -N }",
|
"bind -N 'List key bindings' ? { list-keys -N }",
|
||||||
"bind -N 'Choose a client from a list' D { choose-client -Z }",
|
"bind -N 'Choose and detach a client from a list' D { choose-client -Z }",
|
||||||
"bind -N 'Spread panes out evenly' E { select-layout -E }",
|
"bind -N 'Spread panes out evenly' E { select-layout -E }",
|
||||||
"bind -N 'Switch to the last client' L { switch-client -l }",
|
"bind -N 'Switch to the last client' L { switch-client -l }",
|
||||||
"bind -N 'Clear the marked pane' M { select-pane -M }",
|
"bind -N 'Clear the marked pane' M { select-pane -M }",
|
||||||
|
@ -462,6 +462,8 @@ out:
|
|||||||
strlcat(out, "B", sizeof out);
|
strlcat(out, "B", sizeof out);
|
||||||
if (saved & KEYC_EXTENDED)
|
if (saved & KEYC_EXTENDED)
|
||||||
strlcat(out, "E", sizeof out);
|
strlcat(out, "E", sizeof out);
|
||||||
|
if (saved & KEYC_SENT)
|
||||||
|
strlcat(out, "S", sizeof out);
|
||||||
strlcat(out, "]", sizeof out);
|
strlcat(out, "]", sizeof out);
|
||||||
}
|
}
|
||||||
return (out);
|
return (out);
|
||||||
|
@ -162,8 +162,10 @@ layout_parse(struct window *w, const char *layout, char **cause)
|
|||||||
u_short csum;
|
u_short csum;
|
||||||
|
|
||||||
/* Check validity. */
|
/* Check validity. */
|
||||||
if (sscanf(layout, "%hx,", &csum) != 1)
|
if (sscanf(layout, "%hx,", &csum) != 1) {
|
||||||
|
*cause = xstrdup("invalid layout");
|
||||||
return (-1);
|
return (-1);
|
||||||
|
}
|
||||||
layout += 5;
|
layout += 5;
|
||||||
if (csum != layout_checksum(layout)) {
|
if (csum != layout_checksum(layout)) {
|
||||||
*cause = xstrdup("invalid layout");
|
*cause = xstrdup("invalid layout");
|
||||||
|
59
menu.c
59
menu.c
@ -64,6 +64,8 @@ menu_add_item(struct menu *menu, const struct menu_item *item,
|
|||||||
line = (item == NULL || item->name == NULL || *item->name == '\0');
|
line = (item == NULL || item->name == NULL || *item->name == '\0');
|
||||||
if (line && menu->count == 0)
|
if (line && menu->count == 0)
|
||||||
return;
|
return;
|
||||||
|
if (line && menu->items[menu->count - 1].name == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
menu->items = xreallocarray(menu->items, menu->count + 1,
|
menu->items = xreallocarray(menu->items, menu->count + 1,
|
||||||
sizeof *menu->items);
|
sizeof *menu->items);
|
||||||
@ -427,12 +429,12 @@ chosen:
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct menu_data *
|
struct menu_data *
|
||||||
menu_prepare(struct menu *menu, int flags, struct cmdq_item *item, u_int px,
|
menu_prepare(struct menu *menu, int flags, int starting_choice,
|
||||||
u_int py, struct client *c, struct cmd_find_state *fs, menu_choice_cb cb,
|
struct cmdq_item *item, u_int px, u_int py, struct client *c,
|
||||||
void *data)
|
struct cmd_find_state *fs, menu_choice_cb cb, void *data)
|
||||||
{
|
{
|
||||||
struct menu_data *md;
|
struct menu_data *md;
|
||||||
u_int i;
|
int choice;
|
||||||
const char *name;
|
const char *name;
|
||||||
|
|
||||||
if (c->tty.sx < menu->width + 4 || c->tty.sy < menu->count + 2)
|
if (c->tty.sx < menu->width + 4 || c->tty.sy < menu->count + 2)
|
||||||
@ -457,18 +459,38 @@ menu_prepare(struct menu *menu, int flags, struct cmdq_item *item, u_int px,
|
|||||||
md->py = py;
|
md->py = py;
|
||||||
|
|
||||||
md->menu = menu;
|
md->menu = menu;
|
||||||
|
md->choice = -1;
|
||||||
|
|
||||||
if (md->flags & MENU_NOMOUSE) {
|
if (md->flags & MENU_NOMOUSE) {
|
||||||
for (i = 0; i < menu->count; i++) {
|
if (starting_choice >= (int)menu->count) {
|
||||||
name = menu->items[i].name;
|
starting_choice = menu->count - 1;
|
||||||
if (name != NULL && *name != '-')
|
choice = starting_choice + 1;
|
||||||
break;
|
for (;;) {
|
||||||
|
name = menu->items[choice - 1].name;
|
||||||
|
if (name != NULL && *name != '-') {
|
||||||
|
md->choice = choice - 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (--choice == 0)
|
||||||
|
choice = menu->count;
|
||||||
|
if (choice == starting_choice + 1)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (starting_choice >= 0) {
|
||||||
|
choice = starting_choice;
|
||||||
|
for (;;) {
|
||||||
|
name = menu->items[choice].name;
|
||||||
|
if (name != NULL && *name != '-') {
|
||||||
|
md->choice = choice;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (++choice == (int)menu->count)
|
||||||
|
choice = 0;
|
||||||
|
if (choice == starting_choice)
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (i != menu->count)
|
}
|
||||||
md->choice = i;
|
|
||||||
else
|
|
||||||
md->choice = -1;
|
|
||||||
} else
|
|
||||||
md->choice = -1;
|
|
||||||
|
|
||||||
md->cb = cb;
|
md->cb = cb;
|
||||||
md->data = data;
|
md->data = data;
|
||||||
@ -476,13 +498,14 @@ menu_prepare(struct menu *menu, int flags, struct cmdq_item *item, u_int px,
|
|||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
menu_display(struct menu *menu, int flags, struct cmdq_item *item, u_int px,
|
menu_display(struct menu *menu, int flags, int starting_choice,
|
||||||
u_int py, struct client *c, struct cmd_find_state *fs, menu_choice_cb cb,
|
struct cmdq_item *item, u_int px, u_int py, struct client *c,
|
||||||
void *data)
|
struct cmd_find_state *fs, menu_choice_cb cb, void *data)
|
||||||
{
|
{
|
||||||
struct menu_data *md;
|
struct menu_data *md;
|
||||||
|
|
||||||
md = menu_prepare(menu, flags, item, px, py, c, fs, cb, data);
|
md = menu_prepare(menu, flags, starting_choice, item, px, py, c, fs, cb,
|
||||||
|
data);
|
||||||
if (md == NULL)
|
if (md == NULL)
|
||||||
return (-1);
|
return (-1);
|
||||||
server_client_set_overlay(c, 0, NULL, menu_mode_cb, menu_draw_cb,
|
server_client_set_overlay(c, 0, NULL, menu_mode_cb, menu_draw_cb,
|
||||||
|
@ -962,8 +962,8 @@ mode_tree_display_menu(struct mode_tree_data *mtd, struct client *c, u_int x,
|
|||||||
x -= (menu->width + 4) / 2;
|
x -= (menu->width + 4) / 2;
|
||||||
else
|
else
|
||||||
x = 0;
|
x = 0;
|
||||||
if (menu_display(menu, 0, NULL, x, y, c, NULL, mode_tree_menu_callback,
|
if (menu_display(menu, 0, 0, NULL, x, y, c, NULL,
|
||||||
mtm) != 0)
|
mode_tree_menu_callback, mtm) != 0)
|
||||||
menu_free(menu);
|
menu_free(menu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
7
paste.c
7
paste.c
@ -240,11 +240,8 @@ paste_rename(const char *oldname, const char *newname, char **cause)
|
|||||||
}
|
}
|
||||||
|
|
||||||
pb_new = paste_get_name(newname);
|
pb_new = paste_get_name(newname);
|
||||||
if (pb_new != NULL) {
|
if (pb_new != NULL)
|
||||||
if (cause != NULL)
|
paste_free(pb_new);
|
||||||
xasprintf(cause, "buffer %s already exists", newname);
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
RB_REMOVE(paste_name_tree, &paste_by_name, pb);
|
RB_REMOVE(paste_name_tree, &paste_by_name, pb);
|
||||||
|
|
||||||
|
3
popup.c
3
popup.c
@ -252,6 +252,7 @@ popup_draw_cb(struct client *c, void *data, struct screen_redraw_ctx *rctx)
|
|||||||
tty_draw_line(tty, &s, 0, i, pd->sx, px, py + i, &defaults,
|
tty_draw_line(tty, &s, 0, i, pd->sx, px, py + i, &defaults,
|
||||||
palette);
|
palette);
|
||||||
}
|
}
|
||||||
|
screen_free(&s);
|
||||||
if (pd->md != NULL) {
|
if (pd->md != NULL) {
|
||||||
c->overlay_check = NULL;
|
c->overlay_check = NULL;
|
||||||
c->overlay_data = NULL;
|
c->overlay_data = NULL;
|
||||||
@ -573,7 +574,7 @@ menu:
|
|||||||
x = m->x - (pd->menu->width + 4) / 2;
|
x = m->x - (pd->menu->width + 4) / 2;
|
||||||
else
|
else
|
||||||
x = 0;
|
x = 0;
|
||||||
pd->md = menu_prepare(pd->menu, 0, NULL, x, m->y, c, NULL,
|
pd->md = menu_prepare(pd->menu, 0, 0, NULL, x, m->y, c, NULL,
|
||||||
popup_menu_done, pd);
|
popup_menu_done, pd);
|
||||||
c->flags |= CLIENT_REDRAWOVERLAY;
|
c->flags |= CLIENT_REDRAWOVERLAY;
|
||||||
|
|
||||||
|
299
regress/input-keys.sh
Normal file
299
regress/input-keys.sh
Normal file
@ -0,0 +1,299 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
PATH=/bin:/usr/bin
|
||||||
|
TERM=screen
|
||||||
|
|
||||||
|
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||||
|
TMUX="$TEST_TMUX -Ltest"
|
||||||
|
$TMUX kill-server 2>/dev/null
|
||||||
|
|
||||||
|
$TMUX -f/dev/null new -x20 -y2 -d || exit 1
|
||||||
|
|
||||||
|
sleep 0.1
|
||||||
|
|
||||||
|
exit_status=0
|
||||||
|
|
||||||
|
assert_key () {
|
||||||
|
key=$1
|
||||||
|
expected_code=$2
|
||||||
|
|
||||||
|
$TMUX new-window -- sh -c 'stty raw -echo && cat -tv'
|
||||||
|
$TMUX send-keys "$key" $
|
||||||
|
|
||||||
|
actual_code=$($TMUX capturep -p | head -1 | sed -e 's/\$$//')
|
||||||
|
$TMUX kill-window
|
||||||
|
|
||||||
|
if [ "$actual_code" = "$expected_code" ]; then
|
||||||
|
if [ -n "$VERBOSE" ]; then
|
||||||
|
echo "[PASS] $key -> $actual_code"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "[FAIL] $key -> $expected_code (Got: $actual_code)"
|
||||||
|
exit_status=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
shift
|
||||||
|
shift
|
||||||
|
|
||||||
|
if [ "$1" = "--" ]; then
|
||||||
|
shift
|
||||||
|
assert_key "$@"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_key 'C-Space' '^@'
|
||||||
|
assert_key 'C-a' '^A' -- 'M-C-a' '^[^A'
|
||||||
|
assert_key 'C-b' '^B' -- 'M-C-b' '^[^B'
|
||||||
|
assert_key 'C-c' '^C' -- 'M-C-c' '^[^C'
|
||||||
|
assert_key 'C-d' '^D' -- 'M-C-d' '^[^D'
|
||||||
|
assert_key 'C-e' '^E' -- 'M-C-e' '^[^E'
|
||||||
|
assert_key 'C-f' '^F' -- 'M-C-f' '^[^F'
|
||||||
|
assert_key 'C-g' '^G' -- 'M-C-g' '^[^G'
|
||||||
|
assert_key 'C-h' '^H' -- 'M-C-h' '^[^H'
|
||||||
|
assert_key 'C-i' '^I' -- 'M-C-i' '^[^I'
|
||||||
|
assert_key 'C-j' '' -- 'M-C-j' '^[' # NL
|
||||||
|
assert_key 'C-k' '^K' -- 'M-C-k' '^[^K'
|
||||||
|
assert_key 'C-l' '^L' -- 'M-C-l' '^[^L'
|
||||||
|
assert_key 'C-m' '^M' -- 'M-C-m' '^[^M'
|
||||||
|
assert_key 'C-n' '^N' -- 'M-C-n' '^[^N'
|
||||||
|
assert_key 'C-o' '^O' -- 'M-C-o' '^[^O'
|
||||||
|
assert_key 'C-p' '^P' -- 'M-C-p' '^[^P'
|
||||||
|
assert_key 'C-q' '^Q' -- 'M-C-q' '^[^Q'
|
||||||
|
assert_key 'C-r' '^R' -- 'M-C-r' '^[^R'
|
||||||
|
assert_key 'C-s' '^S' -- 'M-C-s' '^[^S'
|
||||||
|
assert_key 'C-t' '^T' -- 'M-C-t' '^[^T'
|
||||||
|
assert_key 'C-u' '^U' -- 'M-C-u' '^[^U'
|
||||||
|
assert_key 'C-v' '^V' -- 'M-C-v' '^[^V'
|
||||||
|
assert_key 'C-w' '^W' -- 'M-C-w' '^[^W'
|
||||||
|
assert_key 'C-x' '^X' -- 'M-C-x' '^[^X'
|
||||||
|
assert_key 'C-y' '^Y' -- 'M-C-y' '^[^Y'
|
||||||
|
assert_key 'C-z' '^Z' -- 'M-C-z' '^[^Z'
|
||||||
|
assert_key 'Escape' '^[' -- 'M-Escape' '^[^['
|
||||||
|
assert_key "C-\\" "^\\" -- "M-C-\\" "^[^\\"
|
||||||
|
assert_key 'C-]' '^]' -- 'M-C-]' '^[^]'
|
||||||
|
assert_key 'C-^' '^^' -- 'M-C-^' '^[^^'
|
||||||
|
assert_key 'C-_' '^_' -- 'M-C-_' '^[^_'
|
||||||
|
assert_key 'Space' ' ' -- 'M-Space' '^[ '
|
||||||
|
assert_key '!' '!' -- 'M-!' '^[!'
|
||||||
|
assert_key '"' '"' -- 'M-"' '^["'
|
||||||
|
assert_key '#' '#' -- 'M-#' '^[#'
|
||||||
|
assert_key '$' '$' -- 'M-$' '^[$'
|
||||||
|
assert_key '%' '%' -- 'M-%' '^[%'
|
||||||
|
assert_key '&' '&' -- 'M-&' '^[&'
|
||||||
|
assert_key "'" "'" -- "M-'" "^['"
|
||||||
|
assert_key '(' '(' -- 'M-(' '^[('
|
||||||
|
assert_key ')' ')' -- 'M-)' '^[)'
|
||||||
|
assert_key '*' '*' -- 'M-*' '^[*'
|
||||||
|
assert_key '+' '+' -- 'M-+' '^[+'
|
||||||
|
assert_key ',' ',' -- 'M-,' '^[,'
|
||||||
|
assert_key '-' '-' -- 'M--' '^[-'
|
||||||
|
assert_key '.' '.' -- 'M-.' '^[.'
|
||||||
|
assert_key '/' '/' -- 'M-/' '^[/'
|
||||||
|
assert_key '0' '0' -- 'M-0' '^[0'
|
||||||
|
assert_key '1' '1' -- 'M-1' '^[1'
|
||||||
|
assert_key '2' '2' -- 'M-2' '^[2'
|
||||||
|
assert_key '3' '3' -- 'M-3' '^[3'
|
||||||
|
assert_key '4' '4' -- 'M-4' '^[4'
|
||||||
|
assert_key '5' '5' -- 'M-5' '^[5'
|
||||||
|
assert_key '6' '6' -- 'M-6' '^[6'
|
||||||
|
assert_key '7' '7' -- 'M-7' '^[7'
|
||||||
|
assert_key '8' '8' -- 'M-8' '^[8'
|
||||||
|
assert_key '9' '9' -- 'M-9' '^[9'
|
||||||
|
assert_key ':' ':' -- 'M-:' '^[:'
|
||||||
|
assert_key '\;' ';' -- 'M-\;' '^[;'
|
||||||
|
assert_key '<' '<' -- 'M-<' '^[<'
|
||||||
|
assert_key '=' '=' -- 'M-=' '^[='
|
||||||
|
assert_key '>' '>' -- 'M->' '^[>'
|
||||||
|
assert_key '?' '?' -- 'M-?' '^[?'
|
||||||
|
assert_key '@' '@' -- 'M-@' '^[@'
|
||||||
|
assert_key 'A' 'A' -- 'M-A' '^[A'
|
||||||
|
assert_key 'B' 'B' -- 'M-B' '^[B'
|
||||||
|
assert_key 'C' 'C' -- 'M-C' '^[C'
|
||||||
|
assert_key 'D' 'D' -- 'M-D' '^[D'
|
||||||
|
assert_key 'E' 'E' -- 'M-E' '^[E'
|
||||||
|
assert_key 'F' 'F' -- 'M-F' '^[F'
|
||||||
|
assert_key 'G' 'G' -- 'M-G' '^[G'
|
||||||
|
assert_key 'H' 'H' -- 'M-H' '^[H'
|
||||||
|
assert_key 'I' 'I' -- 'M-I' '^[I'
|
||||||
|
assert_key 'J' 'J' -- 'M-J' '^[J'
|
||||||
|
assert_key 'K' 'K' -- 'M-K' '^[K'
|
||||||
|
assert_key 'L' 'L' -- 'M-L' '^[L'
|
||||||
|
assert_key 'M' 'M' -- 'M-M' '^[M'
|
||||||
|
assert_key 'N' 'N' -- 'M-N' '^[N'
|
||||||
|
assert_key 'O' 'O' -- 'M-O' '^[O'
|
||||||
|
assert_key 'P' 'P' -- 'M-P' '^[P'
|
||||||
|
assert_key 'Q' 'Q' -- 'M-Q' '^[Q'
|
||||||
|
assert_key 'R' 'R' -- 'M-R' '^[R'
|
||||||
|
assert_key 'S' 'S' -- 'M-S' '^[S'
|
||||||
|
assert_key 'T' 'T' -- 'M-T' '^[T'
|
||||||
|
assert_key 'U' 'U' -- 'M-U' '^[U'
|
||||||
|
assert_key 'V' 'V' -- 'M-V' '^[V'
|
||||||
|
assert_key 'W' 'W' -- 'M-W' '^[W'
|
||||||
|
assert_key 'X' 'X' -- 'M-X' '^[X'
|
||||||
|
assert_key 'Y' 'Y' -- 'M-Y' '^[Y'
|
||||||
|
assert_key 'Z' 'Z' -- 'M-Z' '^[Z'
|
||||||
|
assert_key '[' '[' -- 'M-[' '^[['
|
||||||
|
assert_key "\\" "\\" -- "M-\\" "^[\\"
|
||||||
|
assert_key ']' ']' -- 'M-]' '^[]'
|
||||||
|
assert_key '^' '^' -- 'M-^' '^[^'
|
||||||
|
assert_key '_' '_' -- 'M-_' '^[_'
|
||||||
|
assert_key '`' '`' -- 'M-`' '^[`'
|
||||||
|
assert_key 'a' 'a' -- 'M-a' '^[a'
|
||||||
|
assert_key 'b' 'b' -- 'M-b' '^[b'
|
||||||
|
assert_key 'c' 'c' -- 'M-c' '^[c'
|
||||||
|
assert_key 'd' 'd' -- 'M-d' '^[d'
|
||||||
|
assert_key 'e' 'e' -- 'M-e' '^[e'
|
||||||
|
assert_key 'f' 'f' -- 'M-f' '^[f'
|
||||||
|
assert_key 'g' 'g' -- 'M-g' '^[g'
|
||||||
|
assert_key 'h' 'h' -- 'M-h' '^[h'
|
||||||
|
assert_key 'i' 'i' -- 'M-i' '^[i'
|
||||||
|
assert_key 'j' 'j' -- 'M-j' '^[j'
|
||||||
|
assert_key 'k' 'k' -- 'M-k' '^[k'
|
||||||
|
assert_key 'l' 'l' -- 'M-l' '^[l'
|
||||||
|
assert_key 'm' 'm' -- 'M-m' '^[m'
|
||||||
|
assert_key 'n' 'n' -- 'M-n' '^[n'
|
||||||
|
assert_key 'o' 'o' -- 'M-o' '^[o'
|
||||||
|
assert_key 'p' 'p' -- 'M-p' '^[p'
|
||||||
|
assert_key 'q' 'q' -- 'M-q' '^[q'
|
||||||
|
assert_key 'r' 'r' -- 'M-r' '^[r'
|
||||||
|
assert_key 's' 's' -- 'M-s' '^[s'
|
||||||
|
assert_key 't' 't' -- 'M-t' '^[t'
|
||||||
|
assert_key 'u' 'u' -- 'M-u' '^[u'
|
||||||
|
assert_key 'v' 'v' -- 'M-v' '^[v'
|
||||||
|
assert_key 'w' 'w' -- 'M-w' '^[w'
|
||||||
|
assert_key 'x' 'x' -- 'M-x' '^[x'
|
||||||
|
assert_key 'y' 'y' -- 'M-y' '^[y'
|
||||||
|
assert_key 'z' 'z' -- 'M-z' '^[z'
|
||||||
|
assert_key '{' '{' -- 'M-{' '^[{'
|
||||||
|
assert_key '|' '|' -- 'M-|' '^[|'
|
||||||
|
assert_key '}' '}' -- 'M-}' '^[}'
|
||||||
|
assert_key '~' '~' -- 'M-~' '^[~'
|
||||||
|
|
||||||
|
assert_key 'Tab' '^I' -- 'M-Tab' '^[^I'
|
||||||
|
assert_key 'BSpace' '^?' -- 'M-BSpace' '^[^?'
|
||||||
|
|
||||||
|
## These cannot be sent, is that intentional?
|
||||||
|
## assert_key 'PasteStart' "^[[200~"
|
||||||
|
## assert_key 'PasteEnd' "^[[201~"
|
||||||
|
|
||||||
|
assert_key 'F1' "^[OP"
|
||||||
|
assert_key 'F2' "^[OQ"
|
||||||
|
assert_key 'F3' "^[OR"
|
||||||
|
assert_key 'F4' "^[OS"
|
||||||
|
assert_key 'F5' "^[[15~"
|
||||||
|
assert_key 'F6' "^[[17~"
|
||||||
|
assert_key 'F8' "^[[19~"
|
||||||
|
assert_key 'F9' "^[[20~"
|
||||||
|
assert_key 'F10' "^[[21~"
|
||||||
|
assert_key 'F11' "^[[23~"
|
||||||
|
assert_key 'F12' "^[[24~"
|
||||||
|
|
||||||
|
assert_key 'IC' '^[[2~'
|
||||||
|
assert_key 'Insert' '^[[2~'
|
||||||
|
assert_key 'DC' '^[[3~'
|
||||||
|
assert_key 'Delete' '^[[3~'
|
||||||
|
|
||||||
|
## Why do these differ from tty-keys?
|
||||||
|
assert_key 'Home' '^[[1~'
|
||||||
|
assert_key 'End' '^[[4~'
|
||||||
|
|
||||||
|
assert_key 'NPage' '^[[6~'
|
||||||
|
assert_key 'PageDown' '^[[6~'
|
||||||
|
assert_key 'PgDn' '^[[6~'
|
||||||
|
assert_key 'PPage' '^[[5~'
|
||||||
|
assert_key 'PageUp' '^[[5~'
|
||||||
|
assert_key 'PgUp' '^[[5~'
|
||||||
|
|
||||||
|
assert_key 'BTab' '^[[Z'
|
||||||
|
assert_key 'C-S-Tab' '^[[Z'
|
||||||
|
|
||||||
|
assert_key 'Up' '^[[A'
|
||||||
|
assert_key 'Down' '^[[B'
|
||||||
|
assert_key 'Right' '^[[C'
|
||||||
|
assert_key 'Left' '^[[D'
|
||||||
|
|
||||||
|
# assert_key 'KPEnter'
|
||||||
|
assert_key 'KP*' '*' -- 'M-KP*' '^[*'
|
||||||
|
assert_key 'KP+' '+' -- 'M-KP+' '^[+'
|
||||||
|
assert_key 'KP-' '-' -- 'M-KP-' '^[-'
|
||||||
|
assert_key 'KP.' '.' -- 'M-KP.' '^[.'
|
||||||
|
assert_key 'KP/' '/' -- 'M-KP/' '^[/'
|
||||||
|
assert_key 'KP0' '0' -- 'M-KP0' '^[0'
|
||||||
|
assert_key 'KP1' '1' -- 'M-KP1' '^[1'
|
||||||
|
assert_key 'KP2' '2' -- 'M-KP2' '^[2'
|
||||||
|
assert_key 'KP3' '3' -- 'M-KP3' '^[3'
|
||||||
|
assert_key 'KP4' '4' -- 'M-KP4' '^[4'
|
||||||
|
assert_key 'KP5' '5' -- 'M-KP5' '^[5'
|
||||||
|
assert_key 'KP6' '6' -- 'M-KP6' '^[6'
|
||||||
|
assert_key 'KP7' '7' -- 'M-KP7' '^[7'
|
||||||
|
assert_key 'KP8' '8' -- 'M-KP8' '^[8'
|
||||||
|
assert_key 'KP9' '9' -- 'M-KP9' '^[9'
|
||||||
|
|
||||||
|
# Extended keys
|
||||||
|
$TMUX set -g extended-keys always
|
||||||
|
|
||||||
|
assert_extended_key () {
|
||||||
|
extended_key=$1
|
||||||
|
expected_code_pattern=$2
|
||||||
|
|
||||||
|
expected_code=$(printf '%s' "$expected_code_pattern" | sed -e 's/;_/;2/')
|
||||||
|
assert_key "S-$extended_key" "$expected_code"
|
||||||
|
|
||||||
|
expected_code=$(printf '%s' "$expected_code_pattern" | sed -e 's/;_/;3/')
|
||||||
|
assert_key "M-$extended_key" "$expected_code"
|
||||||
|
|
||||||
|
expected_code=$(printf '%s' "$expected_code_pattern" | sed -e 's/;_/;4/')
|
||||||
|
assert_key "S-M-$extended_key" "$expected_code"
|
||||||
|
|
||||||
|
expected_code=$(printf '%s' "$expected_code_pattern" | sed -e 's/;_/;5/')
|
||||||
|
assert_key "C-$extended_key" "$expected_code"
|
||||||
|
|
||||||
|
expected_code=$(printf '%s' "$expected_code_pattern" | sed -e 's/;_/;6/')
|
||||||
|
assert_key "S-C-$extended_key" "$expected_code"
|
||||||
|
|
||||||
|
expected_code=$(printf '%s' "$expected_code_pattern" | sed -e 's/;_/;7/')
|
||||||
|
assert_key "C-M-$extended_key" "$expected_code"
|
||||||
|
|
||||||
|
expected_code=$(printf '%s' "$expected_code_pattern" | sed -e 's/;_/;8/')
|
||||||
|
assert_key "S-C-M-$extended_key" "$expected_code"
|
||||||
|
}
|
||||||
|
|
||||||
|
## Many of these pass without extended keys enabled -- are they extended keys?
|
||||||
|
assert_extended_key 'F1' '^[[1;_P'
|
||||||
|
assert_extended_key 'F2' "^[[1;_Q"
|
||||||
|
assert_extended_key 'F3' "^[[1;_R"
|
||||||
|
assert_extended_key 'F4' "^[[1;_S"
|
||||||
|
assert_extended_key 'F5' "^[[15;_~"
|
||||||
|
assert_extended_key 'F6' "^[[17;_~"
|
||||||
|
assert_extended_key 'F8' "^[[19;_~"
|
||||||
|
assert_extended_key 'F9' "^[[20;_~"
|
||||||
|
assert_extended_key 'F10' "^[[21;_~"
|
||||||
|
assert_extended_key 'F11' "^[[23;_~"
|
||||||
|
assert_extended_key 'F12' "^[[24;_~"
|
||||||
|
|
||||||
|
assert_extended_key 'Up' '^[[1;_A'
|
||||||
|
assert_extended_key 'Down' '^[[1;_B'
|
||||||
|
assert_extended_key 'Right' '^[[1;_C'
|
||||||
|
assert_extended_key 'Left' '^[[1;_D'
|
||||||
|
|
||||||
|
assert_extended_key 'Home' '^[[1;_H'
|
||||||
|
assert_extended_key 'End' '^[[1;_F'
|
||||||
|
|
||||||
|
assert_extended_key 'PPage' '^[[5;_~'
|
||||||
|
assert_extended_key 'PageUp' '^[[5;_~'
|
||||||
|
assert_extended_key 'PgUp' '^[[5;_~'
|
||||||
|
assert_extended_key 'NPage' '^[[6;_~'
|
||||||
|
assert_extended_key 'PageDown' '^[[6;_~'
|
||||||
|
assert_extended_key 'PgDn' '^[[6;_~'
|
||||||
|
|
||||||
|
assert_extended_key 'IC' '^[[2;_~'
|
||||||
|
assert_extended_key 'Insert' '^[[2;_~'
|
||||||
|
assert_extended_key 'DC' '^[[3;_~'
|
||||||
|
assert_extended_key 'Delete' '^[[3;_~'
|
||||||
|
|
||||||
|
assert_key 'C-Tab' "^[[9;5u"
|
||||||
|
assert_key 'C-S-Tab' "^[[1;5Z"
|
||||||
|
|
||||||
|
$TMUX kill-server 2>/dev/null
|
||||||
|
|
||||||
|
exit $exit_status
|
361
regress/tty-keys.sh
Normal file
361
regress/tty-keys.sh
Normal file
@ -0,0 +1,361 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
PATH=/bin:/usr/bin
|
||||||
|
TERM=screen
|
||||||
|
|
||||||
|
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||||
|
TMUX="$TEST_TMUX -Ltest"
|
||||||
|
$TMUX kill-server 2>/dev/null
|
||||||
|
TMUX2="$TEST_TMUX -Ltest2"
|
||||||
|
$TMUX2 kill-server 2>/dev/null
|
||||||
|
|
||||||
|
TMP=$(mktemp)
|
||||||
|
trap "rm -f $TMP" 0 1 15
|
||||||
|
|
||||||
|
$TMUX2 -f/dev/null new -d || exit 1
|
||||||
|
$TMUX -f/dev/null new -d "$TMUX2 attach" || exit 1
|
||||||
|
sleep 0.1
|
||||||
|
|
||||||
|
exit_status=0
|
||||||
|
|
||||||
|
format_string () {
|
||||||
|
case $1 in
|
||||||
|
*\')
|
||||||
|
printf '"%%%%"'
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
printf "'%%%%'"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_key () {
|
||||||
|
keys=$1
|
||||||
|
expected_name=$2
|
||||||
|
format_string=$(format_string "$expected_name")
|
||||||
|
|
||||||
|
$TMUX2 command-prompt -k 'display-message -pl '"$format_string" > "$TMP" &
|
||||||
|
sleep 0.05
|
||||||
|
|
||||||
|
$TMUX send-keys $keys
|
||||||
|
|
||||||
|
wait
|
||||||
|
|
||||||
|
keys=$(printf '%s' "$keys" | sed -e 's/Escape/\\\\033/g' | tr -d '[:space:]')
|
||||||
|
actual_name=$(tr -d '[:space:]' < "$TMP")
|
||||||
|
|
||||||
|
if [ "$actual_name" = "$expected_name" ]; then
|
||||||
|
if [ -n "$VERBOSE" ]; then
|
||||||
|
echo "[PASS] $keys -> $actual_name"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "[FAIL] $keys -> $expected_name (Got: '$actual_name')"
|
||||||
|
exit_status=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$3" = "--" ]; then
|
||||||
|
shift; shift; shift
|
||||||
|
assert_key "$@"
|
||||||
|
fi
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_key 0x00 'C-Space' # -- 'Escape 0x00' 'M-C-Space'
|
||||||
|
assert_key 0x01 'C-a' -- 'Escape 0x01' 'M-C-a'
|
||||||
|
assert_key 0x02 'C-b' -- 'Escape 0x02' 'M-C-b'
|
||||||
|
assert_key 0x03 'C-c' -- 'Escape 0x03' 'M-C-c'
|
||||||
|
assert_key 0x04 'C-d' -- 'Escape 0x04' 'M-C-d'
|
||||||
|
assert_key 0x05 'C-e' -- 'Escape 0x05' 'M-C-e'
|
||||||
|
assert_key 0x06 'C-f' -- 'Escape 0x06' 'M-C-f'
|
||||||
|
assert_key 0x07 'C-g' -- 'Escape 0x07' 'M-C-g'
|
||||||
|
assert_key 0x08 'C-h' -- 'Escape 0x08' 'M-C-h'
|
||||||
|
assert_key 0x09 'Tab' -- 'Escape 0x09' 'M-Tab'
|
||||||
|
assert_key 0x0A 'C-j' -- 'Escape 0x0A' 'M-C-j'
|
||||||
|
assert_key 0x0B 'C-k' -- 'Escape 0x0B' 'M-C-k'
|
||||||
|
assert_key 0x0C 'C-l' -- 'Escape 0x0C' 'M-C-l'
|
||||||
|
assert_key 0x0D 'Enter' -- 'Escape 0x0D' 'M-Enter'
|
||||||
|
assert_key 0x0E 'C-n' -- 'Escape 0x0E' 'M-C-n'
|
||||||
|
assert_key 0x0F 'C-o' -- 'Escape 0x0F' 'M-C-o'
|
||||||
|
assert_key 0x10 'C-p' -- 'Escape 0x10' 'M-C-p'
|
||||||
|
assert_key 0x11 'C-q' -- 'Escape 0x11' 'M-C-q'
|
||||||
|
assert_key 0x12 'C-r' -- 'Escape 0x12' 'M-C-r'
|
||||||
|
assert_key 0x13 'C-s' -- 'Escape 0x13' 'M-C-s'
|
||||||
|
assert_key 0x14 'C-t' -- 'Escape 0x14' 'M-C-t'
|
||||||
|
assert_key 0x15 'C-u' -- 'Escape 0x15' 'M-C-u'
|
||||||
|
assert_key 0x16 'C-v' -- 'Escape 0x16' 'M-C-v'
|
||||||
|
assert_key 0x17 'C-w' -- 'Escape 0x17' 'M-C-w'
|
||||||
|
assert_key 0x18 'C-x' -- 'Escape 0x18' 'M-C-x'
|
||||||
|
assert_key 0x19 'C-y' -- 'Escape 0x19' 'M-C-y'
|
||||||
|
assert_key 0x1A 'C-z' -- 'Escape 0x1A' 'M-C-z'
|
||||||
|
assert_key 0x1B 'Escape' -- 'Escape 0x1B' 'M-Escape'
|
||||||
|
assert_key 0x1C "C-\\" -- 'Escape 0x1C' "M-C-\\"
|
||||||
|
assert_key 0x1D 'C-]' -- 'Escape 0x1D' 'M-C-]'
|
||||||
|
assert_key 0x1E 'C-^' -- 'Escape 0x1E' 'M-C-^'
|
||||||
|
assert_key 0x1F 'C-_' -- 'Escape 0x1F' 'M-C-_'
|
||||||
|
assert_key 0x20 'Space' -- 'Escape 0x20' 'M-Space'
|
||||||
|
assert_key 0x21 '!' -- 'Escape 0x21' 'M-!'
|
||||||
|
assert_key 0x22 '"' -- 'Escape 0x22' 'M-"'
|
||||||
|
assert_key 0x23 '#' -- 'Escape 0x23'= 'M-#'
|
||||||
|
assert_key 0x24 '$' -- 'Escape 0x24'= 'M-$'
|
||||||
|
assert_key 0x25 '%' -- 'Escape 0x25'= 'M-%'
|
||||||
|
assert_key 0x26 '&' -- 'Escape 0x26'= 'M-&'
|
||||||
|
assert_key 0x27 "'" -- 'Escape 0x27' "M-'"
|
||||||
|
assert_key 0x28 '(' -- 'Escape 0x28' 'M-('
|
||||||
|
assert_key 0x29 ')' -- 'Escape 0x29' 'M-)'
|
||||||
|
assert_key 0x2A '*' -- 'Escape 0x2A' 'M-*'
|
||||||
|
assert_key 0x2B '+' -- 'Escape 0x2B' 'M-+'
|
||||||
|
assert_key 0x2C ',' -- 'Escape 0x2C' 'M-,'
|
||||||
|
assert_key 0x2D '-' -- 'Escape 0x2D' 'M--'
|
||||||
|
assert_key 0x2E '.' -- 'Escape 0x2E' 'M-.'
|
||||||
|
assert_key 0x2F '/' -- 'Escape 0x2F' 'M-/'
|
||||||
|
assert_key 0x30 '0' -- 'Escape 0x30' 'M-0'
|
||||||
|
assert_key 0x31 '1' -- 'Escape 0x31' 'M-1'
|
||||||
|
assert_key 0x32 '2' -- 'Escape 0x32' 'M-2'
|
||||||
|
assert_key 0x33 '3' -- 'Escape 0x33' 'M-3'
|
||||||
|
assert_key 0x34 '4' -- 'Escape 0x34' 'M-4'
|
||||||
|
assert_key 0x35 '5' -- 'Escape 0x35' 'M-5'
|
||||||
|
assert_key 0x36 '6' -- 'Escape 0x36' 'M-6'
|
||||||
|
assert_key 0x37 '7' -- 'Escape 0x37' 'M-7'
|
||||||
|
assert_key 0x38 '8' -- 'Escape 0x38' 'M-8'
|
||||||
|
assert_key 0x39 '9' -- 'Escape 0x39' 'M-9'
|
||||||
|
assert_key 0x3A ':' -- 'Escape 0x3A' 'M-:'
|
||||||
|
assert_key 0x3B ';' -- 'Escape 0x3B' 'M-;'
|
||||||
|
assert_key 0x3C '<' -- 'Escape 0x3C' 'M-<'
|
||||||
|
assert_key 0x3D '=' -- 'Escape 0x3D' 'M-='
|
||||||
|
assert_key 0x3E '>' -- 'Escape 0x3E' 'M->'
|
||||||
|
assert_key 0x3F '?' -- 'Escape 0x3F' 'M-?'
|
||||||
|
assert_key 0x40 '@' -- 'Escape 0x40' 'M-@'
|
||||||
|
assert_key 0x41 'A' -- 'Escape 0x41' 'M-A'
|
||||||
|
assert_key 0x42 'B' -- 'Escape 0x42' 'M-B'
|
||||||
|
assert_key 0x43 'C' -- 'Escape 0x43' 'M-C'
|
||||||
|
assert_key 0x44 'D' -- 'Escape 0x44' 'M-D'
|
||||||
|
assert_key 0x45 'E' -- 'Escape 0x45' 'M-E'
|
||||||
|
assert_key 0x46 'F' -- 'Escape 0x46' 'M-F'
|
||||||
|
assert_key 0x47 'G' -- 'Escape 0x47' 'M-G'
|
||||||
|
assert_key 0x48 'H' -- 'Escape 0x48' 'M-H'
|
||||||
|
assert_key 0x49 'I' -- 'Escape 0x49' 'M-I'
|
||||||
|
assert_key 0x4A 'J' -- 'Escape 0x4A' 'M-J'
|
||||||
|
assert_key 0x4B 'K' -- 'Escape 0x4B' 'M-K'
|
||||||
|
assert_key 0x4C 'L' -- 'Escape 0x4C' 'M-L'
|
||||||
|
assert_key 0x4D 'M' -- 'Escape 0x4D' 'M-M'
|
||||||
|
assert_key 0x4E 'N' -- 'Escape 0x4E' 'M-N'
|
||||||
|
assert_key 0x4F 'O' -- 'Escape 0x4F' 'M-O'
|
||||||
|
assert_key 0x50 'P' -- 'Escape 0x50' 'M-P'
|
||||||
|
assert_key 0x51 'Q' -- 'Escape 0x51' 'M-Q'
|
||||||
|
assert_key 0x52 'R' -- 'Escape 0x52' 'M-R'
|
||||||
|
assert_key 0x53 'S' -- 'Escape 0x53' 'M-S'
|
||||||
|
assert_key 0x54 'T' -- 'Escape 0x54' 'M-T'
|
||||||
|
assert_key 0x55 'U' -- 'Escape 0x55' 'M-U'
|
||||||
|
assert_key 0x56 'V' -- 'Escape 0x56' 'M-V'
|
||||||
|
assert_key 0x57 'W' -- 'Escape 0x57' 'M-W'
|
||||||
|
assert_key 0x58 'X' -- 'Escape 0x58' 'M-X'
|
||||||
|
assert_key 0x59 'Y' -- 'Escape 0x59' 'M-Y'
|
||||||
|
assert_key 0x5A 'Z' -- 'Escape 0x5A' 'M-Z'
|
||||||
|
assert_key 0x5B '[' -- 'Escape 0x5B' 'M-['
|
||||||
|
assert_key 0x5C "\\" -- 'Escape 0x5C' "M-\\"
|
||||||
|
assert_key 0x5D ']' -- 'Escape 0x5D' 'M-]'
|
||||||
|
assert_key 0x5E '^' -- 'Escape 0x5E' 'M-^'
|
||||||
|
assert_key 0x5F '_' -- 'Escape 0x5F' 'M-_'
|
||||||
|
assert_key 0x60 '`' -- 'Escape 0x60' 'M-`'
|
||||||
|
assert_key 0x61 'a' -- 'Escape 0x61' 'M-a'
|
||||||
|
assert_key 0x62 'b' -- 'Escape 0x62' 'M-b'
|
||||||
|
assert_key 0x63 'c' -- 'Escape 0x63' 'M-c'
|
||||||
|
assert_key 0x64 'd' -- 'Escape 0x64' 'M-d'
|
||||||
|
assert_key 0x65 'e' -- 'Escape 0x65' 'M-e'
|
||||||
|
assert_key 0x66 'f' -- 'Escape 0x66' 'M-f'
|
||||||
|
assert_key 0x67 'g' -- 'Escape 0x67' 'M-g'
|
||||||
|
assert_key 0x68 'h' -- 'Escape 0x68' 'M-h'
|
||||||
|
assert_key 0x69 'i' -- 'Escape 0x69' 'M-i'
|
||||||
|
assert_key 0x6A 'j' -- 'Escape 0x6A' 'M-j'
|
||||||
|
assert_key 0x6B 'k' -- 'Escape 0x6B' 'M-k'
|
||||||
|
assert_key 0x6C 'l' -- 'Escape 0x6C' 'M-l'
|
||||||
|
assert_key 0x6D 'm' -- 'Escape 0x6D' 'M-m'
|
||||||
|
assert_key 0x6E 'n' -- 'Escape 0x6E' 'M-n'
|
||||||
|
assert_key 0x6F 'o' -- 'Escape 0x6F' 'M-o'
|
||||||
|
assert_key 0x70 'p' -- 'Escape 0x70' 'M-p'
|
||||||
|
assert_key 0x71 'q' -- 'Escape 0x71' 'M-q'
|
||||||
|
assert_key 0x72 'r' -- 'Escape 0x72' 'M-r'
|
||||||
|
assert_key 0x73 's' -- 'Escape 0x73' 'M-s'
|
||||||
|
assert_key 0x74 't' -- 'Escape 0x74' 'M-t'
|
||||||
|
assert_key 0x75 'u' -- 'Escape 0x75' 'M-u'
|
||||||
|
assert_key 0x76 'v' -- 'Escape 0x76' 'M-v'
|
||||||
|
assert_key 0x77 'w' -- 'Escape 0x77' 'M-w'
|
||||||
|
assert_key 0x78 'x' -- 'Escape 0x78' 'M-x'
|
||||||
|
assert_key 0x79 'y' -- 'Escape 0x79' 'M-y'
|
||||||
|
assert_key 0x7A 'z' -- 'Escape 0x7A' 'M-z'
|
||||||
|
assert_key 0x7B '{' -- 'Escape 0x7B' 'M-{'
|
||||||
|
assert_key 0x7C '|' -- 'Escape 0x7C' 'M-|'
|
||||||
|
assert_key 0x7D '}' -- 'Escape 0x7D' 'M-}'
|
||||||
|
assert_key 0x7E '~' -- 'Escape 0x7E' 'M-~'
|
||||||
|
assert_key 0x7F 'BSpace' -- 'Escape 0x7F' 'M-BSpace'
|
||||||
|
|
||||||
|
# Numeric keypad
|
||||||
|
assert_key 'Escape OM' 'KPEnter' -- 'Escape Escape OM' 'M-KPEnter'
|
||||||
|
assert_key 'Escape Oj' 'KP*' -- 'Escape Escape Oj' 'M-KP*'
|
||||||
|
assert_key 'Escape Ok' 'KP+' -- 'Escape Escape Ok' 'M-KP+'
|
||||||
|
assert_key 'Escape Om' 'KP-' -- 'Escape Escape Om' 'M-KP-'
|
||||||
|
assert_key 'Escape On' 'KP.' -- 'Escape Escape On' 'M-KP.'
|
||||||
|
assert_key 'Escape Oo' 'KP/' -- 'Escape Escape Oo' 'M-KP/'
|
||||||
|
assert_key 'Escape Op' 'KP0' -- 'Escape Escape Op' 'M-KP0'
|
||||||
|
assert_key 'Escape Oq' 'KP1' -- 'Escape Escape Oq' 'M-KP1'
|
||||||
|
assert_key 'Escape Or' 'KP2' -- 'Escape Escape Or' 'M-KP2'
|
||||||
|
assert_key 'Escape Os' 'KP3' -- 'Escape Escape Os' 'M-KP3'
|
||||||
|
assert_key 'Escape Ot' 'KP4' -- 'Escape Escape Ot' 'M-KP4'
|
||||||
|
assert_key 'Escape Ou' 'KP5' -- 'Escape Escape Ou' 'M-KP5'
|
||||||
|
assert_key 'Escape Ov' 'KP6' -- 'Escape Escape Ov' 'M-KP6'
|
||||||
|
assert_key 'Escape Ow' 'KP7' -- 'Escape Escape Ow' 'M-KP7'
|
||||||
|
assert_key 'Escape Ox' 'KP8' -- 'Escape Escape Ox' 'M-KP8'
|
||||||
|
assert_key 'Escape Oy' 'KP9' -- 'Escape Escape Oy' 'M-KP9'
|
||||||
|
|
||||||
|
# Arrow keys
|
||||||
|
assert_key 'Escape OA' 'Up' -- 'Escape Escape OA' 'M-Up'
|
||||||
|
assert_key 'Escape OB' 'Down' -- 'Escape Escape OB' 'M-Down'
|
||||||
|
assert_key 'Escape OC' 'Right' -- 'Escape Escape OC' 'M-Right'
|
||||||
|
assert_key 'Escape OD' 'Left' -- 'Escape Escape OD' 'M-Left'
|
||||||
|
|
||||||
|
assert_key 'Escape [A' 'Up' -- 'Escape Escape [A' 'M-Up'
|
||||||
|
assert_key 'Escape [B' 'Down' -- 'Escape Escape [B' 'M-Down'
|
||||||
|
assert_key 'Escape [C' 'Right' -- 'Escape Escape [C' 'M-Right'
|
||||||
|
assert_key 'Escape [D' 'Left' -- 'Escape Escape [D' 'M-Left'
|
||||||
|
|
||||||
|
# Other xterm keys
|
||||||
|
assert_key 'Escape OH' 'Home' -- 'Escape Escape OH' 'M-Home'
|
||||||
|
assert_key 'Escape OF' 'End' -- 'Escape Escape OF' 'M-End'
|
||||||
|
|
||||||
|
assert_key 'Escape [H' 'Home' -- 'Escape Escape [H' 'M-Home'
|
||||||
|
assert_key 'Escape [F' 'End' -- 'Escape Escape [F' 'M-End'
|
||||||
|
|
||||||
|
# rxvt arrow keys
|
||||||
|
assert_key 'Escape Oa' 'C-Up'
|
||||||
|
assert_key 'Escape Ob' 'C-Down'
|
||||||
|
assert_key 'Escape Oc' 'C-Right'
|
||||||
|
assert_key 'Escape Od' 'C-Left'
|
||||||
|
assert_key 'Escape [a' 'S-Up'
|
||||||
|
assert_key 'Escape [b' 'S-Down'
|
||||||
|
assert_key 'Escape [c' 'S-Right'
|
||||||
|
assert_key 'Escape [d' 'S-Left'
|
||||||
|
|
||||||
|
# rxvt function keys
|
||||||
|
assert_key 'Escape [11~' 'F1'
|
||||||
|
assert_key 'Escape [12~' 'F2'
|
||||||
|
assert_key 'Escape [13~' 'F3'
|
||||||
|
assert_key 'Escape [14~' 'F4'
|
||||||
|
assert_key 'Escape [15~' 'F5'
|
||||||
|
assert_key 'Escape [17~' 'F6'
|
||||||
|
assert_key 'Escape [18~' 'F7'
|
||||||
|
assert_key 'Escape [19~' 'F8'
|
||||||
|
assert_key 'Escape [20~' 'F9'
|
||||||
|
assert_key 'Escape [21~' 'F10'
|
||||||
|
assert_key 'Escape [23~' 'F11'
|
||||||
|
assert_key 'Escape [24~' 'F12'
|
||||||
|
|
||||||
|
# With TERM=screen, these will be seen as F11 and F12
|
||||||
|
# assert_key 'Escape [23~' 'S-F1'
|
||||||
|
# assert_key 'Escape [24~' 'S-F2'
|
||||||
|
assert_key 'Escape [25~' 'S-F3'
|
||||||
|
assert_key 'Escape [26~' 'S-F4'
|
||||||
|
assert_key 'Escape [28~' 'S-F5'
|
||||||
|
assert_key 'Escape [29~' 'S-F6'
|
||||||
|
assert_key 'Escape [31~' 'S-F7'
|
||||||
|
assert_key 'Escape [32~' 'S-F8'
|
||||||
|
assert_key 'Escape [33~' 'S-F9'
|
||||||
|
assert_key 'Escape [34~' 'S-F10'
|
||||||
|
assert_key 'Escape [23$' 'S-F11'
|
||||||
|
assert_key 'Escape [24$' 'S-F12'
|
||||||
|
|
||||||
|
assert_key 'Escape [11^' 'C-F1'
|
||||||
|
assert_key 'Escape [12^' 'C-F2'
|
||||||
|
assert_key 'Escape [13^' 'C-F3'
|
||||||
|
assert_key 'Escape [14^' 'C-F4'
|
||||||
|
assert_key 'Escape [15^' 'C-F5'
|
||||||
|
assert_key 'Escape [17^' 'C-F6'
|
||||||
|
assert_key 'Escape [18^' 'C-F7'
|
||||||
|
assert_key 'Escape [19^' 'C-F8'
|
||||||
|
assert_key 'Escape [20^' 'C-F9'
|
||||||
|
assert_key 'Escape [21^' 'C-F10'
|
||||||
|
assert_key 'Escape [23^' 'C-F11'
|
||||||
|
assert_key 'Escape [24^' 'C-F12'
|
||||||
|
|
||||||
|
assert_key 'Escape [11@' 'C-S-F1'
|
||||||
|
assert_key 'Escape [12@' 'C-S-F2'
|
||||||
|
assert_key 'Escape [13@' 'C-S-F3'
|
||||||
|
assert_key 'Escape [14@' 'C-S-F4'
|
||||||
|
assert_key 'Escape [15@' 'C-S-F5'
|
||||||
|
assert_key 'Escape [17@' 'C-S-F6'
|
||||||
|
assert_key 'Escape [18@' 'C-S-F7'
|
||||||
|
assert_key 'Escape [19@' 'C-S-F8'
|
||||||
|
assert_key 'Escape [20@' 'C-S-F9'
|
||||||
|
assert_key 'Escape [21@' 'C-S-F10'
|
||||||
|
assert_key 'Escape [23@' 'C-S-F11'
|
||||||
|
assert_key 'Escape [24@' 'C-S-F12'
|
||||||
|
|
||||||
|
# Focus tracking
|
||||||
|
assert_key 'Escape [I' 'FocusIn'
|
||||||
|
assert_key 'Escape [O' 'FocusOut'
|
||||||
|
|
||||||
|
# Paste keys
|
||||||
|
assert_key 'Escape [200~' 'PasteStart'
|
||||||
|
assert_key 'Escape [201~' 'PasteEnd'
|
||||||
|
|
||||||
|
assert_key 'Escape [Z' 'BTab'
|
||||||
|
|
||||||
|
assert_extended_key () {
|
||||||
|
code=$1
|
||||||
|
key_name=$2
|
||||||
|
|
||||||
|
assert_key "Escape [${code};5u" "C-$key_name"
|
||||||
|
assert_key "Escape [${code};7u" "M-C-$key_name"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Extended keys
|
||||||
|
# assert_extended_key 65 'A'
|
||||||
|
# assert_extended_key 66 'B'
|
||||||
|
# assert_extended_key 67 'C'
|
||||||
|
# assert_extended_key 68 'D'
|
||||||
|
# assert_extended_key 69 'E'
|
||||||
|
# assert_extended_key 70 'F'
|
||||||
|
# assert_extended_key 71 'G'
|
||||||
|
# assert_extended_key 72 'H'
|
||||||
|
# assert_extended_key 73 'I'
|
||||||
|
# assert_extended_key 74 'J'
|
||||||
|
# assert_extended_key 75 'K'
|
||||||
|
# assert_extended_key 76 'L'
|
||||||
|
# assert_extended_key 77 'M'
|
||||||
|
# assert_extended_key 78 'N'
|
||||||
|
# assert_extended_key 79 'O'
|
||||||
|
# assert_extended_key 80 'P'
|
||||||
|
# assert_extended_key 81 'Q'
|
||||||
|
# assert_extended_key 82 'R'
|
||||||
|
# assert_extended_key 83 'S'
|
||||||
|
# assert_extended_key 84 'T'
|
||||||
|
# assert_extended_key 85 'U'
|
||||||
|
# assert_extended_key 86 'V'
|
||||||
|
# assert_extended_key 87 'W'
|
||||||
|
# assert_extended_key 88 'X'
|
||||||
|
# assert_extended_key 89 'Y'
|
||||||
|
# assert_extended_key 90 'Z'
|
||||||
|
# assert_extended_key 123 '{'
|
||||||
|
# assert_extended_key 124 '|'
|
||||||
|
# assert_extended_key 125 '}'
|
||||||
|
|
||||||
|
# assert_key 'Escape [105;5u' 'C-i'
|
||||||
|
# assert_key 'Escape [73;5u' 'C-I'
|
||||||
|
|
||||||
|
# assert_key 'Escape [109;5u' 'C-m'
|
||||||
|
# assert_key 'Escape [77;5u' 'C-M'
|
||||||
|
|
||||||
|
# assert_key 'Escape [91;5u' 'C-['
|
||||||
|
assert_key 'Escape [123;5u' 'C-{'
|
||||||
|
|
||||||
|
# assert_key 'Escape [64;5u' 'C-@'
|
||||||
|
|
||||||
|
assert_key 'Escape [32;2u' 'S-Space'
|
||||||
|
# assert_key 'Escape [32;6u' 'C-S-Space'
|
||||||
|
|
||||||
|
assert_key 'Escape [9;5u' 'C-Tab'
|
||||||
|
assert_key 'Escape [1;5Z' 'C-S-Tab'
|
||||||
|
|
||||||
|
$TMUX kill-server 2>/dev/null
|
||||||
|
$TMUX2 kill-server 2>/dev/null
|
||||||
|
|
||||||
|
exit $exit_status
|
@ -34,7 +34,7 @@ static void screen_write_collect_flush(struct screen_write_ctx *, int,
|
|||||||
static int screen_write_overwrite(struct screen_write_ctx *,
|
static int screen_write_overwrite(struct screen_write_ctx *,
|
||||||
struct grid_cell *, u_int);
|
struct grid_cell *, u_int);
|
||||||
static const struct grid_cell *screen_write_combine(struct screen_write_ctx *,
|
static const struct grid_cell *screen_write_combine(struct screen_write_ctx *,
|
||||||
const struct utf8_data *, u_int *);
|
const struct utf8_data *, u_int *, u_int *);
|
||||||
|
|
||||||
struct screen_write_citem {
|
struct screen_write_citem {
|
||||||
u_int x;
|
u_int x;
|
||||||
@ -1905,13 +1905,13 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc)
|
|||||||
*/
|
*/
|
||||||
if (ctx->flags & SCREEN_WRITE_ZWJ) {
|
if (ctx->flags & SCREEN_WRITE_ZWJ) {
|
||||||
screen_write_collect_flush(ctx, 0, __func__);
|
screen_write_collect_flush(ctx, 0, __func__);
|
||||||
screen_write_combine(ctx, &zwj, &xx);
|
screen_write_combine(ctx, &zwj, &xx, &cx);
|
||||||
}
|
}
|
||||||
if (width == 0 || (ctx->flags & SCREEN_WRITE_ZWJ)) {
|
if (width == 0 || (ctx->flags & SCREEN_WRITE_ZWJ)) {
|
||||||
ctx->flags &= ~SCREEN_WRITE_ZWJ;
|
ctx->flags &= ~SCREEN_WRITE_ZWJ;
|
||||||
screen_write_collect_flush(ctx, 0, __func__);
|
screen_write_collect_flush(ctx, 0, __func__);
|
||||||
if ((gc = screen_write_combine(ctx, ud, &xx)) != NULL) {
|
if ((gc = screen_write_combine(ctx, ud, &xx, &cx)) != NULL) {
|
||||||
cx = s->cx; cy = s->cy;
|
cy = s->cy;
|
||||||
screen_write_set_cursor(ctx, xx, s->cy);
|
screen_write_set_cursor(ctx, xx, s->cy);
|
||||||
screen_write_initctx(ctx, &ttyctx, 0);
|
screen_write_initctx(ctx, &ttyctx, 0);
|
||||||
ttyctx.cell = gc;
|
ttyctx.cell = gc;
|
||||||
@ -2038,16 +2038,19 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc)
|
|||||||
/* Combine a UTF-8 zero-width character onto the previous. */
|
/* Combine a UTF-8 zero-width character onto the previous. */
|
||||||
static const struct grid_cell *
|
static const struct grid_cell *
|
||||||
screen_write_combine(struct screen_write_ctx *ctx, const struct utf8_data *ud,
|
screen_write_combine(struct screen_write_ctx *ctx, const struct utf8_data *ud,
|
||||||
u_int *xx)
|
u_int *xx, u_int *cx)
|
||||||
{
|
{
|
||||||
struct screen *s = ctx->s;
|
struct screen *s = ctx->s;
|
||||||
struct grid *gd = s->grid;
|
struct grid *gd = s->grid;
|
||||||
static struct grid_cell gc;
|
static struct grid_cell gc;
|
||||||
u_int n;
|
u_int n, width;
|
||||||
|
|
||||||
/* Can't combine if at 0. */
|
/* Can't combine if at 0. */
|
||||||
if (s->cx == 0)
|
if (s->cx == 0) {
|
||||||
|
*xx = 0;
|
||||||
return (NULL);
|
return (NULL);
|
||||||
|
}
|
||||||
|
*xx = s->cx;
|
||||||
|
|
||||||
/* Empty data is out. */
|
/* Empty data is out. */
|
||||||
if (ud->size == 0)
|
if (ud->size == 0)
|
||||||
@ -2061,22 +2064,35 @@ screen_write_combine(struct screen_write_ctx *ctx, const struct utf8_data *ud,
|
|||||||
}
|
}
|
||||||
if (n > s->cx)
|
if (n > s->cx)
|
||||||
return (NULL);
|
return (NULL);
|
||||||
*xx = s->cx - n;
|
|
||||||
|
|
||||||
/* Check there is enough space. */
|
/* Check there is enough space. */
|
||||||
if (gc.data.size + ud->size > sizeof gc.data.data)
|
if (gc.data.size + ud->size > sizeof gc.data.data)
|
||||||
return (NULL);
|
return (NULL);
|
||||||
|
(*xx) -= n;
|
||||||
|
|
||||||
log_debug("%s: %.*s onto %.*s at %u,%u", __func__, (int)ud->size,
|
log_debug("%s: %.*s onto %.*s at %u,%u (width %u)", __func__,
|
||||||
ud->data, (int)gc.data.size, gc.data.data, *xx, s->cy);
|
(int)ud->size, ud->data, (int)gc.data.size, gc.data.data, *xx,
|
||||||
|
s->cy, gc.data.width);
|
||||||
|
|
||||||
/* Append the data. */
|
/* Append the data. */
|
||||||
memcpy(gc.data.data + gc.data.size, ud->data, ud->size);
|
memcpy(gc.data.data + gc.data.size, ud->data, ud->size);
|
||||||
gc.data.size += ud->size;
|
gc.data.size += ud->size;
|
||||||
|
width = gc.data.width;
|
||||||
|
|
||||||
|
/* If this is U+FE0F VARIATION SELECTOR-16, force the width to 2. */
|
||||||
|
if (gc.data.width == 1 &&
|
||||||
|
ud->size == 3 &&
|
||||||
|
memcmp(ud->data, "\357\270\217", 3) == 0) {
|
||||||
|
grid_view_set_padding(gd, (*xx) + 1, s->cy);
|
||||||
|
gc.data.width = 2;
|
||||||
|
width += 2;
|
||||||
|
}
|
||||||
|
|
||||||
/* Set the new cell. */
|
/* Set the new cell. */
|
||||||
grid_view_set_cell(gd, *xx, s->cy, &gc);
|
grid_view_set_cell(gd, *xx, s->cy, &gc);
|
||||||
|
|
||||||
|
*cx = (*xx) + width;
|
||||||
|
log_debug("%s: character at %u; cursor at %u", __func__, *xx, *cx);
|
||||||
return (&gc);
|
return (&gc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,6 +42,7 @@ static void server_client_check_modes(struct client *);
|
|||||||
static void server_client_set_title(struct client *);
|
static void server_client_set_title(struct client *);
|
||||||
static void server_client_set_path(struct client *);
|
static void server_client_set_path(struct client *);
|
||||||
static void server_client_reset_state(struct client *);
|
static void server_client_reset_state(struct client *);
|
||||||
|
static int server_client_is_bracket_pasting(struct client *, key_code);
|
||||||
static int server_client_assume_paste(struct session *);
|
static int server_client_assume_paste(struct session *);
|
||||||
static void server_client_update_latest(struct client *);
|
static void server_client_update_latest(struct client *);
|
||||||
|
|
||||||
@ -1754,6 +1755,25 @@ out:
|
|||||||
return (key);
|
return (key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Is this a bracket paste key? */
|
||||||
|
static int
|
||||||
|
server_client_is_bracket_pasting(struct client *c, key_code key)
|
||||||
|
{
|
||||||
|
if (key == KEYC_PASTE_START) {
|
||||||
|
c->flags |= CLIENT_BRACKETPASTING;
|
||||||
|
log_debug("%s: bracket paste on", c->name);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key == KEYC_PASTE_END) {
|
||||||
|
c->flags &= ~CLIENT_BRACKETPASTING;
|
||||||
|
log_debug("%s: bracket paste off", c->name);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return !!(c->flags & CLIENT_BRACKETPASTING);
|
||||||
|
}
|
||||||
|
|
||||||
/* Is this fast enough to probably be a paste? */
|
/* Is this fast enough to probably be a paste? */
|
||||||
static int
|
static int
|
||||||
server_client_assume_paste(struct session *s)
|
server_client_assume_paste(struct session *s)
|
||||||
@ -1862,8 +1882,14 @@ server_client_key_callback(struct cmdq_item *item, void *data)
|
|||||||
if (KEYC_IS_MOUSE(key) && !options_get_number(s->options, "mouse"))
|
if (KEYC_IS_MOUSE(key) && !options_get_number(s->options, "mouse"))
|
||||||
goto forward_key;
|
goto forward_key;
|
||||||
|
|
||||||
|
/* Forward if bracket pasting. */
|
||||||
|
if (server_client_is_bracket_pasting(c, key))
|
||||||
|
goto forward_key;
|
||||||
|
|
||||||
/* Treat everything as a regular key when pasting is detected. */
|
/* Treat everything as a regular key when pasting is detected. */
|
||||||
if (!KEYC_IS_MOUSE(key) && server_client_assume_paste(s))
|
if (!KEYC_IS_MOUSE(key) &&
|
||||||
|
(~key & KEYC_SENT) &&
|
||||||
|
server_client_assume_paste(s))
|
||||||
goto forward_key;
|
goto forward_key;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -3214,3 +3240,69 @@ server_client_remove_pane(struct window_pane *wp)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Print to a client. */
|
||||||
|
void
|
||||||
|
server_client_print(struct client *c, int parse, struct evbuffer *evb)
|
||||||
|
{
|
||||||
|
void *data = EVBUFFER_DATA(evb);
|
||||||
|
size_t size = EVBUFFER_LENGTH(evb);
|
||||||
|
struct window_pane *wp;
|
||||||
|
struct window_mode_entry *wme;
|
||||||
|
char *sanitized, *msg, *line;
|
||||||
|
|
||||||
|
if (!parse) {
|
||||||
|
utf8_stravisx(&msg, data, size,
|
||||||
|
VIS_OCTAL|VIS_CSTYLE|VIS_NOSLASH);
|
||||||
|
log_debug("%s: %s", __func__, msg);
|
||||||
|
} else {
|
||||||
|
msg = EVBUFFER_DATA(evb);
|
||||||
|
if (msg[size - 1] != '\0')
|
||||||
|
evbuffer_add(evb, "", 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == NULL)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (c->session == NULL || (c->flags & CLIENT_CONTROL)) {
|
||||||
|
if (~c->flags & CLIENT_UTF8) {
|
||||||
|
sanitized = utf8_sanitize(msg);
|
||||||
|
if (c->flags & CLIENT_CONTROL)
|
||||||
|
control_write(c, "%s", sanitized);
|
||||||
|
else
|
||||||
|
file_print(c, "%s\n", sanitized);
|
||||||
|
free(sanitized);
|
||||||
|
} else {
|
||||||
|
if (c->flags & CLIENT_CONTROL)
|
||||||
|
control_write(c, "%s", msg);
|
||||||
|
else
|
||||||
|
file_print(c, "%s\n", msg);
|
||||||
|
}
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
wp = server_client_get_pane(c);
|
||||||
|
wme = TAILQ_FIRST(&wp->modes);
|
||||||
|
if (wme == NULL || wme->mode != &window_view_mode)
|
||||||
|
window_pane_set_mode(wp, NULL, &window_view_mode, NULL, NULL);
|
||||||
|
if (parse) {
|
||||||
|
do {
|
||||||
|
line = evbuffer_readln(evb, NULL, EVBUFFER_EOL_LF);
|
||||||
|
if (line != NULL) {
|
||||||
|
window_copy_add(wp, 1, "%s", line);
|
||||||
|
free(line);
|
||||||
|
}
|
||||||
|
} while (line != NULL);
|
||||||
|
|
||||||
|
size = EVBUFFER_LENGTH(evb);
|
||||||
|
if (size != 0) {
|
||||||
|
line = EVBUFFER_DATA(evb);
|
||||||
|
window_copy_add(wp, 1, "%.*s", (int)size, line);
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
window_copy_add(wp, 0, "%s", msg);
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (!parse)
|
||||||
|
free(msg);
|
||||||
|
}
|
||||||
|
4
status.c
4
status.c
@ -1766,7 +1766,7 @@ status_prompt_complete_list_menu(struct client *c, char **list, u_int size,
|
|||||||
else
|
else
|
||||||
offset = 0;
|
offset = 0;
|
||||||
|
|
||||||
if (menu_display(menu, MENU_NOMOUSE|MENU_TAB, NULL, offset,
|
if (menu_display(menu, MENU_NOMOUSE|MENU_TAB, 0, NULL, offset,
|
||||||
py, c, NULL, status_prompt_menu_callback, spm) != 0) {
|
py, c, NULL, status_prompt_menu_callback, spm) != 0) {
|
||||||
menu_free(menu);
|
menu_free(menu);
|
||||||
free(spm);
|
free(spm);
|
||||||
@ -1859,7 +1859,7 @@ status_prompt_complete_window_menu(struct client *c, struct session *s,
|
|||||||
else
|
else
|
||||||
offset = 0;
|
offset = 0;
|
||||||
|
|
||||||
if (menu_display(menu, MENU_NOMOUSE|MENU_TAB, NULL, offset,
|
if (menu_display(menu, MENU_NOMOUSE|MENU_TAB, 0, NULL, offset,
|
||||||
py, c, NULL, status_prompt_menu_callback, spm) != 0) {
|
py, c, NULL, status_prompt_menu_callback, spm) != 0) {
|
||||||
menu_free(menu);
|
menu_free(menu);
|
||||||
free(spm);
|
free(spm);
|
||||||
|
@ -66,7 +66,8 @@ enum msgtype {
|
|||||||
MSG_WRITE_OPEN,
|
MSG_WRITE_OPEN,
|
||||||
MSG_WRITE,
|
MSG_WRITE,
|
||||||
MSG_WRITE_READY,
|
MSG_WRITE_READY,
|
||||||
MSG_WRITE_CLOSE
|
MSG_WRITE_CLOSE,
|
||||||
|
MSG_READ_CANCEL
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -92,6 +93,10 @@ struct msg_read_done {
|
|||||||
int error;
|
int error;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct msg_read_cancel {
|
||||||
|
int stream;
|
||||||
|
};
|
||||||
|
|
||||||
struct msg_write_open {
|
struct msg_write_open {
|
||||||
int stream;
|
int stream;
|
||||||
int fd;
|
int fd;
|
||||||
|
120
tmux.1
120
tmux.1
@ -469,7 +469,8 @@ and
|
|||||||
.Ic confirm-before ,
|
.Ic confirm-before ,
|
||||||
parse their argument to create a new command which is inserted immediately
|
parse their argument to create a new command which is inserted immediately
|
||||||
after themselves.
|
after themselves.
|
||||||
This means that arguments can be parsed twice or more - once when the parent command (such as
|
This means that arguments can be parsed twice or more - once when the parent
|
||||||
|
command (such as
|
||||||
.Ic if-shell )
|
.Ic if-shell )
|
||||||
is parsed and again when it parses and executes its command.
|
is parsed and again when it parses and executes its command.
|
||||||
Commands like
|
Commands like
|
||||||
@ -545,7 +546,7 @@ for example in these
|
|||||||
.Xr sh 1
|
.Xr sh 1
|
||||||
commands:
|
commands:
|
||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
$ tmux neww\e\e; splitw
|
$ tmux neww\e; splitw
|
||||||
.Ed
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
Or:
|
Or:
|
||||||
@ -887,8 +888,8 @@ may consist entirely of the token
|
|||||||
.Ql {mouse}
|
.Ql {mouse}
|
||||||
(alternative form
|
(alternative form
|
||||||
.Ql = )
|
.Ql = )
|
||||||
to specify the session, window or pane where the most recent mouse event occurred
|
to specify the session, window or pane where the most recent mouse event
|
||||||
(see the
|
occurred (see the
|
||||||
.Sx MOUSE SUPPORT
|
.Sx MOUSE SUPPORT
|
||||||
section)
|
section)
|
||||||
or
|
or
|
||||||
@ -964,7 +965,7 @@ Will run
|
|||||||
directly without invoking the shell.
|
directly without invoking the shell.
|
||||||
.Pp
|
.Pp
|
||||||
.Ar command
|
.Ar command
|
||||||
.Op Ar arguments
|
.Op Ar argument ...
|
||||||
refers to a
|
refers to a
|
||||||
.Nm
|
.Nm
|
||||||
command, either passed with the command and arguments separately, for example:
|
command, either passed with the command and arguments separately, for example:
|
||||||
@ -1167,13 +1168,17 @@ session.
|
|||||||
.Tg lsc
|
.Tg lsc
|
||||||
.It Xo Ic list-clients
|
.It Xo Ic list-clients
|
||||||
.Op Fl F Ar format
|
.Op Fl F Ar format
|
||||||
|
.Op Fl f Ar filter
|
||||||
.Op Fl t Ar target-session
|
.Op Fl t Ar target-session
|
||||||
.Xc
|
.Xc
|
||||||
.D1 Pq alias: Ic lsc
|
.D1 Pq alias: Ic lsc
|
||||||
List all clients attached to the server.
|
List all clients attached to the server.
|
||||||
For the meaning of the
|
|
||||||
.Fl F
|
.Fl F
|
||||||
flag, see the
|
specifies the format of each line and
|
||||||
|
.Fl f
|
||||||
|
a filter.
|
||||||
|
Only clients for which the filter is true are shown.
|
||||||
|
See the
|
||||||
.Sx FORMATS
|
.Sx FORMATS
|
||||||
section.
|
section.
|
||||||
If
|
If
|
||||||
@ -1460,7 +1465,7 @@ requests the clipboard from the client using the
|
|||||||
.Xr xterm 1
|
.Xr xterm 1
|
||||||
escape sequence.
|
escape sequence.
|
||||||
If
|
If
|
||||||
Ar target-pane
|
.Ar target-pane
|
||||||
is given, the clipboard is sent (in encoded form), otherwise it is stored in a
|
is given, the clipboard is sent (in encoded form), otherwise it is stored in a
|
||||||
new paste buffer.
|
new paste buffer.
|
||||||
.Pp
|
.Pp
|
||||||
@ -1541,8 +1546,7 @@ show debugging information about jobs and terminals.
|
|||||||
.Tg source
|
.Tg source
|
||||||
.It Xo Ic source-file
|
.It Xo Ic source-file
|
||||||
.Op Fl Fnqv
|
.Op Fl Fnqv
|
||||||
.Ar path
|
.Ar path ...
|
||||||
.Ar ...
|
|
||||||
.Xc
|
.Xc
|
||||||
.D1 Pq alias: Ic source
|
.D1 Pq alias: Ic source
|
||||||
Execute commands from one or more files specified by
|
Execute commands from one or more files specified by
|
||||||
@ -1574,7 +1578,8 @@ server, if not already running, without creating any sessions.
|
|||||||
.Pp
|
.Pp
|
||||||
Note that as by default the
|
Note that as by default the
|
||||||
.Nm
|
.Nm
|
||||||
server will exit with no sessions, this is only useful if a session is created in
|
server will exit with no sessions, this is only useful if a session is created
|
||||||
|
in
|
||||||
.Pa ~/.tmux.conf ,
|
.Pa ~/.tmux.conf ,
|
||||||
.Ic exit-empty
|
.Ic exit-empty
|
||||||
is turned off, or another command is run as part of the same command sequence.
|
is turned off, or another command is run as part of the same command sequence.
|
||||||
@ -1929,7 +1934,8 @@ bind PageUp copy-mode -eu
|
|||||||
.Ed
|
.Ed
|
||||||
.El
|
.El
|
||||||
.Pp
|
.Pp
|
||||||
A number of preset arrangements of panes are available, these are called layouts.
|
A number of preset arrangements of panes are available, these are called
|
||||||
|
layouts.
|
||||||
These may be selected with the
|
These may be selected with the
|
||||||
.Ic select-layout
|
.Ic select-layout
|
||||||
command or cycled with
|
command or cycled with
|
||||||
@ -1975,7 +1981,7 @@ For example:
|
|||||||
$ tmux list-windows
|
$ tmux list-windows
|
||||||
0: ksh [159x48]
|
0: ksh [159x48]
|
||||||
layout: bb62,159x48,0,0{79x48,0,0,79x48,80,0}
|
layout: bb62,159x48,0,0{79x48,0,0,79x48,80,0}
|
||||||
$ tmux select-layout bb62,159x48,0,0{79x48,0,0,79x48,80,0}
|
$ tmux select-layout 'bb62,159x48,0,0{79x48,0,0,79x48,80,0}'
|
||||||
.Ed
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
.Nm
|
.Nm
|
||||||
@ -3123,7 +3129,7 @@ Commands related to key bindings are as follows:
|
|||||||
.Op Fl nr
|
.Op Fl nr
|
||||||
.Op Fl N Ar note
|
.Op Fl N Ar note
|
||||||
.Op Fl T Ar key-table
|
.Op Fl T Ar key-table
|
||||||
.Ar key command Op Ar arguments
|
.Ar key command Op Ar argument ...
|
||||||
.Xc
|
.Xc
|
||||||
.D1 Pq alias: Ic bind
|
.D1 Pq alias: Ic bind
|
||||||
Bind key
|
Bind key
|
||||||
@ -3215,13 +3221,14 @@ lists only the first matching key.
|
|||||||
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
|
||||||
.It Xo Ic send-keys
|
.It Xo Ic send-keys
|
||||||
.Op Fl FHlMRX
|
.Op Fl FHKlMRX
|
||||||
|
.Op Fl c Ar target-client
|
||||||
.Op Fl N Ar repeat-count
|
.Op Fl N Ar repeat-count
|
||||||
.Op Fl t Ar target-pane
|
.Op Fl t Ar target-pane
|
||||||
.Ar key Ar ...
|
.Ar key ...
|
||||||
.Xc
|
.Xc
|
||||||
.D1 Pq alias: Ic send
|
.D1 Pq alias: Ic send
|
||||||
Send a key or keys to a window.
|
Send a key or keys to a window or client.
|
||||||
Each argument
|
Each argument
|
||||||
.Ar key
|
.Ar key
|
||||||
is the name of the key (such as
|
is the name of the key (such as
|
||||||
@ -3230,6 +3237,12 @@ or
|
|||||||
.Ql NPage )
|
.Ql NPage )
|
||||||
to send; if the string is not recognised as a key, it is sent as a series of
|
to send; if the string is not recognised as a key, it is sent as a series of
|
||||||
characters.
|
characters.
|
||||||
|
If
|
||||||
|
.Fl K
|
||||||
|
is given, keys are sent to
|
||||||
|
.Ar target-client ,
|
||||||
|
so they are looked up in the client's key table, rather than to
|
||||||
|
.Ar target-pane .
|
||||||
All arguments are sent sequentially from first to last.
|
All arguments are sent sequentially from first to last.
|
||||||
If no keys are given and the command is bound to a key, then that key is used.
|
If no keys are given and the command is bound to a key, then that key is used.
|
||||||
.Pp
|
.Pp
|
||||||
@ -3690,6 +3703,8 @@ Supports the overline SGR attribute.
|
|||||||
Supports the DECFRA rectangle fill escape sequence.
|
Supports the DECFRA rectangle fill escape sequence.
|
||||||
.It RGB
|
.It RGB
|
||||||
Supports RGB colour with the SGR escape sequences.
|
Supports RGB colour with the SGR escape sequences.
|
||||||
|
.It sixel
|
||||||
|
Supports SIXEL graphics.
|
||||||
.It strikethrough
|
.It strikethrough
|
||||||
Supports the strikethrough SGR escape sequence.
|
Supports the strikethrough SGR escape sequence.
|
||||||
.It sync
|
.It sync
|
||||||
@ -4586,7 +4601,8 @@ hook and there are a number of hooks not associated with commands.
|
|||||||
.Pp
|
.Pp
|
||||||
Hooks are stored as array options, members of the array are executed in
|
Hooks are stored as array options, members of the array are executed in
|
||||||
order when the hook is triggered.
|
order when the hook is triggered.
|
||||||
Like options different hooks may be global or belong to a session, window or pane.
|
Like options different hooks may be global or belong to a session, window or
|
||||||
|
pane.
|
||||||
Hooks may be configured with the
|
Hooks may be configured with the
|
||||||
.Ic set-hook
|
.Ic set-hook
|
||||||
or
|
or
|
||||||
@ -4769,7 +4785,8 @@ or
|
|||||||
.Ar target-pane
|
.Ar target-pane
|
||||||
in commands bound to mouse key bindings.
|
in commands bound to mouse key bindings.
|
||||||
It resolves to the window or pane over which the mouse event took place
|
It resolves to the window or pane over which the mouse event took place
|
||||||
(for example, the window in the status line over which button 1 was released for a
|
(for example, the window in the status line over which button 1 was released
|
||||||
|
for a
|
||||||
.Ql MouseUp1Status
|
.Ql MouseUp1Status
|
||||||
binding, or the pane over which the wheel was scrolled for a
|
binding, or the pane over which the wheel was scrolled for a
|
||||||
.Ql WheelDownPane
|
.Ql WheelDownPane
|
||||||
@ -4909,13 +4926,16 @@ ignores case.
|
|||||||
For example:
|
For example:
|
||||||
.Ql #{C/r:^Start}
|
.Ql #{C/r:^Start}
|
||||||
.Pp
|
.Pp
|
||||||
Numeric operators may be performed by prefixing two comma-separated alternatives with an
|
Numeric operators may be performed by prefixing two comma-separated alternatives
|
||||||
|
with an
|
||||||
.Ql e
|
.Ql e
|
||||||
and an operator.
|
and an operator.
|
||||||
An optional
|
An optional
|
||||||
.Ql f
|
.Ql f
|
||||||
flag may be given after the operator to use floating point numbers, otherwise integers are used.
|
flag may be given after the operator to use floating point numbers, otherwise
|
||||||
This may be followed by a number giving the number of decimal places to use for the result.
|
integers are used.
|
||||||
|
This may be followed by a number giving the number of decimal places to use for
|
||||||
|
the result.
|
||||||
The available operators are:
|
The available operators are:
|
||||||
addition
|
addition
|
||||||
.Ql + ,
|
.Ql + ,
|
||||||
@ -5045,10 +5065,11 @@ but also expands
|
|||||||
.Xr strftime 3
|
.Xr strftime 3
|
||||||
specifiers.
|
specifiers.
|
||||||
.Ql S:\& ,
|
.Ql S:\& ,
|
||||||
.Ql W:\&
|
.Ql W:\& ,
|
||||||
or
|
|
||||||
.Ql P:\&
|
.Ql P:\&
|
||||||
will loop over each session, window or pane and insert the format once
|
or
|
||||||
|
.Ql L:\&
|
||||||
|
will loop over each session, window, pane or client and insert the format once
|
||||||
for each.
|
for each.
|
||||||
For windows and panes, two comma-separated formats may be given:
|
For windows and panes, two comma-separated formats may be given:
|
||||||
the second is used for the current window or active pane.
|
the second is used for the current window or active pane.
|
||||||
@ -5075,7 +5096,8 @@ will substitute
|
|||||||
with
|
with
|
||||||
.Ql bar
|
.Ql bar
|
||||||
throughout.
|
throughout.
|
||||||
The first argument may be an extended regular expression and a final argument may be
|
The first argument may be an extended regular expression and a final argument
|
||||||
|
may be
|
||||||
.Ql i
|
.Ql i
|
||||||
to ignore case, for example
|
to ignore case, for example
|
||||||
.Ql s/a(.)/\e1x/i:\&
|
.Ql s/a(.)/\e1x/i:\&
|
||||||
@ -5083,6 +5105,15 @@ would change
|
|||||||
.Ql abABab
|
.Ql abABab
|
||||||
into
|
into
|
||||||
.Ql bxBxbx .
|
.Ql bxBxbx .
|
||||||
|
A different delimiter character may also be used, to avoid collisions with
|
||||||
|
literal slashes in the pattern.
|
||||||
|
For example,
|
||||||
|
.Ql s|foo/|bar/|:\&
|
||||||
|
will substitute
|
||||||
|
.Ql foo/
|
||||||
|
with
|
||||||
|
.Ql bar/
|
||||||
|
throughout.
|
||||||
.Pp
|
.Pp
|
||||||
In addition, the last line of a shell command's output may be inserted using
|
In addition, the last line of a shell command's output may be inserted using
|
||||||
.Ql #() .
|
.Ql #() .
|
||||||
@ -5093,10 +5124,10 @@ When constructing formats,
|
|||||||
.Nm
|
.Nm
|
||||||
does not wait for
|
does not wait for
|
||||||
.Ql #()
|
.Ql #()
|
||||||
commands to finish; instead, the previous result from running the same command is used,
|
commands to finish; instead, the previous result from running the same command
|
||||||
or a placeholder if the command has not been run before.
|
is used, or a placeholder if the command has not been run before.
|
||||||
If the command hasn't exited, the most recent line of output will be used, but the status
|
If the command hasn't exited, the most recent line of output will be used, but
|
||||||
line will not be updated more than once a second.
|
the status line will not be updated more than once a second.
|
||||||
Commands are executed using
|
Commands are executed using
|
||||||
.Pa /bin/sh
|
.Pa /bin/sh
|
||||||
and with the
|
and with the
|
||||||
@ -5397,8 +5428,8 @@ option:
|
|||||||
.Ic list=on
|
.Ic list=on
|
||||||
marks the start of the list;
|
marks the start of the list;
|
||||||
.Ic list=focus
|
.Ic list=focus
|
||||||
is the part of the list that should be kept in focus if the entire list won't fit
|
is the part of the list that should be kept in focus if the entire list won't
|
||||||
in the available space (typically the current window);
|
fit in the available space (typically the current window);
|
||||||
.Ic list=left-marker
|
.Ic list=left-marker
|
||||||
and
|
and
|
||||||
.Ic list=right-marker
|
.Ic list=right-marker
|
||||||
@ -5801,13 +5832,13 @@ until it is dismissed.
|
|||||||
.Op Fl O
|
.Op Fl O
|
||||||
.Op Fl c Ar target-client
|
.Op Fl c Ar target-client
|
||||||
.Op Fl t Ar target-pane
|
.Op Fl t Ar target-pane
|
||||||
|
.Op Fl S Ar starting-choice
|
||||||
.Op Fl T Ar title
|
.Op Fl T Ar title
|
||||||
.Op Fl x Ar position
|
.Op Fl x Ar position
|
||||||
.Op Fl y Ar position
|
.Op Fl y Ar position
|
||||||
.Ar name
|
.Ar name
|
||||||
.Ar key
|
.Ar key
|
||||||
.Ar command
|
.Ar command Op Ar argument ...
|
||||||
.Ar ...
|
|
||||||
.Xc
|
.Xc
|
||||||
.D1 Pq alias: Ic menu
|
.D1 Pq alias: Ic menu
|
||||||
Display a menu on
|
Display a menu on
|
||||||
@ -5831,6 +5862,9 @@ command should be omitted.
|
|||||||
.Fl T
|
.Fl T
|
||||||
is a format for the menu title (see
|
is a format for the menu title (see
|
||||||
.Sx FORMATS ) .
|
.Sx FORMATS ) .
|
||||||
|
.Fl S
|
||||||
|
sets the menu item selected by default, if the menu is not bound to a mouse key
|
||||||
|
binding.
|
||||||
.Pp
|
.Pp
|
||||||
.Fl x
|
.Fl x
|
||||||
and
|
and
|
||||||
@ -6545,8 +6579,8 @@ and matching
|
|||||||
.Em %end
|
.Em %end
|
||||||
or
|
or
|
||||||
.Em %error
|
.Em %error
|
||||||
have three arguments: an integer time (as seconds from epoch), command number and
|
have three arguments: an integer time (as seconds from epoch), command number
|
||||||
flags (currently not used).
|
and flags (currently not used).
|
||||||
For example:
|
For example:
|
||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
%begin 1363006971 2 1
|
%begin 1363006971 2 1
|
||||||
@ -6596,11 +6630,17 @@ sent when the
|
|||||||
.Ar pause-after
|
.Ar pause-after
|
||||||
flag is set.
|
flag is set.
|
||||||
.Ar age
|
.Ar age
|
||||||
is the time in milliseconds for which tmux had buffered the output before it was sent.
|
is the time in milliseconds for which tmux had buffered the output before it
|
||||||
|
was sent.
|
||||||
Any subsequent arguments up until a single
|
Any subsequent arguments up until a single
|
||||||
.Ql \&:
|
.Ql \&:
|
||||||
are for future use and should be ignored.
|
are for future use and should be ignored.
|
||||||
.It Ic %layout-change Ar window-id Ar window-layout Ar window-visible-layout Ar window-flags
|
.It Xo Ic %layout-change
|
||||||
|
.Ar window-id
|
||||||
|
.Ar window-layout
|
||||||
|
.Ar window-visible-layout
|
||||||
|
.Ar window-flags
|
||||||
|
.Xc
|
||||||
The layout of a window with ID
|
The layout of a window with ID
|
||||||
.Ar window-id
|
.Ar window-id
|
||||||
changed.
|
changed.
|
||||||
@ -6610,6 +6650,10 @@ The window's visible layout is
|
|||||||
.Ar window-visible-layout
|
.Ar window-visible-layout
|
||||||
and the window flags are
|
and the window flags are
|
||||||
.Ar window-flags .
|
.Ar window-flags .
|
||||||
|
.It Ic %message Ar message
|
||||||
|
A message sent with the
|
||||||
|
.Ic display-message
|
||||||
|
command.
|
||||||
.It Ic %output Ar pane-id Ar value
|
.It Ic %output Ar pane-id Ar value
|
||||||
A window pane produced output.
|
A window pane produced output.
|
||||||
.Ar value
|
.Ar value
|
||||||
|
39
tmux.h
39
tmux.h
@ -133,13 +133,14 @@ struct winlink;
|
|||||||
#define KEYC_SHIFT 0x00400000000000ULL
|
#define KEYC_SHIFT 0x00400000000000ULL
|
||||||
|
|
||||||
/* Key flag bits. */
|
/* Key flag bits. */
|
||||||
#define KEYC_LITERAL 0x01000000000000ULL
|
#define KEYC_LITERAL 0x01000000000000ULL
|
||||||
#define KEYC_KEYPAD 0x02000000000000ULL
|
#define KEYC_KEYPAD 0x02000000000000ULL
|
||||||
#define KEYC_CURSOR 0x04000000000000ULL
|
#define KEYC_CURSOR 0x04000000000000ULL
|
||||||
#define KEYC_IMPLIED_META 0x08000000000000ULL
|
#define KEYC_IMPLIED_META 0x08000000000000ULL
|
||||||
#define KEYC_BUILD_MODIFIERS 0x10000000000000ULL
|
#define KEYC_BUILD_MODIFIERS 0x10000000000000ULL
|
||||||
#define KEYC_VI 0x20000000000000ULL
|
#define KEYC_VI 0x20000000000000ULL
|
||||||
#define KEYC_EXTENDED 0x40000000000000ULL
|
#define KEYC_EXTENDED 0x40000000000000ULL
|
||||||
|
#define KEYC_SENT 0x80000000000000ULL
|
||||||
|
|
||||||
/* Masks for key bits. */
|
/* Masks for key bits. */
|
||||||
#define KEYC_MASK_MODIFIERS 0x00f00000000000ULL
|
#define KEYC_MASK_MODIFIERS 0x00f00000000000ULL
|
||||||
@ -1398,6 +1399,8 @@ struct tty {
|
|||||||
u_int osy;
|
u_int osy;
|
||||||
|
|
||||||
int mode;
|
int mode;
|
||||||
|
int fg;
|
||||||
|
int bg;
|
||||||
|
|
||||||
u_int rlower;
|
u_int rlower;
|
||||||
u_int rupper;
|
u_int rupper;
|
||||||
@ -1425,9 +1428,14 @@ struct tty {
|
|||||||
#define TTY_OPENED 0x20
|
#define TTY_OPENED 0x20
|
||||||
#define TTY_OSC52QUERY 0x40
|
#define TTY_OSC52QUERY 0x40
|
||||||
#define TTY_BLOCK 0x80
|
#define TTY_BLOCK 0x80
|
||||||
#define TTY_HAVEDA 0x100
|
#define TTY_HAVEDA 0x100 /* Primary DA. */
|
||||||
#define TTY_HAVEXDA 0x200
|
#define TTY_HAVEXDA 0x200
|
||||||
#define TTY_SYNCING 0x400
|
#define TTY_SYNCING 0x400
|
||||||
|
#define TTY_HAVEDA2 0x800 /* Secondary DA. */
|
||||||
|
#define TTY_HAVEFG 0x1000
|
||||||
|
#define TTY_HAVEBG 0x2000
|
||||||
|
#define TTY_ALL_REQUEST_FLAGS \
|
||||||
|
(TTY_HAVEDA|TTY_HAVEDA2|TTY_HAVEXDA|TTY_HAVEFG|TTY_HAVEBG)
|
||||||
int flags;
|
int flags;
|
||||||
|
|
||||||
struct tty_term *term;
|
struct tty_term *term;
|
||||||
@ -1823,6 +1831,7 @@ struct client {
|
|||||||
#define CLIENT_CONTROL_WAITEXIT 0x200000000ULL
|
#define CLIENT_CONTROL_WAITEXIT 0x200000000ULL
|
||||||
#define CLIENT_WINDOWSIZECHANGED 0x400000000ULL
|
#define CLIENT_WINDOWSIZECHANGED 0x400000000ULL
|
||||||
#define CLIENT_CLIPBOARDBUFFER 0x800000000ULL
|
#define CLIENT_CLIPBOARDBUFFER 0x800000000ULL
|
||||||
|
#define CLIENT_BRACKETPASTING 0x1000000000ULL
|
||||||
#define CLIENT_ALLREDRAWFLAGS \
|
#define CLIENT_ALLREDRAWFLAGS \
|
||||||
(CLIENT_REDRAWWINDOW| \
|
(CLIENT_REDRAWWINDOW| \
|
||||||
CLIENT_REDRAWSTATUS| \
|
CLIENT_REDRAWSTATUS| \
|
||||||
@ -2407,7 +2416,7 @@ void tty_keys_free(struct tty *);
|
|||||||
int tty_keys_next(struct tty *);
|
int tty_keys_next(struct tty *);
|
||||||
|
|
||||||
/* arguments.c */
|
/* arguments.c */
|
||||||
void args_set(struct args *, u_char, struct args_value *);
|
void args_set(struct args *, u_char, struct args_value *, int);
|
||||||
struct args *args_create(void);
|
struct args *args_create(void);
|
||||||
struct args *args_parse(const struct args_parse *, struct args_value *,
|
struct args *args_parse(const struct args_parse *, struct args_value *,
|
||||||
u_int, char **);
|
u_int, char **);
|
||||||
@ -2570,6 +2579,7 @@ u_int cmdq_next(struct client *);
|
|||||||
struct cmdq_item *cmdq_running(struct client *);
|
struct cmdq_item *cmdq_running(struct client *);
|
||||||
void cmdq_guard(struct cmdq_item *, const char *, int);
|
void cmdq_guard(struct cmdq_item *, const char *, int);
|
||||||
void printflike(2, 3) cmdq_print(struct cmdq_item *, const char *, ...);
|
void printflike(2, 3) cmdq_print(struct cmdq_item *, const char *, ...);
|
||||||
|
void cmdq_print_data(struct cmdq_item *, int, struct evbuffer *);
|
||||||
void printflike(2, 3) cmdq_error(struct cmdq_item *, const char *, ...);
|
void printflike(2, 3) cmdq_error(struct cmdq_item *, const char *, ...);
|
||||||
|
|
||||||
/* cmd-wait-for.c */
|
/* cmd-wait-for.c */
|
||||||
@ -2624,7 +2634,9 @@ void file_print_buffer(struct client *, void *, size_t);
|
|||||||
void printflike(2, 3) file_error(struct client *, const char *, ...);
|
void printflike(2, 3) file_error(struct client *, const char *, ...);
|
||||||
void file_write(struct client *, const char *, int, const void *, size_t,
|
void file_write(struct client *, const char *, int, const void *, size_t,
|
||||||
client_file_cb, void *);
|
client_file_cb, void *);
|
||||||
void file_read(struct client *, const char *, client_file_cb, void *);
|
struct client_file *file_read(struct client *, const char *, client_file_cb,
|
||||||
|
void *);
|
||||||
|
void file_cancel(struct client_file *);
|
||||||
void file_push(struct client_file *);
|
void file_push(struct client_file *);
|
||||||
int file_write_left(struct client_files *);
|
int file_write_left(struct client_files *);
|
||||||
void file_write_open(struct client_files *, struct tmuxpeer *,
|
void file_write_open(struct client_files *, struct tmuxpeer *,
|
||||||
@ -2636,6 +2648,7 @@ void file_read_open(struct client_files *, struct tmuxpeer *, struct imsg *,
|
|||||||
void file_write_ready(struct client_files *, struct imsg *);
|
void file_write_ready(struct client_files *, struct imsg *);
|
||||||
void file_read_data(struct client_files *, struct imsg *);
|
void file_read_data(struct client_files *, struct imsg *);
|
||||||
void file_read_done(struct client_files *, struct imsg *);
|
void file_read_done(struct client_files *, struct imsg *);
|
||||||
|
void file_read_cancel(struct client_files *, struct imsg *);
|
||||||
|
|
||||||
/* server.c */
|
/* server.c */
|
||||||
extern struct tmuxproc *server_proc;
|
extern struct tmuxproc *server_proc;
|
||||||
@ -2687,6 +2700,7 @@ struct client_window *server_client_add_client_window(struct client *, u_int);
|
|||||||
struct window_pane *server_client_get_pane(struct client *);
|
struct window_pane *server_client_get_pane(struct client *);
|
||||||
void server_client_set_pane(struct client *, struct window_pane *);
|
void server_client_set_pane(struct client *, struct window_pane *);
|
||||||
void server_client_remove_pane(struct window_pane *);
|
void server_client_remove_pane(struct window_pane *);
|
||||||
|
void server_client_print(struct client *, int, struct evbuffer *);
|
||||||
|
|
||||||
/* server-fn.c */
|
/* server-fn.c */
|
||||||
void server_redraw_client(struct client *);
|
void server_redraw_client(struct client *);
|
||||||
@ -2779,6 +2793,7 @@ int colour_fromstring(const char *s);
|
|||||||
int colour_256toRGB(int);
|
int colour_256toRGB(int);
|
||||||
int colour_256to16(int);
|
int colour_256to16(int);
|
||||||
int colour_byname(const char *);
|
int colour_byname(const char *);
|
||||||
|
int colour_parseX11(const char *);
|
||||||
void colour_palette_init(struct colour_palette *);
|
void colour_palette_init(struct colour_palette *);
|
||||||
void colour_palette_clear(struct colour_palette *);
|
void colour_palette_clear(struct colour_palette *);
|
||||||
void colour_palette_free(struct colour_palette *);
|
void colour_palette_free(struct colour_palette *);
|
||||||
@ -3303,11 +3318,11 @@ void menu_add_item(struct menu *, const struct menu_item *,
|
|||||||
struct cmdq_item *, struct client *,
|
struct cmdq_item *, struct client *,
|
||||||
struct cmd_find_state *);
|
struct cmd_find_state *);
|
||||||
void menu_free(struct menu *);
|
void menu_free(struct menu *);
|
||||||
struct menu_data *menu_prepare(struct menu *, int, struct cmdq_item *, u_int,
|
struct menu_data *menu_prepare(struct menu *, int, int, struct cmdq_item *,
|
||||||
u_int, struct client *, struct cmd_find_state *,
|
u_int, u_int, struct client *, struct cmd_find_state *,
|
||||||
menu_choice_cb, void *);
|
menu_choice_cb, void *);
|
||||||
int menu_display(struct menu *, int, struct cmdq_item *, u_int,
|
int menu_display(struct menu *, int, int, struct cmdq_item *,
|
||||||
u_int, struct client *, struct cmd_find_state *,
|
u_int, u_int, struct client *, struct cmd_find_state *,
|
||||||
menu_choice_cb, void *);
|
menu_choice_cb, void *);
|
||||||
struct screen *menu_mode_cb(struct client *, void *, u_int *, u_int *);
|
struct screen *menu_mode_cb(struct client *, void *, u_int *, u_int *);
|
||||||
void menu_check_cb(struct client *, void *, u_int, u_int, u_int,
|
void menu_check_cb(struct client *, void *, u_int, u_int, u_int,
|
||||||
|
@ -345,6 +345,17 @@ static const struct tty_feature tty_feature_ignorefkeys = {
|
|||||||
0
|
0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Terminal has sixel capability. */
|
||||||
|
static const char *const tty_feature_sixel_capabilities[] = {
|
||||||
|
"Sxl",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
static const struct tty_feature tty_feature_sixel = {
|
||||||
|
"sixel",
|
||||||
|
tty_feature_sixel_capabilities,
|
||||||
|
TERM_SIXEL
|
||||||
|
};
|
||||||
|
|
||||||
/* Available terminal features. */
|
/* Available terminal features. */
|
||||||
static const struct tty_feature *const tty_features[] = {
|
static const struct tty_feature *const tty_features[] = {
|
||||||
&tty_feature_256,
|
&tty_feature_256,
|
||||||
@ -362,6 +373,7 @@ static const struct tty_feature *const tty_features[] = {
|
|||||||
&tty_feature_overline,
|
&tty_feature_overline,
|
||||||
&tty_feature_rectfill,
|
&tty_feature_rectfill,
|
||||||
&tty_feature_rgb,
|
&tty_feature_rgb,
|
||||||
|
&tty_feature_sixel,
|
||||||
&tty_feature_strikethrough,
|
&tty_feature_strikethrough,
|
||||||
&tty_feature_sync,
|
&tty_feature_sync,
|
||||||
&tty_feature_title,
|
&tty_feature_title,
|
||||||
|
217
tty-keys.c
217
tty-keys.c
@ -55,8 +55,11 @@ static int tty_keys_clipboard(struct tty *, const char *, size_t,
|
|||||||
size_t *);
|
size_t *);
|
||||||
static int tty_keys_device_attributes(struct tty *, const char *, size_t,
|
static int tty_keys_device_attributes(struct tty *, const char *, size_t,
|
||||||
size_t *);
|
size_t *);
|
||||||
|
static int tty_keys_device_attributes2(struct tty *, const char *, size_t,
|
||||||
|
size_t *);
|
||||||
static int tty_keys_extended_device_attributes(struct tty *, const char *,
|
static int tty_keys_extended_device_attributes(struct tty *, const char *,
|
||||||
size_t, size_t *);
|
size_t, size_t *);
|
||||||
|
static int tty_keys_colours(struct tty *, const char *, size_t, size_t *);
|
||||||
|
|
||||||
/* A key tree entry. */
|
/* A key tree entry. */
|
||||||
struct tty_key {
|
struct tty_key {
|
||||||
@ -684,7 +687,7 @@ tty_keys_next(struct tty *tty)
|
|||||||
goto partial_key;
|
goto partial_key;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Is this a device attributes response? */
|
/* Is this a primary device attributes response? */
|
||||||
switch (tty_keys_device_attributes(tty, buf, len, &size)) {
|
switch (tty_keys_device_attributes(tty, buf, len, &size)) {
|
||||||
case 0: /* yes */
|
case 0: /* yes */
|
||||||
key = KEYC_UNKNOWN;
|
key = KEYC_UNKNOWN;
|
||||||
@ -695,6 +698,17 @@ tty_keys_next(struct tty *tty)
|
|||||||
goto partial_key;
|
goto partial_key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Is this a secondary device attributes response? */
|
||||||
|
switch (tty_keys_device_attributes2(tty, buf, len, &size)) {
|
||||||
|
case 0: /* yes */
|
||||||
|
key = KEYC_UNKNOWN;
|
||||||
|
goto complete_key;
|
||||||
|
case -1: /* no, or not valid */
|
||||||
|
break;
|
||||||
|
case 1: /* partial */
|
||||||
|
goto partial_key;
|
||||||
|
}
|
||||||
|
|
||||||
/* Is this an extended device attributes response? */
|
/* Is this an extended device attributes response? */
|
||||||
switch (tty_keys_extended_device_attributes(tty, buf, len, &size)) {
|
switch (tty_keys_extended_device_attributes(tty, buf, len, &size)) {
|
||||||
case 0: /* yes */
|
case 0: /* yes */
|
||||||
@ -706,6 +720,17 @@ tty_keys_next(struct tty *tty)
|
|||||||
goto partial_key;
|
goto partial_key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Is this a colours response? */
|
||||||
|
switch (tty_keys_colours(tty, buf, len, &size)) {
|
||||||
|
case 0: /* yes */
|
||||||
|
key = KEYC_UNKNOWN;
|
||||||
|
goto complete_key;
|
||||||
|
case -1: /* no, or not valid */
|
||||||
|
break;
|
||||||
|
case 1: /* partial */
|
||||||
|
goto partial_key;
|
||||||
|
}
|
||||||
|
|
||||||
/* Is this a mouse key press? */
|
/* Is this a mouse key press? */
|
||||||
switch (tty_keys_mouse(tty, buf, len, &size, &m)) {
|
switch (tty_keys_mouse(tty, buf, len, &size, &m)) {
|
||||||
case 0: /* yes */
|
case 0: /* yes */
|
||||||
@ -1242,7 +1267,7 @@ tty_keys_clipboard(struct tty *tty, const char *buf, size_t len, size_t *size)
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Handle secondary device attributes input. Returns 0 for success, -1 for
|
* Handle primary device attributes input. Returns 0 for success, -1 for
|
||||||
* failure, 1 for partial.
|
* failure, 1 for partial.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
@ -1250,17 +1275,15 @@ tty_keys_device_attributes(struct tty *tty, const char *buf, size_t len,
|
|||||||
size_t *size)
|
size_t *size)
|
||||||
{
|
{
|
||||||
struct client *c = tty->client;
|
struct client *c = tty->client;
|
||||||
|
int *features = &c->term_features;
|
||||||
u_int i, n = 0;
|
u_int i, n = 0;
|
||||||
char tmp[64], *endptr, p[32] = { 0 }, *cp, *next;
|
char tmp[128], *endptr, p[32] = { 0 }, *cp, *next;
|
||||||
|
|
||||||
*size = 0;
|
*size = 0;
|
||||||
if (tty->flags & TTY_HAVEDA)
|
if (tty->flags & TTY_HAVEDA)
|
||||||
return (-1);
|
return (-1);
|
||||||
|
|
||||||
/*
|
/* First three bytes are always \033[?. */
|
||||||
* First three bytes are always \033[>. Some older Terminal.app
|
|
||||||
* versions respond as for DA (\033[?) so accept and ignore that.
|
|
||||||
*/
|
|
||||||
if (buf[0] != '\033')
|
if (buf[0] != '\033')
|
||||||
return (-1);
|
return (-1);
|
||||||
if (len == 1)
|
if (len == 1)
|
||||||
@ -1269,56 +1292,127 @@ tty_keys_device_attributes(struct tty *tty, const char *buf, size_t len,
|
|||||||
return (-1);
|
return (-1);
|
||||||
if (len == 2)
|
if (len == 2)
|
||||||
return (1);
|
return (1);
|
||||||
if (buf[2] != '>' && buf[2] != '?')
|
if (buf[2] != '?')
|
||||||
return (-1);
|
return (-1);
|
||||||
if (len == 3)
|
if (len == 3)
|
||||||
return (1);
|
return (1);
|
||||||
|
|
||||||
/* Copy the rest up to a 'c'. */
|
/* Copy the rest up to a c. */
|
||||||
for (i = 0; i < (sizeof tmp) - 1; i++) {
|
for (i = 0; i < (sizeof tmp); i++) {
|
||||||
if (3 + i == len)
|
if (3 + i == len)
|
||||||
return (1);
|
return (1);
|
||||||
if (buf[3 + i] == 'c')
|
if (buf[3 + i] == 'c')
|
||||||
break;
|
break;
|
||||||
tmp[i] = buf[3 + i];
|
tmp[i] = buf[3 + i];
|
||||||
}
|
}
|
||||||
if (i == (sizeof tmp) - 1)
|
if (i == (sizeof tmp))
|
||||||
return (-1);
|
return (-1);
|
||||||
tmp[i] = '\0';
|
tmp[i] = '\0';
|
||||||
*size = 4 + i;
|
*size = 4 + i;
|
||||||
|
|
||||||
/* Ignore DA response. */
|
|
||||||
if (buf[2] == '?')
|
|
||||||
return (0);
|
|
||||||
|
|
||||||
/* Convert all arguments to numbers. */
|
/* Convert all arguments to numbers. */
|
||||||
cp = tmp;
|
cp = tmp;
|
||||||
while ((next = strsep(&cp, ";")) != NULL) {
|
while ((next = strsep(&cp, ";")) != NULL) {
|
||||||
p[n] = strtoul(next, &endptr, 10);
|
p[n] = strtoul(next, &endptr, 10);
|
||||||
if (*endptr != '\0')
|
if (*endptr != '\0')
|
||||||
p[n] = 0;
|
p[n] = 0;
|
||||||
n++;
|
if (++n == nitems(p))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add terminal features. */
|
||||||
|
switch (p[0]) {
|
||||||
|
case 62: /* VT220 */
|
||||||
|
case 63: /* VT320 */
|
||||||
|
case 64: /* VT420 */
|
||||||
|
for (i = 1; i < n; i++) {
|
||||||
|
log_debug("%s: DA feature: %d", c->name, p[i]);
|
||||||
|
if (p[i] == 4)
|
||||||
|
tty_add_features(features, "sixel", ",");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
log_debug("%s: received primary DA %.*s", c->name, (int)*size, buf);
|
||||||
|
|
||||||
|
tty_update_features(tty);
|
||||||
|
tty->flags |= TTY_HAVEDA;
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Handle secondary device attributes input. Returns 0 for success, -1 for
|
||||||
|
* failure, 1 for partial.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
tty_keys_device_attributes2(struct tty *tty, const char *buf, size_t len,
|
||||||
|
size_t *size)
|
||||||
|
{
|
||||||
|
struct client *c = tty->client;
|
||||||
|
int *features = &c->term_features;
|
||||||
|
u_int i, n = 0;
|
||||||
|
char tmp[128], *endptr, p[32] = { 0 }, *cp, *next;
|
||||||
|
|
||||||
|
*size = 0;
|
||||||
|
if (tty->flags & TTY_HAVEDA2)
|
||||||
|
return (-1);
|
||||||
|
|
||||||
|
/* First three bytes are always \033[>. */
|
||||||
|
if (buf[0] != '\033')
|
||||||
|
return (-1);
|
||||||
|
if (len == 1)
|
||||||
|
return (1);
|
||||||
|
if (buf[1] != '[')
|
||||||
|
return (-1);
|
||||||
|
if (len == 2)
|
||||||
|
return (1);
|
||||||
|
if (buf[2] != '>')
|
||||||
|
return (-1);
|
||||||
|
if (len == 3)
|
||||||
|
return (1);
|
||||||
|
|
||||||
|
/* Copy the rest up to a c. */
|
||||||
|
for (i = 0; i < (sizeof tmp); i++) {
|
||||||
|
if (3 + i == len)
|
||||||
|
return (1);
|
||||||
|
if (buf[3 + i] == 'c')
|
||||||
|
break;
|
||||||
|
tmp[i] = buf[3 + i];
|
||||||
|
}
|
||||||
|
if (i == (sizeof tmp))
|
||||||
|
return (-1);
|
||||||
|
tmp[i] = '\0';
|
||||||
|
*size = 4 + i;
|
||||||
|
|
||||||
|
/* Convert all arguments to numbers. */
|
||||||
|
cp = tmp;
|
||||||
|
while ((next = strsep(&cp, ";")) != NULL) {
|
||||||
|
p[n] = strtoul(next, &endptr, 10);
|
||||||
|
if (*endptr != '\0')
|
||||||
|
p[n] = 0;
|
||||||
|
if (++n == nitems(p))
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add terminal features. */
|
/* Add terminal features. */
|
||||||
switch (p[0]) {
|
switch (p[0]) {
|
||||||
case 41: /* VT420 */
|
case 41: /* VT420 */
|
||||||
tty_add_features(&c->term_features, "margins,rectfill", ",");
|
tty_add_features(features, "margins,rectfill", ",");
|
||||||
break;
|
break;
|
||||||
case 'M': /* mintty */
|
case 'M': /* mintty */
|
||||||
tty_default_features(&c->term_features, "mintty", 0);
|
tty_default_features(features, "mintty", 0);
|
||||||
break;
|
break;
|
||||||
case 'T': /* tmux */
|
case 'T': /* tmux */
|
||||||
tty_default_features(&c->term_features, "tmux", 0);
|
tty_default_features(features, "tmux", 0);
|
||||||
break;
|
break;
|
||||||
case 'U': /* rxvt-unicode */
|
case 'U': /* rxvt-unicode */
|
||||||
tty_default_features(&c->term_features, "rxvt-unicode", 0);
|
tty_default_features(features, "rxvt-unicode", 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
log_debug("%s: received secondary DA %.*s", c->name, (int)*size, buf);
|
log_debug("%s: received secondary DA %.*s", c->name, (int)*size, buf);
|
||||||
|
|
||||||
tty_update_features(tty);
|
tty_update_features(tty);
|
||||||
tty->flags |= TTY_HAVEDA;
|
tty->flags |= TTY_HAVEDA2;
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
@ -1332,6 +1426,7 @@ tty_keys_extended_device_attributes(struct tty *tty, const char *buf,
|
|||||||
size_t len, size_t *size)
|
size_t len, size_t *size)
|
||||||
{
|
{
|
||||||
struct client *c = tty->client;
|
struct client *c = tty->client;
|
||||||
|
int *features = &c->term_features;
|
||||||
u_int i;
|
u_int i;
|
||||||
char tmp[128];
|
char tmp[128];
|
||||||
|
|
||||||
@ -1357,7 +1452,7 @@ tty_keys_extended_device_attributes(struct tty *tty, const char *buf,
|
|||||||
if (len == 4)
|
if (len == 4)
|
||||||
return (1);
|
return (1);
|
||||||
|
|
||||||
/* Copy the rest up to a '\033\\'. */
|
/* Copy the rest up to \033\. */
|
||||||
for (i = 0; i < (sizeof tmp) - 1; i++) {
|
for (i = 0; i < (sizeof tmp) - 1; i++) {
|
||||||
if (4 + i == len)
|
if (4 + i == len)
|
||||||
return (1);
|
return (1);
|
||||||
@ -1372,13 +1467,13 @@ tty_keys_extended_device_attributes(struct tty *tty, const char *buf,
|
|||||||
|
|
||||||
/* Add terminal features. */
|
/* Add terminal features. */
|
||||||
if (strncmp(tmp, "iTerm2 ", 7) == 0)
|
if (strncmp(tmp, "iTerm2 ", 7) == 0)
|
||||||
tty_default_features(&c->term_features, "iTerm2", 0);
|
tty_default_features(features, "iTerm2", 0);
|
||||||
else if (strncmp(tmp, "tmux ", 5) == 0)
|
else if (strncmp(tmp, "tmux ", 5) == 0)
|
||||||
tty_default_features(&c->term_features, "tmux", 0);
|
tty_default_features(features, "tmux", 0);
|
||||||
else if (strncmp(tmp, "XTerm(", 6) == 0)
|
else if (strncmp(tmp, "XTerm(", 6) == 0)
|
||||||
tty_default_features(&c->term_features, "XTerm", 0);
|
tty_default_features(features, "XTerm", 0);
|
||||||
else if (strncmp(tmp, "mintty ", 7) == 0)
|
else if (strncmp(tmp, "mintty ", 7) == 0)
|
||||||
tty_default_features(&c->term_features, "mintty", 0);
|
tty_default_features(features, "mintty", 0);
|
||||||
log_debug("%s: received extended DA %.*s", c->name, (int)*size, buf);
|
log_debug("%s: received extended DA %.*s", c->name, (int)*size, buf);
|
||||||
|
|
||||||
free(c->term_type);
|
free(c->term_type);
|
||||||
@ -1389,3 +1484,73 @@ tty_keys_extended_device_attributes(struct tty *tty, const char *buf,
|
|||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Handle foreground or background input. Returns 0 for success, -1 for
|
||||||
|
* failure, 1 for partial.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
tty_keys_colours(struct tty *tty, const char *buf, size_t len, size_t *size)
|
||||||
|
{
|
||||||
|
struct client *c = tty->client;
|
||||||
|
u_int i;
|
||||||
|
char tmp[128];
|
||||||
|
int n;
|
||||||
|
|
||||||
|
*size = 0;
|
||||||
|
if ((tty->flags & TTY_HAVEFG) && (tty->flags & TTY_HAVEBG))
|
||||||
|
return (-1);
|
||||||
|
|
||||||
|
/* First four bytes are always \033]1 and 0 or 1 and ;. */
|
||||||
|
if (buf[0] != '\033')
|
||||||
|
return (-1);
|
||||||
|
if (len == 1)
|
||||||
|
return (1);
|
||||||
|
if (buf[1] != ']')
|
||||||
|
return (-1);
|
||||||
|
if (len == 2)
|
||||||
|
return (1);
|
||||||
|
if (buf[2] != '1')
|
||||||
|
return (-1);
|
||||||
|
if (len == 3)
|
||||||
|
return (1);
|
||||||
|
if (buf[3] != '0' && buf[3] != '1')
|
||||||
|
return (-1);
|
||||||
|
if (len == 4)
|
||||||
|
return (1);
|
||||||
|
if (buf[4] != ';')
|
||||||
|
return (-1);
|
||||||
|
if (len == 5)
|
||||||
|
return (1);
|
||||||
|
|
||||||
|
/* Copy the rest up to \033\ or \007. */
|
||||||
|
for (i = 0; i < (sizeof tmp) - 1; i++) {
|
||||||
|
if (5 + i == len)
|
||||||
|
return (1);
|
||||||
|
if (buf[5 + i - 1] == '\033' && buf[5 + i] == '\\')
|
||||||
|
break;
|
||||||
|
if (buf[5 + i] == '\007')
|
||||||
|
break;
|
||||||
|
tmp[i] = buf[5 + i];
|
||||||
|
}
|
||||||
|
if (i == (sizeof tmp) - 1)
|
||||||
|
return (-1);
|
||||||
|
if (tmp[i - 1] == '\033')
|
||||||
|
tmp[i - 1] = '\0';
|
||||||
|
else
|
||||||
|
tmp[i] = '\0';
|
||||||
|
*size = 6 + i;
|
||||||
|
|
||||||
|
n = colour_parseX11(tmp);
|
||||||
|
if (n != -1 && buf[3] == '0') {
|
||||||
|
log_debug("%s: foreground is %s", c->name, colour_tostring(n));
|
||||||
|
tty->fg = n;
|
||||||
|
tty->flags |= TTY_HAVEFG;
|
||||||
|
} else if (n != -1) {
|
||||||
|
log_debug("%s: background is %s", c->name, colour_tostring(n));
|
||||||
|
tty->bg = n;
|
||||||
|
tty->flags |= TTY_HAVEBG;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
@ -457,6 +457,9 @@ tty_term_apply_overrides(struct tty_term *term)
|
|||||||
a = options_array_next(a);
|
a = options_array_next(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Log the SIXEL flag. */
|
||||||
|
log_debug("SIXEL flag is %d", !!(term->flags & TERM_SIXEL));
|
||||||
|
|
||||||
/* Update the RGB flag if the terminal has RGB colours. */
|
/* Update the RGB flag if the terminal has RGB colours. */
|
||||||
if (tty_term_has(term, TTYC_SETRGBF) &&
|
if (tty_term_has(term, TTYC_SETRGBF) &&
|
||||||
tty_term_has(term, TTYC_SETRGBB))
|
tty_term_has(term, TTYC_SETRGBB))
|
||||||
|
28
tty.c
28
tty.c
@ -108,6 +108,7 @@ tty_init(struct tty *tty, struct client *c)
|
|||||||
|
|
||||||
tty->cstyle = SCREEN_CURSOR_DEFAULT;
|
tty->cstyle = SCREEN_CURSOR_DEFAULT;
|
||||||
tty->ccolour = -1;
|
tty->ccolour = -1;
|
||||||
|
tty->fg = tty->bg = -1;
|
||||||
|
|
||||||
if (tcgetattr(c->fd, &tty->tio) != 0)
|
if (tcgetattr(c->fd, &tty->tio) != 0)
|
||||||
return (-1);
|
return (-1);
|
||||||
@ -286,7 +287,6 @@ tty_open(struct tty *tty, char **cause)
|
|||||||
evtimer_set(&tty->timer, tty_timer_callback, tty);
|
evtimer_set(&tty->timer, tty_timer_callback, tty);
|
||||||
|
|
||||||
tty_start_tty(tty);
|
tty_start_tty(tty);
|
||||||
|
|
||||||
tty_keys_build(tty);
|
tty_keys_build(tty);
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
@ -299,9 +299,9 @@ tty_start_timer_callback(__unused int fd, __unused short events, void *data)
|
|||||||
struct client *c = tty->client;
|
struct client *c = tty->client;
|
||||||
|
|
||||||
log_debug("%s: start timer fired", c->name);
|
log_debug("%s: start timer fired", c->name);
|
||||||
if ((tty->flags & (TTY_HAVEDA|TTY_HAVEXDA)) == 0)
|
if ((tty->flags & (TTY_HAVEDA|TTY_HAVEDA2|TTY_HAVEXDA)) == 0)
|
||||||
tty_update_features(tty);
|
tty_update_features(tty);
|
||||||
tty->flags |= (TTY_HAVEDA|TTY_HAVEXDA);
|
tty->flags |= TTY_ALL_REQUEST_FLAGS;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -341,6 +341,8 @@ tty_start_tty(struct tty *tty)
|
|||||||
tty_puts(tty, "\033[?1000l\033[?1002l\033[?1003l");
|
tty_puts(tty, "\033[?1000l\033[?1002l\033[?1003l");
|
||||||
tty_puts(tty, "\033[?1006l\033[?1005l");
|
tty_puts(tty, "\033[?1006l\033[?1005l");
|
||||||
}
|
}
|
||||||
|
if (tty_term_has(tty->term, TTYC_ENBP))
|
||||||
|
tty_putcode(tty, TTYC_ENBP);
|
||||||
|
|
||||||
evtimer_set(&tty->start_timer, tty_start_timer_callback, tty);
|
evtimer_set(&tty->start_timer, tty_start_timer_callback, tty);
|
||||||
evtimer_add(&tty->start_timer, &tv);
|
evtimer_add(&tty->start_timer, &tv);
|
||||||
@ -363,12 +365,18 @@ tty_send_requests(struct tty *tty)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (tty->term->flags & TERM_VT100LIKE) {
|
if (tty->term->flags & TERM_VT100LIKE) {
|
||||||
if (~tty->flags & TTY_HAVEDA)
|
if (~tty->term->flags & TTY_HAVEDA)
|
||||||
|
tty_puts(tty, "\033[c");
|
||||||
|
if (~tty->flags & TTY_HAVEDA2)
|
||||||
tty_puts(tty, "\033[>c");
|
tty_puts(tty, "\033[>c");
|
||||||
if (~tty->flags & TTY_HAVEXDA)
|
if (~tty->flags & TTY_HAVEXDA)
|
||||||
tty_puts(tty, "\033[>q");
|
tty_puts(tty, "\033[>q");
|
||||||
|
if (~tty->flags & TTY_HAVEFG)
|
||||||
|
tty_puts(tty, "\033]10;?\033\\");
|
||||||
|
if (~tty->flags & TTY_HAVEBG)
|
||||||
|
tty_puts(tty, "\033]11;?\033\\");
|
||||||
} else
|
} else
|
||||||
tty->flags |= (TTY_HAVEDA|TTY_HAVEXDA);
|
tty->flags |= TTY_ALL_REQUEST_FLAGS;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -411,8 +419,6 @@ tty_stop_tty(struct tty *tty)
|
|||||||
else if (tty_term_has(tty->term, TTYC_SS))
|
else if (tty_term_has(tty->term, TTYC_SS))
|
||||||
tty_raw(tty, tty_term_string1(tty->term, TTYC_SS, 0));
|
tty_raw(tty, tty_term_string1(tty->term, TTYC_SS, 0));
|
||||||
}
|
}
|
||||||
if (tty->mode & MODE_BRACKETPASTE)
|
|
||||||
tty_raw(tty, tty_term_string(tty->term, TTYC_DSBP));
|
|
||||||
if (tty->ccolour != -1)
|
if (tty->ccolour != -1)
|
||||||
tty_raw(tty, tty_term_string(tty->term, TTYC_CR));
|
tty_raw(tty, tty_term_string(tty->term, TTYC_CR));
|
||||||
|
|
||||||
@ -421,6 +427,8 @@ tty_stop_tty(struct tty *tty)
|
|||||||
tty_raw(tty, "\033[?1000l\033[?1002l\033[?1003l");
|
tty_raw(tty, "\033[?1000l\033[?1002l\033[?1003l");
|
||||||
tty_raw(tty, "\033[?1006l\033[?1005l");
|
tty_raw(tty, "\033[?1006l\033[?1005l");
|
||||||
}
|
}
|
||||||
|
if (tty_term_has(tty->term, TTYC_DSBP))
|
||||||
|
tty_raw(tty, tty_term_string(tty->term, TTYC_DSBP));
|
||||||
|
|
||||||
if (tty->term->flags & TERM_VT100LIKE)
|
if (tty->term->flags & TERM_VT100LIKE)
|
||||||
tty_raw(tty, "\033[?7727l");
|
tty_raw(tty, "\033[?7727l");
|
||||||
@ -819,12 +827,6 @@ tty_update_mode(struct tty *tty, int mode, struct screen *s)
|
|||||||
else if (mode & MODE_MOUSE_STANDARD)
|
else if (mode & MODE_MOUSE_STANDARD)
|
||||||
tty_puts(tty, "\033[?1000h");
|
tty_puts(tty, "\033[?1000h");
|
||||||
}
|
}
|
||||||
if (changed & MODE_BRACKETPASTE) {
|
|
||||||
if (mode & MODE_BRACKETPASTE)
|
|
||||||
tty_putcode(tty, TTYC_ENBP);
|
|
||||||
else
|
|
||||||
tty_putcode(tty, TTYC_DSBP);
|
|
||||||
}
|
|
||||||
tty->mode = mode;
|
tty->mode = mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
11
utf8.c
11
utf8.c
@ -229,14 +229,23 @@ utf8_width(struct utf8_data *ud, int *width)
|
|||||||
case 0:
|
case 0:
|
||||||
return (UTF8_ERROR);
|
return (UTF8_ERROR);
|
||||||
}
|
}
|
||||||
|
log_debug("UTF-8 %.*s is %08X", (int)ud->size, ud->data, (u_int)wc);
|
||||||
#ifdef HAVE_UTF8PROC
|
#ifdef HAVE_UTF8PROC
|
||||||
*width = utf8proc_wcwidth(wc);
|
*width = utf8proc_wcwidth(wc);
|
||||||
|
log_debug("utf8proc_wcwidth(%08X) returned %d", (u_int)wc, *width);
|
||||||
#else
|
#else
|
||||||
*width = wcwidth(wc);
|
*width = wcwidth(wc);
|
||||||
|
log_debug("wcwidth(%08X) returned %d", (u_int)wc, *width);
|
||||||
|
if (*width < 0) {
|
||||||
|
/*
|
||||||
|
* C1 control characters are nonprintable, so they are always
|
||||||
|
* zero width.
|
||||||
|
*/
|
||||||
|
*width = (wc >= 0x80 && wc <= 0x9f) ? 0 : 1;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
if (*width >= 0 && *width <= 0xff)
|
if (*width >= 0 && *width <= 0xff)
|
||||||
return (UTF8_DONE);
|
return (UTF8_DONE);
|
||||||
log_debug("UTF-8 %.*s, wcwidth() %d", (int)ud->size, ud->data, *width);
|
|
||||||
return (UTF8_ERROR);
|
return (UTF8_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
20
window.c
20
window.c
@ -64,6 +64,7 @@ static u_int next_active_point;
|
|||||||
struct window_pane_input_data {
|
struct window_pane_input_data {
|
||||||
struct cmdq_item *item;
|
struct cmdq_item *item;
|
||||||
u_int wp;
|
u_int wp;
|
||||||
|
struct client_file *file;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct window_pane *window_pane_create(struct window *, u_int, u_int,
|
static struct window_pane *window_pane_create(struct window *, u_int, u_int,
|
||||||
@ -1543,18 +1544,18 @@ window_pane_input_callback(struct client *c, __unused const char *path,
|
|||||||
size_t len = EVBUFFER_LENGTH(buffer);
|
size_t len = EVBUFFER_LENGTH(buffer);
|
||||||
|
|
||||||
wp = window_pane_find_by_id(cdata->wp);
|
wp = window_pane_find_by_id(cdata->wp);
|
||||||
if (wp == NULL || closed || error != 0 || (c->flags & CLIENT_DEAD)) {
|
if (cdata->file != NULL && (wp == NULL || c->flags & CLIENT_DEAD)) {
|
||||||
if (wp == NULL)
|
if (wp == NULL) {
|
||||||
|
c->retval = 1;
|
||||||
c->flags |= CLIENT_EXIT;
|
c->flags |= CLIENT_EXIT;
|
||||||
|
}
|
||||||
evbuffer_drain(buffer, len);
|
file_cancel(cdata->file);
|
||||||
|
} else if (cdata->file == NULL || closed || error != 0) {
|
||||||
cmdq_continue(cdata->item);
|
cmdq_continue(cdata->item);
|
||||||
|
|
||||||
server_client_unref(c);
|
server_client_unref(c);
|
||||||
free(cdata);
|
free(cdata);
|
||||||
return;
|
} else
|
||||||
}
|
input_parse_buffer(wp, buf, len);
|
||||||
input_parse_buffer(wp, buf, len);
|
|
||||||
evbuffer_drain(buffer, len);
|
evbuffer_drain(buffer, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1577,9 +1578,8 @@ window_pane_start_input(struct window_pane *wp, struct cmdq_item *item,
|
|||||||
cdata = xmalloc(sizeof *cdata);
|
cdata = xmalloc(sizeof *cdata);
|
||||||
cdata->item = item;
|
cdata->item = item;
|
||||||
cdata->wp = wp->id;
|
cdata->wp = wp->id;
|
||||||
|
cdata->file = file_read(c, "-", window_pane_input_callback, cdata);
|
||||||
c->references++;
|
c->references++;
|
||||||
file_read(c, "-", window_pane_input_callback, cdata);
|
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user