diff --git a/input.c b/input.c index 779b9013..f162b92f 100644 --- a/input.c +++ b/input.c @@ -1345,8 +1345,8 @@ input_csi_dispatch(struct input_ctx *ictx) if (ictx->flags & INPUT_DISCARD) return (0); - log_debug("%s: '%c' \"%s\" \"%s\"", - __func__, ictx->ch, ictx->interm_buf, ictx->param_buf); + log_debug("%s: '%c' \"%s\" \"%s\"", __func__, ictx->ch, + ictx->interm_buf, ictx->param_buf); if (input_split(ictx) != 0) return (0); diff --git a/tmux.1 b/tmux.1 index c25440d4..1e325154 100644 --- a/tmux.1 +++ b/tmux.1 @@ -3690,6 +3690,8 @@ Supports the overline SGR attribute. Supports the DECFRA rectangle fill escape sequence. .It RGB Supports RGB colour with the SGR escape sequences. +.It sixel +Supports SIXEL graphics. .It strikethrough Supports the strikethrough SGR escape sequence. .It sync @@ -5083,6 +5085,15 @@ would change .Ql abABab into .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 In addition, the last line of a shell command's output may be inserted using .Ql #() . @@ -6485,6 +6496,8 @@ Set the opening sequence for the working directory notification. The sequence is terminated using the standard .Em fsl capability. +.It Em \&Sxl +Indicates that the terminal supports SIXEL. .It Em \&Sync Start (parameter is 1) or end (parameter is 2) a synchronized update. .It Em \&Tc diff --git a/tmux.h b/tmux.h index e88eac0f..751e8a99 100644 --- a/tmux.h +++ b/tmux.h @@ -544,6 +544,7 @@ enum tty_code_code { TTYC_SMUL, TTYC_SMULX, TTYC_SMXX, + TTYC_SXL, TTYC_SS, TTYC_SWD, TTYC_SYNC, @@ -1350,6 +1351,7 @@ struct tty_term { #define TERM_DECFRA 0x8 #define TERM_RGBCOLOURS 0x10 #define TERM_VT100LIKE 0x20 +#define TERM_SIXEL 0x40 int flags; LIST_ENTRY(tty_term) entry; @@ -1406,9 +1408,10 @@ struct tty { #define TTY_OPENED 0x20 #define TTY_OSC52QUERY 0x40 #define TTY_BLOCK 0x80 -#define TTY_HAVEDA 0x100 +#define TTY_HAVEDA 0x100 /* Primary DA. */ #define TTY_HAVEXDA 0x200 #define TTY_SYNCING 0x400 +#define TTY_HAVEDA2 0x800 /* Seconday DA. */ int flags; struct tty_term *term; diff --git a/tty-features.c b/tty-features.c index 8ed61e9a..dca40fad 100644 --- a/tty-features.c +++ b/tty-features.c @@ -345,6 +345,17 @@ static const struct tty_feature tty_feature_ignorefkeys = { 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. */ static const struct tty_feature *const tty_features[] = { &tty_feature_256, @@ -362,6 +373,7 @@ static const struct tty_feature *const tty_features[] = { &tty_feature_overline, &tty_feature_rectfill, &tty_feature_rgb, + &tty_feature_sixel, &tty_feature_strikethrough, &tty_feature_sync, &tty_feature_title, diff --git a/tty-keys.c b/tty-keys.c index cb8efd49..6fe121f0 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -55,6 +55,8 @@ 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 *); +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 *, size_t, size_t *); @@ -684,7 +686,7 @@ tty_keys_next(struct tty *tty) 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)) { case 0: /* yes */ key = KEYC_UNKNOWN; @@ -695,6 +697,17 @@ tty_keys_next(struct tty *tty) 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? */ switch (tty_keys_extended_device_attributes(tty, buf, len, &size)) { case 0: /* yes */ @@ -1235,7 +1248,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. */ static int @@ -1243,17 +1256,15 @@ tty_keys_device_attributes(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[64], *endptr, p[32] = { 0 }, *cp, *next; + char tmp[128], *endptr, p[32] = { 0 }, *cp, *next; *size = 0; if (tty->flags & TTY_HAVEDA) return (-1); - /* - * First three bytes are always \033[>. Some older Terminal.app - * versions respond as for DA (\033[?) so accept and ignore that. - */ + /* First three bytes are always \033[?. */ if (buf[0] != '\033') return (-1); if (len == 1) @@ -1262,56 +1273,127 @@ tty_keys_device_attributes(struct tty *tty, const char *buf, size_t len, return (-1); if (len == 2) return (1); - if (buf[2] != '>' && buf[2] != '?') + if (buf[2] != '?') return (-1); if (len == 3) return (1); /* 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) return (1); if (buf[3 + i] == 'c') break; tmp[i] = buf[3 + i]; } - if (i == (sizeof tmp) - 1) + if (i == (sizeof tmp)) return (-1); tmp[i] = '\0'; *size = 4 + i; - /* Ignore DA response. */ - if (buf[2] == '?') - return (0); - /* Convert all arguments to numbers. */ cp = tmp; while ((next = strsep(&cp, ";")) != NULL) { p[n] = strtoul(next, &endptr, 10); if (*endptr != '\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. */ switch (p[0]) { case 41: /* VT420 */ - tty_add_features(&c->term_features, "margins,rectfill", ","); + tty_add_features(features, "margins,rectfill", ","); break; case 'M': /* mintty */ - tty_default_features(&c->term_features, "mintty", 0); + tty_default_features(features, "mintty", 0); break; case 'T': /* tmux */ - tty_default_features(&c->term_features, "tmux", 0); + tty_default_features(features, "tmux", 0); break; case 'U': /* rxvt-unicode */ - tty_default_features(&c->term_features, "rxvt-unicode", 0); + tty_default_features(features, "rxvt-unicode", 0); break; } log_debug("%s: received secondary DA %.*s", c->name, (int)*size, buf); tty_update_features(tty); - tty->flags |= TTY_HAVEDA; + tty->flags |= TTY_HAVEDA2; return (0); } @@ -1325,6 +1407,7 @@ tty_keys_extended_device_attributes(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; char tmp[128]; @@ -1365,13 +1448,13 @@ tty_keys_extended_device_attributes(struct tty *tty, const char *buf, /* Add terminal features. */ 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) - tty_default_features(&c->term_features, "tmux", 0); + tty_default_features(features, "tmux", 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) - 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); free(c->term_type); diff --git a/tty-term.c b/tty-term.c index 8c3e8e8d..4e9b7799 100644 --- a/tty-term.c +++ b/tty-term.c @@ -268,6 +268,7 @@ static const struct tty_term_code_entry tty_term_codes[] = { [TTYC_SETRGBF] = { TTYCODE_STRING, "setrgbf" }, [TTYC_SETULC] = { TTYCODE_STRING, "Setulc" }, [TTYC_SE] = { TTYCODE_STRING, "Se" }, + [TTYC_SXL] = { TTYCODE_FLAG, "Sxl" }, [TTYC_SGR0] = { TTYCODE_STRING, "sgr0" }, [TTYC_SITM] = { TTYCODE_STRING, "sitm" }, [TTYC_SMACS] = { TTYCODE_STRING, "smacs" }, @@ -456,6 +457,9 @@ tty_term_apply_overrides(struct tty_term *term) 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. */ if (tty_term_has(term, TTYC_SETRGBF) && tty_term_has(term, TTYC_SETRGBB)) diff --git a/tty.c b/tty.c index 1394075d..43a2961f 100644 --- a/tty.c +++ b/tty.c @@ -299,9 +299,9 @@ tty_start_timer_callback(__unused int fd, __unused short events, void *data) struct client *c = tty->client; 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->flags |= (TTY_HAVEDA|TTY_HAVEXDA); + tty->flags |= (TTY_HAVEDA|TTY_HAVEDA2|TTY_HAVEXDA); } void @@ -363,12 +363,14 @@ tty_send_requests(struct tty *tty) return; 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"); if (~tty->flags & TTY_HAVEXDA) tty_puts(tty, "\033[>q"); } else - tty->flags |= (TTY_HAVEDA|TTY_HAVEXDA); + tty->flags |= (TTY_HAVEDA|TTY_HAVEDA2|TTY_HAVEXDA); } void