Support OSC 52 ? to read the top buffer inside tmux (when set-clipboard

is changed to on), also add refresh-client -l to ask tmux to use the
same mechanism to get the clipboard from the terminal outside
tmux. GitHub issue 1477.
pull/1545/head
nicm 2018-10-18 08:04:14 +00:00
parent bc0e527f32
commit a51668ca06
4 changed files with 201 additions and 39 deletions

View File

@ -31,8 +31,8 @@ const struct cmd_entry cmd_refresh_client_entry = {
.name = "refresh-client",
.alias = "refresh",
.args = { "C:St:", 0, 0 },
.usage = "[-S] [-C size] " CMD_TARGET_CLIENT_USAGE,
.args = { "C:lSt:", 0, 0 },
.usage = "[-lS] [-C size] " CMD_TARGET_CLIENT_USAGE,
.flags = CMD_AFTERHOOK,
.exec = cmd_refresh_client_exec
@ -49,7 +49,10 @@ cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item)
if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
if (args_has(args, 'C')) {
if (args_has(args, 'l')) {
if (c->session != NULL)
tty_putcode_ptr2(&c->tty, TTYC_MS, "", "?");
} else if (args_has(args, 'C')) {
if ((size = args_get(args, 'C')) == NULL) {
cmdq_error(item, "missing size");
return (CMD_RETURN_ERROR);

118
input.c
View File

@ -93,6 +93,10 @@ struct input_ctx {
u_char *input_buf;
size_t input_len;
size_t input_space;
enum {
INPUT_END_ST,
INPUT_END_BEL
} input_end;
struct input_param param_list[24];
u_int param_list_len;
@ -126,11 +130,11 @@ static void input_set_state(struct window_pane *,
const struct input_transition *);
static void input_reset_cell(struct input_ctx *);
static void input_osc_4(struct window_pane *, const char *);
static void input_osc_10(struct window_pane *, const char *);
static void input_osc_11(struct window_pane *, const char *);
static void input_osc_52(struct window_pane *, const char *);
static void input_osc_104(struct window_pane *, const char *);
static void input_osc_4(struct input_ctx *, const char *);
static void input_osc_10(struct input_ctx *, const char *);
static void input_osc_11(struct input_ctx *, const char *);
static void input_osc_52(struct input_ctx *, const char *);
static void input_osc_104(struct input_ctx *, const char *);
/* Transition entry/exit handlers. */
static void input_clear(struct input_ctx *);
@ -161,6 +165,7 @@ static void input_csi_dispatch_sgr_rgb(struct input_ctx *, int, u_int *);
static void input_csi_dispatch_sgr(struct input_ctx *);
static int input_dcs_dispatch(struct input_ctx *);
static int input_top_bit_set(struct input_ctx *);
static int input_end_bel(struct input_ctx *);
/* Command table comparison function. */
static int input_table_compare(const void *, const void *);
@ -487,7 +492,7 @@ static const struct input_transition input_state_esc_enter_table[] = {
{ -1, -1, NULL, NULL }
};
/* esc_interm state table. */
/* esc_intermediate state table. */
static const struct input_transition input_state_esc_intermediate_table[] = {
INPUT_STATE_ANYWHERE,
@ -602,7 +607,7 @@ static const struct input_transition input_state_dcs_parameter_table[] = {
{ -1, -1, NULL, NULL }
};
/* dcs_interm state table. */
/* dcs_intermediate state table. */
static const struct input_transition input_state_dcs_intermediate_table[] = {
INPUT_STATE_ANYWHERE,
@ -655,12 +660,12 @@ static const struct input_transition input_state_dcs_ignore_table[] = {
static const struct input_transition input_state_osc_string_table[] = {
INPUT_STATE_ANYWHERE,
{ 0x00, 0x06, NULL, NULL },
{ 0x07, 0x07, NULL, &input_state_ground },
{ 0x08, 0x17, NULL, NULL },
{ 0x19, 0x19, NULL, NULL },
{ 0x1c, 0x1f, NULL, NULL },
{ 0x20, 0xff, input_input, NULL },
{ 0x00, 0x06, NULL, NULL },
{ 0x07, 0x07, input_end_bel, &input_state_ground },
{ 0x08, 0x17, NULL, NULL },
{ 0x19, 0x19, NULL, NULL },
{ 0x1c, 0x1f, NULL, NULL },
{ 0x20, 0xff, input_input, NULL },
{ -1, -1, NULL, NULL }
};
@ -993,8 +998,8 @@ input_get(struct input_ctx *ictx, u_int validx, int minval, int defval)
static void
input_reply(struct input_ctx *ictx, const char *fmt, ...)
{
va_list ap;
char *reply;
va_list ap;
char *reply;
va_start(ap, fmt);
xvasprintf(&reply, fmt, ap);
@ -1019,6 +1024,8 @@ input_clear(struct input_ctx *ictx)
*ictx->input_buf = '\0';
ictx->input_len = 0;
ictx->input_end = INPUT_END_ST;
ictx->flags &= ~INPUT_DISCARD;
}
@ -2046,6 +2053,17 @@ input_csi_dispatch_sgr(struct input_ctx *ictx)
}
}
/* End of input with BEL. */
static int
input_end_bel(struct input_ctx *ictx)
{
log_debug("%s", __func__);
ictx->input_end = INPUT_END_BEL;
return (0);
}
/* DCS string started. */
static void
input_enter_dcs(struct input_ctx *ictx)
@ -2102,7 +2120,8 @@ input_exit_osc(struct input_ctx *ictx)
if (ictx->input_len < 1 || *p < '0' || *p > '9')
return;
log_debug("%s: \"%s\"", __func__, p);
log_debug("%s: \"%s\" (end %s)", __func__, p,
ictx->input_end == INPUT_END_ST ? "ST" : "BEL");
option = 0;
while (*p >= '0' && *p <= '9')
@ -2119,23 +2138,23 @@ input_exit_osc(struct input_ctx *ictx)
}
break;
case 4:
input_osc_4(ictx->wp, p);
input_osc_4(ictx, p);
break;
case 10:
input_osc_10(ictx->wp, p);
input_osc_10(ictx, p);
break;
case 11:
input_osc_11(ictx->wp, p);
input_osc_11(ictx, p);
break;
case 12:
if (utf8_isvalid(p) && *p != '?') /* ? is colour request */
screen_set_cursor_colour(ictx->ctx.s, p);
break;
case 52:
input_osc_52(ictx->wp, p);
input_osc_52(ictx, p);
break;
case 104:
input_osc_104(ictx->wp, p);
input_osc_104(ictx, p);
break;
case 112:
if (*p == '\0') /* no arguments allowed */
@ -2237,11 +2256,12 @@ input_top_bit_set(struct input_ctx *ictx)
/* Handle the OSC 4 sequence for setting (multiple) palette entries. */
static void
input_osc_4(struct window_pane *wp, const char *p)
input_osc_4(struct input_ctx *ictx, const char *p)
{
char *copy, *s, *next = NULL;
long idx;
u_int r, g, b;
struct window_pane *wp = ictx->wp;
char *copy, *s, *next = NULL;
long idx;
u_int r, g, b;
copy = s = xstrdup(p);
while (s != NULL && *s != '\0') {
@ -2271,9 +2291,10 @@ bad:
/* Handle the OSC 10 sequence for setting foreground colour. */
static void
input_osc_10(struct window_pane *wp, const char *p)
input_osc_10(struct input_ctx *ictx, const char *p)
{
u_int r, g, b;
struct window_pane *wp = ictx->wp;
u_int r, g, b;
if (sscanf(p, "rgb:%2x/%2x/%2x", &r, &g, &b) != 3)
goto bad;
@ -2289,9 +2310,10 @@ bad:
/* Handle the OSC 11 sequence for setting background colour. */
static void
input_osc_11(struct window_pane *wp, const char *p)
input_osc_11(struct input_ctx *ictx, const char *p)
{
u_int r, g, b;
struct window_pane *wp = ictx->wp;
u_int r, g, b;
if (sscanf(p, "rgb:%2x/%2x/%2x", &r, &g, &b) != 3)
goto bad;
@ -2307,13 +2329,16 @@ bad:
/* Handle the OSC 52 sequence for setting the clipboard. */
static void
input_osc_52(struct window_pane *wp, const char *p)
input_osc_52(struct input_ctx *ictx, const char *p)
{
struct window_pane *wp = ictx->wp;
char *end;
const char *buf;
size_t len;
u_char *out;
int outlen, state;
struct screen_write_ctx ctx;
struct paste_buffer *pb;
state = options_get_number(global_options, "set-clipboard");
if (state != 2)
@ -2324,6 +2349,32 @@ input_osc_52(struct window_pane *wp, const char *p)
end++;
if (*end == '\0')
return;
log_debug("%s: %s", __func__, end);
if (strcmp(end, "?") == 0) {
if ((pb = paste_get_top(NULL)) != NULL) {
buf = paste_buffer_data(pb, &len);
outlen = 4 * ((len + 2) / 3) + 1;
out = xmalloc(outlen);
if ((outlen = b64_ntop(buf, len, out, outlen)) == -1) {
abort();
free(out);
return;
}
} else {
outlen = 0;
out = NULL;
}
bufferevent_write(wp->event, "\033]52;;", 6);
if (outlen != 0)
bufferevent_write(wp->event, out, outlen);
if (ictx->input_end == INPUT_END_BEL)
bufferevent_write(wp->event, "\007", 1);
else
bufferevent_write(wp->event, "\033\\", 2);
free(out);
return;
}
len = (strlen(end) / 4) * 3;
if (len == 0)
@ -2345,10 +2396,11 @@ input_osc_52(struct window_pane *wp, const char *p)
/* Handle the OSC 104 sequence for unsetting (multiple) palette entries. */
static void
input_osc_104(struct window_pane *wp, const char *p)
input_osc_104(struct input_ctx *ictx, const char *p)
{
char *copy, *s;
long idx;
struct window_pane *wp = ictx->wp;
char *copy, *s;
long idx;
if (*p == '\0') {
window_pane_reset_palette(wp);

10
tmux.1
View File

@ -917,8 +917,8 @@ is used, the
.Ic update-environment
option will not be applied.
.It Xo Ic refresh-client
.Op Fl lS
.Op Fl C Ar width,height
.Op Fl S
.Op Fl t Ar target-client
.Xc
.D1 (alias: Ic refresh )
@ -931,6 +931,10 @@ is specified, only update the client's status line.
.Pp
.Fl C
sets the width and height of a control client.
.Fl l
requests the clipboard from the client using the
.Xr xterm 1
escape sequence and stores it in a new paste buffer.
.It Xo Ic rename-session
.Op Fl t Ar target-session
.Ar new-name
@ -3890,7 +3894,7 @@ option.
.El
.Pp
When a pane is first created, its title is the hostname.
A pane's title can be set via the OSC title setting sequence, for example:
A pane's title can be set via the title setting escape sequence, for example:
.Bd -literal -offset indent
$ printf '\e033]2;My Title\e033\e\e'
.Ed
@ -4444,7 +4448,7 @@ Indicate that the terminal supports the
.Ql direct colour
RGB escape sequence (for example, \ee[38;2;255;255;255m).
.Pp
If supported, this is used for the OSC initialize colour escape sequence (which
If supported, this is used for the initialize colour escape sequence (which
may be enabled by adding the
.Ql initc
and

View File

@ -19,7 +19,10 @@
#include <sys/types.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <limits.h>
#include <resolv.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
@ -44,6 +47,8 @@ static int tty_keys_next1(struct tty *, const char *, size_t, key_code *,
size_t *, int);
static void tty_keys_callback(int, short, void *);
static int tty_keys_mouse(struct tty *, const char *, size_t, size_t *);
static int tty_keys_clipboard(struct tty *, const char *, size_t,
size_t *);
static int tty_keys_device_attributes(struct tty *, const char *, size_t,
size_t *);
@ -571,6 +576,17 @@ tty_keys_next(struct tty *tty)
return (0);
log_debug("%s: keys are %zu (%.*s)", c->name, len, (int)len, buf);
/* Is this a clipboard response? */
switch (tty_keys_clipboard(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 device attributes response? */
switch (tty_keys_device_attributes(tty, buf, len, &size)) {
case 0: /* yes */
@ -871,6 +887,93 @@ tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size)
return (0);
}
/*
* Handle OSC 52 clipboard input. Returns 0 for success, -1 for failure, 1 for
* partial.
*/
static int
tty_keys_clipboard(__unused struct tty *tty, const char *buf, size_t len,
size_t *size)
{
size_t end, terminator, needed;
char *copy, *out;
int outlen;
*size = 0;
/* First three bytes are always \033]52;. */
if (buf[0] != '\033')
return (-1);
if (len == 1)
return (1);
if (buf[1] != ']')
return (-1);
if (len == 2)
return (1);
if (buf[2] != '5')
return (-1);
if (len == 3)
return (1);
if (buf[3] != '2')
return (-1);
if (len == 4)
return (1);
if (buf[4] != ';')
return (-1);
if (len == 5)
return (1);
/* Find the terminator if any. */
for (end = 5; end < len; end++) {
if (buf[end] == '\007') {
terminator = 1;
break;
}
if (end > 5 && buf[end - 1] == '\033' && buf[end] == '\\') {
terminator = 2;
break;
}
}
if (end == len)
return (1);
*size = end + terminator;
/* Skip the initial part. */
buf += 5;
end -= 5;
/* Get the second argument. */
while (end != 0 && *buf != ';') {
buf++;
end--;
}
if (end == 0 || end == 1)
return (0);
buf++;
end--;
/* It has to be a string so copy it. */
copy = xmalloc(end + 1);
memcpy(copy, buf, end);
copy[end] = '\0';
/* Convert from base64. */
needed = (end / 4) * 3;
out = xmalloc(needed);
if ((outlen = b64_pton(copy, out, len)) == -1) {
free(out);
free(copy);
return (0);
}
free(copy);
/* Create a new paste buffer. */
log_debug("%s: %.*s", __func__, outlen, out);
paste_add(out, outlen);
return (0);
}
/*
* Handle device attributes input. Returns 0 for success, -1 for failure, 1 for
* partial.