Merge branch 'obsd-master'

pull/3431/head
Thomas Adam 2023-01-06 09:02:00 +00:00
commit 21e00e4635
16 changed files with 443 additions and 181 deletions

View File

@ -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;
}; };
@ -122,6 +126,101 @@ 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->string[0] == '-')
argument = NULL;
}
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 != ':') {
log_debug("%s: -%c", __func__, flag);
args_set(args, flag, NULL, 0);
continue;
}
optional_argument = (*found == ':');
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 +230,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) {
@ -323,13 +357,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 +521,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 +529,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 +542,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 +559,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 +632,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 +641,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

View File

@ -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,

View File

@ -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);

View File

@ -833,7 +833,8 @@ cmdq_print_data(struct cmdq_item *item, int parse, struct evbuffer *evb)
char *sanitized, *msg, *line; char *sanitized, *msg, *line;
if (!parse) { if (!parse) {
utf8_stravisx(&msg, data, size, VIS_OCTAL|VIS_CSTYLE|VIS_TAB); utf8_stravisx(&msg, data, size,
VIS_OCTAL|VIS_CSTYLE|VIS_NOSLASH);
log_debug("%s: %s", __func__, msg); log_debug("%s: %s", __func__, msg);
} else { } else {
msg = EVBUFFER_DATA(evb); msg = EVBUFFER_DATA(evb);

View File

@ -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;
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);
} }

View File

@ -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
View File

@ -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);

115
input.c
View File

@ -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);
} }
@ -2456,47 +2457,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)
@ -2545,7 +2505,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;
} }
@ -2601,6 +2561,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)
@ -2610,14 +2611,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;
} }
@ -2654,14 +2659,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;
} }
@ -2706,7 +2715,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;
} }

View File

@ -1820,7 +1820,7 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc)
struct grid_cell tmp_gc, now_gc; struct grid_cell tmp_gc, now_gc;
struct tty_ctx ttyctx; struct tty_ctx ttyctx;
u_int sx = screen_size_x(s), sy = screen_size_y(s); u_int sx = screen_size_x(s), sy = screen_size_y(s);
u_int width = gc->data.width, xx, last, cx, cy; u_int width = gc->data.width, xx, last, cy;
int selected, skip = 1; int selected, skip = 1;
/* Ignore padding cells. */ /* Ignore padding cells. */
@ -1853,12 +1853,12 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc)
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)) != 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;
tty_write(tty_cmd_cell, &ttyctx); tty_write(tty_cmd_cell, &ttyctx);
s->cx = cx; s->cy = cy; s->cx = xx + 1 + gc->data.width; s->cy = cy;
} }
return; return;
} }
@ -2016,6 +2016,14 @@ screen_write_combine(struct screen_write_ctx *ctx, const struct utf8_data *ud,
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;
/* 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;
}
/* 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);

View File

@ -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;

23
tmux.1
View File

@ -964,7 +964,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:
@ -1541,8 +1541,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
@ -3123,7 +3122,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 +3214,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 +3230,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
@ -5817,8 +5823,7 @@ until it is dismissed.
.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

16
tmux.h
View File

@ -1381,6 +1381,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;
@ -1411,7 +1413,11 @@ struct tty {
#define TTY_HAVEDA 0x100 /* Primary DA. */ #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 /* Seconday DA. */ #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;
@ -2388,7 +2394,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 **);
@ -2606,7 +2612,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 *,
@ -2618,6 +2626,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;
@ -2761,6 +2770,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 *);

View File

@ -59,6 +59,7 @@ static int tty_keys_device_attributes2(struct tty *, const char *, size_t,
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 {
@ -719,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 */
@ -1278,7 +1290,7 @@ tty_keys_device_attributes(struct tty *tty, const char *buf, size_t len,
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); i++) { for (i = 0; i < (sizeof tmp); i++) {
if (3 + i == len) if (3 + i == len)
return (1); return (1);
@ -1352,7 +1364,7 @@ tty_keys_device_attributes2(struct tty *tty, const char *buf, size_t len,
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); i++) { for (i = 0; i < (sizeof tmp); i++) {
if (3 + i == len) if (3 + i == len)
return (1); return (1);
@ -1433,7 +1445,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);
@ -1465,3 +1477,68 @@ 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\. */
for (i = 0; i < (sizeof tmp) - 1; i++) {
if (5 + i == len)
return (1);
if (buf[5 + i - 1] == '\033' && buf[5 + i] == '\\')
break;
tmp[i] = buf[5 + i];
}
if (i == (sizeof tmp) - 1)
return (-1);
tmp[i - 1] = '\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);
}

10
tty.c
View File

@ -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);
@ -301,7 +301,7 @@ tty_start_timer_callback(__unused int fd, __unused short events, void *data)
log_debug("%s: start timer fired", c->name); log_debug("%s: start timer fired", c->name);
if ((tty->flags & (TTY_HAVEDA|TTY_HAVEDA2|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_HAVEDA2|TTY_HAVEXDA); tty->flags |= TTY_ALL_REQUEST_FLAGS;
} }
void void
@ -369,8 +369,12 @@ tty_send_requests(struct tty *tty)
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_HAVEDA2|TTY_HAVEXDA); tty->flags |= TTY_ALL_REQUEST_FLAGS;
} }
void void

4
utf8.c
View File

@ -233,10 +233,10 @@ utf8_width(struct utf8_data *ud, int *width)
*width = utf8proc_wcwidth(wc); *width = utf8proc_wcwidth(wc);
#else #else
*width = wcwidth(wc); *width = wcwidth(wc);
#endif log_debug("UTF-8 %.*s %#x, wcwidth() %d", (int)ud->size, ud->data,
(u_int)wc, *width);
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);
} }

View File

@ -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,16 @@ 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->flags |= CLIENT_EXIT; c->flags |= CLIENT_EXIT;
file_cancel(cdata->file);
evbuffer_drain(buffer, len); } 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 +1576,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);
} }